0% found this document useful (0 votes)
6 views

Pyramid Web Framework, For Python

Uploaded by

Dhiman Kalita
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views

Pyramid Web Framework, For Python

Uploaded by

Dhiman Kalita
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1274

The Pyramid Web Framework

Version 2.0.2

Chris McDonough

August 25, 2023


CONTENTS

0.1 Front Matter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1


0.2 Tutorials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
0.3 Narrative Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
0.4 API Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716
0.5 p* Scripts Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 909
0.6 Change History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915
0.7 Glossary and Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1226

Index 1247

i
ii
The Pyramid Web Framework, Version 2.0.2

0.1 Front Matter

0.1.1 Copyright, Trademarks, and Attributions

”The Pyramid Web Framework, Version 2.0.2”

by Chris McDonough

Copyright © 2008-2011, Agendaless Consulting.

ISBN-10: 0615445675

ISBN-13: 978-0615445670

First print publishing: February, 2011

All rights reserved. This material may be copied or distributed only subject to the terms and conditions set
forth in the Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License. You
must give the original author credit. You may not use this work for commercial purposes. If you alter,
transform, or build upon this work, you may distribute the resulting work only under the same or similar
license to this one.

While the Pyramid documentation is offered under the Creative Commons Attribution-
Nonconmmercial-Share Alike 3.0 United States License, the Pyramid software is offered under a less
restrictive (BSD-like) license .

All terms mentioned in this book that are known to be trademarks or service marks have been appropriately
capitalized. However, use of a term in this book should not be regarded as affecting the validity of any
trademark or service mark.

Every effort has been made to make this book as complete and as accurate as possible, but no warranty
or fitness is implied. The information provided is on an ”as-is” basis. The author and the publisher shall
have neither liability nor responsibility to any person or entity with respect to any loss or damages arising
from the information contained in this book. No patent liability is assumed with respect to the use of the
information contained herein.

0.1. Front Matter 1


The Pyramid Web Framework, Version 2.0.2

Attributions

Editor:
Casey Duncan

Contributors:
Ben Bangert, Blaise Laflamme, Rob Miller, Mike Orr, Carlos de la Guardia, Paul Everitt, Tres
Seaver, John Shipman, Marius Gedminas, Chris Rossi, Joachim Krebs, Xavier Spriet, Reed O’Brien,
William Chambers, Charlie Choiniere, Jamaludin Ahmad, Graham Higgins, Patricio Paez, Michael
Merickel, Eric Ongerth, Niall O’Higgins, Christoph Zwerschke, John Anderson, Atsushi Odagiri,
Kirk Strauser, JD Navarro, Joe Dallago, Savoir-Faire Linux, Łukasz Fidosz, Christopher Lambacher,
Claus Conrad, Chris Beelby, Phil Jenvey and a number of people with only pseudonyms on GitHub.

Cover Designer:
Hugues Laflamme of Kemeneur.

Used with permission:

The Request and Response Objects chapter is adapted, with permission, from documentation
originally written by Ian Bicking.

The Much Ado About Traversal chapter is adapted, with permission, from an article written
by Rob Miller.

The Logging is adapted, with permission, from the Pylons documentation logging chapter,
originally written by Phil Jenvey.

Print Production

The print version of this book was produced using the Sphinx documentation generation system and the
LaTeX typesetting system.

Contacting The Publisher

Please send documentation licensing inquiries, translation inquiries, and other business communications
to Agendaless Consulting. Please send software and other technical queries to the Pylons-devel mailing
list.

2 CONTENTS
The Pyramid Web Framework, Version 2.0.2

HTML Version and Source Code

An HTML version of this book is freely available via https://docs.pylonsproject.org/projects/pyramid/en/


latest/

The source code for the examples used in this book are available within the Pyramid software distribution,
always available via https://github.com/Pylons/pyramid

0.1.2 Typographical Conventions

Introduction

This chapter describes typographical conventions used in the Pyramid documentation.

Glossary

A glossary defines terms used throughout the documentation. References to glossary terms appear as
follows.

request

Note it is hyperlinked, and when clicked it will take the user to the term in the Glossary and highlight the
term.

Links

Links are presented as follows, and may be clickable.

TryPyramid

See also:

See also Cross-references for other links within the documentation.

Topic

A topic is similar to a block quote with a title, or a self-contained section with no subsections. A topic
indicates a self-contained idea that is separate from the flow of the document. Topics may occur anywhere
a section or transition may occur.

0.1. Front Matter 3


The Pyramid Web Framework, Version 2.0.2

Topic Title

Subsequent indented lines comprise the body of the topic, and are interpreted as body elements.

Code

Code may be displayed in blocks or inline. Blocks of code may use syntax highlighting, line numbering,
and emphasis.

Syntax highlighting

XML:

<somesnippet>Some XML</somesnippet>

Unix shell commands (See venv for the meaning of $VENV.):

$VENV/bin/pip install -e .

Windows commands (See venv for the meaning of %VENV%.):

%VENV%\Scripts\pserve development.ini

cfg:

[some-part]
# A random part in the buildout
recipe = collective.recipe.foo
option = value

ini:

4 CONTENTS
The Pyramid Web Framework, Version 2.0.2

[tool:pytest]
python_files = test_*.py
testpaths =
tests
addopts = -W always

Interactive Python:

>>> class Foo:


... bar = 100
...
>>> f = Foo()
>>> f.bar
100
>>> f.bar / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

Displaying long commands

When a command that should be typed on one line is too long to fit on the displayed width of a page, the
backslash character \ is used to indicate that the subsequent printed line should be part of the command:

$VENV/bin/pytest tutorial/tests.py --cov-report term-missing \


--cov=tutorial -q

Code block options

To emphasize lines, we give the appearance that a highlighting pen has been used on the code.

if "foo" == "bar":
# This is Python code
pass

A code block with line numbers.

0.1. Front Matter 5


The Pyramid Web Framework, Version 2.0.2

1 if "foo" == "bar":
2 # This is Python code
3 pass

Some code blocks may be given a caption.

Listing 1: sample.py

if "foo" == "bar":
# This is Python code
pass

Inline code

Inline code is displayed as follows, where the inline code is ’pip install -e ”.[docs]”’.

Install requirements for building documentation: pip install -e ".[docs]"

Feature versioning

We designate the version in which something is added, changed, or deprecated in the project.

Version added

The version in which a feature is added to a project is displayed as follows.

New in version 1.1: pyramid.paster.bootstrap()

Version changed

The version in which a feature is changed in a project is displayed as follows.

Changed in version 1.8: Added the ability for bootstrap to cleanup automatically via the with state-
ment.

6 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Deprecated

The version in which a feature is deprecated in a project is displayed as follows.

Deprecated since version 1.7: Use the require_csrf option or read Checking CSRF Tokens Automat-
ically instead to have pyramid.exceptions.BadCSRFToken exceptions raised.

Warnings

Warnings represent limitations and advice related to a topic or concept.

This is a warning.

Notes

Notes represent additional information related to a topic or concept.

This is a note.

See also

”See also” messages refer to topics that are related to the current topic, but have a narrative tone to them
instead of merely a link without explanation. ”See also” is rendered in a block as well, so that it stands out
for the reader’s attention.

See also:

See Quick Tutorial section on Requirements.

Cross-references

Cross-references are links that may be to a document, arbitrary location, object, or other items.

0.1. Front Matter 7


The Pyramid Web Framework, Version 2.0.2

Cross-referencing documents

Links to pages within this documentation display as follows.

Quick Tour of Pyramid

Cross-referencing arbitrary locations

Links to sections, and tables and figures with captions, within this documentation display as follows.

Internationalization and Localization

Python modules, classes, methods, and functions

All of the following are clickable links to Python modules, classes, methods, and functions.

Python module names display as follows.

pyramid.config

Python class names display as follows.

pyramid.config.Configurator

Python method names display as follows.

pyramid.config.Configurator.add_view()

Python function names display as follows.

pyramid.renderers.render_to_response()

Sometimes we show only the last segment of a Python object’s name, which displays as follows.

render_to_response()

The application ”Pyramid” itself displays as follows.

Pyramid

8 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.1.3 Author Introduction

Welcome to ”The Pyramid Web Framework”. In this introduction, I’ll describe the audience for this book,
I’ll describe the book content, I’ll provide some context regarding the genesis of Pyramid, and I’ll thank
some important people.

I hope you enjoy both this book and the software it documents. I’ve had a blast writing both.

Audience

This book is aimed primarily at a reader that has the following attributes:

• At least a moderate amount of Python experience.

• A familiarity with web protocols such as HTTP and CGI.

If you fit into both of these categories, you’re in the direct target audience for this book. But don’t worry,
even if you have no experience with Python or the web, both are easy to pick up ”on the fly”.

Python is an excellent language in which to write applications; becoming productive in Python is almost
mind-blowingly easy. If you already have experience in another language such as Java, Visual Basic, Perl,
Ruby, or even C/C++, learning Python will be a snap; it should take you no longer than a couple of days
to become modestly productive. If you don’t have previous programming experience, it will be slightly
harder, and it will take a little longer, but you’d be hard-pressed to find a better ”first language.”

Web technology familiarity is assumed in various places within the book. For example, the book doesn’t
try to define common web-related concepts like ”URL” or ”query string.” Likewise, the book describes
various interactions in terms of the HTTP protocol, but it does not describe how the HTTP protocol works
in detail. Like any good web framework, though, Pyramid shields you from needing to know most of the
gory details of web protocols and low-level data structures. As a result, you can usually avoid becoming
”blocked” while you read this book even if you don’t yet deeply understand web technologies.

0.1. Front Matter 9


The Pyramid Web Framework, Version 2.0.2

Book Content

This book is divided into four major parts:

Tutorials

Each tutorial builds a sample application or implements a set of concepts with a sample; it then
describes the application or concepts in terms of the sample. You should read the tutorials if
you want a guided tour of Pyramid.

Narrative Documentation

This is documentation which describes Pyramid concepts in narrative form, written in a largely
conversational tone. Each narrative documentation chapter describes an isolated Pyramid con-
cept. You should be able to get useful information out of the narrative chapters if you read
them out-of-order, or when you need only a reminder about a particular topic while you’re
developing an application.

API Documentation

Comprehensive reference material for every public API exposed by Pyramid. The API docu-
mentation is organized alphabetically by module name.

p* Scripts Documentation

p* scripts included with Pyramid.

The Genesis of repoze.bfg

Before the end of 2010, Pyramid was known as repoze.bfg.

I wrote repoze.bfg after many years of writing applications using Zope. Zope provided me with a lot of
mileage: it wasn’t until almost a decade of successfully creating applications using it that I decided to write
a different web framework. Although repoze.bfg takes inspiration from a variety of web frameworks,
it owes more of its core design to Zope than any other.

The Repoze ”brand” existed before repoze.bfg was created. One of the first packages developed as
part of the Repoze brand was a package named repoze.zope2. This was a package that allowed Zope
2 applications to run under a WSGI server without modification. Zope 2 did not have reasonable WSGI
support at the time.

10 CONTENTS
The Pyramid Web Framework, Version 2.0.2

During the development of the repoze.zope2 package, I found that replicating the Zope 2 ”publisher”
-- the machinery that maps URLs to code -- was time-consuming and fiddly. Zope 2 had evolved over
many years, and emulating all of its edge cases was extremely difficult. I finished the repoze.zope2
package, and it emulates the normal Zope 2 publisher pretty well. But during its development, it became
clear that Zope 2 had simply begun to exceed my tolerance for complexity, and I began to look around for
simpler options.

I considered using the Zope 3 application server machinery, but it turned out that it had become more
indirect than the Zope 2 machinery it aimed to replace, which didn’t fulfill the goal of simplification. I
also considered using Django and Pylons, but neither of those frameworks offer much along the axes of
traversal, contextual declarative security, or application extensibility; these were features I had become
accustomed to as a Zope developer.

I decided that in the long term, creating a simpler framework that retained features I had become accus-
tomed to when developing Zope applications was a more reasonable idea than continuing to use any Zope
publisher or living with the limitations and unfamiliarities of a different framework. The result is what is
now Pyramid.

The Genesis of Pyramid

What was repoze.bfg has become Pyramid as the result of a coalition built between the Repoze and
Pylons community throughout the year 2010. By merging technology, we’re able to reduce duplication of
effort, and take advantage of more of each others’ technology.

Thanks

This book is dedicated to my grandmother, who gave me my first typewriter (a Royal), and my mother,
who bought me my first computer (a VIC-20).

Thanks to the following people for providing expertise, resources, and software. Without the help of
these folks, neither this book nor the software which it details would exist: Paul Everitt, Tres Seaver, An-
drew Sawyers, Malthe Borch, Carlos de la Guardia, Chris Rossi, Shane Hathaway, Daniel Holth, Wichert
Akkerman, Georg Brandl, Blaise Laflamme, Ben Bangert, Casey Duncan, Hugues Laflamme, Mike Orr,
John Shipman, Chris Beelby, Patricio Paez, Simon Oram, Nat Hardwick, Ian Bicking, Jim Fulton, Michael
Merickel, Tom Moroz of the Open Society Institute, and Todd Koym of Environmental Health Sciences.

Thanks to Guido van Rossum and Tim Peters for Python.

Special thanks to Tricia for putting up with me.

0.1. Front Matter 11


The Pyramid Web Framework, Version 2.0.2

0.1.4 Defending Pyramid’s Design

From time to time, challenges to various aspects of Pyramid design are lodged. To give context to discus-
sions that follow, we detail some of the design decisions and trade-offs here. In some cases, we acknowl-
edge that the framework can be made better and we describe future steps which will be taken to improve
it. In others we just file the challenge as noted, as obviously you can’t please everyone all of the time.

Pyramid Provides More Than One Way to Do It

A canon of Python popular culture is ”TIOOWTDI” (”there is only one way to do it”, a slighting, tongue-
in-cheek reference to Perl’s ”TIMTOWTDI”, which is an acronym for ”there is more than one way to do
it”).

Pyramid is, for better or worse, a ”TIMTOWTDI” system. For example, it includes more than one way to
resolve a URL to a view callable: via url dispatch or traversal. Multiple methods of configuration exist:
imperative configuration, configuration decoration, and ZCML (optionally via pyramid_zcml). It works
with multiple different kinds of persistence and templating systems. And so on. However, the existence
of most of these overlapping ways to do things are not without reason and purpose: we have a number of
audiences to serve, and we believe that TIMTOWTDI at the web framework level actually prevents a much
more insidious and harmful set of duplication at higher levels in the Python web community.

Pyramid began its life as repoze.bfg, written by a team of people with many years of prior Zope
experience. The idea of traversal and the way view lookup works was stolen entirely from Zope. The
authorization subsystem provided by Pyramid is a derivative of Zope’s. The idea that an application can
be extended without forking is also a Zope derivative.

Implementations of these features were required to allow the Pyramid authors to build the bread-and-butter
CMS-type systems for customers in the way in which they were accustomed. No other system, save for
Zope itself, had such features, and Zope itself was beginning to show signs of its age. We were becoming
hampered by consequences of its early design mistakes. Zope’s lack of documentation was also difficult
to work around. It was hard to hire smart people to work on Zope applications because there was no
comprehensive documentation set which explained ”it all” in one consumable place, and it was too large
and self-inconsistent to document properly. Before repoze.bfg went under development, its authors
obviously looked around for other frameworks that fit the bill. But no non-Zope framework did. So we
embarked on building repoze.bfg.

As the result of our research, however, it became apparent that, despite the fact that no one framework had
all the features we required, lots of existing frameworks had good, and sometimes very compelling ideas.
In particular, URL dispatch is a more direct mechanism to map URLs to code.

So, although we couldn’t find a framework, save for Zope, that fit our needs, and while we incorporated a
lot of Zope ideas into BFG, we also emulated the features we found compelling in other frameworks (such

12 CONTENTS
The Pyramid Web Framework, Version 2.0.2

as url dispatch). After the initial public release of BFG, as time went on, features were added to support
people allergic to various Zope-isms in the system, such as the ability to configure the application using
imperative configuration and configuration decoration, rather than solely using ZCML, and the elimination
of the required use of interface objects. It soon became clear that we had a system that was very generic,
and was beginning to appeal to non-Zope users as well as ex-Zope users.

As the result of this generalization, it became obvious BFG shared 90% of its feature set with the feature
set of Pylons 1, and thus had a very similar target market. Because they were so similar, choosing between
the two systems was an exercise in frustration for an otherwise non-partisan developer. It was also strange
for the Pylons and BFG development communities to be in competition for the same set of users, given
how similar the two frameworks were. So the Pylons and BFG teams began to work together to form a
plan to merge. The features missing from BFG (notably view handler classes, flash messaging, and other
minor missing bits), were added to provide familiarity to ex-Pylons users. The result is Pyramid.

The Python web framework space is currently notoriously balkanized. We’re truly hoping that the amal-
gamation of components in Pyramid will appeal to at least two currently very distinct sets of users: Pylons
and BFG users. By unifying the best concepts from Pylons and BFG into a single codebase, and leaving
the bad concepts from their ancestors behind, we’ll be able to consolidate our efforts better, share more
code, and promote our efforts as a unit rather than competing pointlessly. We hope to be able to shortcut
the pack mentality which results in a much larger duplication of effort, represented by competing but in-
credibly similar applications and libraries, each built upon a specific low level stack that is incompatible
with the other. We’ll also shrink the choice of credible Python web frameworks down by at least one.
We’re also hoping to attract users from other communities (such as Zope’s and TurboGears’) by provid-
ing the features they require, while allowing enough flexibility to do things in a familiar fashion. Some
overlap of functionality to achieve these goals is expected and unavoidable, at least if we aim to prevent
pointless duplication at higher levels. If we’ve done our job well enough, the various audiences will be
able to coexist and cooperate rather than firing at each other across some imaginary web framework DMZ.

Pyramid Uses a Zope Component Architecture (”ZCA”) Registry

Pyramid uses a Zope Component Architecture (ZCA) ”component registry” as its application registry
under the hood. This is a point of some contention. Pyramid is of a Zope pedigree, so it was natural for its
developers to use a ZCA registry at its inception. However, we understand that using a ZCA registry has
issues and consequences, which we’ve attempted to address as best we can. Here’s an introspection about
Pyramid use of a ZCA registry, and the trade-offs its usage involves.

0.1. Front Matter 13


The Pyramid Web Framework, Version 2.0.2

Problems

The global API that may be used to access data in a ZCA component registry is not particularly pretty
or intuitive, and sometimes it’s just plain obtuse. Likewise, the conceptual load on a casual source code
reader of code that uses the ZCA global API is somewhat high. Consider a ZCA neophyte reading the
code that performs a typical ”unnamed utility” lookup using the zope.component.getUtility()
global API:

1 from pyramid.interfaces import ISettings


2 from zope.component import getUtility
3 settings = getUtility(ISettings)

After this code runs, settings will be a Python dictionary. But it’s unlikely that any civilian would
know that just by reading the code. There are a number of comprehension issues with the bit of code
above that are obvious.
First, what’s a ”utility”? Well, for the purposes of this discussion, and for the purpose of the code above,
it’s just not very important. If you really want to know, you can read this. However, still, readers of such
code need to understand the concept in order to parse it. This is problem number one.
Second, what’s this ISettings thing? It’s an interface. Is that important here? Not really, we’re just
using it as a key for some lookup based on its identity as a marker: it represents an object that has the
dictionary API, but that’s not very important in this context. That’s problem number two.
Third of all, what does the getUtility function do? It’s performing a lookup for the ISettings
”utility” that should return... well, a utility. Note how we’ve already built up a dependency on the under-
standing of an interface and the concept of ”utility” to answer this question: a bad sign so far. Note also
that the answer is circular, a really bad sign.
Fourth, where does getUtility look to get the data? Well, the ”component registry” of course. What’s
a component registry? Problem number four.
Fifth, assuming you buy that there’s some magical registry hanging around, where is this registry? Homina
homina... ”around”? That’s sort of the best answer in this context (a more specific answer would require
knowledge of internals). Can there be more than one registry? Yes. So in which registry does it find the
registration? Well, the ”current” registry of course. In terms of Pyramid, the current registry is a thread
local variable. Using an API that consults a thread local makes understanding how it works non-local.
You’ve now bought in to the fact that there’s a registry that is just hanging around. But how does the
registry get populated? Why, via code that calls directives like config.add_view. In this particular
case, however, the registration of ISettings is made by the framework itself under the hood: it’s not
present in any user configuration. This is extremely hard to comprehend. Problem number six.
Clearly there’s some amount of cognitive load here that needs to be borne by a reader of code that extends
the Pyramid framework due to its use of the ZCA, even if they are already an expert Python programmer
and an expert in the domain of web applications. This is suboptimal.

14 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Ameliorations

First, the primary amelioration: Pyramid does not expect application developers to understand ZCA con-
cepts or any of its APIs. If an application developer needs to understand a ZCA concept or API during the
creation of a Pyramid application, we’ve failed on some axis.

Instead the framework hides the presence of the ZCA registry behind special-purpose API functions that
do use ZCA APIs. Take for example the request.authenticated_userid function, which re-
turns the userid present in the current request or None if no userid is present in the current request. The
application developer calls it like so:

1 userid = request.authenticated_userid

They now have the current user id.

Under its hood however, the implementation of authenticated_userid is this:

1 def authenticated_userid(request):
2 """ Return the userid of the currently authenticated user or
3 ``None`` if there is no security policy in effect or there
4 is no currently authenticated user. """
5

6 registry = request.registry # the ZCA component registry


7 policy = registry.queryUtility(ISecurityPolicy)
8 if policy is None:
9 return None
10 return policy.authenticated_userid(request)

Using such wrappers, we strive to always hide the ZCA API from application developers. Application
developers should just never know about the ZCA API; they should call a Python function with some
object germane to the domain as an argument, and it should return a result. A corollary that follows is that
any reader of an application that has been written using Pyramid needn’t understand the ZCA API either.

Hiding the ZCA API from application developers and code readers is a form of enhancing domain speci-
ficity. No application developer wants to need to understand the small, detailed mechanics of how a web
framework does its thing. People want to deal in concepts that are closer to the domain they’re working
in. For example, web developers want to know about users, not utilities. Pyramid uses the ZCA as an
implementation detail, not as a feature which is exposed to end users.

However, unlike application developers, framework developers, including people who want to override
Pyramid functionality via preordained framework plugpoints like traversal or view lookup, must under-
stand the ZCA registry API.

0.1. Front Matter 15


The Pyramid Web Framework, Version 2.0.2

Pyramid framework developers were so concerned about conceptual load issues of the ZCA registry
API that a replacement registry implementation named repoze.component was actually developed.
Though this package has a registry implementation which is fully functional and well-tested, and its API
is much nicer than the ZCA registry API, work on it was largely abandoned, and it is not used in Pyramid.
We continued to use a ZCA registry within Pyramid because it ultimately proved a better fit.

We continued using ZCA registry rather than disusing it in favor of using the registry implementation
in repoze.component largely because the ZCA concept of interfaces provides for use of an interface
hierarchy, which is useful in a lot of scenarios (such as context type inheritance). Coming up with a
marker type that was something like an interface that allowed for this functionality seemed like it was just
reinventing the wheel.

Making framework developers and extenders understand the ZCA registry API is a trade-off. We (the
Pyramid developers) like the features that the ZCA registry gives us, and we have long-ago borne the
weight of understanding what it does and how it works. The authors of Pyramid understand the ZCA
deeply and can read code that uses it as easily as any other code.

But we recognize that developers who might want to extend the framework are not as comfortable with
the ZCA registry API as the original developers. So for the purpose of being kind to third-party Pyramid
framework developers, we’ve drawn some lines in the sand.

In all core code, we’ve made use of ZCA global API functions, such as zope.component.
getUtility and zope.component.getAdapter, the exception instead of the rule. So instead
of:

1 from pyramid.interfaces import ISecurityPolicy


2 from zope.component import getUtility
3 policy = getUtility(ISecurityPolicy)

Pyramid code will usually do:

1 from pyramid.interfaces import ISecurityPolicy


2 from pyramid.threadlocal import get_current_registry
3 registry = get_current_registry()
4 policy = registry.getUtility(ISecurityPolicy)

While the latter is more verbose, it also arguably makes it more obvious what’s going on. All of the
Pyramid core code uses this pattern rather than the ZCA global API.

16 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Rationale

Here are the main rationales involved in the Pyramid decision to use the ZCA registry:

• History. A nontrivial part of the answer to this question is ”history”. Much of the design of Pyramid
is stolen directly from Zope. Zope uses the ZCA registry to do a number of tricks. Pyramid mimics
these tricks, and, because the ZCA registry works well for that set of tricks, Pyramid uses it for the
same purposes. For example, the way that Pyramid maps a request to a view callable using traversal
is lifted almost entirely from Zope. The ZCA registry plays an important role in the particulars of
how this request to view mapping is done.

• Features. The ZCA component registry essentially provides what can be considered something like
a superdictionary, which allows for more complex lookups than retrieving a value based on a single
key. Some of this lookup capability is very useful for end users, such as being able to register a view
that is only found when the context is some class of object, or when the context implements some
interface.

• Singularity. There’s only one place where ”application configuration” lives in a Pyramid application:
in a component registry. The component registry answers questions made to it by the framework at
runtime based on the configuration of an application. Note: ”an application” is not the same as ”a
process”; multiple independently configured copies of the same Pyramid application are capable of
running in the same process space.

• Composability. A ZCA component registry can be populated imperatively, or there’s an existing


mechanism to populate a registry via the use of a configuration file (ZCML, via the optional pyra-
mid_zcml package). We didn’t need to write a frontend from scratch to make use of configuration-
file-driven registry population.

• Pluggability. Use of the ZCA registry allows for framework extensibility via a well-defined and
widely understood plugin architecture. As long as framework developers and extenders understand
the ZCA registry, it’s possible to extend Pyramid almost arbitrarily. For example, it’s relatively
easy to build a directive that registers several views all at once, allowing app developers to use that
directive as a ”macro” in code that they write. This is somewhat of a differentiating feature from
other (non-Zope) frameworks.

• Testability. Judicious use of the ZCA registry in framework code makes testing that code slightly
easier. Instead of using monkeypatching or other facilities to register mock objects for testing, we
inject dependencies via ZCA registrations, then use lookups in the code to find our mock objects.

• Speed. The ZCA registry is very fast for a specific set of complex lookup scenarios that Pyramid
uses, having been optimized through the years for just these purposes. The ZCA registry contains
optional C code for this purpose which demonstrably has no (or very few) bugs.

• Ecosystem. Many existing Zope packages can be used in Pyramid with few (or no) changes due to
our use of the ZCA registry.

0.1. Front Matter 17


The Pyramid Web Framework, Version 2.0.2

Conclusion

If you only develop applications using Pyramid, there’s not much to complain about here. You just should
never need to understand the ZCA registry API; use documented Pyramid APIs instead. However, you
may be an application developer who doesn’t read API documentation. Instead you read the raw source
code, and because you haven’t read the API documentation, you don’t know what functions, classes, and
methods even form the Pyramid API. As a result, you’ve now written code that uses internals, and you’ve
painted yourself into a conceptual corner, needing to wrestle with some ZCA-using implementation detail.
If this is you, it’s extremely hard to have a lot of sympathy for you. You’ll either need to get familiar with
how we’re using the ZCA registry or you’ll need to use only the documented APIs; that’s why we document
them as APIs.

If you extend or develop Pyramid (create new directives, use some of the more obscure hooks as described
in Using Hooks, or work on the Pyramid core code), you will be faced with needing to understand at least
some ZCA concepts. In some places it’s used unabashedly, and will be forever. We know it’s quirky, but
it’s also useful and fundamentally understandable if you take the time to do some reading about it.

Pyramid ”Encourages Use of ZCML”

ZCML is a configuration language that can be used to configure the Zope Component Architecture registry
that Pyramid uses for application configuration. Often people claim that Pyramid ”needs ZCML”.

It doesn’t. In Pyramid 1.0, ZCML doesn’t ship as part of the core; instead it ships in the pyramid_zcml
add-on package, which is completely optional. No ZCML is required at all to use Pyramid, nor any other
sort of frameworky declarative frontend to application configuration.

Pyramid Does Traversal, and I Don’t Like Traversal

In Pyramid, traversal is the act of resolving a URL path to a resource object in a resource tree. Some
people are uncomfortable with this notion, and believe it is wrong. Thankfully if you use Pyramid and you
don’t want to model your application in terms of a resource tree, you needn’t use it at all. Instead use URL
dispatch to map URL paths to views.

The idea that some folks believe traversal is unilaterally wrong is understandable. The people who believe
it is wrong almost invariably have all of their data in a relational database. Relational databases aren’t
naturally hierarchical, so traversing one like a tree is not possible.

However, folks who deem traversal unilaterally wrong are neglecting to take into account that many per-
sistence mechanisms are hierarchical. Examples include a filesystem, an LDAP database, a ZODB (or

18 CONTENTS
The Pyramid Web Framework, Version 2.0.2

another type of graph) database, an XML document, and the Python module namespace. It is often conve-
nient to model the frontend to a hierarchical data store as a graph, using traversal to apply views to objects
that either are the resources in the tree being traversed (such as in the case of ZODB) or at least ones which
stand in for them (such as in the case of wrappers for files from the filesystem).

Also, many website structures are naturally hierarchical, even if the data which drives them isn’t. For
example, newspaper websites are often extremely hierarchical: sections within sections within sections,
ad infinitum. If you want your URLs to indicate this structure, and the structure is indefinite (the number
of nested sections can be ”N” instead of some fixed number), a resource tree is an excellent way to model
this, even if the backend is a relational database. In this situation, the resource tree is just a site structure.

Traversal also offers better composability of applications than URL dispatch, because it doesn’t rely on
a fixed ordering of URL matching. You can compose a set of disparate functionality (and add to it later)
around a mapping of view to resource more predictably than trying to get the right ordering of URL pattern
matching.

But the point is ultimately moot. If you don’t want to use traversal, you needn’t. Use URL dispatch instead.

Pyramid Does URL Dispatch, and I Don’t Like URL Dispatch

In Pyramid, url dispatch is the act of resolving a URL path to a view callable by performing pattern match-
ing against some set of ordered route definitions. The route definitions are examined in order: the first
pattern which matches is used to associate the URL with a view callable.

Some people are uncomfortable with this notion, and believe it is wrong. These are usually people who
are steeped deeply in Zope. Zope does not provide any mechanism except traversal to map code to URLs.
This is mainly because Zope effectively requires use of ZODB, which is a hierarchical object store. Zope
also supports relational databases, but typically the code that calls into the database lives somewhere in
the ZODB object graph (or at least is a view related to a node in the object graph), and traversal is required
to reach this code.

I’ll argue that URL dispatch is ultimately useful, even if you want to use traversal as well. You can actu-
ally combine URL dispatch and traversal in Pyramid (see Combining Traversal and URL Dispatch). One
example of such a usage: if you want to emulate something like Zope 2’s ”Zope Management Interface”
UI on top of your object graph (or any administrative interface), you can register a route like config.
add_route('manage', '/manage/*traverse') and then associate ”management” views in
your code by using the route_name argument to a view configuration, e.g., config.add_view('.
some.callable', context=".some.Resource", route_name='manage'). If you wire
things up this way, someone then walks up to, for example, /manage/ob1/ob2, they might be pre-
sented with a management interface, but walking up to /ob1/ob2 would present them with the default
object view. There are other tricks you can pull in these hybrid configurations if you’re clever (and maybe
masochistic) too.

0.1. Front Matter 19


The Pyramid Web Framework, Version 2.0.2

Also, if you are a URL dispatch hater, if you should ever be asked to write an application that must use
some legacy relational database structure, you might find that using URL dispatch comes in handy for one-
off associations between views and URL paths. Sometimes it’s just pointless to add a node to the object
graph that effectively represents the entry point for some bit of code. You can just use a route and be done
with it. If a route matches, a view associated with the route will be called. If no route matches, Pyramid
falls back to using traversal.
But the point is ultimately moot. If you use Pyramid, and you really don’t want to use URL dispatch, you
needn’t use it at all. Instead, use traversal exclusively to map URL paths to views, just like you do in Zope.

Pyramid Views Do Not Accept Arbitrary Keyword Arguments

Many web frameworks (Zope, TurboGears, Pylons 1.X, Django) allow for their variant of a view callable
to accept arbitrary keyword or positional arguments, which are filled in using values present in the
request.POST, request.GET, or route match dictionaries. For example, a Django view will ac-
cept positional arguments which match information in an associated ”urlconf” such as r'^polls/(?
P<poll_id>\d+)/$:

1 def aview(request, poll_id):


2 return HttpResponse(poll_id)

Zope likewise allows you to add arbitrary keyword and positional arguments to any method of a resource
object found via traversal:

1 from persistent import Persistent


2

3 class MyZopeObject(Persistent):
4 def aview(self, a, b, c=None):
5 return '%s %s %c' % (a, b, c)

When this method is called as the result of being the published callable, the Zope request object’s GET and
POST namespaces are searched for keys which match the names of the positional and keyword arguments
in the request, and the method is called (if possible) with its argument list filled with values mentioned
therein. TurboGears and Pylons 1.X operate similarly.
Out of the box, Pyramid is configured to have none of these features. By default Pyramid view callables
always accept only request and no other arguments. The rationale is, this argument specification match-
ing when done aggressively can be costly, and Pyramid has performance as one of its main goals. Therefore
we’ve decided to make people, by default, obtain information by interrogating the request object within
the view callable body instead of providing magic to do unpacking into the view argument list.
However, as of Pyramid 1.0a9, user code can influence the way view callables are expected to be called,
making it possible to compose a system out of view callables which are called with arbitrary arguments.
See Using a View Mapper.

20 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Pyramid Provides Too Few ”Rails”

By design, Pyramid is not a particularly opinionated web framework. It has a relatively parsimonious
feature set. It contains no built in ORM nor any particular database bindings. It contains no form generation
framework. It has no administrative web user interface. It has no built in text indexing. It does not dictate
how you arrange your code.

Such opinionated functionality exists in applications and frameworks built on top of Pyramid. It’s intended
that higher-level systems emerge built using Pyramid as a base.

See also:

See also Pyramid Applications Are Extensible; I Don’t Believe in Application Extensibility.

Pyramid Provides Too Many ”Rails”

Pyramid provides some features that other web frameworks do not. These are features meant for use cases
that might not make sense to you if you’re building a simple bespoke web application:

• An optional way to map URLs to code using traversal which implies a walk of a resource tree.

• The ability to aggregate Pyramid application configuration from multiple sources using pyramid.
config.Configurator.include().

• View and subscriber registrations made using interface objects instead of class objects (e.g., Using
Resource Interfaces in View Configuration).

• A declarative authorization system.

• Multiple separate I18N translation string factories, each of which can name its own domain.

These features are important to the authors of Pyramid. The Pyramid authors are often commissioned
to build CMS-style applications. Such applications are often frameworky because they have more than
one deployment. Each deployment requires a slightly different composition of sub-applications, and the
framework and sub-applications often need to be extensible. Because the application has more than one
deployment, pluggability and extensibility is important, as maintaining multiple forks of the application,
one per deployment, is extremely undesirable. Because it’s easier to extend a system that uses traversal
from the outside than it is to do the same in a system that uses URL dispatch, each deployment uses
a resource tree composed of a persistent tree of domain model objects, and uses traversal to map view
callable code to resources in the tree. The resource tree contains very granular security declarations, as

0.1. Front Matter 21


The Pyramid Web Framework, Version 2.0.2

resources are owned and accessible by different sets of users. Interfaces are used to make unit testing and
implementation substitutability easier.

In a bespoke web application, usually there’s a single canonical deployment, and therefore no possibility of
multiple code forks. Extensibility is not required; the code is just changed in place. Security requirements
are often less granular. Using the features listed above will often be overkill for such an application.

If you don’t like these features, it doesn’t mean you can’t or shouldn’t use Pyramid. They are all optional,
and a lot of time has been spent making sure you don’t need to know about them up front. You can build
”Pylons 1.X style” applications using Pyramid that are purely bespoke by ignoring the features above. You
may find these features handy later after building a bespoke web application that suddenly becomes popular
and requires extensibility because it must be deployed in multiple locations.

Pyramid Is Too Big

”The Pyramid compressed tarball is larger than 2MB. It must be enormous!”

No. We just ship it with docs, test code, and scaffolding. Here’s a breakdown of what’s included in
subdirectories of the package tree:

docs/

3.6MB

pyramid/tests/

1.3MB

pyramid/scaffolds/

133KB

pyramid/ (except for pyramid/tests and pyramid/scaffolds)

812KB

Of the approximately 34K lines of Python code in the package, the code that actually has a chance of
executing during normal operation, excluding tests and scaffolding Python files, accounts for approximately
10K lines.

22 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Pyramid Has Too Many Dependencies

Over time, we’ve made lots of progress on reducing the number of packaging dependencies Pyramid has
had. Pyramid 1.2 had 15 of them. Pyramid 1.3 and 1.4 had 12 of them. The current release as of this
writing, Pyramid 1.5, has only 7. This number is unlikely to become any smaller.

A port to Python 3 completed in Pyramid 1.3 helped us shed a good number of dependencies by forcing
us to make better packaging decisions. Removing Chameleon and Mako templating system dependencies
in the Pyramid core in 1.5 let us shed most of the remainder of them.

Pyramid ”Cheats” to Obtain Speed

Complaints have been lodged by other web framework authors at various times that Pyramid ”cheats” to
gain performance. One claimed cheating mechanism is our use (transitively) of the C extensions provided
by zope.interface to do fast lookups. Another claimed cheating mechanism is the religious avoidance
of extraneous function calls.

If there’s such a thing as cheating to get better performance, we want to cheat as much as possible. We
optimize Pyramid aggressively. This comes at a cost. The core code has sections that could be expressed
with more readability. As an amelioration, we’ve commented these sections liberally.

Pyramid Gets Its Terminology Wrong (”MVC”)

”I’m a MVC web framework user, and I’m confused. Pyramid calls the controller a view! And it doesn’t
have any controllers.”

If you are in this camp, you might have come to expect things about how your existing ”MVC” framework
uses its terminology. For example, you probably expect that models are ORM models, controllers are
classes that have methods that map to URLs, and views are templates. Pyramid indeed has each of these
concepts, and each probably works almost exactly like your existing ”MVC” web framework. We just don’t
use the MVC terminology, as we can’t square its usage in the web framework space with historical reality.

People very much want to give web applications the same properties as common desktop GUI platforms
by using similar terminology, and to provide some frame of reference for how various components in the
common web framework might hang together. But in the opinion of the author, ”MVC” doesn’t match the
web very well in general. Quoting from the Model-View-Controller Wikipedia entry:

Though MVC comes in different flavors, control flow is generally as follows:

0.1. Front Matter 23


The Pyramid Web Framework, Version 2.0.2

The user interacts with the user interface in some way (for example, presses a
mouse button).

The controller handles the input event from the user interface, often via a registered
handler or callback and converts the event into appropriate user action, understand-
able for the model.

The controller notifies the model of the user action, possibly resulting in a change in
the model’s state. (For example, the controller updates the user’s shopping cart.)[5]

A view queries the model in order to generate an appropriate user interface (for
example, the view lists the shopping cart’s contents). Note that the view gets its
own data from the model.

The controller may (in some implementations) issue a general instruction to the
view to render itself. In others, the view is automatically notified by the model of
changes in state (Observer) which require a screen update.

The user interface waits for further user interactions, which restarts the cycle.

To the author, it seems as if someone edited this Wikipedia definition, tortuously couching concepts in the
most generic terms possible in order to account for the use of the term ”MVC” by current web frameworks.
I doubt such a broad definition would ever be agreed to by the original authors of the MVC pattern. But
even so, it seems most MVC web frameworks fail to meet even this falsely generic definition.

For example, do your templates (views) always query models directly as is claimed in ”note that the view
gets its own data from the model”? Probably not. My ”controllers” tend to do this, massaging the data
for easier use by the ”view” (template). What do you do when your ”controller” returns JSON? Do your
controllers use a template to generate JSON? If not, what’s the ”view” then? Most MVC-style GUI web
frameworks have some sort of event system hooked up that lets the view detect when the model changes.
The web just has no such facility in its current form; it’s effectively pull-only.

So, in the interest of not mistaking desire with reality, and instead of trying to jam the square peg that is
the web into the round hole of ”MVC”, we just punt and say there are two things: resources and views.
The resource tree represents a site structure, the view presents a resource. The templates are really just an
implementation detail of any given view. A view doesn’t need a template to return a response. There’s no
”controller”; it just doesn’t exist. The ”model” is either represented by the resource tree or by a ”domain
model” (like an SQLAlchemy model) that is separate from the framework entirely. This seems to us like
more reasonable terminology, given the current constraints of the web.

24 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Pyramid Applications Are Extensible; I Don’t Believe in Application Extensibility

Any Pyramid application written obeying certain constraints is extensible. This feature is discussed in
the Pyramid documentation chapters named Extending an Existing Pyramid Application and Advanced
Configuration. It is made possible by the use of the Zope Component Architecture within Pyramid.

”Extensible” in this context means:

• The behavior of an application can be overridden or extended in a particular deployment of the


application without requiring that the deployer modify the source of the original application.

• The original developer is not required to anticipate any extensibility plug points at application cre-
ation time to allow fundamental application behavior to be overridden or extended.

• The original developer may optionally choose to anticipate an application-specific set of plug points,
which may be hooked by a deployer. If they choose to use the facilities provided by the ZCA, the
original developer does not need to think terribly hard about the mechanics of introducing such a
plug point.

Many developers seem to believe that creating extensible applications is not worth it. They instead sug-
gest that modifying the source of a given application for each deployment to override behavior is more
reasonable. Much discussion about version control branching and merging typically ensues.

It’s clear that making every application extensible isn’t required. The majority of web applications only
have a single deployment, and thus needn’t be extensible at all. However some web applications have
multiple deployments, and others have many deployments. For example, a generic content management
system (CMS) may have basic functionality that needs to be extended for a particular deployment. That
CMS may be deployed for many organizations at many places. Some number of deployments of this CMS
may be deployed centrally by a third party and managed as a group. It’s easier to be able to extend such a
system for each deployment via preordained plug points than it is to continually keep each software branch
of the system in sync with some upstream source. The upstream developers may change code in such a way
that your changes to the same codebase conflict with theirs in fiddly, trivial ways. Merging such changes
repeatedly over the lifetime of a deployment can be difficult and time consuming, and it’s often useful to
be able to modify an application for a particular deployment in a less invasive way.

If you don’t want to think about Pyramid application extensibility at all, you needn’t. You can ignore
extensibility entirely. However if you follow the set of rules defined in Extending an Existing Pyramid
Application, you don’t need to make your application extensible. Any application you write in the frame-
work just is automatically extensible at a basic level. The mechanisms that deployers use to extend it will
be necessarily coarse. Typically views, routes, and resources will be capable of being overridden. But for
most minor (and even some major) customizations, these are often the only override plug points neces-
sary. If the application doesn’t do exactly what the deployment requires, it’s often possible for a deployer
to override a view, route, or resource, and quickly make it do what they want it to do in ways not neces-
sarily anticipated by the original developer. Here are some example scenarios demonstrating the benefits
of such a feature.

0.1. Front Matter 25


The Pyramid Web Framework, Version 2.0.2

• If a deployment needs a different styling, the deployer may override the main template and the CSS
in a separate Python package which defines overrides.

• If a deployment needs an application page to do something differently, or to expose more or different


information, the deployer may override the view that renders the page within a separate Python
package.

• If a deployment needs an additional feature, the deployer may add a view to the override package.

As long as the fundamental design of the upstream package doesn’t change, these types of modifications
often survive across many releases of the upstream package without needing to be revisited.

Extending an application externally is not a panacea, and carries a set of risks similar to branching and
merging. Sometimes major changes upstream will cause you to revisit and update some of your modifica-
tions. But you won’t regularly need to deal with meaningless textual merge conflicts that trivial changes to
upstream packages often entail when it comes time to update the upstream package, because if you extend
an application externally, there just is no textual merge done. Your modifications will also, for whatever
it’s worth, be contained in one, canonical, well-defined place.

Branching an application and continually merging in order to get new features and bug fixes is clearly
useful. You can do that with a Pyramid application just as usefully as you can do it with any application.
But deployment of an application written in Pyramid makes it possible to avoid the need for this even if
the application doesn’t define any plug points ahead of time. It’s possible that promoters of competing web
frameworks dismiss this feature in favor of branching and merging because applications written in their
framework of choice aren’t extensible out of the box in a comparably fundamental way.

While Pyramid applications are fundamentally extensible even if you don’t write them with specific ex-
tensibility in mind, if you’re moderately adventurous, you can also take it a step further. If you learn more
about the Zope Component Architecture, you can optionally use it to expose other more domain-specific
configuration plug points while developing an application. The plug points you expose needn’t be as coarse
as the ones provided automatically by Pyramid itself. For example, you might compose your own direc-
tive that configures a set of views for a pre-baked purpose (e.g., restview or somesuch), allowing other
people to refer to that directive when they make declarations in the includeme of their customization
package. There is a cost for this: the developer of an application that defines custom plug points for its
deployers will need to understand the ZCA or they will need to develop their own similar extensibility
system.

Ultimately any argument about whether the extensibility features lent to applications by Pyramid are good
or bad is mostly pointless. You needn’t take advantage of the extensibility features provided by a particular
Pyramid application in order to affect a modification for a particular set of its deployments. You can
ignore the application’s extensibility plug points entirely, and use version control branching and merging
to manage application deployment modifications instead, as if you were deploying an application written
using any other web framework.

26 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Zope 3 Enforces ”TTW” Authorization Checks by Default; Pyramid Does Not

Challenge

Pyramid performs automatic authorization checks only at view execution time. Zope 3 wraps context
objects with a security proxy, which causes Zope 3 also to do security checks during attribute access. I
like this, because it means:

1) When I use the security proxy machinery, I can have a view that conditionally displays certain
HTML elements (like form fields) or prevents certain attributes from being modified depending on
the permissions that the accessing user possesses with respect to a context object.

2) I want to also expose my resources via a REST API using Twisted Web. If Pyramid performed au-
thorization based on attribute access via Zope3’s security proxies, I could enforce my authorization
policy in both Pyramid and in the Twisted-based system the same way.

Defense

Pyramid was developed by folks familiar with Zope 2, which has a ”through the web” security model. This
TTW security model was the precursor to Zope 3’s security proxies. Over time, as the Pyramid developers
(working in Zope 2) created such sites, we found authorization checks during code interpretation extremely
useful in a minority of projects. But much of the time, TTW authorization checks usually slowed down the
development velocity of projects that had no delegation requirements. In particular, if we weren’t allowing
untrusted users to write arbitrary Python code to be executed by our application, the burden of through the
web security checks proved too costly to justify. We (collectively) haven’t written an application on top of
which untrusted developers are allowed to write code in many years, so it seemed to make sense to drop
this model by default in a new web framework.

And since we tend to use the same toolkit for all web applications, it’s just never been a concern to be able
to use the same set of restricted-execution code under two different web frameworks.

Justifications for disabling security proxies by default notwithstanding, given that Zope 3 security proxies
are viral by nature, the only requirement to use one is to make sure you wrap a single object in a security
proxy and make sure to access that object normally when you want proxy security checks to happen. It
is possible to override the Pyramid traverser for a given application (see Changing the Traverser). To
get Zope3-like behavior, it is possible to plug in a different traverser which returns Zope3-security-proxy-
wrapped objects for each traversed object (including the context and the root). This would have the effect
of creating a more Zope3-like environment without much effort.

0.1. Front Matter 27


The Pyramid Web Framework, Version 2.0.2

Pyramid uses its own HTTP exception class hierarchy rather than webob.exc

New in version 1.1.

The HTTP exception classes defined in pyramid.httpexceptions are very much like the ones de-
fined in webob.exc, (e.g., HTTPNotFound or HTTPForbidden). They have the same names and
largely the same behavior, and all have a very similar implementation, but not the same identity. Here’s
why they have a separate identity.

• Making them separate allows the HTTP exception classes to subclass pyramid.response.
Response. This speeds up response generation slightly due to the way the Pyramid router works.
The same speed up could be gained by monkeypatching webob.response.Response, but it’s
usually the case that monkeypatching turns out to be evil and wrong.

• Making them separate allows them to provide alternate __call__ logic, which also speeds up
response generation.

• Making them separate allows the exception classes to provide for the proper value of Request-
Class (pyramid.request.Request).

• Making them separate gives us freedom from thinking about backwards compatibility code present
in webob.exc related to Python 2.4, which we no longer support in Pyramid 1.1+.

• We change the behavior of two classes (HTTPNotFound and HTTPForbidden) in the module
so that they can be used by Pyramid internally for notfound and forbidden exceptions.

• Making them separate allows us to influence the docstrings of the exception classes to provide
Pyramid-specific documentation.

• Making them separate allows us to silence a stupid deprecation warning under Python 2.6 when the
response objects are used as exceptions (related to self.message).

Pyramid has simpler traversal machinery than does Zope

Zope’s default traverser:

• Allows developers to mutate the traversal name stack while traversing (they can add and remove path
elements).

• Attempts to use an adaptation to obtain the next element in the path from the currently traversed
object, falling back to __bobo_traverse__, __getitem__, and eventually __getattr__.

28 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Zope’s default traverser allows developers to mutate the traversal name stack during traversal by mutat-
ing REQUEST['TraversalNameStack']. Pyramid’s default traverser (pyramid.traversal.
ResourceTreeTraverser) does not offer a way to do this. It does not maintain a stack as a request
attribute and, even if it did, it does not pass the request to resource objects while it’s traversing. While it
was handy at times, this feature was abused in frameworks built atop Zope (like CMF and Plone), often
making it difficult to tell exactly what was happening when a traversal didn’t match a view. I felt it was
better for folks that wanted the feature to make them replace the traverser rather than build that particular
honey pot in to the default traverser.

Zope uses multiple mechanisms to attempt to obtain the next element in the resource tree based on a name.
It first tries an adaptation of the current resource to ITraversable, and if that fails, it falls back to
attempting a number of magic methods on the resource (__bobo_traverse__, __getitem__, and
__getattr__). My experience while both using Zope and attempting to reimplement its publisher in
repoze.zope2 led me to believe the following:

• The default traverser should be as simple as possible. Zope’s publisher is somewhat difficult to
follow and replicate due to the fallbacks it tried when one traversal method failed. It is also slow.

• The entire traverser should be replaceable, not just elements of the traversal machinery. Pyramid
has a few big components rather than a plethora of small ones. If the entire traverser is replaceable,
it’s an antipattern to make portions of the default traverser replaceable. Doing so is a ”knobs on
knobs” pattern, which is unfortunately somewhat endemic in Zope. In a ”knobs on knobs” pattern, a
replaceable subcomponent of a larger component is made configurable using the same configuration
mechanism that can be used to replace the larger component. For example, in Zope, you can replace
the default traverser by registering an adapter. But you can also (or alternately) control how the
default traverser traverses by registering one or more adapters. As a result of being able to either
replace the larger component entirely or turn knobs on the default implementation of the larger
component, no one understands when (or whether) they should ever override the larger component
entirely. This results, over time, in a rusting together of the larger ”replaceable” component and
the framework itself because people come to depend on the availability of the default component
in order just to turn its knobs. The default component effectively becomes part of the framework,
which entirely subverts the goal of making it replaceable. In Pyramid, typically if a component is
replaceable, it will itself have no knobs (it will be solid state). If you want to influence behavior
controlled by that component, you will replace the component instead of turning knobs attached to
the component.

Microframeworks have smaller Hello World programs

Self-described ”microframeworks” exist. Bottle and Flask are two that are becoming popular. Bobo doesn’t
describe itself as a microframework, but its intended user base is much the same. Many others exist. We’ve
even (only as a teaching tool, not as any sort of official project) created one using Pyramid. The videos use
BFG, a precursor to Pyramid, but the resulting code is available for Pyramid too). Microframeworks are

0.1. Front Matter 29


The Pyramid Web Framework, Version 2.0.2

small frameworks with one common feature: each allows its users to create a fully functional application
that lives in a single Python file.

Some developers and microframework authors point out that Pyramid’s ”hello world” single-file program
is longer (by about five lines) than the equivalent program in their favorite microframework. Guilty as
charged.

This loss isn’t for lack of trying. Pyramid is useful in the same circumstance in which microframe-
works claim dominance: single-file applications. But Pyramid doesn’t sacrifice its ability to credibly
support larger applications in order to achieve ”hello world” lines of code parity with the current crop of
microframeworks. Pyramid’s design instead tries to avoid some common pitfalls associated with naive
declarative configuration schemes. The subsections which follow explain the rationale.

Application programmers don’t control the module-scope codepath (import-time side-


effects are evil)

Imagine a directory structure with a set of Python files in it:

.
|-- app.py
|-- app2.py
`-- config.py

The contents of app.py:

1 from config import decorator


2 from config import L
3 import pprint
4

5 @decorator
6 def foo():
7 pass
8

9 if __name__ == '__main__':
10 import app2
11 pprint.pprint(L)

The contents of app2.py:

30 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 import app
2

3 @app.decorator
4 def bar():
5 pass

The contents of config.py:

1 L = []
2

3 def decorator(func):
4 L.append(func)
5 return func

If we cd to the directory that holds these files, and we run python app.py, given the directory structure
and code above, what happens? Presumably, our decorator decorator will be used twice, once by the
decorated function foo in app.py, and once by the decorated function bar in app2.py. Since each
time the decorator is used, the list L in config.py is appended to, we’d expect a list with two elements
to be printed, right? Sadly, no:

[chrism@thinko]$ python app.py


[<function foo at 0x7f4ea41ab1b8>,
<function foo at 0x7f4ea41ab230>,
<function bar at 0x7f4ea41ab2a8>]

By visual inspection, that outcome (three different functions in the list) seems impossible. We defined only
two functions, and we decorated each of those functions only once, so we believe that the decorator
decorator will run only twice. However, what we believe is in fact wrong, because the code at module
scope in our app.py module was executed twice. The code is executed once when the script is run as
__main__ (via python app.py), and then it is executed again when app2.py imports the same file
as app.

What does this have to do with our comparison to microframeworks? Many microframeworks in the current
crop (e.g., Bottle and Flask) encourage you to attach configuration decorators to objects defined at module
scope. These decorators execute arbitrarily complex registration code, which populates a singleton registry
that is a global which is in turn defined in external Python module. This is analogous to the above example:
the ”global registry” in the above example is the list L.

Let’s see what happens when we use the same pattern with the Groundhog microframework. Replace the
contents of app.py above with this:

0.1. Front Matter 31


The Pyramid Web Framework, Version 2.0.2

1 from config import gh


2

3 @gh.route('/foo/')
4 def foo():
5 return 'foo'
6

7 if __name__ == '__main__':
8 import app2
9 pprint.pprint(L)

Replace the contents of app2.py above with this:

1 import app
2

3 @app.gh.route('/bar/')
4 def bar():
5 'return bar'

Replace the contents of config.py above with this:

1 from groundhog import Groundhog


2 gh = Groundhog('myapp', 'seekrit')

How many routes will be registered within the routing table of the ”gh” Groundhog application? If you
answered three, you are correct. How many would a casual reader (and any sane developer) expect to be
registered? If you answered two, you are correct. Will the double registration be a problem? With our
Groundhog framework’s route method backing this application, not really. It will slow the application
down a little bit, because it will need to miss twice for a route when it does not match. Will it be a problem
with another framework, another application, or another decorator? Who knows. You need to understand
the application in its totality, the framework in its totality, and the chronology of execution to be able to
predict what the impact of unintentional code double-execution will be.

The encouragement to use decorators which perform population of an external registry has an unintended
consequence: the application developer now must assert ownership of every code path that executes Python
module scope code. Module-scope code is presumed by the current crop of decorator-based microframe-
works to execute once and only once. If it executes more than once, weird things will start to happen. It
is up to the application developer to maintain this invariant. Unfortunately, in reality this is an impossible
task, because Python programmers do not own the module scope code path, and never will. Anyone who
tries to sell you on the idea that they do so is simply mistaken. Test runners that you may want to use to run
your code’s tests often perform imports of arbitrary code in strange orders that manifest bugs like the one
demonstrated above. API documentation generation tools do the same. Some people even think it’s safe

32 CONTENTS
The Pyramid Web Framework, Version 2.0.2

to use the Python reload command, or delete objects from sys.modules, each of which has hilarious
effects when used against code that has import-time side effects.

Global registry-mutating microframework programmers therefore will at some point need to start reading
the tea leaves about what might happen if module scope code gets executed more than once, like we do in
the previous paragraph. When Python programmers assume they can use the module-scope code path to
run arbitrary code (especially code which populates an external registry), and this assumption is challenged
by reality, the application developer is often required to undergo a painful, meticulous debugging process
to find the root cause of an inevitably obscure symptom. The solution is often to rearrange application
import ordering, or move an import statement from module-scope into a function body. The rationale for
doing so can never be expressed adequately in the commit message which accompanies the fix, and can’t
be documented succinctly enough for the benefit of the rest of the development team so that the problem
never happens again. It will happen again, especially if you are working on a project with other people who
haven’t yet internalized the lessons you learned while you stepped through module-scope code using pdb.
This is a very poor situation in which to find yourself as an application developer: you probably didn’t
even know you or your team signed up for the job, because the documentation offered by decorator-based
microframeworks don’t warn you about it.

Folks who have a large investment in eager decorator-based configuration that populates an external data
structure (such as microframework authors) may argue that the set of circumstances I outlined above is
anomalous and contrived. They will argue that it just will never happen. If you never intend your applica-
tion to grow beyond one or two or three modules, that’s probably true. However, as your codebase grows,
and becomes spread across a greater number of modules, the circumstances in which module-scope code
will be executed multiple times will become more and more likely to occur and less and less predictable.
It’s not responsible to claim that double-execution of module-scope code will never happen. It will; it’s
just a matter of luck, time, and application complexity.

If microframework authors do admit that the circumstance isn’t contrived, they might then argue that real
damage will never happen as the result of the double-execution (or triple-execution, etc.) of module scope
code. You would be wise to disbelieve this assertion. The potential outcomes of multiple execution are
too numerous to predict because they involve delicate relationships between application and framework
code as well as chronology of code execution. It’s literally impossible for a framework author to know
what will happen in all circumstances. But even if given the gift of omniscience for some limited set of
circumstances, the framework author almost certainly does not have the double-execution anomaly in mind
when coding new features. They’re thinking of adding a feature, not protecting against problems that might
be caused by the 1% multiple execution case. However, any 1% case may cause 50% of your pain on a
project, so it’d be nice if it never occurred.

Responsible microframeworks actually offer a back-door way around the problem. They allow you to
disuse decorator-based configuration entirely. Instead of requiring you to do the following:

0.1. Front Matter 33


The Pyramid Web Framework, Version 2.0.2

1 gh = Groundhog('myapp', 'seekrit')
2

3 @gh.route('/foo/')
4 def foo():
5 return 'foo'
6

7 if __name__ == '__main__':
8 gh.run()

They allow you to disuse the decorator syntax and go almost all-imperative:

1 def foo():
2 return 'foo'
3

4 gh = Groundhog('myapp', 'seekrit')
5

6 if __name__ == '__main__':
7 gh.add_route(foo, '/foo/')
8 gh.run()

This is a generic mode of operation that is encouraged in the Pyramid documentation. Some existing
microframeworks (Flask, in particular) allow for it as well. None (other than Pyramid) encourage it. If
you never expect your application to grow beyond two or three or four or ten modules, it probably doesn’t
matter very much which mode you use. If your application grows large, however, imperative configuration
can provide better predictability.

Astute readers may notice that Pyramid has configuration decorators too. Aha! Don’t these decorators
have the same problems? No. These decorators do not populate an external Python module when they are
executed. They only mutate the functions (and classes and methods) to which they’re attached. These
mutations must later be found during a scan process that has a predictable and structured import phase.
Module-localized mutation is actually the best-case circumstance for double-imports. If a module only
mutates itself and its contents at import time, if it is imported twice, that’s OK, because each decorator
invocation will always be mutating an independent copy of the object to which it’s attached, not a shared
resource like a registry in another module. This has the effect that double-registrations will never be
performed.

34 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Routes need relative ordering

Consider the following simple Groundhog application:

1 from groundhog import Groundhog


2 app = Groundhog('myapp', 'seekrit')
3

4 @app.route('/admin')
5 def admin():
6 return '<html>admin page</html>'
7

8 @app.route('/:action')
9 def do_action(action):
10 if action == 'add':
11 return '<html>add</html>'
12 if action == 'delete':
13 return '<html>delete</html>'
14 return app.abort(404)
15

16 if __name__ == '__main__':
17 app.run()

If you run this application and visit the URL /admin, you will see the ”admin” page. This is the intended
result. However, what if you rearrange the order of the function definitions in the file?

1 from groundhog import Groundhog


2 app = Groundhog('myapp', 'seekrit')
3

4 @app.route('/:action')
5 def do_action(action):
6 if action == 'add':
7 return '<html>add</html>'
8 if action == 'delete':
9 return '<html>delete</html>'
10 return app.abort(404)
11

12 @app.route('/admin')
13 def admin():
14 return '<html>admin page</html>'
15

16 if __name__ == '__main__':
17 app.run()

If you run this application and visit the URL /admin, your app will now return a 404 error. This is proba-
bly not what you intended. The reason you see a 404 error when you rearrange function definition ordering

0.1. Front Matter 35


The Pyramid Web Framework, Version 2.0.2

is that routing declarations expressed via our microframework’s routing decorators have an ordering, and
that ordering matters.

In the first case, where we achieved the expected result, we first added a route with the pattern /admin,
then we added a route with the pattern /:action by virtue of adding routing patterns via decorators at
module scope. When a request with a PATH_INFO of /admin enters our application, the web framework
loops over each of our application’s route patterns in the order in which they were defined in our module.
As a result, the view associated with the /admin routing pattern will be invoked because it matches first.
All is right with the world.

In the second case, where we did not achieve the expected result, we first added a route with the pattern
/:action, then we added a route with the pattern /admin. When a request with a PATH_INFO of
/admin enters our application, the web framework loops over each of our application’s route patterns in
the order in which they were defined in our module. As a result, the view associated with the /:action
routing pattern will be invoked because it matches first. A 404 error is raised. This is not what we wanted;
it just happened due to the order in which we defined our view functions.

This is because Groundhog routes are added to the routing map in import order, and matched in the same
order when a request comes in. Bottle, like Groundhog, as of this writing, matches routes in the order in
which they’re defined at Python execution time. Flask, on the other hand, does not order route matching
based on import order. Instead it reorders the routes you add to your application based on their ”complex-
ity”. Other microframeworks have varying strategies to do route ordering.

Your application may be small enough where route ordering will never cause an issue. If your application
becomes large enough, however, being able to specify or predict that ordering as your application grows
larger will be difficult. At some point, you will likely need to start controlling route ordering more explicitly,
especially in applications that require extensibility.

If your microframework orders route matching based on complexity, you’ll need to understand what is
meant by ”complexity”, and you’ll need to attempt to inject a ”less complex” route to have it get matched
before any ”more complex” one to ensure that it’s tried first.

If your microframework orders its route matching based on relative import/execution of function decorator
definitions, you will need to ensure that you execute all of these statements in the ”right” order, and you’ll
need to be cognizant of this import/execution ordering as you grow your application or try to extend it.
This is a difficult invariant to maintain for all but the smallest applications.

In either case, your application must import the non-__main__ modules which contain configuration
decorations somehow for their configuration to be executed. Does that make you a little uncomfortable?
It should, because Application programmers don’t control the module-scope codepath (import-time side-
effects are evil).

36 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Pyramid uses neither decorator import time ordering nor does it attempt to divine the relative complexity
of one route to another as a means to define a route match ordering. In Pyramid, you have to maintain rel-
ative route ordering imperatively via the chronology of multiple executions of the pyramid.config.
Configurator.add_route() method. The order in which you repeatedly call add_route be-
comes the order of route matching.

If needing to maintain this imperative ordering truly bugs you, you can use traversal instead of route
matching, which is a completely declarative (and completely predictable) mechanism to map code to URLs.
While URL dispatch is easier to understand for small non-extensible applications, traversal is a great fit
for very large applications and applications that need to be arbitrarily extensible.

”Stacked object proxies” are too clever / thread locals are a nuisance

Some microframeworks use the import statement to get a handle to an object which is not logically
global:

1 from flask import request


2

3 @app.route('/login', methods=['POST', 'GET'])


4 def login():
5 error = None
6 if request.method == 'POST':
7 if valid_login(request.form['username'],
8 request.form['password']):
9 return log_the_user_in(request.form['username'])
10 else:
11 error = 'Invalid username/password'
12 # this is executed if the request method was GET or the
13 # credentials were invalid

The Pylons 1.X web framework uses a similar strategy. It calls these things ”Stacked Object Proxies”, so,
for purposes of this discussion, I’ll do so as well.

Import statements in Python (import foo, from bar import baz) are most frequently performed
to obtain a reference to an object defined globally within an external Python module. However, in normal
programs, they are never used to obtain a reference to an object that has a lifetime measured by the scope
of the body of a function. It would be absurd to try to import, for example, a variable named i representing
a loop counter defined in the body of a function. For example, we’d never try to import i from the code
below:

0.1. Front Matter 37


The Pyramid Web Framework, Version 2.0.2

1 def afunc():
2 for i in range(10):
3 print(i)

By its nature, the request object that is created as the result of a WSGI server’s call into a long-lived web
framework cannot be global, because the lifetime of a single request will be much shorter than the lifetime
of the process running the framework. A request object created by a web framework actually has more
similarity to the i loop counter in our example above than it has to any comparable importable object
defined in the Python standard library or in normal library code.

However, systems which use stacked object proxies promote locally scoped objects, such as request,
out to module scope, for the purpose of being able to offer users a nice spelling involving import. They,
for what I consider dubious reasons, would rather present to their users the canonical way of getting at
a request as from framework import request instead of a saner from myframework.
threadlocals import get_request; request = get_request(), even though the latter
is more explicit.

It would be most explicit if the microframeworks did not use thread local variables at all. Pyramid view
functions are passed a request object. Many of Pyramid’s APIs require that an explicit request object be
passed to them. It is possible to retrieve the current Pyramid request as a threadlocal variable, but it is an
”in case of emergency, break glass” type of activity. This explicitness makes Pyramid view functions more
easily unit testable, as you don’t need to rely on the framework to manufacture suitable ”dummy” request
(and other similarly-scoped) objects during test setup. It also makes them more likely to work on arbitrary
systems, such as async servers, that do no monkeypatching.

Explicitly WSGI

Some microframeworks offer a run() method of an application object that executes a default server
configuration for easy execution.

Pyramid doesn’t currently try to hide the fact that its router is a WSGI application behind a convenience
run() API. It just tells people to import a WSGI server and use it to serve up their Pyramid application
as per the documentation of that WSGI server.

The extra lines saved by abstracting away the serving step behind run() seems to have driven dubi-
ous second-order decisions related to its API in some microframeworks. For example, Bottle contains a
ServerAdapter subclass for each type of WSGI server it supports via its app.run() mechanism.
This means that there exists code in bottle.py that depends on the following modules: wsgiref,
flup, paste, cherrypy, fapws, tornado, google.appengine, twisted.web, diesel,
gevent, gunicorn, eventlet, and rocket. You choose the kind of server you want to run by

38 CONTENTS
The Pyramid Web Framework, Version 2.0.2

passing its name into the run method. In theory, this sounds great: I can try out Bottle on gunicorn
just by passing in a name! However, to fully test Bottle, all of these third-party systems must be installed
and functional. The Bottle developers must monitor changes to each of these packages and make sure their
code still interfaces properly with them. This increases the number of packages required for testing greatly;
this is a lot of requirements. It is likely difficult to fully automate these tests due to requirements conflicts
and build issues.

As a result, for single-file apps, we currently don’t bother to offer a run() shortcut. We tell folks to import
their WSGI server of choice and run it by hand. For the people who want a server abstraction layer, we
suggest that they use PasteDeploy. In PasteDeploy-based systems, the onus for making sure that the server
can interface with a WSGI application is placed on the server developer, not the web framework developer,
making it more likely to be timely and correct.

Wrapping up

Here’s a diagrammed version of the simplest pyramid application, where the inlined comments take into
account what we’ve discussed in the Microframeworks have smaller Hello World programs section.

1 from wsgiref.simple_server import make_server # explicitly WSGI


2 from pyramid.config import Configurator # to configure app registry
3 from pyramid.response import Response # explicit response, no threadlocal
4

5 def hello_world(request): # accept a request; no request threadlocal reqd


6 # explicit response object means no response threadlocal
7 return Response('Hello world!')
8

9 if __name__ == '__main__':
10 with Configurator() as config: # no global application object
11 config.add_view(hello_world) # explicit non-decorator registration
12 app = config.make_wsgi_app() # explicitly WSGI
13 server = make_server('0.0.0.0', 8080, app)
14 server.serve_forever() # explicitly WSGI

Pyramid doesn’t offer pluggable apps

It is ”Pyramidic” to compose multiple external sources into the same configuration using include().
Any number of includes can be done to compose an application; includes can even be done from within
other includes. Any directive can be used within an include that can be used outside of one (such as
add_view()).

0.1. Front Matter 39


The Pyramid Web Framework, Version 2.0.2

Pyramid has a conflict detection system that will throw an error if two included externals try to add the
same configuration in a conflicting way (such as both externals trying to add a route using the same name,
or both externals trying to add a view with the same set of predicates). It’s awful tempting to call this set
of features something that can be used to compose a system out of ”pluggable applications”. But in reality,
there are a number of problems with claiming this:

• The terminology is strained. Pyramid really has no notion of a plurality of ”applications”, just a
way to compose configuration from multiple sources to create a single WSGI application. That
WSGI application may gain behavior by including or disincluding configuration, but once it’s all
composed together, Pyramid doesn’t really provide any machinery which can be used to demarcate
the boundaries of one ”application” (in the sense of configuration from an external that adds routes,
views, etc) from another.

• Pyramid doesn’t provide enough ”rails” to make it possible to integrate truly honest-to-god,
download-an-app-from-a-random-place and-plug-it-in-to-create-a-system ”pluggable” applications.
Because Pyramid itself isn’t opinionated (it doesn’t mandate a particular kind of database, it of-
fers multiple ways to map URLs to code, etc), it’s unlikely that someone who creates something
application-like will be able to casually redistribute it to J. Random Pyramid User and have it just
work by asking him to config.include a function from the package. This is particularly true of very
high level components such as blogs, wikis, twitter clones, commenting systems, etc. The integrator
(the Pyramid developer who has downloaded a package advertised as a ”pluggable app”) will almost
certainly have made different choices about e.g. what type of persistence system he’s using, and for
the integrator to appease the requirements of the ”pluggable application”, he may be required to set
up a different database, make changes to his own code to prevent his application from shadowing
the pluggable app (or vice versa), and any other number of arbitrary changes.

For this reason, we claim that Pyramid has ”extensible” applications, not pluggable applications. Any
Pyramid application can be extended without forking it as long as its configuration statements have been
composed into things that can be pulled in via config.include.

It’s also perfectly reasonable for a single developer or team to create a set of interoperating components
which can be enabled or disabled by using config.include. That developer or team will be able to provide
the ”rails” (by way of making high-level choices about the technology used to create the project, so there
won’t be any issues with plugging all of the components together. The problem only rears its head when
the components need to be distributed to arbitrary users. Note that Django has a similar problem with
”pluggable applications” that need to work for arbitrary third parties, even though they provide many,
many more rails than does Pyramid. Even the rails they provide are not enough to make the ”pluggable
application” story really work without local modification.

Truly pluggable applications need to be created at a much higher level than a web framework, as no web
framework can offer enough constraints to really make them work out of the box. They really need to plug
into an application, instead. It would be a noble goal to build an application with Pyramid that provides
these constraints and which truly does offer a way to plug in applications (Joomla, Plone, Drupal come to
mind).

40 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Pyramid Has Zope Things In It, So It’s Too Complex

On occasion, someone will feel compelled to post a mailing list message that reads something like this:

had a quick look at pyramid ... too complex to me and not really
understand for which benefits.. I feel should consider whether it's time
for me to step back to django .. I always hated zope (useless ?)
complexity and I love simple way of thinking

(Paraphrased from a real email, actually.)

Let’s take this criticism point-by-point.

Too Complex

If you can understand this ”hello world” program, you can use Pyramid:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4

5 def hello_world(request):
6 return Response('Hello World!')
7

8 if __name__ == '__main__':
9 with Configurator() as config:
10 config.add_route('hello', '/')
11 config.add_view(hello_world, route_name='hello')
12 app = config.make_wsgi_app()
13 server = make_server('0.0.0.0', 6543, app)
14 server.serve_forever()

Pyramid has over 1200 pages of documentation (printed), covering topics from the very basic to the most
advanced. Nothing is left undocumented, quite literally. It also has an awesome, very helpful community.
Visit the #pyramid IRC channel on Libera.Chat and see.

0.1. Front Matter 41


The Pyramid Web Framework, Version 2.0.2

Hate Zope

I’m sorry you feel that way. The Zope brand has certainly taken its share of lumps over the years, and has
a reputation for being insular and mysterious. But the word ”Zope” is literally quite meaningless without
qualification. What part of Zope do you hate? ”Zope” is a brand, not a technology.

If it’s Zope2-the-web-framework, Pyramid is not that. The primary designers and developers of Pyramid,
if anyone, should know. We wrote Pyramid’s predecessor (repoze.bfg), in part, because we knew that
Zope 2 had usability issues and limitations. repoze.bfg (and now Pyramid) was written to address
these issues.

If it’s Zope3-the-web-framework, Pyramid is definitely not that. Making use of lots of Zope 3 technolo-
gies is territory already staked out by the Grok project. Save for the obvious fact that they’re both web
frameworks, Pyramid is very, very different than Grok. Grok exposes lots of Zope technologies to end
users. On the other hand, if you need to understand a Zope-only concept while using Pyramid, then we’ve
failed on some very basic axis.

If it’s just the word Zope: this can only be guilt by association. Because a piece of software internally uses
some package named zope.foo, it doesn’t turn the piece of software that uses it into ”Zope”. There is
a lot of great software written that has the word Zope in its name. Zope is not some sort of monolithic
thing, and a lot of its software is usable externally. And while it’s not really the job of this document to
defend it, Zope has been around for over 10 years and has an incredibly large, active community. If you
don’t believe this, https://pypi.org/search/?q=zope is an eye-opening reality check.

Love Simplicity

Years of effort have gone into honing this package and its documentation to make it as simple as humanly
possible for developers to use. Everything is a tradeoff, of course, and people have their own ideas about
what ”simple” is. You may have a style difference if you believe Pyramid is complex. Its developers
obviously disagree.

Other Challenges

Other challenges are encouraged to be sent to the Pylons-devel maillist. We’ll try to address them by
considering a design change, or at very least via exposition here.

42 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.2 Tutorials

0.2.1 Quick Tour of Pyramid

Pyramid lets you start small and finish big. This Quick Tour of Pyramid is for those who want to evaluate
Pyramid, whether you are new to Python web frameworks, or a pro in a hurry. For more detailed treatment
of each topic, give the Quick Tutorial for Pyramid a try.

If you would prefer to cut and paste the example code in this tour you may browse the source code located
in the Pyramid repository in the directory ”docs/quick_tour” <https://github.com/Pylons/pyramid/>. If
you have downloaded the source code, you will find the tour in the same location.

Installation

Once you have a standard Python environment setup, getting started with Pyramid is a breeze. Unfor-
tunately ”standard” is not so simple in Python. For this Quick Tour, it means Python, venv, pip, and
Setuptools.

To save a little bit of typing and to be certain that we use the modules, scripts, and packages installed in
our virtual environment, we’ll set an environment variable, too.

As an example, for Python 3 on Linux:

# set an environment variable to where you want your virtual␣


,→environment

$ export VENV=~/env
# create the virtual environment
$ python3 -m venv $VENV
# install pyramid
$ $VENV/bin/pip install pyramid
# or for a specific released version
$ $VENV/bin/pip install "pyramid==2.0.2"

For Windows:

0.2. Tutorials 43
The Pyramid Web Framework, Version 2.0.2

# set an environment variable to where you want your virtual␣


,→environment

c:\> set VENV=c:\env


# create the virtual environment
c:\> python -m venv %VENV%
# install pyramid
c:\> %VENV%\Scripts\pip install pyramid
# or for a specific released version
c:\> %VENV%\Scripts\pip install "pyramid==2.0.2"

As of version 2.0, Pyramid runs on Python 3 only. For simplicity, the remaining examples will show only
Unix commands.

See also:

See also: Quick Tutorial section on Requirements, Installing Pyramid on a Unix System, Before You Install,
Why use $VENV/bin/pip instead of source bin/activate, then pip, and Installing Pyramid on a Windows
System.

Hello World

Microframeworks have shown that learning starts best from a very small first step. Here’s a tiny application
in Pyramid:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4

6 def hello_world(request):
7 return Response('Hello World!')
8

10 if __name__ == '__main__':
11 with Configurator() as config:
12 config.add_route('hello', '/')
13 config.add_view(hello_world, route_name='hello')
14 app = config.make_wsgi_app()
15 server = make_server('0.0.0.0', 6543, app)
16 server.serve_forever()

This simple example is easy to run. Save this as app.py and run it:

44 CONTENTS
The Pyramid Web Framework, Version 2.0.2

$ $VENV/bin/python ./app.py

Next open http://localhost:6543/ in a browser, and you will see the Hello World! message.

New to Python web programming? If so, some lines in the module merit explanation:

1. Lines 6-7. Implement the view code that generates the response.

2. Line 10. if __name__ == '__main__': is Python’s way of saying ”Start here when running
from the command line”.

3. Lines 11-13. Use Pyramid’s configurator in a context manager to connect view code to a particular
URL route.

4. Lines 14-16. Publish a WSGI app using an HTTP server.

As shown in this example, the configurator plays a central role in Pyramid development. Building an
application from loosely-coupled parts via Application Configuration is a central idea in Pyramid, one that
we will revisit regularly in this Quick Tour.

See also:

See also: Quick Tutorial Hello World, Creating Your First Pyramid Application, and Todo List Application
in One File.

Handling web requests and responses

Developing for the web means processing web requests. As this is a critical part of a web application, web
developers need a robust, mature set of software for web requests.

Pyramid has always fit nicely into the existing world of Python web development (virtual environments,
packaging, cookiecutters, one of the first to embrace Python 3, etc.). Pyramid turned to the well-
regarded WebOb Python library for request and response handling. In our example above, Pyramid hands
hello_world a request that is based on WebOb.

Let’s see some features of requests and responses in action:

0.2. Tutorials 45
The Pyramid Web Framework, Version 2.0.2

def hello_world(request):
# Some parameters from a request such as /?name=lisa
url = request.url
name = request.params.get('name', 'No Name Provided')

body = 'URL %s with name: %s' % (url, name)


return Response(
content_type="text/plain",
body=body
)

In this Pyramid view, we get the URL being visited from request.url. Also if you visited http://
localhost:6543/?name=alice in a browser, the name is included in the body of the response:

URL http://localhost:6543/?name=alice with name: alice

Finally we set the response’s content type, and return the Response.

See also:

See also: Quick Tutorial Request and Response and Request and Response Objects.

Views

For the examples above, the hello_world function is a ”view”. In Pyramid views are the primary way
to accept web requests and return responses.

So far our examples place everything in one file:

• the view function

• its registration with the configurator

• the route to map it to an URL

• the WSGI application launcher

Let’s move the views out to their own views.py module and change the app.py to scan that module,
looking for decorators that set up the views.

First our revised app.py:

46 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3

4 if __name__ == '__main__':
5 with Configurator() as config:
6 config.add_route('home', '/')
7 config.add_route('hello', '/howdy')
8 config.add_route('redirect', '/goto')
9 config.add_route('exception', '/problem')
10 config.scan('views')
11 app = config.make_wsgi_app()
12 server = make_server('0.0.0.0', 6543, app)
13 server.serve_forever()

We added some more routes, but we also removed the view code. Our views and their registrations (via
decorators) are now in a module views.py, which is scanned via config.scan('views').

We now have a views.py module that is focused on handling requests and responses:

1 from html import escape


2

3 from pyramid.httpexceptions import HTTPFound


4 from pyramid.response import Response
5 from pyramid.view import view_config
6

8 # First view, available at http://localhost:6543/


9 @view_config(route_name='home')
10 def home_view(request):
11 return Response('<p>Visit <a href="/howdy?name=lisa">hello</a></p>')
12

13

14 # /howdy?name=alice which links to the next view


15 @view_config(route_name='hello')
16 def hello_view(request):
17 name = request.params.get('name', 'No Name')
18 body = '<p>Hi %s, this <a href="/goto">redirects</a></p>'
19 # Python html.escape to prevent Cross-Site Scripting (XSS) [CWE 79]
20 return Response(body % escape(name))
21

22

23 # /goto which issues HTTP redirect to the last view


24 @view_config(route_name='redirect')
25 def redirect_view(request):
(continues on next page)

0.2. Tutorials 47
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


26 return HTTPFound(location="/problem")
27

28

29 # /problem which causes a site error


30 @view_config(route_name='exception')
31 def exception_view(request):
32 raise Exception()

We have four views, each leading to the other. If you start at http://localhost:6543/, you get a response
with a link to the next view. The hello_view (available at the URL /howdy) has a link to the redi-
rect_view, which issues a redirect to the final view.

Earlier we saw config.add_view as one way to configure a view. This section introduces
@view_config. Pyramid’s configuration supports imperative configuration, such as the config.
add_view in the previous example. You can also use declarative configuration in which a Python dec-
orator is placed on the line above the view. Both approaches result in the same final configuration, thus
usually it is simply a matter of taste.

See also:

See also: Quick Tutorial Views, Views, View Configuration, and Debugging View Configuration.

Routing

Writing web applications usually means sophisticated URL design. We just saw some Pyramid machinery
for requests and views. Let’s look at features that help with routing.

Above we saw the basics of routing URLs to views in Pyramid:

• Your project’s ”setup” code registers a route name to be used when matching part of the URL.

• Elsewhere a view is configured to be called for that route name.

Why do this twice? Other Python web frameworks let you create a route and associate it with a view
in one step. As illustrated in Routes need relative ordering, multiple routes might match the same URL
pattern. Rather than provide ways to help guess, Pyramid lets you be explicit in ordering. Pyramid also
gives facilities to avoid the problem.

What if we want part of the URL to be available as data in my view? We can use this route declaration,
for example:

48 CONTENTS
The Pyramid Web Framework, Version 2.0.2

6 config.add_route('hello', '/howdy/{first}/{last}')

With this, URLs such as /howdy/amy/smith will assign amy to first and smith to last. We
can then use this data in our view:

5 @view_config(route_name='hello')
6 def hello_world(request):
7 body = '<h1>Hi %(first)s %(last)s!</h1>' % request.matchdict
8 return Response(body)

request.matchdict contains values from the URL that match the ”replacement patterns” (the curly
braces) in the route declaration. This information can then be used in your view.

See also:

See also: Quick Tutorial Routing, URL Dispatch, Debugging Route Matching, and Request Processing.

Templating

Ouch. We have been making our own Response and filling the response body with HTML. You usually
won’t embed an HTML string directly in Python, but instead you will use a templating language.

Pyramid doesn’t mandate a particular database system, form library, and so on. It encourages replaceabil-
ity. This applies equally to templating, which is fortunate: developers have strong views about template
languages. That said, the Pylons Project officially supports bindings for Chameleon, Jinja2, and Mako. In
this step let’s use Chameleon.

Let’s add pyramid_chameleon, a Pyramid add-on which enables Chameleon as a renderer in our
Pyramid application:

$VENV/bin/pip install pyramid_chameleon

With the package installed, we can include the template bindings into our configuration in app.py:

6 config.add_route('hello', '/howdy/{name}')
7 config.include('pyramid_chameleon')
8 config.scan('views')

Now lets change our views.py file:

0.2. Tutorials 49
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.view import view_config


2

4 @view_config(route_name='hello', renderer='hello_world.pt')
5 def hello_world(request):
6 return dict(name=request.matchdict['name'])

Ahh, that looks better. We have a view that is focused on Python code. Our @view_config decorator
specifies a renderer that points to our template file. Our view then simply returns data which is then
supplied to our template hello_world.pt:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Quick Glance</title>
</head>
<body>
<h1>Hello ${name}</h1>
</body>
</html>

Since our view returned dict(name=request.matchdict['name']), we can use name as a


variable in our template via ${name}.

See also:

See also: Quick Tutorial Templating, Templates, Debugging Templates, and Available Add-On Template
System Bindings.

Templating with Jinja2

We just said Pyramid doesn’t prefer one templating language over another. Time to prove it. Jinja2 is a
popular templating system, modeled after Django’s templates. Let’s add pyramid_jinja2, a Pyramid
add-on which enables Jinja2 as a renderer in our Pyramid applications:

$VENV/bin/pip install pyramid_jinja2

With the package installed, we can include the template bindings into our configuration:

50 CONTENTS
The Pyramid Web Framework, Version 2.0.2

6 config.add_route('hello', '/howdy/{name}')
7 config.include('pyramid_jinja2')
8 config.scan('views')

The only change in our view is to point the renderer at the .jinja2 file:

4 @view_config(route_name='hello', renderer='hello_world.jinja2')
5 def hello_world(request):
6 return dict(name=request.matchdict['name'])

Our Jinja2 template is very similar to our previous template:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello {{ name }}!</h1>
</body>
</html>

Pyramid’s templating add-ons register a new kind of renderer into your application. The renderer regis-
tration maps to different kinds of filename extensions. In this case, changing the extension from .pt to
.jinja2 passed the view response through the pyramid_jinja2 renderer.

See also:

See also: Quick Tutorial Jinja2, Jinja2 homepage, and pyramid_jinja2 Overview.

Static assets

Of course the Web is more than just markup. You need static assets: CSS, JS, and images. Let’s point our
web app at a directory from which Pyramid will serve some static assets. First let’s make another call to
the configurator in app.py:

6 config.add_route('hello', '/howdy/{name}')
7 config.add_static_view(name='static', path='static')
8 config.include('pyramid_jinja2')

0.2. Tutorials 51
The Pyramid Web Framework, Version 2.0.2

This tells our WSGI application to map requests under http://localhost:6543/static/ to files and directories
inside a static directory alongside our Python module.

Next make a directory named static, and place app.css inside:

body {
margin: 2em;
font-family: sans-serif;
}

All we need to do now is point to it in the <head> of our Jinja2 template, hello_world.jinja2:

4 <title>Hello World</title>
5 <link rel="stylesheet" href="/static/app.css"/>
6 </head>

This link presumes that our CSS is at a URL starting with /static/. What if the site is later moved
under /somesite/static/? Or perhaps a web developer changes the arrangement on disk? Pyramid
provides a helper to allow flexibility on URL generation:

4 <title>Hello World</title>
5 <link rel="stylesheet" href="{{ request.static_url('__main__:static/
,→app.css') }}"/>

6 </head>

By using request.static_url to generate the full URL to the static assets, you ensure that you stay
in sync with the configuration and gain refactoring flexibility later.

See also:

See also: Quick Tutorial Static Assets, Static Assets, Preventing HTTP Caching, and Influencing HTTP
Caching.

Returning JSON

Modern web apps are more than rendered HTML. Dynamic pages now use JavaScript to update the UI in
the browser by requesting server data as JSON. Pyramid supports this with a JSON renderer:

52 CONTENTS
The Pyramid Web Framework, Version 2.0.2

9 @view_config(route_name='hello_json', renderer='json')
10 def hello_json(request):
11 return [1, 2, 3]

This wires up a view that returns some data through the JSON renderer, which calls Python’s JSON support
to serialize the data into JSON, and sets the appropriate HTTP headers.

We also need to add a route to app.py so that our app will know how to respond to a request for hello.
json.

6 config.add_route('hello', '/howdy/{name}')
7 config.add_route('hello_json', 'hello.json')
8 config.add_static_view(name='static', path='static')

See also:

See also: Quick Tutorial JSON, Writing View Callables Which Use a Renderer, JSON Renderer, and
Adding and Changing Renderers.

View classes

So far our views have been simple, free-standing functions. Many times your views are related. They may
have different ways to look at or work on the same data, or they may be a REST API that handles multiple
operations. Grouping these together as a view class makes sense and achieves the following goals.

• Group views

• Centralize some repetitive defaults

• Share some state and helpers

The following shows a ”Hello World” example with three operations: view a form, save a change, or press
the delete button in our views.py:

0.2. Tutorials 53
The Pyramid Web Framework, Version 2.0.2

7 # One route, at /howdy/amy, so don't repeat on each @view_config


8 @view_defaults(route_name='hello')
9 class HelloWorldViews:
10 def __init__(self, request):
11 self.request = request
12 # Our templates can now say {{ view.name }}
13 self.name = request.matchdict['name']
14

15 # Retrieving /howdy/amy the first time


16 @view_config(renderer='hello.jinja2')
17 def hello_view(self):
18 return dict()
19

20 # Posting to /howdy/amy via the "Edit" submit button


21 @view_config(request_param='form.edit', renderer='edit.jinja2')
22 def edit_view(self):
23 print('Edited')
24 return dict()
25

26 # Posting to /howdy/amy via the "Delete" submit button


27 @view_config(request_param='form.delete', renderer='delete.jinja2')
28 def delete_view(self):
29 print('Deleted')
30 return dict()

As you can see, the three views are logically grouped together. Specifically:

• The first view is returned when you go to /howdy/amy. This URL is mapped to the hello route
that we centrally set using the optional @view_defaults.

• The second view is returned when the form data contains a field with form.edit, such as click-
ing on <input type="submit" name="form.edit" value="Save">. This rule is
specified in the @view_config for that view.

• The third view is returned when clicking on a button such as <input type="submit"
name="form.delete" value="Delete">.

Only one route is needed, stated in one place atop the view class. Also, the assignment of name is done
in the __init__ function. Our templates can then use {{ view.name }}.

Pyramid view classes, combined with built-in and custom predicates, have much more to offer:

• All the same view configuration parameters as function views

54 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• One route leading to multiple views, based on information in the request or data such as re-
quest_param, request_method, accept, header, xhr, containment, and custom
predicates.
See also:
See also: View Classes and More View Classes in the Quick Tutorial, Defining a View Callable as a Class,
and View and Route Predicates.

Quick project startup with cookiecutters

So far we have done all of our Quick Tour as a single Python file. No Python packages, no structure. Most
Pyramid projects, though, aren’t developed this way.
To ease the process of getting started, the Pylons Project provides a cookiecutter that generates a sample
Pyramid project from project templates. This cookiecutter will install Pyramid and its dependencies as
well.
First you’ll need to install cookiecutter.

$VENV/bin/pip install cookiecutter

Let’s use the cookiecutter pyramid-cookiecutter-starter to create a starter Pyramid project in


the current directory, entering values at the prompts as shown below for the following command.

$VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 2.


,→0-branch

If prompted for the first item, accept the default yes by hitting return.

You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.


Is it okay to delete and re-clone it? [yes]: yes
project_name [Pyramid Scaffold]: hello_world
repo_name [hello_world]: hello_world
Select template_language:
1 - jinja2
2 - chameleon
3 - mako
Choose from 1, 2, 3 [1]: 1
Select backend:
1 - none
2 - sqlalchemy
3 - zodb
Choose from 1, 2, 3 [1]: 1

0.2. Tutorials 55
The Pyramid Web Framework, Version 2.0.2

We then run through the following commands.

# Change directory into your newly created project.


cd hello_world
# Create a new virtual environment...
python3 -m venv env
# ...where we upgrade packaging tools...
env/bin/pip install --upgrade pip setuptools
# ...and into which we install our project and its testing requirements.
env/bin/pip install -e ".[testing]"
# Reset our environment variable for a new virtual environment.
export VENV=~/hello_world/env

We are moving in the direction of a full-featured Pyramid project, with a proper setup for Python standards
(packaging) and Pyramid configuration. This includes a new way of running your application:

$VENV/bin/pserve development.ini

Let’s look at pserve and configuration in more depth.


See also:
See also: Quick Tutorial Cookiecutters, Creating a Pyramid Project, and Pyramid cookiecutters

Application running with pserve

Prior to the cookiecutter, our project mixed a number of operational details into our code. Why should my
main code care which HTTP server I want and what port number to run on?
pserve is Pyramid’s application runner, separating operational details from your code. When you install
Pyramid, a small command program called pserve is written to your bin directory. This program is an
executable Python module. It’s very small, getting most of its brains via import.
You can run pserve with --help to see some of its options. Doing so reveals that you can ask pserve
to watch your development files and reload the server when they change:

$VENV/bin/pserve development.ini --reload

The pserve command has a number of other options and operations. Most of the work, though, comes
from your project’s wiring, as expressed in the configuration file you supply to pserve. Let’s take a look
at this configuration file.
See also:
See also: What Is This pserve Thing

56 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Configuration with .ini files

Earlier in Quick Tour we first met Pyramid’s configuration system. At that point we did all configuration
in Python code. For example, the port number chosen for our HTTP server was right there in Python code.
Our cookiecutter has moved this decision and more into the development.ini file:

###
# app configuration
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/
,→environment.html

###

[app:main]
use = egg:hello_world

pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar

# By default, the toolbar only appears for clients from IP addresses


# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1

###
# wsgi server configuration
###

[server:main]
use = egg:waitress#main
listen = localhost:6543

###
# logging configuration
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.
,→html

###

[loggers]
keys = root, hello_world

[handlers]
(continues on next page)

0.2. Tutorials 57
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


keys = console

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console

[logger_hello_world]
level = DEBUG
handlers =
qualname = hello_world

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][
,→%(threadName)s] %(message)s

Let’s take a quick high-level look. First the .ini file is divided into sections:

• [app:main] configures our WSGI app

• [server:main] holds our WSGI server settings

• Various sections afterwards configure our Python logging system

We have a few decisions made for us in this configuration:

1. WSGI app: What package has our WSGI application in it? use = egg:hello_world in the
app section tells the configuration what application to load.

2. Easier development by automatic template reloading: In development mode, you shouldn’t have to
restart the server when editing a Jinja2 template. pyramid.reload_templates = true sets
this policy, which might be different in production.

3. Choice of web server: use = egg:waitress#main tells pserve to use the waitress
server.

58 CONTENTS
The Pyramid Web Framework, Version 2.0.2

4. Interfaces: listen = localhost:6543 tells waitress to listen on all interfaces on port


6543 for both IPv4 and IPv6.

Additionally the development.ini generated by this cookiecutter wired up Python’s standard logging.
We’ll now see in the console, for example, a log on every request that comes in, as well as traceback
information.

See also:

See also: Quick Tutorial Application Configuration, Environment Variables and .ini File Settings and
PasteDeploy Configuration Files

Easier development with debugtoolbar

As we introduce the basics, we also want to show how to be productive in development and debugging. For
example, we just discussed template reloading and earlier we showed --reload for application reloading.

pyramid_debugtoolbar is a popular Pyramid add-on which makes several tools available in your
browser. Adding it to your project illustrates several points about configuration.

Our cookiecutter pyramid-cookiecutter-starter already configured our package to include the


add-on pyramid_debugtoolbar in its setup.py:

11 requires = [
12 'plaster_pastedeploy',
13 'pyramid',
14 'pyramid_jinja2',
15 'pyramid_debugtoolbar',
16 'waitress',
17 ]

It was installed when you previously ran:

$VENV/bin/pip install -e ".[testing]"

The pyramid_debugtoolbar package is a Pyramid add-on, which means we need to include


its configuration into our web application. The cookiecutter already took care of this for us in its
development.ini using the pyramid.includes facility:

0.2. Tutorials 59
The Pyramid Web Framework, Version 2.0.2

14 pyramid.includes =
15 pyramid_debugtoolbar

You’ll now see a Pyramid logo on the right side of your browser window, which when clicked opens a new
window that provides introspective access to debugging information. Even better, if your web application
generates an error, you will see a nice traceback on the screen. When you want to disable this toolbar,
there’s no need to change code: you can remove it from pyramid.includes in the relevant .ini
configuration file.

See also:

See also: Quick Tutorial pyramid_debugtoolbar and pyramid_debugtoolbar

Unit and functional tests and pytest

Yikes! We got this far and we haven’t yet discussed tests. This is particularly egregious, as Pyramid has
had a deep commitment to full test coverage since before its release.

Our pyramid-cookiecutter-starter cookiecutter generated conftest.py,


test_functional.py, and test_views.py modules inside the tests package with two
unit tests and two functional tests in it. It also configured setup.py with test requirements: pytest as
the test runner, WebTest for running view tests, and the pytest-cov tool which yells at us for code
that isn’t tested:

19 tests_require = [
20 'WebTest',
21 'pytest',
22 'pytest-cov',
23 ]

43 extras_require={
44 'testing': tests_require,
45 },

We already installed the test requirements when we ran the command $VENV/bin/pip install -e
".[testing]". We can now run all our tests:

60 CONTENTS
The Pyramid Web Framework, Version 2.0.2

$VENV/bin/pytest --cov --cov-report=term-missing

This yields the following output.

=========================== test session starts ===========================


platform darwin -- Python 3.9.0, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: /<somepath>/hello_world, configfile: pytest.ini, testpaths: hello_
,→world, tests

plugins: cov-2.10.1
collected 4 items

tests/test_functional.py .. [ 50%]
tests/test_views.py .. [100%]

---------- coverage: platform darwin, python 3.9.0-final-0 -----------


Name Stmts Miss Cover Missing
-------------------------------------------------------------
hello_world/__init__.py 7 0 100%
hello_world/routes.py 3 0 100%
hello_world/views/__init__.py 0 0 100%
hello_world/views/default.py 4 0 100%
hello_world/views/notfound.py 5 0 100%
-------------------------------------------------------------
TOTAL 19 0 100%

======================== 4 passed in 0.65 seconds =========================

Our tests passed, and its coverage is complete. What did our tests look like?

1 def test_root(testapp):
2 res = testapp.get('/', status=200)
3 assert b'Pyramid' in res.body
4

5 def test_notfound(testapp):
6 res = testapp.get('/badurl', status=404)
7 assert res.status_code == 404

1 from hello_world.views.default import my_view


2 from hello_world.views.notfound import notfound_view
3

5 def test_my_view(app_request):
(continues on next page)

0.2. Tutorials 61
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


6 info = my_view(app_request)
7 assert app_request.response.status_int == 200
8 assert info['project'] == 'hello_world'
9

10 def test_notfound_view(app_request):
11 info = notfound_view(app_request)
12 assert app_request.response.status_int == 404
13 assert info == {}

Pyramid supplies helpers for test writing, which we use in the test setup and teardown. Our view tests
import the view, make a dummy request, and sees if the view returns what we expected. Our functional
tests verify that the response body from a request to the web root contains what we expected and that the
expected response code for making a request to /badurl results in 404.
See also:
See also: Quick Tutorial Unit Testing, Quick Tutorial Functional Testing, and Unit, Integration, and Func-
tional Testing

Logging

It’s important to know what is going on inside our web application. In development we might need to
collect some output. In production we might need to detect situations when other people use the site. We
need logging.
Fortunately Pyramid uses the normal Python approach to logging. The development.ini file for your
project has a number of lines that configure the logging for you to some reasonable defaults. You then see
messages sent by Pyramid (for example, when a new request comes in).
Maybe you would like to log messages in your code? In your Python module, import and set up the logging
in your views/default.py:

3 import logging
4 log = logging.getLogger(__name__)

You can now, in your code, log messages:

7 def my_view(request):
8 log.debug('Some Message')

This will log Some Message at a DEBUG log level to the application-configured logger in your
development.ini. What controls that? These emphasized sections in the configuration file:

62 CONTENTS
The Pyramid Web Framework, Version 2.0.2

34 [loggers]
35 keys = root, hello_world
36

37 [handlers]
38 keys = console
39

40 [formatters]
41 keys = generic
42

43 [logger_root]
44 level = INFO
45 handlers = console
46

47 [logger_hello_world]
48 level = DEBUG
49 handlers =
50 qualname = hello_world

Our application, a package named hello_world, is set up as a logger and configured to log messages
at a DEBUG or higher level. When you visit http://localhost:6543, your console will now show:

2016-12-25 03:03:57,059 DEBUG [hello_world.views:8][waitress] Some Message

See also:

See also: Quick Tutorial Logging and Logging.

Sessions

When people use your web application, they frequently perform a task that requires semi-permanent data
to be saved. For example, a shopping cart. This is called a session.

Pyramid has basic built-in support for sessions. Third party packages such as pyra-
mid_redis_sessions provide richer session support. Or you can create your own custom
sessioning engine. Let’s take a look at the built-in sessioning support. In our __init__.py we first
import the kind of sessioning we want:

1 from pyramid.config import Configurator


2 from pyramid.session import SignedCookieSessionFactory

0.2. Tutorials 63
The Pyramid Web Framework, Version 2.0.2

As noted in the session docs, this example implementation is not intended for use in settings with
security implications.

Now make a ”factory” and pass it to the configurator’s session_factory argument:

9 config.include('.routes')
10 my_session_factory = SignedCookieSessionFactory('itsaseekreet')
11 config.set_session_factory(my_session_factory)
12 config.scan()

Pyramid’s request object now has a session attribute that we can use in our view code in views/
default.py:

7 def my_view(request):
8 log.debug('Some Message')
9 session = request.session
10 if 'counter' in session:
11 session['counter'] += 1
12 else:
13 session['counter'] = 0
14 return {'project': 'hello_world'}

We need to update our Jinja2 template templates/mytemplate.jinja2 to show counter increment


in the session:

4 <div class="content">
5 <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">
,→Starter project</span></h1>

6 <p class="lead">Welcome to <span class="font-normal">{{project}}</span>,␣


,→a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal

,→">Cookiecutter</span>.</p>

7 <p>Counter: {{ request.session.counter }}</p>


8 </div>

See also:

See also: Quick Tutorial Sessions, Sessions, Flash Messages, pyramid.session, and pyra-
mid_redis_sessions.

64 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Databases

Web applications mean data. Data means databases. Frequently SQL databases. SQL databases fre-
quently mean an ”ORM” (object-relational mapper.) In Python, ORM usually leads to the mega-quality
SQLAlchemy, a Python package that greatly eases working with databases.

Pyramid and SQLAlchemy are great friends. That friendship includes a cookiecutter!

cd ~
env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 2.0-
,→branch

If prompted for the first item, accept the default yes by hitting return.

You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.


Is it okay to delete and re-clone it? [yes]: yes
project_name [Pyramid Scaffold]: sqla_demo
repo_name [sqla_demo]: sqla_demo
Select template_language:
1 - jinja2
2 - chameleon
3 - mako
Choose from 1, 2, 3 [1]: 1
Select backend:
1 - none
2 - sqlalchemy
3 - zodb
Choose from 1, 2, 3 [1]: 2

We then run through the following commands as before.

# Change directory into your newly created project.


cd sqla_demo
# Create a new virtual environment...
python3 -m venv env
# ...where we upgrade packaging tools...
env/bin/pip install --upgrade pip setuptools
# ...and into which we install our project and its testing requirements.
env/bin/pip install -e ".[testing]"
# Reset our environment variable for a new virtual environment.
export VENV=~/sqla_demo/env

0.2. Tutorials 65
The Pyramid Web Framework, Version 2.0.2

We now have a working sample SQLAlchemy application with all dependencies installed. The sample
project provides a method to generate a database migration from existing models and upgrade the database
schema using Alembic. Let’s generate the first revision.

$VENV/bin/alembic -c development.ini revision --autogenerate -m "init"

Now let’s upgrade the database schema.

$VENV/bin/alembic -c development.ini upgrade head

The sample project also provides a console script to load data into the SQLite database. Let’s run it, then
start the application:

$VENV/bin/initialize_sqla_demo_db development.ini
$VENV/bin/pserve development.ini

The ORM eases the mapping of database structures into a programming language. SQLAlchemy uses
”models” for this mapping. The cookiecutter generated a sample model:

11 class MyModel(Base):
12 __tablename__ = 'models'
13 id = Column(Integer, primary_key=True)
14 name = Column(Text)
15 value = Column(Integer)

View code, which mediates the logic between web requests and the rest of the system, can then easily get
at the data thanks to SQLAlchemy:

8 @view_config(route_name='home', renderer='sqla_demo:templates/mytemplate.
,→jinja2')

9 def my_view(request):
10 try:
11 query = request.dbsession.query(models.MyModel)
12 one = query.filter(models.MyModel.name == 'one').one()
13 except SQLAlchemyError:
14 return Response(db_err_msg, content_type='text/plain', status=500)
15 return {'one': one, 'project': 'sqla_demo'}

See also:

See also: Quick Tutorial Databases, SQLAlchemy, Making Your Script into a Console Script,
SQLAlchemy + URL dispatch wiki tutorial, and Application Transactions with pyramid_tm.

66 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Forms

Developers have lots of opinions about web forms, thus there are many form libraries for Python. Pyramid
doesn’t directly bundle a form library, but Deform is a popular choice for forms, along with its related
Colander schema system.
As an example, imagine we want a form that edits a wiki page. The form should have two fields on it, one
of them a required title and the other a rich text editor for the body. With Deform we can express this as a
Colander schema:

class WikiPage(colander.MappingSchema):
title = colander.SchemaNode(colander.String())
body = colander.SchemaNode(
colander.String(),
widget=deform.widget.RichTextWidget()
)

With this in place, we can render the HTML for a form, perhaps with form data from an existing page:

form = self.wiki_form.render()

We’d like to handle form submission, validation, and saving:

# Get the form data that was posted


controls = self.request.POST.items()
try:
# Validate and either raise a validation error
# or return deserialized data from widgets
appstruct = wiki_form.validate(controls)
except deform.ValidationFailure as e:
# Bail out and render form with errors
return dict(title=title, page=page, form=e.render())

# Change the content and redirect to the view


page['title'] = appstruct['title']
page['body'] = appstruct['body']

Deform and Colander provide a very flexible combination for forms, widgets, schemas, and validation.
Recent versions of Deform also include a retail mode for gaining Deform features on custom forms.
Deform uses attractive CSS from Twitter Bootstrap and more powerful select, checkbox, and date and time
widgets.
See also:
See also: Quick Tutorial Forms, Deform, and Colander.

0.2. Tutorials 67
The Pyramid Web Framework, Version 2.0.2

Conclusion

This Quick Tour covered a little about a lot. We introduced a long list of concepts in Pyramid, many of
which are expanded on more fully in the Pyramid developer docs.

0.2.2 Quick Tutorial for Pyramid

This tutorial gives a high-level tour of the major features.

This hands-on tutorial covers ”a little about a lot”: practical introductions to the most common facilities.
Fun, fast-paced, and most certainly not aimed at experts of the Pyramid web framework.

Contents

Requirements

Let’s get our tutorial environment set up. Most of the set up work is in standard Python development
practices (install Python and make an isolated virtual environment.)

Pyramid encourages standard Python development practices with packaging tools, virtual environ-
ments, logging, and so on. There are many variations, implementations, and opinions across the Python
community. For consistency, ease of documentation maintenance, and to minimize confusion, the Pyramid
documentation has adopted specific conventions that are consistent with the Python Packaging Authority.

This Quick Tutorial is based on:

• Python 3.8. Pyramid fully supports Python 3.6+. This tutorial uses Python 3.8.

• venv. We believe in virtual environments. For this tutorial, we use Python 3’s built-in solution venv.

• pip. We use pip for package management.

• Workspaces, projects, and packages. Our home directory will contain a tutorial workspace with
our Python virtual environment and Python projects (a directory with packaging information and
Python packages of working code.)

68 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Unix commands. Commands in this tutorial use Unix syntax and paths. Windows users should
adjust commands accordingly.

Pyramid was one of the first web frameworks to fully support Python 3 in October 2011.

Windows commands use the plain old MSDOS shell. For PowerShell command syntax, see its
documentation.

Steps

1. Install Python 3

2. Create a project directory structure

3. Set an environment variable

4. Create a virtual environment

5. Install Pyramid

Install Python 3

See the detailed recommendation for your operating system described under Installing Pyramid.

• For macOS Users

• If You Don’t Yet Have a Python Interpreter (Unix)

• If You Don’t Yet Have a Python Interpreter (Windows)

Create a project directory structure

We will arrive at a directory structure of workspace -> project -> package, where our
workspace is named quick_tutorial. The following tree diagram shows how this will be structured,
and where our virtual environment will reside as we proceed through the tutorial:

0.2. Tutorials 69
The Pyramid Web Framework, Version 2.0.2

~
└── projects
└── quick_tutorial
├── env
└── step_one
├── intro
│ ├── __init__.py
│ └── app.py
└── setup.py

For macOS and Linux, the commands to do so are as follows:

# macOS and Linux


cd ~
mkdir -p projects/quick_tutorial
cd projects/quick_tutorial

For Windows:

# Windows
cd \
mkdir projects\quick_tutorial
cd projects\quick_tutorial

In the above figure, your user home directory is represented by ~. In your home directory, all of your
projects are in the projects directory. This is a general convention not specific to Pyramid that many
developers use. Windows users will do well to use c:\ as the location for projects in order to avoid
spaces in any of the path names.

Next within projects is your workspace directory, here named quick_tutorial. A workspace is
a common term used by integrated development environments (IDE), like PyCharm and PyDev, where
virtual environments, specific project files, and repositories are stored.

Set an environment variable

This tutorial will refer frequently to the location of the virtual environment. We set an environment variable
to save typing later.

70 CONTENTS
The Pyramid Web Framework, Version 2.0.2

# macOS and Linux


export VENV=~/projects/quick_tutorial/env

# Windows
set VENV=c:\projects\quick_tutorial\env

Create a virtual environment

venv is a tool to create isolated Python 3 environments, each with its own Python binary and independent
set of installed Python packages in its site directories. Let’s create one, using the location we just specified
in the environment variable.

# macOS and Linux


python3 -m venv $VENV

# Windows
python -m venv %VENV%

See also:

See also venv module.

Update packaging tools in the virtual environment

It’s always a good idea to update to the very latest version of packaging tools because the installed Python
bundles only the version that was available at the time of its release.

# macOS and Linux


$VENV/bin/pip install --upgrade pip setuptools

# Windows
%VENV%\Scripts\pip install --upgrade pip setuptools

See also:

See also Why use $VENV/bin/pip instead of source bin/activate, then pip.

0.2. Tutorials 71
The Pyramid Web Framework, Version 2.0.2

Install Pyramid

We have our Python standard prerequisites out of the way. The Pyramid part is pretty easy. We’ll also
install a WSGI server, Waitress.

# macOS and Linux


$VENV/bin/pip install "pyramid==2.0.2" waitress

# Windows
%VENV%\Scripts\pip install "pyramid==2.0.2" waitress

Our Python virtual environment now has the Pyramid software available as well as the waitress pack-
age.

Tutorial Approach

This tutorial uses conventions to keep the introduction focused and concise. Details, references, and deeper
discussions are mentioned in ”See also” notes.

See also:

This is an example ”See also” note.

Directory tree

This ”Getting Started” tutorial is broken into independent steps, starting with the smallest possible ”single
file WSGI app” example. Each of these steps introduces a topic and a very small set of concepts via
working code. The steps each correspond to a directory in our workspace, where each step’s directory is
a Python package. Source code used in this tutorial is located in the Pyramid repository in the directory
”docs/quick_tutorial”. You may git clone the repository, download, or copy-paste the source code. If
you do so, then make sure you use the same branch as this documentation.

As we develop our tutorial, our directory tree will resemble the structure below:

72 CONTENTS
The Pyramid Web Framework, Version 2.0.2

quick_tutorial
├── env
└── request_response
├── tutorial
│ ├── __init__.py
│ ├── tests.py
│ └── views.py
├── development.ini
└── setup.py

Each of the directories in our quick_tutorial workspace (e.g., request_response) is a Python


project (except as noted for the hello_world step). The tutorial directory is a Python package.

For most steps you will copy an earlier step’s directory to a new directory, change your working directory
to the new directory, then install your project:

cd ..; cp -r package ini; cd ini


$VENV/bin/pip install -e .

For a few steps, you won’t copy an earlier step’s directory, but you will still need to install your project
with $VENV/bin/pip install -e ..

Finally for a few steps, you might add a dependency to your project in its setup.py file, and then install
both the dependency and the project with either $VENV/bin/pip install -e . or $VENV/bin/
pip install -e ".[dev]".

Prelude: Quick Project Startup with Cookiecutters

To ease the process of getting started on a project, the Pylons Project provides a cookiecutter that generates
sample Pyramid projects from project templates. The cookiecutter will install Pyramid and its dependen-
cies as well. We will still cover many topics of web application development using Pyramid, but it’s good
to know of this facility. This prelude will demonstrate how to get a working Pyramid web application
running via cookiecutter.

Objectives

• Use a cookiecutter to make a new project.

• Start up a Pyramid application and visit it in a web browser.

0.2. Tutorials 73
The Pyramid Web Framework, Version 2.0.2

Steps

1. Install cookiecutter into your virtual environment.

$VENV/bin/pip install cookiecutter

2. Let’s use the cookiecutter pyramid-cookiecutter-starter to create a starter Pyramid


project in the current directory, entering values at the prompts as shown below for the following
command.

$VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --
,→checkout 2.0-branch

If prompted for the first item, accept the default yes by hitting return.

You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.


Is it okay to delete and re-clone it? [yes]: yes
project_name [Pyramid Scaffold]: cc_starter
repo_name [cc_starter]: cc_starter
Select template_language:
1 - jinja2
2 - chameleon
3 - mako
Choose from 1, 2, 3 [1]: 1
Select backend:
1 - none
2 - sqlalchemy
3 - zodb
Choose from 1, 2, 3 [1]: 1

3. We then run through the following commands.

# Change directory into your newly created project.


cd cc_starter
# Create a new virtual environment...
python3 -m venv env
# ...where we upgrade packaging tools...
env/bin/pip install --upgrade pip setuptools
# ...and into which we install our project.
env/bin/pip install -e .

74 CONTENTS
The Pyramid Web Framework, Version 2.0.2

4. Start up the application by pointing Pyramid’s pserve command at the project’s (generated) con-
figuration file:

env/bin/pserve development.ini --reload

On start up, pserve logs some output:

Starting monitor for PID 60461.


Starting server in PID 60461.
Serving on http://localhost:6543
Serving on http://localhost:6543

5. Open http://localhost:6543/ in your browser.

Analysis

Rather than starting from scratch, a cookiecutter can make it easy to get a Python project containing a
working Pyramid application.
pserve is Pyramid’s application runner, separating operational details from your code. When you install
Pyramid, a small command program called pserve is written to your bin directory. This program is an
executable Python module. It is passed a configuration file (in this case, development.ini).

01: Single-File Web Applications

What’s the simplest way to get started in Pyramid? A single-file module. No Python packages, no pip
install -e ., no other machinery.

Background

Microframeworks were all the rage, until the next shiny thing came along. ”Microframework” is a mar-
keting term, not a technical one. They have a low mental overhead: they do so little, the only things you
have to worry about are your things.
Pyramid is special because it can act as a single-file module microframework. You can have a single Python
file that can be executed directly by Python. But Pyramid also provides facilities to scale to the largest of
applications.
Python has a standard called WSGI that defines how Python web applications plug into standard servers,
getting passed incoming requests, and returning responses. Most modern Python web frameworks obey an
”MVC” (model-view-controller) application pattern, where the data in the model has a view that mediates
interaction with outside systems.
In this step we’ll see a brief glimpse of WSGI servers, WSGI applications, requests, responses, and views.

0.2. Tutorials 75
The Pyramid Web Framework, Version 2.0.2

Objectives

• Get a running Pyramid web application, as simply as possible.

• Use that as a well-understood base for adding each unit of complexity.

• Initial exposure to WSGI apps, requests, views, and responses.

Steps

1. Make sure you have followed the steps in Requirements.

2. Starting from your workspace directory (~/projects/quick_tutorial), create a directory


for this step:

cd ~/projects/quick_tutorial; mkdir hello_world; cd hello_world

3. Copy the following into hello_world/app.py:

1 from waitress import serve


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4

6 def hello_world(request):
7 print('Incoming request')
8 return Response('<body><h1>Hello World!</h1></body>')
9

10

11 if __name__ == '__main__':
12 with Configurator() as config:
13 config.add_route('hello', '/')
14 config.add_view(hello_world, route_name='hello')
15 app = config.make_wsgi_app()
16 serve(app, host='0.0.0.0', port=6543)

4. Run the application:

76 CONTENTS
The Pyramid Web Framework, Version 2.0.2

$VENV/bin/python app.py

5. Open http://localhost:6543/ in your browser.

Analysis

New to Python web programming? If so, some lines in the module merit explanation:

1. Line 11. The if __name__ == '__main__': is Python’s way of saying, ”Start here when
running from the command line”, rather than when this module is imported.

2. Lines 12-14. Use Pyramid’s configurator in a context manager to connect view code to a particular
URL route.

3. Lines 6-8. Implement the view code that generates the response.

4. Lines 15-17. Publish a WSGI app using an HTTP server.

As shown in this example, the configurator plays a central role in Pyramid development. Building an
application from loosely-coupled parts via Application Configuration is a central idea in Pyramid, one that
we will revisit regularly in this Quick Tutorial.

Extra credit

1. Why do we do this:

print('Incoming request')

...instead of:

print 'Incoming request'

2. What happens if you return a string of HTML? A sequence of integers?

3. Put something invalid, such as print xyz, in the view function. Kill your python app.py
with ctrl-C and restart, then reload your browser. See the exception in the console?

4. The GI in WSGI stands for ”Gateway Interface”. What web standard is this modelled after?

0.2. Tutorials 77
The Pyramid Web Framework, Version 2.0.2

02: Python Packages for Pyramid Applications

Most modern Python development is done using Python packages, an approach Pyramid puts to good use.
In this step we redo ”Hello World” as a minimal Python package inside a minimal Python project.

Background

Python developers can organize a collection of modules and files into a namespaced unit called a package.
If a directory is on sys.path and has a special file named __init__.py, it is treated as a Python
package.

Packages can be bundled up, made available for installation, and installed through a toolchain oriented
around a setup.py file. For this tutorial, this is all you need to know:

• We will have a directory for each tutorial step as a project.

• This project will contain a setup.py which injects the features of the project machinery into the
directory.

• In this project we will make a tutorial subdirectory into a Python package using an __init__.
py Python module file.

• We will run pip install -e . to install our project in development mode.

In summary:

• You’ll do your development in a Python package.

• That package will be part of a project.

Objectives

• Make a Python ”package” directory with an __init__.py.

• Get a minimum Python ”project” in place by making a setup.py.

• Install our tutorial project in development mode.

Steps

1. Make an area for this tutorial step:

78 CONTENTS
The Pyramid Web Framework, Version 2.0.2

cd ..; mkdir package; cd package

2. In package/setup.py, enter the following:

from setuptools import setup

# List of dependencies installed via `pip install -e .`


# by virtue of the Setuptools `install_requires` value below.
requires = [
'pyramid',
'waitress',
]

setup(
name='tutorial',
install_requires=requires,
)

3. Make the new project installed for development then make a directory for the actual code:

$VENV/bin/pip install -e .
mkdir tutorial

4. Enter the following into package/tutorial/__init__.py:

# package

5. Enter the following into package/tutorial/app.py:

from waitress import serve


from pyramid.config import Configurator
from pyramid.response import Response

def hello_world(request):
print('Incoming request')
return Response('<body><h1>Hello World!</h1></body>')

if __name__ == '__main__':
with Configurator() as config:
(continues on next page)

0.2. Tutorials 79
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


config.add_route('hello', '/')
config.add_view(hello_world, route_name='hello')
app = config.make_wsgi_app()
serve(app, host='0.0.0.0', port=6543)

6. Run the WSGI application with:

$VENV/bin/python tutorial/app.py

7. Open http://localhost:6543/ in your browser.

Analysis

Python packages give us an organized unit of project development. Python projects, via setup.py, give
us special features when our package is installed (in this case, in local development mode, also called local
editable mode as indicated by -e .).

In this step we have a Python package called tutorial. We use the same name in each step of the
tutorial, to avoid unnecessary retyping.

Above this tutorial directory we have the files that handle the packaging of this project. At the moment,
all we need is a bare-bones setup.py.

Everything else is the same about our application. We simply made a Python package with a setup.py
and installed it in development mode.

Note that the way we’re running the app (python tutorial/app.py) is a bit of an odd duck. We
would never do this unless we were writing a tutorial that tries to capture how this stuff works one step at
a time. It’s generally a bad idea to run a Python module inside a package directly as a script.

See also:

Python Packages and Working in ”Development Mode”.

03: Application Configuration with .ini Files

Use Pyramid’s pserve command with a .ini configuration file for simpler, better application running.

80 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Background

Pyramid has a first-class concept of configuration distinct from code. This approach is optional, but its
presence makes it distinct from other Python web frameworks. It taps into Python’s Setuptools library,
which establishes conventions for installing and providing ”entry points” for Python projects. Pyramid
uses an entry point to let a Pyramid application know where to find the WSGI app.

Objectives

• Modify our setup.py to have an entry point telling Pyramid the location of the WSGI app.
• Create an application driven by an .ini file.
• Start the application with Pyramid’s pserve command.
• Move code into the package’s __init__.py.

Steps

1. First we copy the results of the previous step:

cd ..; cp -r package ini; cd ini

2. Our ini/setup.py needs a Setuptools entry point in the setup() function:

1 from setuptools import setup


2

3 # List of dependencies installed via `pip install -e .`


4 # by virtue of the Setuptools `install_requires` value below.
5 requires = [
6 'pyramid',
7 'waitress',
8 ]
9

10 setup(
11 name='tutorial',
12 install_requires=requires,
13 entry_points={
14 'paste.app_factory': [
15 'main = tutorial:main'
16 ],
17 },
18 )

0.2. Tutorials 81
The Pyramid Web Framework, Version 2.0.2

3. We can now install our project, thus generating (or re-generating) an ”egg” at ini/tutorial.
egg-info:

$VENV/bin/pip install -e .

4. Let’s make a file ini/development.ini for our configuration:

1 [app:main]
2 use = egg:tutorial
3

4 [server:main]
5 use = egg:waitress#main
6 listen = localhost:6543

5. We can refactor our startup code from the previous step’s app.py into ini/tutorial/
__init__.py:

1 from pyramid.config import Configurator


2 from pyramid.response import Response
3

5 def hello_world(request):
6 return Response('<body><h1>Hello World!</h1></body>')
7

9 def main(global_config, **settings):


10 config = Configurator(settings=settings)
11 config.add_route('hello', '/')
12 config.add_view(hello_world, route_name='hello')
13 return config.make_wsgi_app()

6. Now that ini/tutorial/app.py isn’t used, let’s remove it:

rm tutorial/app.py

7. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

8. Open http://localhost:6543/.

82 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Analysis

Our development.ini file is read by pserve and serves to bootstrap our application. Processing
then proceeds as described in the Pyramid chapter on application startup:

• pserve looks for [app:main] and finds use = egg:tutorial.

• The projects’s setup.py has defined an entry point (lines 10-13) for the project’s ”main” entry
point of tutorial:main.

• The tutorial package’s __init__ has a main function.

• This function is invoked, with the values from certain .ini sections passed in.

The .ini file is also used for two other functions:

• Configuring the WSGI server. [server:main] wires up the choice of which WSGI server for
your WSGI application. In this case, we are using waitress which we specified in tutorial/
setup.py and was installed in the Requirements step at the start of this tutorial. It also wires up
the port number: listen = localhost:6543 tells waitress to listen on host localhost
at port 6543.

Running the command $VENV/bin/pip install -e . will check for previously


installed packages in our virtual environment that are specified in our package’s setup.py file, then
install our package in editable mode, installing any requirements that were not previously installed.
If a requirement was manually installed previously on the command line or otherwise, in this case
Waitress, then $VENV/bin/pip install -e . will merely check that it is installed and move
on.

• Configuring Python logging. Pyramid uses Python standard logging, which needs a number of con-
figuration values. The .ini serves this function. This provides the console log output that you see
on startup and each request.

We moved our startup code from app.py to the package’s tutorial/__init__.py. This isn’t nec-
essary, but it is a common style in Pyramid to take the WSGI app bootstrapping out of your module’s code
and put it in the package’s __init__.py.

The pserve application runner has a number of command-line arguments and options. We are using
--reload which tells pserve to watch the filesystem for changes to relevant code (Python files, the
INI file, etc.) and, when something changes, restart the application. Very handy during development.

0.2. Tutorials 83
The Pyramid Web Framework, Version 2.0.2

Extra credit

1. If you don’t like configuration and/or .ini files, could you do this yourself in Python code?
2. Can we have multiple .ini configuration files for a project? Why might you want to do that?
3. The entry point in setup.py didn’t mention __init__.py when it declared tutorial:main
function. Why not?
4. What is the purpose of **settings? What does the ** signify?
See also:
Creating a Pyramid Project, Pyramid cookiecutters, What Is This pserve Thing, Environment Variables
and .ini File Settings, PasteDeploy Configuration Files

04: Easier Development with debugtoolbar

Error handling and introspection using the pyramid_debugtoolbar add-on.

Background

As we introduce the basics, we also want to show how to be productive in development and debugging.
For example, we just discussed template reloading, and earlier we showed --reload for application
reloading.
pyramid_debugtoolbar is a popular Pyramid add-on which makes several tools available in your
browser. Adding it to your project illustrates several points about configuration.

Objectives

• Install and enable the toolbar to help during development.


• Explain Pyramid add-ons.
• Show how an add-on gets configured into your application.

Steps

1. First we copy the results of the previous step.

84 CONTENTS
The Pyramid Web Framework, Version 2.0.2

cd ..; cp -r ini debugtoolbar; cd debugtoolbar

2. Add pyramid_debugtoolbar to our project’s dependencies in setup.py as a Setuptools ”ex-


tra” for development:

1 from setuptools import setup


2

3 # List of dependencies installed via `pip install -e .`


4 # by virtue of the Setuptools `install_requires` value below.
5 requires = [
6 'pyramid',
7 'waitress',
8 ]
9

10 # List of dependencies installed via `pip install -e ".[dev]"`


11 # by virtue of the Setuptools `extras_require` value in the Python
12 # dictionary below.
13 dev_requires = [
14 'pyramid_debugtoolbar',
15 ]
16

17 setup(
18 name='tutorial',
19 install_requires=requires,
20 extras_require={
21 'dev': dev_requires,
22 },
23 entry_points={
24 'paste.app_factory': [
25 'main = tutorial:main'
26 ],
27 },
28 )

3. Install our project and its newly added dependency. Note that we use the extra specifier [dev] to
install development requirements and surround it and the period with double quote marks.

$VENV/bin/pip install -e ".[dev]"

4. Our debugtoolbar/development.ini gets a configuration entry for pyramid.


includes:

0.2. Tutorials 85
The Pyramid Web Framework, Version 2.0.2

1 [app:main]
2 use = egg:tutorial
3 pyramid.includes =
4 pyramid_debugtoolbar
5

6 [server:main]
7 use = egg:waitress#main
8 listen = localhost:6543

5. Run the WSGI application with:

$VENV/bin/pserve development.ini --reload

6. Open http://localhost:6543/ in your browser. See the handy toolbar on the right.

Analysis

pyramid_debugtoolbar is a full-fledged Python package, available on PyPI just like thousands of


other Python packages. Thus we start by installing the pyramid_debugtoolbar package into our
virtual environment using normal Python package installation commands.
The pyramid_debugtoolbar Python package is also a Pyramid add-on, which means we need to
include its add-on configuration into our web application. We could do this with imperative configuration
in tutorial/__init__.py by using config.include. Pyramid also supports wiring in add-
on configuration via our development.ini using pyramid.includes. We use this to load the
configuration for the debugtoolbar.
You’ll now see an attractive button on the right side of your browser, which you may click to provide
introspective access to debugging information in a new browser tab. Even better, if your web application
generates an error, you will see a nice traceback on the screen. When you want to disable this toolbar,
there’s no need to change code: you can remove it from pyramid.includes in the relevant .ini
configuration file (thus showing why configuration files are handy).
Note that the toolbar injects a small amount of HTML/CSS into your app just before the closing </body>
tag in order to display itself. If you start to experience otherwise inexplicable client-side weirdness, you
can shut it off by commenting out the pyramid_debugtoolbar line in pyramid.includes tem-
porarily.
Finally we’ve introduced the concept of Setuptools extras. These are optional or recommended features
that may be installed with an ”extras” specifier, in this case, dev. The specifier is the name of a key in a
Python dictionary, and is surrounded by square brackets when invoked on the command line, for example,
. The value for the key is a Python list of dependencies.
See also:
See also pyramid_debugtoolbar.

86 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Extra credit

1. We added pyramid_debugtoolbar to the list of dev_requires dependencies in


debugtoolbar/setup.py. We then installed the dependencies via pip install -e ".
[dev]" by virtue of the Setuptools extras_require value in the Python dictionary. Why did
we add them there instead of in the requires list?

2. Introduce a bug into your application. Change:

def hello_world(request):
return Response('<body><h1>Hello World!</h1></body>')

to:

def hello_world(request):
return xResponse('<body><h1>Hello World!</h1></body>')

Save, and visit http://localhost:6543/ again. Notice the nice traceback display. On the lowest line,
click the ”screen” icon to the right, and try typing the variable names request and Response.
What else can you discover?

05: Unit Tests and pytest

Provide unit testing for our project’s Python code.

Background

As the mantra says, ”Untested code is broken code.” The Python community has had a long culture of
writing test scripts which ensure that your code works correctly as you write it and maintain it in the
future. Pyramid has always had a deep commitment to testing, with 100% test coverage from the earliest
pre-releases.

Python includes a unit testing framework in its standard library. Over the years a number of Python projects,
such as pytest, have extended this framework with alternative test runners that provide more convenience
and functionality. The Pyramid developers use pytest, which we’ll use in this tutorial.

Don’t worry, this tutorial won’t be pedantic about ”test-driven development” (TDD). We’ll do just enough
to ensure that, in each step, we haven’t majorly broken the code. As you’re writing your code, you might
find this more convenient than changing to your browser constantly and clicking reload.

We’ll also leave discussion of pytest-cov for another section.

0.2. Tutorials 87
The Pyramid Web Framework, Version 2.0.2

Objectives

• Write unit tests that ensure the quality of our code.

• Install a Python package (pytest) which helps in our testing.

Steps

1. First we copy the results of the previous step.

cd ..; cp -r debugtoolbar unit_testing; cd unit_testing

2. Add pytest to our project’s dependencies in setup.py as a Setuptools ”extra”:

1 from setuptools import setup


2

3 # List of dependencies installed via `pip install -e .`


4 # by virtue of the Setuptools `install_requires` value below.
5 requires = [
6 'pyramid',
7 'waitress',
8 ]
9

10 # List of dependencies installed via `pip install -e ".[dev]"`


11 # by virtue of the Setuptools `extras_require` value in the Python
12 # dictionary below.
13 dev_requires = [
14 'pyramid_debugtoolbar',
15 'pytest',
16 ]
17

18 setup(
19 name='tutorial',
20 install_requires=requires,
21 extras_require={
22 'dev': dev_requires,
23 },
24 entry_points={
25 'paste.app_factory': [
26 'main = tutorial:main'
27 ],
28 },
29 )

88 CONTENTS
The Pyramid Web Framework, Version 2.0.2

3. Install our project and its newly added dependency. Note that we use the extra specifier [dev] to
install testing requirements for development and surround it and the period with double quote marks.

$VENV/bin/pip install -e ".[dev]"

4. Now we write a simple unit test in unit_testing/tutorial/tests.py:

1 import unittest
2

3 from pyramid import testing


4

6 class TutorialViewTests(unittest.TestCase):
7 def setUp(self):
8 self.config = testing.setUp()
9

10 def tearDown(self):
11 testing.tearDown()
12

13 def test_hello_world(self):
14 from tutorial import hello_world
15

16 request = testing.DummyRequest()
17 response = hello_world(request)
18 self.assertEqual(response.status_code, 200)

5. Now run the tests:

$VENV/bin/pytest tutorial/tests.py -q
.
1 passed in 0.14 seconds

Analysis

Our tests.py imports the Python standard unit testing framework. To make writing Pyramid-oriented
tests more convenient, Pyramid supplies some pyramid.testing helpers which we use in the test
setup and teardown. Our one test imports the view, makes a dummy request, and sees if the view returns
what we expect.

The tests.TutorialViewTests.test_hello_world test is a small example of a unit test.


First, we import the view inside each test. Why not import at the top, like in normal Python code? Because

0.2. Tutorials 89
The Pyramid Web Framework, Version 2.0.2

imports can cause effects that break a test. We’d like our tests to be in units, hence the name unit testing.
Each test should isolate itself to the correct degree.

Our test then makes a fake incoming web request, then calls our Pyramid view. We test the HTTP status
code on the response to make sure it matches our expectations.

Note that our use of pyramid.testing.setUp() and pyramid.testing.tearDown() aren’t


actually necessary here; they are only necessary when your test needs to make use of the config object
(it’s a Configurator) to add stuff to the configuration state before calling the view.

Extra credit

1. Change the test to assert that the response status code should be 404 (meaning, not found). Run
pytest again. Read the error report and see if you can decipher what it is telling you.

2. As a more realistic example, put the tests.py back as you found it, and put an error in your view,
such as a reference to a non-existing variable. Run the tests and see how this is more convenient than
reloading your browser and going back to your code.

3. Finally, for the most realistic test, read about Pyramid Response objects and see how to change
the response code. Run the tests and see how testing confirms the ”contract” that your code claims
to support.

4. How could we add a unit test assertion to test the HTML value of the response body?

5. Why do we import the hello_world view function inside the test_hello_world method
instead of at the top of the module?

See also:

See also Unit, Integration, and Functional Testing and Setuptools Declaring ”Extras” (optional features
with their own dependencies).

06: Functional Testing with WebTest

Write end-to-end full-stack testing using webtest.

90 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Background

Unit tests are a common and popular approach to test-driven development (TDD). In web applications,
though, the templating and entire apparatus of a web site are important parts of the delivered quality. We’d
like a way to test these.

WebTest is a Python package that does functional testing. With WebTest you can write tests which simulate
a full HTTP request against a WSGI application, then test the information in the response. For speed
purposes, WebTest skips the setup/teardown of an actual HTTP server, providing tests that run fast enough
to be part of TDD.

Objectives

• Write a test which checks the contents of the returned HTML.

Steps

1. First we copy the results of the previous step.

cd ..; cp -r unit_testing functional_testing; cd functional_testing

2. Add webtest to our project’s dependencies in setup.py as a Setuptools ”extra”:

1 from setuptools import setup


2

3 # List of dependencies installed via `pip install -e .`


4 # by virtue of the Setuptools `install_requires` value below.
5 requires = [
6 'pyramid',
7 'waitress',
8 ]
9

10 # List of dependencies installed via `pip install -e ".[dev]"`


11 # by virtue of the Setuptools `extras_require` value in the Python
12 # dictionary below.
13 dev_requires = [
14 'pyramid_debugtoolbar',
15 'pytest',
(continues on next page)

0.2. Tutorials 91
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


16 'webtest',
17 ]
18

19 setup(
20 name='tutorial',
21 install_requires=requires,
22 extras_require={
23 'dev': dev_requires,
24 },
25 entry_points={
26 'paste.app_factory': [
27 'main = tutorial:main'
28 ],
29 },
30 )

3. Install our project and its newly added dependency. Note that we use the extra specifier [dev] to
install testing requirements for development and surround it and the period with double quote marks.

$VENV/bin/pip install -e ".[dev]"

4. Let’s extend functional_testing/tutorial/tests.py to include a functional test:

1 import unittest
2

3 from pyramid import testing


4

6 class TutorialViewTests(unittest.TestCase):
7 def setUp(self):
8 self.config = testing.setUp()
9

10 def tearDown(self):
11 testing.tearDown()
12

13 def test_hello_world(self):
14 from tutorial import hello_world
15

16 request = testing.DummyRequest()
17 response = hello_world(request)
18 self.assertEqual(response.status_code, 200)
19

20

(continues on next page)

92 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


21 class TutorialFunctionalTests(unittest.TestCase):
22 def setUp(self):
23 from tutorial import main
24 app = main({})
25 from webtest import TestApp
26

27 self.testapp = TestApp(app)
28

29 def test_hello_world(self):
30 res = self.testapp.get('/', status=200)
31 self.assertIn(b'<h1>Hello World!</h1>', res.body)

Be sure this file is not executable, or pytest may not include your tests.

5. Now run the tests:

$VENV/bin/pytest tutorial/tests.py -q
..
2 passed in 0.25 seconds

Analysis

We now have the end-to-end testing we were looking for. WebTest lets us simply extend our existing
pytest-based test approach with functional tests that are reported in the same output. These new tests
not only cover our templating, but they didn’t dramatically increase the execution time of our tests.

Extra credit

1. Why do our functional tests use b''?

07: Basic Web Handling With Views

Organize a views module with decorators and multiple views.

0.2. Tutorials 93
The Pyramid Web Framework, Version 2.0.2

Background

For the examples so far, the hello_world function is a ”view”. In Pyramid, views are the primary way
to accept web requests and return responses.

So far our examples place everything in one file:

• The view function

• Its registration with the configurator

• The route to map it to a URL

• The WSGI application launcher

Let’s move the views out to their own views.py module and change our startup code to scan that module,
looking for decorators that set up the views. Let’s also add a second view and update our tests.

Objectives

• Move views into a module that is scanned by the configurator.

• Create decorators that do declarative configuration.

Steps

1. Let’s begin by using the previous package as a starting point for a new distribution, then making it
active:

cd ..; cp -r functional_testing views; cd views


$VENV/bin/pip install -e .

2. Our views/tutorial/__init__.py gets a lot shorter:

94 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 config = Configurator(settings=settings)
6 config.add_route('home', '/')
7 config.add_route('hello', '/howdy')
8 config.scan('.views')
9 return config.make_wsgi_app()

3. Let’s add a module views/tutorial/views.py that is focused on handling requests and re-
sponses:

1 from pyramid.response import Response


2 from pyramid.view import view_config
3

5 # First view, available at http://localhost:6543/


6 @view_config(route_name='home')
7 def home(request):
8 return Response('<body>Visit <a href="/howdy">hello</a></body>')
9

10

11 # /howdy
12 @view_config(route_name='hello')
13 def hello(request):
14 return Response('<body>Go back <a href="/">home</a></body>')

4. Update the tests to cover the two new views:

1 import unittest
2

3 from pyramid import testing


4

6 class TutorialViewTests(unittest.TestCase):
7 def setUp(self):
8 self.config = testing.setUp()
9

10 def tearDown(self):
11 testing.tearDown()
12

13 def test_home(self):
(continues on next page)

0.2. Tutorials 95
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


14 from .views import home
15

16 request = testing.DummyRequest()
17 response = home(request)
18 self.assertEqual(response.status_code, 200)
19 self.assertIn(b'Visit', response.body)
20

21 def test_hello(self):
22 from .views import hello
23

24 request = testing.DummyRequest()
25 response = hello(request)
26 self.assertEqual(response.status_code, 200)
27 self.assertIn(b'Go back', response.body)
28

29

30 class TutorialFunctionalTests(unittest.TestCase):
31 def setUp(self):
32 from tutorial import main
33 app = main({})
34 from webtest import TestApp
35

36 self.testapp = TestApp(app)
37

38 def test_home(self):
39 res = self.testapp.get('/', status=200)
40 self.assertIn(b'<body>Visit', res.body)
41

42 def test_hello(self):
43 res = self.testapp.get('/howdy', status=200)
44 self.assertIn(b'<body>Go back', res.body)

5. Now run the tests:

$VENV/bin/pytest tutorial/tests.py -q
....
4 passed in 0.28 seconds

6. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

7. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser.

96 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Analysis

We added some more URLs, but we also removed the view code from the application startup code in
tutorial/__init__.py. Our views, and their view registrations (via decorators) are now in a module
views.py, which is scanned via config.scan('.views').

We have two views, each leading to the other. If you start at http://localhost:6543/, you get a response with
a link to the next view. The hello view (available at the URL /howdy) has a link back to the first view.

This step also shows that the name appearing in the URL, the name of the ”route” that maps a URL to a
view, and the name of the view, can all be different. More on routes later.

Earlier we saw config.add_view as one way to configure a view. This section introduces
@view_config. Pyramid’s configuration supports imperative configuration, such as the config.
add_view in the previous example. You can also use declarative configuration, in which a Python
decorator is placed on the line above the view. Both approaches result in the same final configuration, thus
usually, it is simply a matter of taste.

Extra credit

1. What does the dot in .views signify?

2. Why might assertIn be a better choice in testing the text in responses than assertEqual?

See also:

Views, View Configuration, and Debugging View Configuration

08: HTML Generation With Templating

Most web frameworks don’t embed HTML in programming code. Instead, they pass data into a templating
system. In this step we look at the basics of using HTML templates in Pyramid.

0.2. Tutorials 97
The Pyramid Web Framework, Version 2.0.2

Background

Ouch. We have been making our own Response and filling the response body with HTML. You usually
won’t embed an HTML string directly in Python, but instead will use a templating language.

Pyramid doesn’t mandate a particular database system, form library, and so on. It encourages replaceabil-
ity. This applies equally to templating, which is fortunate: developers have strong views about template
languages. As of Pyramid 1.5a2, Pyramid doesn’t even bundle a template language!

It does, however, have strong ties to Jinja2, Mako, and Chameleon. In this step we see how to add pyra-
mid_chameleon to your project, then change your views to use templating.

Objectives

• Enable the pyramid_chameleon Pyramid add-on.

• Generate HTML from template files.

• Connect the templates as ”renderers” for view code.

• Change the view code to simply return data.

Steps

1. Let’s begin by using the previous package as a starting point for a new project:

cd ..; cp -r views templating; cd templating

2. This step depends on pyramid_chameleon, so add it as a dependency in templating/


setup.py:

98 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from setuptools import setup


2

3 # List of dependencies installed via `pip install -e .`


4 # by virtue of the Setuptools `install_requires` value below.
5 requires = [
6 'pyramid',
7 'pyramid_chameleon',
8 'waitress',
9 ]
10

11 # List of dependencies installed via `pip install -e ".[dev]"`


12 # by virtue of the Setuptools `extras_require` value in the Python
13 # dictionary below.
14 dev_requires = [
15 'pyramid_debugtoolbar',
16 'pytest',
17 'webtest',
18 ]
19

20 setup(
21 name='tutorial',
22 install_requires=requires,
23 extras_require={
24 'dev': dev_requires,
25 },
26 entry_points={
27 'paste.app_factory': [
28 'main = tutorial:main'
29 ],
30 },
31 )

3. Now we can activate the development-mode distribution:

$VENV/bin/pip install -e .

4. We need to connect pyramid_chameleon as a renderer by making a call in the setup of


templating/tutorial/__init__.py:

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


(continues on next page)

0.2. Tutorials 99
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


5 config = Configurator(settings=settings)
6 config.include('pyramid_chameleon')
7 config.add_route('home', '/')
8 config.add_route('hello', '/howdy')
9 config.scan('.views')
10 return config.make_wsgi_app()

5. Our templating/tutorial/views.py no longer has HTML in it:

1 from pyramid.view import view_config


2

4 # First view, available at http://localhost:6543/


5 @view_config(route_name='home', renderer='home.pt')
6 def home(request):
7 return {'name': 'Home View'}
8

10 # /howdy
11 @view_config(route_name='hello', renderer='home.pt')
12 def hello(request):
13 return {'name': 'Hello View'}

6. Instead we have templating/tutorial/home.pt as a template:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Quick Tutorial: ${name}</title>
</head>
<body>
<h1>Hi ${name}</h1>
</body>
</html>

7. For convenience, change templating/development.ini to reload templates automatically


with pyramid.reload_templates:

[app:main]
use = egg:tutorial
pyramid.reload_templates = true
(continues on next page)

100 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


pyramid.includes =
pyramid_debugtoolbar

[server:main]
use = egg:waitress#main
listen = localhost:6543

8. Our unit tests in templating/tutorial/tests.py can focus on data:

1 import unittest
2

3 from pyramid import testing


4

6 class TutorialViewTests(unittest.TestCase):
7 def setUp(self):
8 self.config = testing.setUp()
9

10 def tearDown(self):
11 testing.tearDown()
12

13 def test_home(self):
14 from .views import home
15

16 request = testing.DummyRequest()
17 response = home(request)
18 # Our view now returns data
19 self.assertEqual('Home View', response['name'])
20

21 def test_hello(self):
22 from .views import hello
23

24 request = testing.DummyRequest()
25 response = hello(request)
26 # Our view now returns data
27 self.assertEqual('Hello View', response['name'])
28

29

30 class TutorialFunctionalTests(unittest.TestCase):
31 def setUp(self):
32 from tutorial import main
33 app = main({})
34 from webtest import TestApp
35

(continues on next page)

0.2. Tutorials 101


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


36 self.testapp = TestApp(app)
37

38 def test_home(self):
39 res = self.testapp.get('/', status=200)
40 self.assertIn(b'<h1>Hi Home View', res.body)
41

42 def test_hello(self):
43 res = self.testapp.get('/howdy', status=200)
44 self.assertIn(b'<h1>Hi Hello View', res.body)

9. Now run the tests:

$VENV/bin/pytest tutorial/tests.py -q
....
4 passed in 0.46 seconds

10. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

11. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser.

Analysis

Ahh, that looks better. We have a view that is focused on Python code. Our @view_config decorator
specifies a renderer that points to our template file. Our view then simply returns data which is then
supplied to our template. Note that we used the same template for both views.

Note the effect on testing. We can focus on having a data-oriented contract with our view code.

See also:

Templates, Debugging Templates, and Available Add-On Template System Bindings.

09: Organizing Views With View Classes

Change our view functions to be methods on a view class, then move some declarations to the class level.

102 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Background

So far our views have been simple, free-standing functions. Many times your views are related to one
another. They may consist of different ways to look at or work on the same data, or be a REST API that
handles multiple operations. Grouping these views together as a view class makes sense:

• Group views.

• Centralize some repetitive defaults.

• Share some state and helpers.

In this step we just do the absolute minimum to convert the existing views to a view class. In a later tutorial
step, we’ll examine view classes in depth.

Objectives

• Group related views into a view class.

• Centralize configuration with class-level @view_defaults.

Steps

1. First we copy the results of the previous step:

cd ..; cp -r templating view_classes; cd view_classes


$VENV/bin/pip install -e .

2. Our view_classes/tutorial/views.py now has a view class with our two views:

0.2. Tutorials 103


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.view import (


2 view_config,
3 view_defaults
4 )
5

6 @view_defaults(renderer='home.pt')
7 class TutorialViews:
8 def __init__(self, request):
9 self.request = request
10

11 @view_config(route_name='home')
12 def home(self):
13 return {'name': 'Home View'}
14

15 @view_config(route_name='hello')
16 def hello(self):
17 return {'name': 'Hello View'}

3. Our unit tests in view_classes/tutorial/tests.py don’t run, so let’s modify them to


import the view class, and make an instance before getting a response:

1 import unittest
2

3 from pyramid import testing


4

6 class TutorialViewTests(unittest.TestCase):
7 def setUp(self):
8 self.config = testing.setUp()
9

10 def tearDown(self):
11 testing.tearDown()
12

13 def test_home(self):
14 from .views import TutorialViews
15

16 request = testing.DummyRequest()
17 inst = TutorialViews(request)
18 response = inst.home()
19 self.assertEqual('Home View', response['name'])
20

21 def test_hello(self):
22 from .views import TutorialViews
23

24 request = testing.DummyRequest()
(continues on next page)

104 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


25 inst = TutorialViews(request)
26 response = inst.hello()
27 self.assertEqual('Hello View', response['name'])
28

29

30 class TutorialFunctionalTests(unittest.TestCase):
31 def setUp(self):
32 from tutorial import main
33 app = main({})
34 from webtest import TestApp
35

36 self.testapp = TestApp(app)
37

38 def test_home(self):
39 res = self.testapp.get('/', status=200)
40 self.assertIn(b'<h1>Hi Home View', res.body)
41

42 def test_hello(self):
43 res = self.testapp.get('/howdy', status=200)
44 self.assertIn(b'<h1>Hi Hello View', res.body)

4. Now run the tests:

$VENV/bin/pytest tutorial/tests.py -q
....
4 passed in 0.34 seconds

5. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

6. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser.

Analysis

To ease the transition to view classes, we didn’t introduce any new functionality. We simply changed the
view functions to methods on a view class, then updated the tests.

In our TutorialViews view class, you can see that our two view functions are logically grouped to-
gether as methods on a common class. Since the two views shared the same template, we could move that
to a @view_defaults decorator at the class level.

0.2. Tutorials 105


The Pyramid Web Framework, Version 2.0.2

The tests needed to change. Obviously we needed to import the view class. But you can also see the pattern
in the tests of instantiating the view class with the dummy request first, then calling the view method being
tested.

See also:

Defining a View Callable as a Class

10: Handling Web Requests and Responses

Web applications handle incoming requests and return outgoing responses. Pyramid makes working with
requests and responses convenient and reliable.

Objectives

• Learn the background on Pyramid’s choices for requests and responses.

• Grab data out of the request.

• Change information in the response headers.

Background

Developing for the web means processing web requests. As this is a critical part of a web application, web
developers need a robust, mature set of software for web requests and returning web responses.

Pyramid has always fit nicely into the existing world of Python web development (virtual environ-
ments, packaging, cookiecutters, first to embrace Python 3, and so on). Pyramid turned to the well-
regarded WebOb Python library for request and response handling. In our example above, Pyramid hands
hello_world a request that is based on WebOb.

Steps

1. First we copy the results of the view_classes step:

106 CONTENTS
The Pyramid Web Framework, Version 2.0.2

cd ..; cp -r view_classes request_response; cd request_response


$VENV/bin/pip install -e .

2. Simplify the routes in request_response/tutorial/__init__.py:

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 config = Configurator(settings=settings)
6 config.add_route('home', '/')
7 config.add_route('plain', '/plain')
8 config.scan('.views')
9 return config.make_wsgi_app()

3. We only need one view in request_response/tutorial/views.py:

1 from pyramid.httpexceptions import HTTPFound


2 from pyramid.response import Response
3 from pyramid.view import view_config
4

6 class TutorialViews:
7 def __init__(self, request):
8 self.request = request
9

10 @view_config(route_name='home')
11 def home(self):
12 return HTTPFound(location='/plain')
13

14 @view_config(route_name='plain')
15 def plain(self):
16 name = self.request.params.get('name', 'No Name Provided')
17

18 body = 'URL %s with name: %s' % (self.request.url, name)


19 return Response(
20 content_type='text/plain',
21 body=body
22 )

4. Update the tests in request_response/tutorial/tests.py:

0.2. Tutorials 107


The Pyramid Web Framework, Version 2.0.2

1 import unittest
2

3 from pyramid import testing


4

6 class TutorialViewTests(unittest.TestCase):
7 def setUp(self):
8 self.config = testing.setUp()
9

10 def tearDown(self):
11 testing.tearDown()
12

13 def test_home(self):
14 from .views import TutorialViews
15

16 request = testing.DummyRequest()
17 inst = TutorialViews(request)
18 response = inst.home()
19 self.assertEqual(response.status, '302 Found')
20

21 def test_plain_without_name(self):
22 from .views import TutorialViews
23

24 request = testing.DummyRequest()
25 inst = TutorialViews(request)
26 response = inst.plain()
27 self.assertIn(b'No Name Provided', response.body)
28

29 def test_plain_with_name(self):
30 from .views import TutorialViews
31

32 request = testing.DummyRequest()
33 request.GET['name'] = 'Jane Doe'
34 inst = TutorialViews(request)
35 response = inst.plain()
36 self.assertIn(b'Jane Doe', response.body)
37

38

39 class TutorialFunctionalTests(unittest.TestCase):
40 def setUp(self):
41 from tutorial import main
42

43 app = main({})
44 from webtest import TestApp
45

46 self.testapp = TestApp(app)
(continues on next page)

108 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


47

48 def test_plain_without_name(self):
49 res = self.testapp.get('/plain', status=200)
50 self.assertIn(b'No Name Provided', res.body)
51

52 def test_plain_with_name(self):
53 res = self.testapp.get('/plain?name=Jane%20Doe', status=200)
54 self.assertIn(b'Jane Doe', res.body)

5. Now run the tests:

$VENV/bin/pytest tutorial/tests.py -q
.....
5 passed in 0.30 seconds

6. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

7. Open http://localhost:6543/ in your browser. You will be redirected to http://localhost:6543/plain.

8. Open http://localhost:6543/plain?name=alice in your browser.

Analysis

In this view class, we have two routes and two views, with the first leading to the second by an HTTP
redirect. Pyramid can generate redirects by returning a special object from a view or raising a special
exception.

In this Pyramid view, we get the URL being visited from request.url. Also, if you visited http:
//localhost:6543/plain?name=alice, the name is included in the body of the response:

URL http://localhost:6543/plain?name=alice with name: alice

Finally, we set the response’s content type and body, then return the response.

We updated the unit and functional tests to prove that our code does the redirection, but also handles
sending and not sending /plain?name.

0.2. Tutorials 109


The Pyramid Web Framework, Version 2.0.2

Extra credit

1. Could we also raise HTTPFound(location='/plain') instead of returning it? If so,


what’s the difference?

See also:

Request and Response Objects, generate redirects

11: Dispatching URLs To Views With Routing

Routing matches incoming URL patterns to view code. Pyramid’s routing has a number of useful features.

Background

Writing web applications usually means sophisticated URL design. We just saw some Pyramid machinery
for requests and views. Let’s look at features that help in routing.

Previously we saw the basics of routing URLs to views in Pyramid.

• Your project’s ”setup” code registers a route name to be used when matching part of the URL

• Elsewhere a view is configured to be called for that route name.

Why do this twice? Other Python web frameworks let you create a route and associate it with a view
in one step. As illustrated in Routes need relative ordering, multiple routes might match the same URL
pattern. Rather than provide ways to help guess, Pyramid lets you be explicit in ordering. Pyramid also
gives facilities to avoid the problem. It’s relatively easy to build a system that uses implicit route ordering
with Pyramid too. See The Groundhog series of screencasts if you’re interested in doing so.

Objectives

• Define a route that extracts part of the URL into a Python dictionary.

• Use that dictionary data in a view.

110 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Steps

1. First we copy the results of the view_classes step:

cd ..; cp -r view_classes routing; cd routing


$VENV/bin/pip install -e .

2. Our routing/tutorial/__init__.py needs a route with a replacement pattern:

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 config = Configurator(settings=settings)
6 config.include('pyramid_chameleon')
7 config.add_route('home', '/howdy/{first}/{last}')
8 config.scan('.views')
9 return config.make_wsgi_app()

3. We just need one view in routing/tutorial/views.py:

1 from pyramid.view import (


2 view_config,
3 view_defaults
4 )
5

7 @view_defaults(renderer='home.pt')
8 class TutorialViews:
9 def __init__(self, request):
10 self.request = request
11

12 @view_config(route_name='home')
13 def home(self):
14 first = self.request.matchdict['first']
15 last = self.request.matchdict['last']
16 return {
17 'name': 'Home View',
18 'first': first,
19 'last': last
20 }

4. We just need one view in routing/tutorial/home.pt:

0.2. Tutorials 111


The Pyramid Web Framework, Version 2.0.2

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <title>Quick Tutorial: ${name}</title>
5 </head>
6 <body>
7 <h1>${name}</h1>
8 <p>First: ${first}, Last: ${last}</p>
9 </body>
10 </html>

5. Update routing/tutorial/tests.py:

1 import unittest
2

3 from pyramid import testing


4

6 class TutorialViewTests(unittest.TestCase):
7 def setUp(self):
8 self.config = testing.setUp()
9

10 def tearDown(self):
11 testing.tearDown()
12

13 def test_home(self):
14 from .views import TutorialViews
15

16 request = testing.DummyRequest()
17 request.matchdict['first'] = 'First'
18 request.matchdict['last'] = 'Last'
19 inst = TutorialViews(request)
20 response = inst.home()
21 self.assertEqual(response['first'], 'First')
22 self.assertEqual(response['last'], 'Last')
23

24

25 class TutorialFunctionalTests(unittest.TestCase):
26 def setUp(self):
27 from tutorial import main
28 app = main({})
29 from webtest import TestApp
30

31 self.testapp = TestApp(app)
32

(continues on next page)

112 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


33 def test_home(self):
34 res = self.testapp.get('/howdy/Jane/Doe', status=200)
35 self.assertIn(b'Jane', res.body)
36 self.assertIn(b'Doe', res.body)

6. Now run the tests:

$VENV/bin/pytest tutorial/tests.py -q
..
2 passed in 0.39 seconds

7. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

8. Open http://localhost:6543/howdy/amy/smith in your browser.

Analysis

In __init__.py we see an important change in our route declaration:

config.add_route('hello', '/howdy/{first}/{last}')

With this we tell the configurator that our URL has a ”replacement pattern”. With this, URLs such as
/howdy/amy/smith will assign amy to first and smith to last. We can then use this data in our
view:

self.request.matchdict['first']
self.request.matchdict['last']

request.matchdict contains values from the URL that match the ”replacement patterns” (the curly
braces) in the route declaration. This information can then be used anywhere in Pyramid that has access
to the request.

0.2. Tutorials 113


The Pyramid Web Framework, Version 2.0.2

Extra credit

1. What happens if you to go the URL http://localhost:6543/howdy? Is this the result that you ex-
pected?

See also:

Weird Stuff You Can Do With URL Dispatch

12: Templating With jinja2

We just said Pyramid doesn’t prefer one templating language over another. Time to prove it. Jinja2 is
a popular templating system, used in Flask and modeled after Django’s templates. Let’s add pyra-
mid_jinja2, a Pyramid add-on which enables Jinja2 as a renderer in our Pyramid applications.

Objectives

• Show Pyramid’s support for different templating systems.

• Learn about installing Pyramid add-ons.

Steps

1. In this step let’s start by copying the view_class step’s directory from a few steps ago.

cd ..; cp -r view_classes jinja2; cd jinja2

2. Add pyramid_jinja2 to our project’s dependencies in setup.py:

114 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from setuptools import setup


2

3 # List of dependencies installed via `pip install -e .`


4 # by virtue of the Setuptools `install_requires` value below.
5 requires = [
6 'pyramid',
7 'pyramid_chameleon',
8 'pyramid_jinja2',
9 'waitress',
10 ]
11

12 # List of dependencies installed via `pip install -e ".[dev]"`


13 # by virtue of the Setuptools `extras_require` value in the Python
14 # dictionary below.
15 dev_requires = [
16 'pyramid_debugtoolbar',
17 'pytest',
18 'webtest',
19 ]
20

21 setup(
22 name='tutorial',
23 install_requires=requires,
24 extras_require={
25 'dev': dev_requires,
26 },
27 entry_points={
28 'paste.app_factory': [
29 'main = tutorial:main'
30 ],
31 },
32 )

3. Install our project and its newly added dependency.

$VENV/bin/pip install -e .

4. We need to include pyramid_jinja2 in jinja2/tutorial/__init__.py:

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


(continues on next page)

0.2. Tutorials 115


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


5 config = Configurator(settings=settings)
6 config.include('pyramid_jinja2')
7 config.add_route('home', '/')
8 config.add_route('hello', '/howdy')
9 config.scan('.views')
10 return config.make_wsgi_app()

5. Our jinja2/tutorial/views.py simply changes its renderer:

1 from pyramid.view import (


2 view_config,
3 view_defaults
4 )
5

7 @view_defaults(renderer='home.jinja2')
8 class TutorialViews:
9 def __init__(self, request):
10 self.request = request
11

12 @view_config(route_name='home')
13 def home(self):
14 return {'name': 'Home View'}
15

16 @view_config(route_name='hello')
17 def hello(self):
18 return {'name': 'Hello View'}

6. Add jinja2/tutorial/home.jinja2 as a template:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Quick Tutorial: {{ name }}</title>
</head>
<body>
<h1>Hi {{ name }}</h1>
</body>
</html>

7. Now run the tests:

116 CONTENTS
The Pyramid Web Framework, Version 2.0.2

$VENV/bin/pytest tutorial/tests.py -q
....
4 passed in 0.40 seconds

8. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

9. Open http://localhost:6543/ in your browser.

Analysis

Getting a Pyramid add-on into Pyramid is simple. First you use normal Python package installation tools
to install the add-on package into your Python virtual environment. You then tell Pyramid’s configurator
to run the setup code in the add-on. In this case the setup code told Pyramid to make a new ”renderer”
available that looked for .jinja2 file extensions.

Our view code stayed largely the same. We simply changed the file extension on the renderer. For the
template, the syntax for Chameleon and Jinja2’s basic variable insertion is very similar.

Extra credit

1. Our project now depends on pyramid_jinja2. We installed that dependency manually. What
is another way we could have made the association?

2. We used config.include which is an imperative configuration to get the Configurator to load


pyramid_jinja2’s configuration. What is another way we could include it into the config?

See also:

Jinja2 homepage, and pyramid_jinja2 Overview

13: CSS/JS/Images Files With Static Assets

Of course the Web is more than just markup. You need static assets: CSS, JS, and images. Let’s point our
web app at a directory where Pyramid will serve some static assets.

0.2. Tutorials 117


The Pyramid Web Framework, Version 2.0.2

Objectives

• Publish a directory of static assets at a URL.

• Use Pyramid to help generate URLs to files in that directory.

Steps

1. First we copy the results of the view_classes step:

cd ..; cp -r view_classes static_assets; cd static_assets


$VENV/bin/pip install -e .

2. We add a call config.add_static_view in static_assets/tutorial/__init__.


py:

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 config = Configurator(settings=settings)
6 config.include('pyramid_chameleon')
7 config.add_route('home', '/')
8 config.add_route('hello', '/howdy')
9 config.add_static_view(name='static', path='tutorial:static')
10 config.scan('.views')
11 return config.make_wsgi_app()

3. We can add a CSS link in the <head> of our template at static_assets/tutorial/home.


pt:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Quick Tutorial: ${name}</title>
<link rel="stylesheet"
href="${request.static_url('tutorial:static/app.css') }"/>
</head>
<body>
<h1>Hi ${name}</h1>
</body>
</html>

118 CONTENTS
The Pyramid Web Framework, Version 2.0.2

4. Add a CSS file at static_assets/tutorial/static/app.css:

body {
margin: 2em;
font-family: sans-serif;
}

5. We add a functional test that asserts that the newly added static file is delivered:

46 def test_css(self):
47 res = self.testapp.get('/static/app.css', status=200)
48 self.assertIn(b'body', res.body)

6. Now run the tests:

$VENV/bin/pytest tutorial/tests.py -q
....
5 passed in 0.50 seconds

7. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

8. Open http://localhost:6543/ in your browser and note the new font.

Analysis

We changed our WSGI application to map requests under http://localhost:6543/static/ to files and directo-
ries inside a static directory inside our tutorial package. This directory contained app.css.

We linked to the CSS in our template. We could have hard-coded this link to /static/app.css. But
what if the site is later moved under /somesite/static/? Or perhaps the web developer changes the
arrangement on disk? Pyramid gives a helper that provides flexibility on URL generation:

${request.static_url('tutorial:static/app.css')}

This matches the path='tutorial:static' in our config.add_static_view registration.


By using request.static_url to generate the full URL to the static assets, you both ensure you stay
in sync with the configuration and gain refactoring flexibility later.

0.2. Tutorials 119


The Pyramid Web Framework, Version 2.0.2

Extra credit

1. There is also a request.static_path API. How does this differ from request.
static_url?

See also:

Static Assets, Preventing HTTP Caching, and Influencing HTTP Caching

14: AJAX Development With JSON Renderers

Modern web apps are more than rendered HTML. Dynamic pages now use JavaScript to update the UI in
the browser by requesting server data as JSON. Pyramid supports this with a JSON renderer.

Background

As we saw in 08: HTML Generation With Templating, view declarations can specify a renderer. Output
from the view is then run through the renderer, which generates and returns the response. We first used a
Chameleon renderer, then a Jinja2 renderer.

Renderers aren’t limited, however, to templates that generate HTML. Pyramid supplies a JSON renderer
which takes Python data, serializes it to JSON, and performs some other functions such as setting the
content type. In fact you can write your own renderer (or extend a built-in renderer) containing custom
logic for your unique application.

Steps

1. First we copy the results of the view_classes step:

cd ..; cp -r view_classes json; cd json


$VENV/bin/pip install -e .

2. We add a new route for hello_json in json/tutorial/__init__.py:

120 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 config = Configurator(settings=settings)
6 config.include('pyramid_chameleon')
7 config.add_route('home', '/')
8 config.add_route('hello', '/howdy')
9 config.add_route('hello_json', '/howdy.json')
10 config.scan('.views')
11 return config.make_wsgi_app()

3. Rather than implement a new view, we will ”stack” another decorator on the hello view in views.
py:

1 from pyramid.view import (


2 view_config,
3 view_defaults
4 )
5

7 @view_defaults(renderer='home.pt')
8 class TutorialViews:
9 def __init__(self, request):
10 self.request = request
11

12 @view_config(route_name='home')
13 def home(self):
14 return {'name': 'Home View'}
15

16 @view_config(route_name='hello')
17 @view_config(route_name='hello_json', renderer='json')
18 def hello(self):
19 return {'name': 'Hello View'}

4. We need a new functional test at the end of json/tutorial/tests.py:

1 import unittest
2

3 from pyramid import testing


4

6 class TutorialViewTests(unittest.TestCase):
(continues on next page)

0.2. Tutorials 121


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


7 def setUp(self):
8 self.config = testing.setUp()
9

10 def tearDown(self):
11 testing.tearDown()
12

13 def test_home(self):
14 from .views import TutorialViews
15

16 request = testing.DummyRequest()
17 inst = TutorialViews(request)
18 response = inst.home()
19 self.assertEqual('Home View', response['name'])
20

21 def test_hello(self):
22 from .views import TutorialViews
23

24 request = testing.DummyRequest()
25 inst = TutorialViews(request)
26 response = inst.hello()
27 self.assertEqual('Hello View', response['name'])
28

29

30 class TutorialFunctionalTests(unittest.TestCase):
31 def setUp(self):
32 from tutorial import main
33 app = main({})
34 from webtest import TestApp
35

36 self.testapp = TestApp(app)
37

38 def test_home(self):
39 res = self.testapp.get('/', status=200)
40 self.assertIn(b'<h1>Hi Home View', res.body)
41

42 def test_hello(self):
43 res = self.testapp.get('/howdy', status=200)
44 self.assertIn(b'<h1>Hi Hello View', res.body)
45

46 def test_hello_json(self):
47 res = self.testapp.get('/howdy.json', status=200)
48 self.assertIn(b'{"name": "Hello View"}', res.body)
49 self.assertEqual(res.content_type, 'application/json')
50

5. Run the tests:

122 CONTENTS
The Pyramid Web Framework, Version 2.0.2

$VENV/bin/pytest tutorial/tests.py -q
.....
5 passed in 0.47 seconds

6. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

7. Open http://localhost:6543/howdy.json in your browser and you will see the resulting JSON re-
sponse.

Analysis

Earlier we changed our view functions and methods to return Python data. This change to a data-oriented
view layer made test writing easier, decoupling the templating from the view logic.

Since Pyramid has a JSON renderer as well as the templating renderers, it is an easy step to return JSON.
In this case we kept the exact same view and arranged to return a JSON encoding of the view data. We did
this by:

• Adding a route to map /howdy.json to a route name.

• Providing a @view_config that associated that route name with an existing view.

• Overriding the view defaults in the view config that mentions the hello_json route, so that
when the route is matched, we use the JSON renderer rather than the home.pt template renderer
that would otherwise be used.

In fact, for pure AJAX-style web applications, we could re-use the existing route by using Pyramid’s view
predicates to match on the Accepts: header sent by modern AJAX implementations.

Pyramid’s JSON renderer uses the base Python JSON encoder, thus inheriting its strengths and weaknesses.
For example, Python can’t natively JSON encode DateTime objects. There are a number of solutions for
this in Pyramid, including extending the JSON renderer with a custom renderer.

See also:

Writing View Callables Which Use a Renderer, JSON Renderer, and Adding and Changing Renderers

0.2. Tutorials 123


The Pyramid Web Framework, Version 2.0.2

15: More With View Classes

Group views into a class, sharing configuration, state, and logic.

Background

As part of its mission to help build more ambitious web applications, Pyramid provides many more features
for views and view classes.

The Pyramid documentation discusses views as a Python ”callable”. This callable can be a function, an
object with a __call__, or a Python class. In this last case, methods on the class can be decorated with
@view_config to register the class methods with the configurator as a view.

At first, our views were simple, free-standing functions. Many times your views are related: different ways
to look at or work on the same data, or a REST API that handles multiple operations. Grouping these
together as a view class makes sense:

• Group views.

• Centralize some repetitive defaults.

• Share some state and helpers.

Pyramid views have view predicates that determine which view is matched to a request, based on factors
such as the request method, the form parameters, and so on. These predicates provide many axes of
flexibility.

The following shows a simple example with four operations: view a home page which leads to a form, save
a change, and press the delete button.

Objectives

• Group related views into a view class.

• Centralize configuration with class-level @view_defaults.

• Dispatch one route/URL to multiple views based on request data.

• Share states and logic between views and templates via the view class.

124 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Steps

1. First we copy the results of the templating step:

cd ..; cp -r templating more_view_classes; cd more_view_classes


$VENV/bin/pip install -e .

2. Our route in more_view_classes/tutorial/__init__.py needs some replacement pat-


terns:

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 config = Configurator(settings=settings)
6 config.include('pyramid_chameleon')
7 config.add_route('home', '/')
8 config.add_route('hello', '/howdy/{first}/{last}')
9 config.scan('.views')
10 return config.make_wsgi_app()

3. Our more_view_classes/tutorial/views.py now has a view class with several views:

1 from pyramid.view import (


2 view_config,
3 view_defaults
4 )
5

7 @view_defaults(route_name='hello')
8 class TutorialViews:
9 def __init__(self, request):
10 self.request = request
11 self.view_name = 'TutorialViews'
12

13 @property
14 def full_name(self):
15 first = self.request.matchdict['first']
16 last = self.request.matchdict['last']
17 return first + ' ' + last
18

19 @view_config(route_name='home', renderer='home.pt')
20 def home(self):
(continues on next page)

0.2. Tutorials 125


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


21 return {'page_title': 'Home View'}
22

23 # Retrieving /howdy/first/last the first time


24 @view_config(renderer='hello.pt')
25 def hello(self):
26 return {'page_title': 'Hello View'}
27

28 # Posting to /howdy/first/last via the "Edit" submit button


29 @view_config(request_method='POST', renderer='edit.pt')
30 def edit(self):
31 new_name = self.request.params['new_name']
32 return {'page_title': 'Edit View', 'new_name': new_name}
33

34 # Posting to /howdy/first/last via the "Delete" submit button


35 @view_config(request_method='POST', request_param='form.delete',
36 renderer='delete.pt')
37 def delete(self):
38 print ('Deleted')
39 return {'page_title': 'Delete View'}

4. Our primary view needs a template at more_view_classes/tutorial/home.pt:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Quick Tutorial: ${view.view_name} - ${page_title}</title>
</head>
<body>
<h1>${view.view_name} - ${page_title}</h1>

<p>Go to the <a href="${request.route_url('hello', first='jane',


last='doe')}">form</a>.</p>
</body>
</html>

5. Ditto for our other view from the previous section at more_view_classes/tutorial/
hello.pt:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Quick Tutorial: ${view.view_name} - ${page_title}</title>
</head>
(continues on next page)

126 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


<body>
<h1>${view.view_name} - ${page_title}</h1>
<p>Welcome, ${view.full_name}</p>
<form method="POST"
action="${request.current_route_url()}">
<input name="new_name"/>
<input type="submit" name="form.edit" value="Save"/>
<input type="submit" name="form.delete" value="Delete"/>
</form>
</body>
</html>

6. We have an edit view that also needs a template at more_view_classes/tutorial/edit.


pt:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Quick Tutorial: ${view.view_name} - ${page_title}</title>
</head>
<body>
<h1>${view.view_name} - ${page_title}</h1>
<p>You submitted <code>${new_name}</code></p>
</body>
</html>

7. And finally the delete view’s template at more_view_classes/tutorial/delete.pt:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Quick Tutorial: ${page_title}</title>
</head>
<body>
<h1>${view.view_name} - ${page_title}</h1>
</body>
</html>

8. Our tests in more_view_classes/tutorial/tests.py fail, so let’s modify them:

0.2. Tutorials 127


The Pyramid Web Framework, Version 2.0.2

1 import unittest
2

3 from pyramid import testing


4

6 class TutorialViewTests(unittest.TestCase):
7 def setUp(self):
8 self.config = testing.setUp()
9

10 def tearDown(self):
11 testing.tearDown()
12

13 def test_home(self):
14 from .views import TutorialViews
15

16 request = testing.DummyRequest()
17 inst = TutorialViews(request)
18 response = inst.home()
19 self.assertEqual('Home View', response['page_title'])
20

21 class TutorialFunctionalTests(unittest.TestCase):
22 def setUp(self):
23 from tutorial import main
24 app = main({})
25 from webtest import TestApp
26

27 self.testapp = TestApp(app)
28

29 def test_home(self):
30 res = self.testapp.get('/', status=200)
31 self.assertIn(b'TutorialViews - Home View', res.body)

9. Now run the tests:

$VENV/bin/pytest tutorial/tests.py -q
..
2 passed in 0.40 seconds

10. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

11. Open http://localhost:6543/howdy/jane/doe in your browser. Click the Save and Delete buttons,
and watch the output in the console window.

128 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Analysis

As you can see, the four views are logically grouped together. Specifically:

• We have a home view available at http://localhost:6543/ with a clickable link to the hello view.

• The second view is returned when you go to /howdy/jane/doe. This URL is mapped to the
hello route that we centrally set using the optional @view_defaults.

• The third view is returned when the form is submitted with a POST method. This rule is specified
in the @view_config for that view.

• The fourth view is returned when clicking on a button such as <input type="submit"
name="form.delete" value="Delete"/>.

In this step we show, using the following information as criteria, how to decide which view to use:

• Method of the HTTP request (GET, POST, etc.)

• Parameter information in the request (submitted form field names)

We also centralize part of the view configuration to the class level with @view_defaults, then in one
view, override that default just for that one view. Finally, we put this commonality between views to work
in the view class by sharing:

• State assigned in TutorialViews.__init__

• A computed value

These are then available both in the view methods and in the templates (e.g., ${view.view_name}
and ${view.full_name}).

As a note, we made a switch in our templates on how we generate URLs. We previously hardcoded the
URLs, such as:

<a href="/howdy/jane/doe">Howdy</a>

In home.pt we switched to:

0.2. Tutorials 129


The Pyramid Web Framework, Version 2.0.2

<a href="${request.route_url('hello', first='jane',


last='doe')}">form</a>

Pyramid has rich facilities to help generate URLs in a flexible, non-error prone fashion.

Extra credit

1. Why could our template do ${view.full_name} and not have to do ${view.


full_name()}?

2. The edit and delete views are both receive POST requests. Why does the edit view configu-
ration not catch the POST used by delete?

3. We used Python @property on full_name. If we reference this many times in a template or


view code, it would re-compute this every time. Does Pyramid provide something that will cache
the initial computation on a property?

4. Can you associate more than one route with the same view?

5. There is also a request.route_path API. How does this differ from request.
route_url?

See also:

Defining a View Callable as a Class, Weird Stuff You Can Do With URL Dispatch

16: Collecting Application Info With Logging

Capture debugging and error output from your web applications using standard Python logging.

Background

It’s important to know what is going on inside our web application. In development we might need to
collect some output. In production, we might need to detect problems when other people use the site. We
need logging.

Fortunately Pyramid uses the normal Python approach to logging. The project generated in your
development.ini has a number of lines that configure the logging for you to some reasonable de-
faults. You then see messages sent by Pyramid, for example, when a new request comes in.

130 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Objectives

• Inspect the configuration setup used for logging.

• Add logging statements to your view code.

Steps

1. First we copy the results of the view_classes step:

cd ..; cp -r view_classes logging; cd logging


$VENV/bin/pip install -e .

2. Extend logging/tutorial/views.py to log a message:

1 import logging
2 log = logging.getLogger(__name__)
3

4 from pyramid.view import (


5 view_config,
6 view_defaults
7 )
8

10 @view_defaults(renderer='home.pt')
11 class TutorialViews:
12 def __init__(self, request):
13 self.request = request
14

15 @view_config(route_name='home')
16 def home(self):
17 log.debug('In home view')
18 return {'name': 'Home View'}
19

20 @view_config(route_name='hello')
21 def hello(self):
22 log.debug('In hello view')
23 return {'name': 'Hello View'}

3. Finally let’s edit development.ini configuration file to enable logging for our Pyramid appli-
cation:

0.2. Tutorials 131


The Pyramid Web Framework, Version 2.0.2

[app:main]
use = egg:tutorial
pyramid.reload_templates = true
pyramid.includes =
pyramid_debugtoolbar

[server:main]
use = egg:waitress#main
listen = localhost:6543

# Begin logging configuration

[loggers]
keys = root, tutorial

[logger_tutorial]
level = DEBUG
handlers =
qualname = tutorial

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s]
,→%(message)s

# End logging configuration

4. Make sure the tests still pass:

132 CONTENTS
The Pyramid Web Framework, Version 2.0.2

$VENV/bin/pytest tutorial/tests.py -q
....
4 passed in 0.41 seconds

5. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

6. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser. Note, both in the


console and in the debug toolbar, the message that you logged.

Analysis

In our configuration file development.ini, our tutorial Python package is set up as a logger and
configured to log messages at a DEBUG or higher level. When you visit http://localhost:6543, your console
will now show:

2013-08-09 10:42:42,968 DEBUG [tutorial.views][MainThread] In home view

Also, if you have configured your Pyramid application to use the pyramid_debugtoolbar, logging
statements appear in one of its menus.

See also:

See also Logging.

17: Transient Data Using Sessions

Store and retrieve non-permanent data in Pyramid sessions.

Background

When people use your web application, they frequently perform a task that requires semi-permanent data
to be saved. For example, a shopping cart. This is called a session.

Pyramid has basic built-in support for sessions. Third party packages such as pyramid_redis_sessions
provide richer session support. Or you can create your own custom sessioning engine. Let’s take a look at
the built-in sessioning support.

0.2. Tutorials 133


The Pyramid Web Framework, Version 2.0.2

Objectives

• Make a session factory using a built-in, simple Pyramid sessioning system.

• Change our code to use a session.

Steps

1. First we copy the results of the view_classes step:

cd ..; cp -r view_classes sessions; cd sessions


$VENV/bin/pip install -e .

2. Our sessions/tutorial/__init__.py needs a choice of session factory to get registered


with the configurator:

1 from pyramid.config import Configurator


2 from pyramid.session import SignedCookieSessionFactory
3

5 def main(global_config, **settings):


6 my_session_factory = SignedCookieSessionFactory(
7 'itsaseekreet')
8 config = Configurator(settings=settings,
9 session_factory=my_session_factory)
10 config.include('pyramid_chameleon')
11 config.add_route('home', '/')
12 config.add_route('hello', '/howdy')
13 config.scan('.views')
14 return config.make_wsgi_app()

3. Our views in sessions/tutorial/views.py can now use request.session:

1 from pyramid.view import (


2 view_config,
3 view_defaults
4 )
5

7 @view_defaults(renderer='home.pt')
(continues on next page)

134 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


8 class TutorialViews:
9 def __init__(self, request):
10 self.request = request
11

12 @property
13 def counter(self):
14 session = self.request.session
15 if 'counter' in session:
16 session['counter'] += 1
17 else:
18 session['counter'] = 1
19

20 return session['counter']
21

22

23 @view_config(route_name='home')
24 def home(self):
25 return {'name': 'Home View'}
26

27 @view_config(route_name='hello')
28 def hello(self):
29 return {'name': 'Hello View'}

4. The template at sessions/tutorial/home.pt can display the value:

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <title>Quick Tutorial: ${name}</title>
5 </head>
6 <body>
7 <h1>Hi ${name}</h1>
8 <p>Count: ${view.counter}</p>
9 </body>
10 </html>

5. Make sure the tests still pass:

$VENV/bin/pytest tutorial/tests.py -q
....
4 passed in 0.42 seconds

6. Run your Pyramid application with:

0.2. Tutorials 135


The Pyramid Web Framework, Version 2.0.2

$VENV/bin/pserve development.ini --reload

7. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser. As you reload and


switch between those URLs, note that the counter increases and is not specific to the URL.

8. Restart the application and revisit the page. Note that counter still increases from where it left off.

Analysis

Pyramid’s request object now has a session attribute that we can use in our view code. It acts like a
dictionary.

Since all the views are using the same counter, we made the counter a Python property at the view class
level. With this, each reload will increase the counter displayed in our template.

In web development, ”flash messages” are notes for the user that need to appear on a screen after a future
web request. For example, when you add an item using a form POST, the site usually issues a second
HTTP Redirect web request to view the new item. You might want a message to appear after that second
web request saying ”Your item was added.” You can’t just return it in the web response for the POST, as it
will be tossed out during the second web request.

Flash messages are a technique where messages can be stored between requests, using sessions, then re-
moved when they finally get displayed.

See also:

Sessions, Flash Messages, and pyramid.session.

18: Forms and Validation with Deform

Schema-driven, autogenerated forms with validation.

Background

Modern web applications deal extensively with forms. Developers, though, have a wide range of philoso-
phies about how frameworks should help them with their forms. As such, Pyramid doesn’t directly bundle
one particular form library. Instead there are a variety of form libraries that are easy to use in Pyramid.

Deform is one such library. In this step, we introduce Deform for our forms. This also gives us Colander
for schemas and validation.

136 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Objectives

• Make a schema using Colander, the companion to Deform.

• Create a form with Deform and change our views to handle validation.

Steps

1. First we copy the results of the view_classes step:

cd ..; cp -r view_classes forms; cd forms

2. Let’s edit forms/setup.py to declare a dependency on Deform, which in turn pulls in Colander
as a dependency:

1 from setuptools import setup


2

3 # List of dependencies installed via `pip install -e .`


4 # by virtue of the Setuptools `install_requires` value below.
5 requires = [
6 'deform',
7 'pyramid',
8 'pyramid_chameleon',
9 'waitress',
10 ]
11

12 # List of dependencies installed via `pip install -e ".[dev]"`


13 # by virtue of the Setuptools `extras_require` value in the Python
14 # dictionary below.
15 dev_requires = [
16 'pyramid_debugtoolbar',
17 'pytest',
18 'webtest',
19 ]
20

21 setup(
22 name='tutorial',
23 install_requires=requires,
24 extras_require={
25 'dev': dev_requires,
26 },
(continues on next page)

0.2. Tutorials 137


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


27 entry_points={
28 'paste.app_factory': [
29 'main = tutorial:main'
30 ],
31 },
32 )

3. We can now install our project in development mode:

$VENV/bin/pip install -e .

4. Register a static view in forms/tutorial/__init__.py for Deform’s CSS, JavaScript, etc.,


as well as our demo wiki page’s views:

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 config = Configurator(settings=settings)
6 config.include('pyramid_chameleon')
7 config.add_route('wiki_view', '/')
8 config.add_route('wikipage_add', '/add')
9 config.add_route('wikipage_view', '/{uid}')
10 config.add_route('wikipage_edit', '/{uid}/edit')
11 config.add_static_view('deform_static', 'deform:static/')
12 config.scan('.views')
13 return config.make_wsgi_app()

5. Implement the new views, as well as the form schemas and some dummy data, in forms/
tutorial/views.py:

1 import colander
2 import deform.widget
3

4 from pyramid.httpexceptions import HTTPFound


5 from pyramid.view import view_config
6

7 pages = {
8 '100': dict(uid='100', title='Page 100', body='<em>100</em>'),
9 '101': dict(uid='101', title='Page 101', body='<em>101</em>'),
10 '102': dict(uid='102', title='Page 102', body='<em>102</em>')
(continues on next page)

138 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


11 }
12

13 class WikiPage(colander.MappingSchema):
14 title = colander.SchemaNode(colander.String())
15 body = colander.SchemaNode(
16 colander.String(),
17 widget=deform.widget.RichTextWidget()
18 )
19

20

21 class WikiViews:
22 def __init__(self, request):
23 self.request = request
24

25 @property
26 def wiki_form(self):
27 schema = WikiPage()
28 return deform.Form(schema, buttons=('submit',))
29

30 @property
31 def reqts(self):
32 return self.wiki_form.get_widget_resources()
33

34 @view_config(route_name='wiki_view', renderer='wiki_view.pt')
35 def wiki_view(self):
36 return dict(pages=pages.values())
37

38 @view_config(route_name='wikipage_add',
39 renderer='wikipage_addedit.pt')
40 def wikipage_add(self):
41 form = self.wiki_form.render()
42

43 if 'submit' in self.request.params:
44 controls = self.request.POST.items()
45 try:
46 appstruct = self.wiki_form.validate(controls)
47 except deform.ValidationFailure as e:
48 # Form is NOT valid
49 return dict(form=e.render())
50

51 # Form is valid, make a new identifier and add to list


52 last_uid = int(sorted(pages.keys())[-1])
53 new_uid = str(last_uid + 1)
54 pages[new_uid] = dict(
55 uid=new_uid, title=appstruct['title'],
(continues on next page)

0.2. Tutorials 139


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


56 body=appstruct['body']
57 )
58

59 # Now visit new page


60 url = self.request.route_url('wikipage_view', uid=new_uid)
61 return HTTPFound(url)
62

63 return dict(form=form)
64

65 @view_config(route_name='wikipage_view', renderer='wikipage_view.pt
,→ ')
66 def wikipage_view(self):
67 uid = self.request.matchdict['uid']
68 page = pages[uid]
69 return dict(page=page)
70

71 @view_config(route_name='wikipage_edit',
72 renderer='wikipage_addedit.pt')
73 def wikipage_edit(self):
74 uid = self.request.matchdict['uid']
75 page = pages[uid]
76

77 wiki_form = self.wiki_form
78

79 if 'submit' in self.request.params:
80 controls = self.request.POST.items()
81 try:
82 appstruct = wiki_form.validate(controls)
83 except deform.ValidationFailure as e:
84 return dict(page=page, form=e.render())
85

86 # Change the content and redirect to the view


87 page['title'] = appstruct['title']
88 page['body'] = appstruct['body']
89

90 url = self.request.route_url('wikipage_view',
91 uid=page['uid'])
92 return HTTPFound(url)
93

94 form = wiki_form.render(page)
95

96 return dict(page=page, form=form)

6. A template for the top of the ”wiki” in forms/tutorial/wiki_view.pt:

140 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <title>Wiki: View</title>
5 </head>
6 <body>
7 <h1>Wiki</h1>
8

9 <a href="${request.route_url('wikipage_add')}">Add
10 WikiPage</a>
11 <ul>
12 <li tal:repeat="page pages">
13 <a href="${request.route_url('wikipage_view', uid=page.uid)}">
14 ${page.title}
15 </a>
16 </li>
17 </ul>
18 </body>
19 </html>

7. Another template for adding/editing in forms/tutorial/wikipage_addedit.pt:

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <title>WikiPage: Add/Edit</title>
5 <link rel="stylesheet"
6 href="${request.static_url('deform:static/css/bootstrap.min.
,→css')}"

7 type="text/css" media="screen" charset="utf-8"/>


8 <link rel="stylesheet"
9 href="${request.static_url('deform:static/css/form.css')}"
10 type="text/css"/>
11 <tal:block tal:repeat="reqt view.reqts['css']">
12 <link rel="stylesheet" type="text/css"
13 href="${request.static_url(reqt)}"/>
14 </tal:block>
15 <script src="${request.static_url('deform:static/scripts/jquery-2.
,→0.3.min.js')}"

16 type="text/javascript"></script>
17 <script src="${request.static_url('deform:static/scripts/bootstrap.
,→min.js')}"

18 type="text/javascript"></script>
19

20 <tal:block tal:repeat="reqt view.reqts['js']">


(continues on next page)

0.2. Tutorials 141


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


21 <script src="${request.static_url(reqt)}"
22 type="text/javascript"></script>
23 </tal:block>
24 </head>
25 <body>
26 <h1>Wiki</h1>
27

28 <p>${structure: form}</p>
29 <script type="text/javascript">
30 deform.load()
31 </script>
32 </body>
33 </html>

8. Add a template at forms/tutorial/wikipage_view.pt for viewing a wiki page:

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <title>WikiPage: View</title>
5 </head>
6 <body>
7 <a href="${request.route_url('wiki_view')}">
8 Up
9 </a> |
10 <a href="${request.route_url('wikipage_edit', uid=page.uid)}">
11 Edit
12 </a>
13

14 <h1>${page.title}</h1>
15 <p>${structure: page.body}</p>
16 </body>
17 </html>

9. Our tests in forms/tutorial/tests.py don’t run, so let’s modify them:

1 import unittest
2

3 from pyramid import testing


4

6 class TutorialViewTests(unittest.TestCase):
7 def setUp(self):
(continues on next page)

142 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


8 self.config = testing.setUp()
9

10 def tearDown(self):
11 testing.tearDown()
12

13 def test_home(self):
14 from .views import WikiViews
15

16 request = testing.DummyRequest()
17 inst = WikiViews(request)
18 response = inst.wiki_view()
19 self.assertEqual(len(response['pages']), 3)
20

21

22 class TutorialFunctionalTests(unittest.TestCase):
23 def setUp(self):
24 from tutorial import main
25

26 app = main({})
27 from webtest import TestApp
28

29 self.testapp = TestApp(app)
30

31 def tearDown(self):
32 testing.tearDown()
33

34 def test_home(self):
35 res = self.testapp.get('/', status=200)
36 self.assertIn(b'<title>Wiki: View</title>', res.body)
37

38 def test_add_page(self):
39 res = self.testapp.get('/add', status=200)
40 self.assertIn(b'<h1>Wiki</h1>', res.body)
41

42 def test_edit_page(self):
43 res = self.testapp.get('/101/edit', status=200)
44 self.assertIn(b'<h1>Wiki</h1>', res.body)
45

46 def test_post_wiki(self):
47 self.testapp.post('/add', {
48 "title": "New Title",
49 "body": "<p>New Body</p>",
50 "submit": "submit"
51 }, status=302)
52

(continues on next page)

0.2. Tutorials 143


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


53 res = self.testapp.get('/103', status=200)
54 self.assertIn(b'<h1>New Title</h1>', res.body)
55 self.assertIn(b'<p>New Body</p>', res.body)
56

57 def test_edit_wiki(self):
58 self.testapp.post('/102/edit', {
59 "title": "New Title",
60 "body": "<p>New Body</p>",
61 "submit": "submit"
62 }, status=302)
63

64 res = self.testapp.get('/102', status=200)


65 self.assertIn(b'<h1>New Title</h1>', res.body)
66 self.assertIn(b'<p>New Body</p>', res.body)

10. Run the tests:

$VENV/bin/pytest tutorial/tests.py -q
..
6 passed in 0.81 seconds

11. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

12. Open http://localhost:6543/ in a browser.

Analysis

This step helps illustrate the utility of asset specifications for static assets. We have an outside package
called Deform with static assets which need to be published. We don’t have to know where on disk it is
located. We point at the package, then the path inside the package.

We just need to include a call to add_static_view to make that directory available at a URL. For
Pyramid-specific packages, Pyramid provides a facility (config.include()) which even makes that
unnecessary for consumers of a package. (Deform is not specific to Pyramid.)

Our forms have rich widgets which need the static CSS and JavaScript just mentioned. Deform
has a resource registry which allows widgets to specify which JavaScript and CSS are needed. Our

144 CONTENTS
The Pyramid Web Framework, Version 2.0.2

wikipage_addedit.pt template shows how we iterated over that data to generate markup that in-
cludes the needed resources.
Our add and edit views use a pattern called self-posting forms. Meaning, the same URL is used to GET
the form as is used to POST the form. The route, the view, and the template are the same URL whether
you are walking up to it for the first time or you clicked a button.
Inside the view we do if 'submit' in self.request.params: to see if this form was a POST
where the user clicked on a particular button <input name="submit">.
The form controller then follows a typical pattern:
• If you are doing a GET, skip over and just return the form.
• If you are doing a POST, validate the form contents.
• If the form is invalid, bail out by re-rendering the form with the supplied POST data.
• If the validation succeeded, perform some action and issue a redirect via HTTPFound.
We are, in essence, writing our own form controller. Other Pyramid-based systems, including pyra-
mid_deform, provide a form-centric view class which automates much of this branching and routing.

Extra credit

1. Give a try at a button that goes to a delete view for a particular wiki page.

19: Databases Using SQLAlchemy

Store and retrieve data using the SQLAlchemy ORM atop the SQLite database.

Background

Our Pyramid-based wiki application now needs database-backed storage of pages. This frequently means
an SQL database. The Pyramid community strongly supports the SQLAlchemy project and its object-
relational mapper (ORM) as a convenient, Pythonic way to interface to databases.
In this step we hook up SQLAlchemy to a SQLite database table, providing storage and retrieval for the
wiki pages in the previous step.

The Pyramid cookiecutter pyramid-cookiecutter-starter is really helpful for getting


a SQLAlchemy project going, including generation of the console script. Since we want to see all the
decisions, we will forgo convenience in this tutorial, and wire it up ourselves.

0.2. Tutorials 145


The Pyramid Web Framework, Version 2.0.2

Objectives

• Store pages in SQLite by using SQLAlchemy models.

• Use SQLAlchemy queries to list/add/view/edit pages.

• Provide a database-initialize command by writing a Pyramid console script which can be run from
the command line.

Steps

1. We are going to use the forms step as our starting point:

cd ..; cp -r forms databases; cd databases

2. We need to add some dependencies in databases/setup.py as well as an entry point for the
command-line script:

1 from setuptools import setup


2

3 # List of dependencies installed via `pip install -e .`


4 # by virtue of the Setuptools `install_requires` value below.
5 requires = [
6 'deform',
7 'pyramid',
8 'pyramid_chameleon',
9 'pyramid_tm',
10 'sqlalchemy',
11 'waitress',
12 'zope.sqlalchemy',
13 ]
14

15 # List of dependencies installed via `pip install -e ".[dev]"`


16 # by virtue of the Setuptools `extras_require` value in the Python
17 # dictionary below.
18 dev_requires = [
19 'pyramid_debugtoolbar',
20 'pytest',
21 'webtest',
22 ]
23

(continues on next page)

146 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


24 setup(
25 name='tutorial',
26 install_requires=requires,
27 extras_require={
28 'dev': dev_requires,
29 },
30 entry_points={
31 'paste.app_factory': [
32 'main = tutorial:main'
33 ],
34 'console_scripts': [
35 'initialize_tutorial_db = tutorial.initialize_db:main'
36 ],
37 },
38 )

We aren’t yet doing $VENV/bin/pip install -e . because we need to write a script


and update configuration first.

3. Our configuration file at databases/development.ini wires together some new pieces:

[app:main]
use = egg:tutorial
pyramid.reload_templates = true
pyramid.includes =
pyramid_debugtoolbar
pyramid_tm

sqlalchemy.url = sqlite:///%(here)s/sqltutorial.sqlite

[server:main]
use = egg:waitress#main
listen = localhost:6543

# Begin logging configuration

[loggers]
keys = root, tutorial, sqlalchemy.engine.Engine

[logger_tutorial]
level = DEBUG
(continues on next page)

0.2. Tutorials 147


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


handlers =
qualname = tutorial

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console

[logger_sqlalchemy.engine.Engine]
level = INFO
handlers =
qualname = sqlalchemy.engine.Engine

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s]
,→%(message)s

# End logging configuration

4. This engine configuration now needs to be read into the application through changes in
databases/tutorial/__init__.py:

1 from pyramid.config import Configurator


2

3 from sqlalchemy import engine_from_config


4

5 from .models import DBSession, Base


6

7 def main(global_config, **settings):


8 engine = engine_from_config(settings, 'sqlalchemy.')
9 DBSession.configure(bind=engine)
10 Base.metadata.bind = engine
11

(continues on next page)

148 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


12 config = Configurator(settings=settings,
13 root_factory='tutorial.models.Root')
14 config.include('pyramid_chameleon')
15 config.add_route('wiki_view', '/')
16 config.add_route('wikipage_add', '/add')
17 config.add_route('wikipage_view', '/{uid}')
18 config.add_route('wikipage_edit', '/{uid}/edit')
19 config.add_static_view('deform_static', 'deform:static/')
20 config.scan('.views')
21 return config.make_wsgi_app()

5. Make a command-line script at databases/tutorial/initialize_db.py to initialize the


database:

1 import os
2 import sys
3 import transaction
4

5 from sqlalchemy import engine_from_config


6

7 from pyramid.paster import (


8 get_appsettings,
9 setup_logging,
10 )
11

12 from .models import (


13 DBSession,
14 Page,
15 Base,
16 )
17

18

19 def usage(argv):
20 cmd = os.path.basename(argv[0])
21 print('usage: %s <config_uri>\n'
22 '(example: "%s development.ini")' % (cmd, cmd))
23 sys.exit(1)
24

25

26 def main(argv=sys.argv):
27 if len(argv) != 2:
28 usage(argv)
29 config_uri = argv[1]
30 setup_logging(config_uri)
(continues on next page)

0.2. Tutorials 149


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


31 settings = get_appsettings(config_uri)
32 engine = engine_from_config(settings, 'sqlalchemy.')
33 DBSession.configure(bind=engine)
34 Base.metadata.create_all(engine)
35 with transaction.manager:
36 model = Page(title='Root', body='<p>Root</p>')
37 DBSession.add(model)

6. Now that we’ve got all the pieces ready, and because we changed setup.py, we now install all the
goodies:

$VENV/bin/pip install -e .

7. The script references some models in databases/tutorial/models.py:

1 from pyramid.authorization import Allow, Everyone


2

3 from sqlalchemy import (


4 Column,
5 Integer,
6 Text,
7 )
8

9 from sqlalchemy.ext.declarative import declarative_base


10

11 from sqlalchemy.orm import (


12 scoped_session,
13 sessionmaker,
14 )
15

16 from zope.sqlalchemy import register


17

18 DBSession = scoped_session(sessionmaker())
19 register(DBSession)
20 Base = declarative_base()
21

22

23 class Page(Base):
24 __tablename__ = 'wikipages'
25 uid = Column(Integer, primary_key=True)
26 title = Column(Text, unique=True)
27 body = Column(Text)
28

(continues on next page)

150 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


29

30 class Root:
31 __acl__ = [(Allow, Everyone, 'view'),
32 (Allow, 'group:editors', 'edit')]
33

34 def __init__(self, request):


35 pass

8. Let’s run this console script, thus producing our database and table:

$VENV/bin/initialize_tutorial_db development.ini

2016-04-16 13:01:33,055 INFO [sqlalchemy.engine.Engine][MainThread]␣


,→SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1

2016-04-16 13:01:33,055 INFO [sqlalchemy.engine.Engine][MainThread] ()


2016-04-16 13:01:33,056 INFO [sqlalchemy.engine.Engine][MainThread]␣
,→SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1

2016-04-16 13:01:33,056 INFO [sqlalchemy.engine.Engine][MainThread] ()


2016-04-16 13:01:33,057 INFO [sqlalchemy.engine.Engine][MainThread]␣
,→PRAGMA table_info("wikipages")

2016-04-16 13:01:33,057 INFO [sqlalchemy.engine.Engine][MainThread] ()


2016-04-16 13:01:33,058 INFO [sqlalchemy.engine.Engine][MainThread]
CREATE TABLE wikipages (
uid INTEGER NOT NULL,
title TEXT,
body TEXT,
PRIMARY KEY (uid),
UNIQUE (title)
)

2016-04-16 13:01:33,058 INFO [sqlalchemy.engine.Engine][MainThread] ()


2016-04-16 13:01:33,059 INFO [sqlalchemy.engine.Engine][MainThread]␣
,→COMMIT

2016-04-16 13:01:33,062 INFO [sqlalchemy.engine.Engine][MainThread]␣


,→BEGIN (implicit)

2016-04-16 13:01:33,062 INFO [sqlalchemy.engine.Engine][MainThread]␣


,→INSERT INTO wikipages (title, body) VALUES (?, ?)

2016-04-16 13:01:33,063 INFO [sqlalchemy.engine.Engine][MainThread] (


,→'Root', '<p>Root</p>')

2016-04-16 13:01:33,063 INFO [sqlalchemy.engine.Engine][MainThread]␣


,→COMMIT

9. With our data now driven by SQLAlchemy queries, we need to update our databases/
tutorial/views.py:

0.2. Tutorials 151


The Pyramid Web Framework, Version 2.0.2

1 import colander
2 import deform.widget
3

4 from pyramid.httpexceptions import HTTPFound


5 from pyramid.view import view_config
6

7 from .models import DBSession, Page


8

10 class WikiPage(colander.MappingSchema):
11 title = colander.SchemaNode(colander.String())
12 body = colander.SchemaNode(
13 colander.String(),
14 widget=deform.widget.RichTextWidget()
15 )
16

17

18 class WikiViews:
19 def __init__(self, request):
20 self.request = request
21

22 @property
23 def wiki_form(self):
24 schema = WikiPage()
25 return deform.Form(schema, buttons=('submit',))
26

27 @property
28 def reqts(self):
29 return self.wiki_form.get_widget_resources()
30

31 @view_config(route_name='wiki_view', renderer='wiki_view.pt')
32 def wiki_view(self):
33 pages = DBSession.query(Page).order_by(Page.title)
34 return dict(title='Wiki View', pages=pages)
35

36 @view_config(route_name='wikipage_add',
37 renderer='wikipage_addedit.pt')
38 def wikipage_add(self):
39 form = self.wiki_form.render()
40

41 if 'submit' in self.request.params:
42 controls = self.request.POST.items()
43 try:
44 appstruct = self.wiki_form.validate(controls)
45 except deform.ValidationFailure as e:
46 # Form is NOT valid
(continues on next page)

152 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


47 return dict(form=e.render())
48

49 # Add a new page to the database


50 new_title = appstruct['title']
51 new_body = appstruct['body']
52 DBSession.add(Page(title=new_title, body=new_body))
53

54 # Get the new ID and redirect


55 page = DBSession.query(Page).filter_by(title=new_title).
,→ one()
56 new_uid = page.uid
57

58 url = self.request.route_url('wikipage_view', uid=new_uid)


59 return HTTPFound(url)
60

61 return dict(form=form)
62

63

64 @view_config(route_name='wikipage_view', renderer='wikipage_view.pt
,→ ')
65 def wikipage_view(self):
66 uid = int(self.request.matchdict['uid'])
67 page = DBSession.query(Page).filter_by(uid=uid).one()
68 return dict(page=page)
69

70

71 @view_config(route_name='wikipage_edit',
72 renderer='wikipage_addedit.pt')
73 def wikipage_edit(self):
74 uid = int(self.request.matchdict['uid'])
75 page = DBSession.query(Page).filter_by(uid=uid).one()
76

77 wiki_form = self.wiki_form
78

79 if 'submit' in self.request.params:
80 controls = self.request.POST.items()
81 try:
82 appstruct = wiki_form.validate(controls)
83 except deform.ValidationFailure as e:
84 return dict(page=page, form=e.render())
85

86 # Change the content and redirect to the view


87 page.title = appstruct['title']
88 page.body = appstruct['body']
89 url = self.request.route_url('wikipage_view', uid=uid)
(continues on next page)

0.2. Tutorials 153


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


90 return HTTPFound(url)
91

92 form = self.wiki_form.render(dict(
93 uid=page.uid, title=page.title, body=page.body)
94 )
95

96 return dict(page=page, form=form)

10. Our tests in databases/tutorial/tests.py changed to include SQLAlchemy bootstrap-


ping:

1 import unittest
2 import transaction
3

4 from pyramid import testing


5

7 def _initTestingDB():
8 from sqlalchemy import create_engine
9 from .models import (
10 DBSession,
11 Page,
12 Base
13 )
14 engine = create_engine('sqlite://')
15 Base.metadata.create_all(engine)
16 DBSession.configure(bind=engine)
17 with transaction.manager:
18 model = Page(title='FrontPage', body='This is the front page')
19 DBSession.add(model)
20 return DBSession
21

22

23 class WikiViewTests(unittest.TestCase):
24 def setUp(self):
25 self.session = _initTestingDB()
26 self.config = testing.setUp()
27

28 def tearDown(self):
29 self.session.remove()
30 testing.tearDown()
31

32 def test_wiki_view(self):
33 from tutorial.views import WikiViews
(continues on next page)

154 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


34

35 request = testing.DummyRequest()
36 inst = WikiViews(request)
37 response = inst.wiki_view()
38 self.assertEqual(response['title'], 'Wiki View')
39

40

41 class WikiFunctionalTests(unittest.TestCase):
42 def setUp(self):
43 from pyramid.paster import get_app
44 app = get_app('development.ini')
45 from webtest import TestApp
46 self.testapp = TestApp(app)
47

48 def tearDown(self):
49 from .models import DBSession
50 DBSession.remove()
51

52 def test_it(self):
53 res = self.testapp.get('/', status=200)
54 self.assertIn(b'Wiki: View', res.body)
55 res = self.testapp.get('/add', status=200)
56 self.assertIn(b'Add/Edit', res.body)

11. Run the tests in your package using pytest:

$VENV/bin/pytest tutorial/tests.py -q
..
2 passed in 1.41 seconds

12. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

13. Open http://localhost:6543/ in a browser.

0.2. Tutorials 155


The Pyramid Web Framework, Version 2.0.2

Analysis

Let’s start with the dependencies. We made the decision to use SQLAlchemy to talk to our database. We
also, though, installed pyramid_tm and zope.sqlalchemy. Why?

Pyramid has a strong orientation towards support for transactions. Specifically, you can install a
transaction manager into your application either as middleware or a Pyramid ”tween”. Then, just before
you return the response, all transaction-aware parts of your application are executed.

This means Pyramid view code usually doesn’t manage transactions. If your view code or a template
generates an error, the transaction manager aborts the transaction. This is a very liberating way to write
code.

The pyramid_tm package provides a ”tween” that is configured in the development.ini config-
uration file. That installs it. We then need a package that makes SQLAlchemy, and thus the RDBMS
transaction manager, integrate with the Pyramid transaction manager. That’s what zope.sqlalchemy
does.

Where do we point at the location on disk for the SQLite file? In the configuration file. This lets consumers
of our package change the location in a safe (non-code) way. That is, in configuration. This configuration-
oriented approach isn’t required in Pyramid; you can still make such statements in your __init__.py
or some companion module.

The initialize_tutorial_db is a nice example of framework support. You point your setup at the
location of some [console_scripts], and these get generated into your virtual environment’s bin
directory. Our console script follows the pattern of being fed a configuration file with all the bootstrapping.
It then opens SQLAlchemy and creates the root of the wiki, which also makes the SQLite file. Note the
with transaction.manager part that puts the work in the scope of a transaction, as we aren’t inside
a web request where this is done automatically.

The models.py does a little bit of extra work to hook up SQLAlchemy into the Pyramid transaction
manager. It then declares the model for a Page.

Our views have changes primarily around replacing our dummy dictionary-of-dictionaries data with proper
database support: list the rows, add a row, edit a row, and delete a row.

Extra credit

1. Why all this code? Why can’t I just type two lines and have magic ensue?

2. Give a try at a button that deletes a wiki page.

156 CONTENTS
The Pyramid Web Framework, Version 2.0.2

20: Logins with authentication

Login views that authenticate a username and password against a list of users.

Background

Most web applications have URLs that allow people to add/edit/delete content via a web browser. Time
to add security to the application. In this first step we introduce authentication. That is, logging in and
logging out, using Pyramid’s rich facilities for pluggable user storage.

In the next step we will introduce protection of resources with authorization security statements.

Objectives

• Introduce the Pyramid concepts of authentication.

• Create login and logout views.

Steps

1. We are going to use the view classes step as our starting point:

cd ..; cp -r view_classes authentication; cd authentication

2. Add bcrypt as a dependency in authentication/setup.py:

1 from setuptools import setup


2

3 # List of dependencies installed via `pip install -e .`


4 # by virtue of the Setuptools `install_requires` value below.
5 requires = [
6 'bcrypt',
7 'pyramid',
8 'pyramid_chameleon',
9 'waitress',
(continues on next page)

0.2. Tutorials 157


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


10 ]
11

12 # List of dependencies installed via `pip install -e ".[dev]"`


13 # by virtue of the Setuptools `extras_require` value in the Python
14 # dictionary below.
15 dev_requires = [
16 'pyramid_debugtoolbar',
17 'pytest',
18 'webtest',
19 ]
20

21 setup(
22 name='tutorial',
23 install_requires=requires,
24 extras_require={
25 'dev': dev_requires,
26 },
27 entry_points={
28 'paste.app_factory': [
29 'main = tutorial:main'
30 ],
31 },
32 )

3. We can now install our project in development mode:

$VENV/bin/pip install -e .

4. Put the security hash in the authentication/development.ini configuration file as


tutorial.secret instead of putting it in the code:

1 [app:main]
2 use = egg:tutorial
3 pyramid.reload_templates = true
4 pyramid.includes =
5 pyramid_debugtoolbar
6 tutorial.secret = 98zd
7

8 [server:main]
9 use = egg:waitress#main
10 listen = localhost:6543

5. Create an authentication/tutorial/security.py module that can find our user infor-


mation by providing a security policy:

158 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 import bcrypt
2 from pyramid.authentication import AuthTktCookieHelper
3

5 def hash_password(pw):
6 pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt())
7 return pwhash.decode('utf8')
8

9 def check_password(pw, hashed_pw):


10 expected_hash = hashed_pw.encode('utf8')
11 return bcrypt.checkpw(pw.encode('utf8'), expected_hash)
12

13

14 USERS = {'editor': hash_password('editor'),


15 'viewer': hash_password('viewer')}
16

17

18 class SecurityPolicy:
19 def __init__(self, secret):
20 self.authtkt = AuthTktCookieHelper(secret=secret)
21

22 def identity(self, request):


23 identity = self.authtkt.identify(request)
24 if identity is not None and identity['userid'] in USERS:
25 return identity
26

27 def authenticated_userid(self, request):


28 identity = self.identity(request)
29 if identity is not None:
30 return identity['userid']
31

32 def remember(self, request, userid, **kw):


33 return self.authtkt.remember(request, userid, **kw)
34

35 def forget(self, request, **kw):


36 return self.authtkt.forget(request, **kw)

6. Register the SecurityPolicy with the configurator in authentication/tutorial/


__init__.py:

1 from pyramid.config import Configurator


2

3 from .security import SecurityPolicy


4

(continues on next page)

0.2. Tutorials 159


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


6 def main(global_config, **settings):
7 config = Configurator(settings=settings)
8 config.include('pyramid_chameleon')
9

10 config.set_security_policy(
11 SecurityPolicy(
12 secret=settings['tutorial.secret'],
13 ),
14 )
15

16 config.add_route('home', '/')
17 config.add_route('hello', '/howdy')
18 config.add_route('login', '/login')
19 config.add_route('logout', '/logout')
20 config.scan('.views')
21 return config.make_wsgi_app()

7. Update the views in authentication/tutorial/views.py:

1 from pyramid.httpexceptions import HTTPFound


2 from pyramid.security import (
3 remember,
4 forget,
5 )
6

7 from pyramid.view import (


8 view_config,
9 view_defaults
10 )
11

12 from .security import (


13 USERS,
14 check_password
15 )
16

17

18 @view_defaults(renderer='home.pt')
19 class TutorialViews:
20 def __init__(self, request):
21 self.request = request
22 self.logged_in = request.authenticated_userid
23

24 @view_config(route_name='home')
25 def home(self):
(continues on next page)

160 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


26 return {'name': 'Home View'}
27

28 @view_config(route_name='hello')
29 def hello(self):
30 return {'name': 'Hello View'}
31

32 @view_config(route_name='login', renderer='login.pt')
33 def login(self):
34 request = self.request
35 login_url = request.route_url('login')
36 referrer = request.url
37 if referrer == login_url:
38 referrer = '/' # never use login form itself as came_from
39 came_from = request.params.get('came_from', referrer)
40 message = ''
41 login = ''
42 password = ''
43 if 'form.submitted' in request.params:
44 login = request.params['login']
45 password = request.params['password']
46 hashed_pw = USERS.get(login)
47 if hashed_pw and check_password(password, hashed_pw):
48 headers = remember(request, login)
49 return HTTPFound(location=came_from,
50 headers=headers)
51 message = 'Failed login'
52

53 return dict(
54 name='Login',
55 message=message,
56 url=request.application_url + '/login',
57 came_from=came_from,
58 login=login,
59 password=password,
60 )
61

62 @view_config(route_name='logout')
63 def logout(self):
64 request = self.request
65 headers = forget(request)
66 url = request.route_url('home')
67 return HTTPFound(location=url,
68 headers=headers)

8. Add a login template at authentication/tutorial/login.pt:

0.2. Tutorials 161


The Pyramid Web Framework, Version 2.0.2

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <title>Quick Tutorial: ${name}</title>
5 </head>
6 <body>
7 <h1>Login</h1>
8 <span tal:replace="message"/>
9

10 <form action="${url}" method="post">


11 <input type="hidden" name="came_from"
12 value="${came_from}"/>
13 <label for="login">Username</label>
14 <input type="text" id="login"
15 name="login"
16 value="${login}"/><br/>
17 <label for="password">Password</label>
18 <input type="password" id="password"
19 name="password"
20 value="${password}"/><br/>
21 <input type="submit" name="form.submitted"
22 value="Log In"/>
23 </form>
24 </body>
25 </html>

9. Provide a login/logout box in authentication/tutorial/home.pt:

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <title>Quick Tutorial: ${name}</title>
5 </head>
6 <body>
7

8 <div>
9 <a tal:condition="view.logged_in is None"
10 href="${request.application_url}/login">Log In</a>
11 <a tal:condition="view.logged_in is not None"
12 href="${request.application_url}/logout">Logout</a>
13 </div>
14

15 <h1>Hi ${name}</h1>
16 <p>Visit <a href="${request.route_url('hello')}">hello</a></p>
(continues on next page)

162 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


17 </body>
18 </html>

10. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

11. Open http://localhost:6543/ in a browser.

12. Click the ”Log In” link.

13. Submit the login form with the username editor and the password editor.

14. Note that the ”Log In” link has changed to ”Logout”.

15. Click the ”Logout” link.

Analysis

Unlike many web frameworks, Pyramid includes a built-in but optional security model for authentication
and authorization. This security system is intended to be flexible and support many needs. In this security
model, authentication (who are you) and authorization (what are you allowed to do) are pluggable. To
learn one step at a time, we provide a system that identifies users and lets them log out.

In this example we chose to use the bundled pyramid.authentication.


AuthTktCookieHelper helper to store the user’s logged-in state in a cookie. We enabled it in
our configuration and provided a ticket-signing secret in our INI file.

Our view class grew a login view. When you reached it via a GET request, it returned a login form. When
reached via POST, it processed the submitted username and password against the USERS data store.

The function hash_password uses a one-way hashing algorithm with a salt on the user’s password
via bcrypt, instead of storing the password in plain text. This is considered to be a ”best practice” for
security.

There are alternative libraries to bcrypt if it is an issue on your system. Just make sure that the
library uses an algorithm approved for storing passwords securely.

0.2. Tutorials 163


The Pyramid Web Framework, Version 2.0.2

The function check_password will compare the two hashed values of the submitted password and the
user’s password stored in the database. If the hashed values are equivalent, then the user is authenticated,
else authentication fails.

Assuming the password was validated, we invoke pyramid.security.remember() to generate a


cookie that is set in the response. Subsequent requests return that cookie and identify the user.

In our template, we fetched the logged_in value from the view class. We use this to calculate the
logged-in user, if any. In the template we can then choose to show a login link to anonymous visitors or a
logout link to logged-in users.

Extra credit

1. Can I use a database instead of USERS to authenticate users?

2. Once I am logged in, does any user-centric information get jammed onto each request? Use import
pdb; pdb.set_trace() to answer this.

See also:

See also Security, pyramid.authentication.AuthTktCookieHelper, bcrypt

21: Protecting Resources With Authorization

Assign security statements to resources describing the permissions required to perform an operation.

Background

Our application has URLs that allow people to add/edit/delete content via a web browser. Time to add
security to the application. Let’s protect our add/edit views to require a login (username of editor and
password of editor). We will allow the other views to continue working without a password.

164 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Objectives

• Introduce the Pyramid concepts of authentication, authorization, permissions, and access control
lists (ACLs).
• Make a root factory that returns an instance of our class for the top of the application.
• Assign security statements to our root resource.
• Add a permissions predicate on a view.
• Provide a Forbidden view to handle visiting a URL without adequate permissions.

Steps

1. We are going to use the authentication step as our starting point:

cd ..; cp -r authentication authorization; cd authorization


$VENV/bin/pip install -e .

2. Start by changing authorization/tutorial/__init__.py to specify a root factory to the


configurator:

1 from pyramid.config import Configurator


2

3 from .security import SecurityPolicy


4

6 def main(global_config, **settings):


7 config = Configurator(settings=settings,
8 root_factory='.resources.Root')
9 config.include('pyramid_chameleon')
10

11 config.set_security_policy(
12 SecurityPolicy(
13 secret=settings['tutorial.secret'],
14 ),
15 )
16

17 config.add_route('home', '/')
18 config.add_route('hello', '/howdy')
19 config.add_route('login', '/login')
20 config.add_route('logout', '/logout')
21 config.scan('.views')
22 return config.make_wsgi_app()

0.2. Tutorials 165


The Pyramid Web Framework, Version 2.0.2

3. That means we need to implement authorization/tutorial/resources.py:

1 from pyramid.authorization import Allow, Everyone


2

4 class Root:
5 __acl__ = [(Allow, Everyone, 'view'),
6 (Allow, 'group:editors', 'edit')]
7

8 def __init__(self, request):


9 pass

4. Define a GROUPS data store and the permits method of our SecurityPolicy:

1 import bcrypt
2 from pyramid.authentication import AuthTktCookieHelper
3 from pyramid.authorization import (
4 ACLHelper,
5 Authenticated,
6 Everyone,
7 )
8

10 def hash_password(pw):
11 pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt())
12 return pwhash.decode('utf8')
13

14 def check_password(pw, hashed_pw):


15 expected_hash = hashed_pw.encode('utf8')
16 return bcrypt.checkpw(pw.encode('utf8'), expected_hash)
17

18

19 USERS = {'editor': hash_password('editor'),


20 'viewer': hash_password('viewer')}
21 GROUPS = {'editor': ['group:editors']}
22

23

24 class SecurityPolicy:
25 def __init__(self, secret):
26 self.authtkt = AuthTktCookieHelper(secret=secret)
27 self.acl = ACLHelper()
28

29 def identity(self, request):


30 identity = self.authtkt.identify(request)
31 if identity is not None and identity['userid'] in USERS:
(continues on next page)

166 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


32 return identity
33

34 def authenticated_userid(self, request):


35 identity = self.identity(request)
36 if identity is not None:
37 return identity['userid']
38

39 def remember(self, request, userid, **kw):


40 return self.authtkt.remember(request, userid, **kw)
41

42 def forget(self, request, **kw):


43 return self.authtkt.forget(request, **kw)
44

45 def permits(self, request, context, permission):


46 principals = self.effective_principals(request)
47 return self.acl.permits(context, principals, permission)
48

49 def effective_principals(self, request):


50 principals = [Everyone]
51 userid = self.authenticated_userid(request)
52 if userid is not None:
53 principals += [Authenticated, 'u:' + userid]
54 principals += GROUPS.get(userid, [])
55 return principals

5. Change authorization/tutorial/views.py to require the edit permission on the


hello view and implement the forbidden view:

1 from pyramid.httpexceptions import HTTPFound


2 from pyramid.security import (
3 remember,
4 forget,
5 )
6

7 from pyramid.view import (


8 view_config,
9 view_defaults,
10 forbidden_view_config
11 )
12

13 from .security import (


14 USERS,
15 check_password
16 )
(continues on next page)

0.2. Tutorials 167


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


17

18

19 @view_defaults(renderer='home.pt')
20 class TutorialViews:
21 def __init__(self, request):
22 self.request = request
23 self.logged_in = request.authenticated_userid
24

25 @view_config(route_name='home')
26 def home(self):
27 return {'name': 'Home View'}
28

29 @view_config(route_name='hello', permission='edit')
30 def hello(self):
31 return {'name': 'Hello View'}
32

33 @view_config(route_name='login', renderer='login.pt')
34 @forbidden_view_config(renderer='login.pt')
35 def login(self):
36 request = self.request
37 login_url = request.route_url('login')
38 referrer = request.url
39 if referrer == login_url:
40 referrer = '/' # never use login form itself as came_from
41 came_from = request.params.get('came_from', referrer)
42 message = ''
43 login = ''
44 password = ''
45 if 'form.submitted' in request.params:
46 login = request.params['login']
47 password = request.params['password']
48 hashed_pw = USERS.get(login)
49 if hashed_pw and check_password(password, hashed_pw):
50 headers = remember(request, login)
51 return HTTPFound(location=came_from,
52 headers=headers)
53 message = 'Failed login'
54

55 return dict(
56 name='Login',
57 message=message,
58 url=request.application_url + '/login',
59 came_from=came_from,
60 login=login,
61 password=password,
(continues on next page)

168 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


62 )
63

64 @view_config(route_name='logout')
65 def logout(self):
66 request = self.request
67 headers = forget(request)
68 url = request.route_url('home')
69 return HTTPFound(location=url,
70 headers=headers)

6. Run your Pyramid application with:

$VENV/bin/pserve development.ini --reload

7. Open http://localhost:6543/ in a browser.


8. If you are still logged in, click the ”Log Out” link.
9. Visit http://localhost:6543/howdy in a browser. You should be asked to login.

Analysis

This simple tutorial step can be boiled down to the following:


• A view can require a permission (edit).
• The context for our view (the Root) has an access control list (ACL).
• This ACL says that the edit permission is available on Root to the group:editors principal.
• The SecurityPolicy.effective_principals method answers whether a particular user
(editor) is a member of a particular group (group:editors).
• The SecurityPolicy.permits method is invoked when Pyramid wants to know whether
the user is allowed to do something. To do this, it uses the pyramid.authorization.
ACLHelper to inspect the ACL on the context and determine if the request is allowed or denied
the specific permission.
In summary, hello wants edit permission, Root says group:editors has edit permission.
Of course, this only applies on Root. Some other part of the site (a.k.a. context) might have a different
ACL.
If you are not logged in and visit /howdy, you need to get shown the login screen. How does Pyramid
know what is the login page to use? We explicitly told Pyramid that the login view should be used by
decorating the view with @forbidden_view_config.

0.2. Tutorials 169


The Pyramid Web Framework, Version 2.0.2

Extra credit

1. What is the difference between a user and a principal?

2. Can I use a database instead of the GROUPS data store to look up principals?

3. Do I have to put a renderer in my @forbidden_view_config decorator?

4. Perhaps you would like the experience of not having enough permissions (forbidden) to be richer.
How could you change this?

5. Perhaps we want to store security statements in a database and allow editing via a browser. How
might this be done?

6. What if we want different security statements on different kinds of objects? Or on the same kinds
of objects, but in different parts of a URL hierarchy?

Indices and tables

• genindex

• modindex

• search

0.2.3 SQLAlchemy + URL dispatch wiki tutorial

This tutorial introduces an SQLAlchemy and URL dispatch-based Pyramid application to a developer fa-
miliar with Python. When finished, the developer will have created a basic wiki application with authen-
tication and authorization.

For cut and paste purposes, the source code for all stages of this tutorial can be browsed on GitHub for
a specific branch or version under docs/tutorials/wiki2/src, which corresponds to the same
location if you have Pyramid sources.

170 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Background

This version of the Pyramid wiki tutorial presents a Pyramid application that uses technologies which will
be familiar to someone with SQL database experience. It uses SQLAlchemy as a persistence mechanism
and URL dispatch to map URLs to code. It can also be followed by people without any prior Python web
framework experience.

To code along with this tutorial, the developer will need a Unix machine with development tools (macOS
with XCode, any Linux or BSD variant, etc.) or a Windows system of any kind.

This tutorial runs on Python 3 without modification.

Have fun!

Design

Following is a quick overview of the design of our wiki application to help us understand the changes that
we will be making as we work through the tutorial.

Overall

We choose to use reStructuredText markup in the wiki text. Translation from reStructuredText to HTML
is provided by the widely used docutils Python module. We will add this module to the dependency
list in the project’s setup.py file.

Models

We’ll be using an SQLite database to hold our wiki data, and we’ll be using SQLAlchemy to access the data
in this database. We will also use Alembic for database migrations, including initialization of the SQLite
database.

Within the database, we will define two tables:

• The users table which will store the id, name, password_hash and role of each wiki user.

0.2. Tutorials 171


The Pyramid Web Framework, Version 2.0.2

• The pages table, whose elements will store the wiki pages. There are four columns: id, name,
data and creator_id.

There is a one-to-many relationship between users and pages tracking the user who created each wiki
page defined by the creator_id column on the pages table.

URLs like /PageName will try to find an element in the pages table that has a corresponding name.

To add a page to the wiki, a new row is created and the text is stored in data.

A page named FrontPage containing the text ”This is the front page” will be created when the storage
is initialized, and will be used as the wiki home page.

Wiki Views

There will be three views to handle the normal operations of adding, editing, and viewing wiki pages, plus
one view for the wiki front page. Two templates will be used, one for viewing, and one for both adding
and editing wiki pages.

As of version 1.5 Pyramid no longer ships with templating systems. In this tutorial, we will use Jinja2.
Jinja2 is a modern and designer-friendly templating language for Python, modeled after Django’s templates.

Security

We’ll eventually be adding security to our application. To do this, we’ll be using a very simple role-based
security model. We’ll assign a single role category to each user in our system.

basic
An authenticated user who can view content and create new pages. A basic user may also edit the
pages they have created but not pages created by other users.

editor
An authenticated user who can create and edit any content in the system.

172 CONTENTS
The Pyramid Web Framework, Version 2.0.2

In order to accomplish this we’ll need to define an authentication policy which can identify users by their
userid and role. Then we’ll need to define a page resource which contains the appropriate ACL:

Action Principal Permission


Allow Everyone view
Allow group:basic create
Allow group:editors edit
Allow <creator of page> edit

Permission declarations will be added to the views to assert the security policies as each request is handled.

On the security side of the application there are two additional views for handling login and logout as well
as two exception views for handling invalid access attempts and unhandled URLs.

Summary

The URL, actions, template, and permission associated to each view are listed in the following table:

0.2. Tutorials 173


The Pyramid Web Framework, Version 2.0.2

URL Action View Template Permission


/ Redirect to view_wiki
/FrontPage
/PageName Display existing view_page1 view.jinja2 view
page2
/Page- Display edit form edit_page edit.jinja2 edit
Name/edit_page with existing con-
tent.
If the form was
submitted, redi-
rect to /PageName
/add_page/PageNameCreate the page add_page edit.jinja2 create
PageName in
storage, display
the edit form
without content.
If the form was
submitted, redi-
rect to /PageName
/login Display login login login.jinja2
form, Forbidden3
If the form was
submitted, au-
thenticate.
• If authen-
tication
succeeds,
redirect to
the page
from which
we came.
• If authenti-
cation fails,
display
login form
with ”login
failed”
message.

/logout Redirect to logout


/FrontPage

174 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Installation

Before you begin

This tutorial assumes that you have already followed the steps in Installing Pyramid, except do not create
a virtual environment or install Pyramid. Thereby you will satisfy the following requirements.

• A Python interpreter is installed on your operating system.

• You’ve satisfied the Requirements for Installing Packages.

Install SQLite3 and its development packages

If you used a package manager to install your Python or if you compiled your Python from source, then
you must install SQLite3 and its development packages. If you downloaded your Python as an installer
from https://www.python.org, then you already have it installed and can skip this step.

If you need to install the SQLite3 packages, then, for example, using the Debian system and apt-get,
the command would be the following:

sudo apt-get install libsqlite3-dev

Install cookiecutter

We will use a cookiecutter to create a Python package project from a Python package project template. See
Cookiecutter Installation for instructions.

Generate a Pyramid project from a cookiecutter

We will create a Pyramid project in your home directory for Unix or at the root for Windows. It is assumed
you know the path to where you installed cookiecutter. Issue the following commands and override
the defaults in the prompts as follows.
2 Pyramid will return a default 404 Not Found page if the page PageName does not exist yet.
1 This is the default view for a Page context when there is no view name.
3 pyramid.exceptions.Forbidden is reached when a user tries to invoke a view that is not authorized by the authorization

policy.

0.2. Tutorials 175


The Pyramid Web Framework, Version 2.0.2

On Unix

cd ~
cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 2.0-branch

On Windows

cd \
cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 2.0-branch

On all operating systems

If prompted for the first item, accept the default yes by hitting return.

You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.


Is it okay to delete and re-clone it? [yes]: yes
project_name [Pyramid Scaffold]: myproj
repo_name [myproj]: tutorial
Select template_language:
1 - jinja2
2 - chameleon
3 - mako
Choose from 1, 2, 3 [1]: 1
Select backend:
1 - none
2 - sqlalchemy
3 - zodb
Choose from 1, 2, 3 [1]: 2

Change directory into your newly created project

On Unix

176 CONTENTS
The Pyramid Web Framework, Version 2.0.2

cd tutorial

On Windows

cd tutorial

Set and use a VENV environment variable

We will set the VENV environment variable to the absolute path of the virtual environment, and use it going
forward.

On Unix

export VENV=~/tutorial

On Windows

set VENV=c:\tutorial

Create a virtual environment

On Unix

python3 -m venv $VENV

0.2. Tutorials 177


The Pyramid Web Framework, Version 2.0.2

On Windows

python -m venv %VENV%

Upgrade packaging tools in the virtual environment

On Unix

$VENV/bin/pip install --upgrade pip setuptools

On Windows

%VENV%\Scripts\pip install --upgrade pip setuptools

Installing the project in development mode

In order to do development on the project easily, you must ”register” the project as a development egg
in your workspace. We will install testing requirements at the same time. We do so with the following
command.

On Unix

$VENV/bin/pip install -e ".[testing]"

On Windows

%VENV%\Scripts\pip install -e ".[testing]"

178 CONTENTS
The Pyramid Web Framework, Version 2.0.2

On all operating systems

The console will show pip checking for packages and installing missing packages. Success executing this
command will show a line like the following:

Successfully installed Jinja2-2.11.2 Mako-1.1.3 MarkupSafe-1.1.1␣


,→PasteDeploy-2.1.1 Pygments-2.7.3 SQLAlchemy-1.3.22 WebTest-2.0.35␣

,→alembic-1.4.3 attrs-20.3.0 beautifulsoup4-4.9.3 coverage-5.3.1 hupper-1.

,→10.2 iniconfig-1.1.1 packaging-20.8 plaster-1.0 plaster-pastedeploy-0.7␣

,→pluggy-0.13.1 py-1.10.0 pyparsing-2.4.7 pyramid-1.10.5 pyramid-

,→debugtoolbar-4.9 pyramid-jinja2-2.8 pyramid-mako-1.1.0 pyramid-retry-2.1.

,→1 pyramid-tm-2.4 pytest-6.2.1 pytest-cov-2.10.1 python-dateutil-2.8.1␣

,→python-editor-1.0.4 repoze.lru-0.7 six-1.15.0 soupsieve-2.1 toml-0.10.2␣

,→transaction-3.0.1 translationstring-1.4 tutorial venusian-3.0.0 waitress-

,→1.4.4 webob-1.8.6 zope.deprecation-4.4.0 zope.interface-5.2.0 zope.

,→sqlalchemy-1.3

Testing requirements are defined in our project’s setup.py file, in the tests_require and ex-
tras_require stanzas.

25 tests_require = [
26 'WebTest',
27 'pytest',
28 'pytest-cov',
29 ]

49 extras_require={
50 'testing': tests_require,
51 },

Initialize and upgrade the database using Alembic

We use Alembic to manage our database initialization and migrations.

Generate your first revision.

0.2. Tutorials 179


The Pyramid Web Framework, Version 2.0.2

On Unix

$VENV/bin/alembic -c development.ini revision --autogenerate -m "init"

On Windows

%VENV%\Scripts\alembic -c development.ini revision --autogenerate -m "init"

The output to your console should be something like this:

2021-01-07 05:15:57,709 INFO [alembic.runtime.migration:155][MainThread]␣


,→Context impl SQLiteImpl.

2021-01-07 05:15:57,709 INFO [alembic.runtime.migration:162][MainThread]␣


,→Will assume non-transactional DDL.

2021-01-07 05:15:57,712 INFO [alembic.autogenerate.


,→compare:134][MainThread] Detected added table 'models'

2021-01-07 05:15:57,712 INFO [alembic.autogenerate.


,→compare:588][MainThread] Detected added index 'my_index' on '['name']'

Generating <somepath>/tutorial/tutorial/alembic/versions/20210107_
,→d7ab09c3fdec.py ... done

Upgrade to that revision.

On Unix

$VENV/bin/alembic -c development.ini upgrade head

On Windows

%VENV%\Scripts\alembic -c development.ini upgrade head

The output to your console should be something like this:

180 CONTENTS
The Pyramid Web Framework, Version 2.0.2

2021-01-07 05:16:21,558 INFO [alembic.runtime.migration:155][MainThread]␣


,→Context impl SQLiteImpl.

2021-01-07 05:16:21,558 INFO [alembic.runtime.migration:162][MainThread]␣


,→Will assume non-transactional DDL.

2021-01-07 05:16:21,560 INFO [alembic.runtime.migration:517][MainThread]␣


,→Running upgrade -> d7ab09c3fdec, init

Load default data

Load default data into the database using a console script. Type the following command, making sure you
are still in the tutorial directory (the directory with a development.ini in it):

On Unix

$VENV/bin/initialize_tutorial_db development.ini

On Windows

%VENV%\Scripts\initialize_tutorial_db development.ini

There should be no output to your console. You should now have a tutorial.sqlite file in your
current working directory. This is an SQLite database with two tables defined in it, alembic_version
and models, where each table has a single record.

Run the tests

After you’ve installed the project in development mode as well as the testing requirements, you may run
the tests for the project. The following commands provide options to pytest that specify the module for
which its tests shall be run, and to run pytest in quiet mode.

0.2. Tutorials 181


The Pyramid Web Framework, Version 2.0.2

On Unix

$VENV/bin/pytest -q

On Windows

%VENV%\Scripts\pytest -q

For a successful test run, you should see output that ends like this:

.....
5 passed in 0.44 seconds

Expose test coverage information

You can run the pytest command to see test coverage information. This runs the tests in the same way
that pytest does, but provides additional coverage information, exposing which lines of your project are
covered by the tests.

We’ve already installed the pytest-cov package into our virtual environment, so we can run the tests
with coverage.

On Unix

$VENV/bin/pytest --cov --cov-report=term-missing

On Windows

%VENV%\Scripts\pytest --cov --cov-report=term-missing

If successful, you will see output something like this:

182 CONTENTS
The Pyramid Web Framework, Version 2.0.2

======================== test session starts ========================


platform darwin -- Python 3.9.0, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: <somepath>/tutorial, inifile: pytest.ini, testpaths: tutorial,␣
,→tests

plugins: cov-2.10.1
collected 5 items

tests/test_functional.py .. ␣
,→ [ 40%]
tests/test_views.py ... ␣
,→ [100%]

---------- coverage: platform darwin, python 3.9.0-final-0 -----------


Name Stmts Miss Cover ␣
,→Missing

---------------------------------------------------------------------------
,→-------

tutorial/__init__.py 8 0 100%
tutorial/alembic/env.py 23 4 83% ␣
,→28-30, 56

tutorial/alembic/versions/20200106_8c274fe5f3c4.py 12 2 83% ␣
,→31-32

tutorial/models/__init__.py 32 2 94% ␣
,→71, 82

tutorial/models/meta.py 5 0 100%
tutorial/models/mymodel.py 8 0 100%
tutorial/pshell.py 7 5 29% ␣
,→5-13

tutorial/routes.py 3 0 100%
tutorial/scripts/__init__.py 0 0 100%
tutorial/scripts/initialize_db.py 22 14 36% ␣
,→15-16, 20-25, 29-38

tutorial/views/__init__.py 0 0 100%
tutorial/views/default.py 13 0 100%
tutorial/views/notfound.py 5 0 100%
---------------------------------------------------------------------------
,→-------

TOTAL 138 27 80%

===================== 5 passed in 0.77 seconds ======================

Our package doesn’t quite have 100% test coverage.

0.2. Tutorials 183


The Pyramid Web Framework, Version 2.0.2

Test and coverage cookiecutter defaults

The Pyramid cookiecutter includes configuration defaults for pytest and test coverage. These configu-
ration files are pytest.ini and .coveragerc, located at the root of your package.

pytest follows conventions for Python test discovery. The configuration defaults from the cookiecutter
tell pytest where to find the module on which we want to run tests and coverage.

See also:

See pytest’s documentation for How to invoke pytest or invoke pytest -h to see its full set of options.

Start the application

Start the application. See What Is This pserve Thing for more information on pserve.

On Unix

$VENV/bin/pserve development.ini --reload

On Windows

%VENV%\Scripts\pserve development.ini --reload

Your OS firewall, if any, may pop up a dialog asking for authorization to allow python to accept
incoming network connections.

If successful, you will see something like this on your console:

Starting monitor for PID 68932.


Starting server in PID 68932.
Serving on http://localhost:6543
Serving on http://localhost:6543

This means the server is ready to accept requests.

184 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Visit the application in a browser

In a browser, visit http://localhost:6543/. You will see the generated application’s default page.

One thing you’ll notice is the ”debug toolbar” icon on right hand side of the page. You can read more about
the purpose of the icon at The Debug Toolbar. It allows you to get information about your application while
you develop.

Decisions the cookiecutter backend option sqlalchemy has made for you

When creating a project and selecting the backend option of sqlalchemy, the cookiecutter makes the
following assumptions:

• You are willing to use SQLite for persistent storage, although almost any SQL database could be
used with SQLAlchemy.

• You are willing to use SQLAlchemy for a database access tool.

• You are willing to use Alembic for a database migrations tool.

• You are willing to use a console script for a data loading tool.

• You are willing to use URL dispatch to map URLs to code.

• You want to use zope.sqlalchemy, pyramid_tm, and the transaction packages to scope sessions to
requests.

Pyramid supports any persistent storage mechanism (e.g., object database or filesystem files). It also
supports an additional mechanism to map URLs to code (traversal). However, for the purposes of this
tutorial, we’ll only be using URL dispatch and SQLAlchemy.

Basic Layout

The starter files generated from choosing the sqlalchemy backend option in the cookiecutter are very
basic, but they provide a good orientation for the high-level patterns common to most URL dispatch-based
Pyramid projects.

0.2. Tutorials 185


The Pyramid Web Framework, Version 2.0.2

Application configuration with __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. We use __init__.py both as a marker, indicating
the directory in which it’s contained is a package, and to contain application configuration code.

Open tutorial/__init__.py. It should already contain the following:

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 """ This function returns a Pyramid WSGI application.
6 """
7 with Configurator(settings=settings) as config:
8 config.include('pyramid_jinja2')
9 config.include('.routes')
10 config.include('.models')
11 config.scan()
12 return config.make_wsgi_app()

Let’s go over this piece-by-piece. First we need some imports to support later code:

1 from pyramid.config import Configurator


2

__init__.py defines a function named main. Here is the entirety of the main function we’ve defined
in our __init__.py:

4 def main(global_config, **settings):


5 """ This function returns a Pyramid WSGI application.
6 """
7 with Configurator(settings=settings) as config:
8 config.include('pyramid_jinja2')
9 config.include('.routes')
10 config.include('.models')
11 config.scan()
12 return config.make_wsgi_app()

When you invoke the pserve development.ini command, the main function above is executed.
It accepts some settings and returns a WSGI application. (See Startup for more about pserve.)

Next in main, construct a Configurator object using a context manager:

186 CONTENTS
The Pyramid Web Framework, Version 2.0.2

7 with Configurator(settings=settings) as config:

settings is passed to the Configurator as a keyword argument with the dictionary values passed
as the **settings argument. This will be a dictionary of settings parsed from the .ini file, which
contains deployment-related values, such as pyramid.reload_templates, sqlalchemy.url,
and so on.

Next include Jinja2 templating bindings so that we can use renderers with the .jinja2 extension within
our project.

8 config.include('pyramid_jinja2')

Next include the routes module using a dotted Python path. This module will be explained in the next
section.

9 config.include('.routes')

Next include the package models using a dotted Python path. The exact setup of the models will be
covered later.

10 config.include('.models')

Pyramid’s pyramid.config.Configurator.include() method is the primary mecha-


nism for extending the configurator and breaking your code into feature-focused modules.

main next calls the scan method of the configurator (pyramid.config.Configurator.


scan()), which will recursively scan our tutorial package, looking for @view_config and other
special decorators. When it finds a @view_config decorator, a view configuration will be registered,
allowing one of our application URLs to be mapped to some code.

11 config.scan()

Finally main is finished configuring things, so it uses the pyramid.config.Configurator.


make_wsgi_app() method to return a WSGI application:

0.2. Tutorials 187


The Pyramid Web Framework, Version 2.0.2

12 return config.make_wsgi_app()

Route declarations

Open the tutorial/routes.py file. It should already contain the following:

1 def includeme(config):
2 config.add_static_view('static', 'static', cache_max_age=3600)
3 config.add_route('home', '/')

On line 2, we call pyramid.config.Configurator.add_static_view() with three argu-


ments: static (the name), static (the path), and cache_max_age (a keyword argument).

This registers a static resource view which will match any URL that starts with the prefix /static
(by virtue of the first argument to add_static_view). This will serve up static resources for us from
within the static directory of our tutorial package, in this case via http://localhost:6543/
static/ and below (by virtue of the second argument to add_static_view). With this declaration,
we’re saying that any URL that starts with /static should go to the static view; any remainder of its
path (e.g., the /foo in /static/foo) will be used to compose a path to a static file resource, such as a
CSS file.

On line 3, the module registers a route configuration via the pyramid.config.Configurator.


add_route() method that will be used when the URL is /. Since this route has a pattern equaling
/, it is the route that will be matched when the URL / is visited, e.g., http://localhost:6543/.

View declarations via the views package

The main function of a web framework is mapping each URL pattern to code (a view callable) that is
executed when the requested URL matches the corresponding route. Our application uses the pyramid.
view.view_config() decorator to perform this mapping.

Open tutorial/views/default.py in the views package. It should already contain the follow-
ing:

188 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.view import view_config


2 from pyramid.response import Response
3 from sqlalchemy.exc import SQLAlchemyError
4

5 from .. import models


6

8 @view_config(route_name='home', renderer='tutorial:templates/mytemplate.
,→jinja2')

9 def my_view(request):
10 try:
11 query = request.dbsession.query(models.MyModel)
12 one = query.filter(models.MyModel.name == 'one').one()
13 except SQLAlchemyError:
14 return Response(db_err_msg, content_type='text/plain', status=500)
15 return {'one': one, 'project': 'myproj'}
16

17

18 db_err_msg = """\
19 Pyramid is having a problem using your SQL database. The problem
20 might be caused by one of the following things:
21

22 1. You may need to initialize your database tables with `alembic`.


23 Check your README.txt for descriptions and try to run it.
24

25 2. Your database server may not be running. Check that the


26 database server referred to by the "sqlalchemy.url" setting in
27 your "development.ini" file is running.
28

29 After you fix the problem, please restart the Pyramid application to
30 try it again.
31 """

The important part here is that the @view_config decorator associates the function it decorates
(my_view) with a view configuration, consisting of:

• a route_name (home)

• a renderer, which is a template from the templates subdirectory of the package.

When the pattern associated with the home view is matched during a request, my_view() will be
executed. my_view() returns a dictionary; the renderer will use the templates/mytemplate.
jinja2 template to create a response based on the values in the dictionary.

0.2. Tutorials 189


The Pyramid Web Framework, Version 2.0.2

Note that my_view() accepts a single argument named request. This is the standard call signature
for a Pyramid view callable.

Remember in our __init__.py when we executed the pyramid.config.Configurator.


scan() method config.scan()? The purpose of calling the scan method was to find and process
this @view_config decorator in order to create a view configuration within our application. Without
being processed by scan, the decorator effectively does nothing. @view_config is inert without being
detected via a scan.

The sample my_view() created by the cookiecutter uses a try: and except: clause to detect if there
is a problem accessing the project database and provide an alternate error response. That response will
include the text shown at the end of the file, which will be displayed in the browser to inform the user
about possible actions to take to solve the problem.

Open tutorial/views/notfound.py in the views package to look at the second view.

1 from pyramid.view import notfound_view_config


2

4 @notfound_view_config(renderer='tutorial:templates/404.jinja2')
5 def notfound_view(request):
6 request.response.status = 404
7 return {}

Without repeating ourselves, we will point out the differences between this view and the previous.

1. Line 4. The notfound_view function is decorated with @notfound_view_config.


This decorator registers a Not Found View using pyramid.config.Configurator.
add_notfound_view().

The renderer argument names an asset specification of tutorial:templates/404.


jinja2.

2. Lines 5-7. A view callable named notfound_view is defined, which is decorated in the step
above. It sets the HTTP response status code to 404. The function returns an empty dictionary to
the template 404.jinja2, which accepts no parameters anyway.

Content models with the models package

In a SQLAlchemy-based application, a model object is an object composed by querying the SQL database.
The models package is where the alchemy cookiecutter put the classes that implement our models.

First, open tutorial/models/meta.py, which should already contain the following:

190 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from sqlalchemy.ext.declarative import declarative_base


2 from sqlalchemy.schema import MetaData
3

4 # Recommended naming convention used by Alembic, as various different␣


,→database

5 # providers will autogenerate vastly different names making migrations more


6 # difficult. See: https://alembic.sqlalchemy.org/en/latest/naming.html
7 NAMING_CONVENTION = {
8 "ix": "ix_%(column_0_label)s",
9 "uq": "uq_%(table_name)s_%(column_0_name)s",
10 "ck": "ck_%(table_name)s_%(constraint_name)s",
11 "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
12 "pk": "pk_%(table_name)s"
13 }
14

15 metadata = MetaData(naming_convention=NAMING_CONVENTION)
16 Base = declarative_base(metadata=metadata)

meta.py contains imports and support code for defining the models. We create a dictionary NAM-
ING_CONVENTION as well for consistent naming of support objects like indices and constraints.

1 from sqlalchemy.ext.declarative import declarative_base


2 from sqlalchemy.schema import MetaData
3

4 # Recommended naming convention used by Alembic, as various different␣


,→database

5 # providers will autogenerate vastly different names making migrations more


6 # difficult. See: https://alembic.sqlalchemy.org/en/latest/naming.html
7 NAMING_CONVENTION = {
8 "ix": "ix_%(column_0_label)s",
9 "uq": "uq_%(table_name)s_%(column_0_name)s",
10 "ck": "ck_%(table_name)s_%(constraint_name)s",
11 "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
12 "pk": "pk_%(table_name)s"
13 }
14

Next we create a metadata object from the class sqlalchemy.schema.MetaData, using NAM-
ING_CONVENTION as the value for the naming_convention argument.

A MetaData object represents the table and other schema definitions for a single database. We also need
to create a declarative Base object to use as a base class for our models. Our models will inherit from this
Base, which will attach the tables to the metadata we created, and define our application’s database
schema.

0.2. Tutorials 191


The Pyramid Web Framework, Version 2.0.2

15 metadata = MetaData(naming_convention=NAMING_CONVENTION)
16 Base = declarative_base(metadata=metadata)

Next open tutorial/models/mymodel.py, which should already contain the following:

1 from sqlalchemy import (


2 Column,
3 Index,
4 Integer,
5 Text,
6 )
7

8 from .meta import Base


9

10

11 class MyModel(Base):
12 __tablename__ = 'models'
13 id = Column(Integer, primary_key=True)
14 name = Column(Text)
15 value = Column(Integer)
16

17

18 Index('my_index', MyModel.name, unique=True, mysql_length=255)

Notice we’ve defined the models as a package to make it straightforward for defining models in separate
modules. To give a simple example of a model class, we have defined one named MyModel in mymodel.
py:

11 class MyModel(Base):
12 __tablename__ = 'models'
13 id = Column(Integer, primary_key=True)
14 name = Column(Text)
15 value = Column(Integer)

Our example model does not require an __init__ method because SQLAlchemy supplies for us a default
constructor, if one is not already present, which accepts keyword arguments of the same name as that of
the mapped attributes.

Example usage of MyModel:

192 CONTENTS
The Pyramid Web Framework, Version 2.0.2

johnny = MyModel(name="John Doe", value=10)

The MyModel class has a __tablename__ attribute. This informs SQLAlchemy which table to use to
store the data representing instances of this class.

Finally, open tutorial/models/__init__.py, which should already contain the following:

1 from sqlalchemy import engine_from_config


2 from sqlalchemy.orm import sessionmaker
3 from sqlalchemy.orm import configure_mappers
4 import zope.sqlalchemy
5

6 # Import or define all models here to ensure they are attached to the
7 # ``Base.metadata`` prior to any initialization routines.
8 from .mymodel import MyModel # flake8: noqa
9

10 # Run ``configure_mappers`` after defining all of the models to ensure


11 # all relationships can be setup.
12 configure_mappers()
13

14

15 def get_engine(settings, prefix='sqlalchemy.'):


16 return engine_from_config(settings, prefix)
17

18

19 def get_session_factory(engine):
20 factory = sessionmaker()
21 factory.configure(bind=engine)
22 return factory
23

24

25 def get_tm_session(session_factory, transaction_manager, request=None):


26 """
27 Get a ``sqlalchemy.orm.Session`` instance backed by a transaction.
28

29 This function will hook the session to the transaction manager which
30 will take care of committing any changes.
31

32 - When using pyramid_tm it will automatically be committed or aborted


33 depending on whether an exception is raised.
34

35 - When using scripts you should wrap the session in a manager yourself.
36 For example:
(continues on next page)

0.2. Tutorials 193


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


37

38 .. code-block:: python
39

40 import transaction
41

42 engine = get_engine(settings)
43 session_factory = get_session_factory(engine)
44 with transaction.manager:
45 dbsession = get_tm_session(session_factory, transaction.
,→ manager)
46

47 This function may be invoked with a ``request`` kwarg, such as when␣


,→invoked
48 by the reified ``.dbsession`` Pyramid request attribute which is␣
,→configured

49 via the ``includeme`` function below. The default value, for backwards
50 compatibility, is ``None``.
51

52 The ``request`` kwarg is used to populate the ``sqlalchemy.orm.


,→Session``'s
53 "info" dict. The "info" dict is the official namespace for developers␣
,→to

54 stash session-specific information. For more information, please see␣


,→the

55 SQLAlchemy docs:
56 https://docs.sqlalchemy.org/en/stable/orm/session_api.html#sqlalchemy.
,→orm.session.Session.params.info

57

58 By placing the active ``request`` in the "info" dict, developers will␣


,→ be
59 able to access the active Pyramid request from an instance of an␣
,→ SQLAlchemy
60 object in one of two ways:
61

62 - Classic SQLAlchemy. This uses the ``Session``'s utility class method:


63

64 .. code-block:: python
65

66 from sqlalchemy.orm.session import Session as sa_Session


67

68 dbsession = sa_Session.object_session(dbObject)
69 request = dbsession.info["request"]
70

71 - Modern SQLAlchemy. This uses the "Runtime Inspection API":


72

(continues on next page)

194 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


73 .. code-block:: python
74

75 from sqlalchemy import inspect as sa_inspect


76

77 dbsession = sa_inspect(dbObject).session
78 request = dbsession.info["request"]
79 """
80 dbsession = session_factory(info={"request": request})
81 zope.sqlalchemy.register(
82 dbsession, transaction_manager=transaction_manager
83 )
84 return dbsession
85

86

87 def includeme(config):
88 """
89 Initialize the model for a Pyramid app.
90

91 Activate this setup using ``config.include('tutorial.models')``.


92

93 """
94 settings = config.get_settings()
95 settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
96

97 # Use ``pyramid_tm`` to hook the transaction lifecycle to the request.


98 # Note: the packages ``pyramid_tm`` and ``transaction`` work together␣
,→ to
99 # automatically close the active database session after every request.
100 # If your project migrates away from ``pyramid_tm``, you may need to␣
,→use a

101 # Pyramid callback function to close the database session after each
102 # request.
103 config.include('pyramid_tm')
104

105 # use pyramid_retry to retry a request when transient exceptions occur


106 config.include('pyramid_retry')
107

108 # hook to share the dbengine fixture in testing


109 dbengine = settings.get('dbengine')
110 if not dbengine:
111 dbengine = get_engine(settings)
112

113 session_factory = get_session_factory(dbengine)


114 config.registry['dbsession_factory'] = session_factory
115

(continues on next page)

0.2. Tutorials 195


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


116 # make request.dbsession available for use in Pyramid
117 def dbsession(request):
118 # hook to share the dbsession fixture in testing
119 dbsession = request.environ.get('app.dbsession')
120 if dbsession is None:
121 # request.tm is the transaction manager used by pyramid_tm
122 dbsession = get_tm_session(
123 session_factory, request.tm, request=request
124 )
125 return dbsession
126

127 config.add_request_method(dbsession, reify=True)

Our models/__init__.py module defines the primary API we will use for configuring the database
connections within our application, and it contains several functions we will cover below.

As we mentioned above, the purpose of the models.meta.metadata object is to describe the schema
of the database. This is done by defining models that inherit from the Base object attached to that meta-
data object. In Python, code is only executed if it is imported, and so to attach the models table
defined in mymodel.py to the metadata, we must import it. If we skip this step, then later, when we
run sqlalchemy.schema.MetaData.create_all(), the table will not be created because the
metadata object does not know about it!

Another important reason to import all of the models is that, when defining relationships between
models, they must all exist in order for SQLAlchemy to find and build those internal mappings.
This is why, after importing all the models, we explicitly execute the function sqlalchemy.orm.
configure_mappers(), once we are sure all the models have been defined and before we start creating
connections.

Next we define several functions for connecting to our database. The first and lowest level is
the get_engine function. This creates an SQLAlchemy database engine using sqlalchemy.
engine_from_config() from the sqlalchemy.-prefixed settings in the development.ini
file’s [app:main] section. This setting is a URI (something like sqlite://).

15 def get_engine(settings, prefix='sqlalchemy.'):


16 return engine_from_config(settings, prefix)

The function get_session_factory accepts an SQLAlchemy database engine, and creates a ses-
sion_factory from the SQLAlchemy class sqlalchemy.orm.session.sessionmaker. This
session_factory is then used for creating sessions bound to the database engine.

196 CONTENTS
The Pyramid Web Framework, Version 2.0.2

19 def get_session_factory(engine):
20 factory = sessionmaker()
21 factory.configure(bind=engine)
22 return factory

The function get_tm_session registers a database session with a transaction manager, and returns a
dbsession object. With the transaction manager, our application will automatically issue a transaction
commit after every request, unless an exception is raised, in which case the transaction will be aborted.

25 def get_tm_session(session_factory, transaction_manager, request=None):


26 """
27 Get a ``sqlalchemy.orm.Session`` instance backed by a transaction.
28

29 This function will hook the session to the transaction manager which
30 will take care of committing any changes.
31

32 - When using pyramid_tm it will automatically be committed or aborted


33 depending on whether an exception is raised.
34

35 - When using scripts you should wrap the session in a manager yourself.
36 For example:
37

38 .. code-block:: python
39

40 import transaction
41

42 engine = get_engine(settings)
43 session_factory = get_session_factory(engine)
44 with transaction.manager:
45 dbsession = get_tm_session(session_factory, transaction.
,→ manager)
46

47 This function may be invoked with a ``request`` kwarg, such as when␣


,→invoked
48 by the reified ``.dbsession`` Pyramid request attribute which is␣
,→configured

49 via the ``includeme`` function below. The default value, for backwards
50 compatibility, is ``None``.
51

52 The ``request`` kwarg is used to populate the ``sqlalchemy.orm.


,→Session``'s
53 "info" dict. The "info" dict is the official namespace for developers␣
,→to

54 stash session-specific information. For more information, please see␣


(continues on next page)

0.2. Tutorials 197


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


,→the
55 SQLAlchemy docs:
56 https://docs.sqlalchemy.org/en/stable/orm/session_api.html#sqlalchemy.
,→orm.session.Session.params.info

57

58 By placing the active ``request`` in the "info" dict, developers will␣


,→ be
59 able to access the active Pyramid request from an instance of an␣
,→ SQLAlchemy
60 object in one of two ways:
61

62 - Classic SQLAlchemy. This uses the ``Session``'s utility class method:


63

64 .. code-block:: python
65

66 from sqlalchemy.orm.session import Session as sa_Session


67

68 dbsession = sa_Session.object_session(dbObject)
69 request = dbsession.info["request"]
70

71 - Modern SQLAlchemy. This uses the "Runtime Inspection API":


72

73 .. code-block:: python
74

75 from sqlalchemy import inspect as sa_inspect


76

77 dbsession = sa_inspect(dbObject).session
78 request = dbsession.info["request"]
79 """
80 dbsession = session_factory(info={"request": request})
81 zope.sqlalchemy.register(
82 dbsession, transaction_manager=transaction_manager
83 )
84 return dbsession

Finally, we define an includeme function, which is a hook for use with pyramid.config.
Configurator.include() to activate code in a Pyramid application add-on. It is the code that is ex-
ecuted above when we ran config.include('.models') in our application’s main function. This
function will take the settings from the application, create an engine, and define a request.dbsession
property, which we can use to do work on behalf of an incoming request to our application.

87 def includeme(config):
88 """
89 Initialize the model for a Pyramid app.
(continues on next page)

198 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


90

91 Activate this setup using ``config.include('tutorial.models')``.


92

93 """
94 settings = config.get_settings()
95 settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
96

97 # Use ``pyramid_tm`` to hook the transaction lifecycle to the request.


98 # Note: the packages ``pyramid_tm`` and ``transaction`` work together␣
,→ to
99 # automatically close the active database session after every request.
100 # If your project migrates away from ``pyramid_tm``, you may need to␣
,→use a

101 # Pyramid callback function to close the database session after each
102 # request.
103 config.include('pyramid_tm')
104

105 # use pyramid_retry to retry a request when transient exceptions occur


106 config.include('pyramid_retry')
107

108 # hook to share the dbengine fixture in testing


109 dbengine = settings.get('dbengine')
110 if not dbengine:
111 dbengine = get_engine(settings)
112

113 session_factory = get_session_factory(dbengine)


114 config.registry['dbsession_factory'] = session_factory
115

116 # make request.dbsession available for use in Pyramid


117 def dbsession(request):
118 # hook to share the dbsession fixture in testing
119 dbsession = request.environ.get('app.dbsession')
120 if dbsession is None:
121 # request.tm is the transaction manager used by pyramid_tm
122 dbsession = get_tm_session(
123 session_factory, request.tm, request=request
124 )
125 return dbsession
126

127 config.add_request_method(dbsession, reify=True)

That’s about all there is to it regarding models, views, and initialization code in our stock application.

The Index import and the Index object creation in mymodel.py is not required for this tutorial, and
will be removed in the next step.

0.2. Tutorials 199


The Pyramid Web Framework, Version 2.0.2

Tests

The project contains a basic structure for a test suite using pytest. The structure is covered later in
Adding Tests.

Defining the Domain Model

The first change we’ll make to our stock cookiecutter-generated application will be to define a wiki page
domain model.

There is nothing special about the filename user.py or page.py except that they are Python
modules. A project may have many models throughout its codebase in arbitrarily named modules. Modules
implementing models often have model in their names or they may live in a Python subpackage of your
application package named models (as we’ve done in this tutorial), but this is only a convention and not
a requirement.

Declaring dependencies in our setup.py file

The models code in our application will depend on a package which is not a dependency of the original
”tutorial” application. The original ”tutorial” application was generated by the cookiecutter; it doesn’t
know about our custom application requirements.

We need to add a dependency, the bcrypt package, to our tutorial package’s setup.py file by as-
signing this dependency to the requires parameter in the setup() function.

Open tutorial/setup.py and edit it to look like the following by adding bcrypt and sorting the
packages:

11 requires = [
12 'alembic',
13 'bcrypt',
14 'plaster_pastedeploy',
15 'pyramid',
16 'pyramid_debugtoolbar',
17 'pyramid_jinja2',
18 'pyramid_retry',
(continues on next page)

200 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


19 'pyramid_tm',
20 'SQLAlchemy',
21 'transaction',
22 'waitress',
23 'zope.sqlalchemy',
24 ]

It is a good practice to sort packages alphabetically to make them easier to find. Our cookiecutter does not
have its packages sorted because it merely tacks on additional packages depending on our selections.

We are using the bcrypt package from PyPI to hash our passwords securely. There are other
one-way hash algorithms for passwords if bcrypt is an issue on your system. Just make sure that it’s an
algorithm approved for storing passwords versus a generic one-way hash.

Running pip install -e .

Since a new software dependency was added, you will need to run pip install -e . again inside
the root of the tutorial package to obtain and register the newly added dependency distribution.

Make sure your current working directory is the root of the project (the directory in which setup.py
lives) and execute the following command.

On Unix:

$VENV/bin/pip install -e .

On Windows:

%VENV%\Scripts\pip install -e .

Success executing this command will end with a line to the console something like the following.

Successfully installed bcrypt-3.2.0 cffi-1.14.4 pycparser-2.20 tutorial

0.2. Tutorials 201


The Pyramid Web Framework, Version 2.0.2

Remove mymodel.py

Let’s delete the file tutorial/models/mymodel.py. The MyModel class is only a sample and
we’re not going to use it.

Add user.py

Create a new file tutorial/models/user.py with the following contents:

1 import bcrypt
2 from sqlalchemy import (
3 Column,
4 Integer,
5 Text,
6 )
7

8 from .meta import Base


9

10

11 class User(Base):
12 """ The SQLAlchemy declarative model class for a User object. """
13 __tablename__ = 'users'
14 id = Column(Integer, primary_key=True)
15 name = Column(Text, nullable=False, unique=True)
16 role = Column(Text, nullable=False)
17

18 password_hash = Column(Text)
19

20 def set_password(self, pw):


21 pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt())
22 self.password_hash = pwhash.decode('utf8')
23

24 def check_password(self, pw):


25 if self.password_hash is not None:
26 expected_hash = self.password_hash.encode('utf8')
27 return bcrypt.checkpw(pw.encode('utf8'), expected_hash)
28 return False

This is a very basic model for a user who can authenticate with our wiki.

We discussed briefly in the previous chapter that our models will inherit from an SQLAlchemy
sqlalchemy.ext.declarative.declarative_base(). This will attach the model to our
schema.

202 CONTENTS
The Pyramid Web Framework, Version 2.0.2

As you can see, our User class has a class-level attribute __tablename__ which equals the string
users. Our User class will also have class-level attributes named id, name, password_hash, and
role (all instances of sqlalchemy.schema.Column). These will map to columns in the users
table. The id attribute will be the primary key in the table. The name attribute will be a text column, each
value of which needs to be unique within the column. The password_hash is a nullable text attribute
that will contain a securely hashed password. Finally, the role text attribute will hold the role of the user.

There are two helper methods that will help us later when using the user objects. The first is
set_password which will take a raw password and transform it using bcrypt into an irreversible
representation, a process known as ”hashing”. The second method, check_password, will allow us to
compare the hashed value of the submitted password against the hashed value of the password stored in
the user’s record in the database. If the two hashed values match, then the submitted password is valid,
and we can authenticate the user.

We hash passwords so that it is impossible to decrypt them and use them to authenticate in the application.
If we stored passwords foolishly in clear text, then anyone with access to the database could retrieve any
password to authenticate as any user.

Add page.py

Create a new file tutorial/models/page.py with the following contents:

1 from sqlalchemy import (


2 Column,
3 ForeignKey,
4 Integer,
5 Text,
6 )
7 from sqlalchemy.orm import relationship
8

9 from .meta import Base


10

11

12 class Page(Base):
13 """ The SQLAlchemy declarative model class for a Page object. """
14 __tablename__ = 'pages'
15 id = Column(Integer, primary_key=True)
16 name = Column(Text, nullable=False, unique=True)
17 data = Column(Text, nullable=False)
18

19 creator_id = Column(ForeignKey('users.id'), nullable=False)


20 creator = relationship('User', backref='created_pages')

0.2. Tutorials 203


The Pyramid Web Framework, Version 2.0.2

As you can see, our Page class is very similar to the User defined above, except with attributes focused
on storing information about a wiki page, including id, name, and data. The only new construct in-
troduced here is the creator_id column, which is a foreign key referencing the users table. Foreign
keys are very useful at the schema-level, but since we want to relate User objects with Page objects,
we also define a creator attribute as an ORM-level mapping between the two tables. SQLAlchemy
will automatically populate this value using the foreign key referencing the user. Since the foreign key
has nullable=False, we are guaranteed that an instance of page will have a corresponding page.
creator, which will be a User instance.

Edit models/__init__.py

Since we are using a package for our models, we also need to update our __init__.py file to ensure
that the models are attached to the metadata.

Open the tutorial/models/__init__.py file and edit it to look like the following:

1 from sqlalchemy import engine_from_config


2 from sqlalchemy.orm import sessionmaker
3 from sqlalchemy.orm import configure_mappers
4 import zope.sqlalchemy
5

6 # Import or define all models here to ensure they are attached to the
7 # ``Base.metadata`` prior to any initialization routines.
8 from .page import Page # flake8: noqa
9 from .user import User # flake8: noqa
10

11 # Run ``configure_mappers`` after defining all of the models to ensure


12 # all relationships can be setup.
13 configure_mappers()
14

15

16 def get_engine(settings, prefix='sqlalchemy.'):


17 return engine_from_config(settings, prefix)
18

19

20 def get_session_factory(engine):
21 factory = sessionmaker()
22 factory.configure(bind=engine)
23 return factory
24

25

26 def get_tm_session(session_factory, transaction_manager, request=None):


27 """
(continues on next page)

204 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


28 Get a ``sqlalchemy.orm.Session`` instance backed by a transaction.
29

30 This function will hook the session to the transaction manager which
31 will take care of committing any changes.
32

33 - When using pyramid_tm it will automatically be committed or aborted


34 depending on whether an exception is raised.
35

36 - When using scripts you should wrap the session in a manager yourself.
37 For example:
38

39 .. code-block:: python
40

41 import transaction
42

43 engine = get_engine(settings)
44 session_factory = get_session_factory(engine)
45 with transaction.manager:
46 dbsession = get_tm_session(session_factory, transaction.
,→ manager)
47

48 This function may be invoked with a ``request`` kwarg, such as when␣


,→invoked
49 by the reified ``.dbsession`` Pyramid request attribute which is␣
,→configured

50 via the ``includeme`` function below. The default value, for backwards
51 compatibility, is ``None``.
52

53 The ``request`` kwarg is used to populate the ``sqlalchemy.orm.


,→Session``'s
54 "info" dict. The "info" dict is the official namespace for developers␣
,→to

55 stash session-specific information. For more information, please see␣


,→the

56 SQLAlchemy docs:
57 https://docs.sqlalchemy.org/en/stable/orm/session_api.html#sqlalchemy.
,→orm.session.Session.params.info

58

59 By placing the active ``request`` in the "info" dict, developers will␣


,→ be
60 able to access the active Pyramid request from an instance of an␣
,→ SQLAlchemy
61 object in one of two ways:
62

63 - Classic SQLAlchemy. This uses the ``Session``'s utility class method:


(continues on next page)

0.2. Tutorials 205


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


64

65 .. code-block:: python
66

67 from sqlalchemy.orm.session import Session as sa_Session


68

69 dbsession = sa_Session.object_session(dbObject)
70 request = dbsession.info["request"]
71

72 - Modern SQLAlchemy. This uses the "Runtime Inspection API":


73

74 .. code-block:: python
75

76 from sqlalchemy import inspect as sa_inspect


77

78 dbsession = sa_inspect(dbObject).session
79 request = dbsession.info["request"]
80 """
81 dbsession = session_factory(info={"request": request})
82 zope.sqlalchemy.register(
83 dbsession, transaction_manager=transaction_manager
84 )
85 return dbsession
86

87

88 def includeme(config):
89 """
90 Initialize the model for a Pyramid app.
91

92 Activate this setup using ``config.include('tutorial.models')``.


93

94 """
95 settings = config.get_settings()
96 settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
97

98 # Use ``pyramid_tm`` to hook the transaction lifecycle to the request.


99 # Note: the packages ``pyramid_tm`` and ``transaction`` work together␣
,→ to
100 # automatically close the active database session after every request.
101 # If your project migrates away from ``pyramid_tm``, you may need to␣
,→use a

102 # Pyramid callback function to close the database session after each
103 # request.
104 config.include('pyramid_tm')
105

106 # use pyramid_retry to retry a request when transient exceptions occur


(continues on next page)

206 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


107 config.include('pyramid_retry')
108

109 # hook to share the dbengine fixture in testing


110 dbengine = settings.get('dbengine')
111 if not dbengine:
112 dbengine = get_engine(settings)
113

114 session_factory = get_session_factory(dbengine)


115 config.registry['dbsession_factory'] = session_factory
116

117 # make request.dbsession available for use in Pyramid


118 def dbsession(request):
119 # hook to share the dbsession fixture in testing
120 dbsession = request.environ.get('app.dbsession')
121 if dbsession is None:
122 # request.tm is the transaction manager used by pyramid_tm
123 dbsession = get_tm_session(
124 session_factory, request.tm, request=request
125 )
126 return dbsession
127

128 config.add_request_method(dbsession, reify=True)

Here we align our imports with the names of the models, Page and User.

Migrate the database with Alembic

Now that we have written our models, we need to modify the database schema to reflect the changes to our
code. Let’s generate a new revision, then upgrade the database to the latest revision (head).

On Unix:

$VENV/bin/alembic -c development.ini revision --autogenerate \


-m "use new models Page and User"
$VENV/bin/alembic -c development.ini upgrade head

On Windows:

%VENV%\Scripts\alembic -c development.ini revision \


--autogenerate -m "use new models Page and User"
%VENV%\Scripts\alembic -c development.ini upgrade head

0.2. Tutorials 207


The Pyramid Web Framework, Version 2.0.2

Success executing these commands will generate output similar to the following.

2021-01-07 08:00:14,550 INFO [alembic.runtime.migration:155][MainThread]␣


,→Context impl SQLiteImpl.

2021-01-07 08:00:14,551 INFO [alembic.runtime.migration:158][MainThread]␣


,→Will assume non-transactional DDL.

2021-01-07 08:00:14,553 INFO [alembic.autogenerate.


,→compare:134][MainThread] Detected added table 'users'

2021-01-07 08:00:14,553 INFO [alembic.autogenerate.


,→compare:134][MainThread] Detected added table 'pages'

2021-01-07 08:00:14,558 INFO [alembic.autogenerate.


,→compare:622][MainThread] Detected removed index 'my_index' on 'models'

2021-01-07 08:00:14,558 INFO [alembic.autogenerate.


,→compare:176][MainThread] Detected removed table 'models'

Generating <somepath>/tutorial/tutorial/alembic/versions/20210107_
,→bc9a3dead43a.py ... done

2021-01-07 08:00:21,318 INFO [alembic.runtime.migration:155][MainThread]␣


,→Context impl SQLiteImpl.

2021-01-07 08:00:21,318 INFO [alembic.runtime.migration:158][MainThread]␣


,→Will assume non-transactional DDL.

2021-01-07 08:00:21,320 INFO [alembic.runtime.migration:517][MainThread]␣


,→Running upgrade 90658c4a9673 -> bc9a3dead43a, use new models Page and␣

,→User

Alembic overview

Let’s briefly discuss our configuration for Alembic.

In the alchemy cookiecutter’s development.ini file, the setting for script_location config-
ures Alembic to look for the migration script in the directory tutorial/alembic. By default
Alembic stores the migration files one level deeper in tutorial/alembic/versions. These
files are generated by Alembic, then executed when we run upgrade or downgrade migrations. The
setting file_template provides the format for each migration’s file name. We’ve configured the
file_template setting to make it somewhat easy to find migrations by file name.

At this point in this tutorial, we have two migration files. Examine them to see what Alembic will do when
you upgrade or downgrade the database to a specific revision. Notice the revision identifiers and how they
relate to one another in a chained sequence.

See also:

For further information, see the Alembic documentation.

208 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Edit scripts/initialize_db.py

We haven’t looked at the details of this file yet, but within the scripts directory of your tutorial
package is a file named initialize_db.py. Code in this file is executed whenever we run the ini-
tialize_tutorial_db command, as we did in the installation step of this tutorial.

The command is named initialize_tutorial_db because of the mapping defined in the


[console_scripts] entry point of our project’s setup.py file.

Since we’ve changed our model, we need to make changes to our initialize_db.py script. In par-
ticular, we’ll replace our import of MyModel with those of User and Page. We’ll also change the the
script to create two User objects (basic and editor) as well as a Page, rather than a MyModel, and
add them to our dbsession.

Open tutorial/scripts/initialize_db.py and edit it to look like the following:

1 import argparse
2 import sys
3

4 from pyramid.paster import bootstrap, setup_logging


5 from sqlalchemy.exc import OperationalError
6

7 from .. import models


8

10 def setup_models(dbsession):
11 """
12 Add or update models / fixtures in the database.
13

14 """
15 editor = models.User(name='editor', role='editor')
16 editor.set_password('editor')
17 dbsession.add(editor)
18

19 basic = models.User(name='basic', role='basic')


20 basic.set_password('basic')
21 dbsession.add(basic)
22

23 page = models.Page(
24 name='FrontPage',
25 creator=editor,
(continues on next page)

0.2. Tutorials 209


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


26 data='This is the front page',
27 )
28 dbsession.add(page)
29

30

31 def parse_args(argv):
32 parser = argparse.ArgumentParser()
33 parser.add_argument(
34 'config_uri',
35 help='Configuration file, e.g., development.ini',
36 )
37 return parser.parse_args(argv[1:])
38

39

40 def main(argv=sys.argv):
41 args = parse_args(argv)
42 setup_logging(args.config_uri)
43 env = bootstrap(args.config_uri)
44

45 try:
46 with env['request'].tm:
47 dbsession = env['request'].dbsession
48 setup_models(dbsession)
49 except OperationalError:
50 print('''
51 Pyramid is having a problem using your SQL database. The problem
52 might be caused by one of the following things:
53

54 1. You may need to initialize your database tables with `alembic`.


55 Check your README.txt for description and try to run it.
56

57 2. Your database server may not be running. Check that the


58 database server referred to by the "sqlalchemy.url" setting in
59 your "development.ini" file is running.
60 ''')

Only the highlighted lines need to be changed.

210 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Populating the database

Because our model has changed, and to repopulate the database, we need to rerun the initial-
ize_tutorial_db command to pick up the changes we’ve made to the initialize_db.py file.

On Unix

$VENV/bin/initialize_tutorial_db development.ini

On Windows

%VENV%\Scripts\initialize_tutorial_db development.ini

There should be no output to your console to indicate success.

View the application in a browser

We can’t. At this point, our system is in a ”non-runnable” state; we’ll need to change view-related files in
the next chapter to be able to start the application successfully. If you try to start the application (see Start
the application) and visit http://localhost:6543, you’ll wind up with a Python traceback on your console
that ends with this exception:

AttributeError: module 'tutorial.models' has no attribute 'MyModel'

This will also happen if you attempt to run the tests.

Defining Views

A view callable in a Pyramid application is typically a simple Python function that accepts a single pa-
rameter named request. A view callable is assumed to return a response object.

The request object has a dictionary as an attribute named matchdict. A matchdict maps the place-
holders in the matching URL pattern to the substrings of the path in the request URL. For instance, if a
call to pyramid.config.Configurator.add_route() has the pattern /{one}/{two}, and a
user visits http://example.com/foo/bar, our pattern would be matched against /foo/bar and
the matchdict would look like {'one':'foo', 'two':'bar'}.

0.2. Tutorials 211


The Pyramid Web Framework, Version 2.0.2

Adding the docutils dependency

Remember in the previous chapter we added a new dependency of the bcrypt package. Again, the view
code in our application will depend on a package which is not a dependency of the original ”tutorial”
application.

We need to add a dependency on the docutils package to our tutorial package’s setup.py file
by assigning this dependency to the requires list.

Open tutorial/setup.py and edit it to look like the following:

11 requires = [
12 'alembic',
13 'bcrypt',
14 'docutils',
15 'plaster_pastedeploy',
16 'pyramid',
17 'pyramid_debugtoolbar',
18 'pyramid_jinja2',
19 'pyramid_retry',
20 'pyramid_tm',
21 'SQLAlchemy',
22 'transaction',
23 'waitress',
24 'zope.sqlalchemy',
25 ]

Only the highlighted line needs to be added.

Again, as we did in the previous chapter, the dependency now needs to be installed, so re-run the $VENV/
bin/pip install -e . command.

Static assets

Our templates name static assets, including CSS and images. We don’t need to create these files within our
package’s static directory because they were provided at the time we created the project.

As an example, the CSS file will be accessed via http://localhost:6543/static/theme.css


by virtue of the call to the add_static_view directive we’ve made in the tutorial/routes.
py file. Any number and type of static assets can be placed in this directory (or subdirectories) and
are just referred to by URL or by using the convenience method static_url, e.g., request.
static_url('<package>:static/foo.css') within templates.

212 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Adding routes to routes.py

This is the URL Dispatch tutorial, so let’s start by adding some URL patterns to our app. Later we’ll attach
views to handle the URLs.

The tutorial/routes.py file contains pyramid.config.Configurator.add_route()


calls which serve to add routes to our application. First we’ll get rid of the existing route created by
the template using the name 'home'. It’s only an example and isn’t relevant to our application.

We then need to add four calls to add_route. Note that the ordering of these declarations is very
important. Route declarations are matched in the order they’re registered.

1. Add a declaration which maps the pattern / (signifying the root URL) to the route named
view_wiki. In the next step, we will map it to our view_wiki view callable by virtue of the
@view_config decorator attached to the view_wiki view function, which in turn will be indi-
cated by route_name='view_wiki'.

2. Add a declaration which maps the pattern /{pagename} to the route named view_page. This
is the regular view for a page. Again, in the next step, we will map it to our view_page view
callable by virtue of the @view_config decorator attached to the view_page view function,
whin in turn will be indicated by route_name='view_page'.

3. Add a declaration which maps the pattern /add_page/{pagename} to the route named
add_page. This is the add view for a new page. We will map it to our add_page view callable
by virtue of the @view_config decorator attached to the add_page view function, which in
turn will be indicated by route_name='add_page'.

4. Add a declaration which maps the pattern /{pagename}/edit_page to the route named
edit_page. This is the edit view for a page. We will map it to our edit_page view callable by
virtue of the @view_config decorator attached to the edit_page view function, which in turn
will be indicated by route_name='edit_page'.

As a result of our edits, the tutorial/routes.py file should look like the following:

1 def includeme(config):
2 config.add_static_view('static', 'static', cache_max_age=3600)
3 config.add_route('view_wiki', '/')
4 config.add_route('view_page', '/{pagename}')
5 config.add_route('add_page', '/add_page/{pagename}')
6 config.add_route('edit_page', '/{pagename}/edit_page')

The highlighted lines are the ones that need to be added or edited.

0.2. Tutorials 213


The Pyramid Web Framework, Version 2.0.2

The order of the routes is important! If you placed /{pagename}/edit_page before /


add_page/{pagename}, then we would never be able to add pages. This is because the first route
would always match a request to /add_page/edit_page whereas we want /add_page/.. to
have priority. This isn’t a huge problem in this particular app because wiki pages are always camel
case, but it’s important to be aware of this behavior in your own apps.

CSRF protection

When handling HTML forms that mutate data in our database we need to verify that the form submission
is legitimate and not from a URL embedded in a third-party website. This is done by adding a unique token
to each form that a third-party could not easily guess. Read more about CSRF at Preventing Cross-Site
Request Forgery Attacks. For this tutorial, we’ll store the active CSRF token in a cookie.

Let’s add a new tutorial/security.py file:

1 from pyramid.csrf import CookieCSRFStoragePolicy


2

4 def includeme(config):
5 config.set_csrf_storage_policy(CookieCSRFStoragePolicy())
6 config.set_default_csrf_options(require_csrf=True)

Since we’ve added a new tutorial/security.py module, we need to include it. Open the file
tutorial/__init__.py and edit the following lines:

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 """ This function returns a Pyramid WSGI application.
6 """
7 with Configurator(settings=settings) as config:
8 config.include('pyramid_jinja2')
9 config.include('.security')
10 config.include('.routes')
11 config.include('.models')
12 config.scan()
13 return config.make_wsgi_app()

On forms that mutate data, we’ll be sure to add the CSRF token to the form, using pyramid.csrf.
get_csrf_token().

214 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Adding view functions in views/default.py

It’s time for a major change. Open tutorial/views/default.py and replace it with the following:

1 from docutils.core import publish_parts


2 from html import escape
3 from pyramid.httpexceptions import (
4 HTTPNotFound,
5 HTTPSeeOther,
6 )
7 from pyramid.view import view_config
8 import re
9

10 from .. import models


11

12

13 # regular expression used to find WikiWords


14 wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
15

16 @view_config(route_name='view_wiki')
17 def view_wiki(request):
18 next_url = request.route_url('view_page', pagename='FrontPage')
19 return HTTPSeeOther(location=next_url)
20

21 @view_config(route_name='view_page', renderer='tutorial:templates/view.
,→jinja2')

22 def view_page(request):
23 pagename = request.matchdict['pagename']
24 page = request.dbsession.query(models.Page).filter_by(name=pagename).
,→first()

25 if page is None:
26 raise HTTPNotFound('No such page')
27

28 def add_link(match):
29 word = match.group(1)
30 exists = request.dbsession.query(models.Page).filter_by(name=word).
,→all()

31 if exists:
32 view_url = request.route_url('view_page', pagename=word)
33 return '<a href="%s">%s</a>' % (view_url, escape(word))
34 else:
35 add_url = request.route_url('add_page', pagename=word)
36 return '<a href="%s">%s</a>' % (add_url, escape(word))
37

38 content = publish_parts(page.data, writer_name='html')['html_body']


(continues on next page)

0.2. Tutorials 215


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


39 content = wikiwords.sub(add_link, content)
40 edit_url = request.route_url('edit_page', pagename=page.name)
41 return dict(page=page, content=content, edit_url=edit_url)
42

43 @view_config(route_name='edit_page', renderer='tutorial:templates/edit.
,→jinja2')

44 def edit_page(request):
45 pagename = request.matchdict['pagename']
46 page = request.dbsession.query(models.Page).filter_by(name=pagename).
,→one()

47 if request.method == 'POST':
48 page.data = request.params['body']
49 next_url = request.route_url('view_page', pagename=page.name)
50 return HTTPSeeOther(location=next_url)
51 return dict(
52 pagename=page.name,
53 pagedata=page.data,
54 save_url=request.route_url('edit_page', pagename=page.name),
55 )
56

57 @view_config(route_name='add_page', renderer='tutorial:templates/edit.
,→jinja2')

58 def add_page(request):
59 pagename = request.matchdict['pagename']
60 if request.dbsession.query(models.Page).filter_by(name=pagename).
,→count() > 0:

61 next_url = request.route_url('edit_page', pagename=pagename)


62 return HTTPSeeOther(location=next_url)
63 if request.method == 'POST':
64 body = request.params['body']
65 page = models.Page(name=pagename, data=body)
66 page.creator = (
67 request.dbsession.query(models.User).filter_by(name='editor').
,→one())

68 request.dbsession.add(page)
69 next_url = request.route_url('view_page', pagename=pagename)
70 return HTTPSeeOther(location=next_url)
71 save_url = request.route_url('add_page', pagename=pagename)
72 return dict(pagename=pagename, pagedata='', save_url=save_url)

We added some imports, and created a regular expression to find ”WikiWords”.

We got rid of the my_view view function and its decorator that was added when originally rendered
after we selected the sqlalchemy backend option in the cookiecutter. It was only an example and isn’t
relevant to our application. We also deleted the db_err_msg string.

216 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Then we added four view callable functions to our tutorial/views/default.py module, as men-
tioned in the previous step:

• view_wiki() - Displays the wiki itself. It will answer on the root URL.

• view_page() - Displays an individual page.

• edit_page() - Allows the user to edit a page.

• add_page() - Allows the user to add a page.

We’ll describe each one briefly in the following sections.

There is nothing special about the filename default.py except that it is a Python module. A
project may have many view callables throughout its codebase in arbitrarily named modules. Modules
implementing view callables often have view in their name (or may live in a Python subpackage of your
application package named views, as in our case), but this is only by convention, not a requirement.

The view_wiki view function

Following is the code for the view_wiki view function and its decorator:

16 @view_config(route_name='view_wiki')
17 def view_wiki(request):
18 next_url = request.route_url('view_page', pagename='FrontPage')
19 return HTTPSeeOther(location=next_url)

view_wiki() is the default view that gets called when a request is made to the root URL of our wiki.
It always redirects to a URL which represents the path to our ”FrontPage”.

The view_wiki view callable always redirects to the URL of a Page resource named ”FrontPage”. To
do so, it returns an instance of the pyramid.httpexceptions.HTTPSeeOther class (instances of
which implement the pyramid.interfaces.IResponse interface, like pyramid.response.
Response). It uses the pyramid.request.Request.route_url() API to construct a URL to
the FrontPage page (i.e., http://localhost:6543/FrontPage), and uses it as the ”location”
of the HTTPSeeOther response, forming an HTTP redirect.

0.2. Tutorials 217


The Pyramid Web Framework, Version 2.0.2

The view_page view function

Here is the code for the view_page view function and its decorator:

21 @view_config(route_name='view_page', renderer='tutorial:templates/view.
,→jinja2')

22 def view_page(request):
23 pagename = request.matchdict['pagename']
24 page = request.dbsession.query(models.Page).filter_by(name=pagename).
,→first()

25 if page is None:
26 raise HTTPNotFound('No such page')
27

28 def add_link(match):
29 word = match.group(1)
30 exists = request.dbsession.query(models.Page).filter_by(name=word).
,→all()

31 if exists:
32 view_url = request.route_url('view_page', pagename=word)
33 return '<a href="%s">%s</a>' % (view_url, escape(word))
34 else:
35 add_url = request.route_url('add_page', pagename=word)
36 return '<a href="%s">%s</a>' % (add_url, escape(word))
37

38 content = publish_parts(page.data, writer_name='html')['html_body']


39 content = wikiwords.sub(add_link, content)
40 edit_url = request.route_url('edit_page', pagename=page.name)
41 return dict(page=page, content=content, edit_url=edit_url)

view_page() is used to display a single page of our wiki. It renders the reStructuredText body of a page
(stored as the data attribute of a Page model object) as HTML. Then it substitutes an HTML anchor for
each WikiWord reference in the rendered HTML using a compiled regular expression.

The curried function named add_link is used as the first argument to wikiwords.sub, indicating
that it should be called to provide a value for each WikiWord match found in the content. If the wiki already
contains a page with the matched WikiWord name, add_link() generates a view link to be used as the
substitution value and returns it. If the wiki does not already contain a page with the matched WikiWord
name, add_link() generates an ”add” link as the substitution value and returns it.

As a result, the content variable is now a fully formed bit of HTML containing various view and add
links for WikiWords based on the content of our current page object.

We then generate an edit URL, because it’s easier to do here than in the template, and we return a dictionary
with a number of arguments. The fact that view_page() returns a dictionary (as opposed to a response

218 CONTENTS
The Pyramid Web Framework, Version 2.0.2

object) is a cue to Pyramid that it should try to use a renderer associated with the view configuration to
render a response. In our case, the renderer used will be the view.jinja2 template, as indicated in the
@view_config decorator that is applied to view_page().

If the page does not exist, then we need to handle that by raising a pyramid.httpexceptions.
HTTPNotFound to trigger our 404 handling, defined in tutorial/views/notfound.py.

Using raise versus return with the HTTP exceptions is an important distinction that can com-
monly mess people up. In tutorial/views/notfound.py there is an exception view registered for
handling the HTTPNotFound exception. Exception views are only triggered for raised exceptions. If the
HTTPNotFound is returned, then it has an internal ”stock” template that it will use to render itself as a
response. If you aren’t seeing your exception view being executed, this is most likely the problem! See
Using Special Exceptions in View Callables for more information about exception views.

The edit_page view function

Here is the code for the edit_page view function and its decorator:

43 @view_config(route_name='edit_page', renderer='tutorial:templates/edit.
,→jinja2')

44 def edit_page(request):
45 pagename = request.matchdict['pagename']
46 page = request.dbsession.query(models.Page).filter_by(name=pagename).
,→one()

47 if request.method == 'POST':
48 page.data = request.params['body']
49 next_url = request.route_url('view_page', pagename=page.name)
50 return HTTPSeeOther(location=next_url)
51 return dict(
52 pagename=page.name,
53 pagedata=page.data,
54 save_url=request.route_url('edit_page', pagename=page.name),
55 )

edit_page() is invoked when a user clicks the ”Edit this Page” button on the view form. It renders an
edit form, but it also acts as the handler for the form which it renders. The matchdict attribute of the
request passed to the edit_page view will have a 'pagename' key matching the name of the page
that the user wants to edit.

0.2. Tutorials 219


The Pyramid Web Framework, Version 2.0.2

If the view execution is a result of a form submission (i.e., request.method == 'POST'), the view
grabs the body element of the request parameters and sets it as the data attribute of the page object. It
then redirects to the view_page view of the wiki page.

If the view execution is not a result of a form submission (i.e., the expression request.method !=
'POST'), the view simply renders the edit form, passing the page object and a save_url which will be
used as the action of the generated form.

Since our request.dbsession defined in the previous chapter is registered with the pyra-
mid_tm transaction manager, any changes we make to objects managed by the session will be committed
automatically. In the event that there was an error (even later, in our template code), the changes would be
aborted. This means the view itself does not need to concern itself with commit/rollback logic.

The add_page view function

Here is the code for the add_page view function and its decorator:

57 @view_config(route_name='add_page', renderer='tutorial:templates/edit.
,→jinja2')

58 def add_page(request):
59 pagename = request.matchdict['pagename']
60 if request.dbsession.query(models.Page).filter_by(name=pagename).
,→count() > 0:

61 next_url = request.route_url('edit_page', pagename=pagename)


62 return HTTPSeeOther(location=next_url)
63 if request.method == 'POST':
64 body = request.params['body']
65 page = models.Page(name=pagename, data=body)
66 page.creator = (
67 request.dbsession.query(models.User).filter_by(name='editor').
,→one())

68 request.dbsession.add(page)
69 next_url = request.route_url('view_page', pagename=pagename)
70 return HTTPSeeOther(location=next_url)
71 save_url = request.route_url('add_page', pagename=pagename)
72 return dict(pagename=pagename, pagedata='', save_url=save_url)

add_page() is invoked when a user clicks on a WikiWord which isn’t yet represented as a page in the sys-
tem. The add_link function within the view_page view generates URLs to this view. add_page()
also acts as a handler for the form that is generated when we want to add a page object. The matchdict

220 CONTENTS
The Pyramid Web Framework, Version 2.0.2

attribute of the request passed to the add_page() view will have the values we need to construct URLs
and find model objects.

The matchdict will have a 'pagename' key that matches the name of the page we’d like to add. If
our add view is invoked via, for example, http://localhost:6543/add_page/SomeName, the
value for 'pagename' in the matchdict will be 'SomeName'.

Next a check is performed to determine whether the Page already exists in the database. If it already
exists, then the client is redirected to the edit_page view, else we continue to the next check.

If the view execution is a result of a form submission (i.e., the expression request.method ==
'POST'), we grab the page body from the form data, create a Page object with this page body and the name
taken from matchdict['pagename'], and save it into the database using request.dbession.
add. Since we have not yet covered authentication, we don’t have a logged-in user to add as the page’s
creator. Until we get to that point in the tutorial, we’ll just assume that all pages are created by the
editor user. Thus we query for that object, and set it on page.creator. Finally, we redirect the
client back to the view_page view for the newly created page.

If the view execution is not a result of a form submission (i.e., the expression request.method !=
'POST' is False), the view callable renders a template. To do so, it generates a save_url which the
template uses as the form post URL during rendering. We’re lazy here, so we’re going to use the same
template (templates/edit.jinja2) for the add view as well as the page edit view. To do so we
create a dummy Page object in order to satisfy the edit form’s desire to have some page object exposed as
page. Pyramid will render the template associated with this view to a response.

Adding templates

The view_page, add_page and edit_page views that we’ve added reference a template. Each
template is a Jinja2 template. These templates will live in the templates directory of our tutorial
package. Jinja2 templates must have a .jinja2 extension to be recognized as such.

The layout.jinja2 template

Update tutorial/templates/layout.jinja2 with the following content, as indicated by the


emphasized lines:

0.2. Tutorials 221


The Pyramid Web Framework, Version 2.0.2

1 <!DOCTYPE html>
2 <html lang="{{request.locale_name}}">
3 <head>
4 <meta charset="utf-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta name="description" content="pyramid web application">
8 <meta name="author" content="Pylons Project">
9 <link rel="shortcut icon" href="{{request.static_url('tutorial:static/
,→pyramid-16x16.png')}}">

10

11 <title>{% block subtitle %}{% endblock %}Pyramid tutorial wiki (based␣


,→ on TurboGears 20-Minute Wiki)</title>
12

13 <!-- Bootstrap core CSS -->


14 <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/
,→css/bootstrap.min.css" integrity="sha384-

,→BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"␣

,→crossorigin="anonymous">

15

16 <!-- Custom styles for this scaffold -->


17 <link href="{{request.static_url('tutorial:static/theme.css')}}" rel=
,→"stylesheet">

18

19 <!-- HTML5 shiv and Respond.js IE8 support of HTML5 elements and media␣
,→queries -->
20 <!--[if lt IE 9]>
21 <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"␣
,→integrity="sha384-

,→0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY"␣

,→crossorigin="anonymous"></script>

22 <script src="//oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"␣
,→integrity="sha384-

,→ZoaMbDF+4LeFxg6WdScQ9nnR1QC2MIRxA1O9KWEXQwns1G8UNyIEZIQidzb0T1fo"␣

,→crossorigin="anonymous"></script>

23 <![endif]-->
24 </head>
25

26 <body>
27

28 <div class="starter-template">
29 <div class="container">
30 <div class="row">
31 <div class="col-md-2">
32 <img class="logo img-responsive" src="{{request.static_url(
,→'tutorial:static/pyramid.png') }}" alt="pyramid web framework">
(continues on next page)

222 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


33 </div>
34 <div class="col-md-10">
35 <div class="content">
36 {% block content %}{% endblock %}
37 </div>
38 </div>
39 </div>
40 <div class="row">
41 <div class="links">
42 <ul>
43 <li><i class="glyphicon glyphicon-cog icon-muted"></i><a␣
,→href="https://github.com/Pylons/pyramid">Github Project</a></li>

44 <li><i class="glyphicon glyphicon-globe icon-muted"></i><a␣


,→href="https://web.libera.chat/#pyramid">IRC Channel</a></li>

45 <li><i class="glyphicon glyphicon-home icon-muted"></i><a␣


,→href="https://pylonsproject.org">Pylons Project</a></li>

46 </ul>
47 </div>
48 </div>
49 <div class="row">
50 <div class="copyright">
51 Copyright &copy; Pylons Project
52 </div>
53 </div>
54 </div>
55 </div>
56

57

58 <!-- Bootstrap core JavaScript


59 ================================================== -->
60 <!-- Placed at the end of the document so the pages load faster -->
61 <script src="//code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-
,→ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></

,→script>

62 <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.
,→min.js" integrity="sha384-

,→Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"␣

,→crossorigin="anonymous"></script>

63 </body>
64 </html>

Since we’re using a templating engine, we can factor common boilerplate out of our page templates into
reusable components. One method for doing this is template inheritance via blocks.
• We have defined two placeholders in the layout template where a child template can override the
content. These blocks are named subtitle (line 11) and content (line 36).

0.2. Tutorials 223


The Pyramid Web Framework, Version 2.0.2

• Please refer to the Jinja2 documentation for more information about template inheritance.

The view.jinja2 template

Create tutorial/templates/view.jinja2 and add the following content:

1 {% extends 'layout.jinja2' %}
2

3 {% block subtitle %}{{page.name}} - {% endblock subtitle %}


4

5 {% block content %}
6 <p>{{ content|safe }}</p>
7 <p>
8 <a href="{{ edit_url }}">
9 Edit this page
10 </a>
11 </p>
12 <p>
13 Viewing <strong>{{page.name}}</strong>, created by <strong>{{page.
,→creator.name}}</strong>.

14 </p>
15 <p>You can return to the
16 <a href="{{request.route_url('view_page', pagename='FrontPage')}}">
,→FrontPage</a>.

17 </p>
18 {% endblock content %}

This template is used by view_page() for displaying a single wiki page.

• We begin by extending the layout.jinja2 template defined above, which provides the skeleton
of the page (line 1).

• We override the subtitle block from the base layout, inserting the page name into the page’s title
(line 3).

• We override the content block from the base layout to insert our markup into the body (lines
5-18).

• We use a variable that is replaced with the content value provided by the view (line 6). content
contains HTML, so the |safe filter is used to prevent escaping it (e.g., changing ”>” to ”&gt;”).

• We create a link that points at the ”edit” URL, which when clicked invokes the edit_page view
for the requested page (lines 8-10).

224 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The edit.jinja2 template

Create tutorial/templates/edit.jinja2 and add the following content:

1 {% extends 'layout.jinja2' %}
2

3 {% block subtitle %}Edit {{pagename}} - {% endblock subtitle %}


4

5 {% block content %}
6 <p>
7 Editing <strong>{{pagename}}</strong>
8 </p>
9 <p>You can return to the
10 <a href="{{request.route_url('view_page', pagename='FrontPage')}}">
,→FrontPage</a>.

11 </p>
12 <form action="{{ save_url }}" method="post">
13 <input type="hidden" name="csrf_token" value="{{ get_csrf_token() }}">
14 <div class="form-group">
15 <textarea class="form-control" name="body" rows="10" cols="60">{{␣
,→pagedata }}</textarea>

16 </div>
17 <div class="form-group">
18 <button type="submit" class="btn btn-default">Save</button>
19 </div>
20 </form>
21 {% endblock content %}

This template serves two use cases. It is used by add_page() and edit_page() for adding and
editing a wiki page. It displays a page containing a form and which provides the following:

• Again, we extend the layout.jinja2 template, which provides the skeleton of the page (line 1).

• Override the subtitle block to affect the <title> tag in the head of the page (line 3).

• Add the CSRF token to the form (line 13). Without this line, attempts to edit the page would result
in a 400 Bad Request error.

• A 10-row by 60-column textarea field named body that is filled with any existing page data
when it is rendered (line 15).

• A submit button (line 18).

• The form POSTs back to the save_url argument supplied by the view (line 12). The view will
use the body value.

0.2. Tutorials 225


The Pyramid Web Framework, Version 2.0.2

The 404.jinja2 template

Replace tutorial/templates/404.jinja2 with the following content:

1 {% extends "layout.jinja2" %}
2

3 {% block content %}
4 <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">
,→Starter project</span></h1>

5 <p class="lead"><span class="font-semi-bold">404</span> Page Not Found</p>


6 {% endblock content %}

This template is linked from the notfound_view defined in tutorial/views/notfound.py as


shown here:

1 from pyramid.view import notfound_view_config


2

4 @notfound_view_config(renderer='tutorial:templates/404.jinja2')
5 def notfound_view(request):
6 request.response.status = 404
7 return {}

There are several important things to note about this configuration:


• The notfound_view in the above snippet is called an exception view. For more information see
Using Special Exceptions in View Callables.
• The notfound_view sets the response status to 404. It’s possible to affect the response object
used by the renderer via Varying Attributes of Rendered Responses.
• The notfound_view is registered as an exception view and will be invoked only if pyramid.
httpexceptions.HTTPNotFound is raised as an exception. This means it will not be invoked
for any responses returned from a view normally. For example, on line 27 of tutorial/views/
default.py the exception is raised which will trigger the view.
Finally, we may delete the tutorial/templates/mytemplate.jinja2 template that was pro-
vided by selecting the backend option of sqlalchemy, as we have created our own templates for the
wiki.

Our templates use a request object that none of our tutorial views return in their dictionary.
request is one of several names that are available ”by default” in a template when a template renderer
is used. See System Values Used During Rendering for information about other names that are available
by default when a template is used as a renderer.

226 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Viewing the application in a browser

We can finally examine our application in a browser (See Start the application). Launch a browser and
visit each of the following URLs, checking that the result is as expected:
• http://localhost:6543/ invokes the view_wiki view. This always redirects to the view_page
view of the FrontPage page object.
• http://localhost:6543/FrontPage invokes the view_page view of the FrontPage page object.
• http://localhost:6543/FrontPage/edit_page invokes the edit_page view for the FrontPage page
object.
• http://localhost:6543/add_page/SomePageName invokes the add_page view for a page. If the
page already exists, then it redirects the user to the edit_page view for the page object.
• http://localhost:6543/SomePageName/edit_page invokes the edit_page view for an existing
page, or generates an error if the page does not exist.
• To generate an error, visit http://localhost:6543/foobars/edit_page which will generate a NoRe-
sultFound: No row was found for one() error. You’ll see an interactive traceback
facility provided by pyramid_debugtoolbar.

Adding authentication

Pyramid provides facilities for authentication and authorization. In this section we’ll focus solely on the
authentication APIs to add login and logout functionality to our wiki.
We will implement authentication with the following steps:
• Add a security policy (security.py).
• Add routes for /login and /logout (routes.py).
• Add login and logout views (views/auth.py).
• Add a login template (login.jinja2).
• Add ”Login” and ”Logout” links to every page based on the user’s authenticated state (layout.
jinja2).
• Make the existing views verify user state (views/default.py).
• Redirect to /login when a user is not logged in and is denied access to any of the views that require
permission (views/auth.py).
• Show a custom ”403 Forbidden” page if a logged in user is denied access to any views that require
permission (views/auth.py).

0.2. Tutorials 227


The Pyramid Web Framework, Version 2.0.2

Authenticating requests

The core of Pyramid authentication is a security policy which is used to identify authentication information
from a request, as well as handling the low-level login and logout operations required to track users
across requests (via cookies, headers, or whatever else you can imagine).

Add the security policy

Update tutorial/security.py with the following content:

1 from pyramid.authentication import AuthTktCookieHelper


2 from pyramid.csrf import CookieCSRFStoragePolicy
3 from pyramid.request import RequestLocalCache
4

5 from . import models


6

8 class MySecurityPolicy:
9 def __init__(self, secret):
10 self.authtkt = AuthTktCookieHelper(secret)
11 self.identity_cache = RequestLocalCache(self.load_identity)
12

13 def load_identity(self, request):


14 identity = self.authtkt.identify(request)
15 if identity is None:
16 return None
17

18 userid = identity['userid']
19 user = request.dbsession.query(models.User).get(userid)
20 return user
21

22 def identity(self, request):


23 return self.identity_cache.get_or_create(request)
24

25 def authenticated_userid(self, request):


26 user = self.identity(request)
27 if user is not None:
28 return user.id
29

30 def remember(self, request, userid, **kw):


31 return self.authtkt.remember(request, userid, **kw)
32

(continues on next page)

228 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


33 def forget(self, request, **kw):
34 return self.authtkt.forget(request, **kw)
35

36 def includeme(config):
37 settings = config.get_settings()
38

39 config.set_csrf_storage_policy(CookieCSRFStoragePolicy())
40 config.set_default_csrf_options(require_csrf=True)
41

42 config.set_security_policy(MySecurityPolicy(settings['auth.secret']))

Here we’ve defined a new security policy named MySecurityPolicy, which is implementing most
of the pyramid.interfaces.ISecurityPolicy interface by tracking an identity using a signed
cookie implemented by pyramid.authentication.AuthTktCookieHelper (lines 8-34). The
security policy outputs the authenticated tutorial.models.User object for the logged-in user as the
identity, which is available as request.identity.

Our new security policy defines how our application will remember, forget, and identify users. It also
handles authorization, which we’ll cover in the next chapter (if you’re wondering why we didn’t implement
the permits method yet).

Identifying the current user is done in a few steps:

1. Pyramid invokes a method on the policy requesting identity, userid, or permission to perform an
operation.

2. The policy starts by calling pyramid.request.RequestLocalCache.


get_or_create() to load the identity.

3. The MySecurityPolicy.load_identity method asks the cookie helper to pull the identity
from the request. This value is None if the cookie is missing or the content cannot be verified.

4. The policy then translates the identity into a tutorial.models.User object by looking for a
record in the database. This is a good spot to confirm that the user is actually allowed to access our
application. For example, maybe they were marked deleted or banned and we should return None
instead of the user object.

5. The result is stored in the identity_cache which ensures that subsequent invocations return the
same identity object for the request.

Finally, pyramid.request.Request.identity contains either None or a tutorial.


models.User instance.

Note the usage of the identity_cache is optional, but it has several advantages in most scenarios:

0.2. Tutorials 229


The Pyramid Web Framework, Version 2.0.2

• It improves performance as the identity is necessary for many operations during the lifetime of a
request.

• It provides consistency across method invocations to ensure the identity does not change while pro-
cessing the request.

It is up to individual security policies and applications to determine the best approach with respect to
caching. Applications with long-running requests may want to avoid caching the identity, or tracking some
extra metadata to re-verify it periodically against the authentication source.

Add new settings

Our authentication policy is expecting a new setting, auth.secret. Open the file development.ini
and add the highlighted line below:

19 retry.attempts = 3
20

21 auth.secret = seekrit

Finally, best practices tell us to use a different secret in each environment, so open production.ini
and add a different secret:

17 retry.attempts = 3
18

19 auth.secret = real-seekrit

And testing.ini:

17 retry.attempts = 3
18

19 auth.secret = test-seekrit

Add permission checks

Pyramid has full support for declarative authorization, which we’ll cover in the next chapter. However,
many people looking to get their feet wet are just interested in authentication with some basic form of
home-grown authorization. We’ll show below how to accomplish the simple security goals of our wiki,
now that we can track the logged-in state of users.

Remember our goals:

230 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Allow only editor and basic logged-in users to create new pages.

• Only allow editor users and the page creator (possibly a basic user) to edit pages.

Open the file tutorial/views/default.py and fix the following import:

3 from pyramid.httpexceptions import (


4 HTTPForbidden,
5 HTTPNotFound,
6 HTTPSeeOther,
7 )

Insert the highlighted line.

In the same file, now edit the edit_page view function:

44 @view_config(route_name='edit_page', renderer='tutorial:templates/edit.
,→jinja2')

45 def edit_page(request):
46 pagename = request.matchdict['pagename']
47 page = request.dbsession.query(models.Page).filter_by(name=pagename).
,→one()

48 user = request.identity
49 if user is None or (user.role != 'editor' and page.creator != user):
50 raise HTTPForbidden
51 if request.method == 'POST':
52 page.data = request.params['body']
53 next_url = request.route_url('view_page', pagename=page.name)
54 return HTTPSeeOther(location=next_url)
55 return dict(
56 pagename=page.name,
57 pagedata=page.data,
58 save_url=request.route_url('edit_page', pagename=page.name),
59 )

Only the highlighted lines need to be changed.

If the user either is not logged in or the user is not the page’s creator and not an editor, then we raise
HTTPForbidden.

In the same file, now edit the add_page view function:

0.2. Tutorials 231


The Pyramid Web Framework, Version 2.0.2

61 @view_config(route_name='add_page', renderer='tutorial:templates/edit.
,→jinja2')

62 def add_page(request):
63 user = request.identity
64 if user is None or user.role not in ('editor', 'basic'):
65 raise HTTPForbidden
66 pagename = request.matchdict['pagename']
67 if request.dbsession.query(models.Page).filter_by(name=pagename).
,→count() > 0:

68 next_url = request.route_url('edit_page', pagename=pagename)


69 return HTTPSeeOther(location=next_url)
70 if request.method == 'POST':
71 body = request.params['body']
72 page = models.Page(name=pagename, data=body)
73 page.creator = request.identity
74 request.dbsession.add(page)
75 next_url = request.route_url('view_page', pagename=pagename)
76 return HTTPSeeOther(location=next_url)
77 save_url = request.route_url('add_page', pagename=pagename)
78 return dict(pagename=pagename, pagedata='', save_url=save_url)

Only the highlighted lines need to be changed.

If the user either is not logged in or is not in the basic or editor roles, then we raise HTTPForbidden,
which will trigger our forbidden view to compute a response. However, we will hook this later to redirect
to the login page. Also, now that we have request.identity, we no longer have to hard-code the
creator as the editor user, so we can finally drop that hack.

These simple checks should protect our views.

Login, logout

Now that we’ve got the ability to detect logged-in users, we need to add the /login and /logout views
so that they can actually login and logout!

Add routes for /login and /logout

Go back to tutorial/routes.py and add these two routes as highlighted:

232 CONTENTS
The Pyramid Web Framework, Version 2.0.2

3 config.add_route('view_wiki', '/')
4 config.add_route('login', '/login')
5 config.add_route('logout', '/logout')
6 config.add_route('view_page', '/{pagename}')

The preceding lines must be added before the following view_page route definition:

6 config.add_route('view_page', '/{pagename}')

This is because view_page’s route definition uses a catch-all ”replacement marker” /{pagename}
(see Route Pattern Syntax), which will catch any route that was not already caught by any route registered
before it. Hence, for login and logout views to have the opportunity of being matched (or ”caught”),
they must be above /{pagename}.

Add login, logout, and forbidden views

Create a new file tutorial/views/auth.py, and add the following code to it:

1 from pyramid.csrf import new_csrf_token


2 from pyramid.httpexceptions import HTTPSeeOther
3 from pyramid.security import (
4 remember,
5 forget,
6 )
7 from pyramid.view import (
8 forbidden_view_config,
9 view_config,
10 )
11

12 from .. import models


13

14

15 @view_config(route_name='login', renderer='tutorial:templates/login.jinja2
,→')

16 def login(request):
17 next_url = request.params.get('next', request.referrer)
18 if not next_url:
19 next_url = request.route_url('view_wiki')
(continues on next page)

0.2. Tutorials 233


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


20 message = ''
21 login = ''
22 if request.method == 'POST':
23 login = request.params['login']
24 password = request.params['password']
25 user = (
26 request.dbsession.query(models.User)
27 .filter_by(name=login)
28 .first()
29 )
30 if user is not None and user.check_password(password):
31 new_csrf_token(request)
32 headers = remember(request, user.id)
33 return HTTPSeeOther(location=next_url, headers=headers)
34 message = 'Failed login'
35 request.response.status = 400
36

37 return dict(
38 message=message,
39 url=request.route_url('login'),
40 next_url=next_url,
41 login=login,
42 )
43

44 @view_config(route_name='logout')
45 def logout(request):
46 next_url = request.route_url('view_wiki')
47 if request.method == 'POST':
48 new_csrf_token(request)
49 headers = forget(request)
50 return HTTPSeeOther(location=next_url, headers=headers)
51

52 return HTTPSeeOther(location=next_url)
53

54 @forbidden_view_config(renderer='tutorial:templates/403.jinja2')
55 def forbidden_view(exc, request):
56 if not request.is_authenticated:
57 next_url = request.route_url('login', _query={'next': request.url})
58 return HTTPSeeOther(location=next_url)
59

60 request.response.status = 403
61 return {}

This code adds three new views to the application:

234 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The login view renders a login form and processes the post from the login form, checking creden-
tials against our users table in the database.

The check is done by first finding a User record in the database, then using our user.
check_password method to compare the hashed passwords.

At a privilege boundary we are sure to reset the CSRF token using pyramid.csrf.
new_csrf_token(). If we were using sessions we would want to invalidate that as well.

If the credentials are valid, then we use our authentication policy to store the user’s id in the response
using pyramid.security.remember().

Finally, the user is redirected back to either the page which they were trying to access (next) or the
front page as a fallback. This parameter is used by our forbidden view, as explained below, to finish
the login workflow.

• The logout view handles requests to /logout by clearing the credentials using pyramid.
security.forget(), then redirecting them to the front page.

At a privilege boundary we are sure to reset the CSRF token using pyramid.csrf.
new_csrf_token(). If we were using sessions we would want to invalidate that as well.

• The forbidden_view is registered using the pyramid.view.forbidden_view_config


decorator. This is a special exception view, which is invoked when a pyramid.
httpexceptions.HTTPForbidden exception is raised.

By default, the view will return a ”403 Forbidden” response and display our 403.jinja2 template
(added below).

However, if the user is not logged in, this view will handle a forbidden error by redirecting the user
to /login. As a convenience, it also sets the next= query string to the current URL (the one that
is forbidding access). This way, if the user successfully logs in, they will be sent back to the page
which they had been trying to access.

Add the login.jinja2 template

Create tutorial/templates/login.jinja2 with the following content:

0.2. Tutorials 235


The Pyramid Web Framework, Version 2.0.2

{% extends 'layout.jinja2' %}

{% block title %}Login - {% endblock title %}

{% block content %}
<p>
<strong>
Login
</strong><br>
{{ message }}
</p>
<form action="{{ url }}" method="post">
<input type="hidden" name="csrf_token" value="{{ get_csrf_token() }}">
<input type="hidden" name="next" value="{{ next_url }}">
<div class="form-group">
<label for="login">Username</label>
<input type="text" name="login" value="{{ login }}">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" name="password">
</div>
<div class="form-group">
<button type="submit" class="btn btn-default">Log In</button>
</div>
</form>
{% endblock content %}

The above template is referenced in the login view that we just added in tutorial/views/auth.py.

Add ”Login” and ”Logout” links

Open tutorial/templates/layout.jinja2 and add the following code as indicated by the high-
lighted lines.

35 <div class="content">
36 {% if not request.is_authenticated %}
37 <p class="pull-right">
38 <a href="{{ request.route_url('login') }}">Login</a>
39 </p>
40 {% else %}
41 <form class="pull-right" action="{{ request.route_url('logout
(continues on next page)

236 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


,→') }}" method="post">
42 {{request.identity.name}}
43 <input type="hidden" name="csrf_token" value="{{ get_csrf_
,→token() }}">

44 <button class="btn btn-link" type="submit">Logout</button>


45 </form>
46 {% endif %}
47 {% block content %}{% endblock %}
48 </div>

The request.identity will be None if the user is not authenticated, or a tutorial.models.


User object if the user is authenticated. This check will make the logout link shown only when the user
is logged in, and conversely the login link is only shown when the user is logged out.

Add the 403.jinja2 template

Create tutorial/templates/403.jinja2 with the following content:

{% extends "layout.jinja2" %}

{% block content %}
<h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">
,→Starter project</span></h1>

<p class="lead"><span class="font-semi-bold">403</span> Forbidden</p>


{% endblock content %}

The above template is referenced in the forbidden view that we just added in tutorial/views/auth.
py.

Viewing the application in a browser

We can finally examine our application in a browser (See Start the application). Launch a browser and
visit each of the following URLs, checking that the result is as expected:

• http://localhost:6543/ invokes the view_wiki view. This always redirects to the view_page
view of the FrontPage page object. It is executable by any user.

0.2. Tutorials 237


The Pyramid Web Framework, Version 2.0.2

• http://localhost:6543/login invokes the login view, and a login form will be displayed. On every
page, there is a ”Login” link in the upper right corner while the user is not authenticated, else it is a
”Logout” link when the user is authenticated.
Supplying the credentials with either the username editor and password editor, or username
basic and password basic, will authenticate the user and grant access for that group.
After logging in (as a result of hitting an edit or add page and submitting valid credentials), we will
see a ”Logout” link in the upper right hand corner. When we click it, we are logged out, redirected
back to the front page, and a ”Login” link is shown in the upper right hand corner.
• http://localhost:6543/FrontPage invokes the view_page view of the FrontPage page object.
• http://localhost:6543/FrontPage/edit_page invokes the edit_page view for the FrontPage page
object. It is executable by only the editor user. If a different user invokes it, then the ”403
Forbidden” page will be displayed. If an anonymous user invokes it, then a login form will be
displayed.
• http://localhost:6543/add_page/SomePageName invokes the add_page view for a page. If the
page already exists, then it redirects the user to the edit_page view for the page object. It is
executable by either the editor or basic user. If an anonymous user invokes it, then a login
form will be displayed.
• http://localhost:6543/SomePageName/edit_page invokes the edit_page view for an existing
page, or generates an error if the page does not exist. It is editable by the basic user if the page
was created by that user in the previous step. If instead the page was created by the editor user,
then the login page should be shown for the basic user.

Adding authorization

In the last chapter we built authentication into our wiki. We also went one step further and used the
request.identity object to perform some explicit authorization checks. This is fine for a lot of
applications, but Pyramid provides some facilities for cleaning this up and decoupling the constraints from
the view function itself.
We will implement access control with the following steps:
• Update the security policy to break down the identity into a list of principals (security.py).
• Utilize the pyramid.authorization.ACLHelper to support a per-context mapping of prin-
cipals to permissions (security.py).
• Add new resource definitions that will be used as the context for the wiki pages (routes.py).
• Add an ACL to each resource (routes.py).
• Replace the inline checks on the views with permission declarations (views/default.py).

238 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Add ACL support

A principal is a level of abstraction on top of the raw identity that describes the user in terms of its capa-
bilities, roles, or other identifiers that are easier to generalize. The permissions are then written against the
principals without focusing on the exact user involved.

Pyramid defines two builtin principals used in every application: pyramid.authorization.


Everyone and pyramid.authorization.Authenticated. On top of these we have already
mentioned the required principals for this application in the original design. The user has two possible
roles: editor or basic. These will be prefixed by the string role: to avoid clashing with any other
types of principals.

Open the file tutorial/security.py and edit it as follows:

1 from pyramid.authentication import AuthTktCookieHelper


2 from pyramid.authorization import (
3 ACLHelper,
4 Authenticated,
5 Everyone,
6 )
7 from pyramid.csrf import CookieCSRFStoragePolicy
8 from pyramid.request import RequestLocalCache
9

10 from . import models


11

12

13 class MySecurityPolicy:
14 def __init__(self, secret):
15 self.authtkt = AuthTktCookieHelper(secret)
16 self.identity_cache = RequestLocalCache(self.load_identity)
17 self.acl = ACLHelper()
18

19 def load_identity(self, request):


20 identity = self.authtkt.identify(request)
21 if identity is None:
22 return None
23

24 userid = identity['userid']
25 user = request.dbsession.query(models.User).get(userid)
26 return user
27

28 def identity(self, request):


29 return self.identity_cache.get_or_create(request)
30

(continues on next page)

0.2. Tutorials 239


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


31 def authenticated_userid(self, request):
32 user = self.identity(request)
33 if user is not None:
34 return user.id
35

36 def remember(self, request, userid, **kw):


37 return self.authtkt.remember(request, userid, **kw)
38

39 def forget(self, request, **kw):


40 return self.authtkt.forget(request, **kw)
41

42 def permits(self, request, context, permission):


43 principals = self.effective_principals(request)
44 return self.acl.permits(context, principals, permission)
45

46 def effective_principals(self, request):


47 principals = [Everyone]
48 user = self.identity(request)
49 if user is not None:
50 principals.append(Authenticated)
51 principals.append('u:' + str(user.id))
52 principals.append('role:' + user.role)
53 return principals
54

55 def includeme(config):
56 settings = config.get_settings()
57

58 config.set_csrf_storage_policy(CookieCSRFStoragePolicy())
59 config.set_default_csrf_options(require_csrf=True)
60

61 config.set_security_policy(MySecurityPolicy(settings['auth.secret']))

Only the highlighted lines need to be added.

Note that the role comes from the User object. We also add the user.id as a principal for when we
want to allow that exact user to edit pages which they have created.

We’re using the pyramid.authorization.ACLHelper, which will suffice for most applications.
It uses the context to define the mapping between a principal and permission for the current request via
the __acl__ method or attribute.

The permits method completes our implementation of the pyramid.interfaces.


ISecurityPolicy interface and enables our application to use pyramid.request.Request.
has_permission and the permission= constraint on views.

240 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Add resources and ACLs

Resources and context are the hidden gems of Pyramid. You’ve made it!

Every URL in a web application represents a resource (the ”R” in Uniform Resource Locator). Often the
resource is something in your data model, but it could also be an abstraction over many models.

Our wiki has two resources:

1. A NewPage. Represents a potential Page that does not exist. Any logged-in user, having either
role of basic or editor, can create pages.

2. A PageResource. Represents a Page that is to be viewed or edited. editor users, as well as


the original creator of the Page, may edit the PageResource. Anyone may view it.

The wiki data model is simple enough that the PageResource is mostly redundant with our
models.Page SQLAlchemy class. It is completely valid to combine these into one class. However,
for this tutorial, they are explicitly separated to make clear the distinction between the parts about which
Pyramid cares versus application-defined objects.

There are many ways to define these resources, and they can even be grouped into collections with a
hierarchy. However, we’re keeping it simple here!

Open the file tutorial/routes.py and edit the following lines:

1 from pyramid.authorization import (


2 Allow,
3 Everyone,
4 )
5 from pyramid.httpexceptions import (
6 HTTPNotFound,
7 HTTPSeeOther,
8 )
9

10 from . import models


11

12

13 def includeme(config):
14 config.add_static_view('static', 'static', cache_max_age=3600)
15 config.add_route('view_wiki', '/')
(continues on next page)

0.2. Tutorials 241


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


16 config.add_route('login', '/login')
17 config.add_route('logout', '/logout')
18 config.add_route('view_page', '/{pagename}', factory=page_factory)
19 config.add_route('add_page', '/add_page/{pagename}',
20 factory=new_page_factory)
21 config.add_route('edit_page', '/{pagename}/edit_page',
22 factory=page_factory)
23

24 def new_page_factory(request):
25 pagename = request.matchdict['pagename']
26 if request.dbsession.query(models.Page).filter_by(name=pagename).
,→count() > 0:

27 next_url = request.route_url('edit_page', pagename=pagename)


28 raise HTTPSeeOther(location=next_url)
29 return NewPage(pagename)
30

31 class NewPage:
32 def __init__(self, pagename):
33 self.pagename = pagename
34

35 def __acl__(self):
36 return [
37 (Allow, 'role:editor', 'create'),
38 (Allow, 'role:basic', 'create'),
39 ]
40

41 def page_factory(request):
42 pagename = request.matchdict['pagename']
43 page = request.dbsession.query(models.Page).filter_by(name=pagename).
,→first()

44 if page is None:
45 raise HTTPNotFound
46 return PageResource(page)
47

48 class PageResource:
49 def __init__(self, page):
50 self.page = page
51

52 def __acl__(self):
53 return [
54 (Allow, Everyone, 'view'),
55 (Allow, 'role:editor', 'edit'),
56 (Allow, 'u:' + str(self.page.creator_id), 'edit'),
57 ]

The highlighted lines need to be edited or added.

242 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The NewPage class has an __acl__ on it that returns a list of mappings from principal to permission.
This defines who can do what with that resource. In our case we want to allow only those users with the
principals of either role:editor or role:basic to have the create permission:

31 class NewPage:
32 def __init__(self, pagename):
33 self.pagename = pagename
34

35 def __acl__(self):
36 return [
37 (Allow, 'role:editor', 'create'),
38 (Allow, 'role:basic', 'create'),
39 ]

The NewPage is loaded as the context of the add_page route by declaring a factory on the route:

19 config.add_route('add_page', '/add_page/{pagename}',
20 factory=new_page_factory)

The PageResource class defines the ACL for a Page. It uses an actual Page object to determine who
can do what to the page.

48 class PageResource:
49 def __init__(self, page):
50 self.page = page
51

52 def __acl__(self):
53 return [
54 (Allow, Everyone, 'view'),
55 (Allow, 'role:editor', 'edit'),
56 (Allow, 'u:' + str(self.page.creator_id), 'edit'),
57 ]

The PageResource is loaded as the context of the view_page and edit_page routes by declaring
a factory on the routes:

18 config.add_route('view_page', '/{pagename}', factory=page_factory)


19 config.add_route('add_page', '/add_page/{pagename}',
20 factory=new_page_factory)
21 config.add_route('edit_page', '/{pagename}/edit_page',
22 factory=page_factory)

0.2. Tutorials 243


The Pyramid Web Framework, Version 2.0.2

Add view permissions

At this point we’ve modified our application to load the PageResource, including the actual Page
model in the page_factory. The PageResource is now the context for all view_page and
edit_page views. Similarly the NewPage will be the context for the add_page view.

Open the file tutorial/views/default.py.

First, you can drop a few imports that are no longer necessary:

3 from pyramid.httpexceptions import HTTPSeeOther


4 from pyramid.view import view_config
5 import re

Edit the view_page view to declare the view permission, and remove the explicit checks within the
view:

18 @view_config(route_name='view_page', renderer='tutorial:templates/view.
,→jinja2',

19 permission='view')
20 def view_page(request):
21 page = request.context.page
22

23 def add_link(match):

The work of loading the page has already been done in the factory, so we can just pull the page object
out of the PageResource, loaded as request.context. Our factory also guarantees we will have
a Page, as it raises the HTTPNotFound exception if no Page exists, again simplifying the view logic.

Edit the edit_page view to declare the edit permission:

38 @view_config(route_name='edit_page', renderer='tutorial:templates/edit.
,→jinja2',

39 permission='edit')
40 def edit_page(request):
41 page = request.context.page
42 if request.method == 'POST':

Edit the add_page view to declare the create permission:

244 CONTENTS
The Pyramid Web Framework, Version 2.0.2

52 @view_config(route_name='add_page', renderer='tutorial:templates/edit.
,→jinja2',

53 permission='create')
54 def add_page(request):
55 pagename = request.context.pagename
56 if request.method == 'POST':

Note the pagename here is pulled off of the context instead of request.matchdict. The factory
has done a lot of work for us to hide the actual route pattern.

The ACLs defined on each resource are used by the security policy to determine if any principal is allowed
to have some permission. If this check fails (for example, the user is not logged in) then an HTTPFor-
bidden exception will be raised automatically. Thus we’re able to drop those exceptions and checks from
the views themselves. Rather we’ve defined them in terms of operations on a resource.

The final tutorial/views/default.py should look like the following:

1 from docutils.core import publish_parts


2 from html import escape
3 from pyramid.httpexceptions import HTTPSeeOther
4 from pyramid.view import view_config
5 import re
6

7 from .. import models


8

10 # regular expression used to find WikiWords


11 wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
12

13 @view_config(route_name='view_wiki')
14 def view_wiki(request):
15 next_url = request.route_url('view_page', pagename='FrontPage')
16 return HTTPSeeOther(location=next_url)
17

18 @view_config(route_name='view_page', renderer='tutorial:templates/view.
,→jinja2',

19 permission='view')
20 def view_page(request):
21 page = request.context.page
22

23 def add_link(match):
24 word = match.group(1)
25 exists = request.dbsession.query(models.Page).filter_by(name=word).
,→all()

(continues on next page)

0.2. Tutorials 245


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


26 if exists:
27 view_url = request.route_url('view_page', pagename=word)
28 return '<a href="%s">%s</a>' % (view_url, escape(word))
29 else:
30 add_url = request.route_url('add_page', pagename=word)
31 return '<a href="%s">%s</a>' % (add_url, escape(word))
32

33 content = publish_parts(page.data, writer_name='html')['html_body']


34 content = wikiwords.sub(add_link, content)
35 edit_url = request.route_url('edit_page', pagename=page.name)
36 return dict(page=page, content=content, edit_url=edit_url)
37

38 @view_config(route_name='edit_page', renderer='tutorial:templates/edit.
,→jinja2',

39 permission='edit')
40 def edit_page(request):
41 page = request.context.page
42 if request.method == 'POST':
43 page.data = request.params['body']
44 next_url = request.route_url('view_page', pagename=page.name)
45 return HTTPSeeOther(location=next_url)
46 return dict(
47 pagename=page.name,
48 pagedata=page.data,
49 save_url=request.route_url('edit_page', pagename=page.name),
50 )
51

52 @view_config(route_name='add_page', renderer='tutorial:templates/edit.
,→jinja2',

53 permission='create')
54 def add_page(request):
55 pagename = request.context.pagename
56 if request.method == 'POST':
57 body = request.params['body']
58 page = models.Page(name=pagename, data=body)
59 page.creator = request.identity
60 request.dbsession.add(page)
61 next_url = request.route_url('view_page', pagename=pagename)
62 return HTTPSeeOther(location=next_url)
63 save_url = request.route_url('add_page', pagename=pagename)
64 return dict(pagename=pagename, pagedata='', save_url=save_url)

246 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Viewing the application in a browser

We can finally examine our application in a browser (See Start the application). Launch a browser and
visit each of the following URLs, checking that the result is as expected:

• http://localhost:6543/ invokes the view_wiki view. This always redirects to the view_page
view of the FrontPage page object. It is executable by any user.

• http://localhost:6543/login invokes the login view, and a login form will be displayed. On every
page, there is a ”Login” link in the upper right corner while the user is not authenticated, else it is a
”Logout” link when the user is authenticated.

Supplying the credentials with either the username editor and password editor, or username
basic and password basic, will authenticate the user and grant access for that group.

After logging in (as a result of hitting an edit or add page and submitting valid credentials), we will
see a ”Logout” link in the upper right hand corner. When we click it, we are logged out, redirected
back to the front page, and a ”Login” link is shown in the upper right hand corner.

• http://localhost:6543/FrontPage invokes the view_page view of the FrontPage page object.

• http://localhost:6543/FrontPage/edit_page invokes the edit_page view for the FrontPage page


object. It is executable by only the editor user. If a different user invokes it, then the ”403
Forbidden” page will be displayed. If an anonymous user invokes it, then a login form will be
displayed.

• http://localhost:6543/add_page/SomePageName invokes the add_page view for a page. If the


page already exists, then it redirects the user to the edit_page view for the page object. It is
executable by either the editor or basic user. If an anonymous user invokes it, then a login
form will be displayed.

• http://localhost:6543/SomePageName/edit_page invokes the edit_page view for an existing


page, or generates an error if the page does not exist. It is editable by the basic user if the page
was created by that user in the previous step. If instead the page was created by the editor user,
then the login page should be shown for the basic user.

Adding Tests

We will now add tests for the models and views as well as a few functional tests in a new tests package.
Tests ensure that an application works, and that it continues to work when changes are made in the future.

0.2. Tutorials 247


The Pyramid Web Framework, Version 2.0.2

Test harness

The project came bootstrapped with some tests and a basic harness. These are located in the tests
package at the top-level of the project. It is a common practice to put tests into a tests package alongside
the application package, especially as projects grow in size and complexity. A useful convention is for
each module in the application to contain a corresponding module in the tests package. The test module
would have the same name with the prefix test_.

The harness consists of the following setup:

• pytest.ini - controls basic pytest config including where to find the tests. We have configured
pytest to search for tests in the application package and in the tests package.

• .coveragerc - controls coverage config. In our setup, it works with the pytest-cov plugin
that we use via the --cov options to the pytest command.

• testing.ini - a mirror of development.ini and production.ini that contains settings


used for executing the test suite. Most importantly, it contains the database connection information
used by tests that require the database.

• tests_require in setup.py - controls the dependencies installed when testing. When the list
is changed, it’s necessary to re-run $VENV/bin/pip install -e ".[testing]" to ensure
the new dependencies are installed.

• tests/conftest.py - the core fixtures available throughout our tests. The fixtures are ex-
plained in more detail below.

Session-scoped test fixtures

• app_settings - the settings dict parsed from the testing.ini file that would normally be
passed by pserve into your app’s main function.

• dbengine - initializes the database. It’s important to start each run of the test suite from a known
state, and this fixture is responsible for preparing the database appropriately. This includes deleting
any existing tables, running migrations, and potentially even loading some fixture data into the tables
for use within the tests.

• app - the Pyramid WSGI application, implementing the pyramid.interfaces.IRouter in-


terface. Most commonly this would be used for functional tests.

248 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Per-test fixtures

• tm - a transaction.TransactionManager object controlling a transaction lifecycle. Gen-


erally other fixtures would join to the tm fixture to control their lifecycle and ensure they are aborted
at the end of the test.

• dbsession - a sqlalchemy.orm.session.Session object connected to the database.


The session is scoped to the tm fixture. Any changes made will be aborted at the end of the test.

• testapp - a webtest.TestApp instance wrapping the app and is used to sending requests
into the application and return full response objects that can be inspected. The testapp is able
to mutate the request environ such that the dbsession and tm fixtures are injected and used by
any code that’s touching request.dbsession and request.tm. The testapp maintains
a cookiejar, so it can be used to share state across requests, as well as the transaction database
connection.

• app_request - a pyramid.request.Request object that can be used for more lightweight


tests versus the full testapp. The app_request can be passed to view functions and other code
that need a fully functional request object.

• dummy_request - a pyramid.testing.DummyRequest object that is very lightweight.


This is a great object to pass to view functions that have minimal side-effects as it’ll be fast and
simple.

• dummy_config — a pyramid.config.Configurator object used as configuration by


dummy_request. Useful for mocking configuration like routes and security policies.

Modifying the fixtures

We’re going to make a few application-specific changes to the test harness. It’s always good to come up
with patterns for things that are done often to avoid lots of boilerplate.

• Initialize the cookiejar with a CSRF token. Remember our application is using pyramid.csrf.
CookieCSRFStoragePolicy.

• testapp.get_csrf_token() - every POST/PUT/DELETE/PATCH request must contain the


current CSRF token to prove to our app that the client isn’t a third-party. So we want an easy way to
grab the current CSRF token and add it to the request.

• testapp.login(params) - many pages are only accessible by logged in users so we want a


simple way to login a user at the start of a test.

Update tests/conftest.py to look like the following, adding the highlighted lines:

0.2. Tutorials 249


The Pyramid Web Framework, Version 2.0.2

1 import alembic
2 import alembic.config
3 import alembic.command
4 import os
5 from pyramid.paster import get_appsettings
6 from pyramid.scripting import prepare
7 from pyramid.testing import DummyRequest, testConfig
8 import pytest
9 import transaction
10 from webob.cookies import Cookie
11 import webtest
12

13 from tutorial import main


14 from tutorial import models
15 from tutorial.models.meta import Base
16

17

18 def pytest_addoption(parser):
19 parser.addoption('--ini', action='store', metavar='INI_FILE')
20

21 @pytest.fixture(scope='session')
22 def ini_file(request):
23 # potentially grab this path from a pytest option
24 return os.path.abspath(request.config.option.ini or 'testing.ini')
25

26 @pytest.fixture(scope='session')
27 def app_settings(ini_file):
28 return get_appsettings(ini_file)
29

30 @pytest.fixture(scope='session')
31 def dbengine(app_settings, ini_file):
32 engine = models.get_engine(app_settings)
33

34 alembic_cfg = alembic.config.Config(ini_file)
35 Base.metadata.drop_all(bind=engine)
36 alembic.command.stamp(alembic_cfg, None, purge=True)
37

38 # run migrations to initialize the database


39 # depending on how we want to initialize the database from scratch
40 # we could alternatively call:
41 # Base.metadata.create_all(bind=engine)
42 # alembic.command.stamp(alembic_cfg, "head")
43 alembic.command.upgrade(alembic_cfg, "head")
44

45 yield engine
46
(continues on next page)

250 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


47 Base.metadata.drop_all(bind=engine)
48 alembic.command.stamp(alembic_cfg, None, purge=True)
49

50 @pytest.fixture(scope='session')
51 def app(app_settings, dbengine):
52 return main({}, dbengine=dbengine, **app_settings)
53

54 @pytest.fixture
55 def tm():
56 tm = transaction.TransactionManager(explicit=True)
57 tm.begin()
58 tm.doom()
59

60 yield tm
61

62 tm.abort()
63

64 @pytest.fixture
65 def dbsession(app, tm):
66 session_factory = app.registry['dbsession_factory']
67 return models.get_tm_session(session_factory, tm)
68

69 class TestApp(webtest.TestApp):
70 def get_cookie(self, name, default=None):
71 # webtest currently doesn't expose the unescaped cookie values
72 # so we're using webob to parse them for us
73 # see https://github.com/Pylons/webtest/issues/171
74 cookie = Cookie(' '.join(
75 '%s=%s' % (c.name, c.value)
76 for c in self.cookiejar
77 if c.name == name
78 ))
79 return next(
80 (m.value.decode('latin-1') for m in cookie.values()),
81 default,
82 )
83

84 def get_csrf_token(self):
85 """
86 Convenience method to get the current CSRF token.
87

88 This value must be passed to POST/PUT/DELETE requests in either the


89 "X-CSRF-Token" header or the "csrf_token" form value.
90

91 testapp.post(..., headers={'X-CSRF-Token': testapp.get_csrf_


(continues on next page)

0.2. Tutorials 251


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


,→ token()})
92

93 or
94

95 testapp.post(..., {'csrf_token': testapp.get_csrf_token()})


96

97 """
98 return self.get_cookie('csrf_token')
99

100 def login(self, params, status=303, **kw):


101 """ Convenience method to login the client."""
102 body = dict(csrf_token=self.get_csrf_token())
103 body.update(params)
104 return self.post('/login', body, **kw)
105

106 @pytest.fixture
107 def testapp(app, tm, dbsession):
108 # override request.dbsession and request.tm with our own
109 # externally-controlled values that are shared across requests but␣
,→aborted

110 # at the end


111 testapp = TestApp(app, extra_environ={
112 'HTTP_HOST': 'example.com',
113 'tm.active': True,
114 'tm.manager': tm,
115 'app.dbsession': dbsession,
116 })
117

118 # initialize a csrf token instead of running an initial request to get␣


,→one
119 # from the actual app - this only works using the␣
,→CookieCSRFStoragePolicy

120 testapp.set_cookie('csrf_token', 'dummy_csrf_token')


121

122 return testapp


123

124 @pytest.fixture
125 def app_request(app, tm, dbsession):
126 """
127 A real request.
128

129 This request is almost identical to a real request but it has some
130 drawbacks in tests as it's harder to mock data and is heavier.
131

132 """
(continues on next page)

252 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


133 with prepare(registry=app.registry) as env:
134 request = env['request']
135 request.host = 'example.com'
136

137 # without this, request.dbsession will be joined to the same␣


,→transaction
138 # manager but it will be using a different sqlalchemy.orm.Session␣
,→using

139 # a separate database transaction


140 request.dbsession = dbsession
141 request.tm = tm
142

143 yield request


144

145 @pytest.fixture
146 def dummy_request(tm, dbsession):
147 """
148 A lightweight dummy request.
149

150 This request is ultra-lightweight and should be used only when the␣
,→request
151 itself is not a large focus in the call-stack. It is much easier to␣
,→mock

152 and control side-effects using this object, however:


153

154 - It does not have request extensions applied.


155 - Threadlocals are not properly pushed.
156

157 """
158 request = DummyRequest()
159 request.host = 'example.com'
160 request.dbsession = dbsession
161 request.tm = tm
162

163 return request


164

165 @pytest.fixture
166 def dummy_config(dummy_request):
167 """
168 A dummy :class:`pyramid.config.Configurator` object. This allows for
169 mock configuration, including configuration for ``dummy_request``, as␣
,→well

170 as pushing the appropriate threadlocals.


171

172 """
(continues on next page)

0.2. Tutorials 253


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


173 with testConfig(request=dummy_request) as config:
174 yield config

Unit tests

We can test individual APIs within our codebase to ensure they fulfill the expected contract that the rest of
the application expects. For example, we’ll test the password hashing features we added to the tutorial.
models.User object.

Create tests/test_user_model.py such that it appears as follows:

1 from tutorial import models


2

4 def test_password_hash_saved():
5 user = models.User(name='foo', role='bar')
6 assert user.password_hash is None
7

8 user.set_password('secret')
9 assert user.password_hash is not None
10

11 def test_password_hash_not_set():
12 user = models.User(name='foo', role='bar')
13 assert not user.check_password('secret')
14

15 def test_correct_password():
16 user = models.User(name='foo', role='bar')
17 user.set_password('secret')
18 assert user.check_password('secret')
19

20 def test_incorrect_password():
21 user = models.User(name='foo', role='bar')
22 user.set_password('secret')
23 assert not user.check_password('incorrect')

254 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Integration tests

We can directly execute the view code, bypassing Pyramid and testing just the code that we’ve written.
These tests use dummy requests that we’ll prepare appropriately to set the conditions each view expects,
such as adding dummy data to the session. We’ll be using dummy_config to configure the necessary
routes, as well as setting the security policy as pyramid.testing.DummySecurityPolicy to
mock dummy_request.identity.

Update tests/test_views.py such that it appears as follows:

1 from pyramid.testing import DummySecurityPolicy


2

3 from tutorial import models


4

6 def makeUser(name, role):


7 return models.User(name=name, role=role)
8

10 def setUser(config, user):


11 config.set_security_policy(
12 DummySecurityPolicy(identity=user)
13 )
14

15 def makePage(name, data, creator):


16 return models.Page(name=name, data=data, creator=creator)
17

18 class Test_view_wiki:
19 def _callFUT(self, request):
20 from tutorial.views.default import view_wiki
21 return view_wiki(request)
22

23 def _addRoutes(self, config):


24 config.add_route('view_page', '/{pagename}')
25

26 def test_it(self, dummy_config, dummy_request):


27 self._addRoutes(dummy_config)
28 response = self._callFUT(dummy_request)
29 assert response.location == 'http://example.com/FrontPage'
30

31 class Test_view_page:
32 def _callFUT(self, request):
33 from tutorial.views.default import view_page
34 return view_page(request)
35

(continues on next page)

0.2. Tutorials 255


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


36 def _makeContext(self, page):
37 from tutorial.routes import PageResource
38 return PageResource(page)
39

40 def _addRoutes(self, config):


41 config.add_route('edit_page', '/{pagename}/edit_page')
42 config.add_route('add_page', '/add_page/{pagename}')
43 config.add_route('view_page', '/{pagename}')
44

45 def test_it(self, dummy_config, dummy_request, dbsession):


46 # add a page to the db
47 user = makeUser('foo', 'editor')
48 page = makePage('IDoExist', 'Hello CruelWorld IDoExist', user)
49 dbsession.add_all([page, user])
50

51 # create a request asking for the page we've created


52 self._addRoutes(dummy_config)
53 dummy_request.context = self._makeContext(page)
54

55 # call the view we're testing and check its behavior


56 info = self._callFUT(dummy_request)
57 assert info['page'] is page
58 assert info['content'] == (
59 '<div class="document">\n'
60 '<p>Hello <a href="http://example.com/add_page/CruelWorld">'
61 'CruelWorld</a> '
62 '<a href="http://example.com/IDoExist">'
63 'IDoExist</a>'
64 '</p>\n</div>\n'
65 )
66 assert info['edit_url'] == 'http://example.com/IDoExist/edit_page'
67

68 class Test_add_page:
69 def _callFUT(self, request):
70 from tutorial.views.default import add_page
71 return add_page(request)
72

73 def _makeContext(self, pagename):


74 from tutorial.routes import NewPage
75 return NewPage(pagename)
76

77 def _addRoutes(self, config):


78 config.add_route('add_page', '/add_page/{pagename}')
79 config.add_route('view_page', '/{pagename}')
80

(continues on next page)

256 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


81 def test_get(self, dummy_config, dummy_request, dbsession):
82 setUser(dummy_config, makeUser('foo', 'editor'))
83 self._addRoutes(dummy_config)
84 dummy_request.context = self._makeContext('AnotherPage')
85 info = self._callFUT(dummy_request)
86 assert info['pagedata'] == ''
87 assert info['save_url'] == 'http://example.com/add_page/AnotherPage
,→ '
88

89 def test_submit_works(self, dummy_config, dummy_request, dbsession):


90 dummy_request.method = 'POST'
91 dummy_request.POST['body'] = 'Hello yo!'
92 dummy_request.context = self._makeContext('AnotherPage')
93 setUser(dummy_config, makeUser('foo', 'editor'))
94 self._addRoutes(dummy_config)
95 self._callFUT(dummy_request)
96 page = (
97 dbsession.query(models.Page)
98 .filter_by(name='AnotherPage')
99 .one()
100 )
101 assert page.data == 'Hello yo!'
102

103 class Test_edit_page:


104 def _callFUT(self, request):
105 from tutorial.views.default import edit_page
106 return edit_page(request)
107

108 def _makeContext(self, page):


109 from tutorial.routes import PageResource
110 return PageResource(page)
111

112 def _addRoutes(self, config):


113 config.add_route('edit_page', '/{pagename}/edit_page')
114 config.add_route('view_page', '/{pagename}')
115

116 def test_get(self, dummy_config, dummy_request, dbsession):


117 user = makeUser('foo', 'editor')
118 page = makePage('abc', 'hello', user)
119 dbsession.add_all([page, user])
120

121 self._addRoutes(dummy_config)
122 dummy_request.context = self._makeContext(page)
123 info = self._callFUT(dummy_request)
124 assert info['pagename'] == 'abc'
(continues on next page)

0.2. Tutorials 257


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


125 assert info['save_url'] == 'http://example.com/abc/edit_page'
126

127 def test_submit_works(self, dummy_config, dummy_request, dbsession):


128 user = makeUser('foo', 'editor')
129 page = makePage('abc', 'hello', user)
130 dbsession.add_all([page, user])
131

132 self._addRoutes(dummy_config)
133 dummy_request.method = 'POST'
134 dummy_request.POST['body'] = 'Hello yo!'
135 setUser(dummy_config, user)
136 dummy_request.context = self._makeContext(page)
137 response = self._callFUT(dummy_request)
138 assert response.location == 'http://example.com/abc'
139 assert page.data == 'Hello yo!'

Functional tests

We’ll test the whole application, covering security aspects that are not tested in the unit and integration
tests, like logging in, logging out, checking that the basic user cannot edit pages that it didn’t create but
the editor user can, and so on.

Update tests/test_functional.py such that it appears as follows:

1 import pytest
2 import transaction
3

4 from tutorial import models


5

7 basic_login = dict(login='basic', password='basic')


8 editor_login = dict(login='editor', password='editor')
9

10 @pytest.fixture(scope='session', autouse=True)
11 def dummy_data(app):
12 """
13 Add some dummy data to the database.
14

15 Note that this is a session fixture that commits data to the database.
16 Think about it similarly to running the ``initialize_db`` script at the
17 start of the test suite.
(continues on next page)

258 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


18

19 This data should not conflict with any other data added throughout the
20 test suite or there will be issues - so be careful with this pattern!
21

22 """
23 tm = transaction.TransactionManager(explicit=True)
24 with tm:
25 dbsession = models.get_tm_session(app.registry['dbsession_factory
,→'], tm)

26 editor = models.User(name='editor', role='editor')


27 editor.set_password('editor')
28 basic = models.User(name='basic', role='basic')
29 basic.set_password('basic')
30 page1 = models.Page(name='FrontPage', data='This is the front page
,→')

31 page1.creator = editor
32 page2 = models.Page(name='BackPage', data='This is the back page')
33 page2.creator = basic
34 dbsession.add_all([basic, editor, page1, page2])
35

36 def test_root(testapp):
37 res = testapp.get('/', status=303)
38 assert res.location == 'http://example.com/FrontPage'
39

40 def test_FrontPage(testapp):
41 res = testapp.get('/FrontPage', status=200)
42 assert b'FrontPage' in res.body
43

44 def test_missing_page(testapp):
45 res = testapp.get('/SomePage', status=404)
46 assert b'404' in res.body
47

48 def test_successful_log_in(testapp):
49 params = dict(
50 **basic_login,
51 csrf_token=testapp.get_csrf_token(),
52 )
53 res = testapp.post('/login', params, status=303)
54 assert res.location == 'http://example.com/'
55

56 def test_successful_log_with_next(testapp):
57 params = dict(
58 **basic_login,
59 next='WikiPage',
60 csrf_token=testapp.get_csrf_token(),
(continues on next page)

0.2. Tutorials 259


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


61 )
62 res = testapp.post('/login', params, status=303)
63 assert res.location == 'http://example.com/WikiPage'
64

65 def test_failed_log_in(testapp):
66 params = dict(
67 login='basic',
68 password='incorrect',
69 csrf_token=testapp.get_csrf_token(),
70 )
71 res = testapp.post('/login', params, status=400)
72 assert b'login' in res.body
73

74 def test_logout_link_present_when_logged_in(testapp):
75 testapp.login(basic_login)
76 res = testapp.get('/FrontPage', status=200)
77 assert b'Logout' in res.body
78

79 def test_logout_link_not_present_after_logged_out(testapp):
80 testapp.login(basic_login)
81 testapp.get('/FrontPage', status=200)
82 params = dict(csrf_token=testapp.get_csrf_token())
83 res = testapp.post('/logout', params, status=303)
84 assert b'Logout' not in res.body
85

86 def test_anonymous_user_cannot_edit(testapp):
87 res = testapp.get('/FrontPage/edit_page', status=303).follow()
88 assert b'Login' in res.body
89

90 def test_anonymous_user_cannot_add(testapp):
91 res = testapp.get('/add_page/NewPage', status=303).follow()
92 assert b'Login' in res.body
93

94 def test_basic_user_cannot_edit_front(testapp):
95 testapp.login(basic_login)
96 res = testapp.get('/FrontPage/edit_page', status=403)
97 assert b'403' in res.body
98

99 def test_basic_user_can_edit_back(testapp):
100 testapp.login(basic_login)
101 res = testapp.get('/BackPage/edit_page', status=200)
102 assert b'Editing' in res.body
103

104 def test_basic_user_can_add(testapp):


105 testapp.login(basic_login)
(continues on next page)

260 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


106 res = testapp.get('/add_page/NewPage', status=200)
107 assert b'Editing' in res.body
108

109 def test_editors_member_user_can_edit(testapp):


110 testapp.login(editor_login)
111 res = testapp.get('/FrontPage/edit_page', status=200)
112 assert b'Editing' in res.body
113

114 def test_editors_member_user_can_add(testapp):


115 testapp.login(editor_login)
116 res = testapp.get('/add_page/NewPage', status=200)
117 assert b'Editing' in res.body
118

119 def test_editors_member_user_can_view(testapp):


120 testapp.login(editor_login)
121 res = testapp.get('/FrontPage', status=200)
122 assert b'FrontPage' in res.body
123

124 def test_redirect_to_edit_for_existing_page(testapp):


125 testapp.login(editor_login)
126 res = testapp.get('/add_page/FrontPage', status=303)
127 assert b'FrontPage' in res.body

Running the tests

On Unix:

$VENV/bin/pytest -q

On Windows:

%VENV%\Scripts\pytest -q

The expected result should look like the following:

........................... [100%]
27 passed in 6.91s

0.2. Tutorials 261


The Pyramid Web Framework, Version 2.0.2

Distributing Your Application

Once your application works properly, you can create a ”tarball” from it by using the setup.py sdist
command. The following commands assume your current working directory contains the tutorial
package and the setup.py file.

On Unix:

$VENV/bin/python setup.py sdist

On Windows:

%VENV%\Scripts\python setup.py sdist

The output of such a command will be something like:

running sdist
# more output
creating dist
Creating tar archive
removing 'tutorial-0.0' (and everything under it)

Note that this command creates a tarball in the dist subdirectory named tutorial-0.0.tar.gz.
You can send this file to your friends to show them your cool new application. They should be able to
install it by pointing the pip install command directly at it. Or you can upload it to PyPI and share it
with the rest of the world, where it can be downloaded via pip install remotely like any other package
people download from PyPI.

0.2.4 ZODB + Traversal Wiki Tutorial

This tutorial introduces a ZODB and traversal-based Pyramid application to a developer familiar with
Python. It will be most familiar to developers with previous Zope experience. When finished, the developer
will have created a basic Wiki application with authentication.

For cut and paste purposes, the source code for all stages of this tutorial can be browsed on GitHub for a
specific branch or version under docs/tutorials/wiki/src, which corresponds to the same loca-
tion if you have Pyramid sources.

262 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Background

This version of the Pyramid wiki tutorial presents a Pyramid application that uses technologies which will
be familiar to someone with Zope experience. It uses ZODB as a persistence mechanism and traversal to
map URLs to code. It can also be followed by people without any prior Python web framework experience.

To code along with this tutorial, the developer will need a Unix machine with development tools (macOS
with XCode, any Linux or BSD variant, and so on) or a Windows system of any kind.

Have fun!

Design

Following is a quick overview of the design of our wiki application to help us understand the changes that
we will make as we work through the tutorial.

Overall

We choose to use reStructuredText markup in the wiki text. Conversion from reStructuredText to HTML
is provided by the widely used docutils Python module. We will add this module in the dependency
list on the project setup.py file.

Models

The root resource named Wiki will be a mapping of wiki page names to page resources. The page re-
sources will be instances of a Page class. They store the text content.

URLs like /PageName will be traversed using Wiki[ PageName ] => page. The resulting context is the
page resource of an existing page.

To add a page to the wiki, a new instance of the page resource is created. Its name and reference are added
to the Wiki mapping.

A page named FrontPage containing the text This is the front page will be created when the storage is
initialized. It will be used as the wiki home page.

0.2. Tutorials 263


The Pyramid Web Framework, Version 2.0.2

Views

There will be three views to handle the normal operations of adding, editing, and viewing wiki pages, plus
one view for the wiki front page. Two templates will be used, one for viewing, and one for both adding
and editing wiki pages.

As of version 1.5 Pyramid no longer ships with templating systems. In this tutorial we will use Chameleon.
Chameleon is a variant of ZPT , which is an XML-based templating language.

Security

We’ll eventually add security to our application. The components we’ll use to do this are below.

• USERS, a dictionary mapping userids to their corresponding passwords.

• GROUPS, a dictionary mapping userids to a list of groups to which they belong.

• groupfinder, an authorization callback that looks up USERS and GROUPS. It will be provided
in a new security.py file.

• An ACL is attached to the root resource. Each row below details an ACE:

Action Principal Permission


Allow Everyone View
Allow group:editors Edit

• Permission declarations are added to the views to assert the security policies as each request is
handled.

Two additional views and one template will handle the login and logout tasks.

264 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Summary

The URL, context, actions, template and permission associated to each view are listed in the following
table:

0.2. Tutorials 265


The Pyramid Web Framework, Version 2.0.2

URL View Context Action Template Permission


/ view_wiki Wiki Redirect to
/FrontPage
/PageName view_page1 Page Display exist- view.pt view
ing page2
/Page- edit_page Page Display edit edit.pt edit
Name/edit_page form with ex-
isting content.
If the form
was submit-
ted, redirect to
/PageName
/add_page/PageName
add_page Wiki Create the edit.pt edit
page Pa-
geName in
storage, dis-
play the edit
form without
content.
If the form
was submit-
ted, redirect to
/PageName
/login login Wiki, Forbid- Display login login.pt
den3 form.
If the form
was submit-
ted, authenti-
cate.
• If
authen-
tication
suc-
ceeds,
redirect
to the
page
that we
came
from.
• If
authen-
tication
fails,
266 display CONTENTS
login
form
with
The Pyramid Web Framework, Version 2.0.2

Installation

Before you begin

This tutorial assumes that you have already followed the steps in Installing Pyramid, except do not create
a virtual environment or install Pyramid. Thereby you will satisfy the following requirements.

• A Python interpreter is installed on your operating system.

• You’ve satisfied the Requirements for Installing Packages.

Install cookiecutter

We will use a cookiecutter to create a Python package project from a Python package project template. See
Cookiecutter Installation for instructions.

Generate a Pyramid project from a cookiecutter

We will create a Pyramid project in your home directory for Unix or at the root for Windows. It is assumed
you know the path to where you installed cookiecutter. Issue the following commands and override
the defaults in the prompts as follows.

On Unix

cd ~
cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 2.0-branch

On Windows

1 This is the default view for a Page context when there is no view name.
2 Pyramid will return a default 404 Not Found page if the page PageName does not exist yet.
3 pyramid.exceptions.Forbidden is reached when a user tries to invoke a view that is not authorized by the authorization

policy.

0.2. Tutorials 267


The Pyramid Web Framework, Version 2.0.2

cd \
cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 2.0-branch

On all operating systems

If prompted for the first item, accept the default yes by hitting return.

You've downloaded ~/.cookiecutters/pyramid-cookiecutter-starter before.


Is it okay to delete and re-download it? [yes]: yes
project_name [Pyramid Scaffold]: myproj
repo_name [myproj]: tutorial
Select template_language:
1 - jinja2
2 - chameleon
3 - mako
Choose from 1, 2, 3 [1]: 2
Select backend:
1 - none
2 - sqlalchemy
3 - zodb
Choose from 1, 2, 3 [1]: 3

Change directory into your newly created project

On Unix

cd tutorial

On Windows

cd tutorial

268 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Set and use a VENV environment variable

We will set the VENV environment variable to the absolute path of the virtual environment, and use it going
forward.

On Unix

export VENV=~/tutorial

On Windows

set VENV=c:\tutorial

Create a virtual environment

On Unix

python3 -m venv $VENV

On Windows

python -m venv %VENV%

Upgrade packaging tools in the virtual environment

On Unix

0.2. Tutorials 269


The Pyramid Web Framework, Version 2.0.2

$VENV/bin/pip install --upgrade pip setuptools

On Windows

%VENV%\Scripts\pip install --upgrade pip setuptools

Installing the project in development mode

In order to work on the project, you must ”register” the project as a development egg in your workspace.
We will install testing requirements at the same time. We do so with the following command.

On Unix

$VENV/bin/pip install -e ".[testing]"

On Windows

%VENV%\Scripts\pip install -e ".[testing]"

On all operating systems

The console will show pip checking for packages and installing missing packages. Success executing this
command will show a line like the following:

270 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Successfully installed BTrees-4.7.2 Chameleon-3.8.1 Mako-1.1.3 MarkupSafe-


,→1.1.1 PasteDeploy-2.1.1 Pygments-2.7.3 WebTest-2.0.35 ZConfig-3.5.0 ZEO-

,→5.2.2 ZODB-5.6.0 attrs-20.3.0 beautifulsoup4-4.9.3 cffi-1.14.4 coverage-

,→5.3.1 hupper-1.10.2 iniconfig-1.1.1 packaging-20.8 persistent-4.6.4␣

,→plaster-1.0 plaster-pastedeploy-0.7 pluggy-0.13.1 py-1.10.0 pycparser-2.

,→20 pyparsing-2.4.7 pyramid-1.10.5 pyramid-chameleon-0.3 pyramid-

,→debugtoolbar-4.9 pyramid-mako-1.1.0 pyramid-retry-2.1.1 pyramid-tm-2.4␣

,→pyramid-zodbconn-0.8.1 pytest-6.2.1 pytest-cov-2.10.1 repoze.lru-0.7 six-

,→1.15.0 soupsieve-2.1 toml-0.10.2 transaction-3.0.1 translationstring-1.4␣

,→tutorial venusian-3.0.0 waitress-1.4.4 webob-1.8.6 zc.lockfile-2.0␣

,→zdaemon-4.3 zodbpickle-2.0.0 zodburi-2.4.0 zope.deprecation-4.4.0 zope.

,→interface-5.2.0

Testing requirements are defined in our project’s setup.py file, in the tests_require and ex-
tras_require stanzas.

24 tests_require = [
25 'WebTest',
26 'pytest',
27 'pytest-cov',
28 ]

48 extras_require={
49 'testing': tests_require,
50 },

Run the tests

After you’ve installed the project in development mode as well as the testing requirements, you may run
the tests for the project. The following commands provide options to pytest that specify the module for
which its tests shall be run, and to run pytest in quiet mode.

On Unix

$VENV/bin/pytest -q

0.2. Tutorials 271


The Pyramid Web Framework, Version 2.0.2

On Windows

%VENV%\Scripts\pytest -q

For a successful test run, you should see output that ends like this:

....
4 passed in 0.49 seconds

Expose test coverage information

You can run the pytest command to see test coverage information. This runs the tests in the same way
that pytest does, but provides additional coverage information, exposing which lines of your project are
covered by the tests.

We’ve already installed the pytest-cov package into our virtual environment, so we can run the tests
with coverage.

On Unix

$VENV/bin/pytest --cov --cov-report=term-missing

On Windows

%VENV%\Scripts\pytest --cov --cov-report=term-missing

If successful, you will see output something like this:

272 CONTENTS
The Pyramid Web Framework, Version 2.0.2

======================== test session starts =========================


platform darwin -- Python 3.9.0, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: /filepath/tutorial, inifile: pytest.ini, testpaths: tutorial
plugins: cov-2.10.1
collected 4 items

tests/test_functional.py .. [ 50%]
tests/test_views.py .. [100%]

---------- coverage: platform darwin, python 3.7.3-final-0 -----------


Name Stmts Miss Cover Missing
-----------------------------------------------------------
tutorial/__init__.py 16 0 100%
tutorial/models/__init__.py 8 0 100%
tutorial/pshell.py 6 4 33% 5-12
tutorial/routes.py 2 0 100%
tutorial/views/__init__.py 0 0 100%
tutorial/views/default.py 4 0 100%
tutorial/views/notfound.py 4 0 100%
-----------------------------------------------------------
TOTAL 40 4 90%

===================== 4 passed in 0.85 seconds =======================

Our package doesn’t quite have 100% test coverage.

Test and coverage cookiecutter defaults

The Pyramid cookiecutter includes configuration defaults for pytest and test coverage. These configu-
ration files are pytest.ini and .coveragerc, located at the root of your package.

pytest follows conventions for Python test discovery. The configuration defaults from the cookiecutter
tell pytest where to find the module on which we want to run tests and coverage.

See also:

See pytest’s documentation for How to invoke pytest or invoke pytest -h to see its full set of options.

0.2. Tutorials 273


The Pyramid Web Framework, Version 2.0.2

Start the application

Start the application. See What Is This pserve Thing for more information on pserve.

On Unix

$VENV/bin/pserve development.ini --reload

On Windows

%VENV%\Scripts\pserve development.ini --reload

Your OS firewall, if any, may pop up a dialog asking for authorization to allow python to accept
incoming network connections.

If successful, you will see something like this on your console:

Starting monitor for PID 65233.


Starting server in PID 65233.
Serving on http://localhost:6543
Serving on http://localhost:6543

This means the server is ready to accept requests.

Visit the application in a browser

In a browser, visit http://localhost:6543/. You will see the generated application’s default page.

One thing you’ll notice is the ”debug toolbar” icon on right hand side of the page. You can read more about
the purpose of the icon at The Debug Toolbar. It allows you to get information about your application while
you develop.

274 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Decisions the cookiecutter backend option zodb has made for you

When creating a project and selecting the backend option of zodb, the cookiecutter makes the following
assumptions:

• You are willing to use ZODB for persistent storage.

• You are willing to use traversal to map URLs to code.

• You want to use pyramid_zodbconn, pyramid_tm, and the transaction packages to manage connec-
tions and transactions with ZODB.

Pyramid supports any persistent storage mechanism (e.g., an SQL database or filesystem files). It
also supports an additional mechanism to map URLs to code (URL dispatch). However, for the purposes
of this tutorial, we will only use traversal and ZODB.

Basic Layout

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

Application configuration with __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. We use __init__.py both as a marker, indicating
the directory in which it is contained is a package, and to contain application configuration code.

When you run the application using the pserve command using the development.ini gener-
ated configuration file, the application configuration points at a Setuptools entry point described as
egg:tutorial. In our application, because the application’s setup.py file says so, this entry point
happens to be the main function within the file named __init__.py.

Open tutorial/__init__.py. It should already contain the following:

0.2. Tutorials 275


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.config import Configurator


2 from pyramid_zodbconn import get_connection
3

4 from .models import appmaker


5

7 def root_factory(request):
8 conn = get_connection(request)
9 return appmaker(conn.root())
10

11

12 def main(global_config, **settings):


13 """ This function returns a Pyramid WSGI application.
14 """
15 with Configurator(settings=settings) as config:
16 config.include('pyramid_chameleon')
17 config.include('pyramid_tm')
18 config.include('pyramid_retry')
19 config.include('pyramid_zodbconn')
20 config.include('.routes')
21 config.set_root_factory(root_factory)
22 config.scan()
23 return config.make_wsgi_app()

Let’s go over this piece-by-piece. First we need some imports to support later code.

1 from pyramid.config import Configurator


2 from pyramid_zodbconn import get_connection
3

4 from .models import appmaker


5

Define a root factory for our Pyramid application. It establishes a connection to ZODB database. It returns
an appmaker, which we will describe in the next section Resources and models with models package.

7 def root_factory(request):
8 conn = get_connection(request)
9 return appmaker(conn.root())

__init__.py defines a function named main. Here is the entirety of the main function that we have
defined in our __init__.py:

276 CONTENTS
The Pyramid Web Framework, Version 2.0.2

12 def main(global_config, **settings):


13 """ This function returns a Pyramid WSGI application.
14 """
15 with Configurator(settings=settings) as config:
16 config.include('pyramid_chameleon')
17 config.include('pyramid_tm')
18 config.include('pyramid_retry')
19 config.include('pyramid_zodbconn')
20 config.include('.routes')
21 config.set_root_factory(root_factory)
22 config.scan()
23 return config.make_wsgi_app()

When you invoke the pserve development.ini command, the main function above is executed.
It accepts some settings and returns a WSGI application. See Startup for more about pserve.

Next in main, construct a Configurator object using a context manager. See also Deployment settings.

15 with Configurator(settings=settings) as config:

settings is passed to the Configurator as a keyword argument with the dictionary values passed
as the **settings argument. This will be a dictionary of settings parsed from the .ini file, which
contains deployment-related values, such as pyramid.reload_templates, zodbconn.uri, and
so on.

Next include support for the Chameleon template rendering bindings, allowing us to use the .pt templates.

16 config.include('pyramid_chameleon')

Next include support for pyramid_tm, allowing Pyramid requests to join the active transaction as pro-
vided by the transaction package.

17 config.include('pyramid_tm')

Next include support for pyramid_retry to retry a request when transient exceptions occur.

18 config.include('pyramid_retry')

Next include support for pyramid_zodbconn, providing integration between ZODB and a Pyramid
application.

0.2. Tutorials 277


The Pyramid Web Framework, Version 2.0.2

19 config.include('pyramid_zodbconn')

Next include routes from the .routes module.

20 config.include('.routes')

Next set a root factory using our function named root_factory.

21 config.set_root_factory(root_factory)

The included module contains the following function.

1 def includeme(config):
2 config.add_static_view('static', 'static', cache_max_age=3600)

This registers a ”static view” using the pyramid.config.Configurator.


add_static_view() method. This view answers requests whose URL path starts with /static.
This statement registers a view that will serve up static assets, such as CSS and image files. In this case
the URL will answer requests at http://localhost:6543/static/ and below.

The first argument is the ”name” static, which indicates that the URL path prefix of the view will be
/static.

The second argument of this method is the ”path”. It is a relative asset specification. It finds the resources it
should serve within the static directory inside the tutorial package. Alternatively the cookiecutter
could have used an absolute asset specification as the path (tutorial:static).

The third argument is an optional cache_max_age which specifies the number of seconds the static
asset will be HTTP-cached.

Back into our __init__.py, next perform a scan.

22 config.scan()

A scan will find configuration decoration, such as view configuration decorators (e.g., @view_config)
in the source code of the tutorial package. It will take actions based on these decorators. We don’t
pass any arguments to scan(), which implies that the scan should take place in the current package (in
this case, tutorial). The cookiecutter could have equivalently said config.scan('tutorial'),
but it chose to omit the package name argument.

Finally use the pyramid.config.Configurator.make_wsgi_app() method to return a WSGI


application.

278 CONTENTS
The Pyramid Web Framework, Version 2.0.2

23 return config.make_wsgi_app()

Resources and models with models package

Pyramid uses the word resource to describe objects arranged hierarchically in a resource tree. This tree
is consulted by traversal to map URLs to code. In this application, the resource tree represents the site
structure, but it also represents the domain model of the application. Each resource is a node stored per-
sistently in a ZODB database. The models.py file is where the zodb cookiecutter put the classes that
implement our resource objects, each of which also happens to be a domain model object.

Here is the source for models.py:

1 from persistent.mapping import PersistentMapping


2

4 class MyModel(PersistentMapping):
5 __parent__ = __name__ = None
6

8 def appmaker(zodb_root):
9 if 'app_root' not in zodb_root:
10 app_root = MyModel()
11 zodb_root['app_root'] = app_root
12 return zodb_root['app_root']

1. Lines 4-5. The MyModel resource class is implemented here. Instances of this class are capa-
ble of being persisted in ZODB because the class inherits from the persistent.mapping.
PersistentMapping class. The __parent__ and __name__ are important parts of the
traversal protocol. By default, these are set to None to indicate that this is the root object.

2. Lines 8-12. appmaker is used to return the application root object. It is called on every request to
the Pyramid application by virtue of the root_factory defined in our __init__.py. It also
performs bootstrapping by creating an application root (inside the ZODB root object) if one does
not already exist.

Bootstrapping is done by first seeing if the database has the persistent application root. If not, then
we make an instance, store it, and commit the transaction.

We then return the application root object.

0.2. Tutorials 279


The Pyramid Web Framework, Version 2.0.2

View declarations via the views package

Our cookiecutter generated a default views package on our behalf. It contains a two views.
The first view is used to render the page shown when you visit the URL http://localhost:6543/.
Open tutorial/views/default.py in the views package. It should already contain the follow-
ing:

1 from pyramid.view import view_config


2

3 from ..models import MyModel


4

6 @view_config(context=MyModel, renderer='tutorial:templates/mytemplate.pt')
7 def my_view(request):
8 return {'project': 'myproj'}

Let’s try to understand the components in this module:


1. Lines 1-3. Perform some dependency imports.
2. Line 6. Use the pyramid.view.view_config() configuration decoration to perform a view
configuration registration. This view configuration registration will be activated when the applica-
tion is started. Remember in our application’s __init__.py when we executed the pyramid.
config.Configurator.scan() method config.scan()? By calling the scan method,
Pyramid’s configurator will find and process this @view_config decorator, and create a view
configuration within our application. Without being processed by scan, the decorator effectively
does nothing. @view_config is inert without being detected via a scan.
The @view_config decorator accepts a number of keyword arguments. We use two keyword
arguments here: context and renderer.
The context argument signifies that the decorated view callable my_view should only be run
when traversal finds the tutorial.models.MyModel resource as the context of a request. In
English this means that when the URL / is visited, and because MyModel is the root model, this
view callable will be invoked.
The renderer argument names an asset specification of tutorial:templates/
mytemplate.pt. This asset specification points at a Chameleon template which lives in
the mytemplate.pt file within the templates directory of the tutorial package. And
indeed if you look in the templates directory of this package, you will see a mytemplate.pt
template file This template renders the default home page of the generated project. This asset
specification is absolute to the views package. Alternatively we could have used the relative asset
specification ../templates/mytemplate.pt.
Since this call to @view_config doesn’t pass a name argument, the my_view function which it
decorates represents the ”default” view callable used when the context is of the type MyModel.

280 CONTENTS
The Pyramid Web Framework, Version 2.0.2

3. Lines 7-8. A view callable named my_view is defined, which is decorated in the step above.
This view callable is a function generated by the cookiecutter. It is given a single argument, re-
quest. This is the standard call signature for a Pyramid view callable. The function returns the
dictionary {'project': 'myproj'}. This dictionary is used by the template named by the
mytemplate.pt asset specification to fill in certain values on the page.

Let us open tutorial/views/notfound.py in the views package to look at the second view.

1 from pyramid.view import notfound_view_config


2

4 @notfound_view_config(renderer='tutorial:templates/404.pt')
5 def notfound_view(request):
6 request.response.status = 404
7 return {}

Without repeating ourselves, we will point out the differences between this view and the previous.

1. Line 4. The notfound_view function is decorated with @notfound_view_config.


This decorator registers a Not Found View using pyramid.config.Configurator.
add_notfound_view().

The renderer argument names an asset specification of tutorial:templates/404.pt.

2. Lines 5-7. A view callable named notfound_view is defined, which is decorated in the step
above. It sets the HTTP response status code to 404. The function returns an empty dictionary to
the template 404.pt, which accepts no parameters anyway.

Configuration in development.ini

The development.ini (in the tutorial project directory, as opposed to the tutorial package
directory) looks like this:

###
# app configuration
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/
,→environment.html

###

[app:main]
use = egg:tutorial
(continues on next page)

0.2. Tutorials 281


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)

pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar

zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000

retry.attempts = 3

# By default, the toolbar only appears for clients from IP addresses


# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1

[pshell]
setup = tutorial.pshell.setup

###
# wsgi server configuration
###

[server:main]
use = egg:waitress#main
listen = localhost:6543

###
# logging configuration
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.
,→html

###

[loggers]
keys = root, tutorial

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = INFO
(continues on next page)

282 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


handlers = console

[logger_tutorial]
level = DEBUG
handlers =
qualname = tutorial

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][
,→%(threadName)s] %(message)s

Note the existence of a [app:main] section which specifies our WSGI application. Our ZODB database
settings are specified as the zodbconn.uri setting within this section. When the server is started via
pserve, the values within this section are passed as **settings to the main function defined in
__init__.py.

Tests

The project contains a basic structure for a test suite using pytest. The structure is covered later in
Adding Tests.

Defining the Domain Model

Let’s make changes to our stock cookiecutter-generated application. We will define two resource construc-
tors, one representing a wiki page, and another representing the wiki as a mapping of wiki page names to
page objects. We will do this inside our models.py file.
Because we are using ZODB to represent our resource tree, each of these resource constructors represents
a domain model object. We will call these constructors ”model constructors”. Both our Page and Wiki
constructors will be class objects. A single instance of the ”Wiki” class will serve as a container for ”Page”
objects, which will be instances of the ”Page” class.
See also:
We will introduce a lot of concepts throughout the remainder of this tutorial. See also the chapter Resources
for a complete description of resources and the chapter Traversal for the technical details of how traversal
works in Pyramid.

0.2. Tutorials 283


The Pyramid Web Framework, Version 2.0.2

Delete the database

In the next step, we will remove the MyModel Python model class from our models package. Since this
class is referred to within our persistent storage (represented on disk as a file named Data.fs), we will
have strange things happen the next time we want to visit the application in a browser.

Remove the Data.fs from the tutorial directory before proceeding any further. It is always fine to
do this as long as you don’t care about the content of the database. The database itself will be recreated as
necessary.

Edit models package

There is nothing special about the package name models. A project may have many models through-
out its codebase in arbitrarily named files and directories. Files that implement models often have model
in their names, or they may live in a Python subpackage of your application package named models, but
this is only by convention.

Open tutorial/models/__init__.py file and edit it to look like the following:

1 from persistent import Persistent


2 from persistent.mapping import PersistentMapping
3

5 class Wiki(PersistentMapping):
6 __name__ = None
7 __parent__ = None
8

9 class Page(Persistent):
10 def __init__(self, data):
11 self.data = data
12

13 def appmaker(zodb_root):
14 if 'app_root' not in zodb_root:
15 app_root = Wiki()
16 frontpage = Page('This is the front page')
17 app_root['FrontPage'] = frontpage
18 frontpage.__name__ = 'FrontPage'
19 frontpage.__parent__ = app_root
20 zodb_root['app_root'] = app_root
21 return zodb_root['app_root']

284 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The emphasized lines indicate changes, described as follows.

Remove the MyModel class from the generated models/__init__.py file. The MyModel class is
only a sample and we’re not going to use it.

Next we add an import at the top for the persistent.Persistent class. We will use this for a new
Page class in a moment.

1 from persistent import Persistent


2 from persistent.mapping import PersistentMapping

Then we add a Wiki class.

5 class Wiki(PersistentMapping):
6 __name__ = None
7 __parent__ = None

We want it to inherit from the persistent.mapping.PersistentMapping class because it pro-


vides mapping behavior. It also makes sure that our Wiki page is stored as a ”first-class” persistent object
in our ZODB database.

Our Wiki class should have two attributes set to None at class scope: __parent__ and __name__.
If a model has a __parent__ attribute of None in a traversal-based Pyramid application, it means that
it is the root model. The __name__ of the root model is also always None.

Now we add a Page class.

9 class Page(Persistent):
10 def __init__(self, data):
11 self.data = data

This class should inherit from the persistent.Persistent class. We will give it an __init__
method that accepts a single parameter named data. This parameter will contain the reStructuredText
body representing the wiki page content.

Note that Page objects don’t have an initial __name__ or __parent__ attribute. All objects in a
traversal graph must have a __name__ and a __parent__ attribute. We do not specify these here.
Instead both __name__ and __parent__ will be set by a view function when a Page is added to our
Wiki mapping. We will create this function in the next chapter.

As a last step, edit the appmaker function.

0.2. Tutorials 285


The Pyramid Web Framework, Version 2.0.2

13 def appmaker(zodb_root):
14 if 'app_root' not in zodb_root:
15 app_root = Wiki()
16 frontpage = Page('This is the front page')
17 app_root['FrontPage'] = frontpage
18 frontpage.__name__ = 'FrontPage'
19 frontpage.__parent__ = app_root
20 zodb_root['app_root'] = app_root
21 return zodb_root['app_root']

The root resource of our application is a Wiki instance.

We will also slot a single page object (the front page) into the Wiki within the appmaker. This will
provide traversal a resource tree to work against when it attempts to resolve URLs to resources.

View the application in a browser

We cannot. At this point, our system is in a ”non-runnable” state We will need to change view-related
files in the next chapter to be able to start the application successfully. If you try to start the application
(See Start the application), you will wind up with a Python traceback on your console that ends with this
exception:

ImportError: cannot import name MyModel

This will also happen if you attempt to run the tests.

Defining Views

A view callable in a traversal-based Pyramid application is typically a simple Python function that accepts
two parameters: context and request. A view callable is assumed to return a response object.

A Pyramid view can also be defined as callable which accepts only a request argument. You will
see this one-argument pattern used in other Pyramid tutorials and applications. Either calling convention
will work in any Pyramid application. The calling conventions can be used interchangeably as necessary.

In traversal-based applications, URLs are mapped to a context resource. Since our resource tree also
represents our application’s ”domain model”, we are often interested in the context because it represents

286 CONTENTS
The Pyramid Web Framework, Version 2.0.2

the persistent storage of our application. For this reason, in this tutorial we define views as callables that
accept context in the callable argument list. If you do need the context within a view function that
only takes the request as a single argument, you can obtain it via request.context.

We will define several view callable functions, then wire them into Pyramid using some view configuration.

See also:

This chapter will introduce more concepts, as did the previous. See also the chapter Resources for a
complete description of resources and the chapter Traversal for the technical details of how traversal works
in Pyramid.

Declaring Dependencies in Our setup.py File

The view code in our application will depend on a package which is not a dependency of the original
”tutorial” application. The original ”tutorial” application was generated by the cookiecutter. It does not
know about our custom application requirements.

We need to add a dependency on the docutils package to our tutorial package’s setup.py file
by assigning this dependency to the requires parameter in the setup() function.

Open setup.py and edit it to look like the following:

11 requires = [
12 'docutils',
13 'plaster_pastedeploy',
14 'pyramid',
15 'pyramid_chameleon',
16 'pyramid_debugtoolbar',
17 'waitress',
18 'pyramid_retry',
19 'pyramid_tm',
20 'pyramid_zodbconn',
21 'transaction',
22 'ZODB',
23 ]
24

25 tests_require = [
26 'WebTest',
27 'pytest',
28 'pytest-cov',
29 ]

Only the highlighted line needs to be added.

0.2. Tutorials 287


The Pyramid Web Framework, Version 2.0.2

Running pip install -e .

Since a new software dependency was added, you need to run pip install -e . again inside the
root of the tutorial package to obtain and register the newly added dependency distribution.

Make sure your current working directory is the root of the project (the directory in which setup.py
lives) and execute the following command.

On Unix:

cd tutorial
$VENV/bin/pip install -e .

On Windows:

cd tutorial
%VENV%\Scripts\pip install -e .

Success executing this command will end with a line to the console similar to the following:

Successfully installed docutils-0.16 tutorial

Adding view functions in the views package

It is time for a major change. Open tutorial/views/default.py and edit it to look like the fol-
lowing:

1 from docutils.core import publish_parts


2 from pyramid.httpexceptions import HTTPSeeOther
3 from pyramid.view import view_config
4 import re
5

6 from ..models import Page


7

9 # regular expression used to find WikiWords


10 wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
11

(continues on next page)

288 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


12 @view_config(context='..models.Wiki')
13 def view_wiki(context, request):
14 return HTTPSeeOther(location=request.resource_url(context, 'FrontPage
,→'))

15

16

17 @view_config(context='..models.Page', renderer='tutorial:templates/view.pt
,→')

18 def view_page(context, request):


19 wiki = context.__parent__
20

21 def check(match):
22 word = match.group(1)
23 if word in wiki:
24 page = wiki[word]
25 view_url = request.resource_url(page)
26 return '<a href="%s">%s</a>' % (view_url, word)
27 else:
28 add_url = request.application_url + '/add_page/' + word
29 return '<a href="%s">%s</a>' % (add_url, word)
30

31 page_text = publish_parts(context.data, writer_name='html')['html_body


,→ ']
32 page_text = wikiwords.sub(check, page_text)
33 edit_url = request.resource_url(context, 'edit_page')
34 return dict(page=context, page_text=page_text, edit_url=edit_url)
35

36

37 @view_config(name='add_page', context='..models.Wiki',
38 renderer='tutorial:templates/edit.pt')
39 def add_page(context, request):
40 pagename = request.subpath[0]
41 if 'form.submitted' in request.params:
42 body = request.params['body']
43 page = Page(body)
44 page.__name__ = pagename
45 page.__parent__ = context
46 context[pagename] = page
47 return HTTPSeeOther(location=request.resource_url(page))
48 save_url = request.resource_url(context, 'add_page', pagename)
49 page = Page('')
50 page.__name__ = pagename
51 page.__parent__ = context
52 return dict(page=page, save_url=save_url)
53

(continues on next page)

0.2. Tutorials 289


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


54

55 @view_config(name='edit_page', context='..models.Page',
56 renderer='tutorial:templates/edit.pt')
57 def edit_page(context, request):
58 if 'form.submitted' in request.params:
59 context.data = request.params['body']
60 return HTTPSeeOther(location=request.resource_url(context))
61

62 return dict(
63 page=context,
64 save_url=request.resource_url(context, 'edit_page'),
65 )

We added some imports and created a regular expression to find ”WikiWords”.

We got rid of the my_view view function and its decorator that was added when originally rendered after
we selected the zodb backend option in the cookiecutter. It was only an example and is not relevant to
our application.

Then we added four view callable functions to our default.py module:

• view_wiki() - Displays the wiki itself. It will answer on the root URL.

• view_page() - Displays an individual page.

• add_page() - Allows the user to add a page.

• edit_page() - Allows the user to edit a page.

We will describe each one briefly in the following sections.

There is nothing special about the filename default.py. A project may have many view callables
throughout its codebase in arbitrarily named files. Files that implement view callables often have view
in their names (or may live in a Python subpackage of your application package named views), but this
is only by convention.

The view_wiki view function

Following is the code for the view_wiki view function and its decorator:

290 CONTENTS
The Pyramid Web Framework, Version 2.0.2

12 @view_config(context='..models.Wiki')
13 def view_wiki(context, request):
14 return HTTPSeeOther(location=request.resource_url(context, 'FrontPage
,→'))

In our code, we use an import that is relative to our package named tutorial. This means we
can omit the name of the package in the import and context statements. In our narrative, however, we
refer to a class and thus we use the absolute form. This means that the name of the package is included.

view_wiki() is the default view that gets called when a request is made to the root URL of our wiki.
It always redirects to an URL which represents the path to our FrontPage.

We provide it with a @view_config decorator which names the class tutorial.models.Wiki


as its context. This means that when a Wiki resource is the context and no view name exists in the
request, then this view will be used. The view configuration associated with view_wiki does not use
a renderer because the view callable always returns a response object rather than a dictionary. No
renderer is necessary when a view returns a response object.

The view_wiki view callable always redirects to the URL of a Page resource named FrontPage. To
do so, it returns an instance of the pyramid.httpexceptions.HTTPSeeOther class. Instances
of this class implement the pyramid.interfaces.IResponse interface, similar to pyramid.
response.Response. It uses the pyramid.request.Request.route_url() API to con-
struct an URL to the FrontPage page resource (in other words, http://localhost:6543/
FrontPage), and uses it as the location of the HTTPSeeOther response, forming an HTTP redirect.

The view_page view function

Here is the code for the view_page view function and its decorator:

17 @view_config(context='..models.Page', renderer='tutorial:templates/view.pt
,→')

18 def view_page(context, request):


19 wiki = context.__parent__
20

21 def check(match):
22 word = match.group(1)
23 if word in wiki:
(continues on next page)

0.2. Tutorials 291


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


24 page = wiki[word]
25 view_url = request.resource_url(page)
26 return '<a href="%s">%s</a>' % (view_url, word)
27 else:
28 add_url = request.application_url + '/add_page/' + word
29 return '<a href="%s">%s</a>' % (add_url, word)
30

31 page_text = publish_parts(context.data, writer_name='html')['html_body


,→ ']
32 page_text = wikiwords.sub(check, page_text)
33 edit_url = request.resource_url(context, 'edit_page')
34 return dict(page=context, page_text=page_text, edit_url=edit_url)

The view_page function is configured to respond as the default view of a Page resource. We provide
it with a @view_config decorator which names the class tutorial.models.Page as its context.
This means that when a Page resource is the context, and no view name exists in the request, this view will
be used. We inform Pyramid this view will use the templates/view.pt template file as a renderer.

The view_page function generates the reStructuredText body of a page as HTML. The body is stored
as the data attribute of the context passed to the view. The context will be a Page resource. Then it
substitutes an HTML anchor for each WikiWord reference in the rendered HTML using a compiled regular
expression.

The curried function named check is used as the first argument to wikiwords.sub, indicating that
it should be called to provide a value for each WikiWord match found in the content. If the wiki (our
page’s __parent__) already contains a page with the matched WikiWord name, the check function
generates a view link to be used as the substitution value and returns it. If the wiki does not already contain
a page with the matched WikiWord name, the function generates an ”add” link as the substitution value
and returns it.

As a result, the page_text variable is now a fully formed bit of HTML containing various view and add
links for WikiWords based on the content of our current page resource.

We then generate an edit URL because it is easier to do here than in the template. Finally we wrap up a
number of arguments in a dictionary and return it.

The arguments we wrap into a dictionary include page, page_text, and edit_url. As a result,
the template associated with this view callable (via renderer= in its configuration) will be able to use
these names to perform various rendering tasks. The template associated with this view callable will be a
template which lives in templates/view.pt.

Note the contrast between this view callable and the view_wiki view callable. In the view_wiki
view callable, we unconditionally return a response object. In the view_page view callable, we return
a dictionary. It is always fine to return a response object from a Pyramid view. Returning a dictionary is
allowed only when there is a renderer associated with the view callable in the view configuration.

292 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The add_page view function

Here is the code for the add_page view function and its decorator:

37 @view_config(name='add_page', context='..models.Wiki',
38 renderer='tutorial:templates/edit.pt')
39 def add_page(context, request):
40 pagename = request.subpath[0]
41 if 'form.submitted' in request.params:
42 body = request.params['body']
43 page = Page(body)
44 page.__name__ = pagename
45 page.__parent__ = context
46 context[pagename] = page
47 return HTTPSeeOther(location=request.resource_url(page))
48 save_url = request.resource_url(context, 'add_page', pagename)
49 page = Page('')
50 page.__name__ = pagename
51 page.__parent__ = context
52 return dict(page=page, save_url=save_url)

The add_page function is configured to respond when the context resource is a Wiki and the view name
is add_page. We provide it with a @view_config decorator which names the string add_page as
its view name (via name=), the class tutorial.models.Wiki as its context, and the renderer named
templates/edit.pt. This means that when a Wiki resource is the context, and a view name named
add_page exists as the result of traversal, then this view will be used. We inform Pyramid this view will
use the templates/edit.pt template file as a renderer. We share the same template between add
and edit views, thus edit.pt instead of add.pt.

The add_page function will be invoked when a user clicks on a WikiWord that is not yet represented as
a page in the system. The check function within the view_page view generates URLs to this view. It
also acts as a handler for the form that is generated when we want to add a page resource. The context
of the add_page view is always a Wiki resource (not a Page resource).

The request subpath in Pyramid is the sequence of names that are found after the view name in the URL
segments given in the PATH_INFO of the WSGI request as the result of traversal. If our add view is in-
voked via, for example, http://localhost:6543/add_page/SomeName, then the subpath will
be a tuple ('SomeName',).

The add view takes the zeroth element of the subpath (the wiki page name), then aliases it to the name
attribute to know the name of the page we are trying to add.

If the view rendering is not a result of a form submission (if the expression 'form.submitted' in
request.params is False), then the view renders a template. To do so, it generates a save_url

0.2. Tutorials 293


The Pyramid Web Framework, Version 2.0.2

which the template uses as the form post URL during rendering. We are lazy here, so we try to use the
same template (templates/edit.pt) for both the add and edit views. To do so, we create a dummy
Page resource object to satisfy the edit form’s desire to have some page object exposed as page. We then
set the Page object’s __name__ and __parent__. Then we will render the template to a response.

If the view rendering is a result of a form submission (if the expression 'form.submitted' in
request.params is True), then do the following:

• Grab the page body from the form data as body.

• Create a Page object using the name in the subpath and the page body as page.

• Set the Page object’s __name__ and __parent__.

• Save it into ”our context” (the Wiki) using the __setitem__ method of the context.

• We then redirect back to the view_page view (the default view for a page) for the newly created
page.

See also:

In the previous chapter, we mentioned that all objects in a traversal graph must have a __name__ and a
__parent__ attribute. That provides location awareness for resources. See also the section on Location-
Aware Resources in the Resources chapter for a complete discussion.

The edit_page view function

Here is the code for the edit_page view function and its decorator:

55 @view_config(name='edit_page', context='..models.Page',
56 renderer='tutorial:templates/edit.pt')
57 def edit_page(context, request):
58 if 'form.submitted' in request.params:
59 context.data = request.params['body']
60 return HTTPSeeOther(location=request.resource_url(context))
61

62 return dict(
63 page=context,
64 save_url=request.resource_url(context, 'edit_page'),
65 )

294 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The edit_page function is configured to respond when the context is a Page resource and the view name
is edit_page. We provide it with a @view_config decorator which names the string edit_page as
its view name (via name=), the class tutorial.models.Page as its context, and the renderer named
templates/edit.pt. This means that when a Page resource is the context, and a view name exists
as the result of traversal named edit_page, this view will be used. We inform Pyramid this view will
use the templates/edit.pt template file as a renderer.

The edit_page function will be invoked when a user clicks the ”Edit this Page” button on the view form.
It renders an edit form. It also acts as the form post view callable for the form it renders. The context
of the edit_page view will always be a Page resource (never a Wiki resource).

If the view execution is not a result of a form submission (if the expression 'form.submitted' in
request.params is False), then the view renders the edit form, passing the page resource, and a
save_url which will be used as the action of the generated form.

If the view execution is a result of a form submission (if the expression 'form.submitted' in
request.params is True), the view grabs the body element of the request parameter and sets it as
the data attribute of the page context. It then redirects to the default view of the context (the page), which
will always be the view_page view.

Modifying the notfound_view in notfound.py

We have one more view to modify. Open tutorial/views/notfound.py and make the changes
shown by the emphasized lines.

1 from pyramid.view import notfound_view_config


2

3 from ..models import Page


4

6 @notfound_view_config(renderer='tutorial:templates/404.pt')
7 def notfound_view(request):
8 request.response.status = 404
9 pagename = request.path
10 page = Page(pagename)
11 page.__name__ = pagename
12 return dict(page=page)

We need to import the Page from our models. We eventually return a Page object as page into the
template layout.pt to display its name in the title tag.

0.2. Tutorials 295


The Pyramid Web Framework, Version 2.0.2

Adding templates

The view_page, add_page, and edit_page views that we added reference a template. Each tem-
plate is a Chameleon ZPT template. These templates will live in the templates directory of our tutorial
package. Chameleon templates must have a .pt extension to be recognized as such.

The layout.pt template

Update tutorial/templates/layout.pt with the following content, as indicated by the empha-


sized lines:

1 <!DOCTYPE html metal:define-macro="layout">


2 <html lang="${request.locale_name}">
3 <head>
4 <meta charset="utf-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta name="description" content="pyramid web application">
8 <meta name="author" content="Pylons Project">
9 <link rel="shortcut icon" href="${request.static_url('tutorial:static/
,→pyramid-16x16.png')}">

10

11 <title><span tal:replace="page.__name__ | title"></span> - Pyramid␣


,→ tutorial wiki (based on TurboGears 20-Minute Wiki)</title>
12

13 <!-- Bootstrap core CSS -->


14 <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/
,→css/bootstrap.min.css" integrity="sha384-

,→BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"␣

,→crossorigin="anonymous">

15

16 <!-- Custom styles for this scaffold -->


17 <link href="${request.static_url('tutorial:static/theme.css')}" rel=
,→"stylesheet">

18

19 <!-- HTML5 shiv and Respond.js IE8 support of HTML5 elements and media␣
,→queries -->
20 <!--[if lt IE 9]>
21 <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"␣
,→integrity="sha384-

,→0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY"␣

,→crossorigin="anonymous"></script>

(continues on next page)

296 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


22 <script src="//oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"␣
,→integrity="sha384-

,→ZoaMbDF+4LeFxg6WdScQ9nnR1QC2MIRxA1O9KWEXQwns1G8UNyIEZIQidzb0T1fo"␣

,→crossorigin="anonymous"></script>

23 <![endif]-->
24 </head>
25

26 <body>
27

28 <div class="starter-template">
29 <div class="container">
30 <div class="row">
31 <div class="col-md-2">
32 <img class="logo img-responsive" src="${request.static_url(
,→'tutorial:static/pyramid.png')}" alt="pyramid web framework">

33 </div>
34 <div class="col-md-10">
35 <div metal:define-slot="content">No content</div>
36 <div class="content">
37 <p>You can return to the
38 <a href="${request.application_url}">FrontPage</a>.
39 </p>
40 </div>
41 </div>
42 </div>
43 <div class="row">
44 <div class="links">
45 <ul>
46 <li><i class="glyphicon glyphicon-cog icon-muted"></i><a␣
,→href="https://github.com/Pylons/pyramid">Github Project</a></li>

47 <li><i class="glyphicon glyphicon-globe icon-muted"></i><a␣


,→href="https://web.libera.chat/#pyramid">IRC Channel</a></li>

48 <li><i class="glyphicon glyphicon-home icon-muted"></i><a␣


,→href="https://pylonsproject.org">Pylons Project</a></li>

49 </ul>
50 </div>
51 </div>
52 <div class="row">
53 <div class="copyright">
54 Copyright &copy; Pylons Project
55 </div>
56 </div>
57 </div>
58 </div>
59

(continues on next page)

0.2. Tutorials 297


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


60

61 <!-- Bootstrap core JavaScript


62 ================================================== -->
63 <!-- Placed at the end of the document so the pages load faster -->
64 <script src="//code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-
,→ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></

,→script>

65 <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.
,→min.js" integrity="sha384-

,→Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"␣

,→crossorigin="anonymous"></script>

66 </body>
67 </html>

Since we are using a templating engine, we can factor common boilerplate out of our page templates into
reusable components. We can do this via METAL macros and slots.

• The cookiecutter defined a macro named layout (line 1). This macro consists of the entire tem-
plate.

• We changed the title tag to use the name attribute of a page object, or if it does not exist then
the page title (line 11).

• The cookiecutter defined a macro customization point or slot (line 35). This slot is inside the macro
layout. Therefore it can be replaced by content, customizing the macro.

• We added a div element with a link to allow the user to return to the front page (lines 36-40).

See also:

Please refer to the Chameleon documentation for more information about using METAL for defining and
using macros and slots.

The view.pt template

Rename tutorial/templates/mytemplate.pt to tutorial/templates/view.pt and


edit the emphasized lines to look like the following:

298 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 <div metal:use-macro="load: layout.pt">


2 <div metal:fill-slot="content">
3

4 <div class="content">
5 <div tal:replace="structure page_text">
6 Page text goes here.
7 </div>
8 <p>
9 <a tal:attributes="href edit_url" href="">
10 Edit this page
11 </a>
12 </p>
13 <p>
14 Viewing <strong><span tal:replace="page.__name__">
15 Page Name Goes Here</span></strong>
16 </p>
17 </div>
18

19 </div>
20 </div>

This template is used by view_page() for displaying a single wiki page. It includes:

• The use of a macro to load the entire template layout.pt.

• The template fills the slot named content (line 2) with a div element.

• A div element that is replaced with the page_text value provided by the view (line 5).
page_text contains HTML, so the structure keyword is used to prevent escaping HTML
entities, such as changing > to &gt;.

• A link that points at the ”edit” URL, which invokes the edit_page view for the page being viewed
(lines 9-11).

• A span whose content is replaced by the name of the page, if present.

The edit.pt template

Copy tutorial/templates/view.pt to tutorial/templates/edit.pt and edit the em-


phasized lines to look like the following:

0.2. Tutorials 299


The Pyramid Web Framework, Version 2.0.2

1 <div metal:use-macro="load: layout.pt">


2 <div metal:fill-slot="content">
3

4 <div class="content">
5 <p>
6 Editing <strong><span tal:replace="page.__name__">
7 Page Name Goes Here</span></strong>
8 </p>
9 <form action="${save_url}" method="post">
10 <div class="form-group">
11 <textarea tal:content="page.data"
12 class="form-control" name="body"
13 rows="10" cols="60"></textarea>
14 </div>
15 <div class="form-group">
16 <button type="submit"
17 name="form.submitted" value="Save"
18 class="btn btn-default">Save</button>
19 </div>
20 </form>
21 </div>
22

23 </div>
24 </div>

This template is used by add_page() and edit_page() for adding and editing a wiki page. It displays
a page containing a form that includes:

• A 10-row by 60-column textarea field named body that is filled with any existing page data
when it is rendered (lines 11-13).

• A submit button that has the name form.submitted (lines 16-18).

When submitted, the form sends a POST request to the save_url argument supplied by the view (line
9). The view will use the body and form.submitted values.

Our templates use a request object that none of our tutorial views return in their dictionary.
request is one of several names that are available ”by default” in a template when a template renderer
is used. See System Values Used During Rendering for information about other names that are available
by default when a template is used as a renderer.

300 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Static assets

Our templates name static assets, including CSS and images. We don’t need to create these files within our
package’s static directory because they were provided by the cookiecutter at the time we created the
project.

As an example, the CSS file will be accessed via http://localhost:6543/static/theme.


css by virtue of the call to the add_static_view directive in the routes.py file. Any
number and type of static assets can be placed in this directory (or subdirectories). They are re-
ferred to by either URL or using the convenience method static_url, for example request.
static_url('<package>:static/foo.css'), within templates.

Viewing the application in a browser

We can finally examine our application in a browser (See Start the application). Launch a browser and
visit each of the following URLs, checking that the result is as expected:

• http://localhost:6543/ invokes the view_wiki view. This always redirects to the view_page
view of the FrontPage Page resource.

• http://localhost:6543/FrontPage/ invokes the view_page view of the front page resource. This is
because it is the default view (a view without a name) for Page resources.

• http://localhost:6543/FrontPage/edit_page invokes the edit view for the FrontPage Page re-
source.

• http://localhost:6543/add_page/SomePageName invokes the add view for a Page.

• To generate an error, visit http://localhost:6543/add_page which will generate an IndexError:


tuple index out of range error. You will see an interactive traceback facility provided by
pyramid_debugtoolbar.

• To generate a not found error, visit http://localhost:6543/wakawaka which will invoke the not-
found_view view provided by the cookiecutter.

0.2. Tutorials 301


The Pyramid Web Framework, Version 2.0.2

Adding authorization and authentication

Pyramid provides facilities for authentication and authorization. We will make use of both features to
provide security to our application. Our application currently allows anyone with access to the server to
view, edit, and add pages to our wiki. We will change that to allow only people who are members of a
group named group:editors to add and edit wiki pages. We will continue to allow anyone with access
to the server to view pages.

We will also add a login page and a logout link on all the pages. The login page will be shown when a user
is denied access to any of the views that require permission, instead of a default ”403 Forbidden” page.

We will implement the access control with the following steps:

• Add password hashing dependencies.

• Add users and groups (security.py, a new module).

• Add a security policy (security.py).

• Add an ACL (models.py).

• Add permission declarations to the edit_page and add_page views (views.py).

Then we will add the login and logout features:

• Add login and logout views (views.py).

• Add a login template (login.pt).

• Make the existing views return a logged_in flag to the renderer (views.py).

• Add a ”Logout” link to be shown when logged in and viewing or editing a page (view.pt, edit.
pt).

Access control

Add dependencies

Just like in Defining Views, we need a new dependency. We need to add the bcrypt package to our tutorial
package’s setup.py file by assigning this dependency to the requires parameter in the setup()
function.

Open setup.py and edit it to look like the following:

302 CONTENTS
The Pyramid Web Framework, Version 2.0.2

11 requires = [
12 'bcrypt',
13 'docutils',
14 'plaster_pastedeploy',
15 'pyramid',
16 'pyramid_chameleon',
17 'pyramid_debugtoolbar',
18 'waitress',
19 'pyramid_retry',
20 'pyramid_tm',
21 'pyramid_zodbconn',
22 'transaction',
23 'ZODB',
24 ]
25

26 tests_require = [
27 'WebTest',
28 'pytest',
29 'pytest-cov',
30 ]

Only the highlighted line needs to be added.

Do not forget to run pip install -e . just like in Running pip install -e ..

We are using the bcrypt package from PyPI to hash our passwords securely. There are other
one-way hash algorithms for passwords if bcrypt is an issue on your system. Just make sure that it is an
algorithm approved for storing passwords versus a generic one-way hash.

Add the security policy

Create a new tutorial/security.py module with the following content:

1 import bcrypt
2 from pyramid.authentication import AuthTktCookieHelper
3 from pyramid.authorization import (
4 ACLHelper,
5 Authenticated,
6 Everyone,
(continues on next page)

0.2. Tutorials 303


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


7 )
8

10 def hash_password(pw):
11 hashed_pw = bcrypt.hashpw(pw.encode('utf-8'), bcrypt.gensalt())
12 # return unicode instead of bytes because databases handle it better
13 return hashed_pw.decode('utf-8')
14

15 def check_password(expected_hash, pw):


16 if expected_hash is not None:
17 return bcrypt.checkpw(pw.encode('utf-8'), expected_hash.encode(
,→'utf-8'))

18 return False
19

20 USERS = {
21 'editor': hash_password('editor'),
22 'viewer': hash_password('viewer'),
23 }
24 GROUPS = {'editor': ['group:editors']}
25

26 class MySecurityPolicy:
27 def __init__(self, secret):
28 self.authtkt = AuthTktCookieHelper(secret)
29 self.acl = ACLHelper()
30

31 def identity(self, request):


32 identity = self.authtkt.identify(request)
33 if identity is not None and identity['userid'] in USERS:
34 return identity
35

36 def authenticated_userid(self, request):


37 identity = self.identity(request)
38 if identity is not None:
39 return identity['userid']
40

41 def remember(self, request, userid, **kw):


42 return self.authtkt.remember(request, userid, **kw)
43

44 def forget(self, request, **kw):


45 return self.authtkt.forget(request, **kw)
46

47 def permits(self, request, context, permission):


48 principals = self.effective_principals(request)
49 return self.acl.permits(context, principals, permission)
50

(continues on next page)

304 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


51 def effective_principals(self, request):
52 principals = [Everyone]
53 identity = self.identity(request)
54 if identity is not None:
55 principals.append(Authenticated)
56 principals.append('u:' + identity['userid'])
57 principals.extend(GROUPS.get(identity['userid'], []))
58 return principals
59

60 def includeme(config):
61 settings = config.get_settings()
62

63 config.set_security_policy(MySecurityPolicy(settings['auth.secret']))

Since we’ve added a new tutorial/security.py module, we need to include it. Open the file
tutorial/__init__.py and edit the following lines:

1 from pyramid.config import Configurator


2 from pyramid_zodbconn import get_connection
3

4 from .models import appmaker


5

7 def root_factory(request):
8 conn = get_connection(request)
9 return appmaker(conn.root())
10

11

12 def main(global_config, **settings):


13 """ This function returns a Pyramid WSGI application.
14 """
15 with Configurator(settings=settings) as config:
16 config.include('pyramid_chameleon')
17 config.include('pyramid_tm')
18 config.include('pyramid_retry')
19 config.include('pyramid_zodbconn')
20 config.include('.routes')
21 config.include('.security')
22 config.set_root_factory(root_factory)
23 config.scan()
24 return config.make_wsgi_app()

The security policy controls several aspects of authentication and authorization:

0.2. Tutorials 305


The Pyramid Web Framework, Version 2.0.2

• Identifying the current user’s identity for a request.


• Authorizating access to resources.
• Creating payloads for remembering and forgetting users.

Identifying logged-in users

The MySecurityPolicy.identity method inspects the request and determines if it


came from an authenticated user. It does this by utilizing the pyramid.authentication.
AuthTktCookieHelper class which stores the identity in a cryptographically-signed cookie. If a
request does contain an identity, then we perform a final check to determine if the user is valid in our
current USERS store.

Authorizing access to resources

The MySecurityPolicy.permits method determines if the request is allowed a specific per-


mission on the given context. This process is done in a few steps:
• Convert the request into a list of principals via the MySecurityPolicy.
effective_principals method.
• Compare the list of principals to the context using the pyramid.authorization.
ACLHelper. It will only allow access if it can find an ACE that grants one of the principals the
necessary permission.
For our application we’ve defined a list of a few principals:
• u:<userid>
• group:editor
• pyramid.authorization.Authenticated
• pyramid.authorization.Everyone
Various wiki pages will grant some of these principals access to edit existing or add new pages.
Finally there are two helper methods that will help us to authenticate users. The first is hash_password
which takes a raw password and transforms it using bcrypt into an irreversible representation, a process
known as ”hashing”. The second method, check_password, will allow us to compare the hashed value
of the submitted password against the hashed value of the password stored in the user’s record. If the two
hashed values match, then the submitted password is valid, and we can authenticate the user.
We hash passwords so that it is impossible to decrypt and use them to authenticate in the application. If
we stored passwords foolishly in clear text, then anyone with access to the database could retrieve any
password to authenticate as any user.
In a production system, user and group data will most often be saved and come from a database. Here we
use ”dummy” data to represent user and groups sources.

306 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Add new settings

Our authentication policy is expecting a new setting, auth.secret. Open the file development.ini
and add the highlighted line below:

19 retry.attempts = 3
20

21 auth.secret = seekrit

Best practices tell us to use a different secret in each environment. Open production.ini and add a
different secret:

17 retry.attempts = 3
18

19 auth.secret = real-seekrit

Edit testing.ini to add its unique secret:

17 retry.attempts = 3
18

19 auth.secret = testing-seekrit

Add an ACL

Open tutorial/models/__init__.py and add the following import statement near the top:

3 from pyramid.authorization import (


4 Allow,
5 Everyone,
6 )

Add the following lines to the Wiki class:

9 class Wiki(PersistentMapping):
10 __name__ = None
11 __parent__ = None
12 __acl__ = [
13 (Allow, Everyone, 'view'),
14 (Allow, 'group:editors', 'edit'),
15 ]

0.2. Tutorials 307


The Pyramid Web Framework, Version 2.0.2

We import Allow, an action which means that permission is allowed. We also import Everyone, a
special principal that is associated to all requests. Both are used in the ACE entries that make up the ACL.

The ACL is a list that needs to be named __acl__ and be an attribute of a class. We define an ACL
with two ACE entries. The first entry allows any user the view permission. The second entry allows the
group:editors principal the edit permission.

The Wiki class that contains the ACL is the resource constructor for the root resource, which is a Wiki
instance. The ACL is provided to each view in the context of the request as the context attribute.

It is only happenstance that we assigned this ACL at class scope. An ACL can be attached to an object
instance too. This is how ”row level security” can be achieved in Pyramid applications. We actually need
only one ACL for the entire system, however, because our security requirements are simple, so this feature
is not demonstrated.

See also:

See Implementing ACL Authorization for more information about what an ACL represents.

Add permission declarations

Open tutorial/views/default.py. Add a permission='view' parameter to the


@view_config decorators for view_wiki() and view_page() as follows:

12 @view_config(context='..models.Wiki', permission='view')

17 @view_config(context='..models.Page',
18 renderer='tutorial:templates/view.pt',
19 permission='view')

Only the highlighted lines, along with their preceding commas, need to be edited and added.

This allows anyone to invoke these two views.

Next add a permission='edit' parameter to the @view_config decorators for add_page()


and edit_page():

39 @view_config(name='add_page', context='..models.Wiki',
40 renderer='tutorial:templates/edit.pt',
41 permission='edit')

308 CONTENTS
The Pyramid Web Framework, Version 2.0.2

58 @view_config(name='edit_page', context='..models.Page',
59 renderer='tutorial:templates/edit.pt',
60 permission='edit')

Only the highlighted lines, along with their preceding commas, need to be edited and added.

The result is that only users who possess the edit permission at the time of the request may invoke those
two views.

We are done with the changes needed to control access. The changes that follow will add the login and
logout feature.

Login, logout

Add login and logout views

We will add a login view which renders a login form and processes the post from the login form, checking
credentials.

We will also add a logout view callable to our application and provide a link to it. This view will clear
the credentials of the logged in user and redirect back to the front page.

Add a new file tutorial/views/auth.py with the following contents:

1 from pyramid.httpexceptions import HTTPSeeOther


2 from pyramid.security import (
3 forget,
4 remember,
5 )
6 from pyramid.view import (
7 forbidden_view_config,
8 view_config,
9 )
10

11 from ..security import check_password, USERS


12

13

14 @view_config(context='..models.Wiki', name='login',
15 renderer='tutorial:templates/login.pt')
(continues on next page)

0.2. Tutorials 309


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


16 @forbidden_view_config(renderer='tutorial:templates/login.pt')
17 def login(request):
18 login_url = request.resource_url(request.root, 'login')
19 referrer = request.url
20 if referrer == login_url:
21 referrer = '/' # never use the login form itself as came_from
22 came_from = request.params.get('came_from', referrer)
23 message = ''
24 login = ''
25 password = ''
26 if 'form.submitted' in request.params:
27 login = request.params['login']
28 password = request.params['password']
29 if check_password(USERS.get(login), password):
30 headers = remember(request, login)
31 return HTTPSeeOther(location=came_from, headers=headers)
32 message = 'Failed login'
33 request.response.status = 400
34

35 return dict(
36 message=message,
37 url=login_url,
38 came_from=came_from,
39 login=login,
40 password=password,
41 title='Login',
42 )
43

44

45 @view_config(context='..models.Wiki', name='logout')
46 def logout(request):
47 headers = forget(request)
48 return HTTPSeeOther(
49 location=request.resource_url(request.context),
50 headers=headers,
51 )

forbidden_view_config() will be used to customize the default 403 Forbidden page. remem-
ber() and forget() help to create and expire an auth ticket cookie.

login() has two decorators:

• A @view_config decorator which associates it with the login route and makes it visible when
we visit /login.

310 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• A @forbidden_view_config decorator which turns it into a forbidden view. login() will


be invoked when a user tries to execute a view callable for which they lack authorization. For
example, if a user has not logged in and tries to add or edit a Wiki page, then they will be shown the
login form before being allowed to continue.
The order of these two view configuration decorators is unimportant.
logout() is decorated with a @view_config decorator which associates it with the logout route.
It will be invoked when we visit /logout.

Add the login.pt Template

Create tutorial/templates/login.pt with the following content:

<div metal:use-macro="load: layout.pt">


<div metal:fill-slot="content">

<div class="content">
<p>
<strong>
Login
</strong><br>
<span tal:replace="message"></span>
</p>
<form action="${url}" method="post">
<input type="hidden" name="came_from" value="${came_from}">
<div class="form-group">
<label for="login">Username</label>
<input type="text" name="login" value="${login}">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" name="password" value="${password}
,→ ">
</div>
<div class="form-group">
<button type="submit" name="form.submitted" value="Log In
,→" class="btn btn-default">Log In</button>

</div>
</form>
</div>

</div>
</div>

The above template is referenced in the login view that we just added in views.py.

0.2. Tutorials 311


The Pyramid Web Framework, Version 2.0.2

Add ”Login” and ”Logout” links

Open tutorial/templates/layout.pt and add the following code as indicated by the highlighted
lines.

34 <div class="col-md-10">
35 <div class="content">
36 <p tal:condition="request.authenticated_userid is None"␣
,→class="pull-right">

37 <a href="${request.application_url}/login">Login</a>
38 </p>
39 <p tal:condition="request.authenticated_userid is not None
,→" class="pull-right">

40 <a href="${request.application_url}/logout">Logout</a>
41 </p>
42 </div>
43 <div metal:define-slot="content">No content</div>

The attribute tal:condition="logged_in" will make the element be included when logged_in
is any user id. The link will invoke the logout view. The above element will not be included if logged_in
is None, such as when a user is not authenticated.

Viewing the application in a browser

We can finally examine our application in a browser (See Start the application). Launch a browser and
visit each of the following URLs, checking that the result is as expected:

• http://localhost:6543/ invokes the view_wiki view. This always redirects to the view_page
view of the FrontPage Page resource. It is executable by any user.

• http://localhost:6543/login invokes the login view, and a login form will be displayed. On every
page, there is a ”Login” link in the upper right corner while the user is not authenticated, else it is a
”Logout” link when the user is authenticated.

Supplying the credentials with either the username editor and password editor will authenti-
cate the user and grant access for that group.

After logging in (as a result of hitting an edit or add page and submitting valid credentials), we will
see a ”Logout” link in the upper right hand corner. When we click it, we are logged out, redirected
back to the front page, and a ”Login” link is shown in the upper right hand corner.

312 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• http://localhost:6543/FrontPage invokes the view_page view of the FrontPage Page resource.


This is because it is the default view (a view without a name) for Page resources. It is executable
by any user.
• http://localhost:6543/FrontPage/edit_page invokes the edit view for the FrontPage object. It is ex-
ecutable by only the editor user. If a different user (or the anonymous user) invokes it, then a
login form will be displayed. The editor user will see the edit page form.
• http://localhost:6543/add_page/SomePageName invokes the add view for a page. It is executable by
only the editor user. If a different user (or the anonymous user) invokes it, a login form will be
displayed. The editor user will see the edit page form.
• To generate a not found error, visit http://localhost:6543/wakawaka which will invoke the not-
found_view view provided by the cookiecutter.

Adding Tests

We will now add tests for the models and the views and a few functional tests in the tests package. Tests
ensure that an application works, and that it continues to work when changes are made in the future.

Test harness

The project came bootstrapped with some tests and a basic harness. These are located in the tests
package at the top-level of the project. It is a common practice to put tests into a tests package alongside
the application package, especially as projects grow in size and complexity. A useful convention is for
each module in the application to contain a corresponding module in the tests package. The test module
would have the same name with the prefix test_.
The harness consists of the following setup:
• pytest.ini - controls basic pytest configuration, including where to find the tests. We have
configured pytest to search for tests in the application package and in the tests package.
• .coveragerc - controls coverage config. In our setup, it works with the pytest-cov plugin
that we use via the --cov options to the pytest command.
• testing.ini - a mirror of development.ini and production.ini that contains settings
used for executing the test suite. Most importantly, it contains the database connection information
used by tests that require the database.
• tests_require in setup.py - controls the dependencies installed when testing. When the
list is changed, it is necessary to re-run $VENV/bin/pip install -e ".[testing]" to
ensure the new dependencies are installed.
• tests/conftest.py - the core fixtures available throughout our tests. The fixtures are ex-
plained in more detail in the following sections. Open tests/conftest.py and follow along.

0.2. Tutorials 313


The Pyramid Web Framework, Version 2.0.2

Session-scoped test fixtures

• app_settings - the settings dict parsed from the testing.ini file that would normally be
passed by pserve into your app’s main function.

• app - the Pyramid WSGI application, implementing the pyramid.interfaces.IRouter in-


terface. Most commonly this would be used for functional tests.

Per-test fixtures

• tm - a transaction.TransactionManager object controlling a transaction lifecycle. Gen-


erally other fixtures would join to the tm fixture to control their lifecycle and ensure they are aborted
at the end of the test.

• testapp - a webtest.TestApp instance wrapping the app and is used to sending requests
into the application and return full response objects that can be inspected. The testapp is able
to mutate the request environ such that the tm fixture is injected and used by any code that touches
request.tm. This should join the request.root ZODB model to the transaction manager as
well, to enable rolling back changes to the database. The testapp maintains a cookiejar, so it can
be used to share state across requests, as well as the transaction database connection.

• app_request - a pyramid.request.Request object that can be used for more lightweight


tests versus the full testapp. The app_request can be passed to view functions and other code
that need a fully functional request object.

• dummy_request - a pyramid.testing.DummyRequest object that is very lightweight.


This is a great object to pass to view functions that have minimal side-effects as it will be fast and
simple.

Unit tests

We can test individual APIs within our codebase to ensure they fulfill the expected contract that the rest of
the application expects. For example, we will test the password hashing features we added to tutorial.
security and the rest of our models.

Create tests/test_models.py such that it appears as follows:

314 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from tutorial import models


2

3 def test_page_model():
4 instance = models.Page(data='some data')
5 assert instance.data == 'some data'
6

7 def test_wiki_model():
8 wiki = models.Wiki()
9 assert wiki.__parent__ is None
10 assert wiki.__name__ is None
11

12 def test_appmaker():
13 root = {}
14 models.appmaker(root)
15 assert root['app_root']['FrontPage'].data == 'This is the front page'
16

17 def test_password_hashing():
18 from tutorial.security import hash_password, check_password
19

20 password = 'secretpassword'
21 hashed_password = hash_password(password)
22 assert check_password(hashed_password, password)
23 assert not check_password(hashed_password, 'attackerpassword')
24 assert not check_password(None, password)

Integration tests

We can directly execute the view code, bypassing Pyramid and testing just the code that we have written.
These tests use dummy requests that we will prepare appropriately to set the conditions each view expects.

Update tests/test_views.py such that it appears as follows:

1 from pyramid import testing


2

4 class Test_view_wiki:
5 def test_it_redirects_to_front_page(self):
6 from tutorial.views.default import view_wiki
7 context = testing.DummyResource()
8 request = testing.DummyRequest()
9 response = view_wiki(context, request)
10 assert response.location == 'http://example.com/FrontPage'
(continues on next page)

0.2. Tutorials 315


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


11

12 class Test_view_page:
13 def _callFUT(self, context, request):
14 from tutorial.views.default import view_page
15 return view_page(context, request)
16

17 def test_it(self):
18 wiki = testing.DummyResource()
19 wiki['IDoExist'] = testing.DummyResource()
20 context = testing.DummyResource(data='Hello CruelWorld IDoExist')
21 context.__parent__ = wiki
22 context.__name__ = 'thepage'
23 request = testing.DummyRequest()
24 info = self._callFUT(context, request)
25 assert info['page'] == context
26 assert info['page_text'] == (
27 '<div class="document">\n'
28 '<p>Hello <a href="http://example.com/add_page/CruelWorld">'
29 'CruelWorld</a> '
30 '<a href="http://example.com/IDoExist/">'
31 'IDoExist</a>'
32 '</p>\n</div>\n')
33 assert info['edit_url'] == 'http://example.com/thepage/edit_page'
34

35

36 class Test_add_page:
37 def _callFUT(self, context, request):
38 from tutorial.views.default import add_page
39 return add_page(context, request)
40

41 def test_it_notsubmitted(self):
42 context = testing.DummyResource()
43 request = testing.DummyRequest()
44 request.subpath = ['AnotherPage']
45 info = self._callFUT(context, request)
46 assert info['page'].data == ''
47 assert info['save_url'] == request.resource_url(
48 context, 'add_page', 'AnotherPage')
49

50 def test_it_submitted(self):
51 context = testing.DummyResource()
52 request = testing.DummyRequest({
53 'form.submitted': True,
54 'body': 'Hello yo!',
55 })
(continues on next page)

316 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


56 request.subpath = ['AnotherPage']
57 self._callFUT(context, request)
58 page = context['AnotherPage']
59 assert page.data == 'Hello yo!'
60 assert page.__name__ == 'AnotherPage'
61 assert page.__parent__ == context
62

63 class Test_edit_page:
64 def _callFUT(self, context, request):
65 from tutorial.views.default import edit_page
66 return edit_page(context, request)
67

68 def test_it_notsubmitted(self):
69 context = testing.DummyResource()
70 request = testing.DummyRequest()
71 info = self._callFUT(context, request)
72 assert info['page'] == context
73 assert info['save_url'] == request.resource_url(context, 'edit_page
,→ ')
74

75 def test_it_submitted(self):
76 context = testing.DummyResource()
77 request = testing.DummyRequest({
78 'form.submitted': True,
79 'body': 'Hello yo!',
80 })
81 response = self._callFUT(context, request)
82 assert response.location == 'http://example.com/'
83 assert context.data == 'Hello yo!'

Functional tests

We will test the whole application, covering security aspects that are not tested in the unit and integration
tests, like logging in, logging out, checking that the basic user cannot edit pages that it did not create,
but that the editor user can, and so on.

Update tests/test_functional.py such that it appears as follows:

1 viewer_login = (
2 '/login?login=viewer&password=viewer'
3 '&came_from=FrontPage&form.submitted=Login'
(continues on next page)

0.2. Tutorials 317


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


4 )
5 viewer_wrong_login = (
6 '/login?login=viewer&password=incorrect'
7 '&came_from=FrontPage&form.submitted=Login'
8 )
9 editor_login = (
10 '/login?login=editor&password=editor'
11 '&came_from=FrontPage&form.submitted=Login'
12 )
13

14 def test_root(testapp):
15 res = testapp.get('/', status=303)
16 assert res.location == 'http://example.com/FrontPage'
17

18 def test_FrontPage(testapp):
19 res = testapp.get('/FrontPage', status=200)
20 assert b'FrontPage' in res.body
21

22 def test_missing_page(testapp):
23 res = testapp.get('/SomePage', status=404)
24 assert b'Not Found' in res.body
25

26 def test_referrer_is_login(testapp):
27 res = testapp.get('/login', status=200)
28 assert b'name="came_from" value="/"' in res.body
29

30 def test_successful_log_in(testapp):
31 res = testapp.get(viewer_login, status=303)
32 assert res.location == 'http://example.com/FrontPage'
33

34 def test_failed_log_in(testapp):
35 res = testapp.get(viewer_wrong_login, status=400)
36 assert b'login' in res.body
37

38 def test_logout_link_present_when_logged_in(testapp):
39 res = testapp.get(viewer_login, status=303)
40 res = testapp.get('/FrontPage', status=200)
41 assert b'Logout' in res.body
42

43 def test_logout_link_not_present_after_logged_out(testapp):
44 res = testapp.get(viewer_login, status=303)
45 res = testapp.get('/FrontPage', status=200)
46 res = testapp.get('/logout', status=303)
47 assert b'Logout' not in res.body
48

(continues on next page)

318 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


49 def test_anonymous_user_cannot_edit(testapp):
50 res = testapp.get('/FrontPage/edit_page', status=200)
51 assert b'Login' in res.body
52

53 def test_anonymous_user_cannot_add(testapp):
54 res = testapp.get('/add_page/NewPage', status=200)
55 assert b'Login' in res.body
56

57 def test_viewer_user_cannot_edit(testapp):
58 res = testapp.get(viewer_login, status=303)
59 res = testapp.get('/FrontPage/edit_page', status=200)
60 assert b'Login' in res.body
61

62 def test_viewer_user_cannot_add(testapp):
63 res = testapp.get(viewer_login, status=303)
64 res = testapp.get('/add_page/NewPage', status=200)
65 assert b'Login' in res.body
66

67 def test_editors_member_user_can_edit(testapp):
68 res = testapp.get(editor_login, status=303)
69 res = testapp.get('/FrontPage/edit_page', status=200)
70 assert b'Editing' in res.body
71

72 def test_editors_member_user_can_add(testapp):
73 res = testapp.get(editor_login, status=303)
74 res = testapp.get('/add_page/NewPage', status=200)
75 assert b'Editing' in res.body
76

77 def test_editors_member_user_can_view(testapp):
78 res = testapp.get(editor_login, status=303)
79 res = testapp.get('/FrontPage', status=200)
80 assert b'FrontPage' in res.body

Running the tests

We can run these tests by using pytest similarly to how we did in Run the tests. Courtesy of the cook-
iecutter, our testing dependencies have already been satisfied. pytest and coverage have already been
configured. We can jump right to running tests.

On Unix:

0.2. Tutorials 319


The Pyramid Web Framework, Version 2.0.2

$VENV/bin/pytest -q

On Windows:

%VENV%\Scripts\pytest -q

The expected result should look like the following:

.........................
25 passed in 3.87 seconds

Distributing Your Application

Once your application works properly, you can create a distribution from it by using the setup.py
sdist command. The following commands assume your current working directory contains the tuto-
rial package and the setup.py file.

On Unix:

$VENV/bin/python setup.py sdist

On Windows:

%VENV%\Scripts\python setup.py sdist

The output of such a command will be something like:

running sdist
# more output
creating dist
Creating tar archive
removing 'tutorial-0.0' (and everything under it)

This command creates a subdirectory named dist. Inside that is a tarball named tutorial-0.0.
tar.gz, which is the distribution of your application. You can send this file to your friends to show them
your cool new application. They should be able to install it by pointing the pip install command
directly at it. Or you can upload it to PyPI and share it with the rest of the world, where it can be downloaded
via pip install remotely like any other package people download from PyPI.

320 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.2.5 Running a Pyramid Application under mod_wsgi

mod_wsgi is an Apache module developed by Graham Dumpleton. It allows WSGI programs to be served
using the Apache web server.

This guide will outline broad steps that can be used to get a Pyramid application running under Apache via
mod_wsgi. This particular tutorial was developed under Apple’s macOS platform (Snow Leopard, on a
32-bit Mac), but the instructions should be largely the same for all systems, delta specific path information
for commands and files.

Unfortunately these instructions almost certainly won’t work for deploying a Pyramid application on
a Windows system using mod_wsgi. If you have experience with Pyramid and mod_wsgi on Windows
systems, please help us document this experience by submitting documentation to the Pylons-devel maillist.

1. The tutorial assumes you have Apache already installed on your system. If you do not, install Apache
2.X for your platform in whatever manner makes sense.

2. It is also assumed that you have satisfied the Requirements for Installing Packages.

3. Once you have Apache installed, install mod_wsgi. Use the (excellent) installation instructions for
your platform into your system’s Apache installation.

4. Create a Pyramid application using our cookiecutter. See Creating a Pyramid Project for more
in-depth information about creating a new project.

cd ~
cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 2.0-
,→branch

If prompted for the first item, accept the default yes by hitting return.

You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.


Is it okay to delete and re-clone it? [yes]: yes
project_name [Pyramid Scaffold]: myproject
repo_name [myproject]: myproject
Select template_language:
1 - jinja2
2 - chameleon
3 - mako
Choose from 1, 2, 3 [1]: 1
(continues on next page)

0.2. Tutorials 321


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


Select backend:
1 - none
2 - sqlalchemy
3 - zodb
Choose from 1, 2, 3 [1]: 1

5. Create a virtual environment which we’ll use to install our application. It is important to use the
same base Python interpreter that was used to build mod_wsgi. For example, if mod_wsgi was
built against the system Python 3.x, then your project should use a virtual environment created from
that same system Python 3.x.

cd myproject
python3 -m venv env

6. Install your Pyramid application and its dependencies.

env/bin/pip install -e .

7. Within the project directory (~/myproject), create a script named pyramid.wsgi. Give it
these contents:

from pyramid.paster import get_app, setup_logging


ini_path = '/Users/chrism/myproject/production.ini'
setup_logging(ini_path)
application = get_app(ini_path, 'main')

The first argument to pyramid.paster.get_app() is the project configuration file name.


It’s best to use the production.ini file provided by your cookiecutter, as it contains settings
appropriate for production. The second is the name of the section within the .ini file that should
be loaded by mod_wsgi. The assignment to the name application is important: mod_wsgi
requires finding such an assignment when it opens the file.

The call to pyramid.paster.setup_logging() initializes the standard library’s logging


module to allow logging within your application. See Logging Configuration.

There is no need to make the pyramid.wsgi script executable. However, you’ll need to make sure
that two users have access to change into the ~/myproject directory: your current user (mine is
chrism and the user that Apache will run as often named apache or httpd). Make sure both of
these users can ”cd” into that directory.

322 CONTENTS
The Pyramid Web Framework, Version 2.0.2

8. Edit your Apache configuration and add some stuff. I happened to create a file named /etc/
apache2/other/modwsgi.conf on my own system while installing Apache, so this stuff went
in there.

# Use only 1 Python sub-interpreter. Multiple sub-interpreters


# play badly with C extensions. See
# http://stackoverflow.com/a/10558360/209039
WSGIApplicationGroup %{GLOBAL}
WSGIPassAuthorization On
WSGIDaemonProcess pyramid user=chrism group=staff threads=4 \
python-path=/Users/chrism/myproject/env/lib/python3.8/site-packages
WSGIScriptAlias /myapp /Users/chrism/myproject/pyramid.wsgi

<Directory /Users/chrism/myproject>
WSGIProcessGroup pyramid
Require all granted
</Directory>

9. Restart Apache

sudo /usr/sbin/apachectl restart

10. Visit http://localhost/myapp in a browser. You should see the sample application rendered
in your browser.

mod_wsgi has many knobs and a great variety of deployment modes. This is just one representation of
how you might use it to serve up a Pyramid application. See the mod_wsgi configuration documentation
for more in-depth configuration information.

0.3 Narrative Documentation

0.3.1 Pyramid Introduction

Pyramid is a Python web application framework. It is designed to make creating web applications easier.
It is open source.

0.3. Narrative Documentation 323


The Pyramid Web Framework, Version 2.0.2

What Is a Framework?

A framework provides capabilities that developers can enhance or extend. A web application framework
provides many of the common needs of building web applications allowing developers to concentrate
only on the parts that are specific to their application.

Every framework makes choices about how a particular problem should be solved. When developers
choose to use a framework, they cede control over the portions of their application that are provided
by the framework. It is possible to write a complete web application without any framework, by using
Python libraries. In practice, however, it is often more practical to use a framework, so long as your
chosen framework fits the requirements of your application.

Pyramid follows these design and engineering principles:

Simplicity
Pyramid is designed to be easy to use. You can get started even if you don’t understand it all. And
when you’re ready to do more, Pyramid will be there for you.

Minimalism
Out of the box, Pyramid provides only the core tools needed for nearly all web applications: mapping
URLs to code, security, and serving static assets (files like JavaScript and CSS). Additional tools
provide templating, database integration and more. But with Pyramid you can ”pay only for what
you eat”.

Documentation
Pyramid is committed to comprehensive and up-to-date documentation.

Speed
Pyramid is designed to be noticeably fast.

Reliability
Pyramid is developed conservatively and tested exhaustively. Our motto is: ”If it ain’t tested, it’s
broke”.

Openness
As with Python, the Pyramid software is distributed under a permissive open source license.

Why Pyramid?

In a world filled with web frameworks, why should you choose Pyramid?

324 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Modern

Pyramid is fully compatible with Python 3. If you develop a Pyramid application today, you can rest
assured that you’ll be able to use the most modern features of your favorite language. And in the years to
come, you’ll continue to be working on a framework that is up-to-date and forward-looking.

Tested

Untested code is broken by design. The Pyramid community has a strong testing culture and our framework
reflects that. Every release of Pyramid has 100% statement coverage (as measured by coverage) and 95%
decision/condition coverage. (as measured by instrumental) It is automatically tested using Travis and
Jenkins on supported versions of Python after each commit to its GitHub repository. Official Pyramid
add-ons are held to a similar testing standard.

We still find bugs in Pyramid, but we’ve noticed we find a lot fewer of them while working on projects
with a solid testing regime.

Documented

The Pyramid documentation is comprehensive. We strive to keep our narrative documentation both com-
plete and friendly to newcomers. We also maintain the Pyramid Community Cookbook of recipes demon-
strating common scenarios you might face. Contributions in the form of improvements to our documenta-
tion are always appreciated. And we always welcome improvements to our official tutorials as well as new
contributions to our community maintained tutorials.

Supported

You can get help quickly with Pyramid. It’s our goal that no Pyramid question go unanswered. Whether
you ask a question on IRC, on the Pylons-discuss mailing list, or on StackOverflow, you’re likely to get a
reasonably prompt response.

Pyramid is also a welcoming, friendly space for newcomers. We don’t tolerate ”support trolls” or those
who enjoy berating fellow users in our support channels. We try to keep it well-lit and new-user-friendly.

See also:

See also our #pyramid IRC channel, our pylons-discuss mailing list, and support-and-development.

0.3. Narrative Documentation 325


The Pyramid Web Framework, Version 2.0.2

What makes Pyramid unique

There are many tools available for web development. What would make someone want to use Pyramid
instead? What makes Pyramid unique?

With Pyramid you can write very small applications without needing to know a lot. And by learning a bit
more, you can write very large applications too. Pyramid will allow you to become productive quickly, and
will grow with you. It won’t hold you back when your application is small, and it won’t get in your way
when your application becomes large. Other application frameworks seem to fall into two non-overlapping
categories: those that support ”small apps” and those designed for ”big apps”.

We don’t believe you should have to make this choice. You can’t really know how large your application
will become. You certainly shouldn’t have to rewrite a small application in another framework when it
gets ”too big”. A well-designed framework should be able to be good at both. Pyramid is that kind of
framework.

Pyramid provides a set of features that are unique among Python web frameworks. Others may provide
some, but only Pyramid provides them all, in one place, fully documented, and à la carte without needing
to pay for the whole banquet.

Build single-file applications

You can write a Pyramid application that lives entirely in one Python file. Such an application is easy to
understand since everything is in one place. It is easy to deploy because you don’t need to know much
about Python packaging. Pyramid allows you to do almost everything that so-called microframeworks can
in very similar ways.

from wsgiref.simple_server import make_server


from pyramid.config import Configurator
from pyramid.response import Response

def hello_world(request):
return Response('Hello World!')

if __name__ == '__main__':
with Configurator() as config:
config.add_route('hello', '/')
config.add_view(hello_world, route_name='hello')
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 6543, app)
server.serve_forever()

326 CONTENTS
The Pyramid Web Framework, Version 2.0.2

See also:

See also Creating Your First Pyramid Application.

Configure applications with decorators

Pyramid allows you to keep your configuration right next to your code. That way you don’t have to switch
files to see your configuration. For example:

from pyramid.view import view_config


from pyramid.response import Response

@view_config(route_name='fred')
def fred_view(request):
return Response('fred')

However, using Pyramid configuration decorators does not change your code. It remains easy to extend,
test, or reuse. You can test your code as if the decorators were not there. You can instruct the framework
to ignore some decorators. You can even use an imperative style to write your configuration, skipping
decorators entirely.

See also:

See also Adding View Configuration Using the @view_config Decorator.

Generate application URLs

Dynamic web applications produce URLs that can change depending on what you are viewing. Pyramid
provides flexible, consistent, easy to use tools for generating URLs. When you use these tools to write
your application, you can change your configuration without fear of breaking links in your web pages.

See also:

See also Generating Route URLs.

0.3. Narrative Documentation 327


The Pyramid Web Framework, Version 2.0.2

Serve static assets

Web applications often require JavaScript, CSS, images and other so-called static assets. Pyramid provides
flexible tools for serving these kinds of files. You can serve them directly from Pyramid, or host them on
an external server or CDN (content delivery network). Either way, Pyramid can help you to generate URLs
so you can change where your files come from without changing any code.

See also:

See also Serving Static Assets.

Develop interactively

Pyramid can automatically detect changes you make to template files and code, so your changes are im-
mediately available in your browser. You can debug using plain old print() calls, which will display to
your console.

Pyramid has a debug toolbar that allows you to see information about how your application is working
right in your browser. See configuration, installed packages, SQL queries, logging statements and more.

When your application has an error, an interactive debugger allows you to poke around from your browser
to find out what happened.

To use the Pyramid debug toolbar, build your project with our cookiecutter.

See also:

See also The Debug Toolbar.

Debug with power

When things go wrong, Pyramid gives you powerful ways to fix the problem.

You can configure Pyramid to print helpful information to the console. The debug_notfound setting
shows information about URLs that aren’t matched. The debug_authorization setting provides
helpful messages about why you aren’t allowed to do what you just tried.

Pyramid also has command line tools to help you verify your configuration. You can use proutes and
pviews to inspect how URLs are connected to your application code.

See also:

See also Debugging View Authorization Failures, Command-Line Pyramid, and p* Scripts Documentation

328 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Extend your application

Pyramid add-ons extend the core of the framework with useful abilities. There are add-ons available for
your favorite template language, SQL and NoSQL databases, authentication services and more.

Supported Pyramid add-ons are held to the same demanding standards as the framework itself. You will
find them to be fully tested and well documented.

See also:

See also https://trypyramid.com/extending-pyramid.html

Write your views, your way

A fundamental task for any framework is to map URLs to code. In Pyramid, that code is called a view
callable. View callables can be functions, class methods or even callable class instances. You are free to
choose the approach that best fits your use case. Regardless of your choice, Pyramid treats them the same.
You can change your mind at any time without any penalty. There are no artificial distinctions between the
various approaches.

Here’s a view callable defined as a function:

1 from pyramid.response import Response


2 from pyramid.view import view_config
3

4 @view_config(route_name='aview')
5 def aview(request):
6 return Response('one')

Here’s a few views defined as methods of a class instead:

1 from pyramid.response import Response


2 from pyramid.view import view_config
3

4 class AView(object):
5 def __init__(self, request):
6 self.request = request
7

8 @view_config(route_name='view_one')
9 def view_one(self):
(continues on next page)

0.3. Narrative Documentation 329


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


10 return Response('one')
11

12 @view_config(route_name='view_two')
13 def view_two(self):
14 return Response('two')

See also:

See also @view_config Placement.

Find your static assets

In many web frameworks, the static assets required by an application are kept in a globally shared location,
”the static directory”. Others use a lookup scheme, like an ordered set of template directories. Both of
these approaches have problems when it comes to customization.

Pyramid takes a different approach. Static assets are located using asset specifications, strings that contain
reference both to a Python package name and a file or directory name, e.g. MyPackage:static/
index.html. These specifications are used for templates, JavaScript and CSS, translation files, and any
other package-bound static resource. By using asset specifications, Pyramid makes it easy to extend your
application with other packages without worrying about conflicts.

What happens if another Pyramid package you are using provides an asset you need to customize? Maybe
that page template needs better HTML, or you want to update some CSS. With asset specifications you
can override the assets from other packages using simple wrappers.

Examples: Understanding Asset Specifications and Overriding Assets.

Use your templates

In Pyramid, the job of creating a Response belongs to a renderer. Any templating system—Mako,
Chameleon, Jinja2—can be a renderer. In fact, packages exist for all of these systems. But if you’d rather
use another, a structured API exists allowing you to create a renderer using your favorite templating system.
You can use the templating system you understand, not one required by the framework.

What’s more, Pyramid does not make you use a single templating system exclusively. You can use multiple
templating systems, even in the same project.

Example: Using Templates Directly.

330 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Write testable views

When you use a renderer with your view callable, you are freed from needing to return a ”webby” Re-
sponse object. Instead your views can return a simple Python dictionary. Pyramid will take care of
rendering the information in that dictionary to a Response on your behalf. As a result, your views are
more easily tested, since you don’t need to parse HTML to evaluate the results. Pyramid makes it a snap
to write unit tests for your views, instead of requiring you to use functional tests.

For example, a typical web framework might return a Response object from a render_to_response
call:

1 from pyramid.renderers import render_to_response


2

3 def myview(request):
4 return render_to_response('myapp:templates/mytemplate.pt', {'a':1},
5 request=request)

While you can do this in Pyramid, you can also return a Python dictionary:

1 from pyramid.view import view_config


2

3 @view_config(renderer='myapp:templates/mytemplate.pt')
4 def myview(request):
5 return {'a':1}

By configuring your view to use a renderer, you tell Pyramid to use the {'a':1} dictionary and the
specified template to render a response on your behalf.

The string passed as renderer= above is an asset specification. Asset specifications are widely used in
Pyramid. They allow for more reliable customization. See Find your static assets for more information.

Example: Renderers.

Use events to coordinate actions

When writing web applications, it is often important to have your code run at a specific point in the lifecycle
of a request. In Pyramid, you can accomplish this using subscribers and events.

For example, you might have a job that needs to be done each time your application handles a new request.
Pyramid emits a NewRequest event at this point in the request handling lifecycle. You can register your
code as a subscriber to this event using a clear, declarative style:

0.3. Narrative Documentation 331


The Pyramid Web Framework, Version 2.0.2

from pyramid.events import NewRequest


from pyramid.events import subscriber

@subscriber(NewRequest)
def my_job(event):
do_something(event.request)

Pyramid’s event system can be extended as well. If you need, you can create events of your own and send
them using Pyramid’s event system. Then anyone working with your application can subscribe to your
events and coordinate their code with yours.

Example: Using Events and Event Types.

Build international applications

Pyramid ships with internationalization-related features in its core: localization, pluralization, and creating
message catalogs from source files and templates. Pyramid allows for a plurality of message catalogs via
the use of translation domains. You can create a system that has its own translations without conflict with
other translations in other domains.

Example: Internationalization and Localization.

Build efficient applications

Pyramid provides an easy way to cache the results of slow or expensive views. You can indicate in view
configuration that you want a view to be cached:

@view_config(http_cache=3600) # 60 minutes
def myview(request):
# ...

Pyramid will automatically add the appropriate Cache-Control and Expires headers to the response
it creates.

See the add_view() method’s http_cache documentation for more information.

332 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Build fast applications

The Pyramid core is fast. It has been engineered from the ground up for speed. It only does as much
work as absolutely necessary when you ask it to get a job done. If you need speed from your application,
Pyramid is the right choice for you.

Example: https://blog.curiasolutions.com/pages/the-great-web-framework-shootout.html

Store session data

Pyramid has built-in support for HTTP sessions, so you can associate data with specific users between
requests. Lots of other frameworks also support sessions. But Pyramid allows you to plug in your own
custom sessioning system. So long as your system conforms to a documented interface, you can drop it in
in place of the provided system.

Currently there is a binding package for the third-party Redis sessioning system that does exactly this. But
if you have a specialized need (perhaps you want to store your session data in MongoDB), you can. You
can even switch between implementations without changing your application code.

Example: Sessions.

Handle problems with grace

Mistakes happen. Problems crop up. No one writes bug-free code. Pyramid‘provides a way to handle the
exceptions your code encounters. An :term:‘exception view is a special kind of view which is automatically
called when a particular exception type arises without being handled by your application.

For example, you might register an exception view for the Exception exception type, which will catch
all exceptions, and present a pretty ”well, this is embarrassing” page. Or you might choose to register an
exception view for only certain application-specific exceptions. You can make one for when a file is not
found, or when the user doesn’t have permission to do something. In the former case, you can show a
pretty ”Not Found” page; in the latter case you might show a login form.

Example: Custom Exception Views.

And much, much more...

Pyramid has been built with a number of other sophisticated design features that make it adaptable. Read
more about them below.

0.3. Narrative Documentation 333


The Pyramid Web Framework, Version 2.0.2

Advanced Pyramid Design Features

Pyramid has been built from the ground up to avoid the problems that other frameworks can suffer.

You Don’t Need Singletons

Have you ever struggled with parameterizing Django’s settings.py file for multiple installations of the
same Django application? Have you ever needed to monkey-patch a framework fixture to get it to behave
properly for your use case? Have you ever tried to deploy your application using an asynchronous server
and failed?

All these problems are symptoms of mutable global state, also known as import time side effects and arise
from the use of singleton data structures.

Pyramid is written so that you don’t run into these types of problems. It is even possible to run multiple
copies of the same Pyramid application configured differently within a single Python process. This makes
running Pyramid in shared hosting environments a snap.

Simplify your View Code with Predicates

How many times have you found yourself beginning the logic of your view code with something like this:

1 if request.user.is_authenticated:
2 # do one thing
3 else:
4 # do something else

Unlike many other systems, Pyramid allows you to associate more than one view with a single route. For
example, you can create a route with the pattern /items and when the route is matched, you can send the
request to one view if the request method is GET, another view if the request method is POST, and so on.

Pyramid uses a system of view predicates to allow this. Matching the request method is one basic thing
you can do with a view predicate. You can also associate views with other request parameters, such as
elements in the query string, the Accept header, whether the request is an AJAX (XHR) request or not, and
lots of other things.

For our example above, you can do this instead:

334 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 @view_config(route_name="items", is_authenticated=True)
2 def auth_view(request):
3 # do one thing
4

5 @view_config(route_name="items")
6 def anon_view(request):
7 # do something else

This approach allows you to develop view code that is simpler, more easily understandable, and more
directly testable.

See also:

See also View Configuration Parameters.

Stop Worrying About Transactions

Pyramid’s cookiecutter renders projects that include a transaction management system. When you use
this system, you can stop worrying about when to commit your changes, Pyramid handles it for you. The
system will commit at the end of a request or abort if there was an exception.

Why is that a good thing? Imagine a situation where you manually commit a change to your persistence
layer. It’s very likely that other framework code will run after your changes are done. If an error happens
in that other code, you can easily wind up with inconsistent data if you’re not extremely careful.

Using transaction management saves you from needing to think about this. Either a request completes
successfully and all changes are committed, or it does not and all changes are aborted.

Pyramid’s transaction management is extendable, so you can synchronize commits between multiple
databases or databases of different kinds. It also allows you to do things like conditionally send email
if a transaction is committed, but otherwise keep quiet.

See also:

See also SQLAlchemy + URL dispatch wiki tutorial (note the lack of commit statements anywhere in
application code).

0.3. Narrative Documentation 335


The Pyramid Web Framework, Version 2.0.2

Stop Worrying About Configuration

When a system is small, it’s reasonably easy to keep it all in your head. But as systems grow large, con-
figuration grows more complex. Your app may grow to have hundreds or even thousands of configuration
statements.

Pyramid’s configuration system keeps track of each of your statements. If you accidentally add two that
are identical, or Pyramid can’t make sense out of what it would mean to have both statements active at the
same time, it will complain loudly at startup time.

Pyramid’s configuration system is not dumb though. If you use the include() system, it can automat-
ically resolve conflicts on its own. More local statements are preferred over less local ones. So you can
intelligently factor large systems into smaller ones.

See also:

See also Conflict Detection.

Compose Powerful Apps From Simple Parts

Speaking of the Pyramid structured include() mechanism, it allows you to compose complex appli-
cations from multiple, simple Python packages. All the configuration statements that can be performed
in your main Pyramid application can also be used in included packages. You can add views, routes, and
subscribers, and even set authentication and authorization policies.

If you need, you can extend or override the configuration of an existing application by including its con-
figuration in your own and then modifying it.

For example, if you want to reuse an existing application that already has a bunch of routes, you can just
use the include statement with a route_prefix. All the routes of that application will be available,
prefixed as you requested:

1 from pyramid.config import Configurator


2

3 if __name__ == '__main__':
4 config = Configurator()
5 config.include('pyramid_jinja2')
6 config.include('pyramid_exclog')
7 config.include('some.other.package', route_prefix='/somethingelse')

See also:

See also Including Configuration from External Sources and Rules for Building an Extensible Application.

336 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Authenticate Users Your Way

Pyramid has a powerful security system that can be tailored to your needs. Build your own security policy
tailored to your needs, or use one of the many helpers provided to easily implement common authentication
and authorization patterns.

See also:

See also Writing a Security Policy.

Build Trees of Resources

Pyramid supports traversal, a way of mapping URLs to a concrete resource tree. If your application
naturally consists of an arbitrary hierarchy of different types of content (like a CMS or a Document Man-
agement System), traversal is for you. If you have a requirement for a highly granular security model (”Jane
can edit documents in this folder, but not that one”), traversal can be a powerful approach.

See also:

See also Hello Traversal World and Much Ado About Traversal.

Take Action on Each Request with Tweens

Pyramid has a system for applying an arbitrary action to each request or response called a tween. The
system is similar in concept to WSGI middleware, but can be more useful since tweens run in the Pyramid
context, and have access to templates, request objects, and other niceties.

The Pyramid debug toolbar is a tween, as is the pyramid_tm transaction manager.

See also:

See also Registering Tweens.

Return What You Want From Your Views

We have shown elsewhere (in the Pyramid Introduction) how using a renderer allows you to return simple
Python dictionaries from your view code. But some frameworks allow you to return strings or tuples
from view callables. When frameworks allow for this, code looks slightly prettier because there are fewer
imports and less code. For example, compare this:

0.3. Narrative Documentation 337


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.response import Response


2

3 def aview(request):
4 return Response("Hello world!")

To this:

1 def aview(request):
2 return "Hello world!"

Nicer to look at, right?

Out of the box, Pyramid will raise an exception if you try to run the second example above. After all, a
view should return a response, and ”explicit is better than implicit”.

But if you’re a developer who likes the aesthetics of simplicity, Pyramid provides a way to support this sort
of thing, the response adapter:

1 from pyramid.config import Configurator


2 from pyramid.response import Response
3

4 def string_response_adapter(s):
5 response = Response(s)
6 response.content_type = 'text/html'
7 return response

A new response adapter is registered in configuration:

1 if __name__ == '__main__':
2 config = Configurator()
3 config.add_response_adapter(string_response_adapter, str)

With that, you may return strings from any of your view callables, e.g.:

1 def helloview(request):
2 return "Hello world!"
3

4 def goodbyeview(request):
5 return "Goodbye world!"

You can even use a response adapter to allow for custom content types and return codes:

338 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.config import Configurator


2

3 def tuple_response_adapter(val):
4 status_int, content_type, body = val
5 response = Response(body)
6 response.content_type = content_type
7 response.status_int = status_int
8 return response
9

10 def string_response_adapter(body):
11 response = Response(body)
12 response.content_type = 'text/html'
13 response.status_int = 200
14 return response
15

16 if __name__ == '__main__':
17 config = Configurator()
18 config.add_response_adapter(string_response_adapter, str)
19 config.add_response_adapter(tuple_response_adapter, tuple)

With this, both of these views will work as expected:

1 def aview(request):
2 return "Hello world!"
3

4 def anotherview(request):
5 return (403, 'text/plain', "Forbidden")

See also:
See also Changing How Pyramid Treats View Responses.

Use Global Response Objects

Views have to return responses. But constructing them in view code is a chore. And perhaps registering
a response adapter as shown above is just too much work. Pyramid provides a global response object as
well. You can use it directly, if you prefer:

1 def aview(request):
2 response = request.response
3 response.body = 'Hello world!'
4 response.content_type = 'text/plain'
5 return response

0.3. Narrative Documentation 339


The Pyramid Web Framework, Version 2.0.2

See also:

See also Varying Attributes of Rendered Responses.

Extend Configuration

Perhaps the Pyramid configurator’s syntax feels a bit verbose to you. Or possibly you would like to add a
feature to configuration without asking the core developers to change Pyramid itself?

You can extend Pyramid’s configurator with your own directives. For example, let’s say you find yourself
calling pyramid.config.Configurator.add_view() repetitively. Usually you can get rid of
the boring with existing shortcuts, but let’s say that this is a case where there is no such shortcut:

1 from pyramid.config import Configurator


2

3 config = Configurator()
4 config.add_route('xhr_route', '/xhr/{id}')
5 config.add_view('my.package.GET_view', route_name='xhr_route', xhr=True,
6 permission='view', request_method='GET')
7 config.add_view('my.package.POST_view', route_name='xhr_route', xhr=True,
8 permission='view', request_method='POST')
9 config.add_view('my.package.HEAD_view', route_name='xhr_route', xhr=True,
10 permission='view', request_method='HEAD')

Pretty tedious right? You can add a directive to the Pyramid configurator to automate some of the tedium
away:

1 from pyramid.config import Configurator


2

3 def add_protected_xhr_views(config, module):


4 module = config.maybe_dotted(module)
5 for method in ('GET', 'POST', 'HEAD'):
6 view = getattr(module, 'xhr_%s_view' % method, None)
7 if view is not None:
8 config.add_view(view, route_name='xhr_route', xhr=True,
9 permission='view', request_method=method)
10

11 config = Configurator()
12 config.add_directive('add_protected_xhr_views', add_protected_xhr_views)

Once that’s done, you can call the directive you’ve just added as a method of the configurator object:

340 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 config.add_route('xhr_route', '/xhr/{id}')
2 config.add_protected_xhr_views('my.package')

Much better!

You can share your configuration code with others, too. Add your code to a Python package. Put the call
to add_directive() in a function. When other programmers install your package, they’ll be able to
use your configuration by passing your function to a call to include().

See also:

See also Adding Methods to the Configurator via add_directive.

Introspect Your Application

If you’re building a large, pluggable system, it’s useful to be able to get a list of what has been plugged in
at application runtime. For example, you might want to show users a set of tabs at the top of the screen
based on a list of the views they registered.

Pyramid provides an introspector for just this purpose.

Here’s an example of using Pyramid’s introspector from within a view:

1 from pyramid.view import view_config


2 from pyramid.response import Response
3

4 @view_config(route_name='bar')
5 def show_current_route_pattern(request):
6 introspector = request.registry.introspector
7 route_name = request.matched_route.name
8 route_intr = introspector.get('routes', route_name)
9 return Response(str(route_intr['pattern']))

See also:

See also Pyramid Configuration Introspection.

0.3. Narrative Documentation 341


The Pyramid Web Framework, Version 2.0.2

What Is The Pylons Project?

Pyramid is a member of the collection of software published under the Pylons Project. Pylons software is
written by a loose-knit community of contributors. The Pylons Project website includes details about how
Pyramid relates to the Pylons Project.

Pyramid and Other Web Frameworks

The first release of Pyramid’s predecessor (named repoze.bfg) was made in July of 2008. At the end
of 2010, we changed the name of repoze.bfg to Pyramid. It was merged into the Pylons project as
Pyramid in November of that year.

Pyramid was inspired by Zope, Pylons (version 1.0), and Django. As a result, Pyramid borrows several
concepts and features from each, combining them into a unique web framework.

Similar to Zope, Pyramid applications may easily be extended. If you work within the constraints of
the framework, you can produce applications that can be reused, modified, or extended without needing
to modify the original application code. Pyramid also inherits the concepts of traversal and declarative
security from Zope.

Similar to Pylons version 1.0, Pyramid is largely free of policy. It makes no assertions about which database
or template system you should use. You are free to use whatever third-party components fit the needs of
your specific application. Pyramid also inherits its approach to URL dispatch from Pylons.

Similar to Django, Pyramid values extensive documentation. In addition, the concept of a view is used by
Pyramid much as it would be by Django.

Other Python web frameworks advertise themselves as members of a class of web frameworks named
model-view-controller frameworks. The authors of Pyramid do not believe that the MVC pattern fits the
web particularly well. However, if this abstraction works for you, Pyramid also generally fits into this class.

0.3.2 Installing Pyramid

This installation guide emphasizes the use of Python 3.6 and greater for simplicity.

342 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Before You Install Pyramid

Install Python version 3.6 or greater for your operating system, and satisfy the Requirements for Installing
Packages, as described in the following sections.

Python Versions

As of this writing, Pyramid is tested against Python 3.6, 3.7, 3.8, 3.9, 3.10, and 3.11 and PyPy3.

Pyramid is known to run on all popular Unix-like systems such as Linux, macOS, and FreeBSD, as well
as on Windows platforms. It is also known to run on PyPy (1.9+).

Pyramid installation does not require the compilation of any C code. However, some Pyramid dependencies
may attempt to build binary extensions from C code for performance speed ups. If a compiler or Python
headers are unavailable, the dependency will fall back to using pure Python instead.

If you see any warnings or errors related to failing to compile the binary extensions, in most cases
you may safely ignore those errors. If you wish to use the binary extensions, please verify that you have a
functioning compiler and the Python header files installed for your operating system.

For macOS Users

Python comes pre-installed on macOS, but due to Apple’s release cycle, it is often out of date. Unless you
have a need for a specific earlier version, it is recommended to install the latest 3.x version of Python.

You can install the latest version of Python for macOS from the binaries on python.org.

Alternatively, you can use the homebrew package manager.

# for python 3.x


brew install python3

If you use an installer for your Python, then you can skip to the section Installing Pyramid on a Unix
System.

0.3. Narrative Documentation 343


The Pyramid Web Framework, Version 2.0.2

If You Don’t Yet Have a Python Interpreter (Unix)

If your system doesn’t have a Python interpreter, and you’re on Unix, you can either install Python using
your operating system’s package manager or you can install Python from source fairly easily on any Unix
system that has development tools.

See also:

See the official Python documentation Using Python on Unix platforms for full details.

If You Don’t Yet Have a Python Interpreter (Windows)

If your Windows system doesn’t have a Python interpreter, you’ll need to install it by downloading a
Python 3.x-series interpreter executable from python.org’s download section (the files labeled ”Windows
Installer”). Once you’ve downloaded it, double click on the executable and select appropriate options dur-
ing the installation process. To standardize this documentation, we used the GUI installer and selected the
following options:

• Screen 1: Install Python 3.x.x (32- or 64-bit)

– Check ”Install launcher for all users (recommended)”.

– Check ”Add Python 3.x to PATH”.

– Click ”Install Now”.

• Screen 2: User Account Control

– Click ”Yes”.

See also:

See the official Python documentation Using Python on Windows for full details.

See also:

You might also need to download and install the Python for Windows extensions. Carefully read the
README.txt file at the end of the list of builds, and follow its directions. Make sure you get the proper
32- or 64-bit build and Python version.

See also:

Python launcher for Windows provides a command py that allows users to run any installed version of
Python.

344 CONTENTS
The Pyramid Web Framework, Version 2.0.2

After you install Python on Windows, you might need to add the directory where Python and
other programs—such as pip, Setuptools, and cookiecutter—are installed to your environment’s Path.
This will make it possible to invoke them from a command prompt.

To do so, search for ”Environment Variables” on your computer (on Windows 10, it is under System
Properties --> Advanced) and add that directory to the Path environment variable, using the
GUI to edit path segments.

Example segments should look like C:\Users\<username>\AppData\Local\Programs\


Python3x-32, where you have your username instead of <username>, and your version of
Python and whether it is 32- or 64-bit. Additionally ensure you have the path segment ending with
\Scripts, i.e., C:\Users\<username>\AppData\Local\Programs\Python3x-32\
Scripts, and for user-installed Python programs, %APPDATA%\Python\Python3x\Scripts.

You may need to restart your command prompt session to load the environment variables.

See also:

See Configuring Python (on Windows) for full details.

Requirements for Installing Packages

Use pip for installing packages and python3 -m venv env for creating a virtual environment. A
virtual environment is a semi-isolated Python environment that allows packages to be installed for use by
a particular application, rather than being installed system wide.

See also:

See the Python Packaging Authority’s (PyPA) documention Requirements for Installing Packages for full
details.

Installing Pyramid on a Unix System

After installing Python as described previously in For macOS Users or If You Don’t Yet Have a Python
Interpreter (Unix), and satisfying the Requirements for Installing Packages, you can now install Pyramid.

1. Make a virtual environment workspace:

0.3. Narrative Documentation 345


The Pyramid Web Framework, Version 2.0.2

export VENV=~/env
python3 -m venv $VENV

You can either follow the use of the environment variable $VENV, or replace it with the root directory
of the virtual environment. If you choose the former approach, ensure that $VENV is an absolute
path. In the latter case, the export command can be skipped.

2. (Optional) Consider using $VENV/bin/activate to make your shell environment wired to use
the virtual environment.

3. Use pip to get Pyramid and its direct dependencies installed:

$VENV/bin/pip install "pyramid==2.0.2"

Why use $VENV/bin/pip instead of source bin/activate, then pip?

$VENV/bin/pip clearly specifies that pip is run from within the virtual environment and not at the
system level.

activate makes changes to the user’s shell environment which can often be convenient. However, in the
context of long-form documentation, environment configuration can easily be forgotten. By keeping each
snippet explicit we can reduce copy / paste errors by users in which commands are executed against the
wrong Python environment. Also, deactivate might not correctly restore previous shell environment
variables. Avoiding activate keeps the environment more reproducible.

Although using source bin/activate, then pip, requires fewer key strokes to issue commands once
invoked, there are other things to consider. Michael F. Lamb (datagrok) presents a summary in Virtualenv’s
bin/activate is Doing It Wrong.

Ultimately we prefer to keep things clear and simple, so we use $VENV/bin/pip.

Installing Pyramid on a Windows System

After installing Python as described previously in If You Don’t Yet Have a Python Interpreter (Windows),
and satisfying the Requirements for Installing Packages, you can now install Pyramid.

1. Make a virtual environment workspace:

346 CONTENTS
The Pyramid Web Framework, Version 2.0.2

cd \
set VENV=c:\env
python -m venv %VENV%
cd %VENV%

You can either follow the use of the environment variable %VENV%, or replace it with the root
directory of the virtual environment. If you choose the former approach, ensure that %VENV% is an
absolute path. In the latter case, the set command can be skipped.

2. (Optional) Consider using %VENV%\Scripts\activate.bat to make your shell environment


wired to use the virtual environment.

3. Use pip to get Pyramid and its direct dependencies installed:

%VENV%\Scripts\pip install "pyramid==2.0.2"

See the note above for Why use $VENV/bin/pip instead of source bin/activate, then pip.

What Gets Installed

When you install Pyramid, various libraries such as WebOb, PasteDeploy, and others are installed.

Additionally, as chronicled in Creating a Pyramid Project, our cookiecutter will be used, which makes it
easy to start a new Pyramid project.

0.3.3 Creating Your First Pyramid Application

In this chapter, we will walk through the creation of a tiny Pyramid application. After we’re finished
creating the application, we’ll explain in more detail how it works. It assumes you already have Pyramid
installed. If you do not, head over to the Installing Pyramid section.

Hello World

Here’s one of the very simplest Pyramid applications:

0.3. Narrative Documentation 347


The Pyramid Web Framework, Version 2.0.2

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4

6 def hello_world(request):
7 return Response('Hello World!')
8

10 if __name__ == '__main__':
11 with Configurator() as config:
12 config.add_route('hello', '/')
13 config.add_view(hello_world, route_name='hello')
14 app = config.make_wsgi_app()
15 server = make_server('0.0.0.0', 6543, app)
16 server.serve_forever()

When this code is inserted into a Python script named helloworld.py and executed by a Python
interpreter which has the Pyramid software installed, an HTTP server is started on TCP port 6543.

On Unix:

$VENV/bin/python helloworld.py

On Windows:

%VENV%\Scripts\python helloworld.py

This command will not return and nothing will be printed to the console. When port 6543 is visited by
a browser on the URL /, the server will simply serve up the text ”Hello world!”. If your application is
running on your local system, using http://localhost:6543/ in a browser will show this result.

Each time you visit a URL served by the application in a browser, a logging line will be emitted to the
console displaying the hostname, the date, the request method and path, and some additional information.
This output is done by the wsgiref server we’ve used to serve this application. It logs an ”access log” in
Apache combined logging format to the console.

Press Ctrl-C (or Ctrl-Break on Windows) to stop the application.

Now that we have a rudimentary understanding of what the application does, let’s examine it piece by
piece.

348 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Imports

The above helloworld.py script uses the following set of import statements:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response

Like many other Python web frameworks, Pyramid uses the WSGI protocol to connect an application and
a web server together. The wsgiref server is used in this example as a WSGI server for convenience, as
it is shipped within the Python standard library.

The script imports the Configurator class from the pyramid.config module. An instance of the
Configurator class is later used to configure your Pyramid application.

The script also imports the pyramid.response.Response class for later use. An instance of this
class will be used to create a web response.

View Callable Declarations

The above script, beneath its set of imports, defines a function named hello_world.

6 def hello_world(request):
7 return Response('Hello World!')

The function accepts a single argument (request) and it returns an instance of the pyramid.
response.Response class. The single argument to the class’ constructor is a string computed from
parameters matched from the URL. This value becomes the body of the response.

This function is known as a view callable. A view callable accepts a single argument, request. It is
expected to return a response object. A view callable doesn’t need to be a function; it can be represented
via another type of object, like a class or an instance, but for our purposes here, a function serves us well.

A view callable is always called with a request object. A request object is a representation of an HTTP
request sent to Pyramid via the active WSGI server.

A view callable is required to return a response object because a response object has all the information
necessary to formulate an actual HTTP response; this object is then converted to text by the WSGI server
which called Pyramid and it is sent back to the requesting browser. To return a response, each view callable
creates an instance of the Response class. In the hello_world function, a string is passed as the body
to the response.

0.3. Narrative Documentation 349


The Pyramid Web Framework, Version 2.0.2

Application Configuration

In the above script, the following code represents the configuration of this simple application. The ap-
plication is configured using the previously defined imports and function definitions, placed within the
confines of an if statement:

10 if __name__ == '__main__':
11 with Configurator() as config:
12 config.add_route('hello', '/')
13 config.add_view(hello_world, route_name='hello')
14 app = config.make_wsgi_app()
15 server = make_server('0.0.0.0', 6543, app)
16 server.serve_forever()

Let’s break this down piece by piece.

Configurator Construction

10 if __name__ == '__main__':
11 with Configurator() as config:

The if __name__ == '__main__': line in the code sample above represents a Python idiom:
the code inside this if clause is not invoked unless the script containing this code is run directly from the
operating system command line. For example, if the file named helloworld.py contains the entire
script body, the code within the if statement will only be invoked when python helloworld.py is
executed from the command line.

Using the if clause is necessary—or at least best practice—because code in a Python .py file may be
eventually imported via the Python import statement by another .py file. .py files that are imported by
other .py files are referred to as modules. By using the if __name__ == '__main__': idiom, the
script above is indicating that it does not want the code within the if statement to execute if this module is
imported from another; the code within the if block should only be run during a direct script execution.

The with Configurator() as config: line above creates an instance of the Configurator
class using a context manager. The resulting config object represents an API which the script uses to
configure this particular Pyramid application. Methods called on the Configurator will cause registrations
to be made in an application registry associated with the application.

350 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Adding Configuration

12 config.add_route('hello', '/')
13 config.add_view(hello_world, route_name='hello')

The first line above calls the pyramid.config.Configurator.add_route() method, which


registers a route to the root (/) URL path.

The second line registers the hello_world function as a view callable and makes sure that it will be
called when the hello route is matched.

WSGI Application Creation

14 app = config.make_wsgi_app()

After configuring views and ending configuration, the script creates a WSGI application via the
pyramid.config.Configurator.make_wsgi_app() method. A call to make_wsgi_app
implies that all configuration is finished (meaning all method calls to the configurator, which sets up views
and various other configuration settings, have been performed). The make_wsgi_app method returns
a WSGI application object that can be used by any WSGI server to present an application to a requestor.
WSGI is a protocol that allows servers to talk to Python applications. We don’t discuss WSGI in any depth
within this book, but you can learn more about it by reading its documentation.

The Pyramid application object, in particular, is an instance of a class representing a Pyramid router. It
has a reference to the application registry which resulted from method calls to the configurator used to
configure it. The router consults the registry to obey the policy choices made by a single application.
These policy choices were informed by method calls to the Configurator made earlier; in our case, the
only policy choices made were implied by calls to its add_view and add_route methods.

WSGI Application Serving

15 server = make_server('0.0.0.0', 6543, app)


16 server.serve_forever()

0.3. Narrative Documentation 351


The Pyramid Web Framework, Version 2.0.2

Finally, we actually serve the application to requestors by starting up a WSGI server. We happen to use the
wsgiref make_server server maker for this purpose. We pass in as the first argument '0.0.0.0',
which means ”listen on all TCP interfaces”. By default, the HTTP server listens only on the 127.0.0.1
interface, which is problematic if you’re running the server on a remote system and you wish to access it
with a web browser from a local system. We also specify a TCP port number to listen on, which is 6543,
passing it as the second argument. The final argument is the app object (a router), which is the application
we wish to serve. Finally, we call the server’s serve_forever method, which starts the main loop in
which it will wait for requests from the outside world.

When this line is invoked, it causes the server to start listening on TCP port 6543. The server will serve
requests forever, or at least until we stop it by killing the process which runs it (usually by pressing Ctrl-C
or Ctrl-Break in the terminal we used to start it).

Conclusion

Our hello world application is one of the simplest possible Pyramid applications, configured ”impera-
tively”. We can see that it’s configured imperatively because the full power of Python is available to us as
we perform configuration tasks.

References

For more information about the API of a Configurator object, see Configurator .

For more information about view configuration, see View Configuration.

0.3.4 Application Configuration

Most people already understand ”configuration” as settings that influence the operation of an application.
For instance, it’s easy to think of the values in a .ini file parsed at application startup time as ”configu-
ration”. However, if you’re reasonably open-minded, it’s easy to think of code as configuration too. Since
Pyramid, like most other web application platforms, is a framework, it calls into code that you write (as
opposed to a library, which is code that exists purely for you to call). The act of plugging application code
that you’ve written into Pyramid is also referred to within this documentation as ”configuration”; you are
configuring Pyramid to call the code that makes up your application.

See also:

For information on .ini files for Pyramid applications see the Startup chapter.

There are two ways to configure a Pyramid application: imperative configuration and declarative config-
uration. Both are described below.

352 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Imperative Configuration

”Imperative configuration” just means configuration done by Python statements, one after the next. Here’s
one of the simplest Pyramid applications, configured imperatively:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4

5 def hello_world(request):
6 return Response('Hello world!')
7

8 if __name__ == '__main__':
9 with Configurator() as config:
10 config.add_route('hello', '/')
11 config.add_view(hello_world, route_name='hello')
12 app = config.make_wsgi_app()
13 server = make_server('0.0.0.0', 6543, app)
14 server.serve_forever()

We won’t talk much about what this application does yet. Just note that the configuration statements take
place underneath the if __name__ == '__main__': stanza in the form of method calls on a
Configurator object (e.g., config.add_view(...)). These statements take place one after the other,
and are executed in order, so the full power of Python, including conditionals, can be employed in this
mode of configuration.

Declarative Configuration

It’s sometimes painful to have all configuration done by imperative code, because often the code for a single
application may live in many files. If the configuration is centralized in one place, you’ll need to have at
least two files open at once to see the ”big picture”: the file that represents the configuration, and the file
that contains the implementation objects referenced by the configuration. To avoid this, Pyramid allows
you to insert configuration decoration statements very close to code that is referred to by the declaration
itself. For example:

1 from pyramid.response import Response


2 from pyramid.view import view_config
3

4 @view_config(route_name='hello', request_method='GET')
5 def hello_world(request):
6 return Response('Hello World!')

0.3. Narrative Documentation 353


The Pyramid Web Framework, Version 2.0.2

The mere existence of configuration decoration doesn’t cause any configuration registration to be per-
formed. Before it has any effect on the configuration of a Pyramid application, a configuration decoration
within application code must be found through a process known as a scan.

For example, the pyramid.view.view_config decorator in the code example above adds an at-
tribute to the hello_world function, making it available for a scan to find it later.

A scan of a module or a package and its subpackages for decorations happens when the pyramid.
config.Configurator.scan() method is invoked: scanning implies searching for configuration
declarations in a package and its subpackages. For example:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4 from pyramid.view import view_config
5

7 @view_config(route_name='hello', request_method='GET')
8 def hello_world(request):
9 return Response('Hello World!')
10

11

12 if __name__ == '__main__':
13 with Configurator() as config:
14 config.add_route('hello', '/')
15 config.scan()
16 app = config.make_wsgi_app()
17 server = make_server('0.0.0.0', 6543, app)
18 server.serve_forever()

The scanning machinery imports each module and subpackage in a package or module recursively, looking
for special attributes attached to objects defined within a module. These special attributes are typically
attached to code via the use of a decorator. For example, the view_config decorator can be attached
to a function or instance method.

Once scanning is invoked, and configuration decoration is found by the scanner, a set of calls are made
to a Configurator on your behalf. These calls replace the need to add imperative configuration statements
that don’t live near the code being configured.

The combination of configuration decoration and the invocation of a scan is collectively known as declar-
ative configuration.

In the example above, the scanner translates the arguments to view_config into a call to the pyramid.
config.Configurator.add_view() method, effectively:

354 CONTENTS
The Pyramid Web Framework, Version 2.0.2

config.add_view(hello_world, route_name='hello',
request_method='GET')

Summary

There are two ways to configure a Pyramid application: declaratively and imperatively. You can choose
the mode with which you’re most comfortable; both are completely equivalent. Examples in this docu-
mentation will use both modes interchangeably.

0.3.5 Creating a Pyramid Project

As we saw in Creating Your First Pyramid Application, it’s possible to create a Pyramid application com-
pletely manually. However, it’s usually more convenient to use our cookiecutter to generate a basic Pyra-
mid project.

A project is a directory that contains at least one Python package. You’ll use the Pyramid cookiecutter
to create a project, and you’ll create your application logic within a package that lives inside the project.
Even if your application is extremely simple, it is useful to place code that drives the application within a
package, because (1) a package is more easily extended with new code, and (2) an application that lives
inside a package can also be distributed more easily than one which does not live within a package.

The Pylons Project provides a Pyramid cookiecutter that you can use to generate a project. Our cookiecutter
allows several configuration options to generate the type of application you’re trying to construct.

This cookiecutter is rendered using the cookiecutter command that you may install.

See also:

See also Cookiecutter Installation.

0.3. Narrative Documentation 355


The Pyramid Web Framework, Version 2.0.2

Pyramid cookiecutters

The Pyramid cookiecutter released under the Pylons Project offers the following configuration options:

• templating libraries (Jinja2, Chameleon, or Mako)

• the persistence mechanism (no persistence mechanism, SQLAlchemy with SQLite, or ZODB)

• the mechanism of mapping URLs to code (URL dispatch or traversal)

• pyramid-cookiecutter-starter

All configuration options offer a choice of templating language.

The configuration of mapping URLs to code (routing) depends on the backend option selected, with addi-
tional variations as follows.

none
URL dispatch for routing

sqlalchemy
SQLite for persistent storage, SQLAlchemy for an ORM, URL dispatch for routing, and Alembic for
database migrations

zodb
ZODB for persistent storage and traversal for routing

Creating the Project

In Installing Pyramid, you created a virtual Python environment via the venv command. We called the
virtual environment directory env and set an environment variable VENV to its path.

We assume that you previously installed cookiecutter, following its installation instructions.

When we invoke cookiecutter, it will create a directory that represents our project.

We assume our current working directory is the value of VENV.

On all platforms, generate a project using cookiecutter.

356 CONTENTS
The Pyramid Web Framework, Version 2.0.2

cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 2.0-branch

If prompted for the first item, accept the default yes by hitting return.

You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.


Is it okay to delete and re-clone it? [yes]: yes
project_name [Pyramid Scaffold]: myproject
repo_name [myproject]: myproject
Select template_language:
1 - jinja2
2 - chameleon
3 - mako
Choose from 1, 2, 3 [1]: 1
Select backend:
1 - none
2 - sqlalchemy
3 - zodb
Choose from 1, 2, 3 [1]: 1

We then run through the following commands.

On Unix:

# Reset our environment variable for a new virtual environment.


export VENV=~/env/myproject/env
# Change directory into your newly created project.
cd myproject
# Create a new virtual environment...
python3 -m venv $VENV
# ...where we upgrade packaging tools.
$VENV/bin/pip install --upgrade pip setuptools

Or on Windows:

# Reset our environment variable for a new virtual environment.


set VENV=c:\env\myproject\env
# Change directory into your newly created project.
cd myproject
# Create a new virtual environment...
python -m venv %VENV%
# ...where we upgrade packaging tools.
%VENV%\Scripts\pip install --upgrade pip setuptools

0.3. Narrative Documentation 357


The Pyramid Web Framework, Version 2.0.2

As a result of invoking the cookiecutter command, a directory named myproject is created. That
directory is a project directory. The setup.py file in that directory can be used to distribute your appli-
cation, or install your application for deployment or development.
An .ini file named development.ini will be created in the project directory. You will use this .ini
file to configure a server, to run your application, and to debug your application. It contains configuration
that enables an interactive debugger and settings optimized for development.
Another .ini file named production.ini will also be created in the project directory. It contains
configuration that disables any interactive debugger (to prevent inappropriate access and disclosure), and
turns off a number of debugging settings. You can use this file to put your application into production.
The myproject project directory contains an additional subdirectory named myproject representing a
Python package which holds very simple Pyramid sample code. This is where you’ll edit your application’s
Python code and templates.
We created this project in a directory next to its virtual environment directory. However, note that this is
not mandatory. The project directory can go more or less anywhere on your filesystem. You don’t need
to put it in a special ”web server” directory. You could put it within a virtual environment directory. The
author uses Linux mainly, and tends to put project directories which he creates within his ~/projects
directory. On Windows, it’s a good idea to put project directories within a directory that contains no space
characters, so it’s wise to avoid a path that contains, i.e., My Documents. As a result, the author, when
he uses Windows, just puts his projects in C:\projects.

You’ll need to avoid using cookiecutter to create a project with the same name as a Python
standard library component. In particular, this means you should avoid using the names site or
test, both of which conflict with Python standard library packages. You should also avoid using the
name pyramid, which will conflict with Pyramid itself.

Installing your Newly Created Project for Development

To install a newly created project for development, you should cd to the newly created project directory
and use the Python interpreter from the virtual environment you created during Installing Pyramid to
invoke the command pip install -e ., which installs the project in development mode (-e is for
”editable”) into the current directory (.).
The file named setup.py will be in the root of the cookiecutter-generated project directory. The python
you’re invoking should be the one that lives in the bin (or Scripts on Windows) directory of your
virtual Python environment. Your terminal’s current working directory must be the newly created project
directory.
On Unix:

358 CONTENTS
The Pyramid Web Framework, Version 2.0.2

$VENV/bin/pip install -e .

Or on Windows:

%VENV%\Scripts\pip install -e .

Elided output from a run of this command on Unix is shown below:

Running setup.py develop for myproject


Successfully installed Jinja2-2.11.2 Mako-1.1.3 MarkupSafe-1.1.1␣
,→PasteDeploy-2.1.1 Pygments-2.7.3 hupper-1.10.2 myproject plaster-1.0␣

,→plaster-pastedeploy-0.7 pyramid-1.10.5 pyramid-debugtoolbar-4.9 pyramid-

,→jinja2-2.8 pyramid-mako-1.1.0 repoze.lru-0.7 translationstring-1.4␣

,→venusian-3.0.0 waitress-1.4.4 webob-1.8.6 zope.deprecation-4.4.0 zope.

,→interface-5.2.0

This will install a distribution representing your project into the virtual environment interpreter’s library
set so it can be found by import statements and by other console scripts such as pserve, pshell,
proutes, and pviews.

Running the Tests for Your Application

To run unit tests for your application, you must first install the testing dependencies.

On Unix:

$VENV/bin/pip install -e ".[testing]"

On Windows:

%VENV%\Scripts\pip install -e ".[testing]"

Once the testing requirements are installed, then you can run the tests using the pytest command that
was just installed in the bin directory of your virtual environment.

On Unix:

0.3. Narrative Documentation 359


The Pyramid Web Framework, Version 2.0.2

$VENV/bin/pytest -q

On Windows:

%VENV%\Scripts\pytest -q

Here’s sample output from a test run on Unix:

$VENV/bin/pytest -q
....
4 passed in 0.31s

The tests themselves are found in the tests package in your cookiecutter-generated project. Within
this project generated by the pyramid-cookiecutter-starter cookiecutter, only a few sample
tests exist.

The -q option is passed to the pytest command to limit the output to a stream of dots. If you
don’t pass -q, you’ll see verbose test result output (which normally isn’t very useful).

Alternatively, if you’d like to see test coverage, pass the --cov option to pytest:

$VENV/bin/pytest --cov -q

Cookiecutters include configuration defaults for pytest and test coverage. These configuration files are
pytest.ini and .coveragerc, located at the root of your package. Without these defaults, we would
need to specify the path to the module on which we want to run tests and coverage.

$VENV/bin/pytest --cov=myproject myproject tests -q

See also:

See pytest’s documentation for How to invoke pytest or invoke pytest -h to see its full set of options.

360 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Running the Project Application

See also:

See also the output of pserve --help.

Once a project is installed for development, you can run the application it represents using the pserve
command against the generated configuration file. In our case, this file is named development.ini.

On Unix:

$VENV/bin/pserve development.ini

On Windows:

%VENV%\Scripts\pserve development.ini

Here’s sample output from a run of pserve on Unix:

$VENV/bin/pserve development.ini
Starting server in PID 77171.
Serving on http://localhost:6543
Serving on http://localhost:6543

Access is restricted such that only a browser running on the same machine as Pyramid will be able to access
your Pyramid application. However, if you want to open access to other machines on the same network,
then edit the development.ini file, and replace the listen value in the [server:main] section,
changing it from localhost:6543 to *:6543 (this is equivalent to 0.0.0.0:6543 [::]:6543).
For example:

[server:main]
use = egg:waitress#main
listen = *:6543

Now when you use pserve to start the application, it will respond to requests on all IP addresses possessed
by your system, not just requests to localhost. This is what the 0.0.0.0 in serving on http:/
/0.0.0.0:6543 means. The server will respond to requests made to 127.0.0.1 and on any external
IP address. For example, your system might be configured to have an external IP address 192.168.1.
50. If that’s the case, if you use a browser running on the same system as Pyramid, it will be able to access
the application via http://127.0.0.1:6543/ as well as via http://192.168.1.50:6543/.

0.3. Narrative Documentation 361


The Pyramid Web Framework, Version 2.0.2

However, other people on other computers on the same network will also be able to visit your Pyramid
application in their browser by visiting http://192.168.1.50:6543/. The same holds true if you
use IPv6. [::] means the same as 0.0.0.0 but for IPv6 protocol.

You can change the port on which the server runs on by changing the same portion of the development.
ini file. For example, you can change the listen = localhost:6543 line in the development.
ini file’s [server:main] section to listen = localhost:8080 to run the server on port 8080
instead of port 6543.

You can shut down a server started this way by pressing Ctrl-C (or Ctrl-Break on Windows).

The default server used to run your Pyramid application when a project is created from a cookiecutter is
named Waitress. This server is what prints the Serving on... line when you run pserve. It’s a
good idea to use this server during development because it’s very simple. It can also be used for light
production. Setting your application up under a different server is not advised until you’ve done some
development work under the default server, particularly if you’re not yet experienced with Python web
development. Python web server setup can be complex, and you should get some confidence that your
application works in a default environment before trying to optimize it or make it ”more like production”.
It’s awfully easy to get sidetracked trying to set up a non-default server for hours without actually starting
to do any development. One of the nice things about Python web servers is that they’re largely interchange-
able, so if your application works under the default server, it will almost certainly work under any other
server in production if you eventually choose to use a different one. Don’t worry about it right now.

For more detailed information about the startup process, see Startup. For more information about environ-
ment variables and configuration file settings that influence startup and runtime behavior, see Environment
Variables and .ini File Settings.

Reloading Code

During development, it’s often useful to run pserve using its --reload option. When --reload is
passed to pserve, changes to any Python module your project uses will cause the server to restart. This
typically makes development easier, as changes to Python code made within a Pyramid application is not
put into effect until the server restarts.

For example, on Unix:

$VENV/bin/pserve development.ini --reload


Starting monitor for PID 36224.
Starting server in PID 36224.
Serving on http://localhost:6543
Serving on http://localhost:6543

362 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Now if you make a change to any of your project’s .py files or .ini files, you’ll see the server restart
automatically:

/file-path-to/myproject/development.ini changed; reloading ...


Gracefully killing the server.
Starting monitor for PID 36286.
Starting server in PID 36286.
Serving on http://localhost:6543
Serving on http://localhost:6543

Changes to template files (such as .pt or .mak files) won’t cause the server to restart. Changes to tem-
plate files don’t require a server restart as long as the pyramid.reload_templates setting in the
development.ini file is true. Changes made to template files when this setting is true will take
effect immediately without a server restart.

Viewing the Application

Once your application is running via pserve, you may visit http://localhost:6543/ in your
browser. You will see something in your browser like what is displayed in the following image:

0.3. Narrative Documentation 363


The Pyramid Web Framework, Version 2.0.2

This is the page shown by default when you visit an unmodified cookiecutter generated
pyramid-cookiecutter-starter application in a browser.

The Debug Toolbar

364 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If you click on the Pyramid logo at the top right of the page, a new target window will open to present
a debug toolbar that provides various niceties while you’re developing. This logo will float above every
HTML page served by Pyramid while you develop an application, and allows you to show the toolbar as
necessary.

If you don’t see the Pyramid logo on the top right of the page, it means you’re browsing from a system
that does not have debugging access. By default, for security reasons, only a browser originating from
localhost (127.0.0.1) can see the debug toolbar. To allow your browser on a remote system to
access the server, add a line within the [app:main] section of the development.ini file in the
form debugtoolbar.hosts = X.X.X.X. For example, if your Pyramid application is running on a
remote system, and you’re browsing from a host with the IP address 192.168.1.1, you’d add something
like this to enable the toolbar when your system contacts Pyramid:

[app:main]
# ... other settings ...
debugtoolbar.hosts = 192.168.1.1

0.3. Narrative Documentation 365


The Pyramid Web Framework, Version 2.0.2

For more information about what the debug toolbar allows you to do, see the documentation for pyra-
mid_debugtoolbar.

The debug toolbar will not be shown (and all debugging will be turned off) when you use the
production.ini file instead of the development.ini ini file to run the application.

You can also turn the debug toolbar off by editing development.ini and commenting out a line. For
example, instead of:

1 [app:main]
2 # ... elided configuration
3 pyramid.includes =
4 pyramid_debugtoolbar

Put a hash mark at the beginning of the pyramid_debugtoolbar line:

1 [app:main]
2 # ... elided configuration
3 pyramid.includes =
4 # pyramid_debugtoolbar

Then restart the application to see that the toolbar has been turned off.

Note that if you comment out the pyramid_debugtoolbar line, the # must be in the first column.
If you put it anywhere else, and then attempt to restart the application, you’ll receive an error that ends
something like this:

ImportError: No module named #pyramid_debugtoolbar

The Project Structure

The pyramid-cookiecutter-starter cookiecutter generated a project (named myproject),


which contains a Python package. The package is also named myproject; the cookiecutter generates a
project which contains a package that shares its name.

All Pyramid cookiecutter-generated projects share a similar structure. The myproject project
we’ve generated has the following directory structure:

366 CONTENTS
The Pyramid Web Framework, Version 2.0.2

myproject
├── .coveragerc
├── .gitignore
├── CHANGES.txt
├── MANIFEST.in
├── README.txt
├── development.ini
├── myproject
│ ├── __init__.py
│ ├── routes.py
│ ├── static
│ │ ├── pyramid-16x16.png
│ │ ├── pyramid.png
│ │ └── theme.css
│ ├── templates
│ │ ├── 404.jinja2
│ │ ├── layout.jinja2
│ │ └── mytemplate.jinja2
│ └── views
│ ├── __init__.py
│ ├── default.py
│ └── notfound.py
├── production.ini
├── pytest.ini
├── setup.py
├── testing.ini
└── tests
├── __init__.py
├── conftest.py
├── test_functional.py
└── test_views.py

tests package

The conftest.py, test_functional.py, and test_views.py modules in the tests package


includes tests for your application.

1 import os
2 from pyramid.paster import get_appsettings
3 from pyramid.scripting import prepare
4 from pyramid.testing import DummyRequest, testConfig
5 import pytest
(continues on next page)

0.3. Narrative Documentation 367


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


6 import webtest
7

8 from myproject import main


9

10

11 def pytest_addoption(parser):
12 parser.addoption('--ini', action='store', metavar='INI_FILE')
13

14 @pytest.fixture(scope='session')
15 def ini_file(request):
16 # potentially grab this path from a pytest option
17 return os.path.abspath(request.config.option.ini or 'testing.ini')
18

19 @pytest.fixture(scope='session')
20 def app_settings(ini_file):
21 return get_appsettings(ini_file)
22

23 @pytest.fixture(scope='session')
24 def app(app_settings):
25 return main({}, **app_settings)
26

27 @pytest.fixture
28 def testapp(app):
29 testapp = webtest.TestApp(app, extra_environ={
30 'HTTP_HOST': 'example.com',
31 })
32

33 return testapp
34

35 @pytest.fixture
36 def app_request(app):
37 """
38 A real request.
39

40 This request is almost identical to a real request but it has some


41 drawbacks in tests as it's harder to mock data and is heavier.
42

43 """
44 with prepare(registry=app.registry) as env:
45 request = env['request']
46 request.host = 'example.com'
47 yield request
48

49 @pytest.fixture
50 def dummy_request():
(continues on next page)

368 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


51 """
52 A lightweight dummy request.
53

54 This request is ultra-lightweight and should be used only when the␣


,→request
55 itself is not a large focus in the call-stack. It is much easier to␣
,→mock

56 and control side-effects using this object, however:


57

58 - It does not have request extensions applied.


59 - Threadlocals are not properly pushed.
60

61 """
62 request = DummyRequest()
63 request.host = 'example.com'
64

65 return request
66

67 @pytest.fixture
68 def dummy_config(dummy_request):
69 """
70 A dummy :class:`pyramid.config.Configurator` object. This allows for
71 mock configuration, including configuration for ``dummy_request``, as␣
,→well

72 as pushing the appropriate threadlocals.


73

74 """
75 with testConfig(request=dummy_request) as config:
76 yield config

1 def test_root(testapp):
2 res = testapp.get('/', status=200)
3 assert b'Pyramid' in res.body
4

5 def test_notfound(testapp):
6 res = testapp.get('/badurl', status=404)
7 assert res.status_code == 404

1 from myproject.views.default import my_view


2 from myproject.views.notfound import notfound_view
3

5 def test_my_view(app_request):
(continues on next page)

0.3. Narrative Documentation 369


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


6 info = my_view(app_request)
7 assert app_request.response.status_int == 200
8 assert info['project'] == 'myproject'
9

10 def test_notfound_view(app_request):
11 info = notfound_view(app_request)
12 assert app_request.response.status_int == 404
13 assert info == {}

The sample conftest.py file contains test configuration and fixtures. The sample
test_functional.py file has two functional tests defined within it. The sample test_views.py
file has two unit tests defined within it. These tests are executed when you run pytest -q. You may
add more tests here as you build your application. You are not required to write tests to use Pyramid.
These files are provided only for convenience and example.

See Unit, Integration, and Functional Testing for more information about writing Pyramid unit tests.

The myproject Project

The myproject project directory is the distribution and deployment wrapper for your application. It
contains both the myproject package representing your application as well as files used to describe,
run, and test your application.

1. .coveragerc configures coverage when running tests.

2. .gitignore tells git which files and directories to ignore from source code version control.

3. CHANGES.txt describes the changes you’ve made to the application. It is conventionally written
in reStructuredText format.

4. MANIFEST.in is a distutils ”manifest” file, naming which files should be included in a source
distribution of the package when python setup.py sdist is run.

5. README.txt describes the application in general. It is conventionally written in reStructuredText


format.

6. development.ini is a PasteDeploy configuration file that can be used to execute your applica-
tion during development.

7. production.ini is a PasteDeploy configuration file that can be used to execute your application
in a production configuration.

370 CONTENTS
The Pyramid Web Framework, Version 2.0.2

8. pytest.ini is a configuration file for running tests.

9. setup.py is the file you’ll use to test and distribute your application. It is a standard Setuptools
setup.py file.

10. testing.ini is a PasteDeploy configuration file that can be used to execute your application’s
tests.

11. tests package which contains unit and functional test code for the application.

development.ini

The development.ini file is a PasteDeploy configuration file. Its purpose is to specify an application
to run when you invoke pserve, as well as the deployment settings provided to that application.

The generated development.ini file looks like so:

1 ###
2 # app configuration
3 # https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/
,→environment.html

4 ###
5

6 [app:main]
7 use = egg:myproject
8

9 pyramid.reload_templates = true
10 pyramid.debug_authorization = false
11 pyramid.debug_notfound = false
12 pyramid.debug_routematch = false
13 pyramid.default_locale_name = en
14 pyramid.includes =
15 pyramid_debugtoolbar
16

17 # By default, the toolbar only appears for clients from IP addresses


18 # '127.0.0.1' and '::1'.
19 # debugtoolbar.hosts = 127.0.0.1 ::1
20

21 ###
22 # wsgi server configuration
23 ###
24

(continues on next page)

0.3. Narrative Documentation 371


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


25 [server:main]
26 use = egg:waitress#main
27 listen = localhost:6543
28

29 ###
30 # logging configuration
31 # https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.
,→html

32 ###
33

34 [loggers]
35 keys = root, myproject
36

37 [handlers]
38 keys = console
39

40 [formatters]
41 keys = generic
42

43 [logger_root]
44 level = INFO
45 handlers = console
46

47 [logger_myproject]
48 level = DEBUG
49 handlers =
50 qualname = myproject
51

52 [handler_console]
53 class = StreamHandler
54 args = (sys.stderr,)
55 level = NOTSET
56 formatter = generic
57

58 [formatter_generic]
59 format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][
,→%(threadName)s] %(message)s

This file contains several sections including [app:main], [server:main], and several other sections
related to logging configuration.

The [app:main] section represents configuration for your Pyramid application. The use setting is the
only setting required to be present in the [app:main] section. Its default value, egg:myproject,
indicates that our myproject project contains the application that should be served. Other settings added to

372 CONTENTS
The Pyramid Web Framework, Version 2.0.2

this section are passed as keyword arguments to the function named main in our package’s __init__.
py module. You can provide startup-time configuration parameters to your application by adding more
settings to this section.

See also:

See Entry Points and PasteDeploy .ini Files for more information about the meaning of the use =
egg:myproject value in this section.

The pyramid.reload_templates setting in the [app:main] section is a Pyramid-specific setting


which is passed into the framework. If it exists, and its value is true, supported template changes will not
require an application restart to be detected. See Automatically Reloading Templates for more information.

The pyramid.reload_templates option should be turned off for production applications,


as template rendering is slowed when it is turned on.

The pyramid.includes setting in the [app:main] section tells Pyramid to ”include” configuration
from another package. In this case, the line pyramid.includes = pyramid_debugtoolbar
tells Pyramid to include configuration from the pyramid_debugtoolbar package. This turns on a
debugging panel in development mode which can be opened by clicking on the Pyramid logo on the top
right of the screen. Including the debug toolbar will also make it possible to interactively debug exceptions
when an error occurs.

Various other settings may exist in this section having to do with debugging or influencing runtime behavior
of a Pyramid application. See Environment Variables and .ini File Settings for more information about
these settings.

The name main in [app:main] signifies that this is the default application run by pserve when it is
invoked against this configuration file. The name main is a convention used by PasteDeploy signifying
that it is the default application.

The [server:main] section of the configuration file configures a WSGI server which listens on TCP
port 6543. It is configured to listen on localhost only (127.0.0.1).

The sections after # logging configuration represent Python’s standard library logging mod-
ule configuration for your application. The default configuration sends application logging output to the
standard error output of your terminal. For more information see Logging.

See the PasteDeploy documentation for more information about other types of things you can put into this
.ini file, such as other applications, middleware, and alternate WSGI server implementations.

0.3. Narrative Documentation 373


The Pyramid Web Framework, Version 2.0.2

production.ini

The production.ini file is a PasteDeploy configuration file with a purpose much like that of
development.ini. However, it disables the debug toolbar, and filters all log messages except those
above the WARN level. It also turns off template development options such that templates are not automat-
ically reloaded when changed, and turns off all debugging options. This file is appropriate to use instead
of development.ini when you put your application into production.

It’s important to use production.ini (and not development.ini) to benchmark your applica-
tion and put it into production. development.ini configures your system with a debug toolbar that
helps development, but the inclusion of this toolbar slows down page rendering times by over an order of
magnitude. The debug toolbar is also a potential security risk if you have it configured incorrectly.

testing.ini

The testing.ini file is a PasteDeploy configuration file with a purpose much like that of
development.ini. It is similar to development.ini, but is optimized to reduce test execution
time. It disables the debug toolbar and automatic reloading of templates, as these slow down test exe-
cution. This file is appropriate to use instead of development.ini when you run your application’s
tests.

MANIFEST.in

The MANIFEST.in file is a distutils configuration file which specifies the non-Python files that should
be included when a distribution of your Pyramid project is created when you run python setup.py
sdist. Due to the information contained in the default MANIFEST.in, an sdist of your Pyramid project
will include .txt files, .ini files, .rst files, graphics files, and template files, as well as .py files. See
the Python Packaging Authority’s Python Packaging User Guide Including files in source distributions
with MANIFEST.in for more information about the syntax and usage of MANIFEST.in.

Without the presence of a MANIFEST.in file or without checking your source code into a version con-
trol repository, setup.py sdist places only Python source files (files ending with a .py extension)
into tarballs generated by python setup.py sdist. This means, for example, if your project
was not checked into a Setuptools-compatible source control system, and your project directory didn’t
contain a MANIFEST.in file that told the sdist machinery to include *.pt files, the myproject/
templates/mytemplate.pt file would not be included in the generated tarball.

Projects generated by Pyramid cookiecutters include a default MANIFEST.in file. The MANIFEST.in
file contains declarations which tell it to include files like *.pt, *.css and *.js in the generated tarball.

374 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If you include files with extensions other than the files named in the project’s MANIFEST.in and you don’t
make use of a Setuptools-compatible version control system, you’ll need to edit the MANIFEST.in file
and include the statements necessary to include your new files. In the aforementioned Python Packaging
User Guide, see MANIFEST.in commands for more information about how to do this.

You can also delete MANIFEST.in from your project and rely on a Setuptools feature which simply causes
all files checked into a version control system to be put into the generated tarball. To allow this to happen,
check all the files that you’d like to be distributed along with your application’s Python files into Subversion.
After you do this, when you rerun setup.py sdist, all files checked into the version control system
will be included in the tarball. If you don’t use Subversion, and instead use a different version control
system, you may need to install a Setuptools add-on such as setuptools-git or setuptools-hg
for this behavior to work properly.

setup.py

The setup.py file is a Setuptools setup file. It is meant to be used to define requirements for installing
dependencies for your package and testing, as well as distributing your application.

setup.py is the de facto standard which Python developers use to distribute their reusable code.
You can read more about setup.py files and their usage in the Python Packaging User Guide and Se-
tuptools documentation.

Our generated setup.py looks like this:

1 import os
2

3 from setuptools import setup, find_packages


4

5 here = os.path.abspath(os.path.dirname(__file__))
6 with open(os.path.join(here, 'README.txt')) as f:
7 README = f.read()
8 with open(os.path.join(here, 'CHANGES.txt')) as f:
9 CHANGES = f.read()
10

11 requires = [
12 'plaster_pastedeploy',
13 'pyramid',
14 'pyramid_jinja2',
15 'pyramid_debugtoolbar',
(continues on next page)

0.3. Narrative Documentation 375


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


16 'waitress',
17 ]
18

19 tests_require = [
20 'WebTest',
21 'pytest',
22 'pytest-cov',
23 ]
24

25 setup(
26 name='myproject',
27 version='0.0',
28 description='myproject',
29 long_description=README + '\n\n' + CHANGES,
30 classifiers=[
31 'Programming Language :: Python',
32 'Framework :: Pyramid',
33 'Topic :: Internet :: WWW/HTTP',
34 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
35 ],
36 author='',
37 author_email='',
38 url='',
39 keywords='web pyramid pylons',
40 packages=find_packages(exclude=['tests']),
41 include_package_data=True,
42 zip_safe=False,
43 extras_require={
44 'testing': tests_require,
45 },
46 install_requires=requires,
47 entry_points={
48 'paste.app_factory': [
49 'main = myproject:main',
50 ],
51 },
52 )

The setup.py file calls the Setuptools setup function, which does various things depending on the
arguments passed to pip on the command line.

Within the arguments to this function call, information about your application is kept. While it’s beyond the
scope of this documentation to explain everything about Setuptools setup files, we’ll provide a whirlwind
tour of what exists in this file in this section.

376 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Your application’s name can be any string; it is specified in the name field. The version number is
specified in the version value. A short description is provided in the description field. The
long_description is conventionally the content of the README and CHANGES files appended to-
gether. The classifiers field is a list of Trove classifiers describing your application. author and
author_email are text fields which probably don’t need any description. url is a field that should
point at your application project’s URL (if any). keywords are keywords that describe your project.
packages=find_packages(exclude=['tests']) causes all packages within the project to be
found when packaging the application. include_package_data will include non-Python files when
the application is packaged if those files are checked into version control. zip_safe=False indicates
that this package is not safe to use as a zipped egg; instead it will always unpack as a directory, which is
more convenient. extras_require is a Python dictionary that defines what is required to be installed
for running tests. install_requires indicates that this package depends on the pyramid package.
We examined entry_points in our discussion of the development.ini file; this file defines the
main entry point that represents our project’s application.

Usually you only need to think about the contents of the setup.py file when distributing your application
to other people, when adding Python package dependencies, or when versioning your application for your
own use. For fun, you can try this command now:

$VENV/bin/python setup.py sdist

This will create a tarball of your application in a dist subdirectory named myproject-0.0.tar.gz.
You can send this tarball to other people who want to install and use your application.

The myproject Package

The myproject package lives inside the myproject project. It contains:

1. An __init__.py file signifies that this is a Python package. It also contains code that helps users
run the application, including a main function which is used as a entry point for commands such
as pserve, pshell, pviews, and others.

2. A templates directory, which contains Jinja2 (or other types of) templates.

3. A routes.py module, which contains routing code for the application.

4. A views package, which contains view code for the application.

5. A static directory, which contains static files, including images and CSS.

These are purely conventions established by the cookiecutter. Pyramid doesn’t insist that you name things
in any particular way. However, it’s generally a good idea to follow Pyramid standards for naming, so that
other Pyramid developers can get up to speed quickly on your code when you need help.

0.3. Narrative Documentation 377


The Pyramid Web Framework, Version 2.0.2

__init__.py

We need a small Python module that configures our application and which advertises an entry point for use
by our PasteDeploy .ini file. This is the file named __init__.py. The presence of an __init__.
py also informs Python that the directory which contains it is a package.

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 """ This function returns a Pyramid WSGI application.
6 """
7 with Configurator(settings=settings) as config:
8 config.include('pyramid_jinja2')
9 config.include('.routes')
10 config.scan()
11 return config.make_wsgi_app()

1. Line 1 imports the Configurator class from pyramid.config that we use later.

2. Lines 4-11 define a function named main that returns a Pyramid WSGI application. This function
is meant to be called by the PasteDeploy framework as a result of running pserve.

The main function configures the application.

Line 7 opens a context manager with an instance of a Configurator.

Line 8 adds support for Jinja2 templating bindings, allowing us to specify renderers with the .
jinja2 extension.

Line 9 includes the routes.py module.

Line 10 calls config.scan(), which picks up view registrations declared elsewhere in the pack-
age (in this case, in the views.py module).

Line 11 returns a WSGI application to the caller of the function (Pyramid’s pserve).

See also:

See The Startup Process for more about the application’s settings and main’s arguments and statements.

378 CONTENTS
The Pyramid Web Framework, Version 2.0.2

routes.py

The routes.py module gets included by the main function in our __init__.py. It registers a view
and a route.

1 def includeme(config):
2 config.add_static_view('static', 'static', cache_max_age=3600)
3 config.add_route('home', '/')

Line 2 registers a static view, which will serve up the files from the myproject:static asset specifi-
cation (the static directory of the myproject package).

Line 3 adds a route to the configuration. This route is later used by a view in the views module.

views package

Much of the heavy lifting in a Pyramid application is done by view callables. A view callable is the main
tool of a Pyramid web application developer; it is a bit of code which accepts a request and which returns
a response.

Our project has a views package by virtue of it being a directory containing an __init__.py file. This
__init__.py file happens to have no content, although it could as a project develops.

We have two view modules in the views package. Let’s look at default.py.

1 from pyramid.view import view_config


2

4 @view_config(route_name='home', renderer='myproject:templates/mytemplate.
,→jinja2')

5 def my_view(request):
6 return {'project': 'myproject'}

Lines 4-6 define and register a view callable named my_view. The function named my_view is
decorated with a view_config decorator (which is processed by the config.scan() line in our
__init__.py). The view_config decorator asserts that this view be found when a route named home
is matched. In our case, because our routes.py maps the route named home to the URL pattern
/, this route will match when a visitor visits the root URL. The view_config decorator also names a
renderer, which in this case is a template that will be used to render the result of the view callable.
This particular view declaration points at myproject:templates/mytemplate.jinja2, which

0.3. Narrative Documentation 379


The Pyramid Web Framework, Version 2.0.2

is an asset specification that specifies the mytemplate.jinja2 file within the templates direc-
tory of the myproject package. There is a second form of asset specification: a relative asset speci-
fication. Instead of using an ”absolute” asset specification which includes the package name, in certain
circumstances you can omit the package name from the specification. For example, you might be able
to use ../templates/mytemplate.jinja2. The template file pointed to is a Jinja2 template file
(templates/mytemplate.jinja2).

This view callable function is handed a single piece of information: the request. The request is an instance
of the WebOb Request class representing the browser’s request to our server.

This view is configured to invoke a renderer on a template. The dictionary the view returns (on line 6)
provides the value the renderer substitutes into the template when generating HTML. The renderer then
returns the HTML in a response.

Dictionaries provide values to templates.

Now let’s look at notfound.py.

1 from pyramid.view import notfound_view_config


2

4 @notfound_view_config(renderer='myproject:templates/404.jinja2')
5 def notfound_view(request):
6 request.response.status = 404
7 return {}

This file is similar to default.py. It merely returns a 404 response status and an empty dictionary to
the template at myproject:templates/404.jinja2.

When the application is run with the cookiecutter’s default development.ini configuration, logging is
set up to aid debugging. If an exception is raised, uncaught tracebacks are displayed after the startup mes-
sages on the console running the server. Also print() statements may be inserted into the application
for debugging to send output to this console.

development.ini has a setting that controls how templates are reloaded, pyramid.
reload_templates.

380 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• When set to True (as in the cookiecutter development.ini), changed templates automatically
reload without a server restart. This is convenient while developing, but slows template rendering
speed.

• When set to False (the default value), changing templates requires a server restart to reload them.
Production applications should use pyramid.reload_templates = False.

See also:

See also Writing View Callables Which Use a Renderer for more information about how views, renderers,
and templates relate and cooperate.

See also:

Pyramid can also dynamically reload changed Python files. See also Reloading Code.

See also:

See also the The Debug Toolbar, which provides interactive access to your application’s internals and,
should an exception occur, allows interactive access to traceback execution stack frames from the Python
interpreter.

static

This directory contains static assets which support the layout.jinja2 template. It includes CSS and
images.

templates/layout.jinja2

This is the base layout content. It contains a single marker for content block. Other templates inherit its
content, providing layout for the web application. Its contents are too long to show here, but here is an
excerpt:

34 <div class="col-md-10">
35 {% block content %}
36 <p>No content</p>
37 {% endblock content %}
38 </div>

0.3. Narrative Documentation 381


The Pyramid Web Framework, Version 2.0.2

templates/mytemplate.jinja2

This is the content Jinja2 template that exists in the project. It is referenced by the call to @view_config
as the renderer of the my_view view callable in the views/default.py file. See Writing View
Callables Which Use a Renderer for more information about renderers. It inherits (”extends”) the HTML
provided by layout.jinja2, replacing the content block with its own content.

1 {% extends "layout.jinja2" %}
2

3 {% block content %}
4 <div class="content">
5 <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">
,→Starter project</span></h1>

6 <p class="lead">Welcome to <span class="font-normal">{{project}}</span>,␣


,→a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal

,→">Cookiecutter</span>.</p>

7 </div>
8 {% endblock content %}

Templates are accessed and used by view configurations and sometimes by view functions themselves. See
Using Templates Directly and Templates Used as Renderers via Configuration.

templates/404.jinja2

This template is similar to mytemplate.jinja2, but with a few differences. It is referenced by the
call to @notfound_view_config as the renderer of the notfound_view view callable in the
views/notfound.py file. It inherits the HTML provided by layout.jinja2, replacing the content
block with its own content.

1 {% extends "layout.jinja2" %}
2

3 {% block content %}
4 <div class="content">
5 <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">
,→Starter project</span></h1>

6 <p class="lead"><span class="font-semi-bold">404</span> Page Not Found</


,→p>

7 </div>
8 {% endblock content %}

382 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Modifying Package Structure

It is best practice for your application’s code layout to not stray too much from accepted Pyramid cook-
iecutter defaults. If you refrain from changing things very much, other Pyramid coders will be able to more
quickly understand your application. However, the code layout choices made for you by a cookiecutter are
in no way magical or required. Despite the choices made for you by any cookiecutter, you can decide to
lay your code out any way you see fit.

For example, the configuration method named add_view() requires you to pass a dotted Python name or
a direct object reference as the class or function to be used as a view. By default, the starter cookiecutter
would have you create a views directory, and add a single file for each view or collection of related views.
However, you might be more comfortable creating a single views.py module in your package and add
view functions to it.

Whatever structure you prefer, as long as you use the @view_config directive to register views in con-
junction with config.scan(), they will be picked up automatically when the application is restarted.

Using the Interactive Shell

It is possible to use the pshell command to load a Python interpreter prompt with a similar configuration
as would be loaded if you were running your Pyramid application via pserve. This can be a useful
debugging tool. See pshell: The Interactive Shell for more details.

What Is This pserve Thing

The code generated by a Pyramid cookiecutter assumes that you will be using the pserve command to
start your application while you do development. pserve is a command that reads a PasteDeploy .ini
file (e.g., development.ini), and configures a server to serve a Pyramid application based on the data
in the file.

pserve is by no means the only way to start up and serve a Pyramid application. As we saw in Creating
Your First Pyramid Application, pserve needn’t be invoked at all to run a Pyramid application. The use of
pserve to run a Pyramid application is purely conventional based on the output of its cookiecutter. But we
strongly recommend using pserve while developing your application because many other convenience
introspection commands (such as pviews, prequest, proutes, and others) are also implemented
in terms of configuration availability of this .ini file format. It also configures Pyramid logging and
provides the --reload switch for convenient restarting of the server when code changes.

0.3. Narrative Documentation 383


The Pyramid Web Framework, Version 2.0.2

Using an Alternate WSGI Server

Pyramid cookiecutters generate projects which use the Waitress WSGI server. Waitress is a server that is
suited for development and light production usage. It’s not the fastest nor the most featureful WSGI server.
Instead, its main feature is that it works on all platforms that Pyramid needs to run on, making it a good
choice as a default server from the perspective of Pyramid’s developers.

Any WSGI server is capable of running a Pyramid application. But we suggest you stick with the default
server for development, and that you wait to investigate other server options until you’re ready to deploy
your application to production. Unless for some reason you need to develop on a non-local system, inves-
tigating alternate server options is usually a distraction until you’re ready to deploy. But we recommend
developing using the default configuration on a local system that you have complete control over; it will
provide the best development experience.

One popular production alternative to the default Waitress server is mod_wsgi. You can use mod_wsgi
to serve your Pyramid application using the Apache web server rather than any ”pure-Python” server like
Waitress. It is fast and featureful. See Running a Pyramid Application under mod_wsgi for details.

Another good production alternative is gunicorn. It’s faster than Waitress and slightly easier to configure
than mod_wsgi, although it depends, in its default configuration, on having a buffering HTTP proxy in
front of it. It does not, as of this writing, work on Windows.

Automatically Reloading Your Code

During development, it can be really useful to automatically have the webserver restart when you make
changes. pserve has a --reload switch to enable this. It uses the hupper package to enable this
behavior. When your code crashes, hupper will wait for another change or the SIGHUP signal before
restarting again.

inotify support

By default hupper will poll the filesystem for changes to all Python code. This can be pretty inefficient
in larger projects. To be nicer to your hard drive, you should install either the watchman or watchdog
package in development. hupper will use, in order of preference for efficiency, if available, watchman,
watchdog, or finally polling to detect changes to the filesystem.

384 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Monitoring Custom Files

By default, pserve --reload will monitor all imported Python code (everything in sys.modules)
as well as the config file passed to pserve (e.g., development.ini). You can instruct pserve to
watch other files for changes as well by defining a [pserve] section in your configuration file. For
example, let’s say your application loads the favicon.ico file at startup and stores it in memory to
efficiently serve it many times. When you change it, you want pserve to restart:

[pserve]
watch_files =
myproject/static/favicon.ico

Paths may be absolute or relative to the configuration file. They may also be an asset specification. These
paths are passed to hupper, which has some basic support for globbing. Acceptable glob patterns depend
on the version of Python being used.

0.3.6 Startup

When you cause a Pyramid application to start up in a console window, you’ll see something much like
this show up on the console:

$VENV/bin/pserve development.ini
Starting server in PID 16305.
Serving on http://localhost:6543
Serving on http://localhost:6543

This chapter explains what happens between the time you press the ”Return” key on your keyboard
after typing pserve development.ini and the time the lines Serving on http://
localhost:6543 are output to your console.

The Startup Process

The easiest and best-documented way to start and serve a Pyramid application is to use the pserve
command against a PasteDeploy .ini file. This uses the .ini file to infer settings and starts a server
listening on a port. For the purposes of this discussion, we’ll assume that you are using this command to
run your Pyramid application.

Here’s a high-level time-ordered overview of what happens when you press return after running
pserve development.ini.

0.3. Narrative Documentation 385


The Pyramid Web Framework, Version 2.0.2

1. The pserve command is invoked under your shell with the argument development.ini. As
a result, Pyramid recognizes that it is meant to begin to run and serve an application using the
information contained within the development.ini file.
2. pserve passes the development.ini path to plaster which finds an available configuration
loader that recognizes the ini format.
3. plaster finds the plaster_pastedeploy library which binds the PasteDeploy library and re-
turns a parser that can understand the format.
4. The PasteDeploy finds a section named either [app:main], [pipeline:main], or [com-
posite:main] in the .ini file. This section configures the WSGI webserver which serves your
application. As such it is the ini section for your application and can be the source for many of
your application’s settings.
If you’re using a simple application (e.g., [app:main]), the application’s paste.
app_factory entry point will be named on the use= line within the section’s configuration.
If instead of a simple application, you’re using a WSGI pipeline (e.g., a [pipeline:main] sec-
tion), the application named on the ”last” element will refer to your Pyramid application. If instead
of a simple application or a pipeline, you’re using a ”composite” (e.g., [composite:main]),
refer to the documentation for that particular composite to understand how to make it refer to your
Pyramid application. In most cases, a Pyramid application built from a cookiecutter will have a
single [app:main] section in it, and this will be the application served.
5. The framework finds all logging related configuration in the .ini file and uses it to configure
the Python standard library logging system for the application. See Logging Configuration for more
information.
6. The application’s entry point, usually the entry point referenced on the above mentioned use= line,
is the application’s constructor. It is passed the key/value parameters in the application’s .ini section.
The constructor should return a router instance, which is a WSGI application.
For Pyramid applications, the constructor is a function named main in the __init__.py file
within the package in which your application lives. If this function succeeds, it will return a Pyramid
router instance. Here’s the contents of an example __init__.py module:

1 from pyramid.config import Configurator


2

4 def main(global_config, **settings):


5 """ This function returns a Pyramid WSGI application.
6 """
7 with Configurator(settings=settings) as config:
8 config.include('pyramid_jinja2')
9 config.include('.routes')
10 config.scan()
11 return config.make_wsgi_app()

386 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Note that the constructor function accepts a global_config argument, which is a dictionary of
key/value pairs mentioned in the [DEFAULT] section of an .ini file (if [DEFAULT] is present).
It also accepts a **settings argument, which collects another set of arbitrary key/value pairs.
The arbitrary key/value pairs received by this function in **settings will be composed of all
the key/value pairs that are present in the [app:main] section (except for the use= setting) when
this function is called when you run pserve.

Our generated development.ini file looks like so:

1 ###
2 # app configuration
3 # https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/
,→environment.html

4 ###
5

6 [app:main]
7 use = egg:myproject
8

9 pyramid.reload_templates = true
10 pyramid.debug_authorization = false
11 pyramid.debug_notfound = false
12 pyramid.debug_routematch = false
13 pyramid.default_locale_name = en
14 pyramid.includes =
15 pyramid_debugtoolbar
16

17 # By default, the toolbar only appears for clients from IP addresses


18 # '127.0.0.1' and '::1'.
19 # debugtoolbar.hosts = 127.0.0.1 ::1
20

21 ###
22 # wsgi server configuration
23 ###
24

25 [server:main]
26 use = egg:waitress#main
27 listen = localhost:6543
28

29 ###
30 # logging configuration
31 # https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/
,→logging.html

32 ###
33

34 [loggers]
35 keys = root, myproject
(continues on next page)

0.3. Narrative Documentation 387


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


36

37 [handlers]
38 keys = console
39

40 [formatters]
41 keys = generic
42

43 [logger_root]
44 level = INFO
45 handlers = console
46

47 [logger_myproject]
48 level = DEBUG
49 handlers =
50 qualname = myproject
51

52 [handler_console]
53 class = StreamHandler
54 args = (sys.stderr,)
55 level = NOTSET
56 formatter = generic
57

58 [formatter_generic]
59 format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][
,→%(threadName)s] %(message)s

In this case, the myproject.__init__:main function referred to by the entry point


URI egg:myproject (see development.ini for more information about entry point
URIs, and how they relate to callables) will receive the key/value pairs {pyramid.
reload_templates = true, pyramid.debug_authorization = false,
pyramid.debug_notfound = false, pyramid.debug_routematch = false,
pyramid.default_locale_name = en, and pyramid.includes = pyra-
mid_debugtoolbar}. See Environment Variables and .ini File Settings for the meanings of
these keys.

7. The main function begins by making a configurator. The dictionary captured via the **set-
tings kwarg is passed to the Configurator constructor in its settings argument. The new
configurator holds the application’s settings and is able to commit any configuration declarations
the settings contain.

The settings dictionary contains all the options in the [app:main] section of our .ini file ex-
cept the use option (which is internal to PasteDeploy) such as pyramid.reload_templates,
pyramid.debug_authorization, etc. It is available for use in your code.

388 CONTENTS
The Pyramid Web Framework, Version 2.0.2

8. The main function then calls various methods on the instance of the class Configurator created
in the previous step. The intent of calling these methods is to populate an application registry, which
represents the Pyramid configuration related to the application.

9. The make_wsgi_app() method is called. The result is a router instance. The router is associated
with the application registry implied by the configurator previously populated by other methods run
against the Configurator. The router is a WSGI application.

10. An ApplicationCreated event is emitted (see Using Events for more information about
events).

11. Assuming there were no errors, the main function in myproject returns the router instance cre-
ated by pyramid.config.Configurator.make_wsgi_app() back to pserve. As far
as pserve is concerned, it is ”just another WSGI application”.

12. pserve starts the WSGI server defined within the [server:main] section. In our case, this is
the Waitress server (use = egg:waitress#main), and it will listen on all interfaces on port
6543 for both IPv4 and IPv6 (listen = localhost:6543). The server code itself is what
prints Serving on http://localhost:6543. The server serves the application, and the
application is running, waiting to receive requests.

See also:

Logging configuration is described in the Logging chapter. There, in Request Logging with Paste’s
TransLogger, you will also find an example of how to configure middleware to add pre-packaged func-
tionality to your application.

Deployment Settings

Note that an augmented version of the values passed as **settings to the Configurator construc-
tor is available in Pyramid view callable code as request.registry.settings. You can create
objects you wish to access later from view code, and put them into the dictionary you pass to the configu-
rator as settings. They will then be present in the request.registry.settings dictionary at
application runtime.

0.3. Narrative Documentation 389


The Pyramid Web Framework, Version 2.0.2

390 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.3.7 Request Processing

0.3. Narrative Documentation 391


The Pyramid Web Framework, Version 2.0.2

Once a Pyramid application is up and running, it is ready to accept requests and return responses. What
happens from the time a WSGI request enters a Pyramid application through to the point that Pyramid
hands off a response back to WSGI for upstream processing?

1. A user initiates a request from their browser to the hostname and port number of the WSGI server
used by the Pyramid application.

2. The WSGI server used by the Pyramid application passes the WSGI environment to the __call__
method of the Pyramid router object.

3. A request object is created based on the WSGI environment.

4. The application registry and the request object created in the last step are pushed on to the thread
local stack that Pyramid uses to allow the functions named get_current_request() and
get_current_registry() to work.

5. A NewRequest event is sent to any subscribers.

6. If any route has been defined within application configuration, the Pyramid router calls a URL
dispatch ”route mapper.” The job of the mapper is to examine the request to determine whether
any user-defined route matches the current WSGI environment. The router passes the request as an
argument to the mapper.

7. If any route matches, the route mapper adds the attributes matchdict and matched_route to
the request object. The former contains a dictionary representing the matched dynamic elements of
the request’s PATH_INFO value, and the latter contains the IRoute object representing the route
which matched.

8. A BeforeTraversal event is sent to any subscribers.

9. Continuing, if any route matches, the root object associated with the found route is generated. If the
route configuration which matched has an associated factory argument, then this factory is used
to generate the root object; otherwise a default root factory is used.

However, if no route matches, and if a root_factory argument was passed to the Configurator
constructor, that callable is used to generate the root object. If the root_factory argument
passed to the Configurator constructor was None, a default root factory is used to generate a root
object.

10. The Pyramid router calls a ”traverser” function with the root object and the request. The traverser
function attempts to traverse the root object (using any existing __getitem__ on the root object
and subobjects) to find a context. If the root object has no __getitem__ method, the root itself
is assumed to be the context. The exact traversal algorithm is described in Traversal. The traverser
function returns a dictionary, which contains a context and a view name as well as other ancillary
information.

392 CONTENTS
The Pyramid Web Framework, Version 2.0.2

11. The request is decorated with various names returned from the traverser (such as context,
view_name, and so forth), so they can be accessed via, for example, request.context within
view code.

12. A ContextFound event is sent to any subscribers.

13. Pyramid looks up a view callable using the context, the request, and the view name. If a view
callable doesn’t exist for this combination of objects (based on the type of the context, the type
of the request, and the value of the view name, and any predicate attributes applied to the view
configuration), Pyramid raises a HTTPNotFound exception, which is meant to be caught by a
surrounding exception view.

14. If a view callable was found, Pyramid attempts to call it. If an authorization policy is in use, and the
view configuration is protected by a permission, Pyramid determines whether the view callable being
asked for can be executed by the requesting user based on credential information in the request and
security information attached to the context. If the view execution is allowed, Pyramid calls the view
callable to obtain a response. If view execution is forbidden, Pyramid raises a HTTPForbidden
exception.

15. If any exception is raised within a root factory, by traversal, by a view callable, or by Pyramid itself
(such as when it raises HTTPNotFound or HTTPForbidden), the router catches the exception,
and attaches it to the request as the exception attribute. It then attempts to find a exception view
for the exception that was caught. If it finds an exception view callable, that callable is called, and is
presumed to generate a response. If an exception view that matches the exception cannot be found,
the exception is reraised.

16. The following steps occur only when a response could be successfully generated by a normal view
callable or an exception view callable. Pyramid will attempt to execute any response callback func-
tions attached via add_response_callback(). A NewResponse event is then sent to any
subscribers. The response object’s __call__ method is then used to generate a WSGI response.
The response is sent back to the upstream WSGI server.

17. Pyramid will attempt to execute any finished callback functions attached via
add_finished_callback().

18. The thread local stack is popped.

0.3. Narrative Documentation 393


The Pyramid Web Framework, Version 2.0.2

394 CONTENTS
The Pyramid Web Framework, Version 2.0.2

This is a very high-level overview that leaves out various details. For more detail about subsystems invoked
by the Pyramid router, such as traversal, URL dispatch, views, and event processing, see URL Dispatch,
Views, and Using Events.

0.3.8 URL Dispatch

URL dispatch provides a simple way to map URLs to view code using a simple pattern matching language.
An ordered set of patterns is checked one by one. If one of the patterns matches the path information
associated with a request, a particular view callable is invoked. A view callable is a specific bit of code,
defined in your application, that receives the request and returns a response object.

High-Level Operational Overview

If any route configuration is present in an application, the Pyramid Router checks every incoming request
against an ordered set of URL matching patterns present in a route map.

If any route pattern matches the information in the request, Pyramid will invoke the view lookup process
to find a matching view.

If no route pattern in the route map matches the information in the request provided in your application,
Pyramid will fail over to using traversal to perform resource location and view lookup.

Route Configuration

Route configuration is the act of adding a new route to an application. A route has a name, which acts as an
identifier to be used for URL generation. The name also allows developers to associate a view configuration
with the route. A route also has a pattern, meant to match against the PATH_INFO portion of a URL (the
portion following the scheme and port, e.g., /foo/bar in the URL http://localhost:8080/
foo/bar). It also optionally has a factory and a set of route predicate attributes.

Configuring a Route to Match a View

The pyramid.config.Configurator.add_route() method adds a single route configuration


to the application registry. Here’s an example:

0.3. Narrative Documentation 395


The Pyramid Web Framework, Version 2.0.2

# "config" below is presumed to be an instance of the


# pyramid.config.Configurator class; "myview" is assumed
# to be a "view callable" function
from views import myview
config.add_route('myroute', '/prefix/{one}/{two}')
config.add_view(myview, route_name='myroute')

When a view callable added to the configuration by way of add_view() becomes associated with a route
via its route_name predicate, that view callable will always be found and invoked when the associated
route pattern matches during a request.

More commonly, you will not use any add_view statements in your project’s ”setup” code. You will
instead use add_route statements, and use a scan to associate view callables with routes. For example,
if this is a portion of your project’s __init__.py:

config.add_route('myroute', '/prefix/{one}/{two}')
config.scan('mypackage')

Note that we don’t call add_view() in this setup code. However, the above scan execution config.
scan('mypackage') will pick up each configuration decoration, including any objects decorated with
the pyramid.view.view_config decorator in the mypackage Python package. For example, if
you have a views.py in your package, a scan will pick up any of its configuration decorators, so we can
add one there that references myroute as a route_name parameter:

from pyramid.view import view_config


from pyramid.response import Response

@view_config(route_name='myroute')
def myview(request):
return Response('OK')

The above combination of add_route and scan is completely equivalent to using the previous combi-
nation of add_route and add_view.

Route Pattern Syntax

The syntax of the pattern matching language used by Pyramid URL dispatch in the pattern argument is
straightforward. It is close to that of the Routes system used by Pylons.

The pattern used in route configuration may start with a slash character. If the pattern does not start with
a slash character, an implicit slash will be prepended to it at matching time. For example, the following
patterns are equivalent:

396 CONTENTS
The Pyramid Web Framework, Version 2.0.2

{foo}/bar/baz

and:

/{foo}/bar/baz

If a pattern is a valid URL it won’t be matched against an incoming request. Instead it can be useful for
generating external URLs. See External routes for details.

A pattern segment (an individual item between / characters in the pattern) may either be a literal string (e.g.,
foo) or it may be a replacement marker (e.g., {foo}), or a certain combination of both. A replacement
marker does not need to be preceded by a / character.

A replacement marker is in the format {name}, where this means ”accept any characters up to the next
slash character and use this as the name matchdict value.”

A replacement marker in a pattern must begin with an uppercase or lowercase ASCII letter or an under-
score, and can be composed only of uppercase or lowercase ASCII letters, underscores, and numbers. For
example: a, a_b, _b, and b9 are all valid replacement marker names, but 0a is not.

Changed in version 1.2: A replacement marker could not start with an underscore until Pyramid 1.2.
Previous versions required that the replacement marker start with an uppercase or lowercase letter.

A matchdict is the dictionary representing the dynamic parts extracted from a URL based on the routing
pattern. It is available as request.matchdict. For example, the following pattern defines one literal
segment (foo) and two replacement markers (baz, and bar):

foo/{baz}/{bar}

The above pattern will match these URLs, generating the following matchdicts:

foo/1/2 -> {'baz': '1', 'bar': '2'}


foo/abc/def -> {'baz': 'abc', 'bar': 'def'}

It will not match the following patterns however:

foo/1/2/ -> No match (trailing slash)


bar/abc/def -> First segment literal mismatch

The match for a segment replacement marker in a segment will be done only up to the first non-
alphanumeric character in the segment in the pattern. So, for instance, if this route pattern was used:

0.3. Narrative Documentation 397


The Pyramid Web Framework, Version 2.0.2

foo/{name}.html

The literal path /foo/biz.html will match the above route pattern, and the match result will be
{'name': 'biz'}. However, the literal path /foo/biz will not match, because it does not con-
tain a literal .html at the end of the segment represented by {name}.html (it only contains biz, not
biz.html).

To capture both segments, two replacement markers can be used:

foo/{name}.{ext}

The literal path /foo/biz.html will match the above route pattern, and the match result will be
{'name': 'biz', 'ext': 'html'}. This occurs because there is a literal part of . (period)
between the two replacement markers {name} and {ext}.

Replacement markers can optionally specify a regular expression which will be used to decide whether
a path segment should match the marker. To specify that a replacement marker should match only a
specific set of characters as defined by a regular expression, you must use a slightly extended form of
replacement marker syntax. Within braces, the replacement marker name must be followed by a colon, then
directly thereafter, the regular expression. The default regular expression associated with a replacement
marker [^/]+ matches one or more characters which are not a slash. For example, under the hood, the
replacement marker {foo} can more verbosely be spelled as {foo:[^/]+}. You can change this to
be an arbitrary regular expression to match an arbitrary sequence of characters, such as {foo:\d+} to
match only digits.

It is possible to use two replacement markers without any literal characters between them, for instance
/{foo}{bar}. However, this would be a nonsensical pattern without specifying a custom regular ex-
pression to restrict what each marker captures.

Segments must contain at least one character in order to match a segment replacement marker. For example,
for the URL /abc/:

• /abc/{foo} will not match.

• /{foo}/ will match.

Note that values representing matched path segments will be URL-unquoted and decoded from UTF-8
into Unicode within the matchdict. So for instance, the following pattern:

398 CONTENTS
The Pyramid Web Framework, Version 2.0.2

foo/{bar}

When matching the following URL:

http://example.com/foo/La%20Pe%C3%B1a

The matchdict will look like so (the value is URL-decoded / UTF-8 decoded):

{'bar': 'La Pe\xf1a'}

Literal strings in the path segment should represent the decoded value of the PATH_INFO provided to
Pyramid. You don’t want to use a URL-encoded value or a bytestring representing the literal encoded as
UTF-8 in the pattern. For example, rather than this:

/Foo%20Bar/{baz}

You’ll want to use something like this:

/Foo Bar/{baz}

For patterns that contain ”high-order” characters in its literals, you’ll want to use a Unicode value as the
pattern as opposed to any URL-encoded or UTF-8-encoded value. For example, you might be tempted to
use a bytestring pattern like this:

/La Pe\xc3\xb1a/{x}

But this will either cause an error at startup time or it won’t match properly. You’ll want to use a Unicode
value as the pattern instead rather than raw bytestring escapes. You can use a high-order Unicode value
as the pattern by using Python source file encoding plus the ”real” character in the Unicode pattern in the
source, like so:

/La Peña/{x}

Or you can ignore source file encoding and use equivalent Unicode escape characters in the pattern.

0.3. Narrative Documentation 399


The Pyramid Web Framework, Version 2.0.2

/La Pe\xf1a/{x}

Dynamic segment names cannot contain high-order characters, so this applies only to literals in the pattern.

If the pattern has a * in it, the name which follows it is considered a ”remainder match”. A remainder
match must come at the end of the pattern. Unlike segment replacement markers, it does not need to be
preceded by a slash. For example:

foo/{baz}/{bar}*fizzle

The above pattern will match these URLs, generating the following matchdicts:

foo/1/2/ ->
{'baz': '1', 'bar': '2', 'fizzle': ()}

foo/abc/def/a/b/c ->
{'baz': 'abc', 'bar': 'def', 'fizzle': ('a', 'b', 'c')}

Note that when a *stararg remainder match is matched, the value put into the matchdict is turned into
a tuple of path segments representing the remainder of the path. These path segments are URL-unquoted
and decoded from UTF-8 into Unicode. For example, for the following pattern:

foo/*fizzle

When matching the following path:

/foo/La%20Pe%C3%B1a/a/b/c

Will generate the following matchdict:

{'fizzle': ('La Pe\xf1a', 'a', 'b', 'c')}

By default, the *stararg will parse the remainder sections into a tuple split by segment. Changing the
regular expression used to match a marker can also capture the remainder of the URL, for example:

foo/{baz}/{bar}{fizzle:.*}

The above pattern will match these URLs, generating the following matchdicts:

400 CONTENTS
The Pyramid Web Framework, Version 2.0.2

foo/1/2/ -> {'baz': '1', 'bar': '2', 'fizzle': ''}


foo/abc/def/a/b/c -> {'baz': 'abc', 'bar': 'def', 'fizzle': 'a/b/c'}

This occurs because the default regular expression for a marker is [^/]+ which will match everything up
to the first /, while {fizzle:.*} will result in a regular expression match of .* capturing the remainder
into a single value.

Route Declaration Ordering

Route configuration declarations are evaluated in a specific order when a request enters the system. As a
result, the order of route configuration declarations is very important. The order in which route declarations
are evaluated is the order in which they are added to the application at startup time. (This is unlike a
different way of mapping URLs to code that Pyramid provides, named traversal, which does not depend
on pattern ordering).

For routes added via the add_route method, the order that routes are evaluated is the order in which
they are added to the configuration imperatively.

For example, route configuration statements with the following patterns might be added in the following
order:

members/{def}
members/abc

In such a configuration, the members/abc pattern would never be matched. This is because the match
ordering will always match members/{def} first; the route configuration with members/abc will
never be evaluated.

Route Configuration Arguments

Route configuration add_route statements may specify a large number of arguments. They are docu-
mented as part of the API documentation at pyramid.config.Configurator.add_route().

Many of these arguments are route predicate arguments. A route predicate argument specifies that some
aspect of the request must be true for the associated route to be considered a match during the route match-
ing process. Examples of route predicate arguments are pattern, xhr, and request_method.

Other arguments are name and factory. These arguments represent neither predicates nor view con-
figuration information.

0.3. Narrative Documentation 401


The Pyramid Web Framework, Version 2.0.2

Route Matching

The main purpose of route configuration is to match (or not match) the PATH_INFO present in the WSGI
environment provided during a request against a URL path pattern. PATH_INFO represents the path
portion of the URL that was requested.

The way that Pyramid does this is very simple. When a request enters the system, for each route config-
uration declaration present in the system, Pyramid checks the request’s PATH_INFO against the pattern
declared. This checking happens in the order that the routes were declared via pyramid.config.
Configurator.add_route().

When a route configuration is declared, it may contain route predicate arguments. All route predicates
associated with a route declaration must be True for the route configuration to be used for a given request
during a check. If any predicate in the set of route predicate arguments provided to a route configuration
returns False during a check, that route is skipped and route matching continues through the ordered set
of routes.

If any route matches, the route matching process stops and the view lookup subsystem takes over to find
the most reasonable view callable for the matched route. Most often, there’s only one view that will
match (a view configured with a route_name argument matching the matched route). To gain a better
understanding of how routes and views are associated in a real application, you can use the pviews
command, as documented in pviews: Displaying Matching Views for a Given URL.

If no route matches after all route patterns are exhausted, Pyramid falls back to traversal to do resource
location and view lookup.

The Matchdict

When the URL pattern associated with a particular route configuration is matched by a request, a dictionary
named matchdict is added as an attribute of the request object. Thus, request.matchdict will
contain the values that match replacement patterns in the pattern element. The keys in a matchdict will
be strings. The values will be Unicode objects.

If no route URL pattern matches, the matchdict object attached to the request will be None.

402 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The Matched Route

When the URL pattern associated with a particular route configuration is matched by a request, an
object named matched_route is added as an attribute of the request object. Thus, request.
matched_route will be an object implementing the IRoute interface which matched the request.
The most useful attribute of the route object is name, which is the name of the route that matched.

If no route URL pattern matches, the matched_route object attached to the request will be None.

Routing Examples

Let’s check out some examples of how route configuration statements might be commonly declared, and
what will happen if they are matched by the information present in a request.

Example 1

The simplest route declaration which configures a route match to directly result in a particular view callable
being invoked:

1 config.add_route('idea', 'site/{id}')
2 config.scan()

When a route configuration with a view attribute is added to the system, and an incoming request matches
the pattern of the route configuration, the view callable named as the view attribute of the route config-
uration will be invoked.
Recall that the @view_config is equivalent to calling config.add_view, because the config.
scan() call will import mypackage.views, shown below, and execute config.add_view under
the hood. Each view then maps the route name to the matching view callable. In the case of the above
example, when the URL of a request matches /site/{id}, the view callable at the Python dotted path
name mypackage.views.site_view will be called with the request. In other words, we’ve associ-
ated a view callable directly with a route pattern.
When the /site/{id} route pattern matches during a request, the site_view view callable is in-
voked with that request as its sole argument. When this route matches, a matchdict will be generated
and attached to the request as request.matchdict. If the specific URL matched is /site/1, the
matchdict will be a dictionary with a single key, id; the value will be the string '1', ex.: {'id':
'1'}.
The mypackage.views module referred to above might look like so:

0.3. Narrative Documentation 403


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.view import view_config


2 from pyramid.response import Response
3

4 @view_config(route_name='idea')
5 def site_view(request):
6 return Response(request.matchdict['id'])

The view has access to the matchdict directly via the request, and can access variables within it that match
keys present as a result of the route pattern.

See Views, and View Configuration for more information about views.

Example 2

Below is an example of a more complicated set of route statements you might add to your application:

1 config.add_route('idea', 'ideas/{idea}')
2 config.add_route('user', 'users/{user}')
3 config.add_route('tag', 'tags/{tag}')
4 config.scan()

Here is an example of a corresponding mypackage.views module:

1 from pyramid.view import view_config


2 from pyramid.response import Response
3

4 @view_config(route_name='idea')
5 def idea_view(request):
6 return Response(request.matchdict['idea'])
7

8 @view_config(route_name='user')
9 def user_view(request):
10 user = request.matchdict['user']
11 return Response('The user is {}.'.format(user))
12

13 @view_config(route_name='tag')
14 def tag_view(request):
15 tag = request.matchdict['tag']
16 return Response('The tag is {}.'.format(tag))

The above configuration will allow Pyramid to service URLs in these forms:

404 CONTENTS
The Pyramid Web Framework, Version 2.0.2

/ideas/{idea}
/users/{user}
/tags/{tag}

• When a URL matches the pattern /ideas/{idea}, the view callable available at the dotted
Python pathname mypackage.views.idea_view will be called. For the specific URL /
ideas/1, the matchdict generated and attached to the request will consist of {'idea':
'1'}.

• When a URL matches the pattern /users/{user}, the view callable available at the dotted
Python pathname mypackage.views.user_view will be called. For the specific URL /
users/1, the matchdict generated and attached to the request will consist of {'user':
'1'}.

• When a URL matches the pattern /tags/{tag}, the view callable available at the dotted Python
pathname mypackage.views.tag_view will be called. For the specific URL /tags/1, the
matchdict generated and attached to the request will consist of {'tag': '1'}.

In this example we’ve again associated each of our routes with a view callable directly. In all cases, the
request, which will have a matchdict attribute detailing the information found in the URL by the process
will be passed to the view callable.

Example 3

The context resource object passed in to a view found as the result of URL dispatch will, by default, be
an instance of the object returned by the root factory configured at startup time (the root_factory
argument to the Configurator used to configure the application).

You can override this behavior by passing in a factory argument to the add_route() method for a
particular route. The factory should be a callable that accepts a request and returns an instance of a
class that will be the context resource used by the view.

An example of using a route with a factory:

1 config.add_route('idea', 'ideas/{idea}', factory='myproject.resources.Idea


,→')

2 config.scan()

The above route will manufacture an Idea resource as a context, assuming that mypackage.
resources.Idea resolves to a class that accepts a request in its __init__. For example:

0.3. Narrative Documentation 405


The Pyramid Web Framework, Version 2.0.2

1 class Idea(object):
2 def __init__(self, request):
3 pass

In a more complicated application, this root factory might be a class representing a SQLAlchemy model.
The view mypackage.views.idea_view might look like this:

1 @view_config(route_name='idea')
2 def idea_view(request):
3 idea = request.context
4 return Response(idea)

Here, request.context is an instance of Idea. If indeed the resource object is a SQLAlchemy


model, you do not even have to perform a query in the view callable, since you have access to the resource
via request.context.

See Route Factories for more details about how to use route factories.

Matching the Root URL

It’s not entirely obvious how to use a route pattern to match the root URL (”/”). To do so, give the empty
string as a pattern in a call to add_route():

1 config.add_route('root', '')

Or provide the literal string / as the pattern:

1 config.add_route('root', '/')

Generating Route URLs

Use the pyramid.request.Request.route_url() method to generate URLs based on route


patterns. For example, if you’ve configured a route with the name ”foo” and the pattern ”{a}/{b}/{c}”,
you might do this.

406 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 url = request.route_url('foo', a='1', b='2', c='3')

This would return something like the string http://example.com/1/2/3 (at least if the current
protocol and hostname implied http://example.com).

To generate only the path portion of a URL from a route, use the pyramid.request.Request.
route_path() API instead of route_url().

url = request.route_path('foo', a='1', b='2', c='3')

This will return the string /1/2/3 rather than a full URL.

Replacement values passed to route_url or route_path must be Unicode or bytestrings encoded


in UTF-8. One exception to this rule exists: if you’re trying to replace a ”remainder” match value (a
*stararg replacement value), the value may be a tuple containing Unicode strings or UTF-8 strings.

Note that URLs and paths generated by route_url and route_path are always URL-quoted string
types (they contain no non-ASCII characters). Therefore, if you’ve added a route like so:

config.add_route('la', '/La Peña/{city}')

And you later generate a URL using route_path or route_url like so:

url = request.route_path('la', city='Québec')

You will wind up with the path encoded to UTF-8 and URL-quoted like so:

/La%20Pe%C3%B1a/Qu%C3%A9bec

If you have a *stararg remainder dynamic part of your route pattern:

config.add_route('abc', 'a/b/c/*foo')

And you later generate a URL using route_path or route_url using a string as the replacement
value:

0.3. Narrative Documentation 407


The Pyramid Web Framework, Version 2.0.2

url = request.route_path('abc', foo='Québec/biz')

The value you pass will be URL-quoted except for embedded slashes in the result:

/a/b/c/Qu%C3%A9bec/biz

You can get a similar result by passing a tuple composed of path elements:

url = request.route_path('abc', foo=('Québec', 'biz'))

Each value in the tuple will be URL-quoted and joined by slashes in this case:

/a/b/c/Qu%C3%A9bec/biz

Static Routes

Routes may be added with a static keyword argument. For example:

1 config = Configurator()
2 config.add_route('page', '/page/{action}', static=True)

Routes added with a True static keyword argument will never be considered for matching at request
time. Static routes are useful for URL generation purposes only. As a result, it is usually nonsensical to
provide other non-name and non-pattern arguments to add_route() when static is passed as
True, as none of the other arguments will ever be employed. A single exception to this rule is use of the
pregenerator argument, which is not ignored when static is True.

External routes are implicitly static.

New in version 1.1: the static argument to add_route().

External Routes

New in version 1.5.

Route patterns that are valid URLs, are treated as external routes. Like static routes they are useful for
URL generation purposes only and are never considered for matching at request time.

408 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 >>> config = Configurator()


2 >>> config.add_route('youtube', 'https://youtube.com/watch/{video_id}')
3 ...
4 >>> request.route_url('youtube', video_id='oHg5SJYRHA0')
5 >>> "https://youtube.com/watch/oHg5SJYRHA0"

Most pattern replacements and calls to pyramid.request.Request.route_url() will work as


expected. However, calls to pyramid.request.Request.route_path() against external pat-
terns will raise an exception, and passing _app_url to route_url() to generate a URL against a
route that has an external pattern will also raise an exception.

Redirecting to Slash-Appended Routes

For behavior like Django’s APPEND_SLASH=True, use the append_slash argument to pyramid.
config.Configurator.add_notfound_view() or the equivalent append_slash argument
to the pyramid.view.notfound_view_config decorator.

Adding append_slash=True is a way to automatically redirect requests where the URL lacks a trail-
ing slash, but requires one to match the proper route. When configured, along with at least one other
route in your application, this view will be invoked if the value of PATH_INFO does not already end
in a slash, and if the value of PATH_INFO plus a slash matches any route’s pattern. In this case it
does an HTTP redirect to the slash-appended PATH_INFO. In addition you may pass anything that im-
plements pyramid.interfaces.IResponse which will then be used in place of the default class
(pyramid.httpexceptions.HTTPFound).

Let’s use an example. If the following routes are configured in your application:

1 from pyramid.httpexceptions import HTTPNotFound


2

3 def notfound(request):
4 return HTTPNotFound()
5

6 def no_slash(request):
7 return Response('No slash')
8

9 def has_slash(request):
10 return Response('Has slash')
11

12 def main(g, **settings):


13 config = Configurator()
14 config.add_route('noslash', 'no_slash')
(continues on next page)

0.3. Narrative Documentation 409


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


15 config.add_route('hasslash', 'has_slash/')
16 config.add_view(no_slash, route_name='noslash')
17 config.add_view(has_slash, route_name='hasslash')
18 config.add_notfound_view(notfound, append_slash=True)

If a request enters the application with the PATH_INFO value of /no_slash, the first route will match
and the browser will show ”No slash”. However, if a request enters the application with the PATH_INFO
value of /no_slash/, no route will match, and the slash-appending not found view will not find a
matching route with an appended slash. As a result, the notfound view will be called and it will return
a ”Not found” body.

If a request enters the application with the PATH_INFO value of /has_slash/, the second route will
match. If a request enters the application with the PATH_INFO value of /has_slash, a route will be
found by the slash-appending Not Found View. An HTTP redirect to /has_slash/ will be returned to
the user’s browser. As a result, the notfound view will never actually be called.

The following application uses the pyramid.view.notfound_view_config and pyramid.


view.view_config decorators and a scan to do exactly the same job:

1 from pyramid.httpexceptions import HTTPNotFound


2 from pyramid.view import notfound_view_config, view_config
3

4 @notfound_view_config(append_slash=True)
5 def notfound(request):
6 return HTTPNotFound()
7

8 @view_config(route_name='noslash')
9 def no_slash(request):
10 return Response('No slash')
11

12 @view_config(route_name='hasslash')
13 def has_slash(request):
14 return Response('Has slash')
15

16 def main(g, **settings):


17 config = Configurator()
18 config.add_route('noslash', 'no_slash')
19 config.add_route('hasslash', 'has_slash/')
20 config.scan()

410 CONTENTS
The Pyramid Web Framework, Version 2.0.2

You should not rely on this mechanism to redirect POST requests. The redirect of the slash-
appending Not Found View will turn a POST request into a GET, losing any POST data in the original
request.

See pyramid.view and Changing the Not Found View for a more general description of how to configure a
view and/or a Not Found View.

Debugging Route Matching

It’s useful to be able to take a peek under the hood when requests that enter your application aren’t matching
your routes as you expect them to. To debug route matching, use the PYRAMID_DEBUG_ROUTEMATCH
environment variable or the pyramid.debug_routematch configuration file setting (set either to
true). Details of the route matching decision for a particular request to the Pyramid application will be
printed to the stderr of the console which you started the application from. For example:

1 PYRAMID_DEBUG_ROUTEMATCH=true $VENV/bin/pserve development.ini


2 Starting server in PID 13586.
3 serving on 0.0.0.0:6543 view at http://127.0.0.1:6543
4 2010-12-16 14:45:19,956 no route matched for url \
5 http://localhost:6543/wontmatch
6 2010-12-16 14:45:20,010 no route matched for url \
7 http://localhost:6543/favicon.ico
8 2010-12-16 14:41:52,084 route matched for url \
9 http://localhost:6543/static/logo.png; \
10 route_name: 'static/', ....

See Environment Variables and .ini File Settings for more information about how and where to set these
values.

You can also use the proutes command to see a display of all the routes configured in your application.
For more information, see proutes: Displaying All Application Routes.

Using a Route Prefix to Compose Applications

New in version 1.2.

The pyramid.config.Configurator.include() method allows configuration statements to be


included from separate files. See Rules for Building an Extensible Application for information about this

0.3. Narrative Documentation 411


The Pyramid Web Framework, Version 2.0.2

method. Using pyramid.config.Configurator.include() allows you to build your applica-


tion from small and potentially reusable components.

The pyramid.config.Configurator.include() method accepts an argument named


route_prefix which can be useful to authors of URL-dispatch-based applications. If
route_prefix is supplied to the include method, it must be a string. This string represents a
route prefix that will be prepended to all route patterns added by the included configuration. Any calls
to pyramid.config.Configurator.add_route() within the included callable will have their
pattern prefixed with the value of route_prefix. This can be used to help mount a set of routes at
a different location than the included callable’s author intended while still maintaining the same route
names. For example:

1 from pyramid.config import Configurator


2

3 def users_include(config):
4 config.add_route('show_users', '/show')
5

6 def main(global_config, **settings):


7 config = Configurator()
8 config.include(users_include, route_prefix='/users')

In the above configuration, the show_users route will have an effective route pattern of /users/show
instead of /show because the route_prefix argument will be prepended to the pattern. The route will
then only match if the URL path is /users/show, and when the pyramid.request.Request.
route_url() function is called with the route name show_users, it will generate a URL with that
same path.

To create a route that matches requests to the route_prefix without a trailing slash, pass in-
herit_slash=True to the call to add_route.

1 from pyramid.config import Configurator


2

3 def users_include(config):
4 config.add_route('show_users', '', inherit_slash=True)
5

6 def main(global_config, **settings):


7 config = Configurator()
8 config.include(users_include, route_prefix='/users')

The above configuration will match /users instead of /users/.

Route prefixes are recursive, so if a callable executed via an include itself turns around and includes another
callable, the second-level route prefix will be prepended with the first:

412 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.config import Configurator


2

3 def timing_include(config):
4 config.add_route('show_times', '/times')
5

6 def users_include(config):
7 config.add_route('show_users', '/show')
8 config.include(timing_include, route_prefix='/timing')
9

10 def main(global_config, **settings):


11 config = Configurator()
12 config.include(users_include, route_prefix='/users')

In the above configuration, the show_users route will still have an effective route pattern of /users/
show. The show_times route, however, will have an effective pattern of /users/timing/times.

Route prefixes have no impact on the requirement that the set of route names in any given Pyramid con-
figuration must be entirely unique. If you compose your URL dispatch application out of many small sub-
applications using pyramid.config.Configurator.include(), it’s wise to use a dotted name
for your route names so they’ll be unlikely to conflict with other packages that may be added in the future.
For example:

1 from pyramid.config import Configurator


2

3 def timing_include(config):
4 config.add_route('timing.show_times', '/times')
5

6 def users_include(config):
7 config.add_route('users.show_users', '/show')
8 config.include(timing_include, route_prefix='/timing')
9

10 def main(global_config, **settings):


11 config = Configurator()
12 config.include(users_include, route_prefix='/users')

A convenience context manager exists to set the route prefix for any pyramid.config.
Configurator.add_route() or pyramid.config.Configurator.include() calls
within the context.

1 from pyramid.config import Configurator


2

3 def timing_include(config):
(continues on next page)

0.3. Narrative Documentation 413


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


4 config.add_route('timing.show_times', '/times')
5

6 def main(global_config, **settings)


7 config = Configurator()
8 with config.route_prefix_context('/timing'):
9 config.include(timing_include)
10 config.add_route('timing.average', '/average')

Custom Route Predicates

A predicate is a callable that accepts two arguments: a dictionary conventionally named info, and the
current request object.

The info dictionary has a number of contained values, including match and route. match is a dictio-
nary which represents the arguments matched in the URL by the route. route is an object representing
the route which was matched (see pyramid.interfaces.IRoute for the API of such a route object).

info['match'] is useful when predicates need access to the route match. Imagine you want to define
a route when a part of the URL matches some specific values. You could define three view configurations,
each one with its own match_param value (see Predicate Arguments), but you want to think of it as one
route, and associate it with one view. See this code:

1 class AnyOfPredicate:
2 def __init__(self, val, info):
3 self.segment_name = val[0]
4 self.allowed = tuple(val[1:])
5

6 def text(self):
7 args = (self.segment_name,) + self.allowed
8 return 'any_of = %s' % (args,)
9

10 phash = text
11

12 def __call__(self, info, request):


13 return info['match'][self.segment_name] in self.allowed
14

15

16 config.add_route_predicate('any_of', AnyOfPredicate)
17 config.add_route('route_to_num', '/{num}', any_of=('num', 'one', 'two',
,→'three'))

414 CONTENTS
The Pyramid Web Framework, Version 2.0.2

We register this class as a predicate factory with the any_of keyword argument name. Then we use
that new keyword argument with add_route(). When the route is requested, Pyramid instantiates the
AnyOfPredicate class using the value passed to the any_of argument. (The info parameter passed
to the factory contains some metadata, you can ignore it for now.) The resulting instance is a predicate.
It will determine whether incoming requests satisfy its condition. In the example above, a request for /
three would match the route’s URL pattern and satisfy the route’s predicate because three is one of
the allowed values, so the route would be matched. However a request for /millions will match the
route’s URL pattern but would not satisfy the route’s predicate, and the route would not be matched.

A custom route predicate may also modify the match dictionary. For instance, a predicate might do some
type conversion of values:

1 class IntegersPredicate:
2 def __init__(self, val, info):
3 self.segment_names = val
4

5 def text(self):
6 return 'integers = %s' % (self.segment_names,)
7

8 phash = text
9

10 def __call__(self, info, request):


11 match = info['match']
12 for segment_name in self.segment_names:
13 try:
14 match[segment_name] = int(match[segment_name])
15 except (TypeError, ValueError):
16 pass
17 return True
18

19

20 config.add_route_predicate('integers', IntegersPredicate)
21 config.add_route('ymd', '/{year}/{month}/{day}',
22 integers=('year', 'month', 'day'))

Note that a conversion predicate is still a predicate, so it must return True or False. A predicate that
does only conversion, such as the one we demonstrate above, should unconditionally return True.

To avoid the try/except uncertainty, the route pattern can contain regular expressions specifying require-
ments for that marker. For instance:

1 class IntegersPredicate:
2 def __init__(self, val, info):
3 self.segment_names = val
(continues on next page)

0.3. Narrative Documentation 415


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


4

5 def text(self):
6 return 'integers = %s' % (self.segment_names,)
7

8 phash = text
9

10 def __call__(self, info, request):


11 match = info['match']
12 for segment_name in self.segment_names:
13 match[segment_name] = int(match[segment_name])
14 return True
15

16

17 config.add_route_predicate('integers', IntegersPredicate)
18 config.add_route('ymd', r'/{year:\d+}/{month:\d+}/{day:\d+}',
19 integers=('year', 'month', 'day'))

Now the try/except is no longer needed because the route will not match at all unless these markers match
\d+ which requires them to be valid digits for an int type conversion.

The match dictionary passed within info to each predicate attached to a route will be the same dictionary.
Therefore, when registering a custom predicate which modifies the match dict, the code registering the
predicate should usually arrange for the predicate to be the last custom predicate in the custom predicate
list. Otherwise, custom predicates which fire subsequent to the predicate which performs the match
modification will receive the modified match dictionary.

It is a poor idea to rely on ordering of custom predicates to build a conversion pipeline, where
one predicate depends on the side effect of another. For instance, it’s a poor idea to register two custom
predicates, one which handles conversion of a value to an int, the next which handles conversion of
that integer to some custom object. Just do all that in a single custom predicate.

The route object in the info dict is an object that has two useful attributes: name and pattern. The
name attribute is the route name. The pattern attribute is the route pattern. Here’s an example of using
the route in a set of route predicates:

1 class TwentyTenPredicate:
2 def __init__(self, val, info):
3 pass
4

(continues on next page)

416 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


5 def text(self):
6 return "twenty_ten = True"
7

8 phash = text
9

10 def __call__(self, info, request):


11 if info['route'].name in ('ymd', 'ym', 'y'):
12 return info['match']['year'] == '2010'
13

14 config.add_route_predicate('twenty_ten', TwentyTenPredicate)
15 config.add_route('y', '/{year}', twenty_ten=True)
16 config.add_route('ym', '/{year}/{month}', twenty_ten=True)
17 config.add_route('ymd', '/{year}/{month}/{day}', twenty_ten=True)

The above predicate, when added to a number of route configurations ensures that the year match argument
is 2010 if and only if the route name is ymd, ym, or y.

The text method is a way to caption the predicates. This will help you with the pviews command (see
proutes: Displaying All Application Routes) and the pyramid_debugtoolbar.

The phash (”predicate hash”) method should return a string that uniquely identifies a specific predicate.
A good way to do that is to use the same argument name and value that are in the call to add_route,
like in the examples above.

See also:

See Adding a Custom View, Route, or Subscriber Predicate for more information about custom view, route,
and subscriber predicates.

See also pyramid.interfaces.IRoute for more API documentation about route objects.

Route Factories

Although it is not a particularly common need in basic applications, a ”route” configuration declaration
can mention a ”factory”. When a route matches a request, and a factory is attached to the route, the root
factory passed at startup time to the Configurator is ignored. Instead the factory associated with the route
is used to generate a root object. This object will usually be used as the context resource of the view
callable ultimately found via view lookup.

0.3. Narrative Documentation 417


The Pyramid Web Framework, Version 2.0.2

1 config.add_route('abc', '/abc',
2 factory='myproject.resources.root_factory')
3 config.add_view('myproject.views.theview', route_name='abc')

The factory can either be a Python object or a dotted Python name (a string) which points to such a Python
object, as it is above.

In this way, each route can use a different factory, making it possible to supply a different context resource
object to the view related to each particular route.

A factory must be a callable which accepts a request and returns an arbitrary Python object. For example,
the below class can be used as a factory:

1 class Mine(object):
2 def __init__(self, request):
3 pass

A route factory is actually conceptually identical to the root factory described at The Resource Tree.

Supplying a different resource factory for each route is useful when you’re trying to use a Pyramid au-
thorization policy to provide declarative, ”context sensitive” security checks. Each resource can maintain
a separate ACL, as documented in Using Pyramid Security with URL Dispatch. It is also useful when
you wish to combine URL dispatch with traversal as documented within Combining Traversal and URL
Dispatch.

Using Pyramid Security with URL Dispatch

Pyramid provides its own security framework which consults an authorization policy before allowing any
application code to be called. This framework operates in terms of an access control list, which is stored
as an __acl__ attribute of a resource object. A common thing to want to do is to attach an __acl__
to the resource object dynamically for declarative security purposes. You can use the factory argument
that points at a factory which attaches a custom __acl__ to an object at its creation time.

Such a factory might look like so:

1 class Article(object):
2 def __init__(self, request):
3 matchdict = request.matchdict
4 article = matchdict.get('article', None)
5 if article == '1':
6 self.__acl__ = [ (Allow, 'editor', 'view') ]

418 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If the route archives/{article} is matched, and the article number is 1, Pyramid will generate an
Article context resource with an ACL on it that allows the editor principal the view permission.
Obviously you can do more generic things than inspect the route’s match dict to see if the article
argument matches a particular string. Our sample Article factory class is not very ambitious.

See Security for more information about Pyramid security and ACLs.

Route View Callable Registration and Lookup Details

When a request enters the system which matches the pattern of the route, the usual result is simple: the
view callable associated with the route is invoked with the request that caused the invocation.

For most usage, you needn’t understand more than this. How it works is an implementation detail. In the
interest of completeness, however, we’ll explain how it does work in this section. You can skip it if you’re
uninterested.

When a view is associated with a route configuration, Pyramid ensures that a view configuration is regis-
tered that will always be found when the route pattern is matched during a request. To do so:

• A special route-specific interface is created at startup time for each route configuration declaration.

• When an add_view statement mentions a route name attribute, a view configuration is regis-
tered at startup time. This view configuration uses a route-specific interface as a request type.

• At runtime, when a request causes any route to match, the request object is decorated with the route-
specific interface.

• The fact that the request is decorated with a route-specific interface causes the view lookup machinery
to always use the view callable registered using that interface by the route configuration to service
requests that match the route pattern.

As we can see from the above description, technically, URL dispatch doesn’t actually map a URL pattern
directly to a view callable. Instead URL dispatch is a resource location mechanism. A Pyramid resource
location subsystem (i.e., URL dispatch or traversal) finds a resource object that is the context of a request.
Once the context is determined, a separate subsystem named view lookup is then responsible for finding
and invoking a view callable based on information available in the context and the request. When URL
dispatch is used, the resource location and view lookup subsystems provided by Pyramid are still being
utilized, but in a way which does not require a developer to understand either of them in detail.

If no route is matched using URL dispatch, Pyramid falls back to traversal to handle the request.

0.3. Narrative Documentation 419


The Pyramid Web Framework, Version 2.0.2

References

A tutorial showing how URL dispatch can be used to create a Pyramid application exists in SQLAlchemy
+ URL dispatch wiki tutorial.

0.3.9 Views

One of the primary jobs of Pyramid is to find and invoke a view callable when a request reaches your
application. View callables are bits of code which do something interesting in response to a request made
to your application. They are the ”meat” of any interesting web application.

A Pyramid view callable is often referred to in conversational shorthand as a view. In this docu-
mentation, however, we need to use less ambiguous terminology because there are significant differences
between view configuration, the code that implements a view callable, and the process of view lookup.

This chapter describes how view callables should be defined. We’ll have to wait until a following chapter
(entitled View Configuration) to find out how we actually tell Pyramid to wire up view callables to particular
URL patterns and other request circumstances.

View Callables

View callables are, at the risk of sounding obvious, callable Python objects. Specifically, view callables can
be functions, classes, or instances that implement a __call__ method (making the instance callable).

View callables must, at a minimum, accept a single argument named request. This argument represents
a Pyramid Request object. A request object represents a WSGI environment provided to Pyramid by the
upstream WSGI server. As you might expect, the request object contains everything your application needs
to know about the specific HTTP request being made.

A view callable’s ultimate responsibility is to create a Pyramid Response object. This can be done by
creating a Response object in the view callable code and returning it directly or by raising special kinds of
exceptions from within the body of a view callable.

Defining a View Callable as a Function

One of the easiest ways to define a view callable is to create a function that accepts a single argument
named request, and which returns a Response object. For example, this is a ”hello world” view callable
implemented as a function:

420 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.response import Response


2

3 def hello_world(request):
4 return Response('Hello world!')

Defining a View Callable as a Class

A view callable may also be represented by a Python class instead of a function. When a view callable is
a class, the calling semantics are slightly different than when it is a function or another non-class callable.
When a view callable is a class, the class’s __init__ method is called with a request parameter. As
a result, an instance of the class is created. Subsequently, that instance’s __call__ method is invoked
with no parameters. Views defined as classes must have the following traits.

• an __init__ method that accepts a request argument

• a __call__ (or other) method that accepts no parameters and which returns a response

For example:

1 from pyramid.response import Response


2

3 class MyView(object):
4 def __init__(self, request):
5 self.request = request
6

7 def __call__(self):
8 return Response('hello')

The request object passed to __init__ is the same type of request object described in Defining a View
Callable as a Function.

If you’d like to use a different attribute than __call__ to represent the method expected to return a
response, you can use an attr value as part of the configuration for the view. See View Configuration
Parameters. The same view callable class can be used in different view configuration statements with
different attr values, each pointing at a different method of the class if you’d like the class to represent a
collection of related view callables.

0.3. Narrative Documentation 421


The Pyramid Web Framework, Version 2.0.2

View Callable Responses

A view callable may return an object that implements the Pyramid Response interface. The easiest
way to return something that implements the Response interface is to return a pyramid.response.
Response object instance directly. For example:

1 from pyramid.response import Response


2

3 def view(request):
4 return Response('OK')

Pyramid provides a range of different ”exception” classes which inherit from pyramid.response.
Response. For example, an instance of the class pyramid.httpexceptions.HTTPFound is also
a valid response object because it inherits from Response. For examples, see HTTP Exceptions and
Using a View Callable to do an HTTP Redirect.

You can also return objects from view callables that aren’t instances of pyramid.response.
Response in various circumstances. This can be helpful when writing tests and when attempting to share
code between view callables. See Renderers for the common way to allow for this. A much less common
way to allow for view callables to return non-Response objects is documented in Changing How Pyramid
Treats View Responses.

Using Special Exceptions in View Callables

Usually when a Python exception is raised within a view callable, Pyramid allows the exception to prop-
agate all the way out to the WSGI server which invoked the application. It is usually caught and logged
there.

However, for convenience, a special set of exceptions exists. When one of these exceptions is raised within
a view callable, it will always cause Pyramid to generate a response. These are known as HTTP exception
objects.

422 CONTENTS
The Pyramid Web Framework, Version 2.0.2

HTTP Exceptions

All pyramid.httpexceptions classes which are documented as inheriting from the pyramid.
httpexceptions.HTTPException are http exception objects. Instances of an HTTP exception
object may either be returned or raised from within view code. In either case (return or raise) the instance
will be used as the view’s response.

For example, the pyramid.httpexceptions.HTTPUnauthorized exception can be raised. This


will cause a response to be generated with a 401 Unauthorized status:

1 from pyramid.httpexceptions import HTTPUnauthorized


2

3 def aview(request):
4 raise HTTPUnauthorized()

An HTTP exception, instead of being raised, can alternately be returned (HTTP exceptions are also valid
response objects):

1 from pyramid.httpexceptions import HTTPUnauthorized


2

3 def aview(request):
4 return HTTPUnauthorized()

A shortcut for creating an HTTP exception is the pyramid.httpexceptions.


exception_response() function. This function accepts an HTTP status code and returns
the corresponding HTTP exception. For example, instead of importing and constructing a HTTPUnau-
thorized response object, you can use the exception_response() function to construct and
return the same object.

1 from pyramid.httpexceptions import exception_response


2

3 def aview(request):
4 raise exception_response(401)

This is the case because 401 is the HTTP status code for ”HTTP Unauthorized”. Therefore, raise ex-
ception_response(401) is functionally equivalent to raise HTTPUnauthorized(). Docu-
mentation which maps each HTTP response code to its purpose and its associated HTTP exception object
is provided within pyramid.httpexceptions.

New in version 1.1: The exception_response() function.

0.3. Narrative Documentation 423


The Pyramid Web Framework, Version 2.0.2

How Pyramid Uses HTTP Exceptions

HTTP exceptions are meant to be used directly by application developers. However, Pyramid itself will
raise two HTTP exceptions at various points during normal operations.

• HTTPNotFound gets raised when a view to service a request is not found.

• HTTPForbidden gets raised when authorization was forbidden by a security policy.

If HTTPNotFound is raised by Pyramid itself or within view code, the result of the Not Found View will
be returned to the user agent which performed the request.

If HTTPForbidden is raised by Pyramid itself or within view code, the result of the Forbidden View
will be returned to the user agent which performed the request.

Custom Exception Views

The machinery which allows HTTP exceptions to be raised and caught by specialized views as described in
Using Special Exceptions in View Callables can also be used by application developers to convert arbitrary
exceptions to responses.

To register an exception view that should be called whenever a particular exception is raised from within
Pyramid view code, use pyramid.config.Configurator.add_exception_view() to reg-
ister a view configuration which matches the exception (or a subclass of the exception) and points at a
view callable for which you’d like to generate a response. The exception will be passed as the context
argument to any view predicate registered with the view, as well as to the view itself. For convenience a
new decorator exists, pyramid.views.exception_view_config, which may be used to easily
register exception views.

For example, given the following exception class in a module named helloworld.exceptions:

1 class ValidationFailure(Exception):
2 def __init__(self, msg):
3 self.msg = msg

You can wire a view callable to be called whenever any of your other code raises a helloworld.
exceptions.ValidationFailure exception:

424 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.view import exception_view_config


2 from helloworld.exceptions import ValidationFailure
3

4 @exception_view_config(ValidationFailure)
5 def failed_validation(exc, request):
6 response = Response('Failed validation: %s' % exc.msg)
7 response.status_int = 500
8 return response

Assuming that a scan was run to pick up this view registration, this view callable will be invoked whenever a
helloworld.exceptions.ValidationFailure is raised by your application’s view code. The
same exception raised by a custom root factory, a custom traverser, or a custom view or route predicate is
also caught and hooked.

Other normal view predicates can also be used in combination with an exception view registration:

1 from pyramid.view import view_config


2 from helloworld.exceptions import ValidationFailure
3

4 @exception_view_config(ValidationFailure, route_name='home')
5 def failed_validation(exc, request):
6 response = Response('Failed validation: %s' % exc.msg)
7 response.status_int = 500
8 return response

The above exception view names the route_name of home, meaning that it will only be called when
the route matched has a name of home. You can therefore have more than one exception view for any
given exception in the system: the ”most specific” one will be called when the set of request circumstances
match the view registration.

The only view predicate that cannot be used successfully when creating an exception view configuration
is name. The name used to look up an exception view is always the empty string. Views registered as
exception views which have a name will be ignored.

In most cases, you should register an exception view by using pyramid.config.


Configurator.add_exception_view(). However, it is possible to register ”normal” (i.e., non-
exception) views against a context resource type which inherits from Exception (i.e., config.
add_view(context=Exception)). When the view configuration is processed, two views are reg-
istered. One as a ”normal” view, the other as an exception view. This means that you can use an exception
as context for a normal view.

0.3. Narrative Documentation 425


The Pyramid Web Framework, Version 2.0.2

The view derivers that wrap these two views may behave differently. See Exception Views and View De-
rivers for more information about this.

Exception views can be configured with any view registration mechanism: @excep-
tion_view_config decorator or imperative add_exception_view styles.

Pyramid’s exception view handling logic is implemented as a tween factory function: pyramid.
tweens.excview_tween_factory(). If Pyramid exception view handling is desired, and tween
factories are specified via the pyramid.tweens configuration setting, the pyramid.tweens.
excview_tween_factory() function must be added to the pyramid.tweens configuration set-
ting list explicitly. If it is not present, Pyramid will not perform exception view handling.

Using a View Callable to do an HTTP Redirect

You can issue an HTTP redirect by using the pyramid.httpexceptions.HTTPFound class. Rais-
ing or returning an instance of this class will cause the client to receive a ”302 Found” response.

To do so, you can return a pyramid.httpexceptions.HTTPFound instance.

1 from pyramid.httpexceptions import HTTPFound


2

3 def myview(request):
4 return HTTPFound(location='http://example.com')

Alternately, you can raise an HTTPFound exception instead of returning one.

1 from pyramid.httpexceptions import HTTPFound


2

3 def myview(request):
4 raise HTTPFound(location='http://example.com')

When the instance is raised, it is caught by the default exception response handler and turned into a re-
sponse.

426 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Handling Form Submissions in View Callables (Unicode and Character Set Issues)

Most web applications need to accept form submissions from web browsers and various other clients.
In Pyramid, form submission handling logic is always part of a view. For a general overview of how
to handle form submission data using the WebOb API, see Request and Response Objects and ”Query
and POST variables” within the WebOb documentation. Pyramid defers to WebOb for its request and
response implementations, and handling form submission data is a property of the request implementation.
Understanding WebOb’s request API is the key to understanding how to process form submission data.

There are some defaults that you need to be aware of when trying to handle form submission data in a
Pyramid view. Having high-order (i.e., non-ASCII) characters in data contained within form submissions is
exceedingly common, and the UTF-8 encoding is the most common encoding used on the web for character
data. Since Unicode values are much saner than working with and storing bytestrings, Pyramid configures
the WebOb request machinery to attempt to decode form submission values into Unicode from UTF-8
implicitly. This implicit decoding happens when view code obtains form field values via the request.
params, request.GET, or request.POST APIs (see pyramid.request for details about these APIs).

Many people find the difference between Unicode and UTF-8 confusing. Unicode is a standard for
representing text that supports most of the world’s writing systems. However, there are many ways that
Unicode data can be encoded into bytes for transit and storage. UTF-8 is a specific encoding for Unicode
that is backwards-compatible with ASCII. This makes UTF-8 very convenient for encoding data where a
large subset of that data is ASCII characters, which is largely true on the web. UTF-8 is also the standard
character encoding for URLs.

As an example, let’s assume that the following form page is served up to a browser client, and its action
points at some Pyramid view code:

1 <html xmlns="http://www.w3.org/1999/xhtml">
2 <form method="POST" action="myview" accept-charset="UTF-8">
3 <div>
4 <input type="text" name="firstname"/>
5 </div>
6 <div>
7 <input type="text" name="lastname"/>
8 </div>
9 <input type="submit" value="Submit"/>
10 </form>
11 </html>

The myview view code in the Pyramid application must expect that the values returned by request.
params will be of type str, as opposed to type bytes. The following will work to accept a form post
from the above form:

0.3. Narrative Documentation 427


The Pyramid Web Framework, Version 2.0.2

1 def myview(request):
2 firstname = request.params['firstname']
3 lastname = request.params['lastname']

For implicit decoding to work reliably, you should ensure that every form you render that posts to a Pyra-
mid view explicitly defines a charset encoding of UTF-8. This can be done via a response that has a ;
charset=UTF-8 in its Content-Type header; or, as in the form above, with an accept-charset
attribute, informing the browser that the server expects the form content to be encoded using UTF-8. This
must be done explicitly because all known browser clients assume that they should encode form data in
the same character set implied by the Content-Type value of the response containing the form when
subsequently submitting that form. There is no other generally accepted way to tell browser clients which
charset to use to encode form data. If you do not specify an encoding explicitly, the browser client will
choose to encode form data in its default character set before submitting it, which may not be UTF-8
as the server expects. If a request containing form data encoded in a non-UTF-8 charset is handled
by your view code, eventually the request code accessed within your view will throw an error when it
can’t decode some high-order character encoded in another character set within form data, e.g., when
request.params['somename'] is accessed.

If you are using the Response class to generate a response, or if you use the pyramid.renderers.
render_* templating APIs, the UTF-8 charset is set automatically as the default via the
Content-Type header. If you return a Content-Type header without an explicit charset, a re-
quest will add a ;charset=utf-8 trailer to the Content-Type header value for you for response
content types that are textual (e.g., text/html or application/xml) as it is rendered. If you are
using your own response object, you will need to ensure you do this yourself.

Alternate View Callable Argument/Calling Conventions

Usually view callables are defined to accept only a single argument: request. However, a view callable
may alternately be defined as any class, function, or callable that accepts two positional arguments: a
context resource as the first argument and a request as the second argument.

The context and request arguments passed to a view function defined in this style can be defined as follows:

context
The resource object found via tree traversal or URL dispatch.

request
A Pyramid Request object representing the current WSGI request.

The following types work as view callables in this style:

1. Functions that accept two arguments: context and request, e.g.:

428 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.response import Response


2

3 def view(context, request):


4 return Response('OK')

2. Classes that have an __init__ method that accepts context, request, and a __call__
method which accepts no arguments, e.g.:

1 from pyramid.response import Response


2

3 class view(object):
4 def __init__(self, context, request):
5 self.context = context
6 self.request = request
7

8 def __call__(self):
9 return Response('OK')

3. Arbitrary callables that have a __call__ method that accepts context, request, e.g.:

1 from pyramid.response import Response


2

3 class View(object):
4 def __call__(self, context, request):
5 return Response('OK')
6 view = View() # this is the view callable

This style of calling convention is most useful for traversal based applications, where the context object is
frequently used within the view callable code itself.

No matter which view calling convention is used, the view code always has access to the context via
request.context.

Passing Configuration Variables to a View

For information on passing a variable from the configuration .ini files to a view, see Deployment Settings.

0.3. Narrative Documentation 429


The Pyramid Web Framework, Version 2.0.2

Pylons-1.0-Style ”Controller” Dispatch

A package named pyramid_handlers (available from PyPI) provides an analogue of Pylons-style ”con-
trollers”, which are a special kind of view class which provides more automation when your application
uses URL dispatch solely.

0.3.10 Renderers

A view callable needn’t always return a Response object. If a view happens to return something which
does not implement the Pyramid Response interface, Pyramid will attempt to use a renderer to construct
a response. For example:

1 from pyramid.view import view_config


2

3 @view_config(renderer='json')
4 def hello_world(request):
5 return {'content':'Hello!'}

The above example returns a dictionary from the view callable. A dictionary does not implement the Pyra-
mid response interface, so you might believe that this example would fail. However, since a renderer is
associated with the view callable through its view configuration (in this case, using a renderer argument
passed to view_config()), if the view does not return a Response object, the renderer will attempt to
convert the result of the view to a response on the developer’s behalf.

Of course, if no renderer is associated with a view’s configuration, returning anything except an object
which implements the Response interface will result in an error. And, if a renderer is used, whatever is
returned by the view must be compatible with the particular kind of renderer used, or an error may occur
during view invocation.

One exception exists: it is always OK to return a Response object, even when a renderer is configured.
In such cases, the renderer is bypassed entirely.

Various types of renderers exist, including serialization renderers and renderers which use templating sys-
tems.

430 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Writing View Callables Which Use a Renderer

As we’ve seen, a view callable needn’t always return a Response object. Instead, it may return an arbitrary
Python object, with the expectation that a renderer will convert that object into a response instance on your
behalf. Some renderers use a templating system, while other renderers use object serialization techniques.
In practice, renderers obtain application data values from Python dictionaries so, in practice, view callables
which use renderers return Python dictionaries.

View callables can explicitly call renderers, but typically don’t. Instead view configuration declares the
renderer used to render a view callable’s results. This is done with the renderer attribute. For example,
this call to add_view() associates the json renderer with a view callable:

config.add_view('myproject.views.my_view', renderer='json')

When this configuration is added to an application, the myproject.views.my_view view callable


will now use a json renderer, which renders view return values to a JSON response serialization.

Pyramid defines several Built-in Renderers, and additional renderers can be added by developers to the
system as necessary. See Adding and Changing Renderers.

Views which use a renderer and return a non-Response value can vary non-body response attributes (such
as headers and the HTTP status code) by attaching a property to the request.response attribute. See
Varying Attributes of Rendered Responses.

As already mentioned, if the view callable associated with a view configuration returns a Response object
(or its instance), any renderer associated with the view configuration is ignored, and the response is passed
back to Pyramid unchanged. For example:

1 from pyramid.response import Response


2 from pyramid.view import view_config
3

4 @view_config(renderer='json')
5 def view(request):
6 return Response('OK') # json renderer avoided

Likewise for an HTTP exception response:

1 from pyramid.httpexceptions import HTTPFound


2 from pyramid.view import view_config
3

4 @view_config(renderer='json')
5 def view(request):
6 return HTTPFound(location='http://example.com') # json renderer avoided

0.3. Narrative Documentation 431


The Pyramid Web Framework, Version 2.0.2

You can of course also return the request.response attribute instead to avoid rendering:

1 from pyramid.view import view_config


2

3 @view_config(renderer='json')
4 def view(request):
5 request.response.body = 'OK'
6 return request.response # json renderer avoided

Built-in Renderers

Several built-in renderers exist in Pyramid. These renderers can be used in the renderer attribute of
view configurations.

Bindings for officially supported templating languages can be found at Available Add-On Template
System Bindings.

string: String Renderer

The string renderer renders a view callable result to a string. If a view callable returns a non-Response
object, and the string renderer is associated in that view’s configuration, the result will be to run the
object through the Python str function to generate a string.

Here’s an example of a view that returns a dictionary. If the string renderer is specified in the con-
figuration for this view, the view will render the returned dictionary to the str() representation of the
dictionary:

1 from pyramid.view import view_config


2

3 @view_config(renderer='string')
4 def hello_world(request):
5 return {'content':'Hello!'}

The body of the response returned by such a view will be a string representing the str() serialization of
the return value:

432 CONTENTS
The Pyramid Web Framework, Version 2.0.2

{'content': 'Hello!'}

Views which use the string renderer can vary non-body response attributes by using the API of the
request.response attribute. See Varying Attributes of Rendered Responses.

JSON Renderer

The json renderer renders view callable results to JSON. By default, it passes the return value through
the json.dumps standard library function, and wraps the result in a response object. It also sets the
response content-type to application/json.

Here’s an example of a view that returns a dictionary. Since the json renderer is specified in the config-
uration for this view, the view will render the returned dictionary to a JSON serialization:

1 from pyramid.view import view_config


2

3 @view_config(renderer='json')
4 def hello_world(request):
5 return {'content':'Hello!'}

The body of the response returned by such a view will be a string representing the JSON serialization of
the return value:

{"content": "Hello!"}

The return value needn’t be a dictionary, but the return value must contain values serializable by the con-
figured serializer (by default json.dumps).

You can configure a view to use the JSON renderer by naming json as the renderer argument of a
view configuration, e.g., by using add_view():

1 config.add_view('myproject.views.hello_world',
2 name='hello',
3 context='myproject.resources.Hello',
4 renderer='json')

Views which use the JSON renderer can vary non-body response attributes by using the API of the
request.response attribute. See Varying Attributes of Rendered Responses.

0.3. Narrative Documentation 433


The Pyramid Web Framework, Version 2.0.2

Serializing Custom Objects

Some objects are not, by default, JSON-serializable (such as datetimes and other arbitrary Python objects).
You can, however, register code that makes non-serializable objects serializable in two ways:

• Define a __json__ method on objects in your application.

• For objects you don’t ”own”, you can register a JSON renderer that knows about an adapter for that
kind of object.

Using a Custom __json__ Method

Custom objects can be made easily JSON-serializable in Pyramid by defining a __json__ method on the
object’s class. This method should return values natively JSON-serializable (such as ints, lists, dictionaries,
strings, and so forth). It should accept a single additional argument, request, which will be the active
request object at render time.

1 from pyramid.view import view_config


2

3 class MyObject(object):
4 def __init__(self, x):
5 self.x = x
6

7 def __json__(self, request):


8 return {'x':self.x}
9

10 @view_config(renderer='json')
11 def objects(request):
12 return [MyObject(1), MyObject(2)]
13

14 # the JSON value returned by ``objects`` will be:


15 # [{"x": 1}, {"x": 2}]

Using the add_adapter Method of a Custom JSON Renderer

If you aren’t the author of the objects being serialized, it won’t be possible (or at least not reasonable) to
add a custom __json__ method to their classes in order to influence serialization. If the object passed
to the renderer is not a serializable type and has no __json__ method, usually a TypeError will be
raised during serialization. You can change this behavior by creating a custom JSON renderer and adding
adapters to handle custom types. The renderer will attempt to adapt non-serializable objects using the
registered adapters. A short example follows:

434 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.renderers import JSON


2

3 if __name__ == '__main__':
4 config = Configurator()
5 json_renderer = JSON()
6 def datetime_adapter(obj, request):
7 return obj.isoformat()
8 json_renderer.add_adapter(datetime.datetime, datetime_adapter)
9 config.add_renderer('json', json_renderer)

The add_adapter method should accept two arguments: the class of the object that you want this
adapter to run for (in the example above, datetime.datetime), and the adapter itself.

The adapter should be a callable. It should accept two arguments: the object needing to be serialized and
request, which will be the current request object at render time. The adapter should raise a TypeError
if it can’t determine what to do with the object.

See pyramid.renderers.JSON and Adding and Changing Renderers for more information.

New in version 1.4: Serializing custom objects.

JSONP Renderer

New in version 1.1.

pyramid.renderers.JSONP is a JSONP renderer factory helper which implements a hybrid


JSON/JSONP renderer. JSONP is useful for making cross-domain AJAX requests.

Unlike other renderers, a JSONP renderer needs to be configured at startup time ”by hand”. Configure a
JSONP renderer using the pyramid.config.Configurator.add_renderer() method:

from pyramid.config import Configurator


from pyramid.renderers import JSONP

config = Configurator()
config.add_renderer('jsonp', JSONP(param_name='callback'))

Once this renderer is registered via add_renderer() as above, you can use jsonp as the renderer=
parameter to @view_config or pyramid.config.Configurator.add_view():

0.3. Narrative Documentation 435


The Pyramid Web Framework, Version 2.0.2

from pyramid.view import view_config

@view_config(renderer='jsonp')
def myview(request):
return {'greeting':'Hello world'}

When a view is called that uses a JSONP renderer:


• If there is a parameter in the request’s HTTP query string (aka request.GET) that matches the
param_name of the registered JSONP renderer (by default, callback), the renderer will return
a JSONP response.
• If there is no callback parameter in the request’s query string, the renderer will return a ”plain” JSON
response.
Javscript library AJAX functionality will help you make JSONP requests. For example, JQuery has a
getJSON function, and has equivalent (but more complicated) functionality in its ajax function.
For example (JavaScript):

var api_url = 'http://api.geonames.org/timezoneJSON' +


'?lat=38.301733840000004' +
'&lng=-77.45869621' +
'&username=fred' +
'&callback=?';
jqhxr = $.getJSON(api_url);

The string callback=? above in the url param to the JQuery getJSON function indicates to jQuery
that the query should be made as a JSONP request; the callback parameter will be automatically filled
in for you and used.
The same custom-object serialization scheme defined used for a ”normal” JSON renderer in Serializing
Custom Objects can be used when passing values to a JSONP renderer too.

Varying Attributes of Rendered Responses

Before a response constructed by a renderer is returned to Pyramid, several attributes of the request are
examined which have the potential to influence response behavior.
View callables that don’t directly return a response should use the API of the pyramid.response.
Response attribute, available as request.response during their execution, to influence associated
response behavior.
For example, if you need to change the response status from within a view callable that uses a renderer,
assign the status attribute to the response attribute of the request before returning a result:

436 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.view import view_config


2

3 @view_config(name='gone', renderer='templates/gone.pt')
4 def myview(request):
5 request.response.status = '404 Not Found'
6 return {'URL':request.URL}

Note that mutations of request.response in views which return a Response object directly will have
no effect unless the response object returned is request.response. For example, the following ex-
ample calls request.response.set_cookie, but this call will have no effect because a different
Response object is returned.

1 from pyramid.response import Response


2

3 def view(request):
4 request.response.set_cookie('abc', '123') # this has no effect
5 return Response('OK') # because we're returning a different response

If you mutate request.response and you’d like the mutations to have an effect, you must return
request.response:

1 def view(request):
2 request.response.set_cookie('abc', '123')
3 return request.response

For more information on attributes of the request, see the API documentation in pyramid.request. For more
information on the API of request.response, see pyramid.request.Request.response.

Adding and Changing Renderers

New templating systems and serializers can be associated with Pyramid renderer names. To this end,
configuration declarations can be made which change an existing renderer factory, and which add a new
renderer factory.

Renderers can be registered imperatively using the pyramid.config.Configurator.


add_renderer() API.

For example, to add a renderer which renders views which have a renderer attribute that is a path that
ends in .jinja2:

0.3. Narrative Documentation 437


The Pyramid Web Framework, Version 2.0.2

config.add_renderer('.jinja2', 'mypackage.MyJinja2Renderer')

The first argument is the renderer name. The second argument is a reference to an implementation of a
renderer factory or a dotted Python name referring to such an object.

Adding a New Renderer

You may add a new renderer by creating and registering a renderer factory.

A renderer factory implementation should conform to the pyramid.interfaces.


IRendererFactory interface. It should be capable of creating an object that conforms to the
pyramid.interfaces.IRenderer interface. A typical class that follows this setup is as follows:

1 class RendererFactory:
2 def __init__(self, info):
3 """ Constructor: info will be an object having the
4 following attributes: name (the renderer name), package
5 (the package that was 'current' at the time the
6 renderer was registered), type (the renderer type
7 name), registry (the current application registry) and
8 settings (the deployment settings dictionary). """
9

10 def __call__(self, value, system):


11 """ Call the renderer implementation with the value
12 and the system value passed in as arguments and return
13 the result (a bytes or string object). The value is
14 the return value of a view. The system value is a
15 dictionary containing available system values
16 (e.g., view, context, and request). """

The formal interface definition of the info object passed to a renderer factory constructor is available as
pyramid.interfaces.IRendererInfo.

There are essentially two different kinds of renderer factories:

• A renderer factory which expects to accept an asset specification, or an absolute path, as the name
attribute of the info object fed to its constructor. These renderer factories are registered with a
name value that begins with a dot (.). These types of renderer factories usually relate to a file on
the filesystem, such as a template.

438 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• A renderer factory which expects to accept a token that does not represent a filesystem path or an
asset specification in the name attribute of the info object fed to its constructor. These renderer
factories are registered with a name value that does not begin with a dot. These renderer factories
are typically object serializers.

Asset Specifications

An asset specification is a colon-delimited identifier for an asset. The colon separates a Python package
name from a package subpath. For example, the asset specification my.package:static/baz.
css identifies the file named baz.css in the static subdirectory of the my.package Python
package.

Here’s an example of the registration of a simple renderer factory via add_renderer(), where config
is an instance of pyramid.config.Configurator():

config.add_renderer(name='amf', factory='my.package.MyAMFRenderer')

Adding the above code to your application startup configuration will allow you to use the my.package.
MyAMFRenderer renderer factory implementation in view configurations. Your application can use this
renderer by specifying amf in the renderer attribute of a view configuration:

1 from pyramid.view import view_config


2

3 @view_config(renderer='amf')
4 def myview(request):
5 return {'Hello':'world'}

At startup time, when a view configuration is encountered which has a name attribute that does not contain
a dot, the full name value is used to construct a renderer from the associated renderer factory. In this case,
the view configuration will create an instance of an MyAMFRenderer for each view configuration which
includes amf as its renderer value. The name passed to the MyAMFRenderer constructor will always
be amf.

Here’s an example of the registration of a more complicated renderer factory, which expects to be passed
a filesystem path:

config.add_renderer(name='.jinja2', factory='my.package.MyJinja2Renderer')

0.3. Narrative Documentation 439


The Pyramid Web Framework, Version 2.0.2

Adding the above code to your application startup will allow you to use the my.package.
MyJinja2Renderer renderer factory implementation in view configurations by referring to any ren-
derer which ends in .jinja2 in the renderer attribute of a view configuration:

1 from pyramid.view import view_config


2

3 @view_config(renderer='templates/mytemplate.jinja2')
4 def myview(request):
5 return {'Hello':'world'}

When a view configuration is encountered at startup time which has a name attribute that does contain a
dot, the value of the name attribute is split on its final dot. The second element of the split is typically the
filename extension. This extension is used to look up a renderer factory for the configured view. Then the
value of renderer is passed to the factory to create a renderer for the view. In this case, the view con-
figuration will create an instance of a MyJinja2Renderer for each view configuration which includes
anything ending with .jinja2 in its renderer value. The name passed to the MyJinja2Renderer
constructor will be the full value that was set as renderer= in the view configuration.

Adding a Default Renderer

To associate a default renderer with all view configurations (even ones which do not possess a renderer
attribute), pass None as the name attribute to the renderer tag:

config.add_renderer(None, 'mypackage.json_renderer_factory')

Changing an Existing Renderer

Pyramid supports overriding almost every aspect of its setup through its Conflict Resolution mechanism.
This means that, in most cases, overriding a renderer is as simple as using the pyramid.config.
Configurator.add_renderer() method to redefine the template extension. For example, if you
would like to override the json renderer to specify a new renderer, you could do the following:

json_renderer = pyramid.renderers.JSON()
config.add_renderer('json', json_renderer)

After doing this, any views registered with the json renderer will use the new renderer.

440 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Overriding a Renderer at Runtime

This is an advanced feature, not typically used by ”civilians”.

In some circumstances, it is necessary to instruct the system to ignore the static renderer declaration pro-
vided by the developer in view configuration, replacing the renderer with another after a request starts.
For example, an ”omnipresent” XML-RPC implementation that detects that the request is from an XML-
RPC client might override a view configuration statement made by the user instructing the view to use a
template renderer with one that uses an XML-RPC renderer. This renderer would produce an XML-RPC
representation of the data returned by an arbitrary view callable.

To use this feature, create a NewRequest subscriber which sniffs at the request data and which con-
ditionally sets an override_renderer attribute on the request itself, which in turn is the name of a
registered renderer. For example:

1 from pyramid.events import subscriber


2 from pyramid.events import NewRequest
3

4 @subscriber(NewRequest)
5 def set_xmlrpc_params(event):
6 request = event.request
7 if (request.content_type == 'text/xml'
8 and request.method == 'POST'
9 and not 'soapaction' in request.headers
10 and not 'x-pyramid-avoid-xmlrpc' in request.headers):
11 params, method = parse_xmlrpc_request(request)
12 request.xmlrpc_params, request.xmlrpc_method = params, method
13 request.is_xmlrpc = True
14 request.override_renderer = 'xmlrpc'
15 return True

The result of such a subscriber will be to replace any existing static renderer configured by the developer
with a (notional, nonexistent) XML-RPC renderer, if the request appears to come from an XML-RPC
client.

0.3. Narrative Documentation 441


The Pyramid Web Framework, Version 2.0.2

0.3.11 Templates

A template is a file on disk which can be used to render dynamic data provided by a view. Pyramid offers
a number of ways to perform templating tasks out of the box, and provides add-on templating support
through a set of bindings packages.

Before discussing how built-in templates are used in detail, we’ll discuss two ways to render templates
within Pyramid in general: directly and via renderer configuration.

Using Templates Directly

The most straightforward way to use a template within Pyramid is to cause it to be rendered directly within
a view callable. You may use whatever API is supplied by a given templating engine to do so.

Pyramid provides various APIs that allow you to render templates directly from within a view callable.
For example, if there is a Chameleon ZPT template named foo.pt in a directory named templates
in your application, you can render the template from within the body of a view callable like so:

1 from pyramid.renderers import render_to_response


2

3 def sample_view(request):
4 return render_to_response('templates/foo.pt',
5 {'foo':1, 'bar':2},
6 request=request)

The sample_view view callable function above returns a response object which contains the body of the
templates/foo.pt template. In this case, the templates directory should live in the same directory
as the module containing the sample_view function. The template author will have the names foo and
bar available as top-level names for replacement or comparison purposes.

In the example above, the path templates/foo.pt is relative to the directory containing the file which
defines the view configuration. In this case, this is the directory containing the file that defines the sam-
ple_view function. Although a renderer path is usually just a simple relative pathname, a path named
as a renderer can be absolute, starting with a slash on Unix or a drive letter prefix on Windows. The path
can alternatively be an asset specification in the form some.dotted.package_name:relative/
path. This makes it possible to address template assets which live in another package. For example:

1 from pyramid.renderers import render_to_response


2

3 def sample_view(request):
4 return render_to_response('mypackage:templates/foo.pt',
5 {'foo':1, 'bar':2},
6 request=request)

442 CONTENTS
The Pyramid Web Framework, Version 2.0.2

An asset specification points at a file within a Python package. In this case, it points at a file named foo.
pt within the templates directory of the mypackage package. Using an asset specification instead of
a relative template name is usually a good idea, because calls to render_to_response() using asset
specifications will continue to work properly if you move the code containing them to another location.

In the examples above we pass in a keyword argument named request representing the current Pyramid
request. Passing a request keyword argument will cause the render_to_response function to supply
the renderer with more correct system values (see System Values Used During Rendering), because most
of the information required to compose proper system values is present in the request. If your template
relies on the name request or context, or if you’ve configured special renderer globals, make sure to
pass request as a keyword argument in every call to a pyramid.renderers.render_* function.

Every view must return a response object, except for views which use a renderer named via view configu-
ration (which we’ll see shortly). The pyramid.renderers.render_to_response() function is
a shortcut function that actually returns a response object. This allows the example view above to simply
return the result of its call to render_to_response() directly.

Obviously not all APIs you might call to get response data will return a response object. For example, you
might render one or more templates to a string that you want to use as response data. The pyramid.
renderers.render() API renders a template to a string. We can manufacture a response object
directly, and use that string as the body of the response:

1 from pyramid.renderers import render


2 from pyramid.response import Response
3

4 def sample_view(request):
5 result = render('mypackage:templates/foo.pt',
6 {'foo':1, 'bar':2},
7 request=request)
8 response = Response(result)
9 return response

Because view callable functions are typically the only code in Pyramid that need to know anything about
templates, and because view functions are very simple Python, you can use whatever templating system
with which you’re most comfortable within Pyramid. Install the templating system, import its API func-
tions into your views module, use those APIs to generate a string, then return that string as the body of a
Pyramid Response object.

For example, here’s an example of using ”raw” Mako from within a Pyramid view:

0.3. Narrative Documentation 443


The Pyramid Web Framework, Version 2.0.2

1 from mako.template import Template


2 from pyramid.response import Response
3

4 def make_view(request):
5 template = Template(filename='/templates/template.mak')
6 result = template.render(name=request.params['name'])
7 response = Response(result)
8 return response

You probably wouldn’t use this particular snippet in a project, because it’s easier to use the supported Mako
bindings. But if your favorite templating system is not supported as a renderer extension for Pyramid, you
can create your own simple combination as shown above.

If you use third-party templating languages without cooperating Pyramid bindings directly within
view callables, the auto-template-reload strategy explained in Automatically Reloading Templates will not
be available, nor will the template asset overriding capability explained in Overriding Assets be available,
nor will it be possible to use any template using that language as a renderer. However, it’s reasonably easy
to write custom templating system binding packages for use under Pyramid so that templates written in the
language can be used as renderers. See Adding and Changing Renderers for instructions on how to create
your own template renderer and Available Add-On Template System Bindings for example packages.

If you need more control over the status code and content-type, or other response attributes from views
that use direct templating, you may set attributes on the response that influence these values.

Here’s an example of changing the content-type and status of the response object returned by ren-
der_to_response():

1 from pyramid.renderers import render_to_response


2

3 def sample_view(request):
4 response = render_to_response('templates/foo.pt',
5 {'foo':1, 'bar':2},
6 request=request)
7 response.content_type = 'text/plain'
8 response.status_int = 204
9 return response

Here’s an example of manufacturing a response object using the result of render() (a string):

444 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.renderers import render


2 from pyramid.response import Response
3

4 def sample_view(request):
5 result = render('mypackage:templates/foo.pt',
6 {'foo':1, 'bar':2},
7 request=request)
8 response = Response(result)
9 response.content_type = 'text/plain'
10 return response

System Values Used During Rendering

When a template is rendered using render_to_response() or render(), or a renderer= argu-


ment to view configuration (see Templates Used as Renderers via Configuration), the renderer representing
the template will be provided with a number of system values. These values are provided to the template:

request
The value provided as the request keyword argument to render_to_response or render
or the request object passed to the view when the renderer= argument to view configuration is
being used to render the template.

req
An alias for request.

context
The current Pyramid context if request was provided as a keyword argument to ren-
der_to_response or render, or None if the request keyword argument was not provided.
This value will always be provided if the template is rendered as the result of a renderer= argu-
ment to the view configuration being used.

get_csrf_token()
A convenience function to access the current CSRF token. See Using the get_csrf_token global in
templates for more information.

renderer_name
The renderer name used to perform the rendering, e.g., mypackage:templates/foo.pt.

renderer_info
An object implementing the pyramid.interfaces.IRendererInfo interface. Basically,
an object with the following attributes: name, package, and type.

0.3. Narrative Documentation 445


The Pyramid Web Framework, Version 2.0.2

view
The view callable object that was used to render this template. If the view callable is a method of
a class-based view, this will be an instance of the class that the method was defined on. If the view
callable is a function or instance, it will be that function or instance. Note that this value will only
be automatically present when a template is rendered as a result of a renderer= argument; it will
be None when the render_to_response or render APIs are used.

You can define more values which will be passed to every template executed as a result of rendering by
defining renderer globals.

What any particular renderer does with these system values is up to the renderer itself, but most template
renderers make these names available as top-level template variables.

Templates Used as Renderers via Configuration

An alternative to using render_to_response() to render templates manually in your view callable


code is to specify the template as a renderer in your view configuration. This can be done with any of the
templating languages supported by Pyramid.

To use a renderer via view configuration, specify a template asset specification as the renderer argu-
ment, or attribute to the view configuration of a view callable. Then return a dictionary from that view
callable. The dictionary items returned by the view callable will be made available to the renderer template
as top-level names.

The association of a template as a renderer for a view configuration makes it possible to replace code within
a view callable that handles the rendering of a template.

Here’s an example of using a view_config decorator to specify a view configuration that names a
template renderer:

1 from pyramid.view import view_config


2

3 @view_config(renderer='templates/foo.pt')
4 def my_view(request):
5 return {'foo':1, 'bar':2}

You do not need to supply the request value as a key in the dictionary result returned from a
renderer-configured view callable. Pyramid automatically supplies this value for you, so that the ”most
correct” system values are provided to the renderer.

446 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The renderer argument to the @view_config configuration decorator shown above is the
template path. In the example above, the path templates/foo.pt is relative. Relative to what,
you ask? Because we’re using a Chameleon renderer, it means ”relative to the directory in which the
file that defines the view configuration lives”. In this case, this is the directory containing the file that
defines the my_view function.

Similar renderer configuration can be done imperatively. See Writing View Callables Which Use a Ren-
derer.

See also:

See also Built-in Renderers.

Although a renderer path is usually just a simple relative pathname, a path named as a renderer can be
absolute, starting with a slash on Unix or a drive letter prefix on Windows. The path can alternatively
be an asset specification in the form some.dotted.package_name:relative/path, making it
possible to address template assets which live in another package.

Not just any template from any arbitrary templating system may be used as a renderer. Bindings must exist
specifically for Pyramid to use a templating language template as a renderer.

Why Use a Renderer via View Configuration

Using a renderer in view configuration is usually a better way to render templates than using any ren-
dering API directly from within a view callable because it makes the view callable more unit-testable.
Views which use templating or rendering APIs directly must return a Response object. Making testing
assertions about response objects is typically an indirect process, because it means that your test code
often needs to somehow parse information out of the response body (often HTML). View callables con-
figured with renderers externally via view configuration typically return a dictionary, as above. Making
assertions about results returned in a dictionary is almost always more direct and straightforward than
needing to parse HTML.

By default, views rendered via a template renderer return a Response object which has a status code of
200 OK, and a content-type of text/html. To vary attributes of the response of a view that uses a
renderer, such as the content-type, headers, or status attributes, you must use the API of the pyramid.
response.Response object exposed as request.response within the view before returning the
dictionary. See Varying Attributes of Rendered Responses for more information.

The same set of system values are provided to templates rendered via a renderer view configuration as
those provided to templates rendered imperatively. See System Values Used During Rendering.

0.3. Narrative Documentation 447


The Pyramid Web Framework, Version 2.0.2

Debugging Templates

A NameError exception resulting from rendering a template with an undefined variable (e.g.
${wrong}) might end up looking like this:

RuntimeError: Caught exception rendering template.


- Expression: ``wrong``
- Filename: /home/fred/env/proj/proj/templates/mytemplate.pt
- Arguments: renderer_name: proj:templates/mytemplate.pt
template: <PageTemplateFile - at 0x1d2ecf0>
xincludes: <XIncludes - at 0x1d3a130>
request: <Request - at 0x1d2ecd0>
project: proj
macros: <Macros - at 0x1d3aed0>
context: <MyResource None at 0x1d39130>
view: <function my_view at 0x1d23570>

NameError: wrong

The output tells you which template the error occurred in, as well as displaying the arguments passed to
the template itself.

Automatically Reloading Templates

It’s often convenient to see changes you make to a template file appear immediately without needing to
restart the application process. Pyramid allows you to configure your application development environment
so that a change to a template will be automatically detected, and the template will be reloaded on the next
rendering.

Auto-template-reload behavior is not recommended for production sites as it slows rendering


slightly; it’s usually only desirable during development.

In order to turn on automatic reloading of templates, you can use an environment variable or a configuration
file setting.

To use an environment variable, start your application under a shell using the PYRA-
MID_RELOAD_TEMPLATES operating system environment variable set to 1, For example:

448 CONTENTS
The Pyramid Web Framework, Version 2.0.2

PYRAMID_RELOAD_TEMPLATES=1 $VENV/bin/pserve myproject.ini

To use a setting in the application .ini file for the same purpose, set the pyramid.
reload_templates key to true within the application’s configuration section, e.g.:

1 [app:main]
2 use = egg:MyProject
3 pyramid.reload_templates = true

Available Add-On Template System Bindings

The Pylons Project maintains several packages providing bindings to different templating languages in-
cluding the following:

Template Language Pyramid Bindings Default Extensions


Chameleon pyramid_chameleon .pt, .txt
Jinja2 pyramid_jinja2 .jinja2
Mako pyramid_mako .mak, .mako

0.3.12 View Configuration

View lookup is the Pyramid subsystem responsible for finding and invoking a view callable. View configu-
ration controls how view lookup operates in your application. During any given request, view configuration
information is compared against request data by the view lookup subsystem in order to find the ”best” view
callable for that request.

In earlier chapters, you have been exposed to a few simple view configuration declarations without much
explanation. In this chapter we will explore the subject in detail.

0.3. Narrative Documentation 449


The Pyramid Web Framework, Version 2.0.2

Mapping a Resource or URL Pattern to a View Callable

A developer makes a view callable available for use within a Pyramid application via view configuration.
A view configuration associates a view callable with a set of statements that determine the set of circum-
stances which must be true for the view callable to be invoked.
A view configuration statement is made about information present in the context resource (or exception)
and the request.
View configuration is performed in one of two ways:
• By running a scan against application source code which has a pyramid.view.view_config
decorator attached to a Python object as per Adding View Configuration Using the @view_config
Decorator.
• By using the pyramid.config.Configurator.add_view() method as per Adding View
Configuration Using add_view().

View Configuration Parameters

All forms of view configuration accept the same general types of arguments.
Many arguments supplied during view configuration are view predicate arguments. View predicate argu-
ments used during view configuration are used to narrow the set of circumstances in which view lookup
will find a particular view callable.
View predicate attributes are an important part of view configuration that enables the view lookup subsys-
tem to find and invoke the appropriate view. The greater the number of predicate attributes possessed by
a view’s configuration, the more specific the circumstances need to be before the registered view callable
will be invoked. The fewer the number of predicates which are supplied to a particular view configuration,
the more likely it is that the associated view callable will be invoked. A view with five predicates will
always be found and evaluated before a view with two, for example.
This does not mean however, that Pyramid ”stops looking” when it finds a view registration with predicates
that don’t match. If one set of view predicates does not match, the ”next most specific” view (if any) is
consulted for predicates, and so on, until a view is found, or no view can be matched up with the request.
The first view with a set of predicates all of which match the request environment will be invoked.
If no view can be found with predicates which allow it to be matched up with the request, Pyramid will
return an error to the user’s browser, representing a ”not found” (404) page. See Changing the Not Found
View for more information about changing the default Not Found View.
Other view configuration arguments are non-predicate arguments. These tend to modify the response of
the view callable or prevent the view callable from being invoked due to an authorization policy. The
presence of non-predicate arguments in a view configuration does not narrow the circumstances in which
the view callable will be invoked.

450 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Non-Predicate Arguments

permission
The name of a permission that the user must possess in order to invoke the view callable. See
Configuring View Security for more information about view security and permissions.
If permission is not supplied, no permission is registered for this view (it’s accessible by any
caller).
attr
The view machinery defaults to using the __call__ method of the view callable (or the function
itself, if the view callable is a function) to obtain a response. The attr value allows you to vary the
method attribute used to obtain the response. For example, if your view was a class, and the class
has a method named index and you wanted to use this method instead of the class’s __call__
method to return the response, you’d say attr="index" in the view configuration for the view.
This is most useful when the view definition is a class.
If attr is not supplied, None is used (implying the function itself if the view is a function, or the
__call__ callable attribute if the view is a class).
renderer
Denotes the renderer implementation which will be used to construct a response from the associated
view callable’s return value.
See also:
See also Renderers.
This is either a single string term (e.g., json) or a string implying a path or asset specification (e.g.,
templates/views.pt) naming a renderer implementation. If the renderer value does not
contain a dot (.), the specified string will be used to look up a renderer implementation, and that
renderer implementation will be used to construct a response from the view return value. If the
renderer value contains a dot (.), the specified term will be treated as a path, and the filename
extension of the last element in the path will be used to look up the renderer implementation, which
will be passed the full path.
When the renderer is a path—although a path is usually just a simple relative pathname (e.g.,
templates/foo.pt, implying that a template named ”foo.pt” is in the ”templates” directory
relative to the directory of the current package)—the path can be absolute, starting with a slash on
Unix or a drive letter prefix on Windows. The path can alternatively be a asset specification in the
form some.dotted.package_name:relative/path, making it possible to address tem-
plate assets which live in a separate package.
The renderer attribute is optional. If it is not defined, the ”null” renderer is assumed (no rendering
is performed and the value is passed back to the upstream Pyramid machinery unchanged). Note that
if the view callable itself returns a response (see View Callable Responses), the specified renderer
implementation is never called.

0.3. Narrative Documentation 451


The Pyramid Web Framework, Version 2.0.2

http_cache
When you supply an http_cache value to a view configuration, the Expires and
Cache-Control headers of a response generated by the associated view callable are modified.
The value for http_cache may be one of the following:

• A nonzero integer. If it’s a nonzero integer, it’s treated as a number of seconds. This num-
ber of seconds will be used to compute the Expires header and the Cache-Control:
max-age parameter of responses to requests which call this view. For example:
http_cache=3600 instructs the requesting browser to ’cache this response for an hour,
please’.

• A datetime.timedelta instance. If it’s a datetime.timedelta instance, it will be


converted into a number of seconds, and that number of seconds will be used to compute the
Expires header and the Cache-Control: max-age parameter of responses to requests
which call this view. For example: http_cache=datetime.timedelta(days=1)
instructs the requesting browser to ’cache this response for a day, please’.

• Zero (0). If the value is zero, the Cache-Control and Expires headers present in all
responses from this view will be composed such that client browser cache (and any intermediate
caches) are instructed to never cache the response.

• A two-tuple. If it’s a two-tuple (e.g., http_cache=(1, {'public':True})), the first


value in the tuple may be a nonzero integer or a datetime.timedelta instance. In either
case this value will be used as the number of seconds to cache the response. The second
value in the tuple must be a dictionary. The values present in the dictionary will be used
as input to the Cache-Control response header. For example: http_cache=(3600,
{'public':True}) means ’cache for an hour, and add public to the Cache-Control
header of the response’. All keys and values supported by the webob.cachecontrol.
CacheControl interface may be added to the dictionary. Supplying {'public':True}
is equivalent to calling response.cache_control.public = True.

Providing a non-tuple value as http_cache is equivalent to calling response.


cache_expires(value) within your view’s body.

Providing a two-tuple value as http_cache is equivalent to calling response.


cache_expires(value[0], **value[1]) within your view’s body.

If you wish to avoid influencing the Expires header, and instead wish to only influence
Cache-Control headers, pass a tuple as http_cache with the first element of None, i.e.,
(None, {'public':True}).

require_csrf

452 CONTENTS
The Pyramid Web Framework, Version 2.0.2

CSRF checks will affect any request method that is not defined as a ”safe” method by
RFC2616. In practice this means that GET, HEAD, OPTIONS, and TRACE methods will
pass untouched and all others methods will require CSRF. This option is used in combination
with the pyramid.require_default_csrf setting to control which request parame-
ters are checked for CSRF tokens.

This feature requires a configured session factory.

If this option is set to True then CSRF checks will be enabled for POST requests
to this view. The required token will be whatever was specified by the pyramid.
require_default_csrf setting, or will fallback to csrf_token.

If this option is set to a string then CSRF checks will be enabled and it will be used as the
required token regardless of the pyramid.require_default_csrf setting.

If this option is set to False then CSRF checks will be disabled regardless of the pyramid.
require_default_csrf setting.

In addition, if this option is set to True or a string then CSRF origin checking will be enabled.

See Checking CSRF Tokens Automatically for more information.

New in version 1.7.

wrapper
The view name of a different view configuration which will receive the response body of this view
as the request.wrapped_body attribute of its own request, and the response returned by
this view as the request.wrapped_response attribute of its own request. Using a wrap-
per makes it possible to ”chain” views together to form a composite response. The response of
the outermost wrapper view will be returned to the user. The wrapper view will be found as
any view is found. See View Configuration. The ”best” wrapper view will be found based on
the lookup ordering. ”Under the hood” this wrapper view is looked up via pyramid.view.
render_view_to_response(context, request, 'wrapper_viewname'). The
context and request of a wrapper view is the same context and request of the inner view.

If wrapper is not supplied, no wrapper view is used.

decorator
A dotted Python name to a function (or the function itself) which will be used to decorate the regis-
tered view callable. The decorator function will be called with the view callable as a single argument.
The view callable it is passed will accept (context, request). The decorator must return a
replacement view callable which also accepts (context, request). The decorator may
also be an iterable of decorators, in which case they will be applied one after the other to the view,
in reverse order. For example:

0.3. Narrative Documentation 453


The Pyramid Web Framework, Version 2.0.2

@view_config(..., decorator=(decorator2, decorator1))


def myview(request):
...

Is similar to decorating the view callable directly:

@view_config(...)
@decorator2
@decorator1
def myview(request):
...

An important distinction is that each decorator will receive a response object implementing
pyramid.interfaces.IResponse instead of the raw value returned from the view callable.
All decorators in the chain must return a response object or raise an exception:

def log_timer(wrapped):
def wrapper(context, request):
start = time.time()
response = wrapped(context, request)
duration = time.time() - start
response.headers['X-View-Time'] = '%.3f' % (duration,)
log.info('view took %.3f seconds', duration)
return response
return wrapper

mapper
A Python object or dotted Python name which refers to a view mapper, or None. By default it is
None, which indicates that the view should use the default view mapper. This plug-point is useful
for Pyramid extension developers, but it’s not very useful for ”civilians” who are just developing
stock Pyramid applications. Pay no attention to the man behind the curtain.

accept
A media type that will be matched against the Accept HTTP request header. If this value is spec-
ified, it must be a specific media type such as text/html or text/html;level=1. If the
media type is acceptable by the Accept header of the request, or if the Accept header isn’t set at
all in the request, this predicate will match. If this does not match the Accept header of the request,
view matching continues.

If accept is not specified, the HTTP_ACCEPT HTTP header is not taken into consideration when
deciding whether or not to invoke the associated view callable.

454 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The accept argument is technically not a predicate and does not support wrapping with
pyramid.config.not_().

See Accept Header Content Negotiation for more information.

Changed in version 1.10: Specifying a media range is deprecated and will be removed in Pyramid
2.0. Use explicit media types to avoid any ambiguities in content negotiation.

Changed in version 2.0: Removed support for media ranges.

exception_only

When this value is True, the context argument must be a subclass of Exception. This
flag indicates that only an exception view should be created, and that this view should not
match if the traversal context matches the context argument. If the context is a subclass
of Exception and this value is False (the default), then a view will be registered to match
the traversal context as well.

New in version 1.8.

Predicate Arguments

These arguments modify view lookup behavior. In general the more predicate arguments that are supplied,
the more specific and narrower the usage of the configured view.

name
The view name required to match this view callable. A name argument is typically only used when
your application uses traversal. Read Traversal to understand the concept of a view name.

If name is not supplied, the empty string is used (implying the default view).

context
An object representing a Python class of which the context resource must be an instance or the
interface that the context resource must provide in order for this view to be found and called. This
predicate is true when the context resource is an instance of the represented class or if the context
resource provides the represented interface; it is otherwise false.

It is possible to pass an exception class as the context if your context may subclass an exception. In
this case two views will be registered. One will match normal incoming requests, and the other will
match as an exception view which only occurs when an exception is raised during the normal request
processing pipeline.

If context is not supplied, the value None, which matches any resource, is used.

0.3. Narrative Documentation 455


The Pyramid Web Framework, Version 2.0.2

route_name
If route_name is supplied, the view callable will be invoked only when the named route has
matched.

This value must match the name of a route configuration declaration (see URL Dispatch) that
must match before this view will be called. Note that the route configuration referred to by
route_name will usually have a *traverse token in the value of its pattern, representing a
part of the path that will be used by traversal against the result of the route’s root factory.

If route_name is not supplied, the view callable will only have a chance of being invoked if no
other route was matched. This is when the request/context pair found via resource location does not
indicate it matched any configured route.

request_type
This value should be an interface that the request must provide in order for this view to be found
and called.

If request_type is not supplied, the value None is used, implying any request type.

This is an advanced feature, not often used by ”civilians”.

request_method
This value can be either a string (such as "GET", "POST", "PUT", "DELETE", "HEAD", or
"OPTIONS") representing an HTTP REQUEST_METHOD or a tuple containing one or more of these
strings. A view declaration with this argument ensures that the view will only be called when the
method attribute of the request (i.e., the REQUEST_METHOD of the WSGI environment) matches
a supplied value.

Changed in version 1.4: The use of "GET" also implies that the view will respond to "HEAD".

If request_method is not supplied, the view will be invoked regardless of the RE-
QUEST_METHOD of the WSGI environment.

request_param
This argument can be any string or a sequence of strings. A view declaration with this argument
ensures that the view will only be called when the request has a key in the request.params
dictionary (an HTTP GET or POST variable) that has a name which matches the supplied value.

If any value supplied has an = sign in it, e.g., request_param="foo=123", then the key (foo)
must both exist in the request.params dictionary, and the value must match the right hand side
of the expression (123) for the view to ”match” the current request.

If request_param is not supplied, the view will be invoked without consideration of keys and
values in the request.params dictionary.

456 CONTENTS
The Pyramid Web Framework, Version 2.0.2

match_param
This argument may be either a single string of the format ”key=value” or a tuple containing one or
more of these strings.

This argument ensures that the view will only be called when the request has key/value
pairs in its matchdict that equal those supplied in the predicate. For example,
match_param="action=edit" would require the action parameter in the matchdict
match the right hand side of the expression (edit) for the view to ”match” the current request.

If the match_param is a tuple, every key/value pair must match for the predicate to pass.

If match_param is not supplied, the view will be invoked without consideration of the keys and
values in request.matchdict.

New in version 1.2.

containment
This value should be a reference to a Python class or interface that a parent object in the context
resource’s lineage must provide in order for this view to be found and called. The resources in your
resource tree must be ”location-aware” to use this feature.

If containment is not supplied, the interfaces and classes in the lineage are not considered when
deciding whether or not to invoke the view callable.

See Location-Aware Resources for more information about location-awareness.

xhr
This value should be either True or False. If this value is specified and is True, the WSGI
environment must possess an HTTP_X_REQUESTED_WITH header (i.e., X-Requested-With)
that has the value XMLHttpRequest for the associated view callable to be found and called. This
is useful for detecting AJAX requests issued from jQuery, Prototype, and other Javascript libraries.

If xhr is not specified, the HTTP_X_REQUESTED_WITH HTTP header is not taken into consid-
eration when deciding whether or not to invoke the associated view callable.

header
This param matches one or more HTTP header names or header name/value pairs. If specified, this
param must be a string or a sequence of strings, each string being a header name or a header-
name:headervalue pair.

• Each string specified as a bare header name without a value (for example
If-Modified-Since) will match a request if it contains an HTTP header with that
same name. The case of the name is not significant, and the header may have any value in the
request.

0.3. Narrative Documentation 457


The Pyramid Web Framework, Version 2.0.2

• Each string specified as a name/value pair (that is, if it contains a : (colon), like
User-Agent:Mozilla/.*) will match a request only if it contains an HTTP header with
the requested name (ignoring case, so User-Agent or user-agent would both match),
and the value of the HTTP header matches the value requested (Mozilla/.* in our exam-
ple). The value portion is interpreted as a regular expression.

The view will only be invoked if all strings are matching.

If header is not specified, the composition, presence, or absence of HTTP headers is not taken
into consideration when deciding whether or not to invoke the associated view callable.

path_info
This value represents a regular expression pattern that will be tested against the PATH_INFO WSGI
environment variable to decide whether or not to call the associated view callable. If the regex
matches, this predicate will be True.

If path_info is not specified, the WSGI PATH_INFO is not taken into consideration when de-
ciding whether or not to invoke the associated view callable.

physical_path
If specified, this value should be a string or a tuple representing the physical path of the context
found via traversal for this predicate to match as true. For example, physical_path='/',
physical_path='/a/b/c', or physical_path=('', 'a', 'b', 'c'). This is
not a path prefix match or a regex, but a whole-path match. It’s useful when you want to always
potentially show a view when some object is traversed to, but you can’t be sure about what kind
of object it will be, so you can’t use the context predicate. The individual path elements be-
tween slash characters or in tuple elements should be the Unicode representation of the name of the
resource and should not be encoded in any way.

New in version 1.4a3.

is_authenticated
This value, if specified, must be either True or False. If it is specified and True, only a request
from an authenticated user, as determined by the security policy in use, will satisfy the predicate.
If it is specified and False, only a request from a user who is not authenticated will satisfy the
predicate.

New in version 2.0.

effective_principals
If specified, this value should be a principal identifier or a sequence of principal identifiers. If the
pyramid.request.Request.effective_principals() method indicates that every
principal named in the argument list is present in the current request, this predicate will return

458 CONTENTS
The Pyramid Web Framework, Version 2.0.2

True; otherwise it will return False. For example: effective_principals=pyramid.


authorization.Authenticated or effective_principals=('fred',
'group:admins').
New in version 1.4a4.
Deprecated since version 2.0: Use is_authenticated or a custom predicate.
custom_predicates
If custom_predicates is specified, it must be a sequence of references to custom predicate
callables. Custom predicates can be combined with predefined predicates as necessary. Each custom
predicate callable should accept two arguments, context and request, and should return either
True or False after doing arbitrary evaluation of the context resource and/or the request. If all
callables return True, the associated view callable will be considered viable for a given request.
This parameter is kept around for backward compatibility.
Deprecated since version 1.5: See section below for new-style custom predicates.
**predicates
Extra keyword parameters are used to invoke custom predicates, defined in your app or by third-
party packages extending Pyramid and registered via pyramid.config.Configurator.
add_view_predicate(). Use custom predicates when no set of predefined predicates do what
you need. See View and Route Predicates for more information about custom predicates.
New in version 1.4a1.

Inverting Predicate Values

You can invert the meaning of any predicate value by wrapping it in a call to pyramid.config.not_.

1 from pyramid.config import not_


2

3 config.add_view(
4 'mypackage.views.my_view',
5 route_name='ok',
6 request_method=not_('POST')
7 )

The above example will ensure that the view is called if the request method is not POST, at least if no other
view is more specific.
This technique of wrapping a predicate value in not_ can be used anywhere predicate values are accepted:
• pyramid.config.Configurator.add_view()
• pyramid.view.view_config()
New in version 1.5.

0.3. Narrative Documentation 459


The Pyramid Web Framework, Version 2.0.2

Adding View Configuration Using the @view_config Decorator

Using this feature tends to slow down application startup slightly, as more work is performed
at application startup to scan for view configuration declarations. For maximum startup performance,
use the view configuration method described in Adding View Configuration Using add_view() instead.

The view_config decorator can be used to associate view configuration information with a function,
method, or class that acts as a Pyramid view callable.

Here’s an example of the view_config decorator that lives within a Pyramid application module
views.py:

1 from resources import MyResource


2 from pyramid.view import view_config
3 from pyramid.response import Response
4

5 @view_config(route_name='ok', request_method='POST', permission='read')


6 def my_view(request):
7 return Response('OK')

Using this decorator as above replaces the need to add this imperative configuration stanza:

1 config.add_view('mypackage.views.my_view', route_name='ok',
2 request_method='POST', permission='read')

All arguments to view_config may be omitted. For example:

1 from pyramid.response import Response


2 from pyramid.view import view_config
3

4 @view_config()
5 def my_view(request):
6 """ My view """
7 return Response()

Such a registration as the one directly above implies that the view name will be my_view, registered with
a context argument that matches any resource type, using no permission, registered against requests
with any request method, request type, request param, route name, or containment.

460 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The mere existence of a @view_config decorator doesn’t suffice to perform view configuration. All
that the decorator does is ”annotate” the function with your configuration declarations, it doesn’t process
them. To make Pyramid process your pyramid.view.view_config declarations, you must use the
scan method of a pyramid.config.Configurator:

1 # config is assumed to be an instance of the


2 # pyramid.config.Configurator class
3 config.scan()

Please see Declarative Configuration for detailed information about what happens when code is scanned
for configuration declarations resulting from use of decorators like view_config.

See pyramid.config for additional API arguments to the scan() method. For example, the method allows
you to supply a package argument to better control exactly which code will be scanned.

All arguments to the view_config decorator mean precisely the same thing as they would if they were
passed as arguments to the pyramid.config.Configurator.add_view() method save for the
view argument. Usage of the view_config decorator is a form of declarative configuration, while
pyramid.config.Configurator.add_view() is a form of imperative configuration. However,
they both do the same thing.

@view_config Placement

A view_config decorator can be placed in various points in your application.

If your view callable is a function, it may be used as a function decorator:

1 from pyramid.view import view_config


2 from pyramid.response import Response
3

4 @view_config(route_name='edit')
5 def edit(request):
6 return Response('edited!')

If your view callable is a class, the decorator can also be used as a class decorator. All the arguments to
the decorator are the same when applied against a class as when they are applied against a function. For
example:

0.3. Narrative Documentation 461


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.response import Response


2 from pyramid.view import view_config
3

4 @view_config(route_name='hello')
5 class MyView(object):
6 def __init__(self, request):
7 self.request = request
8

9 def __call__(self):
10 return Response('hello')

More than one view_config decorator can be stacked on top of any number of others. Each decorator
creates a separate view registration. For example:

1 from pyramid.view import view_config


2 from pyramid.response import Response
3

4 @view_config(route_name='edit')
5 @view_config(route_name='change')
6 def edit(request):
7 return Response('edited!')

This registers the same view under two different names.

The decorator can also be used against a method of a class:

1 from pyramid.response import Response


2 from pyramid.view import view_config
3

4 class MyView(object):
5 def __init__(self, request):
6 self.request = request
7

8 @view_config(route_name='hello')
9 def amethod(self):
10 return Response('hello')

When the decorator is used against a method of a class, a view is registered for the class, so the class
constructor must accept an argument list in one of two forms: either a single argument, request, or two
arguments, context, request.

The method which is decorated must return a response.

462 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Using the decorator against a particular method of a class is equivalent to using the attr parameter in a
decorator attached to the class itself. For example, the above registration implied by the decorator being
used against the amethod method could be written equivalently as follows:

1 from pyramid.response import Response


2 from pyramid.view import view_config
3

4 @view_config(attr='amethod', route_name='hello')
5 class MyView(object):
6 def __init__(self, request):
7 self.request = request
8

9 def amethod(self):
10 return Response('hello')

Adding View Configuration Using add_view()

The pyramid.config.Configurator.add_view() method within pyramid.config is used to


configure a view ”imperatively” (without a view_config decorator). The arguments to this method
are very similar to the arguments that you provide to the view_config decorator. For example:

1 from pyramid.response import Response


2

3 def hello_world(request):
4 return Response('hello!')
5

6 # config is assumed to be an instance of the


7 # pyramid.config.Configurator class
8 config.add_view(hello_world, route_name='hello')

The first argument, a view callable, is the only required argument. It must either be a Python object which
is the view itself or a dotted Python name to such an object. In the above example, the view callable
is the hello_world function.

When you use only add_view() to add view configurations, you don’t need to issue a scan in order for
the view configuration to take effect.

0.3. Narrative Documentation 463


The Pyramid Web Framework, Version 2.0.2

@view_defaults Class Decorator

New in version 1.3.

If you use a class as a view, you can use the pyramid.view.view_defaults class decorator on the
class to provide defaults to the view configuration information used by every @view_config decorator
that decorates a method of that class.

For instance, if you’ve got a class that has methods that represent ”REST actions”, all of which are mapped
to the same route but different request methods, instead of this:

1 from pyramid.view import view_config


2 from pyramid.response import Response
3

4 class RESTView(object):
5 def __init__(self, request):
6 self.request = request
7

8 @view_config(route_name='rest', request_method='GET')
9 def get(self):
10 return Response('get')
11

12 @view_config(route_name='rest', request_method='POST')
13 def post(self):
14 return Response('post')
15

16 @view_config(route_name='rest', request_method='DELETE')
17 def delete(self):
18 return Response('delete')

You can do this:

1 from pyramid.view import view_defaults


2 from pyramid.view import view_config
3 from pyramid.response import Response
4

5 @view_defaults(route_name='rest')
6 class RESTView(object):
7 def __init__(self, request):
8 self.request = request
9

10 @view_config(request_method='GET')
11 def get(self):
(continues on next page)

464 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


12 return Response('get')
13

14 @view_config(request_method='POST')
15 def post(self):
16 return Response('post')
17

18 @view_config(request_method='DELETE')
19 def delete(self):
20 return Response('delete')

In the above example, we were able to take the route_name='rest' argument out of the call to each
individual @view_config statement because we used a @view_defaults class decorator to provide
the argument as a default to each view method it possessed.

Arguments passed to @view_config will override any default passed to @view_defaults.

The view_defaults class decorator can also provide defaults to the pyramid.config.
Configurator.add_view() directive when a decorated class is passed to that directive as its view
argument. For example, instead of this:

1 from pyramid.response import Response


2 from pyramid.config import Configurator
3

4 class RESTView(object):
5 def __init__(self, request):
6 self.request = request
7

8 def get(self):
9 return Response('get')
10

11 def post(self):
12 return Response('post')
13

14 def delete(self):
15 return Response('delete')
16

17 def main(global_config, **settings):


18 config = Configurator()
19 config.add_route('rest', '/rest')
20 config.add_view(
21 RESTView, route_name='rest', attr='get', request_method='GET')
22 config.add_view(
23 RESTView, route_name='rest', attr='post', request_method='POST')
(continues on next page)

0.3. Narrative Documentation 465


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


24 config.add_view(
25 RESTView, route_name='rest', attr='delete', request_method='DELETE
,→ ')
26 return config.make_wsgi_app()

To reduce the amount of repetition in the config.add_view statements, we can move the
route_name='rest' argument to a @view_defaults class decorator on the RESTView class:

1 from pyramid.view import view_defaults


2 from pyramid.response import Response
3 from pyramid.config import Configurator
4

5 @view_defaults(route_name='rest')
6 class RESTView(object):
7 def __init__(self, request):
8 self.request = request
9

10 def get(self):
11 return Response('get')
12

13 def post(self):
14 return Response('post')
15

16 def delete(self):
17 return Response('delete')
18

19 def main(global_config, **settings):


20 config = Configurator()
21 config.add_route('rest', '/rest')
22 config.add_view(RESTView, attr='get', request_method='GET')
23 config.add_view(RESTView, attr='post', request_method='POST')
24 config.add_view(RESTView, attr='delete', request_method='DELETE')
25 return config.make_wsgi_app()

pyramid.view.view_defaults accepts the same set of arguments that pyramid.view.


view_config does, and they have the same meaning. Each argument passed to view_defaults
provides a default for the view configurations of methods of the class it’s decorating.

Normal Python inheritance rules apply to defaults added via view_defaults. For example:

1 @view_defaults(route_name='rest')
2 class Foo(object):
(continues on next page)

466 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


3 pass
4

5 class Bar(Foo):
6 pass

The Bar class above will inherit its view defaults from the arguments passed to the view_defaults
decorator of the Foo class. To prevent this from happening, use a view_defaults decorator without
any arguments on the subclass:

1 @view_defaults(route_name='rest')
2 class Foo(object):
3 pass
4

5 @view_defaults()
6 class Bar(Foo):
7 pass

The view_defaults decorator only works as a class decorator; using it against a function or a method
will produce nonsensical results.

Configuring View Security

If an authorization policy is active, any permission attached to a view configuration found during view
lookup will be verified. This will ensure that the currently authenticated user possesses that permission
against the context resource before the view function is actually called. Here’s an example of specifying a
permission in a view configuration using add_view():

1 # config is an instance of pyramid.config.Configurator


2

3 config.add_route('add', '/add.html', factory='mypackage.Blog')


4 config.add_view('myproject.views.add_entry', route_name='add',
5 permission='add')

When an authorization policy is enabled, this view will be protected with the add permission. The view
will not be called if the user does not possess the add permission relative to the current context. Instead
the forbidden view result will be returned to the client as per Protecting Views with Permissions.

0.3. Narrative Documentation 467


The Pyramid Web Framework, Version 2.0.2

NotFound Errors

It’s useful to be able to debug NotFound error responses when they occur unexpectedly due to an ap-
plication registry misconfiguration. To debug these errors, use the PYRAMID_DEBUG_NOTFOUND envi-
ronment variable or the pyramid.debug_notfound configuration file setting. Details of why a view
was not found will be printed to stderr, and the browser representation of the error will include the same
information. See Environment Variables and .ini File Settings for more information about how, and where
to set these values.

Accept Header Content Negotiation

The accept argument to pyramid.config.Configurator.add_view() can be used to control


view lookup by dispatching to different views based on the HTTP Accept request header. Consider the
example below in which there are three views configured.

from pyramid.httpexceptions import HTTPNotAcceptable


from pyramid.view import view_config

@view_config(accept='application/json', renderer='json')
@view_config(accept='text/html', renderer='templates/hello.jinja2')
def myview(request):
return {
'name': request.GET.get('name', 'bob'),
}

@view_config()
def myview_unacceptable(request):
raise HTTPNotAcceptable

Each view relies on the Accept header to trigger an appropriate response renderer. The appropriate
view is selected here when the client specifies headers such as Accept: text/* or Accept:
application/json, text/html;q=0.9 in which only one of the views matches or it’s clear based
on the preferences which one should win. Similarly, if the client specifies a media type that no view is reg-
istered to handle, such as Accept: text/plain, it will fall through to myview_unacceptable
and raise 406 Not Acceptable.

There are a few cases in which the client may specify an Accept header such that it’s not clear which
view should win. For example:

• Accept: */*.

468 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• More than one acceptable media type with the same quality.

• A missing Accept header.

• An invalid Accept header.

In these cases the preferred view is not clearly defined (see RFC 7231#section-5.3.2) and Pyra-
mid will select one randomly. This can be controlled by telling Pyramid what the preferred rel-
ative ordering is between various media types by using pyramid.config.Configurator.
add_accept_view_order(). For example:

from pyramid.config import Configurator

def main(global_config, **settings):


config = Configurator(settings=settings)
config.add_accept_view_order('text/html')
config.add_accept_view_order(
'application/json',
weighs_more_than='text/html',
)
config.scan()
return config.make_wsgi_app()

Now, the application/json view should always be preferred in cases where the client wasn’t clear.

Default Accept Ordering

Pyramid will always sort multiple views with the same (name, context, route_name) first by
the specificity of the accept offer. For any set of media type offers with the same type/subtype,
the offers with params will weigh more than the bare type/subtype offer. This means that text/
plain;charset=utf8 will always be offered before text/plain.

By default, within a given type/subtype, the order of offers is unspecified. For example, text/
plain;charset=utf8 versus text/plain;charset=latin1 are sorted randomly. Similarly,
between media types the order is also unspecified other than the defaults described below. For ex-
ample, image/jpeg versus image/png versus application/pdf. In these cases, the order-
ing may be controlled using pyramid.config.Configurator.add_accept_view_order().
For example, to sort text/plain higher than text/html and to prefer a charset=utf8 versus a
charset=latin-1 within the text/plain media type:

0.3. Narrative Documentation 469


The Pyramid Web Framework, Version 2.0.2

config.add_accept_view_order('text/html')
config.add_accept_view_order('text/plain;charset=latin-1')
config.add_accept_view_order('text/plain', weighs_more_than='text/html')
config.add_accept_view_order('text/plain;charset=utf8', weighs_more_than=
,→'text/plain;charset=latin-1')

It is an error to try and sort accept headers across levels of specificity. You can only sort a type/subtype
against another type/subtype, not against a type/subtype;params. That ordering is a hard
requirement.

By default, Pyramid defines a very simple priority ordering for views that prefers human-readable responses
over JSON:

• text/html

• application/xhtml+xml

• application/xml

• text/xml

• text/plain

• application/json

API clients tend to be able to specify their desired headers with more control than web browsers, and can
specify the correct Accept value, if necessary. Therefore, the motivation for this ordering is to optimize
for readability. Media types that are not listed above are ordered randomly during view lookup between
otherwise-similar views. The defaults can be overridden using pyramid.config.Configurator.
add_accept_view_order() as described above.

Influencing HTTP Caching

New in version 1.1.

When a non-None http_cache argument is passed to a view configuration, Pyramid will set Expires
and Cache-Control response headers in the resulting response, causing browsers to cache the response
data for some time. See http_cache in Non-Predicate Arguments for the allowable values and what
they mean.

470 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Sometimes it’s undesirable to have these headers set as the result of returning a response from a view, even
though you’d like to decorate the view with a view configuration decorator that has http_cache. Per-
haps there’s an alternative branch in your view code that returns a response that should never be cacheable,
while the ”normal” branch returns something that should always be cacheable. If this is the case, set the
prevent_auto attribute of the response.cache_control object to a non-False value. For ex-
ample, the below view callable is configured with a @view_config decorator that indicates any response
from the view should be cached for 3600 seconds. However, the view itself prevents caching from taking
place unless there’s a should_cache GET or POST variable:

from pyramid.view import view_config

@view_config(http_cache=3600)
def view(request):
response = Response()
if 'should_cache' not in request.params:
response.cache_control.prevent_auto = True
return response

Note that the http_cache machinery will overwrite or add to caching headers you set within the view
itself, unless you use prevent_auto.

You can also turn off the effect of http_cache entirely for the duration of a Pyramid application life-
time. To do so, set the PYRAMID_PREVENT_HTTP_CACHE environment variable or the pyramid.
prevent_http_cache configuration value setting to a true value. For more information, see Prevent-
ing HTTP Caching.

Note that setting pyramid.prevent_http_cache will have no effect on caching headers that your
application code itself sets. It will only prevent caching headers that would have been set by the Pyramid
HTTP caching machinery invoked as the result of the http_cache argument to view configuration.

Debugging View Configuration

See pviews: Displaying Matching Views for a Given URL for information about how to display each of
the view callables that might match for a given URL. This can be an effective way to figure out why a
particular view callable is being called instead of the one you’d like to be called.

0.3.13 Static Assets

An asset is any file contained within a Python package which is not a Python source code file. For example,
each of the following is an asset:

0.3. Narrative Documentation 471


The Pyramid Web Framework, Version 2.0.2

• a GIF image file contained within a Python package or contained within any subdirectory of a Python
package.

• a CSS file contained within a Python package or contained within any subdirectory of a Python
package.

• a JavaScript source file contained within a Python package or contained within any subdirectory of
a Python package.

• A directory within a package that does not have an __init__.py in it (if it possessed an
__init__.py it would be a package).

• a Chameleon or Mako template file contained within a Python package.

The use of assets is quite common in most web development projects. For example, when you create a
Pyramid application using the cookiecutter, as described in Creating the Project, the directory representing
the application contains a Python package. Within that Python package, there are directories full of files
which are static assets. For example, there’s a static directory which contains .css, .js, and .gif
files. These asset files are delivered when a user visits an application URL.

Understanding Asset Specifications

Let’s imagine you’ve created a Pyramid application that uses a Chameleon ZPT template via the
pyramid.renderers.render_to_response() API. For example, the application might ad-
dress the asset using the asset specification myapp:templates/some_template.pt using that API
within a views.py file inside a myapp package:

1 from pyramid.renderers import render_to_response


2 render_to_response('myapp:templates/some_template.pt', {}, request)

”Under the hood”, when this API is called, Pyramid attempts to make sense out of the string
myapp:templates/some_template.pt provided by the developer. This string is an asset speci-
fication. It is composed of two parts:

• The package name (myapp)

• The asset name (templates/some_template.pt), relative to the package directory.

472 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The two parts are separated by a colon : character.

Pyramid uses the Python pkg_resources API to resolve the package name and asset name to an absolute
(operating system-specific) file name. It eventually passes this resolved absolute filesystem path to the
Chameleon templating engine, which then uses it to load, parse, and execute the template file.

There is a second form of asset specification: a relative asset specification. Instead of using an ”absolute”
asset specification which includes the package name, in certain circumstances you can omit the package
name from the specification. For example, you might be able to use templates/mytemplate.pt
instead of myapp:templates/some_template.pt. Such asset specifications are usually relative
to a ”current package”. The ”current package” is usually the package which contains the code that uses
the asset specification. Pyramid APIs which accept relative asset specifications typically describe to what
the asset is relative in their individual documentation.

Serving Static Assets

Pyramid makes it possible to serve up static asset files from a directory on a filesystem to an application
user’s browser. Use the pyramid.config.Configurator.add_static_view() to instruct
Pyramid to serve static assets, such as JavaScript and CSS files. This mechanism makes a directory of
static files available at a name relative to the application root URL, e.g., /static, or as an external URL.

add_static_view() cannot serve a single file, nor can it serve a directory of static files directly
relative to the root URL of a Pyramid application. For these features, see Advanced: Serving Static Assets
Using a View Callable.

Here’s an example of a use of add_static_view() that will serve files up from the /var/www/
static directory of the computer which runs the Pyramid application as URLs beneath the /static
URL prefix.

1 # config is an instance of pyramid.config.Configurator


2 config.add_static_view(name='static', path='/var/www/static')

The name represents a URL prefix. In order for files that live in the path directory to be served, a URL
that requests one of them must begin with that prefix. In the example above, name is static and path
is /var/www/static. In English this means that you wish to serve the files that live in /var/www/
static as sub-URLs of the /static URL prefix. Therefore, the file /var/www/static/foo.css
will be returned when the user visits your application’s URL /static/foo.css.

0.3. Narrative Documentation 473


The Pyramid Web Framework, Version 2.0.2

A static directory named at path may contain subdirectories recursively, and any subdirectories may hold
files; these will be resolved by the static view as you would expect. The Content-Type header returned
by the static view for each particular type of file is dependent upon its file extension.

By default, all files made available via add_static_view() are accessible by completely anonymous
users. Simple authorization can be required, however. To protect a set of static files using a permission, in
addition to passing the required name and path arguments, also pass the permission keyword argu-
ment to add_static_view(). The value of the permission argument represents the permission
that the user must have relative to the current context when the static view is invoked. A user will be re-
quired to possess this permission to view any of the files represented by path of the static view. If your
static assets must be protected by a more complex authorization scheme, see Advanced: Serving Static
Assets Using a View Callable.

Here’s another example that uses an asset specification instead of an absolute path as the path argu-
ment. To convince add_static_view() to serve files up under the /static URL from the a/b/
c/static directory of the Python package named some_package, we can use a fully qualified asset
specification as the path:

1 # config is an instance of pyramid.config.Configurator


2 config.add_static_view(name='static', path='some_package:a/b/c/static')

The path provided to add_static_view() may be a fully qualified asset specification or an absolute
path.

Instead of representing a URL prefix, the name argument of a call to add_static_view() can al-
ternately be a URL. Each of the examples we’ve seen so far have shown usage of the name argument as
a URL prefix. However, when name is a URL, static assets can be served from an external webserver.
In this mode, the name is used as the URL prefix when generating a URL using pyramid.request.
Request.static_url().

For example, add_static_view() may be fed a name argument which is http://example.


com/images:

1 # config is an instance of pyramid.config.Configurator


2 config.add_static_view(name='http://example.com/images',
3 path='mypackage:images')

Because add_static_view() is provided with a name argument that is the URL http://
example.com/images, subsequent calls to static_url() with paths that start with the path
argument passed to add_static_view() will generate a URL something like http://example.
com/images/logo.png. The external webserver listening on example.com must be itself config-
ured to respond properly to such a request. The static_url() API is discussed in more detail later in
this chapter.

474 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Serving Pre-compressed Assets

New in version 2.0.

It’s possible to configure Pyramid to serve pre-compressed static assets. This can greatly reduce the band-
width required to serve assets - most modern browsers support gzip, deflate, and br (brotli) encoded
responses. A client declares support for encoded responses using the Accept-Encoding HTTP header.
For example, Accept-Encoding: gzip, default, br. The response will then contain the pre-
compressed content with the Content-Encoding header set to the matched encoding. This feature
assumes that the static assets exist unencoded (identity encoding) as well as in zero or more encoded
formats. If the encoded version of a file is missing, or the client doesn’t declare support for the encoded
version, the unencoded version is returned instead.

In order to configure this in your application, the first step is to compress your assets. For
example, update your static asset pipeline to export .gz versions of every file. Second,
add content_encodings=['gzip'] when invoking pyramid.config.Configurator.
add_static_view().

The encoded file extensions are determined by mimetypes.encodings_map. So, if your desired
encoding is missing, you’ll need to add it there:

import mimetypes
mimetypes.encodings_map['.br'] = 'br' # add brotli

It is not necessary for every file to support every encoding, but Pyramid will not serve an encoding that is
not declared.

Generating Static Asset URLs

When an add_static_view() method is used to register a static asset directory, a special helper API
named pyramid.request.Request.static_url() can be used to generate the appropriate URL
for an asset that lives in one of the directories named by the static registration path attribute.

For example, let’s assume you create a set of static declarations like so:

1 config.add_static_view(name='static1', path='mypackage:assets/1')
2 config.add_static_view(name='static2', path='mypackage:assets/2')

0.3. Narrative Documentation 475


The Pyramid Web Framework, Version 2.0.2

These declarations create URL-accessible directories which have URLs that begin with /static1 and /
static2, respectively. The assets in the assets/1 directory of the mypackage package are consulted
when a user visits a URL which begins with /static1, and the assets in the assets/2 directory of
the mypackage package are consulted when a user visits a URL which begins with /static2.

You needn’t generate the URLs to static assets ”by hand” in such a configuration. Instead, use the
static_url() API to generate them for you. For example:

1 from pyramid.renderers import render_to_response


2

3 def my_view(request):
4 css_url = request.static_url('mypackage:assets/1/foo.css')
5 js_url = request.static_url('mypackage:assets/2/foo.js')
6 return render_to_response('templates/my_template.pt',
7 dict(css_url=css_url, js_url=js_url),
8 request=request)

If the request ”application URL” of the running system is http://example.com, the css_url gener-
ated above would be: http://example.com/static1/foo.css. The js_url generated above
would be http://example.com/static2/foo.js.

One benefit of using the static_url() function rather than constructing static URLs ”by hand” is that
if you need to change the name of a static URL declaration, the generated URLs will continue to resolve
properly after the rename.

URLs may also be generated by static_url() to static assets that live outside the Pyramid application.
This will happen when the add_static_view() API associated with the path fed to static_url()
is a URL instead of a view name. For example, the name argument may be http://example.com
while the path given may be mypackage:images:

1 config.add_static_view(name='http://example.com/images',
2 path='mypackage:images')

Under such a configuration, the URL generated by static_url for assets which begin with mypack-
age:images will be prefixed with http://example.com/images:

1 request.static_url('mypackage:images/logo.png')
2 # -> http://example.com/images/logo.png

Using static_url() in conjunction with a add_static_view() makes it possible to put static


media on a separate webserver during production (if the name argument to add_static_view() is

476 CONTENTS
The Pyramid Web Framework, Version 2.0.2

a URL), while keeping static media package-internal and served by the development webserver during
development (if the name argument to add_static_view() is a URL prefix).

For example, we may define a custom setting named media_location which we can set to an external
URL in production when our assets are hosted on a CDN.

1 media_location = settings.get('media_location', 'static')


2

3 config = Configurator(settings=settings)
4 config.add_static_view(path='myapp:static', name=media_location)

Now we can optionally define the setting in our ini file:

1 # production.ini
2 [app:main]
3 use = egg:myapp#main
4

5 media_location = http://static.example.com/

It is also possible to serve assets that live outside of the source by referring to an absolute path on the
filesystem. There are two ways to accomplish this.

First, add_static_view() supports taking an absolute path directly instead of an asset spec. This
works as expected, looking in the file or folder of files and serving them up at some URL within your
application or externally. Unfortunately, this technique has a drawback in that it is not possible to use the
static_url() method to generate URLs, since it works based on an asset specification.

New in version 1.6.

The second approach, available in Pyramid 1.6+, uses the asset overriding APIs described in the Overriding
Assets section. It is then possible to configure a ”dummy” package which then serves its file or folder from
an absolute path.

config.add_static_view(path='myapp:static_images', name='static')
config.override_asset(to_override='myapp:static_images/',
override_with='/abs/path/to/images/')

From this configuration it is now possible to use static_url() to generate URLs to the data in the
folder by doing something like request.static_url('myapp:static_images/foo.png').
While it is not necessary that the static_images file or folder actually exist in the myapp package, it
is important that the myapp portion points to a valid package. If the folder does exist, then the overriden
folder is given priority, if the file’s name exists in both locations.

0.3. Narrative Documentation 477


The Pyramid Web Framework, Version 2.0.2

Cache Busting

New in version 1.6.

In order to maximize performance of a web application, you generally want to limit the number of times
a particular client requests the same static asset. Ideally a client would cache a particular static asset
”forever”, requiring it to be sent to the client a single time. The HTTP protocol allows you to send headers
with an HTTP response that can instruct a client to cache a particular asset for an amount of time. As long
as the client has a copy of the asset in its cache and that cache hasn’t expired, the client will use the cached
copy rather than request a new copy from the server. The drawback to sending cache headers to the client
for a static asset is that at some point the static asset may change, and then you’ll want the client to load a
new copy of the asset. Under normal circumstances you’d just need to wait for the client’s cached copy to
expire before they get the new version of the static resource.

A commonly used workaround to this problem is a technique known as cache busting. Cache busting
schemes generally involve generating a URL for a static asset that changes when the static asset changes.
This way headers can be sent along with the static asset instructing the client to cache the asset for a very
long time. When a static asset is changed, the URL used to refer to it in a web page also changes, so the
client sees it as a new resource and requests the asset, regardless of any caching policy set for the resource’s
old URL.

Pyramid can be configured to produce cache busting URLs for static assets using
add_cache_buster():

1 import time
2 from pyramid.static import QueryStringConstantCacheBuster
3

4 # config is an instance of pyramid.config.Configurator


5 config.add_static_view(name='static', path='mypackage:folder/static/')
6 config.add_cache_buster(
7 'mypackage:folder/static/',
8 QueryStringConstantCacheBuster(str(int(time.time()))))

Adding the cachebuster instructs Pyramid to add the current time for a static asset to the query string in
the asset’s URL:

1 js_url = request.static_url('mypackage:folder/static/js/myapp.js')
2 # Returns: 'http://www.example.com/static/js/myapp.js?x=1445318121'

When the web server restarts, the time constant will change and therefore so will its URL.

478 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Cache busting is an inherently complex topic as it integrates the asset pipeline and the web applica-
tion. It is expected and desired that application authors will write their own cache buster implementations
conforming to the properties of their own asset pipelines. See Customizing the Cache Buster for informa-
tion on writing your own.

Disabling the Cache Buster

It can be useful in some situations (e.g., development) to globally disable all configured cache busters with-
out changing calls to add_cache_buster(). To do this set the PYRAMID_PREVENT_CACHEBUST
environment variable or the pyramid.prevent_cachebust configuration value to a true value.

Customizing the Cache Buster

Calls to add_cache_buster() may use any object that implements the interface ICacheBuster.

Pyramid ships with a very simplistic QueryStringConstantCacheBuster, which adds an arbi-


trary token you provide to the query string of the asset’s URL. This is almost never what you want in
production as it does not allow fine-grained busting of individual assets.

In order to implement your own cache buster, you can write your own class from scratch which implements
the ICacheBuster interface. Alternatively you may choose to subclass one of the existing implementa-
tions. One of the most likely scenarios is you’d want to change the way the asset token is generated. To do
this just subclass QueryStringCacheBuster and define a tokenize(pathspec) method. Here
is an example which uses Git to get the hash of the current commit:

1 import os
2 import subprocess
3 from pyramid.static import QueryStringCacheBuster
4

5 class GitCacheBuster(QueryStringCacheBuster):
6 """
7 Assuming your code is installed as a Git checkout, as opposed to an egg
8 from an egg repository like PYPI, you can use this cachebuster to get
9 the current commit's SHA1 to use as the cache bust token.
10 """
11 def __init__(self, param='x', repo_path=None):
12 super(GitCacheBuster, self).__init__(param=param)
(continues on next page)

0.3. Narrative Documentation 479


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


13 if repo_path is None:
14 repo_path = os.path.dirname(os.path.abspath(__file__))
15 self.sha1 = subprocess.check_output(
16 ['git', 'rev-parse', 'HEAD'],
17 cwd=repo_path).strip()
18

19 def tokenize(self, pathspec):


20 return self.sha1

A simple cache buster that modifies the path segment can be constructed as well:

1 import posixpath
2

3 class PathConstantCacheBuster(object):
4 def __init__(self, token):
5 self.token = token
6

7 def __call__(self, request, subpath, kw):


8 base_subpath, ext = posixpath.splitext(subpath)
9 new_subpath = base_subpath + self.token + ext
10 return new_subpath, kw

The caveat with this approach is that modifying the path segment changes the file name, and thus must
match what is actually on the filesystem in order for add_static_view() to find the file. It’s better to
use the ManifestCacheBuster for these situations, as described in the next section.

Path Segments and Choosing a Cache Buster

Many caching HTTP proxies will fail to cache a resource if the URL contains a query string. Therefore, in
general, you should prefer a cache busting strategy which modifies the path segment rather than methods
which add a token to the query string.

You will need to consider whether the Pyramid application will be serving your static assets, whether
you are using an external asset pipeline to handle rewriting urls internal to the css/javascript, and how
fine-grained do you want the cache busting tokens to be.

In many cases you will want to host the static assets on another web server or externally on a CDN. In
these cases your Pyramid application may not even have access to a copy of the static assets. In order to
cache bust these assets you will need some information about them.

480 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If you are using an external asset pipeline to generate your static files you should consider using the Man-
ifestCacheBuster. This cache buster can load a standard JSON formatted file generated by your
pipeline and use it to cache bust the assets. This has many performance advantages as Pyramid does not
need to look at the files to generate any cache busting tokens, but still supports fine-grained per-file tokens.

Assuming an example manifest.json like:

{
"css/main.css": "css/main-678b7c80.css",
"images/background.png": "images/background-a8169106.png"
}

The following code would set up a cachebuster:

1 from pyramid.static import ManifestCacheBuster


2

3 config.add_static_view(
4 name='http://mycdn.example.com/',
5 path='mypackage:static')
6

7 config.add_cache_buster(
8 'mypackage:static/',
9 ManifestCacheBuster('myapp:static/manifest.json'))

It’s important to note that the cache buster only handles generating cache-busted URLs for static assets. It
does NOT provide any solutions for serving those assets. For example, if you generated a URL for css/
main-678b7c80.css then that URL needs to be valid either by configuring add_static_view
properly to point to the location of the files or some other mechanism such as the files existing on your
CDN or rewriting the incoming URL to remove the cache bust tokens.

CSS and JavaScript source and cache busting

Often one needs to refer to images and other static assets inside CSS and JavaScript files. If cache busting is
active, the final static asset URL is not available until the static assets have been assembled. These URLs
cannot be handwritten. Below is an example of how to integrate the cache buster into the entire stack.
Remember, it is just an example and should be modified to fit your specific tools.

• First, process the files by using a precompiler which rewrites URLs to their final cache-busted form.
Then, you can use the ManifestCacheBuster to synchronize your asset pipeline with Pyramid,
allowing the pipeline to have full control over the final URLs of your assets.

0.3. Narrative Documentation 481


The Pyramid Web Framework, Version 2.0.2

Now that you are able to generate static URLs within Pyramid, you’ll need to handle URLs that are out of
our control. To do this you may use some of the following options to get started:

• Configure your asset pipeline to rewrite URL references inline in CSS and JavaScript. This is the
best approach because then the files may be hosted by Pyramid or an external CDN without having
to change anything. They really are static.

• Templatize JS and CSS, and call request.static_url() inside their template code. While
this approach may work in certain scenarios, it is not recommended because your static assets will
not really be static and are now dependent on Pyramid to be served correctly. See Advanced: Serving
Static Assets Using a View Callable for more information on this approach.

If your CSS and JavaScript assets use URLs to reference other assets it is recommended that you implement
an external asset pipeline that can rewrite the generated static files with new URLs containing cache busting
tokens. The machinery inside Pyramid will not help with this step as it has very little knowledge of the
asset types your application may use. The integration into Pyramid is simply for linking those assets into
your HTML and other dynamic content.

Advanced: Serving Static Assets Using a View Callable

For more flexibility, static assets can be served by a view callable which you register manually. For example,
if you’re using URL dispatch, you may want static assets to only be available as a fallback if no previous
route matches. Alternatively, you might like to serve a particular static asset manually, because its download
requires authentication.

Note that you cannot use the static_url() API to generate URLs against assets made accessible by
registering a custom static view.

Root-Relative Custom Static View (URL Dispatch Only)

The pyramid.static.static_view helper class generates a Pyramid view callable. This view
callable can serve static assets from a directory. An instance of this class is actually used by the
add_static_view() configuration method, so its behavior is almost exactly the same once it’s con-
figured.

482 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The following example will not work for applications that use traversal; it will only work if
you use URL dispatch exclusively. The root-relative route we’ll be registering will always be matched
before traversal takes place, subverting any views registered via add_view (at least those without a
route_name). A static_view static view cannot be made root-relative when you use traversal
unless it’s registered as a Not Found View.

To serve files within a directory located on your filesystem at /path/to/static/dir as the result of
a ”catchall” route hanging from the root that exists at the end of your routing table, create an instance of
the static_view class inside a static.py file in your application root as below.

1 from pyramid.static import static_view


2 static_view = static_view('/path/to/static/dir', use_subpath=True)

For better cross-system flexibility, use an asset specification as the argument to static_view
instead of a physical absolute filesystem path, e.g., mypackage:static, instead of /path/to/
mypackage/static.

Subsequently, you may wire the files that are served by this view up to be accessible as /<filename>
using a configuration method in your application’s startup code.

1 # .. every other add_route declaration should come


2 # before this one, as it will, by default, catch all requests
3

4 config.add_route('catchall_static', '/*subpath')
5 config.add_view('myapp.static.static_view', route_name='catchall_static')

The special name *subpath above is used by the static_view view callable to signify the path of
the file relative to the directory you’re serving.

Registering a View Callable to Serve a ”Static” Asset

You can register a simple view callable to serve a single static asset. To do so, do things ”by hand”. First
define the view callable.

0.3. Narrative Documentation 483


The Pyramid Web Framework, Version 2.0.2

1 import os
2 from pyramid.response import FileResponse
3

4 def favicon_view(request):
5 here = os.path.dirname(__file__)
6 icon = os.path.join(here, 'static', 'favicon.ico')
7 return FileResponse(icon, request=request)

The above bit of code within favicon_view computes ”here”, which is a path relative to the Python file
in which the function is defined. It then creates a pyramid.response.FileResponse using the file
path as the response’s path argument and the request as the response’s request argument. pyramid.
response.FileResponse will serve the file as quickly as possible when it’s used this way. It makes
sure to set the right content length and content_type, too, based on the file extension of the file you pass.
You might register such a view via configuration as a view callable that should be called as the result of a
traversal:

1 config.add_view('myapp.views.favicon_view', name='favicon.ico')

Or you might register it to be the view callable for a particular route:

1 config.add_route('favicon', '/favicon.ico')
2 config.add_view('myapp.views.favicon_view', route_name='favicon')

Because this is a simple view callable, it can be protected with a permission or can be configured to respond
under different circumstances using view predicate arguments.

Overriding Assets

It can often be useful to override specific assets from ”outside” a given Pyramid application. For example,
you may wish to reuse an existing Pyramid application more or less unchanged. However, some specific
template file owned by the application might have inappropriate HTML, or some static asset (such as a logo
file or some CSS file) might not be appropriate. You could just fork the application entirely, but it’s often
more convenient to just override the assets that are inappropriate and reuse the application ”as is”. This
is particularly true when you reuse some ”core” application over and over again for some set of customers
(such as a CMS application, or some bug tracking application), and you want to make arbitrary visual
modifications to a particular application deployment without forking the underlying code.
To this end, Pyramid contains a feature that makes it possible to ”override” one asset with one or
more other assets. In support of this feature, a Configurator API exists named pyramid.config.
Configurator.override_asset(). This API allows you to override the following kinds of assets
defined in any Python package:

484 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Individual template files.

• A directory containing multiple template files.

• Individual static files served up by an instance of the pyramid.static.static_view helper


class.

• A directory of static files served up by an instance of the pyramid.static.static_view


helper class.

• Any other asset (or set of assets) addressed by code that uses the Setuptools pkg_resources API.

The override_asset API

An individual call to override_asset() can override a single asset. For example:

1 config.override_asset(
2 to_override='some.package:templates/mytemplate.pt',
3 override_with='another.package:othertemplates/anothertemplate.pt')

The string value passed to both to_override and override_with sent to the override_asset
API is called an asset specification. The colon separator in a specification separates the package name from
the asset name. The colon and the following asset name are optional. If they are not specified, the override
attempts to resolve every lookup into a package from the directory of another package. For example:

1 config.override_asset(to_override='some.package',
2 override_with='another.package')

Individual subdirectories within a package can also be overridden:

1 config.override_asset(to_override='some.package:templates/',
2 override_with='another.package:othertemplates/')

If you wish to override a directory with another directory, you must make sure to attach the slash to the end
of both the to_override specification and the override_with specification. If you fail to attach a
slash to the end of a specification that points to a directory, you will get unexpected results.

You cannot override a directory specification with a file specification, and vice versa; a startup error will
occur if you try. You cannot override an asset with itself; a startup error will occur if you try.

0.3. Narrative Documentation 485


The Pyramid Web Framework, Version 2.0.2

Only individual package assets may be overridden. Overrides will not traverse through subpack-
ages within an overridden package. This means that if you want to override assets for both some.
package:templates, and some.package.views:templates, you will need to register two
overrides.

The package name in a specification may start with a dot, meaning that the package is relative to the package
in which the configuration construction file resides (or the package argument to the Configurator
class construction). For example:

1 config.override_asset(to_override='.subpackage:templates/',
2 override_with='another.package:templates/')

Multiple calls to override_asset which name a shared to_override but a different over-
ride_with specification can be ”stacked” to form a search path. The first asset that exists in the search
path will be used; if no asset exists in the override path, the original asset is used.

Asset overrides can actually override assets other than templates and static files. Any soft-
ware which uses the pkg_resources.get_resource_filename(), pkg_resources.
get_resource_stream(), or pkg_resources.get_resource_string() APIs will obtain
an overridden file when an override is used.

New in version 1.6: As of Pyramid 1.6, it is also possible to override an asset by supplying an absolute
path to a file or directory. This may be useful if the assets are not distributed as part of a Python package.

Cache Busting and Asset Overrides

Overriding static assets that are being hosted using pyramid.config.Configurator.


add_static_view() can affect your cache busting strategy when using any cache busters that
are asset-aware such as pyramid.static.ManifestCacheBuster. What sets asset-aware cache
busters apart is that they have logic tied to specific assets. For example, a manifest is only generated for
a specific set of pre-defined assets. Now, imagine you have overridden an asset defined in this manifest
with a new, unknown version. By default, the cache buster will be invoked for an asset it has never seen
before and will likely end up returning a cache busting token for the original asset rather than the asset
that will actually end up being served! In order to get around this issue, it’s possible to attach a different
pyramid.interfaces.ICacheBuster implementation to the new assets. This would cause the
original assets to be served by their manifest, and the new assets served by their own cache buster. To
do this, pyramid.config.Configurator.add_cache_buster() supports an explicit
option. For example:

486 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.static import ManifestCacheBuster


2

3 # define a static view for myapp:static assets


4 config.add_static_view('static', 'myapp:static')
5

6 # setup a cache buster for your app based on the myapp:static assets
7 my_cb = ManifestCacheBuster('myapp:static/manifest.json')
8 config.add_cache_buster('myapp:static', my_cb)
9

10 # override an asset
11 config.override_asset(
12 to_override='myapp:static/background.png',
13 override_with='theme:static/background.png')
14

15 # override the cache buster for theme:static assets


16 theme_cb = ManifestCacheBuster('theme:static/manifest.json')
17 config.add_cache_buster('theme:static', theme_cb, explicit=True)

In the above example there is a default cache buster, my_cb, for all assets served from the
myapp:static folder. This would also affect theme:static/background.png when gener-
ating URLs via request.static_url('myapp:static/background.png').

The theme_cb is defined explicitly for any assets loaded from the theme:static folder.
Explicit cache busters have priority and thus theme_cb would be invoked for request.
static_url('myapp:static/background.png'), but my_cb would be used for any other
assets like request.static_url('myapp:static/favicon.ico').

0.3.14 Request and Response Objects

This chapter is adapted from a portion of the WebOb documentation, originally written by Ian
Bicking.

Pyramid uses the WebOb package as a basis for its request and response object implementations. The re-
quest object that is passed to a Pyramid view is an instance of the pyramid.request.Request class,
which is a subclass of webob.request.Request. The response returned from a Pyramid view ren-
derer is an instance of the pyramid.response.Response class, which is a subclass of the webob.
response.Response class. Users can also return an instance of pyramid.response.Response
directly from a view as necessary.

0.3. Narrative Documentation 487


The Pyramid Web Framework, Version 2.0.2

WebOb is a project separate from Pyramid with a separate set of authors and a fully separate set of docu-
mentation. Pyramid adds some functionality to the standard WebOb request, which is documented in the
pyramid.request API documentation.

WebOb provides objects for HTTP requests and responses. Specifically it does this by wrapping the WSGI
request environment and response status, header list, and app_iter (body) values.

WebOb request and response objects provide many conveniences for parsing WSGI requests and forming
WSGI responses. WebOb is a nice way to represent ”raw” WSGI requests and responses. However, we
won’t cover that use case in this document, as users of Pyramid don’t typically need to use the WSGI-related
features of WebOb directly. The reference documentation shows many examples of creating requests and
using response objects in this manner, however.

Request

The request object is a wrapper around the WSGI environ dictionary. This dictionary contains keys for
each header, keys that describe the request (including the path and query string), a file-like object for the
request body, and a variety of custom keys. You can always access the environ with req.environ.

Some of the most important and interesting attributes of a request object are below.

req.method
The request method, e.g., GET, POST

req.GET
A multidict with all the variables in the query string.

req.POST
A multidict with all the variables in the request body. This only has variables if the request was a
POST and it is a form submission.

req.params
A multidict with a combination of everything in req.GET and req.POST.

req.body
The contents of the body of the request. This contains the entire request body as a string. This is
useful when the request is a POST that is not a form submission, or a request like a PUT. You can
also get req.body_file for a file-like object.

req.json_body
The JSON-decoded contents of the body of the request. See Dealing with a JSON-Encoded Request
Body.

488 CONTENTS
The Pyramid Web Framework, Version 2.0.2

req.cookies
A simple dictionary of all the cookies.

req.headers
A dictionary of all the headers. This dictionary is case-insensitive.

req.urlvars and req.urlargs


req.urlvars are the keyword parameters associated with the request URL. req.urlargs are
the positional parameters. These are set by products like Routes and Selector.

Also for standard HTTP request headers, there are usually attributes such as req.accept_language,
req.content_length, and req.user_agent. These properties expose the parsed form of each
header, for whatever parsing makes sense. For instance, req.if_modified_since returns a date-
time object (or None if the header is was not provided).

Full API documentation for the Pyramid request object is available in pyramid.request.

Special Attributes Added to the Request by Pyramid

In addition to the standard WebOb attributes, Pyramid adds special attributes to every request:
context, registry, root, subpath, traversed, view_name, virtual_root, vir-
tual_root_path, session, matchdict, and matched_route. These attributes are docu-
mented further within the pyramid.request.Request API documentation.

URLs

In addition to these attributes, there are several ways to get the URL of the request and its parts. We’ll show
various values for an example URL http://localhost/app/blog?id=10, where the application
is mounted at http://localhost/app.

req.url
The full request URL with query string, e.g., http://localhost/app/blog?id=10

req.host
The host information in the URL, e.g., localhost

0.3. Narrative Documentation 489


The Pyramid Web Framework, Version 2.0.2

req.host_url
The URL with the host, e.g., http://localhost

req.application_url
The URL of the application (just the SCRIPT_NAME portion of the path, not PATH_INFO), e.g.,
http://localhost/app

req.path_url
The URL of the application including the PATH_INFO, e.g., http://localhost/app/blog

req.path
The URL including PATH_INFO without the host or scheme, e.g., /app/blog

req.path_qs
The URL including PATH_INFO and the query string, e.g, /app/blog?id=10

req.query_string
The query string in the URL, e.g., id=10

req.relative_url(url, to_application=False)
Gives a URL relative to the current URL. If to_application is True, then resolves it relative to
req.application_url.

Methods

There are methods of request objects documented in pyramid.request.Request but you’ll find that
you won’t use very many of them. Here are a couple that might be useful:

Request.blank(base_url)
Creates a new request with blank information, based at the given URL. This can be useful for sub-
requests and artificial requests. You can also use req.copy() to copy an existing request, or for
subrequests req.copy_get() which copies the request but always turns it into a GET (which is
safer to share for subrequests).

req.get_response(wsgi_application)
This method calls the given WSGI application with this request, and returns a pyramid.
response.Response object. You can also use this for subrequests or testing.

490 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Text (Unicode)

Most of the properties of the request object will be text values. The values in req.POST, req.
GET, req.params, and req.cookies will contain text and are generated assuming a UTF-8
charset. The client can indicate the charset with something like Content-Type: application/
x-www-form-urlencoded; charset=utf8, but browsers seldom set this. You can reset the
charset of an existing request with newreq = req.decode('utf-8'), or during instantiation with
Request(environ, charset='utf8').

Multidict

Several attributes of a WebOb request are multidict structures (such as request.GET, request.
POST, and request.params). A multidict is a dictionary where a key can have multiple values. The
quintessential example is a query string like ?pref=red&pref=blue; the pref variable has two val-
ues: red and blue.

In a multidict, when you do request.GET['pref'], you’ll get back only "blue" (the last value
of pref). This returned result might not be expected—sometimes returning a string, and sometimes
returning a list—and may be cause of frequent exceptions. If you want all the values back, use request.
GET.getall('pref'). If you want to be sure there is one and only one value, use request.GET.
getone('pref'), which will raise an exception if there is zero or more than one value for pref.

When you use operations like request.GET.items(), you’ll get back something like [('pref',
'red'), ('pref', 'blue')]. All the key/value pairs will show up. Similarly request.GET.
keys() returns ['pref', 'pref']. Multidict is a view on a list of tuples; all the keys are ordered,
and all the values are ordered.

API documentation for a multidict exists as pyramid.interfaces.IMultiDict.

Dealing with a JSON-Encoded Request Body

New in version 1.1.

pyramid.request.Request.json_body is a property that returns a JSON-decoded representa-


tion of the request body. If the request does not have a body, or the body is not a properly JSON-encoded
value, an exception will be raised when this attribute is accessed.

This attribute is useful when you invoke a Pyramid view callable via, for example, jQuery’s $.ajax
function, which has the potential to send a request with a JSON-encoded body.

Using request.json_body is equivalent to:

0.3. Narrative Documentation 491


The Pyramid Web Framework, Version 2.0.2

from json import loads


loads(request.body, encoding=request.charset)

Here’s how to construct an AJAX request in JavaScript using jQuery that allows you to use the request.
json_body attribute when the request is sent to a Pyramid application:

jQuery.ajax({type:'POST',
url: 'http://localhost:6543/', // the pyramid server
data: JSON.stringify({'a':1}),
contentType: 'application/json'});

When such a request reaches a view in your application, the request.json_body attribute will be
available in the view callable body.

@view_config(renderer='string')
def aview(request):
print(request.json_body)
return 'OK'

For the above view, printed to the console will be:

{'a': 1}

For bonus points, here’s a bit of client-side code that will produce a request that has a body suitable for
reading via request.json_body using Python’s urllib2 instead of a JavaScript AJAX request:

import urllib2
import json

json_payload = json.dumps({'a':1})
headers = {'Content-Type':'application/json'}
req = urllib2.Request('http://localhost:6543/', json_payload, headers)
resp = urllib2.urlopen(req)

If you are doing Cross-origin resource sharing (CORS), then the standard requires the browser to do a
pre-flight HTTP OPTIONS request. The easiest way to handle this is to add an extra view_config for
the same route, with request_method set to OPTIONS, and set the desired response header before
returning. You can find examples of response headers Access control CORS, Preflighted requests.

492 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Cleaning up after a Request

Sometimes it’s required to perform some cleanup at the end of a request when a database connection is
involved.

For example, let’s say you have a mypackage Pyramid application package that uses SQLAlchemy, and
you’d like the current SQLAlchemy database session to be removed after each request. Put the following
in the mypackage.__init__ module:

1 from mypackage.models import DBSession


2

3 from pyramid.events import subscriber


4 from pyramid.events import NewRequest
5

6 def cleanup_callback(request):
7 DBSession.remove()
8

9 @subscriber(NewRequest)
10 def add_cleanup_callback(event):
11 event.request.add_finished_callback(cleanup_callback)

Registering the cleanup_callback finished callback at the start of a request (by causing the
add_cleanup_callback to receive a pyramid.events.NewRequest event at the start of each
request) will cause the DBSession to be removed whenever request processing has ended. Note that in the
example above, for the pyramid.events.subscriber decorator to work, the pyramid.config.
Configurator.scan() method must be called against your mypackage package during application
initialization.

This is only an example. In particular, it is not necessary to cause DBSession.remove to be


called in an application generated from the Pyramid cookiecutter, because these all use the pyramid_tm
package. The cleanup done by DBSession.remove is unnecessary when pyramid_tm middleware
is configured into the application.

More Details

More detail about the request object API is available as follows.

• pyramid.request.Request API documentation

• WebOb documentation. All methods and attributes of a webob.Request documented within the
WebOb documentation will work with request objects created by Pyramid.

0.3. Narrative Documentation 493


The Pyramid Web Framework, Version 2.0.2

Response

The Pyramid response object can be imported as pyramid.response.Response. This class is a sub-
class of the webob.reponse.Response class. The subclass does not add or change any functionality,
so the WebOb Response documentation will be completely relevant for this class as well.
A response object has three fundamental parts:
response.status
The response code plus reason message, like 200 OK. To set the code without a message, use
status_int, i.e., response.status_int = 200.
response.headerlist
A list of all the headers, like [('Content-Type', 'text/html')]. There’s a case-
insensitive multidict in response.headers that also allows you to access these same headers.
response.app_iter
An iterable (such as a list or generator) that will produce the content of the response. This is
also accessible as response.body (bytes), response.text (a Unicode string, informed by
response.charset), and response.body_file (a file-like object; writing to it appends to
app_iter).
Everything else in the object typically derives from this underlying state. Here are some highlights:
response.content_type
The content type not including the charset parameter.
Typical use: response.content_type = 'text/html'.
Default value: response.content_type = 'text/html'.
response.charset
The charset parameter of the content-type, it also informs encoding in response.text.
response.content_type_params is a dictionary of all the parameters.
response.set_cookie(name, value, max_age=None, path='/', ...)
Set a cookie. The keyword arguments control the various cookie parameters. The max_age ar-
gument is the length for the cookie to live in seconds (you may also use a timedelta object). The
Expires key will also be set based on the value of max_age.
response.delete_cookie(name, path='/', domain=None)
Delete a cookie from the client. This sets max_age to 0 and the cookie value to ''.
response.cache_expires(seconds=0)
This makes the response cacheable for the given number of seconds, or if seconds is 0 then the
response is uncacheable (this also sets the Expires header).
response(environ, start_response)
The response object is a WSGI application. As an application, it acts according to how you create it.
It can do conditional responses if you pass conditional_response=True when instantiating
(or set that attribute later). It can also do HEAD and Range requests.

494 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Headers

Like the request, most HTTP response headers are available as properties. These are parsed, so you can
do things like response.last_modified = os.path.getmtime(filename).

The details are available in the webob.response API documentation.

Instantiating the Response

Of course most of the time you just want to make a response. Generally any attribute of the response can
be passed in as a keyword argument to the class, e.g.:

1 from pyramid.response import Response


2 response = Response(body='hello world!', content_type='text/plain')

The status defaults to '200 OK'.

The value of content_type defaults to webob.response.Response.


default_content_type, which is text/html. You can subclass pyramid.response.
Response and set default_content_type to override this behavior.

Exception Responses

To facilitate error responses like 404 Not Found, the module pyramid.httpexceptions con-
tains classes for each kind of error response. These include boring but appropriate error bodies. The
exceptions exposed by this module, when used under Pyramid, should be imported from the pyramid.
httpexceptions module. This import location contains subclasses and replacements that mirror those
in the webob.exc module.

Each class is named pyramid.httpexceptions.HTTP*, where * is the reason for the error.
For instance, pyramid.httpexceptions.HTTPNotFound subclasses pyramid.response.
Response, so you can manipulate the instances in the same way. A typical example is:

1 from pyramid.httpexceptions import HTTPNotFound


2 from pyramid.httpexceptions import HTTPMovedPermanently
3

4 response = HTTPNotFound('There is no such resource')


5 # or:
6 response = HTTPMovedPermanently(location=new_url)

0.3. Narrative Documentation 495


The Pyramid Web Framework, Version 2.0.2

More Details

More details about the response object API are available in the pyramid.response documentation.
More details about exception responses are in the pyramid.httpexceptions API documentation.
The WebOb documentation is also useful.

0.3.15 Sessions

A session is a namespace which is valid for some period of continual activity that can be used to represent
a user’s interaction with a web application.

This chapter describes how to configure sessions, what session implementations Pyramid provides out of
the box, how to store and retrieve data from sessions, and a session-specific feature: flash messages.

Using the Default Session Factory

In order to use sessions, you must set up a session factory during your Pyramid configuration.

A very basic session factory implementation is provided in the Pyramid core. It uses a cookie to store
session information. This implementation has the following limitations:

• The session information in the cookies used by this implementation is not encrypted, so it can be
viewed by anyone with access to the cookie storage of the user’s browser or anyone with access to
the network along which the cookie travels.

• The maximum number of bytes that are storable in a serialized representation of the session is fewer
than 4000. This is suitable only for very small data sets.

It is digitally signed, however, and thus a client cannot easily tamper with the content without having access
to the secret key.

You can configure this session factory in your Pyramid application by using the pyramid.config.
Configurator.set_session_factory() method.

1 from pyramid.session import SignedCookieSessionFactory


2 my_session_factory = SignedCookieSessionFactory('itsaseekreet')
3

4 from pyramid.config import Configurator


5 config = Configurator()
6 config.set_session_factory(my_session_factory)

496 CONTENTS
The Pyramid Web Framework, Version 2.0.2

By default the SignedCookieSessionFactory() implementation contains the following


security concerns:

• Session data is unencrypted (but it is signed / authenticated).

This means an attacker cannot change the session data, but they can view it. You should not use
it when you keep sensitive information in the session object, as the information can be easily
read by both users of your application and third parties who have access to your users’ network
traffic.

At the very least, use TLS and set secure=True to avoid arbitrary users on the network from
viewing the session contents.

• If you use this sessioning implementation, and you inadvertently create a cross-site scripting
vulnerability in your application, because the session data is stored unencrypted in a cookie, it
will also be easier for evildoers to obtain the current user’s cross-site scripting token.

Set httponly=True to mitigate this vulnerability by hiding the cookie from client-side
JavaScript.

In short, use a different session factory implementation (preferably one which keeps session data on
the server) for anything but the most basic of applications where ”session security doesn’t matter”, you
are sure your application has no cross-site scripting vulnerabilities, and you are confident your secret
key will not be exposed.

Using a Session Object

Once a session factory has been configured for your application, you can access session objects provided
by the session factory via the session attribute of any request object. For example:

1 from pyramid.response import Response


2

3 def myview(request):
4 session = request.session
5 if 'abc' in session:
6 session['fred'] = 'yes'
7 session['abc'] = '123'
8 if 'fred' in session:
(continues on next page)

0.3. Narrative Documentation 497


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


9 return Response('Fred was in the session')
10 else:
11 return Response('Fred was not in the session')

The first time this view is invoked produces Fred was not in the session. Subsequent invo-
cations produce Fred was in the session, assuming of course that the client side maintains the
session’s identity across multiple requests.
You can use a session much like a Python dictionary. It supports all dictionary methods, along with some
extra attributes and methods.
Extra attributes:
created
An integer timestamp indicating the time that this session was created.
new
A boolean. If new is True, this session is new. Otherwise, it has been constituted from data that
was already serialized.
Extra methods:
changed()
Call this when you mutate a mutable value in the session namespace. See the gotchas below for
details on when and why you should call this.
invalidate()
Call this when you want to invalidate the session (dump all data, and perhaps set a clearing cookie).
The formal definition of the methods and attributes supported by the session object are in the pyramid.
interfaces.ISession documentation.
Some gotchas:
• Keys and values of session data must be JSON-serializable. This means, typically, that they are
instances of basic types of objects, such as strings, lists, dictionaries, tuples, integers, etc. If you
place an object in a session data key or value that is not JSON-serializable, an error will be raised
when the session is serialized. Please also see upgrading_session_20.
• If you place a mutable value (for example, a list or a dictionary) in a session object, and you sub-
sequently mutate that value, you must call the changed() method of the session object. In this
case, the session has no way to know that it was modified. However, when you modify a session
object directly, such as setting a value (i.e., __setitem__), or removing a key (e.g., del or pop),
the session will automatically know that it needs to re-serialize its data, thus calling changed() is
unnecessary. There is no harm in calling changed() in either case, so when in doubt, call it after
you’ve changed sessioning data.

498 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Using Alternate Session Factories

The following session factories exist at the time of this writing.

Session Fac- Back- Description


tory end
pyra- Py- Defines an encrypting, pickle-based cookie serializer, using PyNaCl to gen-
mid_nacl_sessionNaCl erate the symmetric encryption for the cookie state.
pyra- Redis Server-side session library for Pyramid, using Redis for storage.
mid_redis_sessions
pyra- Beaker Session factory for Pyramid backed by the Beaker sessioning system.
mid_beaker

Creating Your Own Session Factory

If none of the default or otherwise available sessioning implementations for Pyramid suit you, you may
create your own session object by implementing a session factory. Your session factory should return a ses-
sion. The interfaces for both types are available in pyramid.interfaces.ISessionFactory and
pyramid.interfaces.ISession. You might use the cookie implementation in the pyramid.
session module as inspiration.

Flash Messages

”Flash messages” are simply a queue of message strings stored in the session. To use flash messaging,
you must enable a session factory as described in Using the Default Session Factory or Using Alternate
Session Factories.

Flash messaging has two main uses: to display a status message only once to the user after performing an
internal redirect, and to allow generic code to log messages for single-time display without having direct
access to an HTML template. The user interface consists of a number of methods of the session object.

Using the session.flash Method

To add a message to a flash message queue, use a session object’s flash() method:

0.3. Narrative Documentation 499


The Pyramid Web Framework, Version 2.0.2

request.session.flash('mymessage')

The flash() method appends a message to a flash queue, creating the queue if necessary.

flash() accepts three arguments:

flash(message, queue=”, allow_duplicate=True)

The message argument is required. It represents a message you wish to later display to a user. It is
usually a string but the message you provide is not modified in any way.

The queue argument allows you to choose a queue to which to append the message you provide. This
can be used to push different kinds of messages into flash storage for later display in different places on
a page. You can pass any name for your queue, but it must be a string. Each queue is independent, and
can be popped by pop_flash() or examined via peek_flash() separately. queue defaults to the
empty string. The empty string represents the default flash message queue.

request.session.flash(msg, 'myappsqueue')

The allow_duplicate argument defaults to True. If this is False, and you attempt to add a message
value which is already present in the queue, it will not be added.

Using the session.pop_flash Method

Once one or more messages have been added to a flash queue by the session.flash() API, the
session.pop_flash() API can be used to pop an entire queue and return it for use.

To pop a particular queue of messages from the flash object, use the session object’s pop_flash()
method. This returns a list of the messages that were added to the flash queue, and empties the queue.

pop_flash(queue=”)

>>> request.session.flash('info message')


>>> request.session.pop_flash()
['info message']

Calling session.pop_flash() again like above without a corresponding call to session.


flash() will return an empty list, because the queue has already been popped.

500 CONTENTS
The Pyramid Web Framework, Version 2.0.2

>>> request.session.flash('info message')


>>> request.session.pop_flash()
['info message']
>>> request.session.pop_flash()
[]

Using the session.peek_flash Method

Once one or more messages have been added to a flash queue by the session.flash() API,
the session.peek_flash() API can be used to ”peek” at that queue. Unlike session.
pop_flash(), the queue is not popped from flash storage.

peek_flash(queue=”)

>>> request.session.flash('info message')


>>> request.session.peek_flash()
['info message']
>>> request.session.peek_flash()
['info message']
>>> request.session.pop_flash()
['info message']
>>> request.session.peek_flash()
[]

0.3.16 Using Events

An event is an object broadcast by the Pyramid framework at interesting points during the lifetime of an
application. You don’t need to use events in order to create most Pyramid applications, but they can be
useful when you want to perform slightly advanced operations. For example, subscribing to an event can
allow you to run some code as the result of every new request.

Events in Pyramid are always broadcast by the framework. However, they only become useful when you
register a subscriber. A subscriber is a function that accepts a single argument named event:

1 def mysubscriber(event):
2 print(event)

0.3. Narrative Documentation 501


The Pyramid Web Framework, Version 2.0.2

The above is a subscriber that simply prints the event to the console when it’s called.

The mere existence of a subscriber function, however, is not sufficient to arrange for it to be called. To
arrange for the subscriber to be called, you’ll need to use the pyramid.config.Configurator.
add_subscriber() method or you’ll need to use the pyramid.events.subscriber() deco-
rator to decorate a function found via a scan.

Configuring an Event Listener Imperatively

You can imperatively configure a subscriber function to be called for some event type via the
add_subscriber() method:

1 from pyramid.events import NewRequest


2

3 from subscribers import mysubscriber


4

5 # "config" below is assumed to be an instance of a


6 # pyramid.config.Configurator object
7

8 config.add_subscriber(mysubscriber, NewRequest)

The first argument to add_subscriber() is the subscriber function (or a dotted Python name which
refers to a subscriber callable); the second argument is the event type.

See also:

See also Configurator.

Configuring an Event Listener Using a Decorator

You can configure a subscriber function to be called for some event type via the pyramid.events.
subscriber() function.

1 from pyramid.events import NewRequest


2 from pyramid.events import subscriber
3

4 @subscriber(NewRequest)
5 def mysubscriber(event):
6 event.request.foo = 1

502 CONTENTS
The Pyramid Web Framework, Version 2.0.2

When the subscriber() decorator is used, a scan must be performed against the package containing
the decorated function for the decorator to have any effect.

Either of the above registration examples implies that every time the Pyramid framework emits an event
object that supplies an pyramid.events.NewRequest interface, the mysubscriber function will
be called with an event object.

As you can see, a subscription is made in terms of a class (such as pyramid.events.NewResponse).


The event object sent to a subscriber will always be an object that possesses an interface. For pyramid.
events.NewResponse, that interface is pyramid.interfaces.INewResponse. The interface
documentation provides information about available attributes and methods of the event objects.

The return value of a subscriber function is ignored. Subscribers to the same event type are not guaranteed
to be called in any particular order relative to each other.

All the concrete Pyramid event types are documented in the pyramid.events API documentation.

An Example

If you create event listener functions in a subscribers.py file in your application like so:

1 def handle_new_request(event):
2 print('request', event.request)
3

4 def handle_new_response(event):
5 print('response', event.response)

You may configure these functions to be called at the appropriate times by adding the following code to
your application’s configuration startup:

1 # config is an instance of pyramid.config.Configurator


2

3 config.add_subscriber('myproject.subscribers.handle_new_request',
4 'pyramid.events.NewRequest')
5 config.add_subscriber('myproject.subscribers.handle_new_response',
6 'pyramid.events.NewResponse')

0.3. Narrative Documentation 503


The Pyramid Web Framework, Version 2.0.2

Either mechanism causes the functions in subscribers.py to be registered as event subscribers. Under
this configuration, when the application is run, each time a new request or response is detected, a message
will be printed to the console.

Each of our subscriber functions accepts an event object and prints an attribute of the event object. This
begs the question: how can we know which attributes a particular event has?

We know that pyramid.events.NewRequest event objects have a request attribute, which is a


request object, because the interface defined at pyramid.interfaces.INewRequest says it must.
Likewise, we know that pyramid.interfaces.NewResponse events have a response attribute,
which is a response object constructed by your application, because the interface defined at pyramid.
interfaces.INewResponse says it must (pyramid.events.NewResponse objects also have
a request).

Creating Your Own Events

In addition to using the events that the Pyramid framework creates, you can create your own events for use
in your application. This can be useful to decouple parts of your application.

For example, suppose your application has to do many things when a new document is created. Rather
than putting all this logic in the view that creates the document, you can create the document in your view
and then fire a custom event. Subscribers to the custom event can take other actions, such as indexing the
document, sending email, or sending a message to a remote system.

An event is simply an object. There are no required attributes or method for your custom events. In general,
your events should keep track of the information that subscribers will need. Here are some example custom
event classes:

1 class DocCreated(object):
2 def __init__(self, doc, request):
3 self.doc = doc
4 self.request = request
5

6 class UserEvent(object):
7 def __init__(self, user):
8 self.user = user
9

10 class UserLoggedIn(UserEvent):
11 pass

504 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Some Pyramid applications choose to define custom events classes in an events module.

You can subscribe to custom events in the same way that you subscribe to Pyramid events—either impera-
tively or with a decorator. You can also use custom events with subscriber predicates. Here’s an example
of subscribing to a custom event with a decorator:

1 from pyramid.events import subscriber


2 from .events import DocCreated
3 from .index import index_doc
4

5 @subscriber(DocCreated)
6 def index_doc(event):
7 # index the document using our application's index_doc function
8 index_doc(event.doc, event.request)

The above example assumes that the application defines a DocCreated event class and an index_doc
function.

To fire your custom events use the pyramid.registry.Registry.notify() method, which is


most often accessed as request.registry.notify. For example:

1 from .events import DocCreated


2

3 def new_doc_view(request):
4 doc = MyDoc()
5 event = DocCreated(doc, request)
6 request.registry.notify(event)
7 return {'document': doc}

This example view will notify all subscribers to the custom DocCreated event.

Note that when you fire an event, all subscribers are run synchronously so it’s generally not a good idea to
create event handlers that may take a long time to run. Although event handlers could be used as a central
place to spawn tasks on your own message queues.

0.3.17 Environment Variables and .ini File Settings

Pyramid behavior can be configured through a combination of operating system environment variables and
.ini configuration file application section settings. The meaning of the environment variables and the
configuration file settings overlap.

0.3. Narrative Documentation 505


The Pyramid Web Framework, Version 2.0.2

Where a configuration file setting exists with the same meaning as an environment variable, and both
are present at application startup time, the environment variable setting takes precedence.

The term ”configuration file setting name” refers to a key in the .ini configuration for your application.
The configuration file setting names documented in this chapter are reserved for Pyramid use. You should
not use them to indicate application-specific configuration settings.

Reloading Templates

When this value is true, templates are automatically reloaded whenever they are modified without restarting
the application, so you can see changes to templates take effect immediately during development. This flag
is meaningful to Chameleon and Mako templates, as well as most third-party template rendering extensions.

Environment Variable Name Config File Setting Name


PYRAMID_RELOAD_TEMPLATES
pyramid.reload_templates
or reload_templates

Reloading Assets

Don’t cache any asset file data when this value is true.

See also:

See also Overriding Assets.

Environment Variable Name Config File Setting Name


PYRAMID_RELOAD_ASSETS pyramid.reload_assets or reload_assets

For backwards compatibility purposes, aliases can be used for configuring asset reloading: PYRA-
MID_RELOAD_RESOURCES (envvar) and pyramid.reload_resources (config file).

506 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Debugging Authorization

Print view authorization failure and success information to stderr when this value is true.

See also:

See also Debugging View Authorization Failures.

Environment Variable Name Config File Setting Name


PYRA- pyramid.debug_authorization or de-
MID_DEBUG_AUTHORIZATION bug_authorization

Debugging Not Found Errors

Print view-related NotFound debug messages to stderr when this value is true.

See also:

See also NotFound Errors.

Environment Variable Name Config File Setting Name


PYRAMID_DEBUG_NOTFOUND pyramid.debug_notfound or debug_notfound

Debugging Route Matching

Print debugging messages related to url dispatch route matching when this value is true.

See also:

See also Debugging Route Matching.

Environment Variable Name Config File Setting Name


PYRA- pyramid.debug_routematch or debug_routematch
MID_DEBUG_ROUTEMATCH

0.3. Narrative Documentation 507


The Pyramid Web Framework, Version 2.0.2

Preventing HTTP Caching

Prevent the http_cache view configuration argument from having any effect globally in this pro-
cess when this value is true. No HTTP caching-related response headers will be set by the Pyramid
http_cache view configuration feature when this is true.

See also:

See also Influencing HTTP Caching.

Environment Variable Name Config File Setting Name


PYRA- pyramid.prevent_http_cache or pre-
MID_PREVENT_HTTP_CACHE vent_http_cache

Preventing Cache Busting

Prevent the cachebust static view configuration argument from having any effect globally in this process
when this value is true. No cache buster will be configured or used when this is true.

New in version 1.6.

See also:

See also Cache Busting.

Environment Variable Name Config File Setting Name


PYRA- pyramid.prevent_cachebust or pre-
MID_PREVENT_CACHEBUST vent_cachebust

Debugging All

Turns on all debug* settings.

Environment Variable Name Config File Setting Name


PYRAMID_DEBUG_ALL pyramid.debug_all or debug_all

508 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Reloading All

Turns on all reload* settings.

Environment Variable Name Config File Setting Name


PYRAMID_RELOAD_ALL pyramid.reload_all or reload_all

Default Locale Name

The value supplied here is used as the default locale name when a locale negotiator is not registered.

See also:

See also Localization-Related Deployment Settings.

Environment Variable Name Config File Setting Name


PYRA- pyramid.default_locale_name or de-
MID_DEFAULT_LOCALE_NAME fault_locale_name

Including Packages

pyramid.includes instructs your application to include other packages. Using the setting is equiva-
lent to using the pyramid.config.Configurator.include() method.

Config File Setting Name


pyramid.includes

The value assigned to pyramid.includes should be a sequence. The sequence can take several dif-
ferent forms.

1) It can be a string.

If it is a string, the package names can be separated by spaces:

0.3. Narrative Documentation 509


The Pyramid Web Framework, Version 2.0.2

package1 package2 package3

The package names can also be separated by carriage returns:

package1
package2
package3

2) It can be a Python list, where the values are strings:

['package1', 'package2', 'package3']

Each value in the sequence should be a dotted Python name.

pyramid.includes vs. pyramid.config.Configurator.include()

Two methods exist for including packages: pyramid.includes and pyramid.config.


Configurator.include(). This section explains their equivalence.

Using PasteDeploy

Using the following pyramid.includes setting in the PasteDeploy .ini file in your application:

[app:main]
pyramid.includes = pyramid_debugtoolbar
pyramid_tm

Is equivalent to using the following statements in your configuration code:

1 from pyramid.config import Configurator


2

3 def main(global_config, **settings):


4 config = Configurator(settings=settings)
5 # ...
6 config.include('pyramid_debugtoolbar')
7 config.include('pyramid_tm')
8 # ...

It is fine to use both or either form.

510 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Plain Python

Using the following pyramid.includes setting in your plain-Python Pyramid application:

1 from pyramid.config import Configurator


2

3 if __name__ == '__main__':
4 settings = {'pyramid.includes':'pyramid_debugtoolbar pyramid_tm'}
5 config = Configurator(settings=settings)

Is equivalent to using the following statements in your configuration code:

1 from pyramid.config import Configurator


2

3 if __name__ == '__main__':
4 settings = {}
5 config = Configurator(settings=settings)
6 config.include('pyramid_debugtoolbar')
7 config.include('pyramid_tm')

It is fine to use both or either form.

Explicit Tween Configuration

This value allows you to perform explicit tween ordering in your configuration. Tweens are bits of code
used by add-on authors to extend Pyramid. They form a chain, and require ordering.

Ideally you won’t need to use the pyramid.tweens setting at all. Tweens are generally ordered and
included ”implicitly” when an add-on package which registers a tween is ”included”. Packages are included
when you name a pyramid.includes setting in your configuration or when you call pyramid.
config.Configurator.include().

Authors of included add-ons provide ”implicit” tween configuration ordering hints to Pyramid when their
packages are included. However, the implicit tween ordering is only best-effort. Pyramid will attempt to
provide an implicit order of tweens as best it can using hints provided by add-on authors, but because it’s
only best-effort, if very precise tween ordering is required, the only surefire way to get it is to use an explicit
tween order. You may be required to inspect your tween ordering (see ptweens: Displaying ”Tweens”) and
add a pyramid.tweens configuration value at the behest of an add-on author.

0.3. Narrative Documentation 511


The Pyramid Web Framework, Version 2.0.2

Config File Setting Name


pyramid.tweens

The value assigned to pyramid.tweens should be a sequence. The sequence can take several different
forms.

1) It can be a string.

If it is a string, the tween names can be separated by spaces:

pkg.tween_factory1 pkg.tween_factory2 pkg.tween_factory3

The tween names can also be separated by carriage returns:

pkg.tween_factory1
pkg.tween_factory2
pkg.tween_factory3

2) It can be a Python list, where the values are strings:

['pkg.tween_factory1', 'pkg.tween_factory2', 'pkg.tween_factory3']

Each value in the sequence should be a dotted Python name.

PasteDeploy Configuration vs. Plain-Python Configuration

Using the following pyramid.tweens setting in the PasteDeploy .ini file in your application:

[app:main]
pyramid.tweens = pyramid_debugtoolbar.toolbar.tween_factory
pyramid.tweens.excview_tween_factory
pyramid_tm.tm_tween_factory

Is equivalent to using the following statements in your configuration code:

512 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.config import Configurator


2

3 def main(global_config, **settings):


4 settings['pyramid.tweens'] = [
5 'pyramid_debugtoolbar.toolbar.tween_factory',
6 'pyramid.tweebs.excview_tween_factory',
7 'pyramid_tm.tm_tween_factory',
8 ]
9 config = Configurator(settings=settings)

It is fine to use both or either form.

Examples

Let’s presume your configuration file is named MyProject.ini, and there is a section representing
your application named [app:main] within the file that represents your Pyramid application. The
configuration file settings documented in the above ”Config File Setting Name” column would go in the
[app:main] section. Here’s an example of such a section:

1 [app:main]
2 use = egg:MyProject
3 pyramid.reload_templates = true
4 pyramid.debug_authorization = true

You can also use environment variables to accomplish the same purpose for settings documented as such.
For example, you might start your Pyramid application using the following command line:

PYRAMID_DEBUG_AUTHORIZATION=1 PYRAMID_RELOAD_TEMPLATES=1 \
$VENV/bin/pserve MyProject.ini

If you started your application this way, your Pyramid application would behave in the same manner as if
you had placed the respective settings in the [app:main] section of your application’s .ini file.

If you want to turn all debug settings (every setting that starts with pyramid.debug_) on in one
fell swoop, you can use PYRAMID_DEBUG_ALL=1 as an environment variable setting or you may use
pyramid.debug_all=true in the config file. Note that this does not affect settings that do not start
with pyramid.debug_* such as pyramid.reload_templates.

If you want to turn all pyramid.reload settings (every setting that starts with pyramid.reload_)
on in one fell swoop, you can use PYRAMID_RELOAD_ALL=1 as an environment variable setting or you

0.3. Narrative Documentation 513


The Pyramid Web Framework, Version 2.0.2

may use pyramid.reload_all=true in the config file. Note that this does not affect settings that do
not start with pyramid.reload_* such as pyramid.debug_notfound.

Specifying configuration settings via environment variables is generally most useful during devel-
opment, where you may wish to augment or override the more permanent settings in the configuration
file. This is useful because many of the reload and debug settings may have performance or security (i.e.,
disclosure) implications that make them undesirable in a production environment.

Understanding the Distinction Between reload_templates and reload_assets

The difference between pyramid.reload_assets and pyramid.reload_templates is a bit


subtle. Templates are themselves also treated by Pyramid as asset files (along with other static files), so
the distinction can be confusing. It’s helpful to read Overriding Assets for some context about assets in
general.

When pyramid.reload_templates is true, Pyramid takes advantage of the underlying templat-


ing system’s ability to check for file modifications to an individual template file. When pyramid.
reload_templates is true, but pyramid.reload_assets is not true, the template filename re-
turned by the pkg_resources package (used under the hood by asset resolution) is cached by Pyramid
on the first request. Subsequent requests for the same template file will return a cached template filename.
The underlying templating system checks for modifications to this particular file for every request. Setting
pyramid.reload_templates to True doesn’t affect performance dramatically (although it should
still not be used in production because it has some effect).

However, when pyramid.reload_assets is true, Pyramid will not cache the template filename,
meaning you can see the effect of changing the content of an overridden asset directory for templates
without restarting the server after every change. Subsequent requests for the same template file may re-
turn different filenames based on the current state of overridden asset directories. Setting pyramid.
reload_assets to True affects performance dramatically, slowing things down by an order of mag-
nitude for each template rendering. However, it’s convenient to enable when moving files around in over-
ridden asset directories. pyramid.reload_assets makes the system very slow when templates are
in use. Never set pyramid.reload_assets to True on a production system.

Adding a Custom Setting

From time to time, you may need to add a custom setting to your application. Here’s how:

• If you’re using an .ini file, change the .ini file, adding the setting to the [app:foo] section
representing your Pyramid application. For example:

514 CONTENTS
The Pyramid Web Framework, Version 2.0.2

[app:main]
# .. other settings
debug_frobnosticator = True

• In the main() function that represents the place that your Pyramid WSGI application is created,
anticipate that you’ll be getting this key/value pair as a setting and do any type conversion necessary.

If you’ve done any type conversion of your custom value, reset the converted values into the set-
tings dictionary before you pass the dictionary as settings to the Configurator. For example:

def main(global_config, **settings):


# ...
from pyramid.settings import asbool
debug_frobnosticator = asbool(settings.get(
'debug_frobnosticator', 'false'))
settings['debug_frobnosticator'] = debug_frobnosticator
config = Configurator(settings=settings)

It’s especially important that you mutate the settings dictionary with the converted version
of the variable before passing it to the Configurator: the configurator makes a copy of settings,
it doesn’t use the one you pass directly.

• When creating an includeme function that will be later added to your application’s configuration
you may access the settings dictionary through the instance of the Configurator that is passed
into the function as its only argument. For Example:

def includeme(config):
settings = config.registry.settings
debug_frobnosticator = settings['debug_frobnosticator']

• In the runtime code from where you need to access the new settings value, find the value in the
registry.settings dictionary and use it. In view code (or any other code that has access to
the request), the easiest way to do this is via request.registry.settings. For example:

settings = request.registry.settings
debug_frobnosticator = settings['debug_frobnosticator']

If you wish to use the value in code that does not have access to the request and you wish to use the
value, you’ll need to use the pyramid.threadlocal.get_current_registry() API to
obtain the current registry, then ask for its settings attribute. For example:

0.3. Narrative Documentation 515


The Pyramid Web Framework, Version 2.0.2

registry = pyramid.threadlocal.get_current_registry()
settings = registry.settings
debug_frobnosticator = settings['debug_frobnosticator']

0.3.18 Logging

Pyramid allows you to make use of the Python standard library logging module. This chapter describes
how to configure logging and how to send log messages to loggers that you’ve configured.

This chapter assumes you’ve used our cookiecutter to create a project which contains
development.ini and production.ini files which help configure logging. The Pyramid
cookiecutter provided by the Pylons Project does this. If you’re not using our cookiecutter, or if you’ve
used a third-party cookiecutter which does not create these files, the configuration information in this
chapter may not be applicable.

Logging Configuration

A Pyramid project created from our cookiecutter is configured to allow you to send messages to Python
standard library logging package loggers from within your application. In particular, the
PasteDeploy development.ini and production.ini files created when you use our cookiecutter
include a basic configuration for the Python logging package. These .ini file sections are passed to
the logging module’s config file configuration engine.

PasteDeploy .ini files use the Python standard library ConfigParser format. This is the same
format used as the Python logging module’s Configuration file format. The application-related and logging-
related sections in the configuration file can coexist peacefully. The logging-related sections in the file
configure logging when you run pserve.

If the configuration .ini file, specified when invoking pserve, contains a [loggers] section then on
startup the following process takes place:

1. The pserve command calls the pyramid.paster.setup_logging() function, passing the


.ini file.

2. setup_logging is a thin wrapper which calls the Python standard library’s logging.
config.fileConfig().

516 CONTENTS
The Pyramid Web Framework, Version 2.0.2

3. logging.config.fileConfig() reads the logging configuration from the .ini file and
configures logging.

Default logging configuration is provided in both the default development.ini and the
production.ini files. If you use our cookiecutter to generate a Pyramid project with the name of
the package as hello_world, then the logging configuration in the development.ini file is as
follows:

29 ###
30 # logging configuration
31 # https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.
,→html

32 ###
33

34 [loggers]
35 keys = root, myproject
36

37 [handlers]
38 keys = console
39

40 [formatters]
41 keys = generic
42

43 [logger_root]
44 level = INFO
45 handlers = console
46

47 [logger_myproject]
48 level = DEBUG
49 handlers =
50 qualname = myproject
51

52 [handler_console]
53 class = StreamHandler
54 args = (sys.stderr,)
55 level = NOTSET
56 formatter = generic
57

58 [formatter_generic]
59 format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][
,→%(threadName)s] %(message)s

The production.ini file uses the WARN level in its logger configuration instead of DEBUG, but it is
otherwise identical.

In this logging configuration:

0.3. Narrative Documentation 517


The Pyramid Web Framework, Version 2.0.2

• a logger named root is created that logs messages at a level above or equal to the INFO level to
stderr, with the following format:

2007-08-17 15:04:08,704 INFO [packagename] Loading resource, id: 86

• a logger named myproject is configured that logs messages sent at a level above or equal to DEBUG
to stderr in the same format as the root logger.

The root logger will be used by all applications in the Pyramid process that ask for a logger (via
logging.getLogger) that has a name which begins with anything except your project’s package name
(e.g., myproject). The logger with the same name as your package name is reserved for your own usage
in your Pyramid application. Its existence means that you can log to a known logging location from any
Pyramid application generated via our cookiecutter.

Pyramid and many other libraries (such as Beaker, SQLAlchemy, Paste) log a number of messages to the
root logger for debugging purposes. Switching the root logger level to DEBUG reveals them:

[logger_root]
#level = INFO
level = DEBUG
handlers = console

Some configurations of the Pyramid cookiecutter configure additional loggers for additional subsystems
they use (such as SQLAlchemy). Take a look at the production.ini and development.ini files
rendered when you create a project from our cookiecutter.

Sending Logging Messages

Python’s special __name__ variable refers to the current module’s fully qualified name. From any module
in a package named myproject, the __name__ builtin variable will always be something like mypro-
ject, or myproject.subpackage or myproject.package.subpackage if your project is
named myproject. Sending a message to this logger will send it to the myproject logger.

To log messages to the package-specific logger configured in your .ini file, simply create a logger object
using the __name__ builtin and call methods on it.

518 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 import logging
2 log = logging.getLogger(__name__)
3

4 def myview(request):
5 content_type = 'text/plain'
6 content = 'Hello World!'
7 log.debug('Returning: %s (content-type: %s)', content, content_type)
8 request.response.content_type = content_type
9 return request.response

This will result in the following printed to the console, on stderr:

16:20:20,440 DEBUG [myproject.views] Returning: Hello World!


(content-type: text/plain)

Filtering log messages

Often there’s too much log output to sift through, such as when switching the root logger’s level to DEBUG.

For example, you’re diagnosing database connection issues in your application and only want to see
SQLAlchemy’s DEBUG messages in relation to database connection pooling. You can leave the root log-
ger’s level at the less verbose INFO level and set that particular SQLAlchemy logger to DEBUG on its own,
apart from the root logger:

[logger_sqlalchemy.pool]
level = DEBUG
handlers =
qualname = sqlalchemy.pool

then add it to the list of loggers:

[loggers]
keys = root, myproject, sqlalchemy.pool

No handlers need to be configured for this logger as by default non-root loggers will propagate their log
records up to their parent logger’s handlers. The root logger is the top level parent of all loggers.

This technique is used in the default development.ini. The root logger’s level is set to INFO, whereas
the application’s log level is set to DEBUG:

0.3. Narrative Documentation 519


The Pyramid Web Framework, Version 2.0.2

# Begin logging configuration

[loggers]
keys = root, myproject

[logger_myproject]
level = DEBUG
handlers =
qualname = myproject

All of the child loggers of the myproject logger will inherit the DEBUG level unless they’re explicitly
set differently. Meaning the myproject.views, myproject.models, and all your app’s modules’
loggers by default have an effective level of DEBUG too.

For more advanced filtering, the logging module provides a logging.Filter object; however it cannot
be used directly from the configuration file.

Advanced Configuration

To capture log output to a separate file, use logging.FileHandler (or logging.handlers.


RotatingFileHandler):

[handler_filelog]
class = FileHandler
args = ('%(here)s/myproject.log','a')
level = INFO
formatter = generic

Before it’s recognized, it needs to be added to the list of handlers:

[handlers]
keys = console, myproject, filelog

and finally utilized by a logger.

[logger_root]
level = INFO
handlers = console, filelog

These final three lines of configuration direct all of the root logger’s output to the myproject.log as
well as the console.

520 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Logging Exceptions

To log or email exceptions generated by your Pyramid application, use the pyramid_exclog package. De-
tails about its configuration are in its documentation.

Request Logging with Paste’s TransLogger

The WSGI design is modular. Waitress logs error conditions, debugging output, etc., but not web traffic.
For web traffic logging, Paste provides the TransLogger middleware. TransLogger produces logs in the
Apache Combined Log Format. But TransLogger does not write to files; the Python logging system must
be configured to do this. The Python logging.FileHandler logging handler can be used alongside
TransLogger to create an access.log file similar to Apache’s.

Like any standard middleware with a Paste entry point, TransLogger can be configured to wrap
your application using .ini file syntax. First rename your Pyramid .ini file’s [app:main]
section to [app:mypyramidapp], then add a [filter:translogger] section, then use a
[pipeline:main] section file to form a WSGI pipeline with both the translogger and your application
in it. For instance, change from this:

[app:main]
use = egg:myproject

To this:

[app:mypyramidapp]
use = egg:myproject

[filter:translogger]
use = egg:Paste#translogger
setup_console_handler = False

[pipeline:main]
pipeline = translogger
mypyramidapp

Using PasteDeploy this way to form and serve a pipeline is equivalent to wrapping your app in a TransLog-
ger instance via the bottom of the main function of your project’s __init__ file:

0.3. Narrative Documentation 521


The Pyramid Web Framework, Version 2.0.2

# ...
app = config.make_wsgi_app()
from paste.translogger import TransLogger
app = TransLogger(app, setup_console_handler=False)
return app

TransLogger will automatically setup a logging handler to the console when called with no arguments,
so it ”just works” in environments that don’t configure logging. Since our logging handlers are configured,
we disable the automation via setup_console_handler = False.

With the filter in place, TransLogger’s logger (named the wsgi logger) will propagate its log messages to
the parent logger (the root logger), sending its output to the console when we request a page:

00:50:53,694 INFO [myproject.views] Returning: Hello World!


(content-type: text/plain)
00:50:53,695 INFO [wsgi] 192.168.1.111 - - [11/Aug/2011:20:09:33 -0700]
,→"GET /hello

HTTP/1.1" 404 - "-"


"Mozilla/5.0 (Macintosh; U; Intel macOS; en-US; rv:1.8.1.6) Gecko/20070725
Firefox/2.0.0.6"

To direct TransLogger to an access.log FileHandler, we need the following to add a FileHandler


(named accesslog) to the list of handlers, and ensure that the wsgi logger is configured and uses
this handler accordingly:

# Begin logging configuration

[loggers]
keys = root, myproject, wsgi

[handlers]
keys = console, accesslog

[logger_wsgi]
level = INFO
handlers = accesslog
qualname = wsgi
propagate = 0

[handler_accesslog]
(continues on next page)

522 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


class = FileHandler
args = ('%(here)s/access.log','a')
level = INFO
formatter = generic

As mentioned above, non-root loggers by default propagate their log records to the root logger’s handlers
(currently the console handler). Setting propagate to 0 (False) here disables this; so the wsgi logger
directs its records only to the accesslog handler.
Finally, there’s no need to use the generic formatter with TransLogger as TransLogger itself provides
all the information we need. We’ll use a formatter that passes through the log messages as is. Add a new
formatter called accesslog by including the following in your configuration file:

[formatters]
keys = generic, accesslog

[formatter_accesslog]
format = %(message)s

Finally alter the existing configuration to wire this new accesslog formatter into the FileHandler:

[handler_accesslog]
class = FileHandler
args = ('%(here)s/access.log','a')
level = INFO
formatter = accesslog

0.3.19 PasteDeploy Configuration Files

Packages generated via a cookiecutter make use of a system created by Ian Bicking named PasteDeploy.
PasteDeploy defines a way to declare WSGI application configuration in an .ini file.
Pyramid uses this configuration file format as input to its WSGI server runner pserve, as well as other
commands such as pviews, pshell, proutes, and ptweens.
PasteDeploy is not a particularly integral part of Pyramid. It’s possible to create a Pyramid application
which does not use PasteDeploy at all. We show a Pyramid application that doesn’t use PasteDeploy
in Creating Your First Pyramid Application. However, the Pyramid cookiecutter renders PasteDeploy
configuration files, to provide new developers with a standardized way of setting deployment values, and
to provide new users with a standardized way of starting, stopping, and debugging an application.
This chapter is not a replacement for documentation about PasteDeploy; it only contextualizes the use
of PasteDeploy within Pyramid. For detailed documentation, see https://docs.pylonsproject.org/projects/
pastedeploy/en/latest/.

0.3. Narrative Documentation 523


The Pyramid Web Framework, Version 2.0.2

PasteDeploy

plaster is the system that Pyramid uses to load settings from configuration files. The most common for-
mat for these files is an .ini format structured in a way defined by PasteDeploy. The format supports
mechanisms to define WSGI app deployment settings, WSGI server settings and logging. This allows the
pserve command to work, allowing you to stop and start a Pyramid application easily.

Entry Points and PasteDeploy .ini Files

In the Creating a Pyramid Project chapter, we breezed over the meaning of a configuration line in the
deployment.ini file. This was the use = egg:myproject line in the [app:main] section.
We breezed over it because it’s pretty confusing and ”too much information” for an introduction to the
system. We’ll try to give it a bit of attention here. Let’s see the config file again:

1 ###
2 # app configuration
3 # https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/
,→environment.html

4 ###
5

6 [app:main]
7 use = egg:myproject
8

9 pyramid.reload_templates = true
10 pyramid.debug_authorization = false
11 pyramid.debug_notfound = false
12 pyramid.debug_routematch = false
13 pyramid.default_locale_name = en
14 pyramid.includes =
15 pyramid_debugtoolbar
16

17 # By default, the toolbar only appears for clients from IP addresses


18 # '127.0.0.1' and '::1'.
19 # debugtoolbar.hosts = 127.0.0.1 ::1
20

21 ###
22 # wsgi server configuration
23 ###
24

25 [server:main]
26 use = egg:waitress#main
27 listen = localhost:6543
(continues on next page)

524 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


28

29 ###
30 # logging configuration
31 # https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.
,→html

32 ###
33

34 [loggers]
35 keys = root, myproject
36

37 [handlers]
38 keys = console
39

40 [formatters]
41 keys = generic
42

43 [logger_root]
44 level = INFO
45 handlers = console
46

47 [logger_myproject]
48 level = DEBUG
49 handlers =
50 qualname = myproject
51

52 [handler_console]
53 class = StreamHandler
54 args = (sys.stderr,)
55 level = NOTSET
56 formatter = generic
57

58 [formatter_generic]
59 format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][
,→%(threadName)s] %(message)s

The line in [app:main] above that says use = egg:myproject is actually shorthand for a longer
spelling: use = egg:myproject#main. The #main part is omitted for brevity, as #main is a
default defined by PasteDeploy. egg:myproject#main is a string which has meaning to PasteDeploy.
It points at a Setuptools entry point named main defined in the myproject project.

Take a look at the generated setup.py file for this project.

1 import os
2

(continues on next page)

0.3. Narrative Documentation 525


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


3 from setuptools import setup, find_packages
4

5 here = os.path.abspath(os.path.dirname(__file__))
6 with open(os.path.join(here, 'README.txt')) as f:
7 README = f.read()
8 with open(os.path.join(here, 'CHANGES.txt')) as f:
9 CHANGES = f.read()
10

11 requires = [
12 'plaster_pastedeploy',
13 'pyramid',
14 'pyramid_jinja2',
15 'pyramid_debugtoolbar',
16 'waitress',
17 ]
18

19 tests_require = [
20 'WebTest',
21 'pytest',
22 'pytest-cov',
23 ]
24

25 setup(
26 name='myproject',
27 version='0.0',
28 description='myproject',
29 long_description=README + '\n\n' + CHANGES,
30 classifiers=[
31 'Programming Language :: Python',
32 'Framework :: Pyramid',
33 'Topic :: Internet :: WWW/HTTP',
34 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
35 ],
36 author='',
37 author_email='',
38 url='',
39 keywords='web pyramid pylons',
40 packages=find_packages(exclude=['tests']),
41 include_package_data=True,
42 zip_safe=False,
43 extras_require={
44 'testing': tests_require,
45 },
46 install_requires=requires,
47 entry_points={
(continues on next page)

526 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


48 'paste.app_factory': [
49 'main = myproject:main',
50 ],
51 },
52 )

Note that entry_points is assigned a string which looks a lot like an .ini file. This string represen-
tation of an .ini file has a section named [paste.app_factory]. Within this section, there is a key
named main (the entry point name) which has a value myproject:main. The key main is what our
egg:myproject#main value of the use section in our config file is pointing at, although it is actually
shortened to egg:myproject there. The value represents a dotted Python name path, which refers to a
callable in our myproject package’s __init__.py module.

The egg: prefix in egg:myproject indicates that this is an entry point URI specifier, where the
”scheme” is ”egg”. An ”egg” is created when you install your project.

In English, this entry point can thus be referred to as a ”PasteDeploy application factory in the mypro-
ject project which has the entry point named main where the entry point refers to a main function
in the mypackage module”. Indeed, if you open up the __init__.py module generated within the
cookiecutter-generated package, you’ll see a main function. This is the function called by PasteDeploy
when the pserve command is invoked against our application. It accepts a global configuration object
and returns an instance of our application.

[DEFAULT] Section of a PasteDeploy .ini File

You can add a [DEFAULT] section to your PasteDeploy .ini file. Such a section should consist of
global parameters that are shared by all the applications, servers, and middleware defined within the con-
figuration file. The values in a [DEFAULT] section will be passed to your application’s main function
as global_config (see the reference to the main function in __init__.py).

Alternative Configuration File Formats

It is possible to use different file formats with Pyramid if you do not like PasteDeploy. Under the hood all
command-line scripts such as pserve and pshell pass the config_uri (e.g., development.ini
or production.ini) to the plaster library which performs a lookup for an appropriate parser. For .
ini files it uses PasteDeploy but you can register your own configuration formats that plaster will find
instead.

0.3. Narrative Documentation 527


The Pyramid Web Framework, Version 2.0.2

0.3.20 Command-Line Pyramid

Your Pyramid application can be controlled and inspected using a variety of command-line utilities. These
utilities are documented in this chapter.

We commonly refer to this collection of utilities as ”p-scripts”, which is short for ”Pyramid console
scripts”.

Each p-script’s command line usage details is available in the p* Scripts Documentation.

Running p-scripts

All of the Pyramid console scripts may be run either:

• by its name

• as a Python module

Running by p* script name

Each of Pyramid’s console scripts may be run by its name. For example:

$VENV/bin/pserve development.ini --reload

$VENV/bin/ is a convention we use to simplify Pyramid documentation. It represents the bin


directory in a virtual environment, where $VENV is an environment variable representing its path. See
Installing Pyramid on a Unix System and Why use $VENV/bin/pip instead of source bin/activate, then pip
for more information.

Using Custom Arguments to Python when Running p* Scripts

New in version 1.5.

Each of Pyramid’s console scripts (pserve, pviews, etc.) can be run using python3 -m, allowing
custom arguments to be sent to the Python interpreter at runtime. For example:

528 CONTENTS
The Pyramid Web Framework, Version 2.0.2

python3 -m pyramid.scripts.pserve development.ini --reload

pviews: Displaying Matching Views for a Given URL

See also:

See also the output of pviews --help.

For a big application with several views, it can be hard to keep the view configuration details in your head,
even if you defined all the views yourself. You can use the pviews command in a terminal window
to print a summary of matching routes and views for a given URL in your application. The pviews
command accepts two arguments. The first argument to pviews is the path to your application’s .ini
file and section name inside the .ini file which points to your application. This should be of the format
config_file#section_name. The second argument is the URL to test for matching views. The
section_name may be omitted; if it is, it’s considered to be main.

Here is an example for a simple view configuration using traversal:

1 $VENV/bin/pviews development.ini#tutorial /FrontPage


2

3 URL = /FrontPage
4

5 context: <tutorial.models.Page object at 0xa12536c>


6 view name:
7

8 View:
9 -----
10 tutorial.views.view_page
11 required permission = view

The output always has the requested URL at the top and below that all the views that matched with their
view configuration details. In this example only one view matches, so there is just a single View section. For
each matching view, the full code path to the associated view callable is shown, along with any permissions
and predicates that are part of that view configuration.

A more complex configuration might generate something like this:

0.3. Narrative Documentation 529


The Pyramid Web Framework, Version 2.0.2

1 $VENV/bin/pviews development.ini#shootout /about


2

3 URL = /about
4

5 context: <shootout.models.RootFactory object at 0xa56668c>


6 view name: about
7

8 Route:
9 ------
10 route name: about
11 route pattern: /about
12 route path: /about
13 subpath:
14 route predicates (request method = GET)
15

16 View:
17 -----
18 shootout.views.about_view
19 required permission = view
20 view predicates (request_param testing, header X/header)
21

22 Route:
23 ------
24 route name: about_post
25 route pattern: /about
26 route path: /about
27 subpath:
28 route predicates (request method = POST)
29

30 View:
31 -----
32 shootout.views.about_view_post
33 required permission = view
34 view predicates (request_param test)
35

36 View:
37 -----
38 shootout.views.about_view_post2
39 required permission = view
40 view predicates (request_param test2)

In this case, we are dealing with a URL dispatch application. This specific URL has two matching routes.
The matching route information is displayed first, followed by any views that are associated with that route.
As you can see from the second matching route output, a route can be associated with more than one view.

For a URL that doesn’t match any views, pviews will simply print out a Not found message.

530 CONTENTS
The Pyramid Web Framework, Version 2.0.2

pshell: The Interactive Shell

See also:

See also the output of pshell --help.

Once you’ve installed your program for development using pip install -e ., you can use an
interactive Python shell to execute expressions in a Python environment exactly like the one that will be
used when your application runs ”for real”. To do so, use the pshell command line utility.

The argument to pshell follows the format config_file#section_name where config_file


is the path to your application’s .ini file and section_name is the app section name inside the
.ini file which points to your application. For example, your application .ini file might have an
[app:main] section that looks like so:

1 [app:main]
2 use = egg:MyProject
3 pyramid.reload_templates = true
4 pyramid.debug_authorization = false
5 pyramid.debug_notfound = false
6 pyramid.debug_templates = true
7 pyramid.default_locale_name = en

If so, you can use the following command to invoke a debug shell using the name main as a section name:

$VENV/bin/pshell starter/development.ini#main
Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32)
[GCC 4.4.3] on linux2
Type "help" for more information.

Environment:
app The WSGI application.
registry Active Pyramid registry.
request Active request object.
root Root of the default resource tree.
root_factory Default root factory used to create `root`.

>>> root
<myproject.resources.MyResource object at 0x445270>
>>> registry
<Registry myproject>
>>> registry.settings['pyramid.debug_notfound']
False
(continues on next page)

0.3. Narrative Documentation 531


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


>>> from myproject.views import my_view
>>> from pyramid.request import Request
>>> r = Request.blank('/')
>>> my_view(r)
{'project': 'myproject'}

The WSGI application that is loaded will be available in the shell as the app global. Also, if the application
that is loaded is the Pyramid app with no surrounding middleware, the root object returned by the default
root factory, registry, and request will be available.

You can also simply rely on the main default section name by omitting any hash after the filename:

$VENV/bin/pshell starter/development.ini

Press Ctrl-D to exit the interactive shell (or Ctrl-Z on Windows).

Extending the Shell

It is convenient when using the interactive shell often to have some variables significant to your application
already loaded as globals when you start the pshell. To facilitate this, pshell will look for a special
[pshell] section in your .ini file and expose the subsequent key/value pairs to the shell. Each key
is a variable name that will be global within the pshell session; each value is a dotted Python name. If
specified, the special key setup should be a dotted Python name pointing to a callable that accepts the
dictionary of globals that will be loaded into the shell. This allows for some custom initializing code to be
executed each time the pshell is run. The setup callable can also be specified from the commandline
using the --setup option which will override the key in the .ini file.

For example, you want to expose your model to the shell along with the database session so that you
can mutate the model on an actual database. Here, we’ll assume your model is stored in the myapp.
models package and that you’re using pyramid_tm to configure a transaction manager on the request
as request.tm.

1 [pshell]
2 setup = myapp.lib.pshell.setup
3 models = myapp.models

By defining the setup callable, we will create the module myapp.lib.pshell containing a callable
named setup that will receive the global environment before it is exposed to the shell. Here we mutate
the environment’s request as well as add a new value containing a WebTest version of the application to
which we can easily submit requests. The setup callable can also be a generator which can wrap the
entire shell lifecycle, executing code when the shell exits.

532 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 # myapp/lib/pshell.py
2 from contextlib import suppress
3 from transaction.interfaces import NoTransaction
4 from webtest import TestApp
5

6 def setup(env):
7 request = env['request']
8 request.host = 'www.example.com'
9 request.scheme = 'https'
10

11 env['testapp'] = TestApp(env['app'])
12

13 # start a transaction which can be used in the shell


14 request.tm.begin()
15

16 # if using the SQLAlchemy backend from our cookiecutter, the dbsession␣


,→ is
17 # connected to the transaction manager above
18 env['tm'] = request.tm
19 env['dbsession'] = request.dbsession
20 try:
21 yield
22

23 finally:
24 with suppress(NoTransaction):
25 request.tm.abort()

When this .ini file is loaded, the extra variable models will be available for use immediately. Since a
setup callable was also specified, it is executed and new variables testapp, tm, and dbsession are
exposed, and the request is configured to generate URLs from the host http://www.example.com.
For example:

$VENV/bin/pshell starter/development.ini
Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32)
[GCC 4.4.3] on linux2
Type "help" for more information.

Environment:
app The WSGI application.
registry Active Pyramid registry.
request Active request object.
root Root of the default resource tree.
root_factory Default root factory used to create `root`.
testapp <webtest.TestApp object at ...>
(continues on next page)

0.3. Narrative Documentation 533


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)

Custom Variables:
dbsession
model myapp.models
tm

>>> testapp.get('/')
<200 OK text/html body='<!DOCTYPE...l>\n'/3337>
>>> request.route_url('home')
'https://www.example.com/'
>>> user = dbsession.query(models.User).get(1)
>>> user.name = 'Joe'
>>> tm.commit()
>>> tm.begin()
>>> user = dbsession.query(models.User).get(1)
>>> user.name == 'Joe'
'Joe'

Alternative Shells

The pshell command can be easily extended with alternate REPLs if the default python REPL is
not satisfactory. Assuming you have a binding installed such as pyramid_ipython it will normally
be auto-selected and used. You may also specifically invoke your choice with the -p choice or
--python-shell choice option.

$VENV/bin/pshell -p ipython development.ini#MyProject

You may use the --list-shells option to see the available shells.

$VENV/bin/pshell --list-shells
Available shells:
bpython
ipython
python

If you want to use a shell that isn’t supported out of the box, you can introduce a new shell by registering
an entry point in your setup.py:

534 CONTENTS
The Pyramid Web Framework, Version 2.0.2

setup(
entry_points={
'pyramid.pshell_runner': [
'myshell=my_app:ptpython_shell_factory',
],
},
)

And then your shell factory should return a function that accepts two arguments, env and help, which
would look like this:

from ptpython.repl import embed

def ptpython_shell_runner(env, help):


print(help)
return embed(locals=env)

Changed in version 1.6: User-defined shells may be registered using entry points. Prior to this the only
supported shells were ipython, bpython and python.

ipython and bpython have been moved into their respective packages pyramid_ipython and
pyramid_bpython.

Setting a Default Shell

You may use the default_shell option in your [pshell] ini section to specify a list of preferred
shells.

1 [pshell]
2 default_shell = ptpython ipython bpython

New in version 1.6.

0.3. Narrative Documentation 535


The Pyramid Web Framework, Version 2.0.2

proutes: Displaying All Application Routes

See also:

See also the output of proutes --help.

You can use the proutes command in a terminal window to print a summary of routes related to your
application. Much like the pshell command (see pshell: The Interactive Shell), the proutes command
accepts one argument with the format config_file#section_name. The config_file is the
path to your application’s .ini file, and section_name is the app section name inside the .ini file
which points to your application. By default, the section_name is main and can be omitted.

For example:

1 $VENV/bin/proutes development.ini
2 Name Pattern View ␣
,→ Method
3 ---- ------- ---- ␣
,→ ------
4 debugtoolbar /_debug_toolbar/*subpath <wsgiapp> ␣
,→ *
5 __static/ /static/*subpath dummy_
,→starter:static/ *
6 __static2/ /static2/*subpath /var/www/static/ ␣
,→ *
7 __pdt_images/ /pdt_images/*subpath pyramid_
,→debugtoolbar:static/img/ *
8 a / <unknown> ␣
,→ *
9 no_view_attached / <unknown> ␣
,→ *
10 route_and_view_attached / app1.standard_views.
,→route_and_view_attached *
11 method_conflicts /conflicts app1.standard_
,→conflicts <route mismatch>
12 multiview /multiview app1.standard_views.
,→multiview GET,PATCH
13 not_post /not_post app1.standard_views.
,→multiview !POST,*

proutes generates a table with four columns: Name, Pattern, View, and Method. The items listed in the
Name column are route names, the items listed in the Pattern column are route patterns, the items listed
in the View column are representations of the view callable that will be invoked when a request matches
the associated route pattern, and the items listed in the Method column are the request methods that are

536 CONTENTS
The Pyramid Web Framework, Version 2.0.2

associated with the route name. The View column may show <unknown> if no associated view callable
could be found. The Method column, for the route name, may show either <route mismatch> if the
view callable does not accept any of the route’s request methods, or * if the view callable will accept any
of the route’s request methods. If no routes are configured within your application, nothing will be printed
to the console when proutes is executed.

It is convenient when using the proutes command often to configure which columns and the order you
would like to view them. To facilitate this, proutes will look for a special [proutes] section in your
.ini file and use those as defaults.

For example you may remove the request method and place the view first:

1 [proutes]
2 format = view
3 name
4 pattern

You can also separate the formats with commas or spaces:

1 [proutes]
2 format = view name pattern
3

4 [proutes]
5 format = view, name, pattern

If you want to temporarily configure the columns and order, there is the argument --format, which is a
comma separated list of columns you want to include. The current available formats are name, pattern,
view, and method.

ptweens: Displaying ”Tweens”

See also:

See also the output of ptweens --help.

A tween is a bit of code that sits between the main Pyramid application request handler and the WSGI
application which calls it. A user can get a representation of both the implicit tween ordering (the ordering
specified by calls to pyramid.config.Configurator.add_tween()) and the explicit tween or-
dering (specified by the pyramid.tweens configuration setting) using the ptweens command. Tween
factories will show up represented by their standard Python dotted name in the ptweens output.

For example, here’s the ptweens command run against a system configured without any explicit tweens:

0.3. Narrative Documentation 537


The Pyramid Web Framework, Version 2.0.2

1 $VENV/bin/ptweens development.ini
2 "pyramid.tweens" config value NOT set (implicitly ordered tweens used)
3

4 Implicit Tween Chain


5

6 Position Name Alias


7 -------- ---- -----
8 - - INGRESS
9 0 pyramid_debugtoolbar.toolbar.toolbar_tween_factory pdbt
10 1 pyramid.tweens.excview_tween_factory excview
11 - - MAIN

Here’s the ptweens command run against a system configured with explicit tweens defined in its
development.ini file:

1 $VENV/bin/ptweens development.ini
2 "pyramid.tweens" config value set (explicitly ordered tweens used)
3

4 Explicit Tween Chain (used)


5

6 Position Name
7 -------- ----
8 - INGRESS
9 0 starter.tween_factory2
10 1 starter.tween_factory1
11 2 pyramid.tweens.excview_tween_factory
12 - MAIN
13

14 Implicit Tween Chain (not used)


15

16 Position Name
17 -------- ----
18 - INGRESS
19 0 pyramid_debugtoolbar.toolbar.toolbar_tween_factory
20 1 pyramid.tweens.excview_tween_factory
21 - MAIN

Here’s the application configuration section of the development.ini used by the above ptweens
command which reports that the explicit tween chain is used:

1 [app:main]
2 use = egg:starter
3 reload_templates = true
(continues on next page)

538 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


4 debug_authorization = false
5 debug_notfound = false
6 debug_routematch = false
7 debug_templates = true
8 default_locale_name = en
9 pyramid.include = pyramid_debugtoolbar
10 pyramid.tweens = starter.tween_factory2
11 starter.tween_factory1
12 pyramid.tweens.excview_tween_factory

See Registering Tweens for more information about tweens.

prequest: Invoking a Request

See also:

See also the output of prequest --help.

You can use the prequest command-line utility to send a request to your application and see the response
body without starting a server.

There are two required arguments to prequest:

• The config file/section: follows the format config_file#section_name, where con-


fig_file is the path to your application’s .ini file and section_name is the app section
name inside the .ini file. The section_name is optional; it defaults to main. For example:
development.ini.

• The path: this should be the non-URL-quoted path element of the URL to the resource you’d like
to be rendered on the server. For example, /.

For example:

$VENV/bin/prequest development.ini /

This will print the body of the response to the console on which it was invoked.

Several options are supported by prequest. These should precede any config file name or URL.

prequest has a -d (i.e., --display-headers) option which prints the status and headers returned
by the server before the output:

0.3. Narrative Documentation 539


The Pyramid Web Framework, Version 2.0.2

$VENV/bin/prequest -d development.ini /

This will print the status, headers, and the body of the response to the console.
You can add request header values by using the --header option:

$VENV/bin/prequest --header=Host:example.com development.ini /

Headers are added to the WSGI environment by converting them to their CGI/WSGI equivalents (e.g.,
Host=example.com will insert the HTTP_HOST header variable as the value example.com). Mul-
tiple --header options can be supplied. The special header value content-type sets the CON-
TENT_TYPE in the WSGI environment.
By default, prequest sends a GET request. You can change this by using the -m (aka --method)
option. GET, HEAD, POST, and DELETE are currently supported. When you use POST, the standard
input of the prequest process is used as the POST body:

$VENV/bin/prequest -mPOST development.ini / < somefile

pdistreport: Showing All Installed Distributions and Their Versions

New in version 1.5.


See also:
See also the output of pdistreport --help.
You can use the pdistreport command to show the Pyramid version in use, the Python version in use,
and all installed versions of Python distributions in your Python environment:

$VENV/bin/pdistreport
Pyramid version: 1.5dev
Platform Linux-3.2.0-51-generic-x86_64-with-debian-wheezy-sid
Packages:
authapp 0.0
/home/chrism/projects/foo/src/authapp
beautifulsoup4 4.1.3
/home/chrism/projects/foo/lib/python2.7/site-packages/beautifulsoup4-4.
,→1.3-py2.7.egg

# ... more output ...

pdistreport takes no options. Its output is useful to paste into a pastebin when you are having problems
and need someone with more familiarity with Python packaging and distribution than you have to look at
your environment.

540 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Writing a Script

All web applications are, at their hearts, systems which accept a request and return a response. When a
request is accepted by a Pyramid application, the system receives state from the request which is later relied
on by your application code. For example, one view callable may assume it’s working against a request that
has a request.matchdict of a particular composition, while another assumes a different composition
of the matchdict.

In the meantime, it’s convenient to be able to write a Python script that can work ”in a Pyramid envi-
ronment”, for instance to update database tables used by your Pyramid application. But a ”real” Pyramid
environment doesn’t have a completely static state independent of a request; your application (and Pyra-
mid itself) is almost always reliant on being able to obtain information from a request. When you run a
Python script that simply imports code from your application and tries to run it, there just is no request
data, because there isn’t any real web request. Therefore some parts of your application and some Pyramid
APIs will not work.

For this reason, Pyramid makes it possible to run a script in an environment much like the environ-
ment produced when a particular request reaches your Pyramid application. This is achieved by using
the pyramid.paster.bootstrap() command in the body of your script.

New in version 1.1: pyramid.paster.bootstrap()

Changed in version 1.8: Added the ability for bootstrap to cleanup automatically via the with state-
ment.

In the simplest case, pyramid.paster.bootstrap() can be used with a single argument, which
accepts the PasteDeploy .ini file representing your Pyramid application’s configuration as a single ar-
gument:

from pyramid.paster import bootstrap

with bootstrap('/path/to/my/development.ini') as env:


print(env['request'].route_url('home'))

pyramid.paster.bootstrap() returns a dictionary containing framework-related information.


This dictionary will always contain a request object as its request key.

The following keys are available in the env dictionary returned by pyramid.paster.bootstrap():

request

A pyramid.request.Request object implying the current request state for your script.

0.3. Narrative Documentation 541


The Pyramid Web Framework, Version 2.0.2

app

The WSGI application object generated by bootstrapping.

root

The resource root of your Pyramid application. This is an object generated by the root factory
configured in your application.

registry

The application registry of your Pyramid application.

closer

A parameterless callable that can be used to pop an internal Pyramid threadlocal stack
(used by pyramid.threadlocal.get_current_registry() and pyramid.
threadlocal.get_current_request()) when your scripting job is finished.

Let’s assume that the /path/to/my/development.ini file used in the example above looks like
so:

[pipeline:main]
pipeline = translogger
another

[filter:translogger]
filter_app_factory = egg:Paste#translogger
setup_console_handler = False
logger_name = wsgi

[app:another]
use = egg:MyProject

The configuration loaded by the above bootstrap example will use the configuration implied by
the [pipeline:main] section of your configuration file by default. Specifying /path/to/
my/development.ini is logically equivalent to specifying /path/to/my/development.
ini#main. In this case, we’ll be using a configuration that includes an app object which is wrapped
in the Paste ”translogger” middleware (which logs requests to the console).

You can also specify a particular section of the PasteDeploy .ini file to load instead of main:

542 CONTENTS
The Pyramid Web Framework, Version 2.0.2

from pyramid.paster import bootstrap

with bootstrap('/path/to/my/development.ini#another') as env:


print(env['request'].route_url('home'))

The above example specifies the another app, pipeline, or composite section of your PasteDe-
ploy configuration file. The app object present in the env dictionary returned by pyramid.paster.
bootstrap() will be a Pyramid router.

Changing the Request

By default, Pyramid will generate a request object in the env dictionary for the URL http://
localhost:80/. This means that any URLs generated by Pyramid during the execution of your script
will be anchored here. This is generally not what you want.

So how do we make Pyramid generate the correct URLs?

Assuming that you have a route configured in your application like so:

config.add_route('verify', '/verify/{code}')

You need to inform the Pyramid environment that the WSGI application is handling requests from a certain
base. For example, we want to simulate mounting our application at https://example.com/prefix, to ensure
that the generated URLs are correct for our deployment. This can be done by either mutating the resulting
request object, or more simply by constructing the desired request and passing it into bootstrap():

from pyramid.paster import bootstrap


from pyramid.request import Request

request = Request.blank('/', base_url='https://example.com/prefix')


with bootstrap('/path/to/my/development.ini#another', request=request) as␣
,→env:

print(env['request'].application_url)
# will print 'https://example.com/prefix'

Now you can readily use Pyramid’s APIs for generating URLs:

0.3. Narrative Documentation 543


The Pyramid Web Framework, Version 2.0.2

env['request'].route_url('verify', code='1337')
# will return 'https://example.com/prefix/verify/1337'

Cleanup

If you’re using the with-statement variant then there’s nothing to worry about. However if you’re using
the returned environment directly then when your scripting logic finishes, it’s good manners to call the
closer callback:

from pyramid.paster import bootstrap


env = bootstrap('/path/to/my/development.ini')

# .. do stuff ...

env['closer']()

Setting Up Logging

By default, pyramid.paster.bootstrap() does not configure logging parameters present in the


configuration file. If you’d like to configure logging based on [logger] and related sections in the
configuration file, use the following command:

import pyramid.paster
pyramid.paster.setup_logging('/path/to/my/development.ini')

See Logging for more information on logging within Pyramid.

Making Your Script into a Console Script

A ”console script” is Setuptools terminology for a script that gets installed into the bin directory of a
Python virtual environment (or ”base” Python environment) when a distribution which houses that script
is installed. Because it’s installed into the bin directory of a virtual environment when the distribution is
installed, it’s a convenient way to package and distribute functionality that you can call from the command-
line. It’s often more convenient to create a console script than it is to create a .py script and instruct people
to call it with the ”right” Python interpreter. A console script generates a file that lives in bin, and when
it’s invoked it will always use the ”right” Python environment, which means it will always be invoked in
an environment where all the libraries it needs (such as Pyramid) are available.
In general, you can make your script into a console script by doing the following:

544 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Use an existing distribution (such as one you’ve already created via cookiecutter) or create a
new distribution that possesses at least one package or module. It should, within any module within
the distribution, house a callable (usually a function) that takes no arguments and which runs any of
the code you wish to run.

• Add a [console_scripts] section to the entry_points argument of the distribution which


creates a mapping between a script name and a dotted name representing the callable you added to
your distribution.

• Run pip install -e . or pip install . to get your distribution reinstalled. When
you reinstall your distribution, a file representing the script that you named in the last step will be
in the bin directory of the virtual environment in which you installed the distribution. It will be
executable. Invoking it from a terminal will execute your callable.

As an example, let’s create some code that can be invoked by a console script that prints the deployment
settings of a Pyramid application. To do so, we’ll pretend you have a distribution with a package in it
named myproject. Within this package, we’ll pretend you’ve added a scripts.py module which
contains the following code:

1 # myproject.scripts module
2

3 import optparse
4 import sys
5 import textwrap
6

7 from pyramid.paster import bootstrap


8

9 def settings_show():
10 description = """\
11 Print the deployment settings for a Pyramid application. Example:
12 'show_settings deployment.ini'
13 """
14 usage = "usage: %prog config_uri"
15 parser = optparse.OptionParser(
16 usage=usage,
17 description=textwrap.dedent(description)
18 )
19 parser.add_option(
20 '-o', '--omit',
21 dest='omit',
22 metavar='PREFIX',
23 type='string',
24 action='append',
25 help=("Omit settings which start with PREFIX (you can use this "
26 "option multiple times)")
(continues on next page)

0.3. Narrative Documentation 545


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


27 )
28

29 options, args = parser.parse_args(sys.argv[1:])


30 if not len(args) >= 1:
31 print('You must provide at least one argument')
32 return 2
33 config_uri = args[0]
34 omit = options.omit
35 if omit is None:
36 omit = []
37 with bootstrap(config_uri) as env:
38 settings = env['registry'].settings
39 for k, v in settings.items():
40 if any([k.startswith(x) for x in omit]):
41 continue
42 print('%-40s %-20s' % (k, v))

This script uses the Python optparse module to allow us to make sense out of extra arguments passed
to the script. It uses the pyramid.paster.bootstrap() function to get information about the
application defined by a config file, and prints the deployment settings defined in that config file.

After adding this script to the package, you’ll need to tell your distribution’s setup.py about its existence.
Within your distribution’s top-level directory, your setup.py file will look something like this:

1 import os
2

3 from setuptools import setup, find_packages


4

5 here = os.path.abspath(os.path.dirname(__file__))
6 with open(os.path.join(here, 'README.txt')) as f:
7 README = f.read()
8 with open(os.path.join(here, 'CHANGES.txt')) as f:
9 CHANGES = f.read()
10

11 requires = ['pyramid', 'pyramid_debugtoolbar']


12

13 tests_require = [
14 'WebTest',
15 'pytest',
16 'pytest-cov',
17 ]
18

19 setup(name='MyProject',
20 version='0.0',
(continues on next page)

546 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


21 description='My project',
22 long_description=README + '\n\n' + CHANGES,
23 classifiers=[
24 "Programming Language :: Python",
25 "Framework :: Pyramid",
26 "Topic :: Internet :: WWW/HTTP",
27 "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
28 ],
29 author='',
30 author_email='',
31 url='',
32 keywords='web pyramid pylons',
33 packages=find_packages(exclude=['tests']),
34 include_package_data=True,
35 zip_safe=False,
36 install_requires=requires,
37 extras_require={
38 'testing': tests_require,
39 },
40 entry_points = """\
41 [paste.app_factory]
42 main = myproject:main
43 """,
44 )

We’re going to change the setup.py file to add a [console_scripts] section within the en-
try_points string. Within this section, you should specify a scriptname = dotted.path.
to:yourfunction line. For example:

[console_scripts]
show_settings = myproject.scripts:settings_show

The show_settings name will be the name of the script that is installed into bin. The colon (:)
between myproject.scripts and settings_show above indicates that myproject.scripts
is a Python module, and settings_show is the function in that module which contains the code you’d
like to run as the result of someone invoking the show_settings script from their command line.

The result will be something like:

1 import os
2

3 from setuptools import setup, find_packages


(continues on next page)

0.3. Narrative Documentation 547


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


4

5 here = os.path.abspath(os.path.dirname(__file__))
6 with open(os.path.join(here, 'README.txt')) as f:
7 README = f.read()
8 with open(os.path.join(here, 'CHANGES.txt')) as f:
9 CHANGES = f.read()
10

11 requires = ['pyramid', 'pyramid_debugtoolbar']


12

13 tests_require = [
14 'WebTest',
15 'pytest',
16 'pytest-cov',
17 ]
18

19 setup(name='MyProject',
20 version='0.0',
21 description='My project',
22 long_description=README + '\n\n' + CHANGES,
23 classifiers=[
24 "Programming Language :: Python",
25 "Framework :: Pyramid",
26 "Topic :: Internet :: WWW/HTTP",
27 "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
28 ],
29 author='',
30 author_email='',
31 url='',
32 keywords='web pyramid pylons',
33 packages=find_packages(),
34 include_package_data=True,
35 zip_safe=False,
36 install_requires=requires,
37 extras_require={
38 'testing': tests_require,
39 },
40 entry_points = """\
41 [paste.app_factory]
42 main = myproject:main
43 [console_scripts]
44 show_settings = myproject.scripts:settings_show
45 """,
46 )

Once you’ve done this, invoking $VENV/bin/pip install -e . will install a file named
show_settings into the $somevenv/bin directory with a small bit of Python code that points to

548 CONTENTS
The Pyramid Web Framework, Version 2.0.2

your entry point. It will be executable. Running it without any arguments will print an error and exit.
Running it with a single argument that is the path of a config file will print the settings. Running it with
an --omit=foo argument will omit the settings that have keys that start with foo. Running it with two
”omit” options (e.g., --omit=foo --omit=bar) will omit all settings that have keys that start with
either foo or bar:

$VENV/bin/show_settings development.ini --omit=pyramid --omit=debugtoolbar


debug_routematch False
debug_templates True
reload_templates True
mako.directories []
debug_notfound False
default_locale_name en
reload_resources False
debug_authorization False
reload_assets False
prevent_http_cache False

Pyramid’s pserve, pshell, prequest, ptweens, and other p* scripts are implemented as console
scripts. When you invoke one of those, you are using a console script.

0.3.21 Internationalization and Localization

Internationalization (i18n) is the act of creating software with a user interface that can potentially be
displayed in more than one language or cultural context. Localization (l10n) is the process of displaying
the user interface of an internationalized application in a particular language or cultural context.

Pyramid offers internationalization and localization subsystems that can be used to translate the text of
buttons, error messages, and other software- and template-defined values into the native language of a user
of your application.

Creating a Translation String

While you write your software, you can insert specialized markup into your Python code that makes it
possible for the system to translate text values into the languages used by your application’s users. This
markup creates a translation string. A translation string is an object that behaves mostly like a normal
Unicode string, except that it also carries around extra information related to its job as part of the Pyramid
translation machinery.

0.3. Narrative Documentation 549


The Pyramid Web Framework, Version 2.0.2

Using the TranslationString Class

The most primitive way to create a translation string is to use the pyramid.i18n.
TranslationString callable:

1 from pyramid.i18n import TranslationString


2 ts = TranslationString('Add')

This creates a str-like object that is a TranslationString.

For people more familiar with Zope i18n, a TranslationString is a lot like a zope.
i18nmessageid.Message object. It is not a subclass, however. For people more familiar with Pylons
or Django i18n, using a TranslationString is a lot like using ”lazy” versions of related gettext APIs.

The first argument to TranslationString is the msgid; it is required. It represents the key into the
translation mappings provided by a particular localization. The msgid argument must be a string. The
msgid may optionally contain replacement markers. For instance:

1 from pyramid.i18n import TranslationString


2 ts = TranslationString('Add ${number}')

Within the string above, ${number} is a replacement marker. It will be replaced by whatever is in the
mapping for a translation string. The mapping may be supplied at the same time as the replacement marker
itself:

1 from pyramid.i18n import TranslationString


2 ts = TranslationString('Add ${number}', mapping={'number':1})

Any number of replacement markers can be present in the msgid value, any number of times. Only
markers which can be replaced by the values in the mapping will be replaced at translation time. The
others will not be interpolated and will be output literally.

A translation string should also usually carry a domain. The domain represents a translation category to
disambiguate it from other translations of the same msgid, in case they conflict.

1 from pyramid.i18n import TranslationString


2 ts = TranslationString('Add ${number}', mapping={'number':1},
3 domain='form')

550 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The above translation string named a domain of form. A translator function will often use the domain
to locate the right translator file on the filesystem which contains translations for a given domain. In this
case, if it were trying to translate our msgid to German, it might try to find a translation from a gettext
file within a translation directory like this one:

locale/de/LC_MESSAGES/form.mo

In other words, it would want to take translations from the form.mo translation file in the German lan-
guage.
Finally, the TranslationString constructor accepts a default argument. If a default argument is sup-
plied, it replaces usages of the msgid as the default value for the translation string. When default is
None, the msgid value passed to a TranslationString is used as an implicit message identifier. Message
identifiers are matched with translations in translation files, so it is often useful to create translation strings
with ”opaque” message identifiers unrelated to their default text:

1 from pyramid.i18n import TranslationString


2 ts = TranslationString('add-number', default='Add ${number}',
3 domain='form', mapping={'number':1})

When default text is used, Default text objects may contain replacement values.

Using the TranslationStringFactory Class

Another way to generate a translation string is to use the TranslationStringFactory object. This
object is a translation string factory. Basically a translation string factory presets the domain value of
any translation string generated by using it. For example:

1 from pyramid.i18n import TranslationStringFactory


2 _ = TranslationStringFactory('pyramid')
3 ts = _('add-number', default='Add ${number}', mapping={'number':1})

We assigned the translation string factory to the name _. This is a convention which will be supported
by translation file generation tools.

After assigning _ to the result of a TranslationStringFactory(), the subsequent result of calling


_ will be a TranslationString instance. Even though a domain value was not passed to _ (as
would have been necessary if the TranslationString constructor were used instead of a translation
string factory), the domain attribute of the resulting translation string will be pyramid. As a result, the
previous code example is completely equivalent (except for spelling) to:

0.3. Narrative Documentation 551


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.i18n import TranslationString as _


2 ts = _('add-number', default='Add ${number}', mapping={'number':1},
3 domain='pyramid')

You can set up your own translation string factory much like the one provided above by using the Trans-
lationStringFactory class. For example, if you’d like to create a translation string factory which
presets the domain value of generated translation strings to form, you’d do something like this:

1 from pyramid.i18n import TranslationStringFactory


2 _ = TranslationStringFactory('form')
3 ts = _('add-number', default='Add ${number}', mapping={'number':1})

Creating a unique domain for your application via a translation string factory is best practice. Using your
own unique translation domain allows another person to reuse your application without needing to merge
your translation files with their own. Instead they can just include your package’s translation directory via
the pyramid.config.Configurator.add_translation_dirs() method.

For people familiar with Zope internationalization, a TranslationStringFactory is a lot like a zope.
i18nmessageid.MessageFactory object. It is not a subclass, however.

Working with gettext Translation Files

The basis of Pyramid translation services is GNU gettext. Once your application source code files and
templates are marked up with translation markers, you can work on translations by creating various kinds
of gettext files.

The steps a developer must take to work with gettext message catalog files within a Pyramid appli-
cation are very similar to the steps a Pylons developer must take to do the same. See the Pylons Interna-
tionalization and Localization documentation for more information.

GNU gettext uses three types of files in the translation framework, .pot files, .po files, and .mo files.

.pot (Portable Object Template) files

552 CONTENTS
The Pyramid Web Framework, Version 2.0.2

A .pot file is created by a program which searches through your project’s source code and
which picks out every message identifier passed to one of the _() functions (e.g., translation
string constructions). The list of all message identifiers is placed into a .pot file, which
serves as a template for creating .po files.

.po (Portable Object) files

The list of messages in a .pot file are translated by a human to a particular language; the
result is saved as a .po file.

.mo (Machine Object) files

A .po file is turned into a machine-readable binary file, which is the .mo file. Compiling the
translations to machine code makes the localized program start faster.

The tools for working with gettext translation files related to a Pyramid application are Lingua and Gettext.
Lingua can scrape i18n references out of Python and Chameleon files and create the .pot file. Gettext
includes msgmerge tool to update a .po file from an updated .pot file and msgfmt to compile .po
files to .mo files.

Installing Lingua and Gettext

In order for the commands related to working with gettext translation files to work properly, you will
need to have Lingua and Gettext installed into the same environment in which Pyramid is installed.

Installation on Unix

Gettext is often already installed on Unix systems. You can check if it is installed by testing if the msgfmt
command is available. If it is not available you can install it through the packaging system from your
OS; the package name is almost always gettext. For example on a Debian or Ubuntu system run this
command:

sudo apt-get install gettext

Installing Lingua is done with the Python packaging tools. If the virtual environment into which you’ve
installed your Pyramid application lives at the environment variable $VENV, you can install Lingua like
so:

0.3. Narrative Documentation 553


The Pyramid Web Framework, Version 2.0.2

$VENV/bin/pip install lingua

Installation on Windows

There are several ways to install Gettext on Windows: it is included in the Cygwin collection, or you can
use the installer from the GnuWin32, or compile it yourself. Make sure the installation path is added to
your $PATH.

Installing Lingua is done with the Python packaging tools. If the virtual environment into which you’ve
installed your Pyramid application lives at the environment variable %VENV%, you can install Lingua like
so:

%VENV%\Scripts\pip install lingua

Extracting Messages from Code and Templates

Once Lingua is installed, you may extract a message catalog template from the code and Chameleon tem-
plates which reside in your Pyramid application. You run a pot-create command to extract the mes-
sages:

cd /file/path/to/myapplication_setup.py
mkdir -p myapplication/locale
$VENV/bin/pot-create -o myapplication/locale/myapplication.pot src

The message catalog .pot template will end up in myapplication/locale/myapplication.


pot.

Initializing a Message Catalog File

Once you’ve extracted messages into a .pot file (see Extracting Messages from Code and Templates), to
begin localizing the messages present in the .pot file, you need to generate at least one .po file. A .po
file represents translations of a particular set of messages to a particular locale. Initialize a .po file for a
specific locale from a pre-generated .pot template by using the msginit command from Gettext:

554 CONTENTS
The Pyramid Web Framework, Version 2.0.2

cd /file/path/to/myapplication_setup.py
cd myapplication/locale
mkdir -p es/LC_MESSAGES
msginit -l es -o es/LC_MESSAGES/myapplication.po

This will create a new message catalog .po file in myapplication/locale/es/LC_MESSAGES/


myapplication.po.

Once the file is there, it can be worked on by a human translator. One tool which may help with this is
Poedit.

Note that Pyramid itself ignores the existence of all .po files. For a running application to have translations
available, a .mo file must exist. See Compiling a Message Catalog File.

Updating a Catalog File

If more translation strings are added to your application, or translation strings change, you will need to
update existing .po files based on changes to the .pot file, so that the new and changed messages can
also be translated or re-translated.

First, regenerate the .pot file as per Extracting Messages from Code and Templates. Then use the msg-
merge command from Gettext.

cd /file/path/to/myapplication_setup.py
cd myapplication/locale
msgmerge --update es/LC_MESSAGES/myapplication.po myapplication.pot

Compiling a Message Catalog File

Finally, to prepare an application for performing actual runtime translations, compile .po files to .mo
files using the msgfmt command from Gettext:

cd /file/path/to/myapplication_setup.py
msgfmt -o myapplication/locale/es/LC_MESSAGES/myapplication.mo \
myapplication/locale/es/LC_MESSAGES/myapplication.po

This will create a .mo file for each .po file in your application. As long as the translation directory in
which the .mo file ends up in is configured into your application (see Adding a Translation Directory),
these translations will be available to Pyramid.

0.3. Narrative Documentation 555


The Pyramid Web Framework, Version 2.0.2

Using a Localizer

A localizer is an object that allows you to perform translation or pluralization ”by hand” in an application.
You may use the pyramid.request.Request.localizer attribute to obtain a localizer. The
localizer object will be configured to produce translations implied by the active locale negotiator, or a
default localizer object if no explicit locale negotiator is registered.

1 def aview(request):
2 localizer = request.localizer

If you need to create a localizer for a locale, use the pyramid.i18n.make_localizer()


function.

Performing a Translation

A localizer has a translate method which accepts either a translation string or a Unicode string and
which returns a Unicode string representing the translation. Generating a translation in a view component
of an application might look like so:

1 from pyramid.i18n import TranslationString


2

3 ts = TranslationString('Add ${number}', mapping={'number':1},


4 domain='pyramid')
5

6 def aview(request):
7 localizer = request.localizer
8 translated = localizer.translate(ts) # translation string
9 # ... use translated ...

The request.localizer attribute will be a pyramid.i18n.Localizer object bound to the lo-


cale name represented by the request. The translation returned from its pyramid.i18n.Localizer.
translate() method will depend on the domain attribute of the provided translation string as well
as the locale of the localizer.

If you’re using Chameleon templates, you don’t need to pre-translate translation strings this way. See
Chameleon Template Support for Translation Strings.

556 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Performing a Pluralization

A localizer has a pluralize method with the following signature:

1 def pluralize(singular, plural, n, domain=None, mapping=None):


2 # ...

The simplest case is the singular and plural arguments being passed as Unicode literals. This re-
turns the appropriate literal according to the locale pluralization rules for the number n, and interpolates
mapping.

1 def aview(request):
2 localizer = request.localizer
3 translated = localizer.pluralize('Item', 'Items', 1, 'mydomain')
4 # ... use translated ...

However, for support of other languages, the singular argument should be a Unicode value representing
a message identifier. In this case the plural value is ignored. domain should be a translation domain,
and mapping should be a dictionary that is used for replacement value interpolation of the translated
string.
The value of n will be used to find the appropriate plural form for the current language, and pluralize
will return a Unicode translation for the message id singular. The message file must have defined
singular as a translation with plural forms.
The argument provided as singular may be a translation string object, but the domain and mapping
information attached is ignored.

1 def aview(request):
2 localizer = request.localizer
3 num = 1
4 translated = localizer.pluralize('item_plural', '${number} items',
5 num, 'mydomain', mapping={'number':num})

The corresponding message catalog must have language plural definitions and plural alternatives set.

1 "Plural-Forms: nplurals=3; plural=n==0 ? 0 : n==1 ? 1 : 2;"


2

3 msgid "item_plural"
4 msgid_plural ""
5 msgstr[0] "No items"
6 msgstr[1] "${number} item"
7 msgstr[2] "${number} items"

More information on complex plurals can be found in the gettext documentation.

0.3. Narrative Documentation 557


The Pyramid Web Framework, Version 2.0.2

Obtaining the Locale Name for a Request

You can obtain the locale name related to a request by using the pyramid.request.Request.
locale_name() attribute of the request.

1 def aview(request):
2 locale_name = request.locale_name

The locale name of a request is dynamically computed; it will be the locale name negotiated by the cur-
rently active locale negotiator, or the default locale name if the locale negotiator returns None. You
can change the default locale name by changing the pyramid.default_locale_name setting. See
Default Locale Name.

Once locale_name() is first run, the locale name is stored on the request object. Subsequent calls to
locale_name() will return the stored locale name without invoking the locale negotiator. To avoid
this caching, you can use the pyramid.i18n.negotiate_locale_name() function:

1 from pyramid.i18n import negotiate_locale_name


2

3 def aview(request):
4 locale_name = negotiate_locale_name(request)

You can also obtain the locale name related to a request using the locale_name attribute of a localizer.

1 def aview(request):
2 localizer = request.localizer
3 locale_name = localizer.locale_name

Obtaining the locale name as an attribute of a localizer is equivalent to obtaining a locale name by asking
for the locale_name() attribute.

Performing Date Formatting and Currency Formatting

Pyramid does not itself perform date and currency formatting for different locales. However, Babel can
help you do this via the babel.core.Locale class. The Babel documentation for this class provides
minimal information about how to perform date and currency related locale operations. See Installing
Lingua and Gettext for information about how to install Babel.

The babel.core.Locale class requires a locale name as an argument to its constructor. You can use
Pyramid APIs to obtain the locale name for a request to pass to the babel.core.Locale constructor.
See Obtaining the Locale Name for a Request. For example:

558 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from babel.core import Locale


2

3 def aview(request):
4 locale_name = request.locale_name
5 locale = Locale(locale_name)

Chameleon Template Support for Translation Strings

When a translation string is used as the subject of textual rendering by a Chameleon template renderer,
it will automatically be translated to the requesting user’s language if a suitable translation exists. This is
true of both the ZPT and text variants of the Chameleon template renderers.

For example, in a Chameleon ZPT template, the translation string represented by


”some_translation_string” in each example below will go through translation before being rendered:

1 <span tal:content="some_translation_string"/>

1 <span tal:replace="some_translation_string"/>

1 <span>${some_translation_string}</span>

1 <a tal:attributes="href some_translation_string">Click here</a>

The features represented by attributes of the i18n namespace of Chameleon will also consult the Pyramid
translations. See https://chameleon.readthedocs.io/en/latest/reference.html#translation-i18n.

Unlike when Chameleon is used outside of Pyramid, when it is used within Pyramid, it does not
support use of the zope.i18n translation framework. Applications which use Pyramid should use the
features documented in this chapter rather than zope.i18n.

Third party Pyramid template renderers might not provide this support out of the box and may need special
code to do an equivalent. For those, you can always use the more manual translation facility described in
Performing a Translation.

0.3. Narrative Documentation 559


The Pyramid Web Framework, Version 2.0.2

Mako Pyramid i18n Support

There exists a recipe within the Pyramid Community Cookbook named Mako Internationalization which
explains how to add idiomatic i18n support to Mako templates.

Jinja2 Pyramid i18n Support

The add-on pyramid_jinja2 provides a scaffold with an example of how to use internationalization with
Jinja2 in Pyramid. See the documentation sections Internalization (i18n) and pcreate template i18n.

Localization-Related Deployment Settings

A Pyramid application will have a pyramid.default_locale_name setting. This value represents


the default locale name used when the locale negotiator returns None. Pass it to the Configurator
constructor at startup time:

1 from pyramid.config import Configurator


2 config = Configurator(settings={'pyramid.default_locale_name':'de'})

You may alternately supply a pyramid.default_locale_name via an application’s .ini file:

1 [app:main]
2 use = egg:MyProject
3 pyramid.reload_templates = true
4 pyramid.debug_authorization = false
5 pyramid.debug_notfound = false
6 pyramid.default_locale_name = de

If this value is not supplied via the Configurator constructor or via a config file, it will default to en.

If this setting is supplied within the Pyramid application .ini file, it will be available as a settings key:

1 from pyramid.threadlocal import get_current_registry


2 settings = get_current_registry().settings
3 default_locale_name = settings['pyramid.default_locale_name']

560 CONTENTS
The Pyramid Web Framework, Version 2.0.2

”Detecting” Available Languages

Other systems provide an API that returns the set of ”available languages” as indicated by the union of all
languages in all translation directories on disk at the time of the call to the API.

It is by design that Pyramid doesn’t supply such an API. Instead the application itself is responsible for
knowing the ”available languages”. The rationale is this: any particular application deployment must
always know which languages it should be translatable to anyway, regardless of which translation files are
on disk.

Here’s why: it’s not a given that because translations exist in a particular language within the registered set
of translation directories that this particular deployment wants to allow translation to that language. For
example, some translations may exist but they may be incomplete or incorrect. Or there may be translations
to a language but not for all translation domains.

Any nontrivial application deployment will always need to be able to selectively choose to allow only some
languages even if that set of languages is smaller than all those detected within registered translation direc-
tories. The easiest way to allow for this is to make the application entirely responsible for knowing which
languages are allowed to be translated to instead of relying on the framework to divine this information
from translation directory file info.

You can set up a system to allow a deployer to select available languages based on convention by using the
pyramid.settings mechanism.

Allow a deployer to modify your application’s .ini file:

1 [app:main]
2 use = egg:MyProject
3 # ...
4 available_languages = fr de en ru

Then as a part of the code of a custom locale negotiator:

1 from pyramid.settings import aslist


2

3 def my_locale_negotiator(request):
4 languages = aslist(request.registry.settings['available_languages'])
5 # ...

This is only a suggestion. You can create your own ”available languages” configuration scheme as neces-
sary.

0.3. Narrative Documentation 561


The Pyramid Web Framework, Version 2.0.2

Activating Translation

By default, a Pyramid application performs no translation. To turn translation on you must:

• add at least one translation directory to your application.

• ensure that your application sets the locale name correctly.

Adding a Translation Directory

gettext is the underlying machinery behind the Pyramid translation machinery. A translation directory is
a directory organized to be useful to gettext. A translation directory usually includes a listing of language
directories, each of which itself includes an LC_MESSAGES directory. Each LC_MESSAGES directory
should contain one or more .mo files. Each .mo file represents a message catalog, which is used to provide
translations to your application.

Adding a translation directory registers all of its constituent message catalog files within your Pyramid
application to be available to use for translation services. This includes all of the .mo files found within
all LC_MESSAGES directories within each locale directory in the translation directory.

You can add a translation directory imperatively by using the pyramid.config.Configurator.


add_translation_dirs() during application startup. For example:

1 from pyramid.config import Configurator


2 config.add_translation_dirs('my.application:locale/',
3 'another.application:locale/')

A message catalog in a translation directory added via add_translation_dirs() will be merged


into translations from a message catalog added earlier if both translation directories contain translations
for the same locale and translation domain.

Setting the Locale

When the default locale negotiator (see The Default Locale Negotiator) is in use, you can inform Pyramid
of the current locale name by doing any of these things before any translations need to be performed:

• Set the _LOCALE_ attribute of the request to a valid locale name (usually directly within view code),
e.g., request._LOCALE_ = 'de'.

562 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Ensure that a valid locale name value is in the request.params dictionary under the key
named _LOCALE_. This is usually the result of passing a _LOCALE_ value in the query string
or in the body of a form post associated with a request. For example, visiting http://my.
application?_LOCALE_=de.

• Ensure that a valid locale name value is in the request.cookies dictionary under the key named
_LOCALE_. This is usually the result of setting a _LOCALE_ cookie in a prior response, e.g.,
response.set_cookie('_LOCALE_', 'de').

If this locale negotiation scheme is inappropriate for a particular application, you can configure a
custom locale negotiator function into that application as required. See Using a Custom Locale Negotiator.

Locale Negotiators

A locale negotiator informs the operation of a localizer by telling it what locale name is related to a particu-
lar request. A locale negotiator is a bit of code which accepts a request and which returns a locale name. It is
consulted when pyramid.i18n.Localizer.translate() or pyramid.i18n.Localizer.
pluralize() is invoked. It is also consulted when locale_name() is accessed or when negoti-
ate_locale_name() is invoked.

The Default Locale Negotiator

Most applications can make use of the default locale negotiator, which requires no additional coding or
configuration.

The default locale negotiator implementation named default_locale_negotiator uses the fol-
lowing set of steps to determine the locale name.

• First the negotiator looks for the _LOCALE_ attribute of the request object (possibly set directly by
view code or by a listener for an event).

• Then it looks for the request.params['_LOCALE_'] value.

• Then it looks for the request.cookies['_LOCALE_'] value.

• If no locale can be found via the request, it falls back to using the default locale name (see
Localization-Related Deployment Settings).

• Finally if the default locale name is not explicitly set, it uses the locale name en.

0.3. Narrative Documentation 563


The Pyramid Web Framework, Version 2.0.2

Using a Custom Locale Negotiator

Locale negotiation is sometimes policy-laden and complex. If the (simple) default locale negotiation
scheme described in Activating Translation is inappropriate for your application, you may create a spe-
cial locale negotiator. Subsequently you may override the default locale negotiator by adding your newly
created locale negotiator to your application’s configuration.
A locale negotiator is simply a callable which accepts a request and returns a single locale name or None
if no locale can be determined.
Here’s an implementation of a simple locale negotiator:

1 def my_locale_negotiator(request):
2 locale_name = request.params.get('my_locale')
3 return locale_name

If a locale negotiator returns None, it signifies to Pyramid that the default application locale name should
be used.
You may add your newly created locale negotiator to your application’s configuration by passing an
object which can act as the negotiator (or a dotted Python name referring to the object) as the lo-
cale_negotiator argument of the Configurator instance during application startup. For ex-
ample:

1 from pyramid.config import Configurator


2 config = Configurator(locale_negotiator=my_locale_negotiator)

Alternatively, use the pyramid.config.Configurator.set_locale_negotiator()


method.
For example:

1 from pyramid.config import Configurator


2 config = Configurator()
3 config.set_locale_negotiator(my_locale_negotiator)

0.3.22 Virtual Hosting

”Virtual hosting” is, loosely, the act of serving a Pyramid application or a portion of a Pyramid application
under a URL space that it does not ”naturally” inhabit.
Pyramid provides facilities for serving an application under a URL ”prefix”, as well as serving a portion
of a traversal based application under a root URL.

564 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Hosting an Application Under a URL Prefix

Pyramid supports a common form of virtual hosting whereby you can host a Pyramid application as a ”sub-
set” of some other site (e.g., under http://example.com/mypyramidapplication/ as opposed
to under http://example.com/).

If you use a ”pure Python” environment, this functionality can be provided by rutter, forming a ”composite”
WSGI application. Alternatively, you can use mod_wsgi to serve your application, which handles this
virtual hosting translation for you ”under the hood”.

If you use the rutter composite application ”in front” of a Pyramid application or if you use mod_wsgi
to serve up a Pyramid application, nothing special needs to be done within the application for URLs to
be generated that contain a prefix. Rutter and mod_wsgi manipulate the WSGI environment in such a way
that the PATH_INFO and SCRIPT_NAME variables are correct for some given prefix.

Here’s an example of a PasteDeploy configuration snippet that includes a rutter composite.

1 [app:mypyramidapp]
2 use = egg:mypyramidapp
3

4 [composite:main]
5 use = egg:rutter#urlmap
6 /pyramidapp = mypyramidapp

This ”roots” the Pyramid application at the prefix /pyramidapp and serves up the composite as the
”main” application in the file.

If you’re using an Apache server to proxy to a urlmap composite, you may have to use
the ProxyPreserveHost directive to pass the original HTTP_HOST header along to the application,
so URLs get generated properly. As of this writing the urlmap composite does not seem to re-
spect the HTTP_X_FORWARDED_HOST parameter, which will contain the original host header even if
HTTP_HOST is incorrect.

If you use mod_wsgi, you do not need to use a composite application in your .ini file. The WSGIS-
criptAlias configuration setting in a mod_wsgi configuration does the work for you:

1 WSGIScriptAlias /pyramidapp /Users/chrism/projects/modwsgi/env/pyramid.wsgi

In the above configuration, we root a Pyramid application at /pyramidapp within the Apache configu-
ration.

0.3. Narrative Documentation 565


The Pyramid Web Framework, Version 2.0.2

Virtual Root Support

Pyramid also supports ”virtual roots”, which can be used in traversal-based (but not URL dispatch-based)
applications.

Virtual root support is useful when you’d like to host some resource in a Pyramid resource tree as an
application under a URL pathname that does not include the resource path itself. For example, you might
want to serve the object at the traversal path /cms as an application reachable via http://example.
com/ (as opposed to http://example.com/cms).

To specify a virtual root, cause an environment variable to be inserted into the WSGI environ named
HTTP_X_VHM_ROOT with a value that is the absolute pathname to the resource object in the resource
tree that should behave as the ”root” resource. As a result, the traversal machinery will respect this value
during traversal (prepending it to the PATH_INFO before traversal starts), and the pyramid.request.
Request.resource_url() API will generate the ”correct” virtually-rooted URLs.

An example of an Apache mod_proxy configuration that will host the /cms subobject as http://
www.example.com/ using this facility is below:

1 NameVirtualHost *:80
2

3 <VirtualHost *:80>
4 ServerName www.example.com
5 RewriteEngine On
6 RewriteRule ^/(.*) http://127.0.0.1:6543/$1 [L,P]
7 ProxyPreserveHost on
8 RequestHeader add X-Vhm-Root /cms
9 </VirtualHost>

Use of the RequestHeader directive requires that the Apache mod_headers module be available
in the Apache environment you’re using.

For a Pyramid application running under mod_wsgi, the same can be achieved using SetEnv:

1 <Location />
2 SetEnv HTTP_X_VHM_ROOT /cms
3 </Location>

Setting a virtual root has no effect when using an application based on URL dispatch.

566 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Further Documentation and Examples

The API documentation in pyramid.traversal documents a pyramid.traversal.


virtual_root() API. When called, it returns the virtual root object (or the physical root object if no
virtual root has been specified).
Running a Pyramid Application under mod_wsgi has detailed information about using mod_wsgi to serve
Pyramid applications.

0.3.23 Unit, Integration, and Functional Testing

Unit testing is, not surprisingly, the act of testing a ”unit” in your application. In this context, a ”unit” is
often a function or a method of a class instance. The unit is also referred to as a ”unit under test”.
The goal of a single unit test is to test only some permutation of the ”unit under test”. If you write a unit
test that aims to verify the result of a particular codepath through a Python function, you need only be
concerned about testing the code that lives in the function body itself. If the function accepts a parameter
that represents a complex application ”domain object” (such as a resource, a database connection, or an
SMTP server), the argument provided to this function during a unit test need not be and likely should not
be a ”real” implementation object. For example, although a particular function implementation may accept
an argument that represents an SMTP server object, and the function may call a method of this object when
the system is operating normally that would result in an email being sent, a unit test of this codepath of
the function does not need to test that an email is actually sent. It just needs to make sure that the function
calls the method of the object provided as an argument that would send an email if the argument happened
to be the ”real” implementation of an SMTP server object.
An integration test, on the other hand, is a different form of testing in which the interaction between two
or more ”units” is explicitly tested. Integration tests verify that the components of your application work
together. You might make sure that an email was actually sent in an integration test.
A functional test is a form of integration test in which the application is run ”literally”. You would have
to make sure that an email was actually sent in a functional test, because it tests your code end to end.
It is often considered best practice to write each type of tests for any given codebase. Unit testing often
provides the opportunity to obtain better ”coverage”: it’s usually possible to supply a unit under test with
arguments and/or an environment which causes all of its potential codepaths to be executed. This is usually
not as easy to do with a set of integration or functional tests, but integration and functional testing provides
a measure of assurance that your ”units” work together, as they will be expected to when your application
is run in production.
The suggested mechanism for unit and integration testing of a Pyramid application is the Python
unittest module. Although this module is named unittest, it is actually capable of driving both
unit and integration tests. A good unittest tutorial is available within Dive Into Python 3 by Mark
Pilgrim.
Pyramid provides a number of facilities that make unit, integration, and functional tests easier to write.
The facilities become particularly useful when your code calls into Pyramid-related framework functions.

0.3. Narrative Documentation 567


The Pyramid Web Framework, Version 2.0.2

Test Set Up and Tear Down

Pyramid uses a ”global” (actually thread local) data structure to hold two items: the current request and
the current application registry. These data structures are available via the pyramid.threadlocal.
get_current_request() and pyramid.threadlocal.get_current_registry() func-
tions, respectively. See Thread Locals for information about these functions and the data structures they
return.

If your code uses these get_current_* functions or calls Pyramid code which uses get_current_*
functions, you will need to call pyramid.testing.setUp() in your test setup and you will need to
call pyramid.testing.tearDown() in your test teardown. setUp() pushes a registry onto the
thread local stack, which makes the get_current_* functions work. It returns a Configurator object
which can be used to perform extra configuration required by the code under test. tearDown() pops the
thread local stack.

Normally when a Configurator is used directly with the main block of a Pyramid application, it defers
performing any ”real work” until its .commit method is called (often implicitly by the pyramid.
config.Configurator.make_wsgi_app() method). The Configurator returned by setUp()
is an autocommitting Configurator, however, which performs all actions implied by methods called on it
immediately. This is more convenient for unit testing purposes than needing to call pyramid.config.
Configurator.commit() in each test after adding extra configuration statements.

The use of the setUp() and tearDown() functions allows you to supply each unit test method in a test
case with an environment that has an isolated registry and an isolated request for the duration of a single
test. Here’s an example of using this feature:

1 import unittest
2 from pyramid import testing
3

4 class MyTest(unittest.TestCase):
5 def setUp(self):
6 self.config = testing.setUp()
7

8 def tearDown(self):
9 testing.tearDown()

The above will make sure that get_current_registry() called within a test case method of
MyTest will return the application registry associated with the config Configurator instance. Each
test case method attached to MyTest will use an isolated registry.

The setUp() and tearDown() functions accept various arguments that influence the environment
of the test. See the pyramid.testing API for information about the extra arguments supported by these
functions.

568 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If you also want to make get_current_request() return something other than None during the
course of a single test, you can pass a request object into the pyramid.testing.setUp() within the
setUp method of your test:

1 import unittest
2 from pyramid import testing
3

4 class MyTest(unittest.TestCase):
5 def setUp(self):
6 request = testing.DummyRequest()
7 self.config = testing.setUp(request=request)
8

9 def tearDown(self):
10 testing.tearDown()

If you pass a request object into pyramid.testing.setUp() within your test case’s setUp, any test
method attached to the MyTest test case that directly or indirectly calls get_current_request()
will receive the request object. Otherwise, during testing, get_current_request() will return
None. We use a ”dummy” request implementation supplied by pyramid.testing.DummyRequest
because it’s easier to construct than a ”real” Pyramid request object.

Test setup using a context manager

An alternative style of setting up a test configuration is to use the with statement and pyramid.
testing.testConfig() to create a context manager. The context manager will call pyramid.
testing.setUp() before the code under test and pyramid.testing.tearDown() afterwards.

This style is useful for small self-contained tests. For example:

1 import unittest
2

3 class MyTest(unittest.TestCase):
4

5 def test_my_function(self):
6 from pyramid import testing
7 with testing.testConfig() as config:
8 config.add_route('bar', '/bar/{id}')
9 my_function_which_needs_route_bar()

0.3. Narrative Documentation 569


The Pyramid Web Framework, Version 2.0.2

What?

Thread local data structures are always a bit confusing, especially when they’re used by frameworks.
Sorry. So here’s a rule of thumb: if you don’t know whether you’re calling code that uses the
get_current_registry() or get_current_request() functions, or you don’t care about any
of this, but you still want to write test code, just always call pyramid.testing.setUp() in your test’s
setUp method and pyramid.testing.tearDown() in your tests’ tearDown method. This won’t
really hurt anything if the application you’re testing does not call any get_current* function.

Using the Configurator and pyramid.testing APIs in Unit Tests

The Configurator API and the pyramid.testing module provide a number of functions which
can be used during unit testing. These functions make configuration declaration calls to the current ap-
plication registry, but typically register a ”stub” or ”dummy” feature in place of the ”real” feature that the
code would call if it was being run normally.

For example, let’s imagine you want to unit test a Pyramid view function.

1 from pyramid.httpexceptions import HTTPForbidden


2

3 def view_fn(request):
4 if request.has_permission('edit'):
5 raise HTTPForbidden
6 return {'greeting':'hello'}

This code implies that you have defined a renderer imperatively in a relevant pyramid.config.
Configurator instance, otherwise it would fail when run normally.

Without doing anything special during a unit test, the call to has_permission() in this view func-
tion will always return a True value. When a Pyramid application starts normally, it will populate an
application registry using configuration declaration calls made against a Configurator. But if this ap-
plication registry is not created and populated (e.g., by initializing the configurator with an authorization
policy), like when you invoke application code via a unit test, Pyramid API functions will tend to either
fail or return default results. So how do you test the branch of the code in this view function that raises
HTTPForbidden?

The testing API provided by Pyramid allows you to simulate various application registry registrations for
use under a unit testing framework without needing to invoke the actual application configuration implied
by its main function. For example, if you wanted to test the above view_fn (assuming it lived in the
package named my.package), you could write a unittest.TestCase that used the testing API.

570 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 import unittest
2 from pyramid import testing
3

4 class MyTest(unittest.TestCase):
5 def setUp(self):
6 self.config = testing.setUp()
7

8 def tearDown(self):
9 testing.tearDown()
10

11 def test_view_fn_forbidden(self):
12 from pyramid.httpexceptions import HTTPForbidden
13 from my.package import view_fn
14 self.config.testing_securitypolicy(userid='hank',
15 permissive=False)
16 request = testing.DummyRequest()
17 request.context = testing.DummyResource()
18 self.assertRaises(HTTPForbidden, view_fn, request)
19

20 def test_view_fn_allowed(self):
21 from my.package import view_fn
22 self.config.testing_securitypolicy(userid='hank',
23 permissive=True)
24 request = testing.DummyRequest()
25 request.context = testing.DummyResource()
26 response = view_fn(request)
27 self.assertEqual(response, {'greeting':'hello'})

In the above example, we create a MyTest test case that inherits from unittest.TestCase. If it’s in
our Pyramid application, it will be found when pytest is run. It has two test methods.
The first test method, test_view_fn_forbidden tests the view_fn when the security policy for-
bids the current user the edit permission. Its third line registers a ”dummy” ”non-permissive” autho-
rization policy using the testing_securitypolicy() method, which is a special helper method
for unit testing.
We then create a pyramid.testing.DummyRequest object which simulates a WebOb request object
API. A pyramid.testing.DummyRequest is a request object that requires less setup than a ”real”
Pyramid request. We call the function being tested with the manufactured request. When the function is
called, pyramid.request.Request.has_permission() will call the ”dummy” security policy
we’ve registered through testing_securitypolicy(), which denies access. We check that the
view function raises a HTTPForbidden error.
The second test method, named test_view_fn_allowed, tests the alternate case, where the security
policy allows access. Notice that we pass different values to testing_securitypolicy() to obtain
this result. We assert at the end of this that the view function returns a value.

0.3. Narrative Documentation 571


The Pyramid Web Framework, Version 2.0.2

Note that the test calls the pyramid.testing.setUp() function in its setUp method and the
pyramid.testing.tearDown() function in its tearDown method. We assign the result of
pyramid.testing.setUp() as config on the unittest class. This is a Configurator object and
all methods of the configurator can be called as necessary within tests. If you use any of the Configu-
rator APIs during testing, be sure to use this pattern in your test case’s setUp and tearDown; these
methods make sure you’re using a ”fresh” application registry per test run.

See the pyramid.testing chapter for the entire Pyramid-specific testing API. This chapter describes APIs
for registering a security policy, registering resources at paths, registering event listeners, registering views
and view permissions, and classes representing ”dummy” implementations of a request and a resource.

See also:

See also the various methods of the Configurator documented in pyramid.config that begin with the test-
ing_ prefix.

Creating Integration Tests

In Pyramid, a unit test typically relies on ”mock” or ”dummy” implementations to give the code under test
enough context to run.

”Integration testing” implies another sort of testing. In the context of a Pyramid integration test, the test
logic exercises the functionality of the code under test and its integration with the rest of the Pyramid
framework.

Creating an integration test for a Pyramid application usually means invoking the application’s in-
cludeme function via pyramid.config.Configurator.include() within the test’s setup
code. This causes the entire Pyramid environment to be set up, simulating what happens when your appli-
cation is run ”for real”. This is a heavy-hammer way of making sure that your tests have enough context
to run properly, and tests your code’s integration with the rest of Pyramid.

See also:

See also Including Configuration from External Sources

Writing unit tests that use the Configurator API to set up the right ”mock” registrations is often
preferred to creating integration tests. Unit tests will run faster (because they do less for each test) and are
usually easier to reason about.

572 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Creating Functional Tests

Functional tests test your literal application.

In Pyramid, functional tests are typically written using the WebTest package, which provides APIs for
invoking HTTP(S) requests to your application. We also like pytest and pytest-cov to provide
simple testing and coverage reports.

Regardless of which testing package you use, be sure to add a tests_require dependency on that
package to your application’s setup.py file. Using the project myproject generated by the starter
cookiecutter as described in Creating a Pyramid Project, we would insert the following code immediately
following the requires block in the file myproject/setup.py.

11 requires = [
12 'plaster_pastedeploy',
13 'pyramid',
14 'pyramid_jinja2',
15 'pyramid_debugtoolbar',
16 'waitress',
17 ]
18

19 tests_require = [
20 'WebTest',
21 'pytest',
22 'pytest-cov',
23 ]

Remember to change the dependency.

42 zip_safe=False,
43 extras_require={
44 'testing': tests_require,
45 },
46 install_requires=requires,

As always, whenever you change your dependencies, make sure to run the correct pip install -e
command.

$VENV/bin/pip install -e ".[testing]"

In your myproject project, your package is named myproject which contains a views package
containing a default.py module, which in turn contains a view function my_view that returns an
HTML body when the root URL is invoked:

0.3. Narrative Documentation 573


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.view import view_config


2

4 @view_config(route_name='home', renderer='myproject:templates/
,→mytemplate.jinja2')

5 def my_view(request):
6 return {'project': 'myproject'}

Test configuration and fixtures are defined in conftest.py. In the following example, we define a test
fixture.

1 @pytest.fixture
2 def testapp(app):
3 testapp = webtest.TestApp(app, extra_environ={
4 'HTTP_HOST': 'example.com',
5 })
6

7 return testapp

This fixture is used in the following example functional tests, to demonstrate invoking the above view:

1 def test_root(testapp):
2 res = testapp.get('/', status=200)
3 assert b'Pyramid' in res.body
4

5 def test_notfound(testapp):
6 res = testapp.get('/badurl', status=404)
7 assert res.status_code == 404

When these tests are run, each test method creates a ”real” WSGI application using the main function
in your myproject.__init__ module, using WebTest to wrap that WSGI application. It assigns the
result to res.

In the test named test_root, the TestApp’s GET method is used to invoke the root URL. An assertion
is made that the returned HTML contains the text Pyramid.

In the test named test_notfound, the TestApp’s GET method is used to invoke a bad URL /
badurl. An assertion is made that the returned status code in the response is 404.

See the WebTest documentation for further information about the methods available to a webtest.app.
TestApp instance.

574 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.3.24 Resources

A resource is an object that represents a ”place” in a tree related to your application. Every Pyramid
application has at least one resource object: the root resource. Even if you don’t define a root resource
manually, a default one is created for you. The root resource is the root of a resource tree. A resource tree
is a set of nested dictionary-like objects which you can use to represent your website’s structure.

In an application which uses traversal to map URLs to code, the resource tree structure is used heavily to
map each URL to a view callable. When traversal is used, Pyramid will walk through the resource tree
by traversing through its nested dictionary structure in order to find a context resource. Once a context
resource is found, the context resource and data in the request will be used to find a view callable.

In an application which uses URL dispatch, the resource tree is only used indirectly, and is often ”invisible”
to the developer. In URL dispatch applications, the resource ”tree” is often composed of only the root
resource by itself. This root resource sometimes has security declarations attached to it, but is not required
to have any. In general, the resource tree is much less important in applications that use URL dispatch than
applications that use traversal.

In ”Zope-like” Pyramid applications, resource objects also often store data persistently, and offer methods
related to mutating that persistent data. In these kinds of applications, resources not only represent the site
structure of your website, but they become the domain model of the application.

Also:

• The context and containment predicate arguments to add_view() (or a


view_config() decorator) reference a resource class or resource interface.

• A root factory returns a resource.

• A resource is exposed to view code as the context of a view.

• Various helpful Pyramid API methods expect a resource as an argument (e.g., resource_url()
and others).

0.3. Narrative Documentation 575


The Pyramid Web Framework, Version 2.0.2

Defining a Resource Tree

When traversal is used (as opposed to a purely URL dispatch based application), Pyramid expects to be
able to traverse a tree composed of resources (the resource tree). Traversal begins at a root resource, and
descends into the tree recursively, trying each resource’s __getitem__ method to resolve a path segment
to another resource object. Pyramid imposes the following policy on resource instances in the tree:

• A container resource (a resource which contains other resources) must supply a __getitem__
method which is willing to resolve a Unicode name to a sub-resource. If a sub-resource by a particular
name does not exist in a container resource, the __getitem__ method of the container resource
must raise a KeyError. If a sub-resource by that name does exist, the container’s __getitem__
should return the sub-resource.

• Leaf resources, which do not contain other resources, must not implement a __getitem__, or if
they do, their __getitem__ method must always raise a KeyError.

See Traversal for more information about how traversal works against resource instances.

Here’s a sample resource tree, represented by a variable named root:

1 class Resource(dict):
2 pass
3

4 root = Resource({'a':Resource({'b':Resource({'c':Resource()})})})

The resource tree we’ve created above is represented by a dictionary-like root object which has a single
child named 'a'. 'a' has a single child named 'b', and 'b' has a single child named 'c', which has
no children. It is therefore possible to access the 'c' leaf resource like so:

1 root['a']['b']['c']

If you returned the above root object from a root factory, the path /a/b/c would find the 'c' object
in the resource tree as the result of traversal.

In this example, each of the resources in the tree is of the same class. This is not a requirement. Resource
elements in the tree can be of any type. We used a single class to represent all resources in the tree for the
sake of simplicity, but in a ”real” app, the resources in the tree can be arbitrary.

Although the example tree above can service a traversal, the resource instances in the above example are
not aware of location, so their utility in a ”real” application is limited. To make best use of built-in Pyramid
API facilities, your resources should be ”location-aware”. The next section details how to make resources
location-aware.

576 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Location-Aware Resources

In order for certain Pyramid location, security, URL-generation, and traversal APIs to work properly against
the resources in a resource tree, all resources in the tree must be location-aware. This means they must
have two attributes: __parent__ and __name__.

The __parent__ attribute of a location-aware resource should be a reference to the resource’s parent
resource instance in the tree. The __name__ attribute should be the name with which a resource’s parent
refers to the resource via __getitem__.

The __parent__ of the root resource should be None and its __name__ should be the empty string.
For instance:

1 class MyRootResource(object):
2 __name__ = ''
3 __parent__ = None

A resource returned from the root resource’s __getitem__ method should have a __parent__ at-
tribute that is a reference to the root resource, and its __name__ attribute should match the name by
which it is reachable via the root resource’s __getitem__. A container resource within the root re-
source should have a __getitem__ that returns resources with a __parent__ attribute that points at
the container, and these sub-objects should have a __name__ attribute that matches the name by which
they are retrieved from the container via __getitem__. This pattern continues recursively ”up” the tree
from the root.

The __parent__ attributes of each resource form a linked list that points ”downwards” toward the root.
This is analogous to the .. entry in filesystem directories. If you follow the __parent__ values from any
resource in the resource tree, you will eventually come to the root resource, just like if you keep executing
the cd .. filesystem command, eventually you will reach the filesystem root directory.

If your root resource has a __name__ argument that is not None or the empty string, URLs
returned by the resource_url() function, and paths generated by the resource_path() and
resource_path_tuple() APIs, will be generated improperly. The value of __name__ will
be prepended to every path and URL generated (as opposed to a single leading slash or empty tuple
element).

0.3. Narrative Documentation 577


The Pyramid Web Framework, Version 2.0.2

For your convenience

If you’d rather not manage the __name__ and __parent__ attributes of your resources ”by hand”,
an add-on package named pyramid_traversalwrapper can help.

In order to use this helper feature, you must first install the pyramid_traversalwrapper package
(available via PyPI), then register its ModelGraphTraverser as the traversal policy, rather than the
default Pyramid traverser. The package contains instructions for doing so.

Once Pyramid is configured with this feature, you will no longer need to manage the __parent__ and
__name__ attributes on resource objects ”by hand”. Instead, as necessary during traversal, Pyramid
will wrap each resource (even the root resource) in a LocationProxy, which will dynamically assign
a __name__ and a __parent__ to the traversed resource, based on the last traversed resource and
the name supplied to __getitem__. The root resource will have a __name__ attribute of None
and a __parent__ attribute of None.

Applications which use tree-walking Pyramid APIs require location-aware resources.


These APIs include (but are not limited to) resource_url(), find_resource(),
find_root(), find_interface(), resource_path(), resource_path_tuple(),
traverse(), virtual_root(), and (usually) has_permission() and princi-
pals_allowed_by_permission().

In general, since so much Pyramid infrastructure depends on location-aware resources, it’s a good idea to
make each resource in your tree location-aware.

Generating the URL of a Resource

If your resources are location-aware, you can use the pyramid.request.Request.


resource_url() API to generate a URL for the resource. This URL will use the resource’s
position in the parent tree to create a resource path, and it will prefix the path with the current application
URL to form a fully-qualified URL with the scheme, host, port, and path. You can also pass extra
arguments to resource_url() to influence the generated URL.

The simplest call to resource_url() looks like this:

1 url = request.resource_url(resource)

578 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The request in the above example is an instance of a Pyramid request object.

If the resource referred to as resource in the above example was the root resource, and the host that
was used to contact the server was example.com, the URL generated would be http://example.
com/. However, if the resource was a child of the root resource named a, the generated URL would be
http://example.com/a/.

A slash is appended to all resource URLs when resource_url() is used to generate them in this simple
manner, because resources are ”places” in the hierarchy, and URLs are meant to be clicked on to be visited.
Relative URLs that you include on HTML pages rendered as the result of the default view of a resource
are more apt to be relative to these resources than relative to their parent.

You can also pass extra elements to resource_url():

1 url = request.resource_url(resource, 'foo', 'bar')

If the resource referred to as resource in the above example was the root resource, and the host that
was used to contact the server was example.com, the URL generated would be http://example.
com/foo/bar. Any number of extra elements can be passed to resource_url() as extra positional
arguments. When extra elements are passed, they are appended to the resource’s URL. A slash is not
appended to the final segment when elements are passed.

You can also pass a query string:

1 url = request.resource_url(resource, query={'a':'1'})

If the resource referred to as resource in the above example was the root resource, and the host that
was used to contact the server was example.com, the URL generated would be http://example.
com/?a=1.

When a virtual root is active, the URL generated by resource_url() for a resource may be ”shorter”
than its physical tree path. See Virtual Root Support for more information about virtually rooting a re-
source.

For more information about generating resource URLs, see the documentation for pyramid.request.
Request.resource_url().

0.3. Narrative Documentation 579


The Pyramid Web Framework, Version 2.0.2

Overriding Resource URL Generation

If a resource object implements a __resource_url__ method, this method will be called when re-
source_url() is called to generate a URL for the resource, overriding the default URL returned for
the resource by resource_url().

The __resource_url__ hook is passed two arguments: request and info. request is the re-
quest object passed to resource_url(). info is a dictionary with the following keys:

physical_path
A string representing the ”physical path” computed for the resource, as defined by pyramid.
traversal.resource_path(resource). It will begin and end with a slash.

virtual_path
A string representing the ”virtual path” computed for the resource, as defined by Virtual Root Sup-
port. This will be identical to the physical path if virtual rooting is not enabled. It will begin and
end with a slash.

app_url
A string representing the application URL generated during request.resource_url. It will
not end with a slash. It represents a potentially customized URL prefix, containing potentially custom
scheme, host and port information passed by the user to request.resource_url. It should be
preferred over use of request.application_url.

The __resource_url__ method of a resource should return a string representing a URL. If it cannot
override the default, it should return None. If it returns None, the default URL will be returned.

Here’s an example __resource_url__ method.

1 class Resource(object):
2 def __resource_url__(self, request, info):
3 return info['app_url'] + info['virtual_path']

The above example actually just generates and returns the default URL, which would have been what
was generated by the default resource_url machinery, but your code can perform arbitrary logic as
necessary. For example, your code may wish to override the hostname or port number of the generated
URL.

Note that the URL generated by __resource_url__ should be fully qualified, should end in a slash,
and should not contain any query string or anchor elements (only path elements) to work with re-
source_url().

580 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Generating the Path To a Resource

pyramid.traversal.resource_path() returns a string object representing the absolute physical


path of the resource object based on its position in the resource tree. Each segment of the path is separated
with a slash character.

1 from pyramid.traversal import resource_path


2 url = resource_path(resource)

If resource in the example above was accessible in the tree as root['a']['b'], the above example
would generate the string /a/b.

Any positional arguments passed in to resource_path() will be appended as path segments to the
end of the resource path.

1 from pyramid.traversal import resource_path


2 url = resource_path(resource, 'foo', 'bar')

If resource in the example above was accessible in the tree as root['a']['b'], the above example
would generate the string /a/b/foo/bar.

The resource passed in must be location-aware.

The presence or absence of a virtual root has no impact on the behavior of resource_path().

Finding a Resource by Path

If you have a string path to a resource, you can grab the resource from that place in the application’s
resource tree using pyramid.traversal.find_resource().

You can resolve an absolute path by passing a string prefixed with a / as the path argument:

1 from pyramid.traversal import find_resource


2 url = find_resource(anyresource, '/path')

Or you can resolve a path relative to the resource that you pass in to pyramid.traversal.
find_resource() by passing a string that isn’t prefixed by /:

0.3. Narrative Documentation 581


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.traversal import find_resource


2 url = find_resource(anyresource, 'path')

Often the paths you pass to find_resource() are generated by the resource_path() API. These
APIs are ”mirrors” of each other.

If the path cannot be resolved when calling find_resource() (if the respective resource in the tree
does not exist), a KeyError will be raised.

See the pyramid.traversal.find_resource() documentation for more information about re-


solving a path to a resource.

Obtaining the Lineage of a Resource

pyramid.location.lineage() returns a generator representing the lineage of the location-aware


resource object.

The lineage() function returns the resource that is passed into it, then each parent of the resource in
order. For example, if the resource tree is composed like so:

1 class Thing(object): pass


2

3 thing1 = Thing()
4 thing2 = Thing()
5 thing2.__parent__ = thing1

Calling lineage(thing2) will return a generator. When we turn it into a list, we will get:

1 list(lineage(thing2))
2 [ <Thing object at thing2>, <Thing object at thing1> ]

The generator returned by lineage() first returns unconditionally the resource that was passed into
it. Then, if the resource supplied a __parent__ attribute, it returns the resource represented by
resource.__parent__. If that resource has a __parent__ attribute, it will return that resource’s
parent, and so on, until the resource being inspected either has no __parent__ attribute or has a __par-
ent__ attribute of None.

See the documentation for pyramid.location.lineage() for more information.

582 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Determining if a Resource is in the Lineage of Another Resource

Use the pyramid.location.inside() function to determine if one resource is in the lineage of


another resource.

For example, if the resource tree is:

1 class Thing(object): pass


2

3 a = Thing()
4 b = Thing()
5 b.__parent__ = a

Calling inside(b, a) will return True, because b has a lineage that includes a. However, calling
inside(a, b) will return False because a does not have a lineage that includes b.

The argument list for inside() is (resource1, resource2). resource1 is ”inside” re-
source2 if resource2 is a lineage ancestor of resource1. It is a lineage ancestor if its parent (or
one of its parent’s parents, etc.) is an ancestor.

See pyramid.location.inside() for more information.

Finding the Root Resource

Use the pyramid.traversal.find_root() API to find the root resource. The root resource is
the resource at the root of the resource tree. The API accepts a single argument: resource. This is a
resource that is location-aware. It can be any resource in the tree for which you want to find the root.

For example, if the resource tree is:

1 class Thing(object): pass


2

3 a = Thing()
4 b = Thing()
5 b.__parent__ = a

Calling find_root(b) will return a.

The root resource is also available as request.root within view callable code.

The presence or absence of a virtual root has no impact on the behavior of find_root(). The root
object returned is always the physical root object.

0.3. Narrative Documentation 583


The Pyramid Web Framework, Version 2.0.2

Resources Which Implement Interfaces

Resources can optionally be made to implement an interface. An interface is used to tag a resource object
with a ”type” that later can be referred to within view configuration and by pyramid.traversal.
find_interface().

Specifying an interface instead of a class as the context or containment predicate arguments within
view configuration statements makes it possible to use a single view callable for more than one class of
resource objects. If your application is simple enough that you see no reason to want to do this, you can
skip reading this section of the chapter.

For example, here’s some code which describes a blog entry which also declares that the blog entry im-
plements an interface.

1 import datetime
2 from zope.interface import implementer
3 from zope.interface import Interface
4

5 class IBlogEntry(Interface):
6 pass
7

8 @implementer(IBlogEntry)
9 class BlogEntry(object):
10 def __init__(self, title, body, author):
11 self.title = title
12 self.body = body
13 self.author = author
14 self.created = datetime.datetime.now()

This resource consists of two things: the class which defines the resource constructor as the class BlogEn-
try, and an interface attached to the class via an implementer class decorator using the IBlogEntry
interface as its sole argument.

The interface object used must be an instance of a class that inherits from zope.interface.
Interface.

A resource class may implement zero or more interfaces. You specify that a resource implements an
interface by using the zope.interface.implementer() function as a class decorator. The above
BlogEntry resource implements the IBlogEntry interface.

You can also specify that a particular resource instance provides an interface as opposed to its class. When
you declare that a class implements an interface, all instances of that class will also provide that interface.
However, you can also just say that a single object provides the interface. To do so, use the zope.
interface.directlyProvides() function:

584 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 import datetime
2 from zope.interface import directlyProvides
3 from zope.interface import Interface
4

5 class IBlogEntry(Interface):
6 pass
7

8 class BlogEntry(object):
9 def __init__(self, title, body, author):
10 self.title = title
11 self.body = body
12 self.author = author
13 self.created = datetime.datetime.now()
14

15 entry = BlogEntry('title', 'body', 'author')


16 directlyProvides(entry, IBlogEntry)

zope.interface.directlyProvides() will replace any existing interface that was previously


provided by an instance. If a resource object already has instance-level interface declarations that you
don’t want to replace, use the zope.interface.alsoProvides() function:

1 import datetime
2 from zope.interface import alsoProvides
3 from zope.interface import directlyProvides
4 from zope.interface import Interface
5

6 class IBlogEntry1(Interface):
7 pass
8

9 class IBlogEntry2(Interface):
10 pass
11

12 class BlogEntry(object):
13 def __init__(self, title, body, author):
14 self.title = title
15 self.body = body
16 self.author = author
17 self.created = datetime.datetime.now()
18

19 entry = BlogEntry('title', 'body', 'author')


20 directlyProvides(entry, IBlogEntry1)
21 alsoProvides(entry, IBlogEntry2)

zope.interface.alsoProvides() will augment the set of interfaces directly provided by an in-


stance instead of overwriting them like zope.interface.directlyProvides() does.

0.3. Narrative Documentation 585


The Pyramid Web Framework, Version 2.0.2

For more information about how resource interfaces can be used by view configuration, see Using Resource
Interfaces in View Configuration.

Finding a Resource with a Class or Interface in Lineage

Use the find_interface() API to locate a parent that is of a particular Python class, or which im-
plements some interface.

For example, if your resource tree is composed as follows:

1 class Thing1(object): pass


2 class Thing2(object): pass
3

4 a = Thing1()
5 b = Thing2()
6 b.__parent__ = a

Calling find_interface(a, Thing1) will return the a resource because a is of class Thing1 (the
resource passed as the first argument is considered first, and is returned if the class or interface specification
matches).

Calling find_interface(b, Thing1) will return the a resource because a is of class Thing1 and
a is the first resource in b’s lineage of this class.

Calling find_interface(b, Thing2) will return the b resource.

The second argument to find_interface may also be a interface instead of a class. If it is an interface,
each resource in the lineage is checked to see if the resource implements the specificed interface (instead
of seeing if the resource is of a class).

See also:

See also Resources Which Implement Interfaces.

586 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Pyramid API Functions That Act Against Resources

A resource object is used as the context provided to a view. See Traversal and URL Dispatch for more
information about how a resource object becomes the context.

The APIs provided by pyramid.traversal are used against resource objects. These functions can be used to
find the ”path” of a resource, the root resource in a resource tree, or to generate a URL for a resource.

The APIs provided by pyramid.location are used against resources. These can be used to walk down a
resource tree, or conveniently locate one resource ”inside” another.

Some APIs on the pyramid.request.Request accept a resource object as a parameter. For example,
the has_permission() API accepts a resource object as one of its arguments; the ACL is obtained
from this resource or one of its ancestors. Other security related APIs on the pyramid.request.
Request class also accept context as an argument, and a context is always a resource.

0.3.25 Hello Traversal World

Traversal is an alternative to URL dispatch which allows Pyramid applications to map URLs to code.

If code speaks louder than words, maybe this will help. Here is a single-file Pyramid application that uses
traversal:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4

6 class Resource(dict):
7 pass
8

10 def get_root(request):
11 return Resource({'a': Resource({'b': Resource({'c': Resource()})})})
12

13

14 def hello_world_of_resources(context, request):


15 output = "Here's a resource and its children: %s" % context
16 return Response(output)
17

18

(continues on next page)

0.3. Narrative Documentation 587


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


19 if __name__ == '__main__':
20 with Configurator() as config:
21 config.set_root_factory(get_root)
22 config.add_view(hello_world_of_resources, context=Resource)
23 app = config.make_wsgi_app()
24 server = make_server('0.0.0.0', 6543, app)
25 server.serve_forever()

You may notice that this application is intentionally very similar to the ”hello world” application from
Creating Your First Pyramid Application.
On lines 6-7, we create a trivial resource class that’s just a dictionary subclass.
On lines 10-11, we hard-code a resource tree in our root factory function.
On lines 14-15, we define a single view callable that can display a single instance of our Resource class,
passed as the context argument.
The rest of the file sets up and serves our Pyramid WSGI app. Line 22 is where our view gets configured
for use whenever the traversal ends with an instance of our Resource class.
Interestingly, there are no URLs explicitly configured in this application. Instead, the URL space is defined
entirely by the keys in the resource tree.

Example requests

If this example is running on http://localhost:6543, and the user browses to http://localhost:6543/a/b, Pyra-
mid will call get_root(request) to get the root resource, then traverse the tree from there by key;
starting from the root, it will find the child with key "a", then its child with key "b"; then use that as the
context argument for calling hello_world_of_resources.
Or, if the user browses to http://localhost:6543/, Pyramid will stop at the root—the outermost Resource
instance, in this case—and use that as the context argument to the same view.
Or, if the user browses to a key that doesn’t exist in this resource tree, like http://localhost:6543/xyz or
http://localhost:6543/a/b/c/d, the traversal will end by raising a KeyError, and Pyramid will turn that into
a 404 HTTP response.
A more complicated application could have many types of resources, with different view callables defined
for each type, and even multiple views for each type.
See also:
Full technical details may be found in Traversal.
For more about why you might use traversal, see Much Ado About Traversal.

588 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.3.26 Much Ado About Traversal

(Or, why you should care about it.)

This chapter was adapted, with permission, from a blog post by Rob Miller.

Traversal is an alternative to URL dispatch which allows Pyramid applications to map URLs to code.

Ex-Zope users who are already familiar with traversal and view lookup conceptually may want to
skip directly to the Traversal chapter, which discusses technical details. This chapter is mostly aimed at
people who have previous Pylons experience or experience in another framework which does not provide
traversal, and need an introduction to the ”why” of traversal.

Some folks who have been using Pylons and its Routes-based URL matching for a long time are being
exposed for the first time, via Pyramid, to new ideas such as ”traversal” and ”view lookup” as a way to
route incoming HTTP requests to callable code. Some of the same folks believe that traversal is hard to
understand. Others question its usefulness; URL matching has worked for them so far, so why should they
even consider dealing with another approach, one which doesn’t fit their brain and which doesn’t provide
any immediately obvious value?

You can be assured that if you don’t want to understand traversal, you don’t have to. You can happily build
Pyramid applications with only URL dispatch. However, there are some straightforward, real-world use
cases that are much more easily served by a traversal-based approach than by a pattern-matching mecha-
nism. Even if you haven’t yet hit one of these use cases yourself, understanding these new ideas is worth
the effort for any web developer so you know when you might want to use them. Traversal is actually a
straightforward metaphor easily comprehended by anyone who’s ever used a run-of-the-mill file system
with folders and files.

URL Dispatch

Let’s step back and consider the problem we’re trying to solve. An HTTP request for a particular path
has been routed to our web application. The requested path will possibly invoke a specific view callable
function defined somewhere in our app. We’re trying to determine which callable function, if any, should
be invoked for a given requested URL.

Many systems, including Pyramid, offer a simple solution. They offer the concept of ”URL matching”.
URL matching approaches this problem by parsing the URL path and comparing the results to a set of

0.3. Narrative Documentation 589


The Pyramid Web Framework, Version 2.0.2

registered ”patterns”, defined by a set of regular expressions or some other URL path templating syntax.
Each pattern is mapped to a callable function somewhere; if the request path matches a specific pattern, the
associated function is called. If the request path matches more than one pattern, some conflict resolution
scheme is used, usually a simple order precedence so that the first match will take priority over any subse-
quent matches. If a request path doesn’t match any of the defined patterns, a ”404 Not Found” response is
returned.

In Pyramid, we offer an implementation of URL matching which we call URL dispatch. Using Pyra-
mid syntax, we might have a match pattern such as /{userid}/photos/{photoid}, mapped to
a photo_view() function defined somewhere in our code. Then a request for a path such as /
joeschmoe/photos/photo1 would be a match, and the photo_view() function would be in-
voked to handle the request. Similarly, /{userid}/blog/{year}/{month}/{postid} might
map to a blog_post_view() function, so /joeschmoe/blog/2010/12/urlmatching would
trigger the function, which presumably would know how to find and render the urlmatching blog post.

Historical Refresher

Now that we’ve refreshed our understanding of URL dispatch, we’ll dig in to the idea of traversal. Before
we do, though, let’s take a trip down memory lane. If you’ve been doing web work for a while, you
may remember a time when we didn’t have fancy web frameworks like Pylons and Pyramid. Instead, we
had general purpose HTTP servers that primarily served files off of a file system. The ”root” of a given
site mapped to a particular folder somewhere on the file system. Each segment of the request URL path
represented a subdirectory. The final path segment would be either a directory or a file, and once the server
found the right file it would package it up in an HTTP response and send it back to the client. So serving
up a request for /joeschmoe/photos/photo1 literally meant that there was a joeschmoe folder
somewhere, which contained a photos folder, which in turn contained a photo1 file. If at any point
along the way we find that there is not a folder or file matching the requested path, we return a 404 response.

As the web grew more dynamic, however, a little bit of extra complexity was added. Technologies such as
CGI and HTTP server modules were developed. Files were still looked up on the file system, but if the file
ended with (for example) .cgi or .php, or if it lived in a special folder, instead of simply sending the
file to the client the server would read the file, execute it using an interpreter of some sort, and then send
the output from this process to the client as the final result. The server configuration specified which files
would trigger some dynamic code, with the default case being to just serve the static file.

Traversal (a.k.a., Resource Location)

Believe it or not, if you understand how serving files from a file system works, you understand traversal.
And if you understand that a server might do something different based on what type of file a given request
specifies, then you understand view lookup.

590 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The major difference between file system lookup and traversal is that a file system lookup steps through
nested directories and files in a file system tree, while traversal steps through nested dictionary-type objects
in a resource tree. Let’s take a detailed look at one of our example paths, so we can see what I mean.

The path /joeschmoe/photos/photo1, has four segments: /, joeschmoe, photos and


photo1. With file system lookup we might have a root folder (/) containing a nested folder
(joeschmoe), which contains another nested folder (photos), which finally contains a JPG file
(photo1). With traversal, we instead have a dictionary-like root object. Asking for the joeschmoe key
gives us another dictionary-like object. Asking in turn for the photos key gives us yet another mapping
object, which finally (hopefully) contains the resource that we’re looking for within its values, referenced
by the photo1 key.

In pure Python terms, then, the traversal or ”resource location” portion of satisfying the /joeschmoe/
photos/photo1 request will look something like this pseudocode:

get_root()['joeschmoe']['photos']['photo1']

get_root() is some function that returns a root traversal resource. If all of the specified keys exist, then
the returned object will be the resource that is being requested, analogous to the JPG file that was retrieved
in the file system example. If a KeyError is generated anywhere along the way, Pyramid will return 404.
(This isn’t precisely true, as you’ll see when we learn about view lookup below, but the basic idea holds.)

What Is a ”Resource”?

”Files on a file system I understand”, you might say. ”But what are these nested dictionary things? Where
do these objects, these ’resources’, live? What are they?”

Since Pyramid is not a highly opinionated framework, it makes no restriction on how a resource is im-
plemented; a developer can implement them as they wish. One common pattern used is to persist all
of the resources, including the root, in a database as a graph. The root object is a dictionary-like ob-
ject. Dictionary-like objects in Python supply a __getitem__ method which is called when key lookup
is done. Under the hood, when adict is a dictionary-like object, Python translates adict['a'] to
adict.__getitem__('a'). Try doing this in a Python interpreter prompt if you don’t believe us:

>>> adict = {}
>>> adict['a'] = 1
>>> adict['a']
1
>>> adict.__getitem__('a')
1

0.3. Narrative Documentation 591


The Pyramid Web Framework, Version 2.0.2

The dictionary-like root object stores the ids of all of its subresources as keys, and provides a
__getitem__ implementation that fetches them. So get_root() fetches the unique root object,
while get_root()['joeschmoe'] returns a different object, also stored in the database, which in
turn has its own subresources and __getitem__ implementation, and so on. These resources might be
persisted in a relational database, one of the many ”NoSQL” solutions that are becoming popular these
days, or anywhere else; it doesn’t matter. As long as the returned objects provide the dictionary-like API
(i.e., as long as they have an appropriately implemented __getitem__ method), then traversal will work.

In fact, you don’t need a ”database” at all. You could use plain dictionaries, with your site’s URL struc-
ture hard-coded directly in the Python source. Or you could trivially implement a set of objects with
__getitem__ methods that search for files in specific directories, and thus precisely recreate the tradi-
tional mechanism of having the URL path mapped directly to a folder structure on the file system. Traversal
is in fact a superset of file system lookup.

See the chapter entitled Resources for a more technical overview of resources.

View Lookup

At this point we’re nearly there. We’ve covered traversal, which is the process by which a specific resource
is retrieved according to a specific URL path. But what is ”view lookup”?

The need for view lookup is simple: there is more than one possible action that you might want to take
after finding a resource. With our photo example, for instance, you might want to view the photo in a
page, but you might also want to provide a way for the user to edit the photo and any associated metadata.
We’ll call the former the view view, and the latter will be the edit view. (Original, I know.) Pyramid
has a centralized view application registry where named views can be associated with specific resource
types. So in our example, we’ll assume that we’ve registered view and edit views for photo objects, and
that we’ve specified the view view as the default, so that /joeschmoe/photos/photo1/view and
/joeschmoe/photos/photo1 are equivalent. The edit view would sensibly be provided by a request
for /joeschmoe/photos/photo1/edit.

Hopefully it’s clear that the first portion of the edit view’s URL path is going to re-
solve to the same resource as the non-edit version, specifically the resource returned by
get_root()['joeschmoe']['photos']['photo1']. But traversal ends there; the photo1
resource doesn’t have an edit key. In fact, it might not even be a dictionary-like object, in which case
photo1['edit'] would be meaningless. When the Pyramid resource location has been resolved to
a leaf resource, but the entire request path has not yet been expended, the very next path segment is
treated as a view name. The registry is then checked to see if a view of the given name has been specified
for a resource of the given type. If so, the view callable is invoked, with the resource passed in as the

592 CONTENTS
The Pyramid Web Framework, Version 2.0.2

related context object (also available as request.context). If a view callable could not be found,
Pyramid will return a ”404 Not Found” response.

You might conceptualize a request for /joeschmoe/photos/photo1/edit as ultimately converted


into the following piece of Pythonic pseudocode:

context = get_root()['joeschmoe']['photos']['photo1']
view_callable = get_view(context, 'edit')
request.context = context
view_callable(request)

The get_root and get_view functions don’t really exist. Internally, Pyramid does something more
complicated. But the example above is a reasonable approximation of the view lookup algorithm in pseu-
docode.

Use Cases

Why should we care about traversal? URL matching is easier to explain, and it’s good enough, right?

In some cases, yes, but certainly not in all cases. So far we’ve had very structured URLs, where our paths
have had a specific, small number of pieces, like this:

/{userid}/{typename}/{objectid}[/{view_name}]

In all of the examples thus far, we’ve hard coded the typename value, assuming that we’d know at de-
velopment time what names were going to be used (”photos”, ”blog”, etc.). But what if we don’t know
what these names will be? Or, worse yet, what if we don’t know anything about the structure of the URLs
inside a user’s folder? We could be writing a CMS where we want the end user to be able to arbitrarily add
content and other folders inside his folder. He might decide to nest folders dozens of layers deep. How
will you construct matching patterns that could account for every possible combination of paths that might
develop?

It might be possible, but it certainly won’t be easy. The matching patterns are going to become complex
quickly as you try to handle all of the edge cases.

With traversal, however, it’s straightforward. Twenty layers of nesting would be no problem. Pyramid
will happily call __getitem__ as many times as it needs to, until it runs out of path segments or until
a resource raises a KeyError. Each resource only needs to know how to fetch its immediate children,
and the traversal algorithm takes care of the rest. Also, since the structure of the resource tree can live

0.3. Narrative Documentation 593


The Pyramid Web Framework, Version 2.0.2

in the database and not in the code, it’s simple to let users modify the tree at runtime to set up their own
personalized ”directory” structures.

Another use case in which traversal shines is when there is a need to support a context-dependent secu-
rity policy. One example might be a document management infrastructure for a large corporation, where
members of different departments have varying access levels to the various other departments’ files. Rea-
sonably, even specific files might need to be made available to specific individuals. Traversal does well
here if your resources actually represent the data objects related to your documents, because the idea of
a resource authorization is baked right into the code resolution and calling process. Resource objects can
store ACLs, which can be inherited and/or overridden by the subresources.

If each resource can thus generate a context-based ACL, then whenever view code is attempting to perform a
sensitive action, it can check against that ACL to see whether the current user should be allowed to perform
the action. In this way you achieve so called ”instance based” or ”row level” security which is considerably
harder to model using a traditional tabular approach. Pyramid actively supports such a scheme, and in fact
if you register your views with guarded permissions and use an authorization policy, Pyramid can check
against a resource’s ACL when deciding whether or not the view itself is available to the current user.

In summary, there are entire classes of problems that are more easily served by traversal and view lookup
than by URL dispatch. If your problems don’t require it, great, stick with URL dispatch. But if you’re
using Pyramid and you ever find that you do need to support one of these use cases, you’ll be glad you
have traversal in your toolkit.

It is even possible to mix and match traversal with URL dispatch in the same Pyramid application.
See the Combining Traversal and URL Dispatch chapter for details.

0.3.27 Traversal

This chapter explains the technical details of how traversal works in Pyramid.

For a quick example, see Hello Traversal World.

For more about why you might use traversal, see Much Ado About Traversal.

A traversal uses the URL (Universal Resource Locator) to find a resource located in a resource tree, which
is a set of nested dictionary-like objects. Traversal is done by using each segment of the path portion of the
URL to navigate through the resource tree. You might think of this as looking up files and directories in
a file system. Traversal walks down the path until it finds a published resource, analogous to a file system
”directory” or ”file”. The resource found as the result of a traversal becomes the context of the request.

594 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Then, the view lookup subsystem is used to find some view code willing to ”publish” this resource by
generating a response.

Using Traversal to map a URL to code is optional. If you’re creating your first Pyramid application, it
probably makes more sense to use URL dispatch to map URLs to code instead of traversal, as new Pyramid
developers tend to find URL dispatch slightly easier to understand. If you use URL dispatch, you needn’t
read this chapter.

Traversal Details

Traversal is dependent on information in a request object. Every request object contains URL path infor-
mation in the PATH_INFO portion of the WSGI environment. The PATH_INFO string is the portion of a
request’s URL following the hostname and port number, but before any query string elements or fragment
element. For example the PATH_INFO portion of the URL http://example.com:8080/a/b/c?
foo=1 is /a/b/c.

Traversal treats the PATH_INFO segment of a URL as a sequence of path segments. For example, the
PATH_INFO string /a/b/c is converted to the sequence ['a', 'b', 'c'].

This path sequence is then used to descend through the resource tree, looking up a resource for each path
segment. Each lookup uses the __getitem__ method of a resource in the tree.

For example, if the path info sequence is ['a', 'b', 'c']:

• Traversal starts by acquiring the root resource of the application by calling the root factory. The
root factory can be configured to return whatever object is appropriate as the traversal root of your
application.

• Next, the first element ('a') is popped from the path segment sequence and is used as a key to
lookup the corresponding resource in the root. This invokes the root resource’s __getitem__
method using that value ('a') as an argument.

• If the root resource ”contains” a resource with key 'a', its __getitem__ method will return it.
The context temporarily becomes the ”A” resource.

• The next segment ('b') is popped from the path sequence, and the ”A” resource’s __getitem__
is called with that value ('b') as an argument; we’ll presume it succeeds.

• The ”A” resource’s __getitem__ returns another resource, which we’ll call ”B”. The context
temporarily becomes the ”B” resource.

0.3. Narrative Documentation 595


The Pyramid Web Framework, Version 2.0.2

Traversal continues until the path segment sequence is exhausted or a path element cannot be resolved to
a resource. In either case, the context resource is the last object that the traversal successfully resolved.
If any resource found during traversal lacks a __getitem__ method, or if its __getitem__ method
raises a KeyError, traversal ends immediately, and that resource becomes the context.

The results of a traversal also include a view name. If traversal ends before the path segment sequence is
exhausted, the view name is the next remaining path segment element. If the traversal expends all of the
path segments, then the view name is the empty string ('').

The combination of the context resource and the view name found via traversal is used later in the same
request by the view lookup subsystem to find a view callable. How Pyramid performs view lookup is
explained within the View Configuration chapter.

The Resource Tree

The resource tree is a set of nested dictionary-like resource objects that begins with a root resource. In
order to use traversal to resolve URLs to code, your application must supply a resource tree to Pyramid.

In order to supply a root resource for an application the Pyramid Router is configured with a callback known
as a root factory. The root factory is supplied by the application at startup time as the root_factory
argument to the Configurator.

The root factory is a Python callable that accepts a request object, and returns the root object of the resource
tree. A function or class is typically used as an application’s root factory. Here’s an example of a simple
root factory class:

1 class Root(dict):
2 def __init__(self, request):
3 pass

Here’s an example of using this root factory within startup configuration, by passing it to an instance of a
Configurator named config:

1 config = Configurator(root_factory=Root)

The root_factory argument to the Configurator constructor registers this root factory to be called
to generate a root resource whenever a request enters the application. The root factory registered this way
is also known as the global root factory. A root factory can alternatively be passed to the Configurator
as a dotted Python name which can refer to a root factory defined in a different module.

596 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If no root factory is passed to the Pyramid Configurator constructor, or if the root_factory value
specified is None, a default root factory is used. The default root factory always returns a resource that
has no child resources; it is effectively empty.

Usually a root factory for a traversal-based application will be more complicated than the above Root
class. In particular it may be associated with a database connection or another persistence mechanism.
The above Root class is analogous to the default root factory present in Pyramid. The default root factory
is very simple and not very useful.

If the items contained within the resource tree are ”persistent” (they have state that lasts longer than
the execution of a single process), they become analogous to the concept of domain model objects used by
many other frameworks.

The resource tree consists of container resources and leaf resources. There is only one difference between
a container resource and a leaf resource: container resources possess a __getitem__ method (making
it ”dictionary-like”) while leaf resources do not. The __getitem__ method was chosen as the signifying
difference between the two types of resources because the presence of this method is how Python itself
typically determines whether an object is ”containerish” or not (dictionary objects are ”containerish”).

Each container resource is presumed to be willing to return a child resource or raise a KeyError based
on a name passed to its __getitem__.

Leaf-level instances must not have a __getitem__. If instances that you’d like to be leaves already
happen to have a __getitem__ through some historical inequity, you should subclass these resource
types and cause their __getitem__ methods to simply raise a KeyError. Or just disuse them and
think up another strategy.

Usually the traversal root is a container resource, and as such it contains other resources. However, it
doesn’t need to be a container. Your resource tree can be as shallow or as deep as you require.

In general, the resource tree is traversed beginning at its root resource using a sequence of path elements
described by the PATH_INFO of the current request. If there are path segments, the root resource’s
__getitem__ is called with the next path segment, and it is expected to return another resource. The
resulting resource’s __getitem__ is called with the very next path segment, and it is expected to return
another resource. This happens ad infinitum until all path segments are exhausted.

0.3. Narrative Documentation 597


The Pyramid Web Framework, Version 2.0.2

The Traversal Algorithm

This section will attempt to explain the Pyramid traversal algorithm. We’ll provide a description of the
algorithm, a diagram of how the algorithm works, and some example traversal scenarios that might help
you understand how the algorithm operates against a specific resource tree.

We’ll also talk a bit about view lookup. The View Configuration chapter discusses view lookup in detail,
and it is the canonical source for information about views. Technically, view lookup is a Pyramid subsystem
that is separated from traversal entirely. However, we’ll describe the fundamental behavior of view lookup
in the examples in the next few sections to give you an idea of how traversal and view lookup cooperate,
because they are almost always used together.

A Description of the Traversal Algorithm

When a user requests a page from your traversal-powered application, the system uses this algorithm to
find a context resource and a view name.

1. The request for the page is presented to the Pyramid router in terms of a standard WSGI request,
which is represented by a WSGI environment and a WSGI start_response callable.

2. The router creates a request object based on the WSGI environment.

3. The root factory is called with the request. It returns a root resource.

4. The router uses the WSGI environment’s PATH_INFO information to determine the path segments
to traverse. The leading slash is stripped off PATH_INFO, and the remaining path segments are
split on the slash character to form a traversal sequence.

The traversal algorithm by default attempts to first URL-unquote and then Unicode-decode each path
segment derived from PATH_INFO from its natural string representation. URL unquoting is per-
formed using the Python standard library urllib.unquote function. Conversion from a URL-
decoded string into Unicode is attempted using the UTF-8 encoding. If any URL-unquoted path seg-
ment in PATH_INFO is not decodeable using the UTF-8 decoding, a TypeError is raised. A seg-
ment will be fully URL-unquoted and UTF-8-decoded before it is passed in to the __getitem__
of any resource during traversal.

Thus a request with a PATH_INFO variable of /a/b/c maps to the traversal sequence ['a',
'b', 'c'].

598 CONTENTS
The Pyramid Web Framework, Version 2.0.2

5. Traversal begins at the root resource returned by the root factory. For the traversal sequence ['a',
'b', 'c'], the root resource’s __getitem__ is called with the name 'a'. Traversal continues
through the sequence. In our example, if the root resource’s __getitem__ called with the name
a returns a resource (a.k.a. resource ”A”), that resource’s __getitem__ is called with the name
'b'. If resource ”A” returns a resource ”B” when asked for 'b', resource B’s __getitem__ is
then asked for the name 'c', and may return resource ”C”.

6. Traversal ends when either (a) the entire path is exhausted, (b) when any resource raises a Key-
Error from its __getitem__, (c) when any non-final path element traversal does not have a
__getitem__ method (resulting in an AttributeError), or (d) when any path element is
prefixed with the set of characters @@ (indicating that the characters following the @@ token should
be treated as a view name).

7. When traversal ends for any of the reasons in the previous step, the last resource found during traver-
sal is deemed to be the context. If the path has been exhausted when traversal ends, the view name
is deemed to be the empty string (''). However, if the path was not exhausted before traversal
terminated, the first remaining path segment is treated as the view name.

8. Any subsequent path elements after the view name is found are deemed the subpath. The subpath is
always a sequence of path segments that come from PATH_INFO that are ”left over” after traversal
has completed.

Once the context resource, the view name, and associated attributes such as the subpath are located, the
job of traversal is finished. It passes back the information it obtained to its caller, the Pyramid Router,
which subsequently invokes view lookup with the context and view name information.

The traversal algorithm exposes two special cases:

• You will often end up with a view name that is the empty string as the result of a particular traversal.
This indicates that the view lookup machinery should lookup the default view. The default view is a
view that is registered with no name or a view which is registered with a name that equals the empty
string.

• If any path segment element begins with the special characters @@ (think of them as goggles), the
value of that segment minus the goggle characters is considered the view name immediately and
traversal stops there. This allows you to address views that may have the same names as resource
names in the tree unambiguously.

Finally, traversal is responsible for locating a virtual root. A virtual root is used during ”virtual hosting”.
See the Virtual Hosting chapter for information. We won’t speak more about it in this chapter.

0.3. Narrative Documentation 599


The Pyramid Web Framework, Version 2.0.2

600 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Traversal Algorithm Examples

No one can be expected to understand the traversal algorithm by analogy and description alone, so let’s
examine some traversal scenarios that use concrete URLs and resource tree compositions.

Let’s pretend the user asks for http://example.com/foo/bar/baz/biz/buz.txt. The re-


quest’s PATH_INFO in that case is /foo/bar/baz/biz/buz.txt. Let’s further pretend that when
this request comes in, we’re traversing the following resource tree:

/--
|
|-- foo
|
----bar

Here’s what happens:

• traversal traverses the root, and attempts to find ”foo”, which it finds.

• traversal traverses ”foo”, and attempts to find ”bar”, which it finds.

• traversal traverses ”bar”, and attempts to find ”baz”, which it does not find (the ”bar” resource raises
a KeyError when asked for ”baz”).

The fact that it does not find ”baz” at this point does not signify an error condition. It signifies the following:

• The context is the ”bar” resource (the context is the last resource found during traversal).

• The view name is baz.

• The subpath is ('biz', 'buz.txt').

At this point, traversal has ended, and view lookup begins.

Because it’s the ”context” resource, the view lookup machinery examines ”bar” to find out what ”type” it
is. Let’s say it finds that the context is a Bar type (because ”bar” happens to be an instance of the class
Bar). Using the view name (baz) and the type, view lookup asks the application registry this question:

• Please find me a view callable registered using a view configuration with the name ”baz” that can
be used for the class Bar.

Let’s say that view lookup finds no matching view type. In this circumstance, the Pyramid router returns
the result of the Not Found View and the request ends.

However, for this tree:

0.3. Narrative Documentation 601


The Pyramid Web Framework, Version 2.0.2

/--
|
|-- foo
|
----bar
|
----baz
|
biz

The user asks for http://example.com/foo/bar/baz/biz/buz.txt

• traversal traverses ”foo”, and attempts to find ”bar”, which it finds.

• traversal traverses ”bar”, and attempts to find ”baz”, which it finds.

• traversal traverses ”baz”, and attempts to find ”biz”, which it finds.

• traversal traverses ”biz”, and attempts to find ”buz.txt”, which it does not find.

The fact that it does not find a resource related to ”buz.txt” at this point does not signify an error condition.
It signifies the following:

• The context is the ”biz” resource (the context is the last resource found during traversal).

• The view name is ”buz.txt”.

• The subpath is an empty sequence ( () ).

At this point, traversal has ended, and view lookup begins.

Because it’s the ”context” resource, the view lookup machinery examines the ”biz” resource to find out
what ”type” it is. Let’s say it finds that the resource is a Biz type (because ”biz” is an instance of the
Python class Biz). Using the view name (buz.txt) and the type, view lookup asks the application
registry this question:

• Please find me a view callable registered with a view configuration with the name buz.txt that
can be used for class Biz.

Let’s say that question is answered by the application registry. In such a situation, the application registry
returns a view callable. The view callable is then called with the current WebOb request as the sole
argument, request. It is expected to return a response.

602 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The Example View Callables Accept Only a Request; How Do I Access the Context Resource?

Most of the examples in this documentation assume that a view callable is typically passed only a
request object. Sometimes your view callables need access to the context resource, especially when
you use traversal. You might use a supported alternative view callable argument list in your view
callables such as the (context, request) calling convention described in Alternate View Callable
Argument/Calling Conventions. But you don’t need to if you don’t want to. In view callables that accept
only a request, the context resource found by traversal is available as the context attribute of the
request object, e.g., request.context. The view name is available as the view_name attribute
of the request object, e.g., request.view_name. Other Pyramid-specific request attributes are also
available as described in Special Attributes Added to the Request by Pyramid.

Using Resource Interfaces in View Configuration

Instead of registering your views with a context that names a Python resource class, you can optionally
register a view callable with a context which is an interface. An interface can be attached arbitrarily to
any resource object. View lookup treats context interfaces specially, and therefore the identity of a resource
can be divorced from that of the class which implements it. As a result, associating a view with an interface
can provide more flexibility for sharing a single view between two or more different implementations of a
resource type. For example, if two resource objects of different Python class types share the same interface,
you can use the same view configuration to specify both of them as a context.

In order to make use of interfaces in your application during view dispatch, you must create an interface
and mark up your resource classes or instances with interface declarations that refer to this interface.

To attach an interface to a resource class, you define the interface and use the zope.interface.
implementer() class decorator to associate the interface with the class.

1 from zope.interface import Interface


2 from zope.interface import implementer
3

4 class IHello(Interface):
5 """ A marker interface """
6

7 @implementer(IHello)
8 class Hello(object):
9 pass

To attach an interface to a resource instance, you define the interface and use the zope.interface.
alsoProvides() function to associate the interface with the instance. This function mutates the in-
stance in such a way that the interface is attached to it.

0.3. Narrative Documentation 603


The Pyramid Web Framework, Version 2.0.2

1 from zope.interface import Interface


2 from zope.interface import alsoProvides
3

4 class IHello(Interface):
5 """ A marker interface """
6

7 class Hello(object):
8 pass
9

10 def make_hello():
11 hello = Hello()
12 alsoProvides(hello, IHello)
13 return hello

Regardless of how you associate an interface—with either a resource instance or a resource class—the
resulting code to associate that interface with a view callable is the same. Assuming the above code that
defines an IHello interface lives in the root of your application, and its module is named ”resources.py”,
the interface declaration below will associate the mypackage.views.hello_world view with re-
sources that implement, or provide, this interface.

1 # config is an instance of pyramid.config.Configurator


2

3 config.add_view('mypackage.views.hello_world', name='hello.html',
4 context='mypackage.resources.IHello')

Any time a resource that is determined to be the context provides this interface, and a view named hello.
html is looked up against it as per the URL, the mypackage.views.hello_world view callable
will be invoked.

Note, in cases where a view is registered against a resource class, and a view is also registered against an
interface that the resource class implements, an ambiguity arises. Views registered for the resource class
take precedence over any views registered for any interface the resource class implements. Thus, if one
view configuration names a context of both the class type of a resource, and another view configuration
names a context of interface implemented by the resource’s class, and both view configurations are
otherwise identical, the view registered for the context’s class will ”win”.

For more information about defining resources with interfaces for use within view configuration, see Re-
sources Which Implement Interfaces.

604 CONTENTS
The Pyramid Web Framework, Version 2.0.2

References

A tutorial showing how traversal can be used within a Pyramid application exists in ZODB + Traversal
Wiki Tutorial.

See the View Configuration chapter for detailed information about view lookup.

The pyramid.traversal module contains API functions that deal with traversal, such as traversal
invocation from within application code.

The pyramid.request.Request.resource_url() method generates a URL when given a re-


source retrieved from a resource tree.

0.3.28 Security

Pyramid provides an optional, declarative security system. The system determines the identity of the
current user (authentication) and whether or not the user has access to certain resources (authorization).

The Pyramid security system can prevent a view from being invoked based on the security policy. Before
a view is invoked, the authorization system can use the credentials in the request along with the context
resource to determine if access will be allowed. Here’s how it works at a high level:

• A user may or may not have previously visited the application and supplied authentication cre-
dentials, including a userid. If so, the application may have called pyramid.security.
remember() to remember these.

• A request is generated when a user visits the application.

• Based on the request, a context resource is located through resource location. A context is located
differently depending on whether the application uses traversal or URL dispatch, but a context is
ultimately found in either case. See the URL Dispatch chapter for more information.

• A view callable is located by view lookup using the context as well as other attributes of the request.

• If a security policy is in effect and the view configuration associated with the view callable that
was found has a permission associated with it, the policy is passed request, the context, and the
permission associated with the view; it will allow or deny access.

• If the security policy allows access, the view callable is invoked.

• If the security policy denies access, the view callable is not invoked. Instead the forbidden view is
invoked.

The security system is enabled by modifying your application to include a security policy. Pyramid comes
with a variety of helpers to assist in the creation of this policy.

0.3. Narrative Documentation 605


The Pyramid Web Framework, Version 2.0.2

Writing a Security Policy

Pyramid does not enable any security policy by default. All views are accessible by completely anonymous
users. In order to begin protecting views from execution based on security settings, you need to write a
security policy.

Security policies are simple classes implementing pyramid.interfaces.ISecurityPolicy. A


simple security policy might look like the following:

1 from pyramid.security import Allowed, Denied


2

3 class SessionSecurityPolicy:
4 def identity(self, request):
5 """ Return app-specific user object. """
6 userid = request.session.get('userid')
7 if userid is None:
8 return None
9 return load_identity_from_db(request, userid)
10

11 def authenticated_userid(self, request):


12 """ Return a string ID for the user. """
13 identity = self.identity(request)
14 if identity is None:
15 return None
16 return string(identity.id)
17

18 def permits(self, request, context, permission):


19 """ Allow access to everything if signed in. """
20 identity = self.identity(request)
21 if identity is not None:
22 return Allowed('User is signed in.')
23 else:
24 return Denied('User is not signed in.')
25

26 def remember(request, userid, **kw):


27 request.session['userid'] = userid
28 return []
29

30 def forget(request, **kw):


31 del request.session['userid']
32 return []

Use the set_security_policy() method of the Configurator to enforce the security policy on
your application.

606 CONTENTS
The Pyramid Web Framework, Version 2.0.2

See also:

For more information on implementing the permits method, see Allowing and Denying Access With a
Security Policy.

Writing a Security Policy Using Helpers

To assist in writing common security policies, Pyramid provides several helpers. The following authenti-
cation helpers assist with implementing identity, remember, and forget.

Use Case Helper


Store the userid in the session. pyramid.authentication.
SessionAuthenticationHelper
Store the userid with an ”auth ticket” pyramid.authentication.
cookie. AuthTktCookieHelper
Retrieve user credentials using HTTP Use pyramid.authentication.
Basic Auth. extract_http_basic_credentials() to retrieve
credentials.
Retrieve the userid from RE- REMOTE_USER can be accessed with request.
MOTE_USER in the WSGI environ- environ.get('REMOTE_USER').
ment.

For example, our above security policy can leverage these helpers like so:

1 from pyramid.security import Allowed, Denied


2 from pyramid.authentication import SessionAuthenticationHelper
3

4 class SessionSecurityPolicy:
5 def __init__(self):
6 self.helper = SessionAuthenticationHelper()
7

8 def identity(self, request):


9 """ Return app-specific user object. """
10 userid = self.helper.authenticated_userid(request)
11 if userid is None:
12 return None
13 return load_identity_from_db(request, userid)
14

15 def authenticated_userid(self, request):


(continues on next page)

0.3. Narrative Documentation 607


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


16 """ Return a string ID for the user. """
17 identity = self.identity(request)
18 if identity is None:
19 return None
20 return str(identity.id)
21

22 def permits(self, request, context, permission):


23 """ Allow access to everything if signed in. """
24 identity = self.identity(request)
25 if identity is not None:
26 return Allowed('User is signed in.')
27 else:
28 return Denied('User is not signed in.')
29

30 def remember(request, userid, **kw):


31 return self.helper.remember(request, userid, **kw)
32

33 def forget(request, **kw):


34 return self.helper.forget(request, **kw)

Helpers are intended to be used with application-specific code. Notice how the above code takes the userid
from the helper and uses it to load the identity from the database. authenticated_userid pulls the
userid from the identity in order to guarantee that the user ID stored in the session exists in the database
(”authenticated”).

Protecting Views with Permissions

To protect a view callable from invocation based on a user’s security settings when a particular type of
resource becomes the context, you must pass a permission to view configuration. Permissions are usually
just strings, and they have no required composition: you can name permissions whatever you like.

For example, the following view declaration protects the view named add_entry.html when the con-
text resource is of type Blog with the add permission using the pyramid.config.Configurator.
add_view() API:

1 # config is an instance of pyramid.config.Configurator


2

3 config.add_view('mypackage.views.blog_entry_add_view',
4 name='add_entry.html',
5 context='mypackage.resources.Blog',
6 permission='add')

608 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The equivalent view registration including the add permission name may be performed via the
@view_config decorator:

1 from pyramid.view import view_config


2 from resources import Blog
3

4 @view_config(context=Blog, name='add_entry.html', permission='add')


5 def blog_entry_add_view(request):
6 """ Add blog entry code goes here """
7 pass

As a result of any of these various view configuration statements, if an security policy is in place when the
view callable is found during normal application operations, the security policy will be queried to see if
the requesting user is allowed the add permission within the current context. If the policy allows access,
blog_entry_add_view will be invoked. If not, the Forbidden view will be invoked.

Allowing and Denying Access With a Security Policy

To determine whether access is allowed to a view with an attached permission, Pyramid calls the permits
method of the security policy. permits should return an instance of pyramid.security.Allowed
or pyramid.security.Denied. Both classes accept a string as an argument, which should detail
why access was allowed or denied.

A simple permits implementation that grants access based on a user role might look like so:

1 from pyramid.security import Allowed, Denied


2

3 class SecurityPolicy:
4 def permits(self, request, context, permission):
5 identity = self.identity(request)
6

7 if identity is None:
8 return Denied('User is not signed in.')
9 if identity.role == 'admin':
10 allowed = ['read', 'write', 'delete']
11 elif identity.role == 'editor':
12 allowed = ['read', 'write']
13 else:
14 allowed = ['read']
15

16 if permission in allowed:
(continues on next page)

0.3. Narrative Documentation 609


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


17 return Allowed(
18 'Access granted for user %s with role %s.',
19 identity,
20 identity.role,
21 )
22 else:
23 return Denied(
24 'Access denied for user %s with role %s.',
25 identity,
26 identity.role,
27 )

Setting a Default Permission

If a permission is not supplied to a view configuration, the registered view will always be executable by
entirely anonymous users: any security policy in effect is ignored.

In support of making it easier to configure applications which are ”secure by default”, Pyramid allows you
to configure a default permission. If supplied, the default permission is used as the permission string to
all view registrations which don’t otherwise name a permission argument.

The pyramid.config.Configurator.set_default_permission() method supports con-


figuring a default permission for an application.

When a default permission is registered:

• If a view configuration names an explicit permission, the default permission is ignored for that
view registration, and the view-configuration-named permission is used.

• If a view configuration names the permission pyramid.security.


NO_PERMISSION_REQUIRED, the default permission is ignored, and the view is registered
without a permission (making it available to all callers regardless of their credentials).

When you register a default permission, all views (even exception view views) are protected
by a permission. For all views which are truly meant to be anonymously accessible, you will need to
associate the view’s configuration with the pyramid.security.NO_PERMISSION_REQUIRED
permission.

610 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Implementing ACL Authorization

A common way to implement authorization is using an ACL. An ACL is a context-specific list of access
control entries, which allow or deny access to permissions based on a user’s principals.

Pyramid provides pyramid.authorization.ACLHelper to assist with an ACL-based imple-


mentation of permits. Application-specific code should construct a list of principals for the user
and call pyramid.authorization.ACLHelper.permits(), which will return an pyramid.
authorization.ACLAllowed or pyramid.authorization.ACLDenied object. An imple-
mentation might look like this:

1 from pyramid.authorization import ACLHelper, Everyone, Authenticated


2

3 class SecurityPolicy:
4 def permits(self, request, context, permission):
5 principals = [Everyone]
6 if identity is not None:
7 principals.append(Authenticated)
8 principals.append('user:' + identity.id)
9 principals.append('group:' + identity.group)
10 return ACLHelper().permits(context, principals, permission)

To associate an ACL with a resource, add an __acl__ attribute to the resource object. This attribute can
be defined on the resource instance if you need instance-level security, or it can be defined on the resource
class if you just need type-level security.

For example, an ACL might be attached to the resource for a blog via its class:

1 from pyramid.authorization import Allow


2 from pyramid.authorization import Everyone
3

4 class Blog(object):
5 __acl__ = [
6 (Allow, Everyone, 'view'),
7 (Allow, 'group:editors', 'add'),
8 (Allow, 'group:editors', 'edit'),
9 ]

Or, if your resources are persistent, an ACL might be specified via the __acl__ attribute of an instance
of a resource:

0.3. Narrative Documentation 611


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.authorization import Allow


2 from pyramid.authorization import Everyone
3

4 class Blog(object):
5 pass
6

7 blog = Blog()
8

9 blog.__acl__ = [
10 (Allow, Everyone, 'view'),
11 (Allow, 'group:editors', 'add'),
12 (Allow, 'group:editors', 'edit'),
13 ]

Whether an ACL is attached to a resource’s class or an instance of the resource itself, the effect is the
same. It is useful to decorate individual resource instances with an ACL (as opposed to just decorating
their class) in applications such as content management systems where fine-grained access is required on
an object-by-object basis.

Dynamic ACLs are also possible by turning the ACL into a callable on the resource. This may allow the
ACL to dynamically generate rules based on properties of the instance.

1 from pyramid.authorization import Allow


2 from pyramid.authorization import Everyone
3

4 class Blog(object):
5 def __acl__(self):
6 return [
7 (Allow, Everyone, 'view'),
8 (Allow, self.owner, 'edit'),
9 (Allow, 'group:editors', 'edit'),
10 ]
11

12 def __init__(self, owner):


13 self.owner = owner

Writing __acl__ as properties is discouraged because an AttributeError occurring in


fget or fset will be silently dismissed (this is consistent with Python getattr and hasattr
behaviors). For dynamic ACLs, simply use callables, as documented above.

612 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Elements of an ACL

Here’s an example ACL:

1 from pyramid.authorization import Allow


2 from pyramid.authorization import Everyone
3

4 __acl__ = [
5 (Allow, Everyone, 'view'),
6 (Allow, 'group:editors', 'add'),
7 (Allow, 'group:editors', 'edit'),
8 ]

The example ACL indicates that the pyramid.authorization.Everyone principal—a spe-


cial system-defined principal indicating, literally, everyone—is allowed to view the blog, and the
group:editors principal is allowed to add to and edit the blog.

Each element of an ACL is an ACE, or access control entry. For example, in the above code block, there
are three ACEs: (Allow, Everyone, 'view'), (Allow, 'group:editors', 'add'),
and (Allow, 'group:editors', 'edit').

The first element of any ACE is either pyramid.authorization.Allow, or pyramid.


authorization.Deny, representing the action to take when the ACE matches. The second element
is a principal. The third argument is a permission or sequence of permission names.

A principal is usually a user id, however it also may be a group id if your authentication system provides
group information.

Each ACE in an ACL is processed by the ACL helper in the order dictated by the ACL. So if you have an
ACL like this:

1 from pyramid.authorization import Allow


2 from pyramid.authorization import Deny
3 from pyramid.authorization import Everyone
4

5 __acl__ = [
6 (Allow, Everyone, 'view'),
7 (Deny, Everyone, 'view'),
8 ]

The ACL helper will allow everyone the view permission, even though later in the ACL you have an ACE
that denies everyone the view permission. On the other hand, if you have an ACL like this:

0.3. Narrative Documentation 613


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.authorization import Everyone


2 from pyramid.authorization import Allow
3 from pyramid.authorization import Deny
4

5 __acl__ = [
6 (Deny, Everyone, 'view'),
7 (Allow, Everyone, 'view'),
8 ]

The ACL helper will deny everyone the view permission, even though later in the ACL, there is an ACE
that allows everyone.

The third argument in an ACE can also be a sequence of permission names instead of a single permission
name. So instead of creating multiple ACEs representing a number of different permission grants to a
single group:editors group, we can collapse this into a single ACE, as below.

1 from pyramid.authorization import Allow


2 from pyramid.authorization import Everyone
3

4 __acl__ = [
5 (Allow, Everyone, 'view'),
6 (Allow, 'group:editors', ('add', 'edit')),
7 ]

Special Principal Names

Special principal names exist in the pyramid.authorization module. They can be imported for
use in your own code to populate ACLs, e.g., pyramid.authorization.Everyone.

pyramid.authorization.Everyone

Literally, everyone, no matter what. This object is actually a string under the hood (system.
Everyone). Every user is the principal named ”Everyone” during every request, even if a
security policy is not in use.

pyramid.authorization.Authenticated

Any user with credentials as determined by the current security policy. You might think of
it as any user that is ”logged in”. This object is actually a string under the hood (system.
Authenticated).

614 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Special Permissions

Special permission names exist in the pyramid.authorization module. These can be imported for
use in ACLs.

pyramid.authorization.ALL_PERMISSIONS

An object representing, literally, all permissions. Useful in an ACL like so: (Allow,
'fred', ALL_PERMISSIONS). The ALL_PERMISSIONS object is actually a stand-
in object that has a __contains__ method that always returns True, which, for all known
authorization policies, has the effect of indicating that a given principal has any permission
asked for by the system.

Special ACEs

A convenience ACE is defined representing a deny to everyone of all permissions in pyramid.


authorization.DENY_ALL. This ACE is often used as the last ACE of an ACL to explicitly cause
inheriting authorization policies to ”stop looking up the traversal tree” (effectively breaking any inher-
itance). For example, an ACL which allows only fred the view permission for a particular resource,
despite what inherited ACLs may say, might look like so:

1 from pyramid.authorization import Allow


2 from pyramid.authorization import DENY_ALL
3

4 __acl__ = [ (Allow, 'fred', 'view'), DENY_ALL ]

Under the hood, the pyramid.authorization.DENY_ALL ACE equals the following:

1 from pyramid.authorization import ALL_PERMISSIONS


2 __acl__ = [ (Deny, Everyone, ALL_PERMISSIONS) ]

ACL Inheritance and Location-Awareness

While the ACL helper is in place, if a resource object does not have an ACL when it is the context, its
parent is consulted for an ACL. If that object does not have an ACL, its parent is consulted for an ACL, ad
infinitum, until we’ve reached the root and there are no more parents left.

In order to allow the security machinery to perform ACL inheritance, resource objects must provide
location-awareness. Providing location-awareness means two things: the root object in the resource tree
must have a __name__ attribute and a __parent__ attribute.

0.3. Narrative Documentation 615


The Pyramid Web Framework, Version 2.0.2

1 class Blog(object):
2 __name__ = ''
3 __parent__ = None

An object with a __parent__ attribute and a __name__ attribute is said to be location-aware.


Location-aware objects define a __parent__ attribute which points at their parent object. The root
object’s __parent__ is None.

See also:

See also pyramid.location for documentations of functions which use location-awareness.

See also:

See also Location-Aware Resources.

Changing the Forbidden View

When Pyramid denies a view invocation due to an authorization denial, the special forbidden view is
invoked. Out of the box, this forbidden view is very plain. See Changing the Forbidden View within Using
Hooks for instructions on how to create a custom forbidden view and arrange for it to be called when view
authorization is denied.

Debugging View Authorization Failures

If your application in your judgment is allowing or denying view access inappropriately, start your appli-
cation under a shell using the PYRAMID_DEBUG_AUTHORIZATION environment variable set to 1. For
example:

PYRAMID_DEBUG_AUTHORIZATION=1 $VENV/bin/pserve myproject.ini

When any authorization takes place during a top-level view rendering, a message will be logged to the
console (to stderr) about what ACE in which ACL permitted or denied the authorization based on authen-
tication information.

This behavior can also be turned on in the application .ini file by setting the pyramid.
debug_authorization key to true within the application’s configuration section, e.g.:

616 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 [app:main]
2 use = egg:MyProject
3 pyramid.debug_authorization = true

With this debug flag turned on, the response sent to the browser will also contain security debugging
information in its body.

Debugging Imperative Authorization Failures

The pyramid.request.Request.has_permission() API is used to check security within


view functions imperatively. It returns instances of objects that are effectively booleans. But these
objects are not raw True or False objects, and have information attached to them about why
the permission was allowed or denied. The object will be one of pyramid.authorization.
ACLAllowed, pyramid.authorization.ACLDenied, pyramid.security.Allowed, or
pyramid.security.Denied, as documented in pyramid.security. At the very minimum, these ob-
jects will have a msg attribute, which is a string indicating why the permission was denied or allowed. In-
trospecting this information in the debugger or via print statements when a call to has_permission()
fails is often useful.

Admonishment Against Secret-Sharing

A ”secret” is required by various components of Pyramid. For example, the helper below might be used
for a security policy and uses a secret value seekrit:

helper = AuthTktCookieHelper('seekrit')

A session factory also requires a secret:

my_session_factory = SignedCookieSessionFactory('itsaseekreet')

It is tempting to use the same secret for multiple Pyramid subsystems. For example, you might be tempted
to use the value seekrit as the secret for both the helper and the session factory defined above. This is
a bad idea, because in both cases, these secrets are used to sign the payload of the data.

If you use the same secret for two different parts of your application for signing purposes, it may allow
an attacker to get his chosen plaintext signed, which would allow the attacker to control the content of the
payload. Re-using a secret across two different subsystems might drop the security of signing to zero. Keys
should not be re-used across different contexts where an attacker has the possibility of providing a chosen
plaintext.

0.3. Narrative Documentation 617


The Pyramid Web Framework, Version 2.0.2

Preventing Cross-Site Request Forgery Attacks

Cross-site request forgery attacks are a phenomenon whereby a user who is logged in to your website might
inadvertently load a URL because it is linked from, or embedded in, an attacker’s website. If the URL is
one that may modify or delete data, the consequences can be dire.

You can avoid most of these attacks by issuing a unique token to the browser and then requiring that it be
present in all potentially unsafe requests. Pyramid provides facilities to create and check CSRF tokens.

By default Pyramid comes with a session-based CSRF implementation pyramid.csrf.


SessionCSRFStoragePolicy. To use it, you must first enable a session factory as described
in Using the Default Session Factory or Using Alternate Session Factories. Alternatively, you can
use a cookie-based implementation pyramid.csrf.CookieCSRFStoragePolicy which gives
some additional flexibility as it does not require a session for each user. You can also define your
own implementation of pyramid.interfaces.ICSRFStoragePolicy and register it with the
pyramid.config.Configurator.set_csrf_storage_policy() directive.

For example:

from pyramid.config import Configurator

config = Configurator()
config.set_csrf_storage_policy(MyCustomCSRFPolicy())

Using the csrf.get_csrf_token Method

To get the current CSRF token, use the pyramid.csrf.get_csrf_token method.

from pyramid.csrf import get_csrf_token


token = get_csrf_token(request)

The get_csrf_token() method accepts a single argument: the request. It returns a CSRF token
string. If get_csrf_token() or new_csrf_token() was invoked previously for this user, then
the existing token will be returned. If no CSRF token previously existed for this user, then a new token
will be set into the session and returned. The newly created token will be opaque and randomized.

618 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Using the get_csrf_token global in templates

Templates have a get_csrf_token() method inserted into their globals, which allows you to get the
current token without modifying the view code. This method takes no arguments and returns a CSRF
token string. You can use the returned token as the value of a hidden field in a form that posts to a method
that requires elevated privileges, or supply it as a request header in AJAX requests.

For example, include the CSRF token as a hidden field:

<form method="post" action="/myview">


<input type="hidden" name="csrf_token" value="${get_csrf_token()}">
<input type="submit" value="Delete Everything">
</form>

Or include it as a header in a jQuery AJAX request:

var csrfToken = "${get_csrf_token()}";


$.ajax({
type: "POST",
url: "/myview",
headers: { 'X-CSRF-Token': csrfToken }
}).done(function() {
alert("Deleted");
});

The handler for the URL that receives the request should then require that the correct CSRF token is
supplied.

Using the csrf.new_csrf_token Method

To explicitly create a new CSRF token, use the csrf.new_csrf_token() method. This differs only
from csrf.get_csrf_token() inasmuch as it clears any existing CSRF token, creates a new CSRF
token, sets the token into the user, and returns the token.

from pyramid.csrf import new_csrf_token


token = new_csrf_token(request)

It is not possible to force a new CSRF token from a template. If you want to regenerate your CSRF
token then do it in the view code and return the new token as part of the context.

0.3. Narrative Documentation 619


The Pyramid Web Framework, Version 2.0.2

Checking CSRF Tokens Manually

In request handling code, you can check the presence and validity of a CSRF token with pyramid.
csrf.check_csrf_token(). If the token is valid, it will return True, otherwise it will raise HTTP-
BadRequest. Optionally, you can specify raises=False to have the check return False instead of
raising an exception.

By default, it checks for a POST parameter named csrf_token or a header named X-CSRF-Token.

from pyramid.csrf import check_csrf_token

def myview(request):
# Require CSRF Token
check_csrf_token(request)

# ...

Checking CSRF Tokens Automatically

New in version 1.7.

Pyramid supports automatically checking CSRF tokens on requests with an unsafe method as defined
by RFC2616. Any other request may be checked manually. This feature can be turned on globally for
an application using the pyramid.config.Configurator.set_default_csrf_options()
directive. For example:

from pyramid.config import Configurator

config = Configurator()
config.set_default_csrf_options(require_csrf=True)

CSRF checking may be explicitly enabled or disabled on a per-view basis using the require_csrf view
option. A value of True or False will override the default set by set_default_csrf_options.
For example:

@view_config(route_name='hello', require_csrf=False)
def myview(request):
# ...

620 CONTENTS
The Pyramid Web Framework, Version 2.0.2

When CSRF checking is active, the token and header used to find the supplied CSRF to-
ken will be csrf_token and X-CSRF-Token, respectively, unless otherwise overridden by
set_default_csrf_options. The token is checked against the value in request.POST which
is the submitted form body. If this value is not present, then the header will be checked.

In addition to token based CSRF checks, if the request is using HTTPS then the automatic CSRF checking
will also check the referrer of the request to ensure that it matches one of the trusted origins. By default the
only trusted origin is the current host, however additional origins may be configured by setting pyramid.
csrf_trusted_origins to a list of domain names (and ports if they are non-standard). If a host in
the list of domains starts with a . then that will allow all subdomains as well as the domain without the
.. If no Referer or Origin header is present in an HTTPS request, the CSRF check will fail unless
allow_no_origin is set. The special Origin: null can be allowed by adding null to the
pyramid.csrf_trusted_origins list.

It is possible to opt out of checking the origin by passing check_origin=False. This is useful if the
CSRF storage policy is known to be secure such that the token cannot be easily used by an attacker.

If CSRF checks fail then a pyramid.exceptions.BadCSRFToken or pyramid.exceptions.


BadCSRFOrigin exception will be raised. This exception may be caught and handled by an exception
view but, by default, will result in a 400 Bad Request response being sent to the client.

0.3.29 Combining Traversal and URL Dispatch

When you write most Pyramid applications, you’ll be using one or the other of two available resource
location subsystems: traversal or URL dispatch. However, to solve a limited set of problems, it’s useful to
use both traversal and URL dispatch together within the same application. Pyramid makes this possible
via hybrid applications.

Reasoning about the behavior of a ”hybrid” URL dispatch + traversal application can be challeng-
ing. To successfully reason about using URL dispatch and traversal together, you need to understand
URL pattern matching, root factories, and the traversal algorithm, and the potential interactions be-
tween them. Therefore, we don’t recommend creating an application that relies on hybrid behavior
unless you must.

A Review of Non-Hybrid Applications

When used according to the tutorials in its documentation, Pyramid is a ”dual-mode” framework: the
tutorials explain how to create an application in terms of using either URL dispatch or traversal. This
chapter details how you might combine these two dispatch mechanisms, but we’ll review how they work
in isolation before trying to combine them.

0.3. Narrative Documentation 621


The Pyramid Web Framework, Version 2.0.2

URL Dispatch Only

An application that uses URL dispatch exclusively to map URLs to code will often have statements like
this within its application startup configuration:

1 # config is an instance of pyramid.config.Configurator


2

3 config.add_route('foobar', '{foo}/{bar}')
4 config.add_route('bazbuz', '{baz}/{buz}')
5

6 config.add_view('myproject.views.foobar', route_name='foobar')
7 config.add_view('myproject.views.bazbuz', route_name='bazbuz')

Each route corresponds to one or more view callables. Each view callable is associated with a route by
passing a route_name parameter that matches its name during a call to add_view(). When a route
is matched during a request, view lookup is used to match the request to its associated view callable. The
presence of calls to add_route() signify that an application is using URL dispatch.

Traversal Only

An application that uses only traversal will have view configuration declarations that look like this:

1 # config is an instance of pyramid.config.Configurator


2

3 config.add_view('mypackage.views.foobar', name='foobar')
4 config.add_view('mypackage.views.bazbuz', name='bazbuz')

When the above configuration is applied to an application, the mypackage.views.foobar view


callable above will be called when the URL /foobar is visited. Likewise, the view mypackage.
views.bazbuz will be called when the URL /bazbuz is visited.

Typically, an application that uses traversal exclusively won’t perform any calls to pyramid.config.
Configurator.add_route() in its startup code.

622 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Hybrid Applications

Either traversal or URL dispatch alone can be used to create a Pyramid application. However, it is also
possible to combine the concepts of traversal and URL dispatch when building an application, the result
of which is a hybrid application. In a hybrid application, traversal is performed after a particular route has
matched.
A hybrid application is a lot more like a ”pure” traversal-based application than it is like a ”pure” URL-
dispatch based application. But unlike in a ”pure” traversal-based application, in a hybrid application
traversal is performed during a request after a route has already matched. This means that the URL pattern
that represents the pattern argument of a route must match the PATH_INFO of a request, and after the
route pattern has matched, most of the ”normal” rules of traversal with respect to resource location and
view lookup apply.
There are only four real differences between a purely traversal-based application and a hybrid application:
• In a purely traversal-based application, no routes are defined. In a hybrid application, at least one
route will be defined.
• In a purely traversal-based application, the root object used is global, implied by the root factory
provided at startup time. In a hybrid application, the root object at which traversal begins may be
varied on a per-route basis.
• In a purely traversal-based application, the PATH_INFO of the underlying WSGI environment is
used wholesale as a traversal path. In a hybrid application, the traversal path is not the entire
PATH_INFO string, but a portion of the URL determined by a matching pattern in the matched
route configuration’s pattern.
• In a purely traversal-based application, view configurations which do not mention a route_name
argument are considered during view lookup. In a hybrid application, when a route is matched, only
view configurations which mention that route’s name as a route_name are considered during view
lookup.
More generally, a hybrid application is a traversal-based application except:
• the traversal root is chosen based on the route configuration of the route that matched, instead of
from the root_factory supplied during application startup configuration.
• the traversal path is chosen based on the route configuration of the route that matched, rather than
from the PATH_INFO of a request.
• the set of views that may be chosen during view lookup when a route matches are limited to those
which specifically name a route_name in their configuration that is the same as the matched
route’s name.
To create a hybrid mode application, use a route configuration that implies a particular root factory and
which also includes a pattern argument that contains a special dynamic part: either *traverse or
*subpath.

0.3. Narrative Documentation 623


The Pyramid Web Framework, Version 2.0.2

The Root Object for a Route Match

A hybrid application implies that traversal is performed during a request after a route has matched. Traver-
sal, by definition, must always begin at a root object. Therefore it’s important to know which root object
will be traversed after a route has matched.

Figuring out which root object results from a particular route match is straightforward. When a route is
matched:

• If the route’s configuration has a factory argument which points to a root factory callable, that
callable will be called to generate a root object.

• If the route’s configuration does not have a factory argument, the global root factory will be called
to generate a root object. The global root factory is the callable implied by the root_factory
argument passed to the Configurator at application startup time.

• If a root_factory argument is not provided to the Configurator at startup time, a default


root factory is used. The default root factory is used to generate a root object.

Root factories related to a route were explained previously within Route Factories. Both the global
root factory and default root factory were explained previously within The Resource Tree.

Using *traverse in a Route Pattern

A hybrid application most often implies the inclusion of a route configuration that contains the special
token *traverse at the end of a route’s pattern:

1 config.add_route('home', '{foo}/{bar}/*traverse')

A *traverse token at the end of the pattern in a route’s configuration implies a ”remainder” capture
value. When it is used, it will match the remainder of the path segments of the URL. This remainder
becomes the path used to perform traversal.

The *remainder route pattern syntax is explained in more detail within Route Pattern Syntax.

624 CONTENTS
The Pyramid Web Framework, Version 2.0.2

A hybrid mode application relies more heavily on traversal to do resource location and view lookup than
most examples indicate within URL Dispatch.

Because the pattern of the above route ends with *traverse, when this route configuration is matched
during a request, Pyramid will attempt to use traversal against the root object implied by the root factory
that is implied by the route’s configuration. Since no root_factory argument is explicitly specified for
this route, this will either be the global root factory for the application, or the default root factory. Once
traversal has found a context resource, view lookup will be invoked in almost exactly the same way it would
have been invoked in a ”pure” traversal-based application.

Let’s assume there is no global root factory configured in this application. The default root factory cannot
be traversed; it has no useful __getitem__ method. So we’ll need to associate this route configuration
with a custom root factory in order to create a useful hybrid application. To that end, let’s imagine that
we’ve created a root factory that looks like so in a module named routes.py:

1 class Resource(object):
2 def __init__(self, subobjects):
3 self.subobjects = subobjects
4

5 def __getitem__(self, name):


6 return self.subobjects[name]
7

8 root = Resource(
9 {'a': Resource({'b': Resource({'c': Resource({})})})}
10 )
11

12 def root_factory(request):
13 return root

Above we’ve defined a (bogus) resource tree that can be traversed, and a root_factory function that
can be used as part of a particular route configuration statement:

1 config.add_route('home', '{foo}/{bar}/*traverse',
2 factory='mypackage.routes.root_factory')

The factory above points at the function we’ve defined. It will return an instance of the Resource
class as a root object whenever this route is matched. Instances of the Resource class can be used for
tree traversal because they have a __getitem__ method that does something nominally useful. Since
traversal uses __getitem__ to walk the resources of a resource tree, using traversal against the root
resource implied by our route statement is a reasonable thing to do.

0.3. Narrative Documentation 625


The Pyramid Web Framework, Version 2.0.2

We could have also used our root_factory function as the root_factory argument of the
Configurator constructor, instead of associating it with a particular route inside the route’s configu-
ration. Every hybrid route configuration that is matched, but which does not name a factory attribute,
will use the global root_factory function to generate a root object.

When the route configuration named home above is matched during a request, the matchdict generated will
be based on its pattern: {foo}/{bar}/*traverse. The ”capture value” implied by the *traverse
element in the pattern will be used to traverse the resource tree in order to find a context resource, starting
from the root object returned from the root factory. In the above example, the root object found will be the
instance named root in routes.py.

If the URL that matched a route with the pattern {foo}/{bar}/*traverse is http://example.
com/one/two/a/b/c, the traversal path used against the root object will be a/b/c. As a result,
Pyramid will attempt to traverse through the edges 'a', 'b', and 'c', beginning at the root object.

In our above example, this particular set of traversal steps will mean that the context resource of the view
would be the Resource object we’ve named 'c' in our bogus resource tree, and the view name resulting
from traversal will be the empty string. If you need a refresher about why this outcome is presumed, see
The Traversal Algorithm.

At this point, a suitable view callable will be found and invoked using view lookup as described in View
Configuration, but with a caveat: in order for view lookup to work, we need to define a view configuration
that will match when view lookup is invoked after a route matches:

1 config.add_route('home', '{foo}/{bar}/*traverse',
2 factory='mypackage.routes.root_factory')
3 config.add_view('mypackage.views.myview', route_name='home')

Note that the above call to add_view() includes a route_name argument. View configurations that
include a route_name argument are meant to associate a particular view declaration with a route, using
the route’s name, in order to indicate that the view should only be invoked when the route matches.

Calls to add_view() may pass a route_name attribute, which refers to the value of an existing route’s
name argument. In the above example, the route name is home, referring to the name of the route defined
above it.

The above mypackage.views.myview view callable will be invoked when the following conditions
are met:

• The route named ”home” is matched.

626 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The view name resulting from traversal is the empty string.

• The context resource is any object.

It is also possible to declare alternative views that may be invoked when a hybrid route is matched:

1 config.add_route('home', '{foo}/{bar}/*traverse',
2 factory='mypackage.routes.root_factory')
3 config.add_view('mypackage.views.myview', route_name='home')
4 config.add_view('mypackage.views.another_view', route_name='home',
5 name='another')

The add_view call for mypackage.views.another_view above names a different view and,
more importantly, a different view name. The above mypackage.views.another_view view will
be invoked when the following conditions are met:

• The route named ”home” is matched.

• The view name resulting from traversal is another.

• The context resource is any object.

For instance, if the URL http://example.com/one/two/a/another is provided to an applica-


tion that uses the previously mentioned resource tree, the mypackage.views.another_view view
callable will be called instead of the mypackage.views.myview view callable because the view name
will be another instead of the empty string.

More complicated matching can be composed. All arguments to route configuration statements and view
configuration statements are supported in hybrid applications (such as predicate arguments).

Using the traverse Argument in a Route Definition

Rather than using the *traverse remainder marker in a pattern, you can use the traverse argument
to the add_route() method.

When you use the *traverse remainder marker, the traversal path is limited to being the remainder
segments of a request URL when a route matches. However, when you use the traverse argument or
attribute, you have more control over how to compose a traversal path.

Here’s a use of the traverse pattern in a call to add_route():

0.3. Narrative Documentation 627


The Pyramid Web Framework, Version 2.0.2

1 config.add_route('abc', '/articles/{article}/edit',
2 traverse='/{article}')

The syntax of the traverse argument is the same as it is for pattern.

If, as above, the pattern provided is /articles/{article}/edit, and the traverse argument
provided is /{article}, when a request comes in that causes the route to match in such a way that the
article match value is 1 (when the request URI is /articles/1/edit), the traversal path will be
generated as /1. This means that the root object’s __getitem__ will be called with the name 1 during
the traversal phase. If the 1 object exists, it will become the context of the request. The Traversal chapter
has more information about traversal.

If the traversal path contains segment marker names which are not present in the pattern argument, a
runtime error will occur. The traverse pattern should not contain segment markers that do not exist in
the path.

Note that the traverse argument is ignored when attached to a route that has a *traverse remainder
marker in its pattern.

Traversal will begin at the root object implied by this route (either the global root, or the object returned
by the factory associated with this route).

Making Global Views Match

By default, only view configurations that mention a route_name will be found during view lookup when
a route that has a *traverse in its pattern matches. You can allow views without a route_name
attribute to match a route by adding the use_global_views flag to the route definition. For example,
the myproject.views.bazbuz view below will be found if the route named abc below is matched
and the PATH_INFO is /abc/bazbuz, even though the view configuration statement does not have the
route_name="abc" attribute.

1 config.add_route('abc', '/abc/*traverse', use_global_views=True)


2 config.add_view('myproject.views.bazbuz', name='bazbuz')

628 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Using *subpath in a Route Pattern

There are certain extremely rare cases when you’d like to influence the traversal subpath when a route
matches without actually performing traversal. For instance, the pyramid.wsgi.wsgiapp2() dec-
orator and the pyramid.static.static_view helper attempt to compute PATH_INFO from the
request’s subpath when its use_subpath argument is True, so it’s useful to be able to influence this
value.

When *subpath exists in a pattern, no path is actually traversed, but the traversal algorithm will return
a subpath list implied by the capture value of *subpath. You’ll see this pattern most commonly in route
declarations that look like this:

1 from pyramid.static import static_view


2

3 www = static_view('mypackage:static', use_subpath=True)


4

5 config.add_route('static', '/static/*subpath')
6 config.add_view(www, route_name='static')

mypackage.views.www is an instance of pyramid.static.static_view. This effectively


tells the static helper to traverse everything in the subpath as a filename.

Generating Hybrid URLs

New in version 1.5.

The pyramid.request.Request.resource_url() method and the pyramid.request.


Request.resource_path() method both accept optional keyword arguments that make it easier
to generate route-prefixed URLs that contain paths to traversal resources: route_name, route_kw,
and route_remainder_name.

Any route that has a pattern that contains a *remainder pattern (any stararg remainder pattern, such as
*traverse, *subpath, or *fred) can be used as the target name for request.resource_url(.
.., route_name=) and request.resource_path(..., route_name=).

For example, let’s imagine you have a route defined in your Pyramid application like so:

config.add_route('mysection', '/mysection*traverse')

If you’d like to generate the URL http://example.com/mysection/a/, you can use the following
incantation, assuming that the variable a below points to a resource that is a child of the root with a
__name__ of a:

0.3. Narrative Documentation 629


The Pyramid Web Framework, Version 2.0.2

request.resource_url(a, route_name='mysection')

You can generate only the path portion /mysection/a/ assuming the same:

request.resource_path(a, route_name='mysection')

The path is virtual host aware, so if the X-Vhm-Root environment variable is present in the request, and
it’s set to /a, the above call to request.resource_url would generate http://example.com/
mysection/, and the above call to request.resource_path would generate /mysection/.
See Virtual Root Support for more information.

If the route you’re trying to use needs simple dynamic part values to be filled in to successfully generate
the URL, you can pass these as the route_kw argument to resource_url and resource_path.
For example, assuming that the route definition is like so:

config.add_route('mysection', '/{id}/mysection*traverse')

You can pass route_kw in to fill in {id} above:

request.resource_url(a, route_name='mysection', route_kw={'id':'1'})

If you pass route_kw but do not pass route_name, route_kw will be ignored.

By default this feature works by calling route_url under the hood, and passing the value of the resource
path to that function as traverse. If your route has a different *stararg remainder name (such as
*subpath), you can tell resource_url or resource_path to use that instead of traverse by
passing route_remainder_name. For example, if you have the following route:

config.add_route('mysection', '/mysection*subpath')

You can fill in the *subpath value using resource_url by doing:

request.resource_path(a, route_name='mysection',
route_remainder_name='subpath')

630 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If you pass route_remainder_name but do not pass route_name, route_remainder_name


will be ignored.
If you try to use resource_path or resource_url when the route_name argument points at a
route that does not have a remainder stararg, an error will not be raised, but the generated URL will not
contain any remainder information either.
All other values that are normally passable to resource_path and resource_url (such as query,
anchor, host, port, and positional elements) work as you might expect in this configuration.
Note that this feature is incompatible with the __resource_url__ feature (see Overriding Resource
URL Generation) implemented on resource objects. Any __resource_url__ supplied by your re-
source will be ignored when you pass route_name.

0.3.30 Invoking a Subrequest

New in version 1.4.


Pyramid allows you to invoke a subrequest at any point during the processing of a request. Invoking a
subrequest allows you to obtain a response object from a view callable within your Pyramid application
while you’re executing a different view callable within the same application.
Here’s an example application which uses a subrequest:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.request import Request
4

5 def view_one(request):
6 subreq = Request.blank('/view_two')
7 response = request.invoke_subrequest(subreq)
8 return response
9

10 def view_two(request):
11 request.response.body = 'This came from view_two'
12 return request.response
13

14 if __name__ == '__main__':
15 config = Configurator()
16 config.add_route('one', '/view_one')
17 config.add_route('two', '/view_two')
18 config.add_view(view_one, route_name='one')
19 config.add_view(view_two, route_name='two')
20 app = config.make_wsgi_app()
21 server = make_server('0.0.0.0', 8080, app)
22 server.serve_forever()

0.3. Narrative Documentation 631


The Pyramid Web Framework, Version 2.0.2

When /view_one is visted in a browser, the text printed in the browser pane will be This
came from view_two. The view_one view used the pyramid.request.Request.
invoke_subrequest() API to obtain a response from another view (view_two) within the same
application when it executed. It did so by constructing a new request that had a URL that it knew would
match the view_two view registration, and passed that new request along to pyramid.request.
Request.invoke_subrequest(). The view_two view callable was invoked, and it returned a re-
sponse. The view_one view callable then simply returned the response it obtained from the view_two
view callable.

Note that it doesn’t matter if the view callable invoked via a subrequest actually returns a literal
Response object. Any view callable that uses a renderer or which returns an object that can be
interpreted by a response adapter when found and invoked via pyramid.request.Request.
invoke_subrequest() will return a Response object:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.request import Request
4

5 def view_one(request):
6 subreq = Request.blank('/view_two')
7 response = request.invoke_subrequest(subreq)
8 return response
9

10 def view_two(request):
11 return 'This came from view_two'
12

13 if __name__ == '__main__':
14 config = Configurator()
15 config.add_route('one', '/view_one')
16 config.add_route('two', '/view_two')
17 config.add_view(view_one, route_name='one')
18 config.add_view(view_two, route_name='two', renderer='string')
19 app = config.make_wsgi_app()
20 server = make_server('0.0.0.0', 8080, app)
21 server.serve_forever()

Even though the view_two view callable returned a string, it was invoked in such a way that the string
renderer associated with the view registration that was found turned it into a ”real” response object for
consumption by view_one.

Being able to unconditionally obtain a response object by invoking a view callable indirectly is the main
advantage to using pyramid.request.Request.invoke_subrequest() instead of simply im-
porting a view callable and executing it directly. Note that there’s not much advantage to invoking a view

632 CONTENTS
The Pyramid Web Framework, Version 2.0.2

using a subrequest if you can invoke a view callable directly. Subrequests are slower and are less conve-
nient if you actually do want just the literal information returned by a function that happens to be a view
callable.

Note that, by default, if a view callable invoked by a subrequest raises an exception, the exception will be
raised to the caller of invoke_subrequest() even if you have a exception view configured:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.request import Request
4

5 def view_one(request):
6 subreq = Request.blank('/view_two')
7 response = request.invoke_subrequest(subreq)
8 return response
9

10 def view_two(request):
11 raise ValueError('foo')
12

13 def excview(request):
14 request.response.body = b'An exception was raised'
15 request.response.status_int = 500
16 return request.response
17

18 if __name__ == '__main__':
19 config = Configurator()
20 config.add_route('one', '/view_one')
21 config.add_route('two', '/view_two')
22 config.add_view(view_one, route_name='one')
23 config.add_view(view_two, route_name='two', renderer='string')
24 config.add_view(excview, context=Exception)
25 app = config.make_wsgi_app()
26 server = make_server('0.0.0.0', 8080, app)
27 server.serve_forever()

When we run the above code and visit /view_one in a browser, the excview exception view will not
be executed. Instead, the call to invoke_subrequest() will cause a ValueError exception to be
raised and a response will never be generated. We can change this behavior; how to do so is described
below in our discussion of the use_tweens argument.

0.3. Narrative Documentation 633


The Pyramid Web Framework, Version 2.0.2

Subrequests with Tweens

The pyramid.request.Request.invoke_subrequest() API accepts two arguments: a re-


quired positional argument request, and an optional keyword argument use_tweens which defaults
to False.

The request object passed to the API must be an object that implements the Pyramid request interface
(such as a pyramid.request.Request instance). If use_tweens is True, the request will be
sent to the tween in the tween stack closest to the request ingress. If use_tweens is False, the request
will be sent to the main router handler, and no tweens will be invoked.

In the example above, the call to invoke_subrequest() will always raise an exception. This is
because it’s using the default value for use_tweens, which is False. Alternatively, you can pass
use_tweens=True to ensure that it will convert an exception to a Response if an exception view is
configured, instead of raising the exception. This is because exception views are called by the exception
view tween as described in Custom Exception Views when any view raises an exception.

We can cause the subrequest to be run through the tween stack by passing use_tweens=True to the
call to invoke_subrequest(), like this:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.request import Request
4

5 def view_one(request):
6 subreq = Request.blank('/view_two')
7 response = request.invoke_subrequest(subreq, use_tweens=True)
8 return response
9

10 def view_two(request):
11 raise ValueError('foo')
12

13 def excview(request):
14 request.response.body = b'An exception was raised'
15 request.response.status_int = 500
16 return request.response
17

18 if __name__ == '__main__':
19 config = Configurator()
20 config.add_route('one', '/view_one')
21 config.add_route('two', '/view_two')
22 config.add_view(view_one, route_name='one')
23 config.add_view(view_two, route_name='two', renderer='string')
24 config.add_view(excview, context=Exception)
(continues on next page)

634 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


25 app = config.make_wsgi_app()
26 server = make_server('0.0.0.0', 8080, app)
27 server.serve_forever()

In the above case, the call to request.invoke_subrequest(subreq) will not raise an exception.
Instead, it will retrieve a ”500” response from the attempted invocation of view_two, because the tween
which invokes an exception view to generate a response is run, and therefore excview is executed.

This is one of the major differences between specifying the use_tweens=True and
use_tweens=False arguments to invoke_subrequest(). use_tweens=True may
also imply invoking a transaction commit or abort for the logic executed in the subrequest if you’ve got
pyramid_tm in the tween list, injecting debug HTML if you’ve got pyramid_debugtoolbar in
the tween list, and other tween-related side effects as defined by your particular tween list.

The invoke_subrequest() function also unconditionally does the following:

• It manages the threadlocal stack so that get_current_request() and


get_current_registry() work during a request (they will return the subrequest instead of
the original request).

• It adds a registry attribute and an invoke_subrequest attribute (a callable) to the request


object to which it is handed.

• It sets request extensions (such as those added via add_request_method()) on the subrequest
object passed as request.

• It causes a NewRequest event to be sent at the beginning of request processing.

• It causes a ContextFound event to be sent when a context resource is found.

• It ensures that the user implied by the request passed in has the necessary authorization to invoke
the view callable before calling it.

• It calls any response callback functions defined within the subrequest’s lifetime if a response is
obtained from the Pyramid application.

• It causes a NewResponse event to be sent if a response is obtained.

• It calls any finished callback functions defined within the subrequest’s lifetime.

0.3. Narrative Documentation 635


The Pyramid Web Framework, Version 2.0.2

The invocation of a subrequest has more or less exactly the same effect as the invocation of a
request received by the Pyramid router from a web client when use_tweens=True. When
use_tweens=False, the tweens are skipped but all the other steps take place.

It’s a poor idea to use the original request object as an argument to invoke_subrequest().
You should construct a new request instead as demonstrated in the above example, using pyramid.
request.Request.blank(). Once you’ve constructed a request object, you’ll need to massage it
to match the view callable that you’d like to be executed during the subrequest. This can be done by ad-
justing the subrequest’s URL, its headers, its request method, and other attributes. The documentation for
pyramid.request.Request exposes the methods you should call and attributes you should set on
the request that you create, then massage it into something that will actually match the view you’d like to
call via a subrequest.

We’ve demonstrated use of a subrequest from within a view callable, but you can use the in-
voke_subrequest() API from within a tween or an event handler as well. Even though you can
do it, it’s usually a poor idea to invoke invoke_subrequest() from within a tween, because tweens
already, by definition, have access to a function that will cause a subrequest (they are passed a handle
function). It’s fine to invoke invoke_subrequest() from within an event handler, however.

Invoking an Exception View

New in version 1.7.

Pyramid apps may define exception views which can handle any raised exceptions that escape from your
code while processing a request. By default an unhandled exception will be caught by the EXCVIEW tween,
which will then lookup an exception view that can handle the exception type, generating an appropriate
error response.

In Pyramid 1.7 the pyramid.request.Request.invoke_exception_view() was intro-


duced, allowing a user to invoke an exception view while manually handling an exception. This can be
useful in a few different circumstances:

• Manually handling an exception losing the current call stack or flow.

• Handling exceptions outside of the context of the EXCVIEW tween. The tween only covers certain
parts of the request processing pipeline (See Request Processing). There are also some corner cases
where an exception can be raised that will still bubble up to middleware, and possibly to the web
server in which case a generic 500 Internal Server Error will be returned to the client.

Below is an example usage of pyramid.request.Request.invoke_exception_view():

636 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 def foo(request):
2 try:
3 some_func_that_errors()
4 return response
5 except Exception:
6 response = request.invoke_exception_view()
7 if response is not None:
8 return response
9 else:
10 # there is no exception view for this exception, simply
11 # re-raise and let someone else handle it
12 raise

Please note that in most cases you do not need to write code like this, and you may rely on the EXCVIEW
tween to handle this for you.

0.3.31 Using Hooks

”Hooks” can be used to influence the behavior of the Pyramid framework in various ways.

Changing the Not Found View

When Pyramid can’t map a URL to view code, it invokes a Not Found View, which is a view callable. The
default Not Found View can be overridden through application configuration.

If your application uses imperative configuration, you can replace the Not Found View by using the
pyramid.config.Configurator.add_notfound_view() method:

1 def notfound(request):
2 return Response('Not Found', status='404 Not Found')
3

4 def main(globals, **settings):


5 config = Configurator()
6 config.add_notfound_view(notfound)

The Not Found View callable is a view callable like any other.

If your application instead uses pyramid.view.view_config decorators and a scan, you can replace
the Not Found View by using the pyramid.view.notfound_view_config decorator:

0.3. Narrative Documentation 637


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.view import notfound_view_config


2

3 @notfound_view_config()
4 def notfound(request):
5 return Response('Not Found', status='404 Not Found')
6

7 def main(globals, **settings):


8 config = Configurator()
9 config.scan()

This does exactly what the imperative example above showed.


Your application can define multiple Not Found Views if necessary. Both pyramid.config.
Configurator.add_notfound_view() and pyramid.view.notfound_view_config
take most of the same arguments as pyramid.config.Configurator.add_view and
pyramid.view.view_config, respectively. This means that Not Found Views can carry predicates
limiting their applicability. For example:

1 from pyramid.view import notfound_view_config


2

3 @notfound_view_config(request_method='GET')
4 def notfound_get(request):
5 return Response('Not Found during GET', status='404 Not Found')
6

7 @notfound_view_config(request_method='POST')
8 def notfound_post(request):
9 return Response('Not Found during POST', status='404 Not Found')
10

11 def main(globals, **settings):


12 config = Configurator()
13 config.scan()

The notfound_get view will be called when a view could not be found and the request method was
GET. The notfound_post view will be called when a view could not be found and the request method
was POST.
Like any other view, the Not Found View must accept at least a request parameter, or both context
and request. The request is the current request representing the denied action. The context (if
used in the call signature) will be the instance of the HTTPNotFound exception that caused the view to
be called.
Both pyramid.config.Configurator.add_notfound_view() and pyramid.view.
notfound_view_config can be used to automatically redirect requests to slash-appended routes.
See Redirecting to Slash-Appended Routes for examples.
Here’s some sample code that implements a minimal Not Found View callable:

638 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.httpexceptions import HTTPNotFound


2

3 def notfound(request):
4 return HTTPNotFound()

When a Not Found View callable is invoked, it is passed a request. The exception attribute of the
request will be an instance of the HTTPNotFound exception that caused the Not Found View to be called.
The value of request.exception.message will be a value explaining why the Not Found exception
was raised. This message has different values depending on whether the pyramid.debug_notfound
environment setting is true or false.

When a Not Found View callable accepts an argument list as described in Alternate View Callable
Argument/Calling Conventions, the context passed as the first argument to the view callable will be
the HTTPNotFound exception instance. If available, the resource context will still be available as
request.context.

The Not Found View callables are only invoked when a HTTPNotFound exception is raised. If
the exception is returned from a view then it will be treated as a regular response object and it will not
trigger the custom view.

Changing the Forbidden View

When Pyramid can’t authorize execution of a view based on the authorization policy in use, it invokes a
forbidden view. The default forbidden response has a 403 status code and is very plain, but the view which
generates it can be overridden as necessary.

The forbidden view callable is a view callable like any other. The view configuration which
causes it to be a ”forbidden” view consists of using the pyramid.config.Configurator.
add_forbidden_view() API or the pyramid.view.forbidden_view_config decorator.

For example, you can add a forbidden view by using the pyramid.config.Configurator.
add_forbidden_view() method to register a forbidden view:

0.3. Narrative Documentation 639


The Pyramid Web Framework, Version 2.0.2

1 def forbidden(request):
2 return Response('forbidden')
3

4 def main(globals, **settings):


5 config = Configurator()
6 config.add_forbidden_view(forbidden)

If instead you prefer to use decorators and a scan, you can use the pyramid.view.
forbidden_view_config decorator to mark a view callable as a forbidden view:

1 from pyramid.view import forbidden_view_config


2

3 @forbidden_view_config()
4 def forbidden(request):
5 return Response('forbidden')
6

7 def main(globals, **settings):


8 config = Configurator()
9 config.scan()

Like any other view, the forbidden view must accept at least a request parameter, or both context and
request. If a forbidden view callable accepts both context and request, the HTTP Exception is
passed as context. The context as found by the router when the view was denied (which you normally
would expect) is available as request.context. The request is the current request representing
the denied action.

Here’s some sample code that implements a minimal forbidden view:

1 from pyramid.view import view_config


2 from pyramid.response import Response
3

4 def forbidden_view(request):
5 return Response('forbidden')

When a forbidden view callable is invoked, it is passed a request. The exception attribute
of the request will be an instance of the HTTPForbidden exception that caused the forbidden view
to be called. The value of request.exception.message will be a value explaining why the for-
bidden exception was raised, and request.exception.result will be extended information about
the forbidden exception. These messages have different values depending on whether the pyramid.
debug_authorization environment setting is true or false.

640 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The forbidden view callables are only invoked when a HTTPForbidden exception is raised. If
the exception is returned from a view then it will be treated as a regular response object and it will not
trigger the custom view.

Changing the Request Factory

Whenever Pyramid handles a request from a WSGI server, it creates a request object based on the WSGI
environment it has been passed. By default, an instance of the pyramid.request.Request class is
created to represent the request object.

The class (a.k.a., ”factory”) that Pyramid uses to create a request object instance can be changed by passing
a request_factory argument to the constructor of the configurator. This argument can be either a
callable or a dotted Python name representing a callable.

1 from pyramid.request import Request


2

3 class MyRequest(Request):
4 pass
5

6 config = Configurator(request_factory=MyRequest)

If you’re doing imperative configuration, and you’d rather do it after you’ve already con-
structed a configurator, it can also be registered via the pyramid.config.Configurator.
set_request_factory() method:

1 from pyramid.config import Configurator


2 from pyramid.request import Request
3

4 class MyRequest(Request):
5 pass
6

7 config = Configurator()
8 config.set_request_factory(MyRequest)

0.3. Narrative Documentation 641


The Pyramid Web Framework, Version 2.0.2

Adding Methods or Properties to a Request Object

New in version 1.4.

Since each Pyramid application can only have one request factory, changing the request factory is not that
extensible, especially if you want to build composable features (e.g., Pyramid add-ons and plugins).

A lazy property can be registered to the request object via the pyramid.config.Configurator.
add_request_method() API. This allows you to specify a callable that will be available on the re-
quest object, but will not actually execute the function until accessed.

This will silently override methods and properties from request factory that have the same name.

1 from pyramid.config import Configurator


2

3 def total(request, *args):


4 return sum(args)
5

6 def prop(request):
7 print("getting the property")
8 return "the property"
9

10 config = Configurator()
11 config.add_request_method(total)
12 config.add_request_method(prop, reify=True)

In the above example, total is added as a method. However, prop is added as a property and its result is
cached per-request by setting reify=True. This way, we eliminate the overhead of running the function
multiple times.

>>> request.total(1, 2, 3)
6
>>> request.prop
getting the property
'the property'
>>> request.prop
'the property'

To not cache the result of request.prop, set property=True instead of reify=True.

Here is an example of passing a class to Configurator.add_request_method:

642 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.config import Configurator


2 from pyramid.decorator import reify
3

4 class ExtraStuff(object):
5

6 def __init__(self, request):


7 self.request = request
8

9 def total(self, *args):


10 return sum(args)
11

12 # use @property if you don't want to cache the result


13 @reify
14 def prop(self):
15 print("getting the property")
16 return "the property"
17

18 config = Configurator()
19 config.add_request_method(ExtraStuff, 'extra', reify=True)

We attach and cache an object named extra to the request object.

>>> request.extra.total(1, 2, 3)
6
>>> request.extra.prop
getting the property
'the property'
>>> request.extra.prop
'the property'

Changing the Response Factory

New in version 1.6.

Whenever Pyramid returns a response from a view, it creates a response object. By default, an instance of
the pyramid.response.Response class is created to represent the response object.

The factory that Pyramid uses to create a response object instance can be changed by passing a pyramid.
interfaces.IResponseFactory argument to the constructor of the configurator. This argument
can be either a callable or a dotted Python name representing a callable.

The factory takes a single positional argument, which is a Request object. The argument may be None.

0.3. Narrative Documentation 643


The Pyramid Web Framework, Version 2.0.2

1 from pyramid.response import Response


2

3 class MyResponse(Response):
4 pass
5

6 config = Configurator(response_factory=lambda r: MyResponse())

If you’re doing imperative configuration and you’d rather do it after you’ve already con-
structed a configurator, it can also be registered via the pyramid.config.Configurator.
set_response_factory() method:

1 from pyramid.config import Configurator


2 from pyramid.response import Response
3

4 class MyResponse(Response):
5 pass
6

7 config = Configurator()
8 config.set_response_factory(lambda r: MyResponse())

Using the Before Render Event

Subscribers to the pyramid.events.BeforeRender event may introspect and modify the set of
renderer globals before they are passed to a renderer. This event object iself has a dictionary-like interface
that can be used for this purpose. For example:

1 from pyramid.events import subscriber


2 from pyramid.events import BeforeRender
3

4 @subscriber(BeforeRender)
5 def add_global(event):
6 event['mykey'] = 'foo'

An object of this type is sent as an event just before a renderer is invoked.

If a subscriber attempts to add a key that already exists in the renderer globals dictionary, a KeyError is
raised. This limitation is enforced because event subscribers do not possess any relative ordering. The set
of keys added to the renderer globals dictionary by all pyramid.events.BeforeRender subscribers
and renderer globals factories must be unique.

644 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The dictionary returned from the view is accessible through the rendering_val attribute of a Be-
foreRender event.

Suppose you return {'mykey': 'somevalue', 'mykey2': 'somevalue2'} from your view
callable, like so:

1 from pyramid.view import view_config


2

3 @view_config(renderer='some_renderer')
4 def myview(request):
5 return {'mykey': 'somevalue', 'mykey2': 'somevalue2'}

rendering_val can be used to access these values from the BeforeRender object:

1 from pyramid.events import subscriber


2 from pyramid.events import BeforeRender
3

4 @subscriber(BeforeRender)
5 def read_return(event):
6 # {'mykey': 'somevalue'} is returned from the view
7 print(event.rendering_val['mykey'])

See the API documentation for the BeforeRender event interface at pyramid.interfaces.
IBeforeRender.

Using Response Callbacks

Unlike many other web frameworks, Pyramid does not eagerly create a global response object. Adding a
response callback allows an application to register an action to be performed against whatever response
object is returned by a view, usually in order to mutate the response.

The pyramid.request.Request.add_response_callback() method is used to register a


response callback.

A response callback is a callable which accepts two positional parameters: request and response.
For example:

1 def cache_callback(request, response):


2 """Set the cache_control max_age for the response"""
3 if request.exception is not None:
4 response.cache_control.max_age = 360
5 request.add_response_callback(cache_callback)

0.3. Narrative Documentation 645


The Pyramid Web Framework, Version 2.0.2

No response callback is called if an unhandled exception happens in application code, or if the response
object returned by a view callable is invalid. Response callbacks are, however, invoked when a exception
view is rendered successfully. In such a case, the request.exception attribute of the request when
it enters a response callback will be an exception object instead of its default value of None.

Response callbacks are called in the order they’re added (first-to-most-recently-added). All response call-
backs are called before the NewResponse event is sent. Errors raised by response callbacks are not
handled specially. They will be propagated to the caller of the Pyramid router application.

A response callback has a lifetime of a single request. If you want a response callback to happen as the
result of every request, you must re-register the callback into every new request (perhaps within a subscriber
of a NewRequest event).

Using Finished Callbacks

A finished callback is a function that will be called unconditionally by the Pyramid router at the very
end of request processing. A finished callback can be used to perform an action at the end of a request
unconditionally.

The pyramid.request.Request.add_finished_callback() method is used to register a


finished callback.

A finished callback is a callable which accepts a single positional parameter: request. For example:

1 import logging
2

3 log = logging.getLogger(__name__)
4

5 def log_callback(request):
6 """Log information at the end of request"""
7 log.debug('Request is finished.')
8 request.add_finished_callback(log_callback)

Finished callbacks are called in the order they’re added (first-to-most-recently-added). Finished callbacks
(unlike a response callback) are always called, even if an exception happens in application code that pre-
vents a response from being generated.

The set of finished callbacks associated with a request are called very late in the processing of that request;
they are essentially the very last thing called by the router before a request ”ends”. They are called after
response processing has already occurred in a top-level finally: block within the router request pro-
cessing code. As a result, mutations performed to the request provided to a finished callback will have

646 CONTENTS
The Pyramid Web Framework, Version 2.0.2

no meaningful effect, because response processing will have already occurred, and the request’s scope will
expire almost immediately after all finished callbacks have been processed.

Errors raised by finished callbacks are not handled specially. They will be propagated to the caller of the
Pyramid router application.

A finished callback has a lifetime of a single request. If you want a finished callback to happen as the result
of every request, you must re-register the callback into every new request (perhaps within a subscriber of
a NewRequest event).

Changing the Traverser

The default traversal algorithm that Pyramid uses is explained in The Traversal Algorithm. Though it is
rarely necessary, this default algorithm can be swapped out selectively for a different traversal pattern via
configuration.

1 from pyramid.config import Configurator


2 from myapp.traversal import Traverser
3 config = Configurator()
4 config.add_traverser(Traverser)

In the example above, myapp.traversal.Traverser is assumed to be a class that implements the


following interface:

1 class Traverser(object):
2 def __init__(self, root):
3 """ Accept the root object returned from the root factory """
4

5 def __call__(self, request):


6 """ Return a dictionary with (at least) the keys ``root``,
7 ``context``, ``view_name``, ``subpath``, ``traversed``,
8 ``virtual_root``, and ``virtual_root_path``. These values are
9 typically the result of a resource tree traversal. ``root``
10 is the physical root object, ``context`` will be a resource
11 object, ``view_name`` will be the view name used (a string),
12 ``subpath`` will be a sequence of strings that
13 followed the view name but were not traversed, ``traversed``
14 will be a sequence of strings that were traversed
15 (including the virtual root path, if any) ``virtual_root``
16 will be a resource object representing the virtual root (or the
17 physical root if traversal was not performed), and
18 ``virtual_root_path`` will be a sequence representing the
(continues on next page)

0.3. Narrative Documentation 647


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


19 virtual root path (a sequence of strings) or ``None`` if
20 traversal was not performed.
21

22 Extra keys for special purpose functionality can be added as


23 necessary.
24

25 All values returned in the dictionary will be made available


26 as attributes of the ``request`` object.
27 """

More than one traversal algorithm can be active at the same time. For instance, if your root factory returns
more than one type of object conditionally, you could claim that an alternative traverser adapter is ”for”
only one particular class or interface. When the root factory returned an object that implemented that
class or interface, a custom traverser would be used. Otherwise the default traverser would be used. For
example:

1 from myapp.traversal import Traverser


2 from myapp.resources import MyRoot
3 from pyramid.config import Configurator
4 config = Configurator()
5 config.add_traverser(Traverser, MyRoot)

If the above stanza was added to a Pyramid __init__.py file’s main function, Pyramid would use
the myapp.traversal.Traverser only when the application root factory returned an instance of
the myapp.resources.MyRoot object. Otherwise it would use the default Pyramid traverser to do
traversal.

Changing How pyramid.request.Request.resource_url() Generates a URL

When you add a traverser as described in Changing the Traverser, it’s often convenient to continue to
use the pyramid.request.Request.resource_url() API. However, since the way traversal
is done will have been modified, the URLs it generates by default may be incorrect when used against
resources derived from your custom traverser.

If you’ve added a traverser, you can change how resource_url() generates a URL
for a specific type of resource by adding a call to pyramid.config.Configurator.
add_resource_url_adapter().

For example:

648 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from myapp.traversal import ResourceURLAdapter


2 from myapp.resources import MyRoot
3

4 config.add_resource_url_adapter(ResourceURLAdapter, MyRoot)

In the above example, the myapp.traversal.ResourceURLAdapter class will be used to provide


services to resource_url() any time the resource passed to resource_url is of the class myapp.
resources.MyRoot. The resource_iface argument MyRoot represents the type of interface that
must be possessed by the resource for this resource url factory to be found. If the resource_iface
argument is omitted, this resource URL adapter will be used for all resources.

The API that must be implemented by a class that provides IResourceURL is as follows:

1 class MyResourceURL(object):
2 """ An adapter which provides the virtual and physical paths of a
3 resource
4 """
5 def __init__(self, resource, request):
6 """ Accept the resource and request and set self.physical_path and
7 self.virtual_path """
8 self.virtual_path = some_function_of(resource, request)
9 self.virtual_path_tuple = some_function_of(resource, request)
10 self.physical_path = some_other_function_of(resource, request)
11 self.physical_path_tuple = some_function_of(resource, request)

The default context URL generator is available for perusal as the class pyramid.traversal.
ResourceURL in the traversal module.

See pyramid.config.Configurator.add_resource_url_adapter() for more informa-


tion.

Changing How Pyramid Treats View Responses

New in version 1.1.

It is possible to control how Pyramid treats the result of calling a view callable on a per-type basis by
using a hook involving pyramid.config.Configurator.add_response_adapter() or the
response_adapter decorator.

Pyramid, in various places, adapts the result of calling a view callable to the IResponse interface to
ensure that the object returned by the view callable is a ”true” response object. The vast majority of time,

0.3. Narrative Documentation 649


The Pyramid Web Framework, Version 2.0.2

the result of this adaptation is the result object itself, as view callables written by ”civilians” who read the
narrative documentation contained in this manual will always return something that implements the IRe-
sponse interface. Most typically, this will be an instance of the pyramid.response.Response
class or a subclass. If a civilian returns a non-Response object from a view callable that isn’t configured
to use a renderer, they will typically expect the router to raise an error. However, you can hook Pyramid
in such a way that users can return arbitrary values from a view callable by providing an adapter which
converts the arbitrary return value into something that implements IResponse.

For example, if you’d like to allow view callables to return bare string objects (without requiring a renderer
to convert a string to a response object), you can register an adapter which converts the string to a Response:

1 from pyramid.response import Response


2

3 def string_response_adapter(s):
4 response = Response(s)
5 return response
6

7 # config is an instance of pyramid.config.Configurator


8

9 config.add_response_adapter(string_response_adapter, str)

Likewise, if you want to be able to return a simplified kind of response object from view callables, you can
use the IResponse hook to register an adapter to the more complex IResponse interface:

1 from pyramid.response import Response


2

3 class SimpleResponse(object):
4 def __init__(self, body):
5 self.body = body
6

7 def simple_response_adapter(simple_response):
8 response = Response(simple_response.body)
9 return response
10

11 # config is an instance of pyramid.config.Configurator


12

13 config.add_response_adapter(simple_response_adapter, SimpleResponse)

If you want to implement your own Response object instead of using the pyramid.response.
Response object in any capacity at all, you’ll have to make sure that the object implements every at-
tribute and method outlined in pyramid.interfaces.IResponse and you’ll have to ensure that it
uses zope.interface.implementer(IResponse) as a class decorator.

650 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.interfaces import IResponse


2 from zope.interface import implementer
3

4 @implementer(IResponse)
5 class MyResponse(object):
6 # ... an implementation of every method and attribute
7 # documented in IResponse should follow ...

When an alternate response object implementation is returned by a view callable, if that object asserts
that it implements IResponse (via zope.interface.implementer(IResponse)) , an adapter
needn’t be registered for the object; Pyramid will use it directly.
An IResponse adapter for webob.reponse.Response (as opposed to pyramid.response.
Response) is registered by Pyramid by default at startup time, as by their nature, instances of this
class (and instances of subclasses of the class) will natively provide IResponse. The adapter registered
for webob.reponse.Response simply returns the response object.
Instead of using pyramid.config.Configurator.add_response_adapter(), you can use
the pyramid.response.response_adapter decorator:

1 from pyramid.response import Response


2 from pyramid.response import response_adapter
3

4 @response_adapter(str)
5 def string_response_adapter(s):
6 response = Response(s)
7 return response

The above example, when scanned, has the same effect as:

config.add_response_adapter(string_response_adapter, str)

The response_adapter decorator will have no effect until activated by a scan.

Using a View Mapper

The default calling conventions for view callables are documented in the Views chapter. You can change
the way users define view callables by employing a view mapper.
A view mapper is an object that accepts a set of keyword arguments and which returns a callable. The
returned callable is called with the view callable object. The returned callable should itself return another
callable which can be called with the ”internal calling protocol” (context, request).
You can use a view mapper in a number of ways:

0.3. Narrative Documentation 651


The Pyramid Web Framework, Version 2.0.2

• by setting a __view_mapper__ attribute (which is the view mapper object) on the view callable
itself

• by passing the mapper object to pyramid.config.Configurator.add_view() (or its


declarative and decorator equivalents) as the mapper argument

• by registering a default view mapper

Here’s an example of a view mapper that emulates (somewhat) a Pylons ”controller”. The mapper is
initialized with some keyword arguments. Its __call__ method accepts the view object (which will be
a class). It uses the attr keyword argument it is passed to determine which attribute should be used as an
action method. The wrapper method it returns accepts (context, request) and returns the result of
calling the action method with keyword arguments implied by the matchdict after popping the action out
of it. This somewhat emulates the Pylons style of calling action methods with routing parameters pulled
out of the route matching dict as keyword arguments.

1 # framework
2

3 class PylonsControllerViewMapper(object):
4 def __init__(self, **kw):
5 self.kw = kw
6

7 def __call__(self, view):


8 attr = self.kw['attr']
9 def wrapper(context, request):
10 matchdict = request.matchdict.copy()
11 matchdict.pop('action', None)
12 inst = view(request)
13 meth = getattr(inst, attr)
14 return meth(**matchdict)
15 return wrapper
16

17 class BaseController(object):
18 __view_mapper__ = PylonsControllerViewMapper

A user might make use of these framework components like so:

1 # user application
2

3 from pyramid.response import Response


4 from pyramid.config import Configurator
5 import pyramid_handlers
6 from wsgiref.simple_server import make_server
7

(continues on next page)

652 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


8 class MyController(BaseController):
9 def index(self, id):
10 return Response(id)
11

12 if __name__ == '__main__':
13 config = Configurator()
14 config.include(pyramid_handlers)
15 config.add_handler('one', '/{id}', MyController, action='index')
16 config.add_handler('two', '/{action}/{id}', MyController)
17 server.make_server('0.0.0.0', 8080, config.make_wsgi_app())
18 server.serve_forever()

The pyramid.config.Configurator.set_view_mapper() method can be used to set a de-


fault view mapper (overriding the superdefault view mapper used by Pyramid itself).

A single view registration can use a view mapper by passing the mapper as the mapper argument to
add_view().

Registering Configuration Decorators

Decorators such as view_config don’t change the behavior of the functions or classes they’re deco-
rating. Instead when a scan is performed, a modified version of the function or class is registered with
Pyramid.

You may wish to have your own decorators that offer such behaviour. This is possible by using the Venusian
package in the same way that it is used by Pyramid.

By way of example, let’s suppose you want to write a decorator that registers the function it wraps with
a Zope Component Architecture ”utility” within the application registry provided by Pyramid. The ap-
plication registry and the utility inside the registry is likely only to be available once your application’s
configuration is at least partially completed. A normal decorator would fail as it would be executed before
the configuration had even begun.

However, using Venusian, the decorator could be written as follows:

1 import venusian
2 from mypackage.interfaces import IMyUtility
3

4 class registerFunction(object):
5

(continues on next page)

0.3. Narrative Documentation 653


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


6 def __init__(self, path):
7 self.path = path
8

9 def register(self, scanner, name, wrapped):


10 registry = scanner.config.registry
11 registry.getUtility(IMyUtility).register(
12 self.path, wrapped)
13

14 def __call__(self, wrapped):


15 venusian.attach(wrapped, self.register)
16 return wrapped

This decorator could then be used to register functions throughout your code:

1 @registerFunction('/some/path')
2 def my_function():
3 do_stuff()

However, the utility would only be looked up when a scan was performed, enabling you to set up the utility
in advance:

1 from zope.interface import implementer


2

3 from wsgiref.simple_server import make_server


4 from pyramid.config import Configurator
5 from mypackage.interfaces import IMyUtility
6

7 @implementer(IMyUtility)
8 class UtilityImplementation:
9

10 def __init__(self):
11 self.registrations = {}
12

13 def register(self, path, callable_):


14 self.registrations[path] = callable_
15

16 if __name__ == '__main__':
17 config = Configurator()
18 config.registry.registerUtility(UtilityImplementation())
19 config.scan()
20 app = config.make_wsgi_app()
21 server = make_server('0.0.0.0', 8080, app)
22 server.serve_forever()

For full details, please read the Venusian documentation.

654 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Registering Tweens

New in version 1.2: Tweens

A tween (a contraction of the word ”between”) is a bit of code that sits between the Pyramid router’s main
request handling function and the upstream WSGI component that uses Pyramid as its ”app”. This is a
feature that may be used by Pyramid framework extensions to provide, for example, Pyramid-specific view
timing support bookkeeping code that examines exceptions before they are returned to the upstream WSGI
application. Tweens behave a bit like WSGI middleware, but they have the benefit of running in a context in
which they have access to the Pyramid request, response, and application registry, as well as the Pyramid
rendering machinery.

Creating a Tween

To create a tween, you must write a ”tween factory”. A tween factory must be a globally importable
callable which accepts two arguments: handler and registry. handler will be either the main
Pyramid request handling function or another tween. registry will be the Pyramid application registry
represented by this Configurator. A tween factory must return the tween (a callable object) when it is
called.

A tween is called with a single argument, request, which is the request created by Pyramid’s router
when it receives a WSGI request. A tween should return a response, usually the one generated by the
downstream Pyramid application.

You can write the tween factory as a simple closure-returning function:

1 def simple_tween_factory(handler, registry):


2 # one-time configuration code goes here
3

4 def simple_tween(request):
5 # code to be executed for each request before
6 # the actual application code goes here
7

8 response = handler(request)
9

10 # code to be executed for each request after


11 # the actual application code goes here
12

13 return response
14

15 return simple_tween

Alternatively, the tween factory can be a class with the __call__ magic method:

0.3. Narrative Documentation 655


The Pyramid Web Framework, Version 2.0.2

1 class simple_tween_factory(object):
2 def __init__(self, handler, registry):
3 self.handler = handler
4 self.registry = registry
5

6 # one-time configuration code goes here


7

8 def __call__(self, request):


9 # code to be executed for each request before
10 # the actual application code goes here
11

12 response = self.handler(request)
13

14 # code to be executed for each request after


15 # the actual application code goes here
16

17 return response

You should avoid mutating any state on the tween instance. The tween is invoked once per request and any
shared mutable state needs to be carefully handled to avoid any race conditions.

The closure style performs slightly better and enables you to conditionally omit the tween from the request
processing pipeline (see the following timing tween example), whereas the class style makes it easier to
have shared mutable state and allows subclassing.

Here’s a complete example of a tween that logs the time spent processing each request:

1 # in a module named myapp.tweens


2

3 import time
4 from pyramid.settings import asbool
5 import logging
6

7 log = logging.getLogger(__name__)
8

9 def timing_tween_factory(handler, registry):


10 if asbool(registry.settings.get('do_timing')):
11 # if timing support is enabled, return a wrapper
12 def timing_tween(request):
13 start = time.time()
14 try:
15 response = handler(request)
16 finally:
17 end = time.time()
(continues on next page)

656 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


18 log.debug('The request took %s seconds' %
19 (end - start))
20 return response
21 return timing_tween
22 # if timing support is not enabled, return the original
23 # handler
24 return handler

In the above example, the tween factory defines a timing_tween tween and returns it if
asbool(registry.settings.get('do_timing')) is true. It otherwise simply returns the
handler which it was given. The registry.settings attribute is a handle to the deployment set-
tings provided by the user (usually in an .ini file). In this case, if the user has defined a do_timing
setting and that setting is True, the user has said they want to do timing, so the tween factory returns the
timing tween; it otherwise just returns the handler it has been provided, preventing any timing.

The example timing tween simply records the start time, calls the downstream handler, logs the number of
seconds consumed by the downstream handler, and returns the response.

Registering an Implicit Tween Factory

Once you’ve created a tween factory, you can register it into the implicit tween chain using the pyramid.
config.Configurator.add_tween() method using its dotted Python name.

Here’s an example of registering a tween factory as an ”implicit” tween in a Pyramid application:

1 from pyramid.config import Configurator


2 config = Configurator()
3 config.add_tween('myapp.tweens.timing_tween_factory')

Note that you must use a dotted Python name as the first argument to pyramid.config.
Configurator.add_tween(); this must point at a tween factory. You cannot pass the tween fac-
tory object itself to the method: it must be dotted Python name that points to a globally importable
object. In the above example, we assume that a timing_tween_factory tween factory was de-
fined in a module named myapp.tweens, so the tween factory is importable as myapp.tweens.
timing_tween_factory.

When you use pyramid.config.Configurator.add_tween(), you’re instructing the system


to use your tween factory at startup time unless the user has provided an explicit tween list in their config-
uration. This is what’s meant by an ”implicit” tween. A user can always elect to supply an explicit tween

0.3. Narrative Documentation 657


The Pyramid Web Framework, Version 2.0.2

list, reordering or disincluding implicitly added tweens. See Explicit Tween Ordering for more information
about explicit tween ordering.

If more than one call to pyramid.config.Configurator.add_tween() is made within a single


application configuration, the tweens will be chained together at application startup time. The first tween
factory added via add_tween will be called with the Pyramid exception view tween factory as its han-
dler argument, then the tween factory added directly after that one will be called with the result of the
first tween factory as its handler argument, and so on, ad infinitum until all tween factories have been
called. The Pyramid router will use the outermost tween produced by this chain (the tween generated by
the very last tween factory added) as its request handler function. For example:

1 from pyramid.config import Configurator


2

3 config = Configurator()
4 config.add_tween('myapp.tween_factory1')
5 config.add_tween('myapp.tween_factory2')

The above example will generate an implicit tween chain that looks like this.

INGRESS (implicit)
myapp.tween_factory2
myapp.tween_factory1
pyramid.tweens.excview_tween_factory (implicit)
MAIN (implicit)

Suggesting Implicit Tween Ordering

By default, as described above, the ordering of the chain is controlled entirely by the relative ordering of
calls to pyramid.config.Configurator.add_tween(). However, the caller of add_tween
can provide an optional hint that can influence the implicit tween chain ordering by supplying under or
over (or both) arguments to add_tween(). These hints are only used when an explicit tween ordering
is not used. See Explicit Tween Ordering for a description of how to set an explicit tween ordering.

Allowable values for under or over (or both) are:

• None (the default),

• a dotted Python name to a tween factory: a string representing the predicted dotted name of a tween
factory added in a call to add_tween in the same configuration session,

658 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• one of the constants pyramid.tweens.MAIN, pyramid.tweens.INGRESS, or pyramid.


tweens.EXCVIEW , or

• an iterable of any combination of the above. This allows the user to specify fallbacks if the desired
tween is not included, as well as compatibility with multiple other tweens.

Effectively, over means ”closer to the request ingress than” and under means ”closer to the main Pyramid
application than”. You can think of an onion with outer layers over the inner layers, the application being
under all the layers at the center.

For example, the following call to add_tween() will attempt to place the tween factory represented by
myapp.tween_factory directly ”above” (in ptweens order) the main Pyramid request handler.

1 import pyramid.tweens
2

3 config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN)

The above example will generate an implicit tween chain that looks like this.

INGRESS (implicit)
pyramid.tweens.excview_tween_factory (implicit)
myapp.tween_factory
MAIN (implicit)

Likewise, calling the following call to add_tween() will attempt to place this tween factory ”above”
the main handler but ”below” a separately added tween factory:

1 import pyramid.tweens
2

3 config.add_tween('myapp.tween_factory1',
4 over=pyramid.tweens.MAIN)
5 config.add_tween('myapp.tween_factory2',
6 over=pyramid.tweens.MAIN,
7 under='myapp.tween_factory1')

The above example will generate an implicit tween chain that looks like this:

INGRESS (implicit)
pyramid.tweens.excview_tween_factory (implicit)
myapp.tween_factory1
myapp.tween_factory2
MAIN (implicit)

0.3. Narrative Documentation 659


The Pyramid Web Framework, Version 2.0.2

Specifying neither over nor under is equivalent to specifying under=INGRESS.


If all options for under (or over) cannot be found in the current configuration, it is an error. If some op-
tions are specified purely for compatibility with other tweens, just add a fallback of MAIN or INGRESS. For
example, under=('someothertween', 'someothertween2', INGRESS). This constraint
will require the tween to be located under the someothertween tween, the someothertween2
tween, and INGRESS. If any of these is not in the current configuration, this constraint will only organize
itself based on the tweens that are present.

Explicit Tween Ordering

Implicit tween ordering is obviously only best-effort. Pyramid will attempt to provide an implicit order of
tweens as best it can using hints provided by calls to add_tween(). But because it’s only best-effort, if
very precise tween ordering is required, the only surefire way to get it is to use an explicit tween order. The
deploying user can override the implicit tween inclusion and ordering implied by calls to add_tween()
entirely by using the pyramid.tweens settings value. When used, this settings value must be a list of
Python dotted names which will override the ordering (and inclusion) of tween factories in the implicit
tween chain. For example:

1 [app:main]
2 use = egg:MyApp
3 pyramid.reload_templates = true
4 pyramid.debug_authorization = false
5 pyramid.debug_notfound = false
6 pyramid.debug_routematch = false
7 pyramid.debug_templates = true
8 pyramid.tweens = myapp.my_cool_tween_factory
9 pyramid.tweens.excview_tween_factory

In the above configuration, calls made during configuration to pyramid.config.Configurator.


add_tween() are ignored, and the user is telling the system to use the tween factories he has listed in the
pyramid.tweens configuration setting (each is a dotted Python name which points to a tween factory)
instead of any tween factories added via pyramid.config.Configurator.add_tween(). The
first tween factory in the pyramid.tweens list will be used as the producer of the effective Pyramid
request handling function; it will wrap the tween factory declared directly ”below” it, ad infinitum. The
”main” Pyramid request handler is implicit, and always ”at the bottom”.

Pyramid’s own exception view handling logic is implemented as a tween factory function:
pyramid.tweens.excview_tween_factory(). If Pyramid exception view handling is desired,
and tween factories are specified via the pyramid.tweens configuration setting, the pyramid.
tweens.excview_tween_factory() function must be added to the pyramid.tweens config-
uration setting list explicitly. If it is not present, Pyramid will not perform exception view handling.

660 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Tween Conflicts and Ordering Cycles

Pyramid will prevent the same tween factory from being added to the tween chain more than once us-
ing configuration conflict detection. If you wish to add the same tween factory more than once in
a configuration, you should either: (a) use a tween factory that is a separate globally importable in-
stance object from the factory that it conflicts with; (b) use a function or class as a tween factory with
the same logic as the other tween factory it conflicts with, but with a different __name__ attribute;
or (c) call pyramid.config.Configurator.commit() between calls to pyramid.config.
Configurator.add_tween().

If a cycle is detected in implicit tween ordering when over and under are used in any call to
add_tween, an exception will be raised at startup time.

Displaying Tween Ordering

The ptweens command-line utility can be used to report the current implicit and explicit tween chains
used by an application. See ptweens: Displaying ”Tweens”.

Adding a Custom View, Route, or Subscriber Predicate

New in version 1.4.

View and Route Predicates

View and route predicates used during configuration allow you to narrow the set of circumstances under
which a view or route will match. For example, the request_method view predicate can be used to
ensure a view callable is only invoked when the request’s method is POST:

@view_config(request_method='POST')
def someview(request):
...

Likewise, a similar predicate can be used as a route predicate:

0.3. Narrative Documentation 661


The Pyramid Web Framework, Version 2.0.2

config.add_route('name', '/foo', request_method='POST')

Many other built-in predicates exists (request_param, and others). You can add cus-
tom predicates to the list of available predicates by using one of pyramid.config.
Configurator.add_view_predicate() or pyramid.config.Configurator.
add_route_predicate(). The former adds a view predicate, the latter a route predicate.

When using one of those APIs, you pass a name and a factory to add a predicate during Pyramid’s config-
uration stage. For example:

config.add_view_predicate('content_type', ContentTypePredicate)

The above example adds a new predicate named content_type to the list of available predicates for
views. This will allow the following view configuration statement to work:

1 @view_config(content_type='File')
2 def aview(request): ...

The first argument to pyramid.config.Configurator.add_view_predicate(), the name,


is a string representing the name that is expected to be passed to view_config (or its imperative analogue
add_view).

The second argument is a view or route predicate factory, or a dotted Python name which refers to a
view or route predicate factory. A view or route predicate factory is most often a class with a constructor
(__init__), a text method, a phash method, and a __call__ method. For example:

1 class ContentTypePredicate(object):
2 def __init__(self, val, info):
3 self.val = val
4

5 def text(self):
6 return 'content_type = %s' % (self.val,)
7

8 phash = text
9

10 def __call__(self, context, request):


11 return request.content_type == self.val

662 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The constructor of an pyramid.interfaces.IPredicateFactory` takes two arguments: val


and info. The val argument will be the argument passed to view_config (or add_view). In
the example above, it will be the string File. The second argument, info, will be an pyramid.
interfaces.IPredicateInfo instance created relative to the action configuring the predicate. This
means the info.package value is the package where the action is invoked passing in val and info.
maybe_dotted is also relative to this package.

The text method must return a string. It should be useful to describe the behavior of the predicate in
error messages.

The phash method must return a string or a sequence of strings. It’s most often the same as text, as long
as text uniquely describes the predicate’s name and the value passed to the constructor. If text is more
general, or doesn’t describe things that way, phash should return a string with the name and the value
serialized. The result of phash is not seen in output anywhere, it just informs the uniqueness constraints
for view configuration.

The __call__ method differs depending on whether the predicate is used as a view predicate or a route
predicate:

• When used as a route predicate, the __call__ signature is (info, request). The info
object is a dictionary containing two keys: match and route. info['match'] is the match-
dict containing the patterns matched in the route pattern. info['route'] is the pyramid.
interfaces.IRoute object for the current route.

• When used as a view predicate, the __call__ signature is (context, request). The con-
text is the result of traversal performed using either the route’s root factory or the app’s default
root factory.

In all cases the __call__ method is expected to return True or False.

It is possible to use the same predicate factory as both a view predicate and as a route predicate, but they’ll
need to handle the info or context argument specially (many predicates do not need this argument)
and you’ll need to call add_view_predicate and add_route_predicate separately with the
same factory.

Subscriber Predicates

Subscriber predicates work almost exactly like view and route predicates. They narrow the set of circum-
stances in which a subscriber will be called. There are several minor differences between a subscriber
predicate and a view or route predicate:

0.3. Narrative Documentation 663


The Pyramid Web Framework, Version 2.0.2

• There are no default subscriber predicates. You must register one to use one.

• The __call__ method of a subscriber predicate accepts a single event object instead of a con-
text and a request.

• Not every subscriber predicate can be used with every event type. Some subscriber predicates will
assume a certain event type.

Here’s an example of a subscriber predicate that can be used in conjunction with a subscriber that subscribes
to the pyramid.events.NewRequest event type.

1 class RequestPathStartsWith(object):
2 def __init__(self, val, info):
3 self.val = val
4

5 def text(self):
6 return 'request_path_startswith = %s' % (self.val,)
7

8 phash = text
9

10 def __call__(self, event):


11 return event.request.path.startswith(self.val)

Once you’ve created a subscriber predicate, it may be registered via pyramid.config.


Configurator.add_subscriber_predicate(). For example:

config.add_subscriber_predicate(
'request_path_startswith', RequestPathStartsWith)

Once a subscriber predicate is registered, you can use it in a call to pyramid.config.


Configurator.add_subscriber() or to pyramid.events.subscriber. Here’s an ex-
ample of using the previously registered request_path_startswith predicate in a call to
add_subscriber():

1 # define a subscriber in your code


2

3 def yosubscriber(event):
4 event.request.yo = 'YO!'
5

6 # and at configuration time


7

8 config.add_subscriber(yosubscriber, NewRequest,
9 request_path_startswith='/add_yo')

664 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Here’s the same subscriber/predicate/event-type combination used via subscriber.

1 from pyramid.events import subscriber


2

3 @subscriber(NewRequest, request_path_startswith='/add_yo')
4 def yosubscriber(event):
5 event.request.yo = 'YO!'

In either of the above configurations, the yosubscriber callable will only be called if the request path
starts with /add_yo. Otherwise the event subscriber will not be called.

Note that the request_path_startswith subscriber you defined can be used with events that have
a request attribute, but not ones that do not. So, for example, the predicate can be used with subscribers
registered for pyramid.events.NewRequest and pyramid.events.ContextFound events,
but it cannot be used with subscribers registered for pyramid.events.ApplicationCreated be-
cause the latter type of event has no request attribute. The point being, unlike route and view predicates,
not every type of subscriber predicate will necessarily be applicable for use in every subscriber registra-
tion. It is not the responsibility of the predicate author to make every predicate make sense for every event
type; it is the responsibility of the predicate consumer to use predicates that make sense for a particular
event type registration.

View Derivers

New in version 1.7.

Every URL processed by Pyramid is matched against a custom view pipeline. See Request Processing
for how this works. The view pipeline itself is built from the user-supplied view callable, which is then
composed with view derivers. A view deriver is a composable element of the view pipeline which is used
to wrap a view with added functionality. View derivers are very similar to the decorator argument to
pyramid.config.Configurator.add_view(), except that they have the option to execute for
every view in the application.

It is helpful to think of a view deriver as middleware for views. Unlike tweens or WSGI middleware which
are scoped to the application itself, a view deriver is invoked once per view in the application, and can use
configuration options from the view to customize its behavior.

0.3. Narrative Documentation 665


The Pyramid Web Framework, Version 2.0.2

Built-in View Derivers

There are several built-in view derivers that Pyramid will automatically apply to any view. Below they are
defined in order from furthest to closest to the user-defined view callable:
secured_view
Enforce the permission defined on the view. This element is a no-op if no permission is
defined. Note there will always be a permission defined if a default permission was assigned
via pyramid.config.Configurator.set_default_permission() unless the
view is an exception view.
This element will also output useful debugging information when pyramid.
debug_authorization is enabled.
csrf_view
Used to check the CSRF token provided in the request. This element is a no-op if re-
quire_csrf view option is not True. Note there will always be a require_csrf
option if a default value was assigned via pyramid.config.Configurator.
set_default_csrf_options() unless the view is an exception view.
owrapped_view
Invokes the wrapped view defined by the wrapper option.
http_cached_view
Applies cache control headers to the response defined by the http_cache option. This
element is a no-op if the pyramid.prevent_http_cache setting is enabled or the
http_cache option is None.
decorated_view
Wraps the view with the decorators from the decorator option.
rendered_view
Adapts the result of the view callable into a response object. Below this point the result may
be any Python object.
mapped_view
Applies the view mapper defined by the mapper option or the application’s default view
mapper to the view callable. This is always the closest deriver to the user-defined view and
standardizes the view pipeline interface to accept (context, request) from all previous
view derivers.

666 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Any view derivers defined under the rendered_view are not guaranteed to receive a valid
response object. Rather they will receive the result from the view mapper which is likely the original
response returned from the view. This is possibly a dictionary for a renderer but it may be any Python
object that may be adapted into a response.

Custom View Derivers

It is possible to define custom view derivers which will affect all views in an application. There are
many uses for this, but most will likely be centered around monitoring and security. In order to regis-
ter a custom view deriver, you should create a callable that conforms to the pyramid.interfaces.
IViewDeriver interface, and then register it with your application using pyramid.config.
Configurator.add_view_deriver(). The callable should accept the view to be wrapped and
the info object which is an instance of pyramid.interfaces.IViewDeriverInfo. For exam-
ple, below is a callable that can provide timing information for the view pipeline:

1 import time
2

3 def timing_view(view, info):


4 if info.options.get('timed'):
5 def wrapper_view(context, request):
6 start = time.time()
7 response = view(context, request)
8 end = time.time()
9 response.headers['X-View-Performance'] = '%.3f' % (end - start,
,→)

10 return response
11 return wrapper_view
12 return view
13

14 timing_view.options = ('timed',)
15

16 config.add_view_deriver(timing_view)

The setting of timed on the timing_view signifies to Pyramid that timed is a valid view_config
keyword argument now. The timing_view custom view deriver as registered above will only be active
for any view defined with a timed=True value passed as one of its view_config keywords.

For example, this view configuration will not be a timed view:

0.3. Narrative Documentation 667


The Pyramid Web Framework, Version 2.0.2

1 @view_config(route_name='home')
2 def home(request):
3 return Response('Home')

But this view will have timing information added to the response headers:

1 @view_config(route_name='home', timed=True)
2 def home(request):
3 return Response('Home')

View derivers are unique in that they have access to most of the options passed to pyramid.config.
Configurator.add_view() in order to decide what to do, and they have a chance to affect every
view in the application.

Exception Views and View Derivers

A view deriver has the opportunity to wrap any view, including an exception view. In general this is fine, but
certain view derivers may wish to avoid doing certain things when handling exceptions. For example, the
csrf_view and secured_view built-in view derivers will not perform security checks on exception
views unless explicitly told to do so.

You can check for info.exception_only on the pyramid.interfaces.


IViewDeriverInfo object when wrapping the view to determine whether you are wrapping an
exception view or a normal view.

Ordering View Derivers

By default, every new view deriver is added between the decorated_view and rendered_view
built-in derivers. It is possible to customize this ordering using the over and under options. Each
option can use the names of other view derivers in order to specify an ordering. There should rarely be a
reason to worry about the ordering of the derivers except when the deriver depends on other operations in
the view pipeline.

Both over and under may also be iterables of constraints. For either option, if one or more constraints
was defined, at least one must be satisfied, else a pyramid.exceptions.ConfigurationError
will be raised. This may be used to define fallback constraints if another deriver is missing.

668 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Two sentinel values exist, pyramid.viewderivers.INGRESS and pyramid.viewderivers.


VIEW , which may be used when specifying constraints at the edges of the view pipeline. For example, to
add a deriver at the start of the pipeline you may use under=INGRESS.
It is not possible to add a view deriver under the mapped_view as the view mapper is intimately tied
to the signature of the user-defined view callable. If you simply need to know what the original view
callable was, it can be found as info.original_view on the provided pyramid.interfaces.
IViewDeriverInfo object passed to every view deriver.

The default constraints for any view deriver are over='rendered_view' and un-
der='decorated_view'. When escaping these constraints you must take care to avoid cyclic
dependencies between derivers. For example, if you want to add a new view deriver before se-
cured_view then simply specifying over='secured_view' is not enough, because the default
is also under decorated view there will be an unsatisfiable cycle. You must specify a valid under
constraint as well, such as under=INGRESS to fall between INGRESS and secured_view at the
beginning of the view pipeline.

0.3.32 Pyramid Configuration Introspection

New in version 1.3.


When Pyramid starts up, each call to a configuration directive causes one or more introspectable objects
to be registered with an introspector. The introspector can be queried by application code to obtain in-
formation about the configuration of the running application. This feature is useful for debug toolbars,
command-line scripts which show some aspect of configuration, and for runtime reporting of startup-time
configuration settings.

Using the Introspector

Here’s an example of using Pyramid’s introspector from within a view callable:

1 from pyramid.view import view_config


2 from pyramid.response import Response
3

4 @view_config(route_name='bar')
5 def show_current_route_pattern(request):
6 introspector = request.registry.introspector
7 route_name = request.matched_route.name
8 route_intr = introspector.get('routes', route_name)
9 return Response(str(route_intr['pattern']))

0.3. Narrative Documentation 669


The Pyramid Web Framework, Version 2.0.2

This view will return a response that contains the ”pattern” argument provided to the add_route
method of the route which matched when the view was called. It uses the pyramid.interfaces.
IIntrospector.get() method to return an introspectable in the category routes with a discrim-
inator equal to the matched route name. It then uses the returned introspectable to obtain a ”pattern”
value.

The introspectable returned by the query methods of the introspector has methods and attributes described
by pyramid.interfaces.IIntrospectable. In particular, the get(), get_category(),
categories(), categorized(), and related() methods of an introspector can be used to query
for introspectables.

Introspectable Objects

Introspectable objects are returned from query methods of an introspector. Each introspectable object
implements the attributes and methods documented at pyramid.interfaces.IIntrospectable.

The important attributes shared by all introspectables are the following:

title

A human-readable text title describing the introspectable

category_name

A text category name describing the introspection category to which this introspectable be-
longs. It is often a plural if there are expected to be more than one introspectable registered
within the category.

discriminator

A hashable object representing the unique value of this introspectable within its category.

discriminator_hash

The integer hash of the discriminator (useful in HTML links).

type_name

The text name of a subtype within this introspectable’s category. If there is only one type name
in this introspectable’s category, this value will often be a singular version of the category name
but it can be an arbitrary value.

670 CONTENTS
The Pyramid Web Framework, Version 2.0.2

action_info

An object describing the directive call site which caused this introspectable to be registered.
It contains attributes described in pyramid.interfaces.IActionInfo.

Besides having the attributes described above, an introspectable is a dictionary-like object. An intro-
spectable can be queried for data values via its __getitem__, get, keys, values, or items meth-
ods. For example:

1 route_intr = introspector.get('routes', 'edit_user')


2 pattern = route_intr['pattern']

Pyramid Introspection Categories

The list of concrete introspection categories provided by built-in Pyramid configuration directives follows.
Add-on packages may supply other introspectables in categories not described here.

subscribers

Each introspectable in the subscribers category represents a call to pyramid.


config.Configurator.add_subscriber() (or the decorator equivalent). Each
will have the following data.

subscriber

The subscriber callable object (the resolution of the subscriber argument


passed to add_subscriber).

interfaces

A sequence of interfaces (or classes) that are subscribed to (the resolution of the
ifaces argument passed to add_subscriber).

derived_subscriber

A wrapper around the subscriber used internally by the system so it can call it with
more than one argument if your original subscriber accepts only one.

predicates

0.3. Narrative Documentation 671


The Pyramid Web Framework, Version 2.0.2

The predicate objects created as the result of passing predicate arguments to


add_subscriber.

derived_predicates

Wrappers around the predicate objects created as the result of passing predicate
arguments to add_subscriber (to be used when predicates take only one value
but must be passed more than one).

response adapters

Each introspectable in the response adapters category represents a call to pyramid.


config.Configurator.add_response_adapter() (or a decorator equivalent).
Each will have the following data.

adapter

The adapter object (the resolved adapter argument to


add_response_adapter).

type

The resolved type_or_iface argument passed to


add_response_adapter.

root factories

Each introspectable in the root factories category represents a call to pyramid.


config.Configurator.set_root_factory() (or the Configurator constructor
equivalent) or a factory argument passed to pyramid.config.Configurator.
add_route(). Each will have the following data.

factory

The factory object (the resolved factory argument to set_root_factory).

route_name

The name of the route which will use this factory. If this is the default root factory
(if it’s registered during a call to set_root_factory), this value will be None.

session factory

672 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Only one introspectable will exist in the session factory category. It represents a call
to pyramid.config.Configurator.set_session_factory() (or the Config-
urator constructor equivalent). It will have the following data.

factory

The factory object (the resolved factory argument to


set_session_factory).

request factory

Only one introspectable will exist in the request factory category. It represents a call
to pyramid.config.Configurator.set_request_factory() (or the Config-
urator constructor equivalent). It will have the following data.

factory

The factory object (the resolved factory argument to


set_request_factory).

locale negotiator

Only one introspectable will exist in the locale negotiator category. It represents
a call to pyramid.config.Configurator.set_locale_negotiator() (or the
Configurator constructor equivalent). It will have the following data.

negotiator

The factory object (the resolved negotiator argument to


set_locale_negotiator).

renderer factories

Each introspectable in the renderer factories category represents a call to pyramid.


config.Configurator.add_renderer() (or the Configurator constructor equiva-
lent). Each will have the following data.

name

The name of the renderer (the value of the name argument to add_renderer).

factory

0.3. Narrative Documentation 673


The Pyramid Web Framework, Version 2.0.2

The factory object (the resolved factory argument to add_renderer).

routes

Each introspectable in the routes category represents a call to pyramid.config.


Configurator.add_route(). Each will have the following data.

name

The name argument passed to add_route.

pattern

The pattern argument passed to add_route.

factory

The (resolved) factory argument passed to add_route.

xhr

The xhr argument passed to add_route.

request_method

The request_method argument passed to add_route.

request_methods

A sequence of request method names implied by the request_method argu-


ment passed to add_route or the value None if a request_method argu-
ment was not supplied.

path_info

The path_info argument passed to add_route.

request_param

The request_param argument passed to add_route.

header

674 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The header argument passed to add_route.

accept

The accept argument passed to add_route.

traverse

The traverse argument passed to add_route.

custom_predicates

The custom_predicates argument passed to add_route.

pregenerator

The pregenerator argument passed to add_route.

static

The static argument passed to add_route.

use_global_views

The use_global_views argument passed to add_route.

object

The pyramid.interfaces.IRoute object that is used to perform matching


and generation for this route.

security policy

There will be one and only one introspectable in the security policy category. It repre-
sents a call to the pyramid.config.Configurator.set_security_policy()
method (or its Configurator constructor equivalent). It will have the following data:

policy

The policy object (the resolved policy argument to


set_security_policy).

authentication policy

0.3. Narrative Documentation 675


The Pyramid Web Framework, Version 2.0.2

There will be one and only one introspectable in the authentication pol-
icy category. It represents a call to the pyramid.config.Configurator.
set_authentication_policy() method (or its Configurator constructor equivalent).
It will have the following data.

policy

The policy object (the resolved policy argument to


set_authentication_policy).

authorization policy

There will be one and only one introspectable in the authorization pol-
icy category. It represents a call to the pyramid.config.Configurator.
set_authorization_policy() method (or its Configurator constructor equivalent).
It will have the following data.

policy

The policy object (the resolved policy argument to


set_authorization_policy).

default permission

There will be one and only one introspectable in the default permission
category. It represents a call to the pyramid.config.Configurator.
set_default_permission() method (or its Configurator constructor equivalent). It
will have the following data.

value

The permission name passed to set_default_permission.

default csrf options

There will be one and only one introspectable in the default csrf op-
tions category. It represents a call to the pyramid.config.Configurator.
set_default_csrf_options() method. It will have the following data.

require_csrf

The default value for require_csrf if left unspecified on calls to pyramid.


config.Configurator.add_view().

676 CONTENTS
The Pyramid Web Framework, Version 2.0.2

token

The name of the token searched in request.POST to find a valid CSRF token.

header

The name of the request header searched to find a valid CSRF token.

safe_methods

The list of HTTP methods considered safe and exempt from CSRF checks.

views

Each introspectable in the views category represents a call to pyramid.config.


Configurator.add_view(). Each will have the following data.

name

The name argument passed to add_view.

context

The (resolved) context argument passed to add_view.

containment

The (resolved) containment argument passed to add_view.

request_param

The request_param argument passed to add_view.

request_methods

A sequence of request method names implied by the request_method argu-


ment passed to add_view or the value None if a request_method argument
was not supplied.

route_name

The route_name argument passed to add_view.

0.3. Narrative Documentation 677


The Pyramid Web Framework, Version 2.0.2

attr

The attr argument passed to add_view.

xhr

The xhr argument passed to add_view.

accept

The accept argument passed to add_view.

header

The header argument passed to add_view.

path_info

The path_info argument passed to add_view.

match_param

The match_param argument passed to add_view.

csrf_token

The csrf_token argument passed to add_view.

callable

The (resolved) view argument passed to add_view. Represents the ”raw” view
callable.

derived_callable

The view callable derived from the view argument passed to add_view. Rep-
resents the view callable which Pyramid itself calls (wrapped in security and other
wrappers).

mapper

The (resolved) mapper argument passed to add_view.

678 CONTENTS
The Pyramid Web Framework, Version 2.0.2

decorator

The (resolved) decorator argument passed to add_view.

permissions

Each introspectable in the permissions category represents a call to pyramid.


config.Configurator.add_view() that has an explicit permission argument or
a call to pyramid.config.Configurator.set_default_permission(). Each
will have the following data.

value

The permission name passed to add_view or set_default_permission.

templates

Each introspectable in the templates category represents a call to pyramid.config.


Configurator.add_view() that has a renderer argument which points to a tem-
plate. Each will have the following data.

name

The renderer’s name (a string).

type

The renderer’s type (a string).

renderer

The pyramid.interfaces.IRendererInfo object which represents this


template’s renderer.

view mappers

Each introspectable in the view mappers category represents a call to pyramid.


config.Configurator.add_view() that has an explicit mapper argument or a call
to pyramid.config.Configurator.set_view_mapper(). Each will have the
following data.

mapper

0.3. Narrative Documentation 679


The Pyramid Web Framework, Version 2.0.2

The (resolved) mapper argument passed to add_view or


set_view_mapper.

asset overrides

Each introspectable in the asset overrides category represents a call to pyramid.


config.Configurator.override_asset(). Each will have the following data.

to_override

The to_override argument (an asset spec) passed to override_asset.

override_with

The override_with argument (an asset spec) passed to override_asset.

translation directories

Each introspectable in the translation directories category represents an indi-


vidual element in a specs argument passed to pyramid.config.Configurator.
add_translation_dirs(). Each will have the following data.

directory

The absolute path of the translation directory.

spec

The asset specification passed to add_translation_dirs.

tweens

Each introspectable in the tweens category represents a call to pyramid.config.


Configurator.add_tween(). Each will have the following data.

name

The dotted name to the tween factory as a string (passed as the tween_factory
argument to add_tween).

factory

The (resolved) tween factory object.

680 CONTENTS
The Pyramid Web Framework, Version 2.0.2

type
implicit or explicit as a string.
under
The under argument passed to add_tween (a string).
over
The over argument passed to add_tween (a string).
static views
Each introspectable in the static views category represents a call to pyramid.
config.Configurator.add_static_view(). Each will have the following data.
name
The name argument provided to add_static_view.
spec
A normalized version of the spec argument provided to add_static_view.
traversers
Each introspectable in the traversers category represents a call to pyramid.config.
Configurator.add_traverser(). Each will have the following data.
iface
The (resolved) interface or class object that represents the return value of a root
factory for which this traverser will be used.
adapter
The (resolved) traverser class.
resource url adapters
Each introspectable in the resource url adapters category represents a call to
pyramid.config.Configurator.add_resource_url_adapter(). Each will
have the following data.
adapter
The (resolved) resource URL adapter class.
resource_iface
The (resolved) interface or class object that represents the resource interface for
which this URL adapter is registered.
request_iface
The (resolved) interface or class object that represents the request interface for
which this URL adapter is registered.

0.3. Narrative Documentation 681


The Pyramid Web Framework, Version 2.0.2

Introspection in the Toolbar

The Pyramid debug toolbar (part of the pyramid_debugtoolbar package) provides a canned view
of all registered introspectables and their relationships. It is currently under the ”Global” tab in the main
navigation, and it looks something like this:

682 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Disabling Introspection

You can disable Pyramid introspection by passing the flag introspection=False to the Configurator
constructor in your application setup:

from pyramid.config import Configurator


config = Configurator(..., introspection=False)

When introspection is False, all introspectables generated by configuration directives are thrown
away.

0.3.33 Extending an Existing Pyramid Application

If a Pyramid developer has obeyed certain constraints while building an application, a third party should
be able to change the application’s behavior without needing to modify its source code. The behavior of a
Pyramid application that obeys certain constraints can be overridden or extended without modification.

We’ll define some jargon here for the benefit of identifying the parties involved in such an effort.

Developer
The original application developer.

Integrator
Another developer who wishes to reuse the application written by the original application developer
in an unanticipated context. They may also wish to modify the original application without changing
the original application’s source code.

The Difference Between ”Extensible” and ”Pluggable” Applications

Other web frameworks, such as Django, advertise that they allow developers to create ”pluggable applica-
tions”. They claim that if you create an application in a certain way, it will be integratable in a sensible,
structured way into another arbitrarily-written application or project created by a third-party developer.

Pyramid, as a platform, does not claim to provide such a feature. The platform provides no guarantee that
you can create an application and package it up such that an arbitrary integrator can use it as a subcomponent
in a larger Pyramid application or project. Pyramid does not mandate the constraints necessary for such a
pattern to work satisfactorily. Because Pyramid is not very ”opinionated”, developers are able to use wildly
different patterns and technologies to build an application. A given Pyramid application may happen to be

0.3. Narrative Documentation 683


The Pyramid Web Framework, Version 2.0.2

reusable by a particular third party integrator because the integrator and the original developer may share
similar base technology choices (such as the use of a particular relational database or ORM). But the same
application may not be reusable by a different developer, because they have made different technology
choices which are incompatible with the original developer’s.
As a result, the concept of a ”pluggable application” is left to layers built above Pyramid, such as a ”CMS”
layer or ”application server” layer. Such layers are apt to provide the necessary ”opinions” (such as man-
dating a storage layer, a templating system, and a structured, well-documented pattern of registering that
certain URLs map to certain bits of code) which makes the concept of a ”pluggable application” possible.
”Pluggable applications”, thus, should not plug into Pyramid itself but should instead plug into a system
written atop Pyramid.
Although it does not provide for ”pluggable applications”, Pyramid does provide a rich set of mechanisms
which allows for the extension of a single existing application. Such features can be used by frameworks
built using Pyramid as a base. All Pyramid applications may not be pluggable, but all Pyramid applications
are extensible.

Rules for Building an Extensible Application

There is only one rule you need to obey if you want to build a maximally extensible Pyramid application:
as a developer, you should factor any overridable imperative configuration you’ve created into functions
which can be used via pyramid.config.Configurator.include(), rather than inlined as calls
to methods of a Configurator within the main function in your application’s __init__.py. For exam-
ple, rather than:

1 from pyramid.config import Configurator


2

3 if __name__ == '__main__':
4 config = Configurator()
5 config.add_view('myapp.views.view1', name='view1')
6 config.add_view('myapp.views.view2', name='view2')

You should move the calls to add_view outside of the (non-reusable) if __name__ ==
'__main__' block, and into a reusable function:

1 from pyramid.config import Configurator


2

3 if __name__ == '__main__':
4 config = Configurator()
5 config.include(add_views)
6

7 def add_views(config):
8 config.add_view('myapp.views.view1', name='view1')
9 config.add_view('myapp.views.view2', name='view2')

684 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Doing this allows an integrator to maximally reuse the configuration statements that relate to your appli-
cation by allowing them to selectively include or exclude the configuration functions you’ve created from
an ”override package”.

Alternatively you can use ZCML for the purpose of making configuration extensible and overridable.
ZCML declarations that belong to an application can be overridden and extended by integrators as nec-
essary in a similar fashion. If you use only ZCML to configure your application, it will automatically be
maximally extensible without any manual effort. See pyramid_zcml for information about using ZCML.

Fundamental Plugpoints

The fundamental ”plug points” of an application developed using Pyramid are routes, views, and as-
sets. Routes are declarations made using the pyramid.config.Configurator.add_route()
method. Views are declarations made using the pyramid.config.Configurator.add_view()
method. Assets are files that are accessed by Pyramid using the pkg_resources API such as static files and
templates via a asset specification. Other directives and configurator methods also deal in routes, views,
and assets. For example, the add_handler directive of the pyramid_handlers package adds a
single route and some number of views.

Extending an Existing Application

The steps for extending an existing application depend largely on whether the application does or does not
use configuration decorators or imperative code.

If the Application Has Configuration Decorations

You’ve inherited a Pyramid application which you’d like to extend or override that uses pyramid.view.
view_config decorators or other configuration decoration decorators.

If you just want to extend the application, you can run a scan against the application’s package, then add
additional configuration that registers more views or routes.

1 if __name__ == '__main__':
2 config.scan('someotherpackage')
3 config.add_view('mypackage.views.myview', name='myview')

If you want to override configuration in the application, you may need to run pyramid.config.
Configurator.commit() after performing the scan of the original package, then add additional
configuration that registers more views or routes which perform overrides.

0.3. Narrative Documentation 685


The Pyramid Web Framework, Version 2.0.2

1 if __name__ == '__main__':
2 config.scan('someotherpackage')
3 config.commit()
4 config.add_view('mypackage.views.myview', name='myview')

Once this is done, you should be able to extend or override the application like any other (see Extending
the Application).

You can alternatively just prevent a scan from happening by omitting any call to the pyramid.config.
Configurator.scan() method. This will cause the decorators attached to objects in the target ap-
plication to do nothing. At this point, you will need to convert all the configuration done in decorators into
equivalent imperative configuration or ZCML, and add that configuration or ZCML to a separate Python
package as described in Extending the Application.

Extending the Application

To extend or override the behavior of an existing application, you will need to create a new package which
includes the configuration of the old package, and you’ll perhaps need to create implementations of the
types of things you’d like to override (such as views), to which they are referred within the original package.

The general pattern for extending an existing application looks something like this:

• Create a new Python package. The easiest way to do this is to create a new Pyramid application
using our cookiecutter. See Creating the Project for more information.

• In the new package, create Python files containing views and other overridden elements, such as
templates and static assets as necessary.

• Install the new package into the same Python environment as the original application (e.g., $VENV/
bin/pip install -e . or $VENV/bin/pip install .).

• Change the main function in the new package’s __init__.py to include the original Pyramid
application’s configuration functions via pyramid.config.Configurator.include()
statements or a scan.

• Wire the new views and assets created in the new package up using imperative registrations within
the main function of the __init__.py file of the new application. This wiring should happen
after including the configuration functions of the old application. These registrations will extend or
override any registrations performed by the original application. See Overriding Views, Overriding
Routes, and Overriding Assets.

686 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Overriding Views

The view configuration declarations that you make which override application behavior will usually have
the same view predicate attributes as the original that you wish to override. These <view> declarations
will point at ”new” view code in the override package that you’ve created. The new view code itself will
usually be copy-and-paste copies of view callables from the original application with slight tweaks.

For example, if the original application has the following configure_views configuration method:

1 def configure_views(config):
2 config.add_view('theoriginalapp.views.theview', name='theview')

You can override the first view configuration statement made by configure_views within the override
package, after loading the original configuration function:

1 from pyramid.config import Configurator


2 from originalapp import configure_views
3

4 if __name == '__main__':
5 config = Configurator()
6 config.include(configure_views)
7 config.add_view('theoverrideapp.views.theview', name='theview')

In this case, the theoriginalapp.views.theview view will never be executed. Instead, a new
view, theoverrideapp.views.theview will be executed when request circumstances dictate.

A similar pattern can be used to extend the application with add_view declarations. Just register a new
view against some other set of predicates to make sure the URLs it implies are available on some other
page rendering.

Overriding Routes

Route setup is currently typically performed in a sequence of ordered calls to add_route(). Because
these calls are ordered relative to each other, and because this ordering is typically important, you should re-
tain their relative ordering when performing an override. Typically this means copying all the add_route
statements into the override package’s file and changing them as necessary. Then exclude any add_route
statements from the original application.

0.3. Narrative Documentation 687


The Pyramid Web Framework, Version 2.0.2

Overriding Assets

Assets are files on the filesystem that are accessible within a Python package. An entire chapter is devoted to
assets: Static Assets. Within this chapter is a section named Overriding Assets. This section of that chapter
describes in detail how to override package assets with other assets by using the pyramid.config.
Configurator.override_asset() method. Add such override_asset calls to your override
package’s __init__.py to perform overrides.

0.3.34 Advanced Configuration

To support application extensibility, the Pyramid Configurator by default detects configuration conflicts
and allows you to include configuration imperatively from other packages or modules. It also by default
performs configuration in two separate phases. This allows you to ignore relative configuration statement
ordering in some circumstances.

Conflict Detection

Here’s a familiar example of one of the simplest Pyramid applications, configured imperatively:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4

5 def hello_world(request):
6 return Response('Hello world!')
7

8 if __name__ == '__main__':
9 config = Configurator()
10 config.add_view(hello_world)
11 app = config.make_wsgi_app()
12 server = make_server('0.0.0.0', 8080, app)
13 server.serve_forever()

When you start this application, all will be OK. However, what happens if we try to add another view to
the configuration with the same set of predicate arguments as one we’ve already added?

688 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4

5 def hello_world(request):
6 return Response('Hello world!')
7

8 def goodbye_world(request):
9 return Response('Goodbye world!')
10

11 if __name__ == '__main__':
12 config = Configurator()
13

14 config.add_view(hello_world, name='hello')
15

16 # conflicting view configuration


17 config.add_view(goodbye_world, name='hello')
18

19 app = config.make_wsgi_app()
20 server = make_server('0.0.0.0', 8080, app)
21 server.serve_forever()

The application now has two conflicting view configuration statements. When we try to start it again, it
won’t start. Instead we’ll receive a traceback that ends something like this:

1 Traceback (most recent call last):


2 File "app.py", line 12, in <module>
3 app = config.make_wsgi_app()
4 File "pyramid/config.py", line 839, in make_wsgi_app
5 self.commit()
6 File "pyramid/pyramid/config.py", line 473, in commit
7 self._ctx.execute_actions()
8 ... more code ...
9 pyramid.exceptions.ConfigurationConflictError:
10 Conflicting configuration actions
11 For: ('view', None, '', None, <InterfaceClass pyramid.interfaces.IView>,
12 None, None, None, None, None, False, None, None, None)
13 Line 14 of file app.py in <module>: 'config.add_view(hello_world)'
14 Line 17 of file app.py in <module>: 'config.add_view(goodbye_world)'

This traceback is trying to tell us:

• We’ve got conflicting information for a set of view configuration statements (The For: line).

0.3. Narrative Documentation 689


The Pyramid Web Framework, Version 2.0.2

• There are two statements which conflict, shown beneath the For: line: config.
add_view(hello_world. 'hello') on line 14 of app.py, and config.
add_view(goodbye_world, 'hello') on line 17 of app.py.

These two configuration statements are in conflict because we’ve tried to tell the system that the set of
predicate values for both view configurations are exactly the same. Both the hello_world and good-
bye_world views are configured to respond under the same set of circumstances. This circumstance,
the view name represented by the name= predicate, is hello.

This presents an ambiguity that Pyramid cannot resolve. Rather than allowing the circumstance to go
unreported, by default Pyramid raises a ConfigurationConflictError error and prevents the ap-
plication from running.

Conflict detection happens for any kind of configuration: imperative configuration or configuration that
results from the execution of a scan.

Manually Resolving Conflicts

There are a number of ways to manually resolve conflicts: by changing registrations to not conflict, by
strategically using pyramid.config.Configurator.commit(), or by using an ”autocommit-
ting” configurator.

The Right Thing

The most correct way to resolve conflicts is to ”do the needful”: change your configuration code to not have
conflicting configuration statements. The details of how this is done depends entirely on the configuration
statements made by your application. Use the detail provided in the ConfigurationConflictEr-
ror to track down the offending conflicts and modify your configuration code accordingly.

If you’re getting a conflict while trying to extend an existing application, and that application has a function
which performs configuration like this one:

1 def add_routes(config):
2 config.add_route(...)

Don’t call this function directly with config as an argument. Instead, use pyramid.config.
Configurator.include():

690 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 config.include(add_routes)

Using include() instead of calling the function directly provides a modicum of automated conflict
resolution, with the configuration statements you define in the calling code overriding those of the included
function.

See also:

See also Automatic Conflict Resolution and Including Configuration from External Sources.

Using config.commit()

You can manually commit a configuration by using the commit() method between configuration calls.
After a commit, more configuration declarations may be added to a configurator. New declarations will
not conflict with committed declarations. The new declarations will override committed declarations.

For example, we prevent conflicts from occurring in the application we examined previously by adding a
commit. Here’s the application that generates conflicts:

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4

5 def hello_world(request):
6 return Response('Hello world!')
7

8 def goodbye_world(request):
9 return Response('Goodbye world!')
10

11 if __name__ == '__main__':
12 config = Configurator()
13

14 config.add_view(hello_world, name='hello')
15

16 # conflicting view configuration


17 config.add_view(goodbye_world, name='hello')
18

19 app = config.make_wsgi_app()
20 server = make_server('0.0.0.0', 8080, app)
21 server.serve_forever()

We can prevent the two add_view calls from conflicting by issuing a call to commit() between them:

0.3. Narrative Documentation 691


The Pyramid Web Framework, Version 2.0.2

1 from wsgiref.simple_server import make_server


2 from pyramid.config import Configurator
3 from pyramid.response import Response
4

5 def hello_world(request):
6 return Response('Hello world!')
7

8 def goodbye_world(request):
9 return Response('Goodbye world!')
10

11 if __name__ == '__main__':
12 config = Configurator()
13

14 config.add_view(hello_world, name='hello')
15

16 config.commit() # commit any pending configuration actions


17

18 # no-longer-conflicting view configuration


19 config.add_view(goodbye_world, name='hello')
20

21 app = config.make_wsgi_app()
22 server = make_server('0.0.0.0', 8080, app)
23 server.serve_forever()

In the above example we’ve issued a call to commit() between the two add_view calls. commit()
will execute any pending configuration statements.

Calling commit() is safe at any time. It executes all pending configuration actions and leaves the con-
figuration action list ”clean”.

Note that commit() has no effect when you’re using an autocommitting configurator (see Using an Au-
tocommitting Configurator).

Using an Autocommitting Configurator

You can also use a heavy hammer to circumvent conflict detection by using a configurator constructor
parameter: autocommit=True. For example:

1 from pyramid.config import Configurator


2

3 if __name__ == '__main__':
4 config = Configurator(autocommit=True)

692 CONTENTS
The Pyramid Web Framework, Version 2.0.2

When the autocommit parameter passed to the Configurator is True, conflict detection (and Two-
Phase Configuration) is disabled. Configuration statements will be executed immediately, and succeeding
statements will override preceding ones.

commit() has no effect when autocommit is True.

If you use a Configurator in code that performs unit testing, it’s usually a good idea to use an autocommitting
Configurator, because you are usually unconcerned about conflict detection or two-phase configuration in
test code.

Automatic Conflict Resolution

If your code uses the include() method to include external configuration, some conflicts are automat-
ically resolved. Configuration statements that are made as the result of an ”include” will be overridden by
configuration statements that happen within the caller of the ”include” method.

Automatic conflict resolution supports this goal. If a user wants to reuse a Pyramid application, and they
want to customize the configuration of this application without hacking its code ”from outside”, they can
”include” a configuration function from the package and override only some of its configuration statements
within the code that does the include. No conflicts will be generated by configuration statements within
the code that does the including, even if configuration statements in the included code would conflict if it
was moved ”up” to the calling code.

Methods Which Provide Conflict Detection

These are the methods of the configurator which provide conflict detection:

• add_renderer()

• add_request_method()

• add_resource_url_adapter()

• add_response_adapter()

• add_route()

• add_traverser()

0.3. Narrative Documentation 693


The Pyramid Web Framework, Version 2.0.2

• add_view()

• set_authentication_policy()

• set_authorization_policy()

• set_default_permission()

• set_locale_negotiator()

• set_request_factory()

• set_root_factory()

• set_security_policy()

• set_session_factory()

• set_view_mapper()

add_static_view() also indirectly provides conflict detection, because it’s implemented in terms of
the conflict-aware add_route and add_view methods.

Including Configuration from External Sources

Some application programmers will factor their configuration code in such a way that it is easy to reuse
and override configuration statements. For example, such a developer might factor out a function used to
add routes to their application:

1 def add_routes(config):
2 config.add_route(...)

Rather than calling this function directly with config as an argument, instead use pyramid.config.
Configurator.include():

1 config.include(add_routes)

Using include rather than calling the function directly will allow Automatic Conflict Resolution to work.

include() can also accept a module as an argument:

694 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 import myapp
2

3 config.include(myapp)

For this to work properly, the myapp module must contain a callable with the special name includeme,
which should perform configuration (like the add_routes callable we showed above as an example).
include() can also accept a dotted Python name to a function or a module.

See The <include> Tag for a declarative alternative to the include() method.

Two-Phase Configuration

When a non-autocommitting Configurator is used to do configuration (the default), configuration execution


happens in two phases. In the first phase, ”eager” configuration actions (actions that must happen before
all others, such as registering a renderer) are executed, and discriminators are computed for each of the
actions that depend on the result of the eager actions. In the second phase, the discriminators of all actions
are compared to do conflict detection.
Due to this, for configuration methods that have no internal ordering constraints, execution order of
configuration method calls is not important. For example, the relative ordering of add_view() and
add_renderer() is unimportant when a non-autocommitting configurator is used. This code snippet:

1 config.add_view('some.view', renderer='path_to_custom/renderer.rn')
2 config.add_renderer('.rn', SomeCustomRendererFactory)

Has the same result as:

1 config.add_renderer('.rn', SomeCustomRendererFactory)
2 config.add_view('some.view', renderer='path_to_custom/renderer.rn')

Even though the view statement depends on the registration of a custom renderer, due to two-phase con-
figuration, the order in which the configuration statements are issued is not important. add_view will
be able to find the .rn renderer even if add_renderer is called after add_view.
The same is untrue when you use an autocommitting configurator (see Using an Autocommitting Config-
urator). When an autocommitting configurator is used, two-phase configuration is disabled, and configu-
ration statements must be ordered in dependency order.
Some configuration methods, such as add_route() have internal ordering constraints: the routes they
imply require relative ordering. Such ordering constraints are not absolved by two-phase configuration.
Routes are still added in configuration execution order.

0.3. Narrative Documentation 695


The Pyramid Web Framework, Version 2.0.2

More Information

For more information, see the article A Whirlwind Tour of Advanced Configuration Tactics in the Pyramid
Community Cookbook.

0.3.35 Extending Pyramid Configuration

Pyramid allows you to extend its Configurator with custom directives. Custom directives can use other
directives, they can add a custom action, they can participate in conflict resolution, and they can provide
some number of introspectable objects.

Adding Methods to the Configurator via add_directive

Framework extension writers can add arbitrary methods to a Configurator by using the
pyramid.config.Configurator.add_directive() method of the configurator. Using
add_directive() makes it possible to extend a Pyramid configurator in arbitrary ways, and allows it
to perform application-specific tasks more succinctly.

The add_directive() method accepts two positional arguments: a method name and a callable object.
The callable object is usually a function that takes the configurator instance as its first argument and accepts
other arbitrary positional and keyword arguments. For example:

1 from pyramid.events import NewRequest


2 from pyramid.config import Configurator
3

4 def add_newrequest_subscriber(config, subscriber):


5 config.add_subscriber(subscriber, NewRequest)
6

7 if __name__ == '__main__':
8 config = Configurator()
9 config.add_directive('add_newrequest_subscriber',
10 add_newrequest_subscriber)

Once add_directive() is called, a user can then call the added directive by its given name as if it
were a built-in method of the Configurator:

1 def mysubscriber(event):
2 print(event.request)
3

4 config.add_newrequest_subscriber(mysubscriber)

696 CONTENTS
The Pyramid Web Framework, Version 2.0.2

A call to add_directive() is often ”hidden” within an includeme function within a ”frameworky”


package meant to be included as per Including Configuration from External Sources via include(). For
example, if you put this code in a package named pyramid_subscriberhelpers:

1 def includeme(config):
2 config.add_directive('add_newrequest_subscriber',
3 add_newrequest_subscriber)

The user of the add-on package pyramid_subscriberhelpers would then be able to install it and
subsequently do:

1 def mysubscriber(event):
2 print(event.request)
3

4 from pyramid.config import Configurator


5 config = Configurator()
6 config.include('pyramid_subscriberhelpers')
7 config.add_newrequest_subscriber(mysubscriber)

Using config.action in a Directive

If a custom directive can’t do its work exclusively in terms of existing configurator methods (such as
pyramid.config.Configurator.add_subscriber() as above), the directive may need to
make use of the pyramid.config.Configurator.action() method. This method adds an entry
to the list of ”actions” that Pyramid will attempt to process when pyramid.config.Configurator.
commit() is called. An action is simply a dictionary that includes a discriminator, possibly a callback
function, and possibly other metadata used by Pyramid’s action system.

Here’s an example directive which uses the ”action” method:

1 def add_jammyjam(config, jammyjam):


2 def register():
3 config.registry.jammyjam = jammyjam
4 config.action('jammyjam', register)
5

6 if __name__ == '__main__':
7 config = Configurator()
8 config.add_directive('add_jammyjam', add_jammyjam)

0.3. Narrative Documentation 697


The Pyramid Web Framework, Version 2.0.2

Fancy, but what does it do? The action method accepts a number of arguments. In the above directive
named add_jammyjam, we call action() with two arguments: the string jammyjam is passed as
the first argument named discriminator, and the closure function named register is passed as the
second argument named callable.

When the action() method is called, it appends an action to the list of pending configuration actions. All
pending actions with the same discriminator value are potentially in conflict with one another (see Conflict
Detection). When the commit() method of the Configurator is called (either explicitly or as the result
of calling make_wsgi_app()), conflicting actions are potentially automatically resolved as per Auto-
matic Conflict Resolution. If a conflict cannot be automatically resolved, a pyramid.exceptions.
ConfigurationConflictError is raised and application startup is prevented.

In our above example, therefore, if a consumer of our add_jammyjam directive did this:

config.add_jammyjam('first')
config.add_jammyjam('second')

When the action list was committed resulting from the set of calls above, our user’s application would not
start, because the discriminators of the actions generated by the two calls are in direct conflict. Automatic
conflict resolution cannot resolve the conflict (because no config.include is involved), and the user
provided no intermediate pyramid.config.Configurator.commit() call between the calls to
add_jammyjam to ensure that the successive calls did not conflict with each other.

This demonstrates the purpose of the discriminator argument to the action method: it’s used to indicate a
uniqueness constraint for an action. Two actions with the same discriminator will conflict unless the conflict
is automatically or manually resolved. A discriminator can be any hashable object, but it is generally a
string or a tuple. You use a discriminator to declaratively ensure that the user doesn’t provide ambiguous
configuration statements.

But let’s imagine that a consumer of add_jammyjam used it in such a way that no configuration conflicts
are generated.

config.add_jammyjam('first')

What happens now? When the add_jammyjam method is called, an action is appended to the pending
actions list. When the pending configuration actions are processed during commit(), and no conflicts
occur, the callable provided as the second argument to the action() method within add_jammyjam
is called with no arguments. The callable in add_jammyjam is the register closure function. It
simply sets the value config.registry.jammyjam to whatever the user passed in as the jammyjam
argument to the add_jammyjam function. Therefore, the result of the user’s call to our directive will set
the jammyjam attribute of the registry to the string first. A callable is used by a directive to defer the
result of a user’s call to the directive until conflict detection has had a chance to do its job.

698 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Other arguments exist to the action() method, including args, kw, order, and introspecta-
bles.

args and kw exist as values, which if passed will be used as arguments to the callable function when
it is called back. For example, our directive might use them like so:

1 def add_jammyjam(config, jammyjam):


2 def register(*arg, **kw):
3 config.registry.jammyjam_args = arg
4 config.registry.jammyjam_kw = kw
5 config.registry.jammyjam = jammyjam
6 config.action('jammyjam', register, args=('one',), kw={'two':'two'})

In the above example, when this directive is used to generate an action, and that action is commit-
ted, config.registry.jammyjam_args will be set to ('one',) and config.registry.
jammyjam_kw will be set to {'two':'two'}. args and kw are honestly not very useful when your
callable is a closure function, because you already usually have access to every local in the directive
without needing them to be passed back. They can be useful, however, if you don’t use a closure as a
callable.

order is a crude order control mechanism. order defaults to the integer 0; it can be set to any
other integer. All actions that share an order will be called before other actions that share a higher
order. This makes it possible to write a directive with callable logic that relies on the execution
of the callable of another directive being done first. For example, Pyramid’s pyramid.config.
Configurator.add_view() directive registers an action with a higher order than the pyramid.
config.Configurator.add_route() method. Due to this, the add_view method’s callable
can assume that, if a route_name was passed to it, that a route by this name was already registered by
add_route, and if such a route has not already been registered, it’s a configuration error (a view that
names a nonexistent route via its route_name parameter will never be called).

Changed in version 1.6: As of Pyramid 1.6 it is possible for one action to invoke another. See Ordering
Actions for more information.

Finally, introspectables is a sequence of introspectable objects. You can pass a sequence of intro-
spectables to the action() method, which allows you to augment Pyramid’s configuration introspection
system.

Ordering Actions

In Pyramid every action has an inherent ordering relative to other actions. The logic within actions
is deferred until a call to pyramid.config.Configurator.commit() (which is automatically

0.3. Narrative Documentation 699


The Pyramid Web Framework, Version 2.0.2

invoked by pyramid.config.Configurator.make_wsgi_app()). This means you may call


config.add_view(route_name='foo') before config.add_route('foo', '/foo')
because nothing actually happens until commit-time. During a commit cycle, conflicts are resolved, and
actions are ordered and executed.
By default, almost every action in Pyramid has an order of pyramid.config.PHASE3_CONFIG.
Every action within the same order-level will be executed in the order it was called. This means that
if an action must be reliably executed before or after another action, the order must be defined ex-
plicitly to make this work. For example, views are dependent on routes being defined. Thus the ac-
tion created by pyramid.config.Configurator.add_route() has an order of pyramid.
config.PHASE2_CONFIG.

Pre-defined Phases

pyramid.config.PHASE0_CONFIG
• This phase is reserved for developers who want to execute actions prior to Pyramid’s core directives.
pyramid.config.PHASE1_CONFIG
• pyramid.config.Configurator.add_accept_view_order()
• pyramid.config.Configurator.add_renderer()
• pyramid.config.Configurator.add_route_predicate()
• pyramid.config.Configurator.add_subscriber_predicate()
• pyramid.config.Configurator.add_view_deriver()
• pyramid.config.Configurator.add_view_predicate()
• pyramid.config.Configurator.override_asset()
• pyramid.config.Configurator.set_authorization_policy()
• pyramid.config.Configurator.set_default_csrf_options()
• pyramid.config.Configurator.set_default_permission()
• pyramid.config.Configurator.set_view_mapper()
pyramid.config.PHASE2_CONFIG
• pyramid.config.Configurator.add_route()
• pyramid.config.Configurator.set_authentication_policy()
• pyramid.config.Configurator.set_security_policy()
pyramid.config.PHASE3_CONFIG
• The default for all builtin or custom directives unless otherwise specified.

700 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Calling Actions from Actions

New in version 1.6.

Pyramid’s configurator allows actions to be added during a commit-cycle as long as they are added to the
current or a later order phase. This means that your custom action can defer decisions until commit-
time and then do things like invoke pyramid.config.Configurator.add_route(). It can also
provide better conflict detection if your addon needs to call more than one other action.

For example, let’s make an addon that invokes add_route and add_view, but we want it to conflict
with any other call to our addon:

1 from pyramid.config import PHASE0_CONFIG


2

3 def includeme(config):
4 config.add_directive('add_auto_route', add_auto_route)
5

6 def add_auto_route(config, name, view):


7 def register():
8 config.add_view(route_name=name, view=view)
9 config.add_route(name, '/' + name)
10 config.action(('auto route', name), register, order=PHASE0_CONFIG)

Now someone else can use your addon and be informed if there is a conflict between this route and an-
other, or two calls to add_auto_route. Notice how we had to invoke our action before add_view or
add_route. If we tried to invoke this afterward, the subsequent calls to add_view and add_route
would cause conflicts because that phase had already been executed, and the configurator cannot go back
in time to add more views during that commit-cycle.

1 from pyramid.config import Configurator


2

3 def main(global_config, **settings):


4 config = Configurator()
5 config.include('auto_route_addon')
6 config.add_auto_route('foo', my_view)
7

8 def my_view(request):
9 return request.response

0.3. Narrative Documentation 701


The Pyramid Web Framework, Version 2.0.2

Adding Configuration Introspection

New in version 1.3.

Pyramid provides a configuration introspection system that can be used by debugging tools to provide
visibility into the configuration of a running application.

All built-in Pyramid directives (such as pyramid.config.Configurator.add_view() and


pyramid.config.Configurator.add_route()) register a set of introspectables when called.
For example, when you register a view via add_view, the directive registers at least one introspectable:
an introspectable about the view registration itself, providing human-consumable values for the arguments
passed into it. You can later use the introspection query system to determine whether a particular view
uses a renderer, or whether a particular view is limited to a particular request method, or against which
routes a particular view is registered. The Pyramid ”debug toolbar” makes use of the introspection system
in various ways to display information to Pyramid developers.

Introspection values are set when a sequence of introspectable objects is passed to the action() method.
Here’s an example of a directive which uses introspectables:

1 def add_jammyjam(config, value):


2 def register():
3 config.registry.jammyjam = value
4 intr = config.introspectable(category_name='jammyjams',
5 discriminator='jammyjam',
6 title='a jammyjam',
7 type_name=None)
8 intr['value'] = value
9 config.action('jammyjam', register, introspectables=(intr,))
10

11 if __name__ == '__main__':
12 config = Configurator()
13 config.add_directive('add_jammyjam', add_jammyjam)

If you notice, the above directive uses the introspectable attribute of a Configurator (pyramid.
config.Configurator.introspectable) to create an introspectable object. The introspectable
object’s constructor requires at least four arguments: the category_name, the discriminator, the
title, and the type_name.

The category_name is a string representing the logical category for this introspectable. Usually the
category_name is a pluralization of the type of object being added via the action.

The discriminator is a value unique within the category (unlike the action discriminator, which must
be unique within the entire set of actions). It is typically a string or tuple representing the values unique

702 CONTENTS
The Pyramid Web Framework, Version 2.0.2

to this introspectable within the category. It is used to generate links and as part of a relationship-forming
target for other introspectables.

The title is a human-consumable string that can be used by introspection system frontends to show a
friendly summary of this introspectable.

The type_name is a value that can be used to subtype this introspectable within its category for sorting
and presentation purposes. It can be any value.

An introspectable is also dictionary-like. It can contain any set of key/value pairs, typically related to the
arguments passed to its related directive. While the category_name, discriminator, title, and
type_name are metadata about the introspectable, the values provided as key/value pairs are the actual
data provided by the introspectable. In the above example, we set the value key to the value of the value
argument passed to the directive.

Our directive above mutates the introspectable, and passes it in to the action method as the first element
of a tuple as the value of the introspectable keyword argument. This associates this introspectable
with the action. Introspection tools will then display this introspectable in their index.

Introspectable Relationships

Two introspectables may have relationships between each other.

1 def add_jammyjam(config, value, template):


2 def register():
3 config.registry.jammyjam = (value, template)
4 intr = config.introspectable(category_name='jammyjams',
5 discriminator='jammyjam',
6 title='a jammyjam',
7 type_name=None)
8 intr['value'] = value
9 tmpl_intr = config.introspectable(category_name='jammyjam templates',
10 discriminator=template,
11 title=template,
12 type_name=None)
13 tmpl_intr['value'] = template
14 intr.relate('jammyjam templates', template)
15 config.action('jammyjam', register, introspectables=(intr, tmpl_intr))
16

17 if __name__ == '__main__':
18 config = Configurator()
19 config.add_directive('add_jammyjam', add_jammyjam)

0.3. Narrative Documentation 703


The Pyramid Web Framework, Version 2.0.2

In the above example, the add_jammyjam directive registers two introspectables: the first is related to
the value passed to the directive, and the second is related to the template passed to the directive. If
you believe a concept within a directive is important enough to have its own introspectable, you can cause
the same directive to register more than one introspectable, registering one introspectable for the ”main
idea” and another for a related concept.

The call to intr.relate above (pyramid.interfaces.IIntrospectable.relate()) is


passed two arguments: a category name and a directive. The example above effectively indicates that
the directive wishes to form a relationship between the intr introspectable and the tmpl_intr intro-
spectable; the arguments passed to relate are the category name and discriminator of the tmpl_intr
introspectable.

Relationships need not be made between two introspectables created by the same directive. Instead a re-
lationship can be formed between an introspectable created in one directive and another introspectable
created in another by calling relate on either side with the other directive’s category name and discrim-
inator. An error will be raised at configuration commit time if you attempt to relate an introspectable with
another nonexistent introspectable, however.

Introspectable relationships will show up in frontend system renderings of introspection values. For ex-
ample, if a view registration names a route name, the introspectable related to the view callable will show
a reference to the route to which it relates and vice versa.

0.3.36 Pyramid cookiecutters

A cookiecutter is a command-line utility that creates projects from cookiecutters (project templates).

The Pylons Project supports one official Pyramid cookiecutter pyramid-cookiecutter-starter.

Cookiecutters that use Pyramid can be found using a search of the GitHub topic ”cookiecutter-template”
for ”Pyramid”.

You can extend Pyramid by creating a cookiecutter project template. This is useful if you would like to
distribute a customizable configuration of Pyramid to other users. Once you have created a cookiecutter,
other people can use it to create a custom version of your Pyramid application.

New in version 1.8: Added cookiecutter support.

Changed in version 1.10: Merged features from pyramid-cookiecutter-alchemy


and pyramid-cookiecutter-zodb into the single cookiecutter to rule them all,
pyramid-cookiecutter-starter.

Deprecated since version 1.10: pyramid-cookiecutter-alchemy


and pyramid-cookiecutter-zodb are no longer supported. Use
pyramid-cookiecutter-starter going forward.

704 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Basics

See Cookiecutter Installation to get started.

Then see the README of pyramid-cookiecutter-starter for its usage to generate a starter
project.

The pyramid-cookiecutter-starter on its main branch is a good starting point to develop your
own cookiecutter. Development of cookiecutters is documented under Learn the Basics of Cookiecutter
by Creating a Cookiecutter. See Cookiecutter Features for details of what is possible.

0.3.37 Upgrading Pyramid

When a new version of Pyramid is released, it will sometimes deprecate a feature or remove a feature that
was deprecated in an older release. When features are removed from Pyramid, applications that depend
on those features will begin to break. This chapter explains how to ensure your Pyramid applications keep
working when you upgrade the Pyramid version you’re using.

About Release Numbering

Conventionally, application version numbering in Python is described as major.minor.micro. If


your Pyramid version is ”1.2.3”, it means you’re running a version of Pyramid with the major version
”1”, the minor version ”2” and the micro version ”3”. A ”major” release is one that increments the
first-dot number; 2.X.X might follow 1.X.X. A ”minor” release is one that increments the second-dot
number; 1.3.X might follow 1.2.X. A ”micro” release is one that increments the third-dot number; 1.2.3
might follow 1.2.2. In general, micro releases are ”bugfix-only”, and contain no new features, minor
releases contain new features but are largely backwards compatible with older versions, and a major
release indicates a large set of backwards incompatibilities.

The Pyramid core team is conservative when it comes to removing features. We don’t remove features
unnecessarily, but we’re human and we make mistakes which cause some features to be evolutionary dead
ends. Though we are willing to support dead-end features for some amount of time, some eventually have
to be removed when the cost of supporting them outweighs the benefit of keeping them around, because
each feature in Pyramid represents a certain documentation and maintenance burden.

0.3. Narrative Documentation 705


The Pyramid Web Framework, Version 2.0.2

Deprecation and removal policy

When a feature is scheduled for removal from Pyramid or any of its official add-ons, the core development
team takes these steps:

• Using the feature will begin to generate a DeprecationWarning, indicating the version in which the
feature became deprecated.

• A note is added to the documentation indicating that the feature is deprecated.

• A note is added to the Pyramid Change History about the deprecation.

When a deprecated feature is eventually removed:

• The feature is removed.

• A note is added to the Pyramid Change History about the removal.

Features are never removed in micro releases. They are only removed in minor and major releases. Depre-
cated features are kept around for at least three minor releases from the time the feature became deprecated.
Therefore, if a feature is added in Pyramid 1.0, but it’s deprecated in Pyramid 1.1, it will be kept around
through all 1.1.X releases, all 1.2.X releases and all 1.3.X releases. It will finally be removed in the first
1.4.X release.

Sometimes features are ”docs-deprecated” instead of formally deprecated. This means that the feature will
be kept around indefinitely, but it will be removed from the documentation or a note will be added to the
documentation telling folks to use some other newer feature. This happens when the cost of keeping an old
feature around is very minimal and the support and documentation burden is very low. For example, we
might rename a function that is an API without changing the arguments it accepts. In this case, we’ll often
rename the function, and change the docs to point at the new function name, but leave around a backwards
compatibility alias to the old function name so older code doesn’t break.

”Docs deprecated” features tend to work ”forever”, meaning that they won’t be removed, and they’ll never
generate a deprecation warning. However, such changes are noted in the Pyramid Change History, so it’s
possible to know that you should change older spellings to newer ones to ensure that people reading your
code can find the APIs you’re using in the Pyramid docs.

706 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Python support policy

At the time of a Pyramid version release, each supports all versions of Python through the end of their
lifespans. The end-of-life for a given version of Python is when security updates are no longer released.

• Python 3.6 Lifespan 2021-12-23.

• Python 3.7 Lifespan 2023-06-27.

• Python 3.8 Lifespan 2024-10.

• Python 3.9 Lifespan 2025-10.

• Python 3.10 Lifespan 2026-10.

• Python 3.11 Lifespan 2027-10.

To determine the Python support for a specific release of Pyramid, view its tox.ini file at the root of
the repository’s version.

Consulting the change history

Your first line of defense against application failures caused by upgrading to a newer Pyramid release is
always to read the Pyramid Change History to find the deprecations and removals for each release between
the release you’re currently running and the one to which you wish to upgrade. The change history notes
every deprecation within a Deprecation section and every removal within a Backwards Incom-
patibilities section for each release.

The change history often contains instructions for changing your code to avoid deprecation warnings and
how to change docs-deprecated spellings to newer ones. You can follow along with each deprecation
explanation in the change history, simply doing a grep or other code search to your application, using the
change log examples to remediate each potential problem.

Testing your application under a new Pyramid release

Once you’ve upgraded your application to a new Pyramid release and you’ve remediated as much as pos-
sible by using the change history notes, you’ll want to run your application’s tests (see Run the tests) in
such a way that you can see DeprecationWarnings printed to the console when the tests run.

0.3. Narrative Documentation 707


The Pyramid Web Framework, Version 2.0.2

python -Wd setup.py test -q

The -Wd argument tells Python to print deprecation warnings to the console. See the Python -W flag
documentation for more information.

As your tests run, deprecation warnings will be printed to the console explaining the deprecation and
providing instructions about how to prevent the deprecation warning from being issued. For example:

python -Wd setup.py test -q


# .. elided ...
running build_ext
/home/chrism/projects/pyramid/env27/myproj/myproj/views.py:3:
DeprecationWarning: static: The "pyramid.view.static" class is deprecated
as of Pyramid 1.1; use the "pyramid.static.static_view" class instead with
the "use_subpath" argument set to True.
from pyramid.view import static
.
----------------------------------------------------------------------
Ran 1 test in 0.014s

OK

In the above case, it’s line #3 in the myproj.views module (from pyramid.view import
static) that is causing the problem:

1 from pyramid.view import view_config


2

3 from pyramid.view import static


4 myview = static('static', 'static')

The deprecation warning tells me how to fix it, so I can change the code to do things the newer way:

1 from pyramid.view import view_config


2

3 from pyramid.static import static_view


4 myview = static_view('static', 'static', use_subpath=True)

When I run the tests again, the deprecation warning is no longer printed to my console:

708 CONTENTS
The Pyramid Web Framework, Version 2.0.2

python -Wd setup.py test -q


# .. elided ...
running build_ext
.
----------------------------------------------------------------------
Ran 1 test in 0.014s

OK

My application doesn’t have any tests or has few tests

If your application has no tests, or has only moderate test coverage, running tests won’t tell you very much,
because the Pyramid codepaths that generate deprecation warnings won’t be executed.

In this circumstance, you can start your application interactively under a server run with the PYTHON-
WARNINGS environment variable set to default. On Unix, you can do that via:

PYTHONWARNINGS=default $VENV/bin/pserve development.ini

On Windows, you need to issue two commands:

set PYTHONWARNINGS=default
Scripts\pserve development.ini

At this point, it’s ensured that deprecation warnings will be printed to the console whenever a codepath is
hit that generates one. You can then click around in your application interactively to try to generate them,
and remediate as explained in Testing your application under a new Pyramid release.

See the PYTHONWARNINGS environment variable documentation or the Python -W flag documentation
for more information.

Upgrading to the very latest Pyramid release

When you upgrade your application to the most recent Pyramid release, it’s advisable to upgrade step-wise
through each most recent minor release, beginning with the one that you know your application currently
runs under, and ending on the most recent release. For example, if your application is running in production
on Pyramid 1.2.1, and the most recent Pyramid 1.3 release is Pyramid 1.3.3, and the most recent Pyramid
release is 1.4.4, it’s advisable to do this:

0.3. Narrative Documentation 709


The Pyramid Web Framework, Version 2.0.2

• Upgrade your environment to the most recent 1.2 release. For example, the most recent 1.2 release
might be 1.2.3, so upgrade to it. Then run your application’s tests under 1.2.3 as described in Testing
your application under a new Pyramid release. Note any deprecation warnings and remediate.

• Upgrade to the most recent 1.3 release, 1.3.3. Run your application’s tests, note any deprecation
warnings, and remediate.

• Upgrade to 1.4.4. Run your application’s tests, note any deprecation warnings, and remediate.

If you skip testing your application under each minor release (for example if you upgrade directly from
1.2.1 to 1.4.4), you might miss a deprecation warning and waste more time trying to figure out an error
caused by a feature removal than it would take to upgrade stepwise through each minor release.

0.3.38 Thread Locals

A thread local variable is a variable that appears to be a ”global” variable to an application which uses
it. However, unlike a true global variable, one thread or process serving the application may receive a
different value than another thread or process when that variable is ”thread local”.

When a request is processed, Pyramid makes two thread local variables available to the application: a
”registry” and a ”request”.

Why and How Pyramid Uses Thread Local Variables

How are thread locals beneficial to Pyramid and application developers who use Pyramid? Well, usually
they’re decidedly not. Using a global or a thread local variable in any application usually makes it a lot
harder to understand for a casual reader. Use of a thread local or a global is usually just a way to avoid
passing some value around between functions, which is itself usually a very bad idea, at least if code
readability counts as an important concern.

For historical reasons, however, thread local variables are indeed consulted by various Pyramid
API functions. For example, the implementation of the pyramid.security function named
authenticated_userid() (deprecated as of 1.5) retrieves the thread local application reg-
istry as a matter of course to find an security policy. It uses the pyramid.threadlocal.
get_current_registry() function to retrieve the application registry, from which it looks up the
security policy; it then uses the security policy to retrieve the authenticated user id. This is how Pyramid
allows arbitrary security policies to be ”plugged in”.

When they need to do so, Pyramid internals use two API functions to retrieve the request and application
registry: get_current_request() and get_current_registry(). The former returns the

710 CONTENTS
The Pyramid Web Framework, Version 2.0.2

”current” request; the latter returns the ”current” registry. Both get_current_* functions retrieve an
object from a thread-local data structure. These API functions are documented in pyramid.threadlocal.

These values are thread locals rather than true globals because one Python process may be handling multi-
ple simultaneous requests or even multiple Pyramid applications. If they were true globals, Pyramid could
not handle multiple simultaneous requests or allow more than one Pyramid application instance to exist in
a single Python process.

Because one Pyramid application is permitted to call another Pyramid application from its own view code
(perhaps as a WSGI app with help from the pyramid.wsgi.wsgiapp2() decorator), these variables
are managed in a stack during normal system operations. The stack instance itself is a threading.
local.

During normal operations, the thread locals stack is managed by a Router object. At the beginning of a
request, the Router pushes the application’s registry and the request on to the stack. At the end of a request,
the stack is popped. The topmost request and registry on the stack are considered ”current”. Therefore,
when the system is operating normally, the very definition of ”current” is defined entirely by the behavior
of a pyramid Router.

However, during unit testing, no Router code is ever invoked, and the definition of ”current” is defined by
the boundary between calls to the pyramid.config.Configurator.begin() and pyramid.
config.Configurator.end() methods (or between calls to the pyramid.testing.setUp()
and pyramid.testing.tearDown() functions). These functions push and pop the threadlocal stack
when the system is under test. See Test Set Up and Tear Down for the definitions of these functions.

Scripts which use Pyramid machinery but never actually start a WSGI server or receive requests via HTTP,
such as scripts which use the pyramid.scripting API, will never cause any Router code to be exe-
cuted. However, the pyramid.scripting APIs also push some values on to the thread locals stack
as a matter of course. Such scripts should expect the get_current_request() function to always
return None, and should expect the get_current_registry() function to return exactly the same
application registry for every request.

Why You Shouldn’t Abuse Thread Locals

You probably should almost never use the get_current_request() or


get_current_registry() functions, except perhaps in tests. In particular, it’s almost al-
ways a mistake to use get_current_request or get_current_registry in application
code because its usage makes it possible to write code that can be neither easily tested nor scripted.
Inappropriate usage is defined as follows:

• get_current_request should never be called within the body of a view callable, or within
code called by a view callable. View callables already have access to the request (it’s passed in to
each as request).

0.3. Narrative Documentation 711


The Pyramid Web Framework, Version 2.0.2

• get_current_request should never be called in resource code. If a resource needs access to


the request, it should be passed the request by a view callable.

• get_current_request function should never be called because it’s ”easier” or ”more elegant”
to think about calling it than to pass a request through a series of function calls when creating some
API design. Your application should instead, almost certainly, pass around data derived from the
request rather than relying on being able to call this function to obtain the request in places that
actually have no business knowing about it. Parameters are meant to be passed around as function
arguments; this is why they exist. Don’t try to ”save typing” or create ”nicer APIs” by using this
function in the place where a request is required; this will only lead to sadness later.

• Neither get_current_request nor get_current_registry should ever be called within


application-specific forks of third-party library code. The library you’ve forked almost certainly has
nothing to do with Pyramid, and making it dependent on Pyramid (rather than making your pyramid
application depend upon it) means you’re forming a dependency in the wrong direction.

Use of the get_current_request() function in application code is still useful in very limited cir-
cumstances. As a rule of thumb, usage of get_current_request is useful within code which is
meant to eventually be removed. For instance, you may find yourself wanting to deprecate some API that
expects to be passed a request object in favor of one that does not expect to be passed a request object. But
you need to keep implementations of the old API working for some period of time while you deprecate the
older API. So you write a ”facade” implementation of the new API which calls into the code which imple-
ments the older API. Since the new API does not require the request, your facade implementation doesn’t
have local access to the request when it needs to pass it into the older API implementation. After some pe-
riod of time, the older implementation code is disused and the hack that uses get_current_request
is removed. This would be an appropriate place to use the get_current_request.

Use of the get_current_registry() function should be limited to testing scenarios. The registry
made current by use of the pyramid.config.Configurator.begin() method during a test (or
via pyramid.testing.setUp()) when you do not pass one in is available to you via this API.

0.3.39 Using the Zope Component Architecture in Pyramid

Under the hood, Pyramid uses a Zope Component Architecture component registry as its application reg-
istry. The Zope Component Architecture is referred to colloquially as the ”ZCA.”

The zope.component API used to access data in a traditional Zope application can be opaque. For
example, here is a typical ”unnamed utility” lookup using the zope.component.getUtility()
global API as it might appear in a traditional Zope application:

712 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.interfaces import ISettings


2 from zope.component import getUtility
3 settings = getUtility(ISettings)

After this code runs, settings will be a Python dictionary. But it’s unlikely that any ”civilian” will be
able to figure this out just by reading the code casually. When the zope.component.getUtility
API is used by a developer, the conceptual load on a casual reader of code is high.

While the ZCA is an excellent tool with which to build a framework such as Pyramid, it is not always
the best tool with which to build an application due to the opacity of the zope.component APIs.
Accordingly, Pyramid tends to hide the presence of the ZCA from application developers. You needn’t
understand the ZCA to create a Pyramid application; its use is effectively only a framework implementation
detail.

However, developers who are already used to writing Zope applications often still wish to use the ZCA
while building a Pyramid application. Pyramid makes this possible.

Using the ZCA global API in a Pyramid application

Zope uses a single ZCA registry—the ”global” ZCA registry—for all Zope applications that run in the
same Python process, effectively making it impossible to run more than one Zope application in a single
process.

However, for ease of deployment, it’s often useful to be able to run more than a single application per
process. For example, use of a PasteDeploy ”composite” allows you to run separate individual WSGI
applications in the same process, each answering requests for some URL prefix. This makes it possible to
run, for example, a TurboGears application at /turbogears and a Pyramid application at /pyramid,
both served up using the same WSGI server within a single Python process.

Most production Zope applications are relatively large, making it impractical due to memory constraints
to run more than one Zope application per Python process. However, a Pyramid application may be very
small and consume very little memory, so it’s a reasonable goal to be able to run more than one Pyramid
application per process.

In order to make it possible to run more than one Pyramid application in a single process, Pyramid defaults
to using a separate ZCA registry per application.

While this services a reasonable goal, it causes some issues when trying to use patterns which you might
use to build a typical Zope application to build a Pyramid application. Without special help, ZCA ”global”
APIs such as zope.component.getUtility() and zope.component.getSiteManager()

0.3. Narrative Documentation 713


The Pyramid Web Framework, Version 2.0.2

will use the ZCA ”global” registry. Therefore, these APIs will appear to fail when used in a Pyramid appli-
cation, because they’ll be consulting the ZCA global registry rather than the component registry associated
with your Pyramid application.

There are three ways to fix this: by disusing the ZCA global API entirely, by using pyramid.config.
Configurator.hook_zca() or by passing the ZCA global registry to the Configurator constructor
at startup time. We’ll describe all three methods in this section.

Disusing the global ZCA API

ZCA ”global” API functions such as zope.component.getSiteManager, zope.


component.getUtility, zope.component.getAdapter(), and zope.component.
getMultiAdapter() aren’t strictly necessary. Every component registry has a method API that
offers the same functionality; it can be used instead. For example, presuming the registry value
below is a Zope Component Architecture component registry, the following bit of code is equivalent to
zope.component.getUtility(IFoo):

registry.getUtility(IFoo)

The full method API is documented in the zope.component package, but it largely mirrors the ”global”
API almost exactly.

If you are willing to disuse the ”global” ZCA APIs and use the method interface of a registry instead, you
need only know how to obtain the Pyramid component registry.

There are two ways of doing so:

• use the pyramid.threadlocal.get_current_registry() function within Pyramid


view or resource code. This will always return the ”current” Pyramid application registry.

• use the attribute of the request object named registry in your Pyramid view code, e.g.,
request.registry. This is the ZCA component registry related to the running Pyramid appli-
cation.

See Thread Locals for more information about pyramid.threadlocal.


get_current_registry().

Enabling the ZCA global API by using hook_zca

Consider the following bit of idiomatic Pyramid startup code:

714 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.config import Configurator


2

3 def app(global_settings, **settings):


4 config = Configurator(settings=settings)
5 config.include('some.other.package')
6 return config.make_wsgi_app()

When the app function above is run, a Configurator is constructed. When the configurator is created, it
creates a new application registry (a ZCA component registry). A new registry is constructed whenever
the registry argument is omitted, when a Configurator constructor is called, or when a registry
argument with a value of None is passed to a Configurator constructor.

During a request, the application registry created by the Configurator is ”made current”. This means calls
to get_current_registry() in the thread handling the request will return the component registry
associated with the application.

As a result, application developers can use get_current_registry to get the registry and thus get
access to utilities and such, as per Disusing the global ZCA API. But they still cannot use the global ZCA
API. Without special treatment, the ZCA global APIs will always return the global ZCA registry (the one
in zope.component.globalregistry.base).

To ”fix” this and make the ZCA global APIs use the ”current” Pyramid registry, you need to call
hook_zca() within your setup code. For example:

1 from pyramid.config import Configurator


2

3 def app(global_settings, **settings):


4 config = Configurator(settings=settings)
5 config.hook_zca()
6 config.include('some.other.application')
7 return config.make_wsgi_app()

We’ve added a line to our original startup code, line number 5, which calls config.hook_zca(). The
effect of this line under the hood is that an analogue of the following code is executed:

1 from zope.component import getSiteManager


2 from pyramid.threadlocal import get_current_registry
3 getSiteManager.sethook(get_current_registry)

This causes the ZCA global API to start using the Pyramid application registry in threads which are running
a Pyramid request.

0.3. Narrative Documentation 715


The Pyramid Web Framework, Version 2.0.2

Calling hook_zca is usually sufficient to ”fix” the problem of being able to use the global ZCA API
within a Pyramid application. However, it also means that a Zope application that is running in the same
process may start using the Pyramid global registry instead of the Zope global registry, effectively inverting
the original problem. In such a case, follow the steps in the next section, Enabling the ZCA global API by
using the ZCA global registry.

Enabling the ZCA global API by using the ZCA global registry

You can tell your Pyramid application to use the ZCA global registry at startup time instead of constructing
a new one:

1 from zope.component import getGlobalSiteManager


2 from pyramid.config import Configurator
3

4 def app(global_settings, **settings):


5 globalreg = getGlobalSiteManager()
6 config = Configurator(registry=globalreg)
7 config.setup_registry(settings=settings)
8 config.include('some.other.application')
9 return config.make_wsgi_app()

Lines 5, 6, and 7 above are the interesting ones. Line 5 retrieves the global ZCA component registry.
Line 6 creates a Configurator, passing the global ZCA registry into its constructor as the registry
argument. Line 7 ”sets up” the global registry with Pyramid-specific registrations; this is code that is
normally executed when a registry is constructed rather than created, but we must call it ”by hand” when
we pass an explicit registry.

At this point, Pyramid will use the ZCA global registry rather than creating a new application-specific
registry. Since by default the ZCA global API will use this registry, things will work as you might expect
in a Zope app when you use the global ZCA API.

0.4 API Documentation

0.4.1 API Documentation

Comprehensive reference material for every public API exposed by Pyramid:

716 CONTENTS
The Pyramid Web Framework, Version 2.0.2

pyramid.authentication

Helper Classes

class SessionAuthenticationHelper(prefix=’auth.’)
A helper for use with a security policy which stores user data in the configured session.

Constructor Arguments

prefix

A prefix used when storing the authentication parameters in the session. Defaults to
’auth.’. Optional.

authenticated_userid(request)
Return the stored userid.

forget(request, **kw)
Remove the stored userid from the session.

remember(request, userid, **kw)


Store a userid in the session.

class AuthTktCookieHelper(secret, cookie_name=’auth_tkt’, secure=False,


include_ip=False, timeout=None, reissue_time=None,
max_age=None, http_only=False, path=’/’, wild_domain=True,
hashalg=’sha512’, parent_domain=False, domain=None,
samesite=’Lax’)
A helper class for security policies that obtains data from an ”auth ticket” cookie.

Constructor Arguments

secret

The secret (a string) used for auth_tkt cookie signing. This value should be unique across
all values provided to Pyramid for various subsystem secrets (see Admonishment Against
Secret-Sharing). Required.

cookie_name

Default: auth_tkt. The cookie name used (string). Optional.

0.4. API Documentation 717


The Pyramid Web Framework, Version 2.0.2

secure

Default: False. Only send the cookie back over a secure conn. Optional.

include_ip

Default: False. Make the requesting IP address part of the authentication data in the
cookie. Optional.

For IPv6 this option is not recommended. The mod_auth_tkt specification does not
specify how to handle IPv6 addresses, so using this option in combination with IPv6
addresses may cause an incompatible cookie. It ties the authentication ticket to that in-
dividual’s IPv6 address.

timeout

Default: None. Maximum number of seconds which a newly issued ticket will be con-
sidered valid. After this amount of time, the ticket will expire (effectively logging the
user out). If this value is None, the ticket never expires. Optional.

reissue_time

Default: None. If this parameter is set, it represents the number of seconds that must pass
before an authentication token cookie is automatically reissued as the result of a request
which requires authentication. The duration is measured as the number of seconds since
the last auth_tkt cookie was issued and ’now’. If this value is 0, a new ticket cookie will
be reissued on every request which requires authentication.

A good rule of thumb: if you want auto-expired cookies based on inactivity: set the
timeout value to 1200 (20 mins) and set the reissue_time value to perhaps a tenth
of the timeout value (120 or 2 mins). It’s nonsensical to set the timeout value lower
than the reissue_time value, as the ticket will never be reissued if so. However, such
a configuration is not explicitly prevented.

Optional.

max_age

Default: None. The max age of the auth_tkt cookie, in seconds. This differs from
timeout inasmuch as timeout represents the lifetime of the ticket contained in the
cookie, while this value represents the lifetime of the cookie itself. When this value
is set, the cookie’s Max-Age and Expires settings will be set, allowing the auth_tkt
cookie to last between browser sessions. It is typically nonsensical to set this to a value
that is lower than timeout or reissue_time, although it is not explicitly prevented.
Optional.

718 CONTENTS
The Pyramid Web Framework, Version 2.0.2

path

Default: /. The path for which the auth_tkt cookie is valid. May be desirable if the
application only serves part of a domain. Optional.

http_only

Default: False. Hide cookie from JavaScript by setting the HttpOnly flag. Not honored
by all browsers. Optional.

wild_domain

Default: True. An auth_tkt cookie will be generated for the wildcard domain. If your
site is hosted as example.com this will make the cookie available for sites underneath
example.com such as www.example.com. Optional.

parent_domain

Default: False. An auth_tkt cookie will be generated for the parent domain of the
current site. For example if your site is hosted under www.example.com a cookie will
be generated for .example.com. This can be useful if you have multiple sites sharing
the same domain. This option supercedes the wild_domain option. Optional.

domain

Default: None. If provided the auth_tkt cookie will only be set for this domain. This
option is not compatible with wild_domain and parent_domain. Optional.

hashalg

Default: sha512 (the literal string).

Any hash algorithm supported by Python’s hashlib.new() function can be used as


the hashalg.

Cookies generated by different instances of AuthTktAuthenticationPolicy using differ-


ent hashalg options are not compatible. Switching the hashalg will imply that all
existing users with a valid cookie will be required to re-login.

Optional.

debug

0.4. API Documentation 719


The Pyramid Web Framework, Version 2.0.2

Default: False. If debug is True, log messages to the Pyramid debug logger about the
results of various authentication steps. The output from debugging is useful for reporting
to maillist or IRC channels when asking for support. Optional.

samesite

Default: 'Lax'. The ’samesite’ option of the session cookie. Set the value to None to
turn off the samesite option. Optional.

Changed in version 2.0: The default hashalg was changed from md5 to sha512.

class AuthTicket(secret, userid, ip, tokens=(), user_data=”, time=None,


cookie_name=’auth_tkt’, secure=False, hashalg=’md5’)
This class represents an authentication token. You must pass in the shared secret, the userid,
and the IP address. Optionally you can include tokens (a list of strings, representing role
names), ’user_data’, which is arbitrary data available for your own use in later scripts. Lastly,
you can override the cookie name and timestamp.

Once you provide all the arguments, use .cookie_value() to generate the appropriate authenti-
cation ticket.

Usage:

token = AuthTicket('sharedsecret', 'username',


os.environ['REMOTE_ADDR'], tokens=['admin'])
val = token.cookie_value()

exception BadTicket(msg, expected=None)


Exception raised when a ticket can’t be parsed. If we get far enough to determine what the
expected digest should have been, expected is set. This should not be shown by default, but
can be useful for debugging.

forget(request)
Return a set of expires Set-Cookie headers, which will destroy any existing auth_tkt cookie
when attached to a response

identify(request)
Return a dictionary with authentication information, or None if no valid auth_tkt is attached
to request

720 CONTENTS
The Pyramid Web Framework, Version 2.0.2

static parse_ticket(secret, ticket, ip, hashalg=’md5’)


Parse the ticket, returning (timestamp, userid, tokens, user_data).

If the ticket cannot be parsed, a BadTicket exception will be raised with an explanation.

remember(request, userid, max_age=None, tokens=())


Return a set of Set-Cookie headers; when set into a response, these headers will represent a
valid authentication ticket.

max_age
The max age of the auth_tkt cookie, in seconds. When this value is set, the cookie’s
Max-Age and Expires settings will be set, allowing the auth_tkt cookie to last between
browser sessions. If this value is None, the max_age value provided to the helper itself
will be used as the max_age value. Default: None.

tokens
A sequence of strings that will be placed into the auth_tkt tokens field. Each
string in the sequence must be of the Python str type and must match the regex
^[A-Za-z][A-Za-z0-9+_-]*$. Tokens are available in the returned identity when
an auth_tkt is found in the request and unpacked. Default: ().

Helper Functions

extract_http_basic_credentials(request)
A helper function for extraction of HTTP Basic credentials from a given request.

Returns a HTTPBasicCredentials 2-tuple with username and password at-


tributes or None if no credentials could be found.

class HTTPBasicCredentials(username, password)

password
Alias for field number 1

username
Alias for field number 0

0.4. API Documentation 721


The Pyramid Web Framework, Version 2.0.2

Authentication Policies

Authentication policies have been deprecated by the new security system. See upgrading_auth_20 for more
information.

class AuthTktAuthenticationPolicy(secret, callback=None,


cookie_name=’auth_tkt’, secure=False,
include_ip=False, timeout=None,
reissue_time=None, max_age=None,
path=’/’, http_only=False,
wild_domain=True, debug=False,
hashalg=’sha512’,
parent_domain=False, domain=None,
samesite=’Lax’)
A Pyramid authentication policy which obtains data from a Pyramid ”auth ticket”
cookie.

Constructor Arguments

secret

The secret (a string) used for auth_tkt cookie signing. This value should be
unique across all values provided to Pyramid for various subsystem secrets
(see Admonishment Against Secret-Sharing). Required.

callback

Default: None. A callback passed the userid and the request, expected to
return None if the userid doesn’t exist or a sequence of principal identifiers
(possibly empty) if the user does exist. If callback is None, the userid will
be assumed to exist with no principals. Optional.

cookie_name

Default: auth_tkt. The cookie name used (string). Optional.

secure

Default: False. Only send the cookie back over a secure conn. Optional.

include_ip

722 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Default: False. Make the requesting IP address part of the authentication


data in the cookie. Optional.

For IPv6 this option is not recommended. The mod_auth_tkt specification


does not specify how to handle IPv6 addresses, so using this option in com-
bination with IPv6 addresses may cause an incompatible cookie. It ties the
authentication ticket to that individual’s IPv6 address.

timeout

Default: None. Maximum number of seconds which a newly issued ticket will
be considered valid. After this amount of time, the ticket will expire (effectively
logging the user out). If this value is None, the ticket never expires. Optional.

reissue_time

Default: None. If this parameter is set, it represents the number of seconds that
must pass before an authentication token cookie is automatically reissued as the
result of a request which requires authentication. The duration is measured as
the number of seconds since the last auth_tkt cookie was issued and ’now’. If
this value is 0, a new ticket cookie will be reissued on every request which
requires authentication.

A good rule of thumb: if you want auto-expired cookies based on inactivity:


set the timeout value to 1200 (20 mins) and set the reissue_time value
to perhaps a tenth of the timeout value (120 or 2 mins). It’s nonsensical to
set the timeout value lower than the reissue_time value, as the ticket
will never be reissued if so. However, such a configuration is not explicitly
prevented.

Optional.

max_age

Default: None. The max age of the auth_tkt cookie, in seconds. This differs
from timeout inasmuch as timeout represents the lifetime of the ticket
contained in the cookie, while this value represents the lifetime of the cookie
itself. When this value is set, the cookie’s Max-Age and Expires settings
will be set, allowing the auth_tkt cookie to last between browser sessions. It
is typically nonsensical to set this to a value that is lower than timeout or
reissue_time, although it is not explicitly prevented. Optional.

path

0.4. API Documentation 723


The Pyramid Web Framework, Version 2.0.2

Default: /. The path for which the auth_tkt cookie is valid. May be desirable
if the application only serves part of a domain. Optional.

http_only

Default: False. Hide cookie from JavaScript by setting the HttpOnly flag.
Not honored by all browsers. Optional.

wild_domain

Default: True. An auth_tkt cookie will be generated for the wildcard domain.
If your site is hosted as example.com this will make the cookie available for
sites underneath example.com such as www.example.com. Optional.

parent_domain

Default: False. An auth_tkt cookie will be generated for the parent domain
of the current site. For example if your site is hosted under www.example.
com a cookie will be generated for .example.com. This can be useful if
you have multiple sites sharing the same domain. This option supercedes the
wild_domain option. Optional.

domain

Default: None. If provided the auth_tkt cookie will only be set for this domain.
This option is not compatible with wild_domain and parent_domain.
Optional.

hashalg

Default: sha512 (the literal string).

Any hash algorithm supported by Python’s hashlib.new() function can


be used as the hashalg.

Cookies generated by different instances of AuthTktAuthenticationPolicy us-


ing different hashalg options are not compatible. Switching the hashalg
will imply that all existing users with a valid cookie will be required to re-login.

Optional.

debug

724 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Default: False. If debug is True, log messages to the Pyramid debug


logger about the results of various authentication steps. The output from de-
bugging is useful for reporting to maillist or IRC channels when asking for
support.

samesite

Default: 'Lax'. The ’samesite’ option of the session cookie. Set the value to
the string 'None' to turn off the samesite option.

Changed in version 1.4: Added the hashalg option, defaulting to sha512.

Changed in version 1.5: Added the domain option.

Added the parent_domain option.

Changed in version 1.10: Added the samesite option and made the default 'Lax'.

Objects of this class implement the interface described by pyramid.interfaces.


IAuthenticationPolicy.

authenticated_userid(request)
Return the authenticated userid or None.

If no callback is registered, this will be the same as unauthenti-


cated_userid.

If a callback is registered, this will return the userid if and only if the callback
returns a value that is not None.

effective_principals(request)
A list of effective principals derived from request.

This will return a list of principals including, at least, pyramid.


authorization.Everyone. If there is no authenticated userid, or the
callback returns None, this will be the only principal:

return [Everyone]

If the callback does not return None and an authenticated userid is found, then
the principals will include pyramid.authorization.Authenticated,
the authenticated_userid and the list of principals returned by the call-
back:

0.4. API Documentation 725


The Pyramid Web Framework, Version 2.0.2

extra_principals = callback(userid, request)


return [Everyone, Authenticated, userid] + extra_principals

forget(request)
A list of headers which will delete appropriate cookies.

remember(request, userid, **kw)


Accepts the following kw args: max_age=<int-seconds>, ``to-
kens=<sequence-of-ascii-strings>.

Return a list of headers which will set appropriate cookies on the response.

unauthenticated_userid(request)
The userid key within the auth_tkt cookie.

class RemoteUserAuthenticationPolicy(environ_key=’REMOTE_USER’,
callback=None, debug=False)
A Pyramid authentication policy which obtains data from the REMOTE_USER WSGI
environment variable.

Constructor Arguments

environ_key

Default: REMOTE_USER. The key in the WSGI environ which provides the
userid.

callback

Default: None. A callback passed the userid and the request, expected to
return None if the userid doesn’t exist or a sequence of principal identifiers
(possibly empty) representing groups if the user does exist. If callback is
None, the userid will be assumed to exist with no group principals.

debug

Default: False. If debug is True, log messages to the Pyramid debug


logger about the results of various authentication steps. The output from de-
bugging is useful for reporting to maillist or IRC channels when asking for
support.

Objects of this class implement the interface described by pyramid.interfaces.


IAuthenticationPolicy.

726 CONTENTS
The Pyramid Web Framework, Version 2.0.2

authenticated_userid(request)
Return the authenticated userid or None.

If no callback is registered, this will be the same as unauthenti-


cated_userid.

If a callback is registered, this will return the userid if and only if the callback
returns a value that is not None.

effective_principals(request)
A list of effective principals derived from request.

This will return a list of principals including, at least, pyramid.


authorization.Everyone. If there is no authenticated userid, or the
callback returns None, this will be the only principal:

return [Everyone]

If the callback does not return None and an authenticated userid is found, then
the principals will include pyramid.authorization.Authenticated,
the authenticated_userid and the list of principals returned by the call-
back:

extra_principals = callback(userid, request)


return [Everyone, Authenticated, userid] + extra_principals

forget(request)
A no-op. The REMOTE_USER does not provide a protocol for forgetting the user.
This will be application-specific and can be done somewhere else or in a subclass.

remember(request, userid, **kw)


A no-op. The REMOTE_USER does not provide a protocol for remembering the
user. This will be application-specific and can be done somewhere else or in a
subclass.

unauthenticated_userid(request)
The REMOTE_USER value found within the environ.

0.4. API Documentation 727


The Pyramid Web Framework, Version 2.0.2

class SessionAuthenticationPolicy(prefix=’auth.’, callback=None,


debug=False)
A Pyramid authentication policy which gets its data from the configured session. For
this authentication policy to work, you will have to follow the instructions in the Sessions
to configure a session factory.

Constructor Arguments

prefix

A prefix used when storing the authentication parameters in the session. De-
faults to ’auth.’. Optional.

callback

Default: None. A callback passed the userid and the request, expected to
return None if the userid doesn’t exist or a sequence of principal identifiers
(possibly empty) if the user does exist. If callback is None, the userid will
be assumed to exist with no principals. Optional.

debug

Default: False. If debug is True, log messages to the Pyramid debug


logger about the results of various authentication steps. The output from de-
bugging is useful for reporting to maillist or IRC channels when asking for
support.

authenticated_userid(request)
Return the authenticated userid or None.

If no callback is registered, this will be the same as unauthenti-


cated_userid.

If a callback is registered, this will return the userid if and only if the callback
returns a value that is not None.

effective_principals(request)
A list of effective principals derived from request.

This will return a list of principals including, at least, pyramid.


authorization.Everyone. If there is no authenticated userid, or the
callback returns None, this will be the only principal:

728 CONTENTS
The Pyramid Web Framework, Version 2.0.2

return [Everyone]

If the callback does not return None and an authenticated userid is found, then
the principals will include pyramid.authorization.Authenticated,
the authenticated_userid and the list of principals returned by the call-
back:

extra_principals = callback(userid, request)


return [Everyone, Authenticated, userid] + extra_principals

forget(request)
Remove the stored userid from the session.

remember(request, userid, **kw)


Store a userid in the session.

class BasicAuthAuthenticationPolicy(check, realm=’Realm’, debug=False)


A Pyramid authentication policy which uses HTTP standard basic authentication proto-
col to authenticate users. To use this policy you will need to provide a callback which
checks the supplied user credentials against your source of login data.

Constructor Arguments

check

A callback function passed a username, password and request, in that order as


positional arguments. Expected to return None if the userid doesn’t exist or a
sequence of principal identifiers (possibly empty) if the user does exist.

realm

Default: "Realm". The Basic Auth Realm string. Usually displayed to the
user by the browser in the login dialog.

debug

Default: False. If debug is True, log messages to the Pyramid debug


logger about the results of various authentication steps. The output from de-
bugging is useful for reporting to maillist or IRC channels when asking for
support.

0.4. API Documentation 729


The Pyramid Web Framework, Version 2.0.2

Issuing a challenge

Regular browsers will not send username/password credentials unless they first receive
a challenge from the server. The following recipe will register a view that will send a
Basic Auth challenge to the user whenever there is an attempt to call a view which results
in a Forbidden response:

from pyramid.httpexceptions import HTTPUnauthorized


from pyramid.security import forget
from pyramid.view import forbidden_view_config

@forbidden_view_config()
def forbidden_view(request):
if request.authenticated_userid is None:
response = HTTPUnauthorized()
response.headers.update(forget(request))
return response
return HTTPForbidden()

authenticated_userid(request)
Return the authenticated userid or None.

If no callback is registered, this will be the same as unauthenti-


cated_userid.

If a callback is registered, this will return the userid if and only if the callback
returns a value that is not None.

effective_principals(request)
A list of effective principals derived from request.

This will return a list of principals including, at least, pyramid.


authorization.Everyone. If there is no authenticated userid, or the
callback returns None, this will be the only principal:

return [Everyone]

If the callback does not return None and an authenticated userid is found, then
the principals will include pyramid.authorization.Authenticated,
the authenticated_userid and the list of principals returned by the call-
back:

730 CONTENTS
The Pyramid Web Framework, Version 2.0.2

extra_principals = callback(userid, request)


return [Everyone, Authenticated, userid] + extra_principals

forget(request)
Returns challenge headers. This should be attached to a response to indicate that
credentials are required.

remember(request, userid, **kw)


A no-op. Basic authentication does not provide a protocol for remembering the
user. Credentials are sent on every request.

unauthenticated_userid(request)
The userid parsed from the Authorization request header.

class RepozeWho1AuthenticationPolicy(identifier_name=’auth_tkt’,
callback=None)
A Pyramid authentication policy which obtains data from the repoze.who 1.X WSGI
’API’ (the repoze.who.identity key in the WSGI environment).

Constructor Arguments

identifier_name

Default: auth_tkt. The repoze.who plugin name that performs remem-


ber/forget. Optional.

callback

Default: None. A callback passed the repoze.who identity and the request,
expected to return None if the user represented by the identity doesn’t exist or
a sequence of principal identifiers (possibly empty) representing groups if the
user does exist. If callback is None, the userid will be assumed to exist
with no group principals.

Objects of this class implement the interface described by pyramid.interfaces.


IAuthenticationPolicy.

0.4. API Documentation 731


The Pyramid Web Framework, Version 2.0.2

authenticated_userid(request)
Return the authenticated userid or None.

If no callback is registered, this will be the same as unauthenti-


cated_userid.

If a callback is registered, this will return the userid if and only if the callback
returns a value that is not None.

effective_principals(request)
A list of effective principals derived from the identity.

This will return a list of principals including, at least, pyramid.


authorization.Everyone. If there is no identity, or the callback
returns None, this will be the only principal.

If the callback does not return None and an identity is found, then the prin-
cipals will include pyramid.authorization.Authenticated, the au-
thenticated_userid and the list of principals returned by the callback.

forget(request)
Forget the current authenticated user.

Return headers that, if included in a response, will delete the cookie responsible for
tracking the current user.

remember(request, userid, **kw)


Store the userid as repoze.who.userid.

The identity to authenticated to repoze.who will contain the given userid as


userid, and provide all keyword arguments as additional identity keys. Useful
keys could be max_age or userdata.

unauthenticated_userid(request)
Return the repoze.who.userid key from the detected identity.

732 CONTENTS
The Pyramid Web Framework, Version 2.0.2

pyramid.authorization

class ACLHelper
A helper for use with constructing a security policy which consults an ACL object attached to a con-
text to determine authorization information about a principal or multiple principals. If the context
is part of a lineage, the context’s parents are consulted for ACL information too.

permits(context, principals, permission)


Return an instance of pyramid.authorization.ACLAllowed if the ACL allows ac-
cess a user with the given principals, return an instance of pyramid.authorization.
ACLDenied if not.

When checking if principals are allowed, the security policy consults the context for an
ACL first. If no ACL exists on the context, or one does exist but the ACL does not explicitly
allow or deny access for any of the effective principals, consult the context’s parent ACL, and
so on, until the lineage is exhausted or we determine that the policy permits or denies.

During this processing, if any pyramid.authorization.Deny ACE is found


matching any principal in principals, stop processing by returning an pyramid.
authorization.ACLDenied instance (equals False) immediately. If any pyramid.
authorization.Allow ACE is found matching any principal, stop processing by return-
ing an pyramid.authorization.ACLAllowed instance (equals True) immediately.
If we exhaust the context’s lineage, and no ACE has explicitly permitted or denied access,
return an instance of pyramid.authorization.ACLDenied (equals False).

principals_allowed_by_permission(context, permission)
Return the set of principals explicitly granted the permission named permission according
to the ACL directly attached to the context as well as inherited ACLs based on the lineage.

When computing principals allowed by a permission, we compute the set of principals that are
explicitly granted the permission in the provided context. We do this by walking ’up’
the object graph from the root to the context. During this walking process, if we find an explicit
pyramid.authorization.Allow ACE for a principal that matches the permission,
the principal is included in the allow list. However, if later in the walking process that prin-
cipal is mentioned in any pyramid.authorization.Deny ACE for the permission, the
principal is removed from the allow list. If a pyramid.authorization.Deny to the
principal pyramid.authorization.Everyone is encountered during the walking pro-
cess that matches the permission, the allow list is cleared for all principals encountered in
previous ACLs. The walking process ends after we’ve processed the any ACL directly attached
to context; a set of principals is returned.

0.4. API Documentation 733


The Pyramid Web Framework, Version 2.0.2

class ACLAuthorizationPolicy
An authorization policy which consults an ACL object attached to a context to determine au-
thorization information about a principal or multiple principals. This class is a wrapper around
ACLHelper, refer to that class for more detailed documentation.

Objects of this class implement the pyramid.interfaces.IAuthorizationPolicy in-


terface.

Deprecated since version 2.0: Authorization policies have been deprecated by the new security sys-
tem. See upgrading_auth_20 for more information.

Constants

Everyone
The special principal id named Everyone. This principal id is granted to all requests. Its actual
value is the string 'system.Everyone'.

New in version 2.0: Moved from pyramid.security into pyramid.authorization.

Authenticated
The special principal id named Authenticated. This principal id is granted to all requests which
contain any other non-Everyone principal id (according to the authentication policy). Its actual value
is the string 'system.Authenticated'.

New in version 2.0: Moved from pyramid.security into pyramid.authorization.

ALL_PERMISSIONS
An object that can be used as the permission member of an ACE which matches all permissions
unconditionally. For example, an ACE that uses ALL_PERMISSIONS might be composed like so:
('Deny', 'system.Everyone', ALL_PERMISSIONS).

New in version 2.0: Moved from pyramid.security into pyramid.authorization.

DENY_ALL
A convenience shorthand ACE that defines ('Deny', 'system.Everyone',
ALL_PERMISSIONS). This is often used as the last ACE in an ACL in systems that use
an ”inheriting” security policy, representing the concept ”don’t inherit any other ACEs”.

New in version 2.0: Moved from pyramid.security into pyramid.authorization.

734 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Return Values

class ACLDenied(ace, acl, permission, principals, context)

static __new__(cls, ace, acl, permission, principals, context)


Create a new instance.

Parameters

• ace -- The ACE that matched, triggering the result.

• acl -- The ACL containing ace.

• permission -- The required permission.

• principals -- The list of principals provided.

• context -- The context providing the lineage searched.

New in version 2.0: Moved from pyramid.security into pyramid.authorization.

property msg
A string indicating why the result was generated.

class ACLAllowed(ace, acl, permission, principals, context)

static __new__(cls, ace, acl, permission, principals, context)


Create a new instance.

Parameters

• ace -- The ACE that matched, triggering the result.

• acl -- The ACL containing ace.

• permission -- The required permission.

• principals -- The list of principals provided.

• context -- The context providing the lineage searched.

New in version 2.0: Moved from pyramid.security into pyramid.authorization.

property msg
A string indicating why the result was generated.

0.4. API Documentation 735


The Pyramid Web Framework, Version 2.0.2

pyramid.config

class Configurator(registry=None, package=None, settings=None, root_factory=None,


security_policy=None, authentication_policy=None,
authorization_policy=None, renderers=None, debug_logger=None,
locale_negotiator=None, request_factory=None, response_factory=None,
default_permission=None, session_factory=None,
default_view_mapper=None, autocommit=False,
exceptionresponse_view=<function default_exceptionresponse_view>,
route_prefix=None, introspection=True, root_package=None)
A Configurator is used to configure a Pyramid application registry.

The Configurator lifecycle can be managed by using a context manager to automatically


handle calling pyramid.config.Configurator.begin() and pyramid.config.
Configurator.end() as well as pyramid.config.Configurator.commit().

with Configurator(settings=settings) as config:


config.add_route('home', '/')
app = config.make_wsgi_app()

If the registry argument is not None, it must be an instance of the pyramid.registry.


Registry class representing the registry to configure. If registry is None, the configurator
will create a pyramid.registry.Registry instance itself; it will also perform some default
configuration that would not otherwise be done. After its construction, the configurator may be used
to add further configuration to the registry.

If registry is assigned the above-mentioned class instance, all other constructor argu-
ments are ignored, with the exception of package.

If the package argument is passed, it must be a reference to a Python package (e.g. sys.
modules['thepackage']) or a dotted Python name to the same. This value is used as a basis
to convert relative paths passed to various configuration methods, such as methods which accept a
renderer argument, into absolute paths. If None is passed (the default), the package is assumed
to be the Python package in which the caller of the Configurator constructor lives.

If the root_package is passed, it will propagate through the configuration hierarchy as a way for
included packages to locate resources relative to the package in which the main Configurator
was created. If None is passed (the default), the root_package will be derived from the pack-
age argument. The package attribute is always pointing at the package being included when using
include(), whereas the root_package does not change.

736 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If the settings argument is passed, it should be a Python dictionary representing the deploy-
ment settings for this application. These are later retrievable using the pyramid.registry.
Registry.settings attribute (aka request.registry.settings).

If the root_factory argument is passed, it should be an object representing the default root
factory for your application or a dotted Python name to the same. If it is None, a default root
factory will be used.

If security_policy is passed, it should be an instance of a security policy or a dotted Python


name to the same.

If authentication_policy is passed, it should be an instance of an authentication policy or


a dotted Python name to the same.

If authorization_policy is passed, it should be an instance of an authorization policy or a


dotted Python name to the same.

A ConfigurationError will be raised when an authorization policy is supplied without


also supplying an authentication policy (authorization requires authentication).

If renderers is None (the default), a default set of renderer factories is used. Else, it should be a
list of tuples representing a set of renderer factories which should be configured into this application,
and each tuple representing a set of positional values that should be passed to pyramid.config.
Configurator.add_renderer().

If debug_logger is not passed, a default debug logger that logs to a logger will be used (the logger
name will be the package name of the caller of this configurator). If it is passed, it should be an
instance of the logging.Logger (PEP 282) standard library class or a Python logger name. The
debug logger is used by Pyramid itself to log warnings and authorization debugging information.

If locale_negotiator is passed, it should be a locale negotiator implementation or a dotted


Python name to same. See Using a Custom Locale Negotiator.

If request_factory is passed, it should be a request factory implementation or a dotted Python


name to the same. See Changing the Request Factory. By default it is None, which means use the
default request factory.

If response_factory is passed, it should be a response factory implementation or a dotted


Python name to the same. See Changing the Response Factory. By default it is None, which means
use the default response factory.

0.4. API Documentation 737


The Pyramid Web Framework, Version 2.0.2

If default_permission is passed, it should be a permission string to be used as the default


permission for all view configuration registrations performed against this Configurator. An exam-
ple of a permission string:'view'. Adding a default permission makes it unnecessary to protect
each view configuration with an explicit permission, unless your application policy requires some
exception for a particular view. By default, default_permission is None, meaning that view
configurations which do not explicitly declare a permission will always be executable by entirely
anonymous users (any authorization policy in effect is ignored).

See also:

See also Setting a Default Permission.

If session_factory is passed, it should be an object which implements the session factory


interface. If a nondefault value is passed, the session_factory will be used to create a ses-
sion object when request.session is accessed. Note that the same outcome can be achieved
by calling pyramid.config.Configurator.set_session_factory(). By default,
this argument is None, indicating that no session factory will be configured (and thus accessing
request.session will throw an error) unless set_session_factory is called later dur-
ing configuration.

If autocommit is True, every method called on the configurator will cause an immediate action,
and no configuration conflict detection will be used. If autocommit is False, most methods of
the configurator will defer their action until pyramid.config.Configurator.commit()
is called. When pyramid.config.Configurator.commit() is called, the actions implied
by the called methods will be checked for configuration conflicts unless autocommit is True. If
a conflict is detected, a ConfigurationConflictError will be raised. Calling pyramid.
config.Configurator.make_wsgi_app() always implies a final commit.

If default_view_mapper is passed, it will be used as the default view mapper fac-


tory for view configurations that don’t otherwise specify one (see pyramid.interfaces.
IViewMapperFactory). If default_view_mapper is not passed, a superdefault view map-
per will be used.

If exceptionresponse_view is passed, it must be a view callable or None. If it is a view


callable, it will be used as an exception view callable when an exception response is raised. If
exceptionresponse_view is None, no exception response view will be registered, and all
raised exception responses will be bubbled up to Pyramid’s caller. By default, the pyramid.
httpexceptions.default_exceptionresponse_view function is used as the ex-
ceptionresponse_view.

If route_prefix is passed, all routes added with pyramid.config.Configurator.


add_route() will have the specified path prepended to their pattern.

738 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If introspection is passed, it must be a boolean value. If it’s True, introspection values during
actions will be kept for use for tools like the debug toolbar. If it’s False, introspection values
provided by registrations will be ignored. By default, it is True.

New in version 1.1: The exceptionresponse_view argument.

New in version 1.2: The route_prefix argument.

New in version 1.3: The introspection argument.

New in version 1.6: The root_package argument. The response_factory argument.

New in version 1.9: The ability to use the configurator as a context manager with the with-statement
to make threadlocal configuration available for further configuration with an implicit commit.

Controlling Configuration State

commit()
Commit any pending configuration actions. If a configuration conflict is detected in
the pending configuration actions, this method will raise a ConfigurationCon-
flictError; within the traceback of this error will be information about the
source of the conflict, usually including file names and line numbers of the cause
of the configuration conflicts.

You should think very carefully before manually invoking commit().


Especially not as part of any reusable configuration methods. Normally it should
only be done by an application author at the end of configuration in order to
override certain aspects of an addon.

begin(request=<object object>)
Indicate that application or test configuration has begun. This pushes a dictionary
containing the application registry implied by registry attribute of this configu-
rator and the request implied by the request argument onto the thread local stack
consulted by various pyramid.threadlocal API functions.

If request is not specified and the registry owned by the configurator is already
pushed as the current threadlocal registry then this method will keep the current
threadlocal request unchanged.

Changed in version 1.8: The current threadlocal request is propagated if the current
threadlocal registry remains unchanged.

0.4. API Documentation 739


The Pyramid Web Framework, Version 2.0.2

end()
Indicate that application or test configuration has ended. This pops the last value
pushed onto the thread local stack (usually by the begin method) and returns that
value.

include(callable, route_prefix=None)
Include a configuration callable, to support imperative application extensibility.

In versions of Pyramid prior to 1.2, this function accepted *callables,


but this has been changed to support only a single callable.

A configuration callable should be a callable that accepts a single argument named


config, which will be an instance of a Configurator. However, be warned that
it will not be the same configurator instance on which you call this method. The
code which runs as a result of calling the callable should invoke methods on the
configurator passed to it which add configuration state. The return value of a callable
will be ignored.

Values allowed to be presented via the callable argument to this method: any
callable Python object or any dotted Python name which resolves to a callable
Python object. It may also be a Python module, in which case, the module will
be searched for a callable named includeme, which will be treated as the config-
uration callable.

For example, if the includeme function below lives in a module named myapp.
myconfig:

1 # myapp.myconfig module
2

3 def my_view(request):
4 from pyramid.response import Response
5 return Response('OK')
6

7 def includeme(config):
8 config.add_view(my_view)

You might cause it to be included within your Pyramid application like so:

740 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1 from pyramid.config import Configurator


2

3 def main(global_config, **settings):


4 config = Configurator()
5 config.include('myapp.myconfig.includeme')

Because the function is named includeme, the function name can also be omitted
from the dotted name reference:

1 from pyramid.config import Configurator


2

3 def main(global_config, **settings):


4 config = Configurator()
5 config.include('myapp.myconfig')

Included configuration statements will be overridden by local configuration state-


ments if an included callable causes a configuration conflict by registering something
with the same configuration parameters.
If the route_prefix is supplied, it must be a string and will
have a similar effect to using pyramid.config.Configurator.
route_prefix_context(). Any calls to pyramid.config.
Configurator.add_route() within the included callable will have
their pattern prefixed with the value of route_prefix. This can be used to
help mount a set of routes at a different location than the included callable’s author
intended, while still maintaining the same route names. For example:

1 from pyramid.config import Configurator


2

3 def included(config):
4 config.add_route('show_users', '/show')
5

6 def main(global_config, **settings):


7 config = Configurator()
8 config.include(included, route_prefix='/users')

In the above configuration, the show_users route will have an effective route pat-
tern of /users/show, instead of /show because the route_prefix argument
will be prepended to the pattern.
New in version 1.2: The route_prefix parameter.
Changed in version 1.9: The included function is wrapped with a call
to pyramid.config.Configurator.begin() and pyramid.config.
Configurator.end() while it is executed.

0.4. API Documentation 741


The Pyramid Web Framework, Version 2.0.2

make_wsgi_app()
Commits any pending configuration statements, sends a pyramid.events.
ApplicationCreated event to all listeners, adds this configuration’s registry to
pyramid.config.global_registries, and returns a Pyramid WSGI ap-
plication representing the committed configuration state.

route_prefix_context(route_prefix)
Return this configurator with a route prefix temporarily set.

When the context exits, the route_prefix is reset to the original.

route_prefix is a string suitable to be used as a route prefix, or None.

Example Usage:

config = Configurator()
with config.route_prefix_context('foo'):
config.add_route('bar', '/bar')

New in version 1.10.

scan(package=None, categories=(’pyramid’,), onerror=None, ignore=None, **kw)


Scan a Python package and any of its subpackages for objects marked with con-
figuration decoration such as pyramid.view.view_config. Any decorated
object found will influence the current configuration state.

The package argument should be a Python package or module object (or a dotted
Python name which refers to such a package or module). If package is None, the
package of the caller is used.

The categories argument, if provided, should be the Venusian ’scan categories’


to use during scanning. Providing this argument is not often necessary; specify-
ing scan categories is an extremely advanced usage. By default, categories is
['pyramid'] which will execute only Pyramid-related Venusian decorator call-
backs such as from pyramid.view.view_config. See the Venusian docu-
mentation for more information about limiting a scan by using an explicit set of
categories. Pass None to pick up all Venusian decorators.

The onerror argument, if provided, should be a Venusian onerror callback


function. The onerror function is passed to venusian.Scanner.scan() to
influence error behavior when an exception is raised during the scanning process.
See the Venusian documentation for more information about onerror callbacks.

742 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The ignore argument, if provided, should be a Venusian ignore value. Pro-


viding an ignore argument allows the scan to ignore particular modules, pack-
ages, or global objects during a scan. ignore can be a string or a callable, or
a list containing strings or callables. The simplest usage of ignore is to pro-
vide a module or package by providing a full path to its dotted name. For exam-
ple: config.scan(ignore='my.module.subpackage') would ignore
the my.module.subpackage package during a scan, which would prevent the
subpackage and any of its submodules from being imported and scanned. See the
Venusian documentation for more information about the ignore argument.

To perform a scan, Pyramid creates a Venusian Scanner object. The kw ar-


gument represents a set of keyword arguments to pass to the Venusian Scanner
object’s constructor. See the venusian documentation (its Scanner class) for more
information about the constructor. By default, the only keyword arguments passed
to the Scanner constructor are {'config':self} where self is this configu-
rator object. This services the requirement of all built-in Pyramid decorators, but
extension systems may require additional arguments. Providing this argument is not
often necessary; it’s an advanced usage.

New in version 1.1: The **kw argument.

New in version 1.3: The ignore argument.

Changed in version 2.0: The categories argument now defaults to ['pyra-


mid'] instead of None to control which decorator callbacks are executed.

Adding Routes and Views

add_route(name, pattern=None, factory=None, for_=None, header=None,


xhr=None, accept=None, path_info=None, request_method=None,
request_param=None, traverse=None, custom_predicates=(),
use_global_views=False, path=None, pregenerator=None,
static=False, inherit_slash=None, **predicates)
Add a route configuration to the current configuration state. Arguments to
add_route are divided into predicate and non-predicate types. Route predicate
arguments narrow the circumstances in which a route will match a request; non-
predicate arguments are informational.

Non-Predicate Arguments

name
The name of the route, e.g. myroute. This attribute is required. It must
be unique among all defined routes in a given application.

0.4. API Documentation 743


The Pyramid Web Framework, Version 2.0.2

factory
A Python object (often a function or a class) or a dotted Python name which
refers to the same object that will generate a Pyramid root resource ob-
ject when this route matches. For example, mypackage.resources.
MyFactory. If this argument is not specified, a default root factory will
be used. See The Resource Tree for more information about root factories.
traverse
If you would like to cause the context to be something other than the root
object when this route matches, you can spell a traversal pattern as the tra-
verse argument. This traversal pattern will be used as the traversal path:
traversal will begin at the root object implied by this route (either the global
root, or the object returned by the factory associated with this route).

The syntax of the traverse argument is the same as it is for pat-


tern. For example, if the pattern provided to add_route is
articles/{article}/edit, and the traverse argument provided
to add_route is /{article}, when a request comes in that causes the
route to match in such a way that the article match value is '1' (when
the request URI is /articles/1/edit), the traversal path will be gen-
erated as /1. This means that the root object’s __getitem__ will be
called with the name '1' during the traversal phase. If the '1' object
exists, it will become the context of the request. Traversal has more infor-
mation about traversal.

If the traversal path contains segment marker names which are not present in
the pattern argument, a runtime error will occur. The traverse pat-
tern should not contain segment markers that do not exist in the pattern
argument.

A similar combining of routing and traversal is available when a route is


matched which contains a *traverse remainder marker in its pattern
(see Using *traverse in a Route Pattern). The traverse argument to
add_route allows you to associate route patterns with an arbitrary traversal
path without using a *traverse remainder marker; instead you can use
other match information.

Note that the traverse argument to add_route is ignored when at-


tached to a route that has a *traverse remainder marker in its pattern.
pregenerator
This option should be a callable object that implements the pyramid.
interfaces.IRoutePregenerator interface. A pregenerator is a
callable called by the pyramid.request.Request.route_url()
function to augment or replace the arguments it is passed when generating a
URL for the route. This is a feature not often used directly by applications,
it is meant to be hooked by frameworks that use Pyramid as a base.

744 CONTENTS
The Pyramid Web Framework, Version 2.0.2

use_global_views
When a request matches this route, and view lookup cannot find a view
which has a route_name predicate argument that matches the route, try
to fall back to using a view that otherwise matches the context, request, and
view name (but which does not match the route_name predicate).
static
If static is True, this route will never match an incoming request; it
will only be useful for URL generation. By default, static is False.
See Static Routes.

New in version 1.1.


inherit_slash
This argument can only be used when the pattern is an empty string
(''). By default, the composed route pattern will always include a trailing
slash, but this argument provides a way to opt-out if both, you (the devel-
oper invoking add_route) and the integrator (the developer setting the
route prefix), agree that the pattern should not contain a trailing slash. For
example:

with config.route_prefix_context('/users'):
config.add_route('users', '', inherit_slash=True)

In this example, the resulting route pattern will be /users. Alternatively,


if the route prefix were /users/, then the resulting route pattern would
be /users/.

New in version 2.0.


Predicate Arguments

pattern
The pattern of the route e.g. ideas/{idea}. This argument is required.
See Route Pattern Syntax for information about the syntax of route patterns.
If the pattern doesn’t match the current URL, route matching continues.

For backwards compatibility purposes (as of Pyramid 1.0), a path


keyword argument passed to this function will be used to represent the pat-
tern value if the pattern argument is None. If both path and pattern
are passed, pattern wins.

xhr

0.4. API Documentation 745


The Pyramid Web Framework, Version 2.0.2

This value should be either True or False. If this value is specified and
is True, the request must possess an HTTP_X_REQUESTED_WITH (aka
X-Requested-With) header for this route to match. This is useful for
detecting AJAX requests issued from jQuery, Prototype and other Javascript
libraries. If this predicate returns False, route matching continues.
request_method
A string representing an HTTP method name, e.g. GET, POST, HEAD,
DELETE, PUT or a tuple of elements containing HTTP method names. If
this argument is not specified, this route will match if the request has any
request method. If this predicate returns False, route matching continues.

Changed in version 1.2: The ability to pass a tuple of items as re-


quest_method. Previous versions allowed only a string.
path_info
This value represents a regular expression pattern that will be tested against
the PATH_INFO WSGI environment variable. If the regex matches, this
predicate will return True. If this predicate returns False, route matching
continues.
request_param
This value can be any string or an iterable of strings. A view declara-
tion with this argument ensures that the associated route will only match
when the request has a key in the request.params dictionary (an
HTTP GET or POST variable) that has a name which matches the supplied
value. If the value supplied as the argument has a = sign in it, e.g. re-
quest_param="foo=123", then both the key (foo) must exist in the
request.params dictionary, and the value must match the right hand
side of the expression (123) for the route to ”match” the current request. If
this predicate returns False, route matching continues.
header
This argument can be a string or an iterable of strings for HTTP headers.
The matching is determined as follow:
• If a string does not contain a : (colon), it will be considered to be
the header name (example If-Modified-Since). In this case, the
header specified by the name must be present in the request for this string
to match. Case is not significant.
• If a string contains a colon, it will be considered a name/value pair (for ex-
ample User-Agent:Mozilla/.* or Host:localhost), where
the value part is a regular expression. The header specified by the name
must be present in the request and the regular expression specified as
the value part must match the value of the request header. Case is not
significant for the header name, but it is for the value.
All strings must be matched for this predicate to return True. If this pred-
icate returns False, route matching continues.
accept

746 CONTENTS
The Pyramid Web Framework, Version 2.0.2

A media type that will be matched against the Accept HTTP request
header. If this value is specified, it may be a specific media type such as
text/html, or a list of the same. If the media type is acceptable by the
Accept header of the request, or if the Accept header isn’t set at all in
the request, this predicate will match. If this does not match the Accept
header of the request, route matching continues.

If accept is not specified, the HTTP_ACCEPT HTTP header is not taken


into consideration when deciding whether or not to select the route.

Unlike the accept argument to pyramid.config.Configurator.


add_view(), this value is strictly a predicate and supports pyramid.
config.not_().

Changed in version 1.10: Specifying a media range is deprecated due to


changes in WebOb and ambiguities that occur when trying to match ranges
against ranges in the Accept header. Support will be removed in Pyramid
2.0. Use a list of specific media types to match more than one type.

Changed in version 2.0: Removed support for media ranges.


is_authenticated
This value, if specified, must be either True or False. If it is specified
and True, only a request from an authenticated user, as determined by the
security policy in use, will satisfy the predicate. If it is specified and False,
only a request from a user who is not authenticated will satisfy the predicate.

New in version 2.0.


effective_principals
If specified, this value should be a principal identifier or a sequence
of principal identifiers. If the pyramid.request.Request.
effective_principals property indicates that every principal
named in the argument list is present in the current request, this
predicate will return True; otherwise it will return False. For exam-
ple: effective_principals=pyramid.authorization.
Authenticated or effective_principals=('fred',
'group:admins').

New in version 1.4a4.

Deprecated since version 2.0: Use is_authenticated or a custom


predicate.
custom_predicates

0.4. API Documentation 747


The Pyramid Web Framework, Version 2.0.2

Deprecated since version 1.5: This value should be a sequence of references


to custom predicate callables. Use custom predicates when no set of prede-
fined predicates does what you need. Custom predicates can be combined
with predefined predicates as necessary. Each custom predicate callable
should accept two arguments: info and request and should return ei-
ther True or False after doing arbitrary evaluation of the info and/or the
request. If all custom and non-custom predicate callables return True the
associated route will be considered viable for a given request. If any predi-
cate callable returns False, route matching continues. Note that the value
info passed to a custom route predicate is a dictionary containing match-
ing information; see Custom Route Predicates for more information about
info.
**predicates
Pass extra keyword parameters to use custom predicates registered via
pyramid.config.Configurator.add_route_predicate().
More than one custom predicate can be used at the same time. See View
and Route Predicates for more information about custom predicates.

New in version 1.4.


add_static_view(name, path, cache_max_age=3600,
permission=NO_PERMISSION_REQUIRED)
Add a view used to render static assets such as images and CSS files.

The name argument is a string representing an application-relative local URL prefix.


It may alternately be a full URL.

The path argument is the path on disk where the static files reside. This can be an
absolute path, a package-relative path, or a asset specification.

The cache_max_age keyword argument is input to set the Expires and


Cache-Control headers for static assets served. Note that this argument has
no effect when the name is a url prefix. By default, this argument is None, meaning
that no particular Expires or Cache-Control headers are set in the response.

The content_encodings keyword argument is a list of alternative file en-


codings supported in the Accept-Encoding HTTP Header. Alternative files
are found using file extensions defined in mimetypes.encodings_map. An
encoded asset will be returned with the Content-Encoding header set to
the selected encoding. If the asset contains alternative encodings then the
Accept-Encoding value will be added to the response’s Vary header. By de-
fault, the list is empty and no alternatives will be supported.

748 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The permission keyword argument is used to specify the permission required by


a user to execute the static view. By default, it is the string pyramid.security.
NO_PERMISSION_REQUIRED, a special sentinel which indicates that, even if a
default permission exists for the current application, the static view should be ren-
derered to completely anonymous users. This default value is permissive because,
in most web apps, static assets seldom need protection from viewing. If permis-
sion is specified, the security checking will be performed against the default root
factory ACL.

Any other keyword arguments sent to add_static_view are passed on to


pyramid.config.Configurator.add_route() (e.g. factory, per-
haps to define a custom factory with a custom ACL for this static view).

Usage

The add_static_view function is typically used in conjunction


with the pyramid.request.Request.static_url() method.
add_static_view adds a view which renders a static asset when some
URL is visited; pyramid.request.Request.static_url() generates a
URL to that asset.

The name argument to add_static_view is usually a simple URL prefix


(e.g. 'images'). When this is the case, the pyramid.request.Request.
static_url() API will generate a URL which points to a Pyramid view, which
will serve up a set of assets that live in the package itself. For example:

add_static_view('images', 'mypackage:images/')

Code that registers such a view can generate URLs to the view via pyramid.
request.Request.static_url():

request.static_url('mypackage:images/logo.png')

When add_static_view is called with a name argument that represents a


URL prefix, as it is above, subsequent calls to pyramid.request.Request.
static_url() with paths that start with the path argument passed to
add_static_view will generate a URL something like http://<Pyramid
app URL>/images/logo.png, which will cause the logo.png file in the
images subdirectory of the mypackage package to be served.

add_static_view can alternately be used with a name argument which is a


URL, causing static assets to be served from an external webserver. This happens

0.4. API Documentation 749


The Pyramid Web Framework, Version 2.0.2

when the name argument is a fully qualified URL (e.g. starts with http:// or
similar). In this mode, the name is used as the prefix of the full URL when gener-
ating a URL using pyramid.request.Request.static_url(). Further-
more, if a protocol-relative URL (e.g. //example.com/images) is used as the
name argument, the generated URL will use the protocol of the request (http or
https, respectively).

For example, if add_static_view is called like so:

add_static_view('http://example.com/images',
,→'mypackage:images/')

Subsequently, the URLs generated by pyramid.request.Request.


static_url() for that static view will be prefixed with http://example.
com/images (the external webserver listening on example.com must be itself
configured to respond properly to such a request.):

static_url('mypackage:images/logo.png', request)

See Serving Static Assets for more information.

Changed in version 2.0: Added the content_encodings argument.

add_view(view=None, name=”, for_=None, permission=None,


request_type=None, route_name=None, request_method=None,
request_param=None, containment=None, attr=None, renderer=None,
wrapper=None, xhr=None, accept=None, header=None,
path_info=None, custom_predicates=(), context=None, decorator=None,
mapper=None, http_cache=None, match_param=None,
require_csrf=None, exception_only=False, **view_options)
Add a view configuration to the current configuration state. Arguments to
add_view are broken down below into predicate arguments and non-predicate ar-
guments. Predicate arguments narrow the circumstances in which the view callable
will be invoked when a request is presented to Pyramid; non-predicate arguments
are informational.

Non-Predicate Arguments

view

750 CONTENTS
The Pyramid Web Framework, Version 2.0.2

A view callable or a dotted Python name which refers to a view callable.


This argument is required unless a renderer argument also exists. If a
renderer argument is passed, and a view argument is not provided, the
view callable defaults to a callable that returns an empty dictionary (see
Writing View Callables Which Use a Renderer).
permission
A permission that the user must possess in order to invoke the view callable.
See Configuring View Security for more information about view security
and permissions. This is often a string like view or edit.

If permission is omitted, a default permission may be


used for this view registration if one was named as the
pyramid.config.Configurator constructor’s de-
fault_permission argument, or if pyramid.config.
Configurator.set_default_permission() was used prior
to this view registration. Pass the value pyramid.security.
NO_PERMISSION_REQUIRED as the permission argument to explicitly
indicate that the view should always be executable by entirely anonymous
users, regardless of the default permission, bypassing any authorization
policy that may be in effect.
attr
This knob is most useful when the view definition is a class.

The view machinery defaults to using the __call__ method of the view
callable (or the function itself, if the view callable is a function) to ob-
tain a response. The attr value allows you to vary the method attribute
used to obtain the response. For example, if your view was a class, and
the class has a method named index and you wanted to use this method
instead of the class’ __call__ method to return the response, you’d say
attr="index" in the view configuration for the view.
renderer
This is either a single string term (e.g. json) or a string implying a path
or asset specification (e.g. templates/views.pt) naming a renderer
implementation. If the renderer value does not contain a dot ., the spec-
ified string will be used to look up a renderer implementation, and that ren-
derer implementation will be used to construct a response from the view
return value. If the renderer value contains a dot (.), the specified term
will be treated as a path, and the filename extension of the last element in
the path will be used to look up the renderer implementation, which will be
passed the full path. The renderer implementation will be used to construct
a response from the view return value.

Note that if the view itself returns a response (see View Callable Responses),
the specified renderer implementation is never called.

0.4. API Documentation 751


The Pyramid Web Framework, Version 2.0.2

When the renderer is a path, although a path is usually just a simple rel-
ative pathname (e.g. templates/foo.pt, implying that a template
named ”foo.pt” is in the ”templates” directory relative to the directory of
the current package of the Configurator), a path can be absolute, start-
ing with a slash on UNIX or a drive letter prefix on Windows. The
path can alternately be a asset specification in the form some.dotted.
package_name:relative/path, making it possible to address tem-
plate assets which live in a separate package.

The renderer attribute is optional. If it is not defined, the ”null” renderer


is assumed (no rendering is performed and the value is passed back to the
upstream Pyramid machinery unmodified).
http_cache
New in version 1.1.

When you supply an http_cache value to a view configuration, the Ex-


pires and Cache-Control headers of a response generated by the as-
sociated view callable are modified. The value for http_cache may be
one of the following:
• A nonzero integer. If it’s a nonzero integer, it’s treated as a number of
seconds. This number of seconds will be used to compute the Expires
header and the Cache-Control: max-age parameter of responses
to requests which call this view. For example: http_cache=3600 in-
structs the requesting browser to ’cache this response for an hour, please’.
• A datetime.timedelta instance. If it’s a datetime.
timedelta instance, it will be converted into a number of seconds, and
that number of seconds will be used to compute the Expires header and
the Cache-Control: max-age parameter of responses to requests
which call this view. For example: http_cache=datetime.
timedelta(days=1) instructs the requesting browser to ’cache this
response for a day, please’.
• Zero (0). If the value is zero, the Cache-Control and Expires
headers present in all responses from this view will be composed such
that client browser cache (and any intermediate caches) are instructed to
never cache the response.
• A two-tuple. If it’s a two tuple (e.g. http_cache=(1, {'pub-
lic':True})), the first value in the tuple may be a nonzero inte-
ger or a datetime.timedelta instance; in either case this value
will be used as the number of seconds to cache the response. The
second value in the tuple must be a dictionary. The values present
in the dictionary will be used as input to the Cache-Control re-
sponse header. For example: http_cache=(3600, {'pub-
lic':True}) means ’cache for an hour, and add public to the
Cache-Control header of the response’. All keys and values supported

752 CONTENTS
The Pyramid Web Framework, Version 2.0.2

by the webob.cachecontrol.CacheControl interface may be


added to the dictionary. Supplying {'public':True} is equivalent
to calling response.cache_control.public = True.
Providing a non-tuple value as http_cache is equivalent to calling
response.cache_expires(value) within your view’s body.

Providing a two-tuple value as http_cache is equivalent to calling


response.cache_expires(value[0], **value[1]) within
your view’s body.

If you wish to avoid influencing, the Expires header, and instead wish to
only influence Cache-Control headers, pass a tuple as http_cache
with the first element of None, e.g.: (None, {'public':True}).

If you wish to prevent a view that uses http_cache in its configuration


from having its caching response headers changed by this machinery, set
response.cache_control.prevent_auto = True before re-
turning the response from the view. This effectively disables any HTTP
caching done by http_cache for that response.
require_csrf
New in version 1.7.

A boolean option or None. Default: None.

If this option is set to True then CSRF checks will be enabled for requests
to this view. The required token or header default to csrf_token and
X-CSRF-Token, respectively.

CSRF checks only affect ”unsafe” methods as defined by RFC2616. By


default, these methods are anything except GET, HEAD, OPTIONS, and
TRACE.

The defaults here may be overridden by pyramid.config.


Configurator.set_default_csrf_options().

This feature requires a configured session factory.

If this option is set to False then CSRF checks will be dis-


abled regardless of the default require_csrf setting passed to
set_default_csrf_options.

See Checking CSRF Tokens Automatically for more information.


wrapper

0.4. API Documentation 753


The Pyramid Web Framework, Version 2.0.2

The view name of a different view configuration which will receive the re-
sponse body of this view as the request.wrapped_body attribute of
its own request, and the response returned by this view as the request.
wrapped_response attribute of its own request. Using a wrapper
makes it possible to ”chain” views together to form a composite response.
The response of the outermost wrapper view will be returned to the user.
The wrapper view will be found as any view is found: see View Configura-
tion. The ”best” wrapper view will be found based on the lookup ordering:
”under the hood” this wrapper view is looked up via pyramid.view.
render_view_to_response(context, request, 'wrap-
per_viewname'). The context and request of a wrapper view is the
same context and request of the inner view. If this attribute is unspecified,
no view wrapping is done.
decorator
A dotted Python name to function (or the function itself, or an iterable of the
aforementioned) which will be used to decorate the registered view callable.
The decorator function(s) will be called with the view callable as a single
argument. The view callable it is passed will accept (context, re-
quest). The decorator(s) must return a replacement view callable which
also accepts (context, request).

If decorator is an iterable, the callables will be combined and used in the


order provided as a decorator. For example:

@view_config(...,
decorator=(decorator2,
decorator1))
def myview(request):
....

Is similar to doing:

@view_config(...)
@decorator2
@decorator1
def myview(request):
...

Except with the existing benefits of decorator= (having a common


decorator syntax for all view calling conventions and not having to think
about preserving function attributes such as __name__ and __mod-
ule__ within decorator logic).

754 CONTENTS
The Pyramid Web Framework, Version 2.0.2

An important distinction is that each decorator will receive a response object


implementing pyramid.interfaces.IResponse instead of the raw
value returned from the view callable. All decorators in the chain must
return a response object or raise an exception:

def log_timer(wrapped):
def wrapper(context, request):
start = time.time()
response = wrapped(context, request)
duration = time.time() - start
response.headers['X-View-Time'] = '%.3f' %␣
,→(duration,)

log.info('view took %.3f seconds', duration)


return response
return wrapper

Changed in version 1.4a4: Passing an iterable.


mapper
A Python object or dotted Python name which refers to a view mapper,
or None. By default it is None, which indicates that the view should use
the default view mapper. This plug-point is useful for Pyramid extension
developers, but it’s not very useful for ’civilians’ who are just developing
stock Pyramid applications. Pay no attention to the man behind the curtain.
accept
A media type that will be matched against the Accept HTTP request
header. If this value is specified, it must be a specific media type such as
text/html or text/html;level=1. If the media type is acceptable
by the Accept header of the request, or if the Accept header isn’t set
at all in the request, this predicate will match. If this does not match the
Accept header of the request, view matching continues.

If accept is not specified, the HTTP_ACCEPT HTTP header is not taken


into consideration when deciding whether or not to invoke the associated
view callable.

The accept argument is technically not a predicate and does not support
wrapping with pyramid.config.not_().

See Accept Header Content Negotiation for more information.

Changed in version 1.10: Specifying a media range is deprecated and will be


removed in Pyramid 2.0. Use explicit media types to avoid any ambiguities
in content negotiation.

Changed in version 2.0: Removed support for media ranges.

0.4. API Documentation 755


The Pyramid Web Framework, Version 2.0.2

exception_only
New in version 1.8.

When this value is True, the context argument must be a subclass of


Exception. This flag indicates that only an exception view should be
created, and that this view should not match if the traversal context matches
the context argument. If the context is a subclass of Exception and
this value is False (the default), then a view will be registered to match
the traversal context as well.
Predicate Arguments

name
The view name. Read Traversal to understand the concept of a view name.
context
An object or a dotted Python name referring to an interface or class object
that the context must be an instance of, or the interface that the context must
provide in order for this view to be found and called. This predicate is true
when the context is an instance of the represented class or if the context
provides the represented interface; it is otherwise false. This argument may
also be provided to add_view as for_ (an older, still-supported spelling).
If the view should only match when handling exceptions, then set the ex-
ception_only to True.
route_name
This value must match the name of a route configuration declaration (see
URL Dispatch) that must match before this view will be called.
request_type
This value should be an interface that the request must provide in order
for this view to be found and called. This value exists only for backwards
compatibility purposes.
request_method
This value can be either a string (such as "GET", "POST", "PUT",
"DELETE", "HEAD" or "OPTIONS") representing an HTTP RE-
QUEST_METHOD, or a tuple containing one or more of these strings. A
view declaration with this argument ensures that the view will only be called
when the method attribute of the request (aka the REQUEST_METHOD of
the WSGI environment) matches a supplied value. Note that use of GET
also implies that the view will respond to HEAD as of Pyramid 1.4.

Changed in version 1.2: The ability to pass a tuple of items as re-


quest_method. Previous versions allowed only a string.
request_param
This value can be any string or any sequence of strings. A view declaration
with this argument ensures that the view will only be called when the request
has a key in the request.params dictionary (an HTTP GET or POST

756 CONTENTS
The Pyramid Web Framework, Version 2.0.2

variable) that has a name which matches the supplied value (if the value is
a string) or values (if the value is a tuple). If any value supplied has a = sign
in it, e.g. request_param="foo=123", then the key (foo) must both
exist in the request.params dictionary, and the value must match the
right hand side of the expression (123) for the view to ”match” the current
request.
match_param
New in version 1.2.
This value can be a string of the format ”key=value” or a tuple containing
one or more of these strings.
A view declaration with this argument ensures that the view will only be
called when the request has key/value pairs in its matchdict that equal those
supplied in the predicate. e.g. match_param="action=edit" would
require the action parameter in the matchdict match the right hand side
of the expression (edit) for the view to ”match” the current request.
If the match_param is a tuple, every key/value pair must match for the
predicate to pass.
containment
This value should be a Python class or interface (or a dotted Python name)
that an object in the lineage of the context must provide in order for this view
to be found and called. The nodes in your object graph must be ”location-
aware” to use this feature. See Location-Aware Resources for more infor-
mation about location-awareness.
xhr
This value should be either True or False. If this value is specified and
is True, the request must possess an HTTP_X_REQUESTED_WITH (aka
X-Requested-With) header that has the value XMLHttpRequest for
this view to be found and called. This is useful for detecting AJAX requests
issued from jQuery, Prototype and other Javascript libraries.
header
This argument can be a string or an iterable of strings for HTTP headers.
The matching is determined as follow:
• If a string does not contain a : (colon), it will be considered to be a header
name (example If-Modified-Since). In this case, the header spec-
ified by the name must be present in the request for this string to match.
Case is not significant.
• If a string contains a colon, it will be considered a name/value pair (for ex-
ample User-Agent:Mozilla/.* or Host:localhost), where
the value part is a regular expression. The header specified by the name
must be present in the request and the regular expression specified as
the value part must match the value of the request header. Case is not
significant for the header name, but it is for the value.

0.4. API Documentation 757


The Pyramid Web Framework, Version 2.0.2

All strings must be matched for this predicate to return True. If this pred-
icate returns False, view matching continues.
path_info
This value represents a regular expression pattern that will be tested against
the PATH_INFO WSGI environment variable. If the regex matches, this
predicate will be True.
physical_path
If specified, this value should be a string or a tuple representing the physical
path of the context found via traversal for this predicate to match as true. For
example: physical_path='/' or physical_path='/a/b/c' or
physical_path=('', 'a', 'b', 'c'). This is not a path pre-
fix match or a regex, it’s a whole-path match. It’s useful when you want to
always potentially show a view when some object is traversed to, but you
can’t be sure about what kind of object it will be, so you can’t use the con-
text predicate. The individual path elements in between slash characters
or in tuple elements should be the Unicode representation of the name of
the resource and should not be encoded in any way.

New in version 1.4a3.


is_authenticated
This value, if specified, must be either True or False. If it is specified
and True, only a request from an authenticated user, as determined by the
security policy in use, will satisfy the predicate. If it is specified and False,
only a request from a user who is not authenticated will satisfy the predicate.

New in version 2.0.


effective_principals
If specified, this value should be a principal identifier or a sequence
of principal identifiers. If the pyramid.request.Request.
effective_principals property indicates that every principal
named in the argument list is present in the current request, this
predicate will return True; otherwise it will return False. For exam-
ple: effective_principals=pyramid.authorization.
Authenticated or effective_principals=('fred',
'group:admins').

New in version 1.4a4.

Deprecated since version 2.0: Use is_authenticated or a custom


predicate.
custom_predicates

758 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Deprecated since version 1.5: This value should be a sequence of references


to custom predicate callables. Each custom predicate callable should accept
two arguments: context and request and should return either True
or False after doing arbitrary evaluation of the context and/or the request.
The ability to register custom view predicates via pyramid.config.
Configurator.add_view_predicate() obsoletes this argument,
but it is kept around for backwards compatibility.
**view_options
Pass extra keyword parameters to use custom predicates or
set a value for a view deriver. See pyramid.config.
Configurator.add_view_predicate() and pyramid.
config.Configurator.add_view_deriver(). See View and
Route Predicates for more information about custom predicates and View
Derivers for information about view derivers.

Changed in version 2.0: Removed support for the check_csrf predicate.

add_notfound_view(view=None, attr=None, renderer=None, wrapper=None,


route_name=None, request_type=None,
request_method=None, request_param=None,
containment=None, xhr=None, accept=None,
header=None, path_info=None, custom_predicates=(),
decorator=None, mapper=None, match_param=None,
append_slash=False, **view_options)
Add a default Not Found View to the current configuration state. The
view will be called when Pyramid or application code raises an pyramid.
httpexceptions.HTTPNotFound exception (e.g., when a view cannot be
found for the request). The simplest example is:

def notfound(request):
return Response('Not Found', status='404 Not␣
,→Found')

config.add_notfound_view(notfound)

If view argument is not provided, the view callable defaults to de-


fault_exceptionresponse_view().

All arguments except append_slash have the same meaning as pyramid.


config.Configurator.add_view() and each predicate argument restricts
the set of circumstances under which this notfound view will be invoked. Unlike
pyramid.config.Configurator.add_view(), this method will raise an
exception if passed name, permission, require_csrf, context, for_, or

0.4. API Documentation 759


The Pyramid Web Framework, Version 2.0.2

exception_only keyword arguments. These argument values make no sense in


the context of a Not Found View.

If append_slash is True, when this Not Found View is invoked, and the current
path info does not end in a slash, the notfound logic will attempt to find a route that
matches the request’s path info suffixed with a slash. If such a route exists, Pyramid
will issue a redirect to the URL implied by the route; if it does not, Pyramid will
return the result of the view callable provided as view, as normal.

If the argument provided as append_slash is not a boolean but in-


stead implements IResponse, the append_slash logic will behave as if ap-
pend_slash=True was passed, but the provided class will be used as the re-
sponse class instead of the default HTTPTemporaryRedirect response class
when a redirect is performed. For example:

from pyramid.httpexceptions import␣


,→HTTPMovedPermanently

config.add_notfound_view(append_
,→slash=HTTPMovedPermanently)

The above means that a redirect to a slash-appended route will be attempted, but in-
stead of HTTPTemporaryRedirect being used, HTTPMovedPermanently
will be used for the redirect response if a slash-appended route is found.

HTTPTemporaryRedirect class is used as default response, which is equivalent


to HTTPFound with addition of redirecting with the same HTTP method (useful
when doing POST requests).

New in version 1.3.

Changed in version 1.6: The append_slash argument was modified to allow any
object that implements the IResponse interface to specify the response class used
when a redirect is performed.

Changed in version 1.8: The view is created using exception_only=True.

add_forbidden_view(view=None, attr=None, renderer=None, wrapper=None,


route_name=None, request_type=None,
request_method=None, request_param=None,
containment=None, xhr=None, accept=None,
header=None, path_info=None, custom_predicates=(),
decorator=None, mapper=None, match_param=None,
**view_options)

760 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Add a forbidden view to the current configuration state. The view will be
called when Pyramid or application code raises a pyramid.httpexceptions.
HTTPForbidden exception and the set of circumstances implied by the predicates
provided are matched. The simplest example is:

def forbidden(request):
return Response('Forbidden', status='403␣
,→Forbidden')

config.add_forbidden_view(forbidden)

If view argument is not provided, the view callable defaults to de-


fault_exceptionresponse_view().

All arguments have the same meaning as pyramid.config.Configurator.


add_view() and each predicate argument restricts the set of circumstances
under which this forbidden view will be invoked. Unlike pyramid.
config.Configurator.add_view(), this method will raise an exception
if passed name, permission, require_csrf, context, for_, or excep-
tion_only keyword arguments. These argument values make no sense in the
context of a forbidden exception view.

New in version 1.3.

Changed in version 1.8: The view is created using exception_only=True.

add_exception_view(view=None, context=None, **view_options)


Add an exception view for the specified exception to the current configuration
state. The view will be called when Pyramid or application code raises the given
exception.

This method accepts almost all of the same arguments as pyramid.config.


Configurator.add_view() except for name, permission, for_, re-
quire_csrf, and exception_only.

By default, this method will set context=Exception, thus registering for most
default Python exceptions. Any subclass of Exception may be specified.

New in version 1.8.

Adding an Event Subscriber

0.4. API Documentation 761


The Pyramid Web Framework, Version 2.0.2

add_subscriber(subscriber, iface=None, **predicates)


Add an event subscriber for the event stream implied by the supplied iface inter-
face.
The subscriber argument represents a callable object (or a dotted Python name
which identifies a callable); it will be called with a single object event whenever
Pyramid emits an event associated with the iface, which may be an interface or a
class or a dotted Python name to a global object representing an interface or a class.
Using the default iface value, None will cause the subscriber to be registered for
all event types. See Using Events for more information about events and subscribers.
Any number of predicate keyword arguments may be passed in **predicates.
Each predicate named will narrow the set of circumstances in which the subscriber
will be invoked. Each named predicate must have been registered via pyramid.
config.Configurator.add_subscriber_predicate() before it can
be used. See Subscriber Predicates for more information.
New in version 1.4: The **predicates argument.
Using Security
set_security_policy(policy)
Override the Pyramid security policy in the current configuration. The
policy argument must be an instance of a security policy or a dotted
Python name that points at an instance of a security policy.

Using the security_policy argument to the pyramid.


config.Configurator constructor can be used to achieve the same
purpose.

set_authentication_policy(policy)
Deprecated since version 2.0: Authentication policies have been replaced
by security policies. See upgrading_auth_20 for more information.
Override the Pyramid authentication policy in the current configuration.
The policy argument must be an instance of an authentication policy or
a dotted Python name that points at an instance of an authentication policy.

Using the authentication_policy argument to the


pyramid.config.Configurator constructor can be used to
achieve the same purpose.

762 CONTENTS
The Pyramid Web Framework, Version 2.0.2

set_authorization_policy(policy)
Deprecated since version 2.0: Authentication policies have been replaced
by security policies. See upgrading_auth_20 for more information.

Override the Pyramid authorization policy in the current configuration.


The policy argument must be an instance of an authorization policy or
a dotted Python name that points at an instance of an authorization policy.

Using the authorization_policy argument to the pyramid.


config.Configurator constructor can be used to achieve the same
purpose.

set_default_csrf_options(require_csrf=True, token=’csrf_token’,
header=’X-CSRF-Token’,
safe_methods=(’GET’, ’HEAD’,
’OPTIONS’, ’TRACE’),
check_origin=True,
allow_no_origin=False,
callback=None)
Set the default CSRF options used by subsequent view registrations.

require_csrf controls whether CSRF checks will be automatically


enabled on each view in the application. This value is used as the fall-
back when require_csrf is left at the default of None on pyramid.
config.Configurator.add_view().

token is the name of the CSRF token used in the body of the request,
accessed via request.POST[token]. Default: csrf_token.

header is the name of the header containing the CSRF token, accessed
via request.headers[header]. Default: X-CSRF-Token.

If token or header are set to None they will not be used for checking
CSRF tokens.

safe_methods is an iterable of HTTP methods which are expected to


not contain side-effects as defined by RFC2616. Safe methods will never be
automatically checked for CSRF tokens. Default: ('GET', 'HEAD',
'OPTIONS', TRACE').

0.4. API Documentation 763


The Pyramid Web Framework, Version 2.0.2

check_origin is a boolean. If False, the Origin and Referer


headers will not be validated as part of automated CSRF checks.

allow_no_origin is a boolean. If True, a request lacking both an


Origin and Referer header will pass the CSRF check. This option has
no effect if check_origin is False.

If callback is set, it must be a callable accepting (request) and re-


turning True if the request should be checked for a valid CSRF token. This
callback allows an application to support alternate authentication methods
that do not rely on cookies which are not subject to CSRF attacks. For
example, if a request is authenticated using the Authorization header
instead of a cookie, this may return False for that request so that clients do
not need to send the X-CSRF-Token header. The callback is only tested
for non-safe methods as defined by safe_methods.

New in version 1.7.

Changed in version 1.8: Added the callback option.

Changed in version 2.0: Added the allow_no_origin and


check_origin options.

set_csrf_storage_policy(policy)
Set the CSRF storage policy used by subsequent view registrations.

policy is a class that implements the pyramid.interfaces.


ICSRFStoragePolicy() interface and defines how to generate and
persist CSRF tokens.

set_default_permission(permission)
Set the default permission to be used by all subsequent view configuration
registrations. permission should be a permission string to be used as the
default permission. An example of a permission string:'view'. Adding a
default permission makes it unnecessary to protect each view configuration
with an explicit permission, unless your application policy requires some
exception for a particular view.

If a default permission is not set, views represented by view configuration


registrations which do not explicitly declare a permission will be executable
by entirely anonymous users (any authorization policy is ignored).

Later calls to this method override will conflict with earlier calls; there can
be only one default permission active at a time within an application.

764 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If a default permission is in effect, view configurations


meant to create a truly anonymously accessible view (even excep-
tion view views) must use the value of the permission importable as
pyramid.security.NO_PERMISSION_REQUIRED. When this
string is used as the permission for a view configuration, the default
permission is ignored, and the view is registered, making it available to
all callers regardless of their credentials.

See also:

See also Setting a Default Permission.

Using the default_permission argument to the pyramid.


config.Configurator constructor can be used to achieve the same
purpose.

add_permission(permission_name)
A configurator directive which registers a free-standing permission without
associating it with a view callable. This can be used so that the permission
shows up in the introspectable data under the permissions category
(permissions mentioned via add_view already end up in there). For ex-
ample:

config = Configurator()
config.add_permission('view')

Extending the Request Object

add_request_method(callable=None, name=None, property=False,


reify=False)
Add a property or method to the request object.

When adding a method to the request, callable may be any function that
receives the request object as the first parameter. If name is None then it
will be computed from the name of the callable.

When adding a property to the request, callable can either be a callable


that accepts the request as its single positional parameter, or it can be a

0.4. API Documentation 765


The Pyramid Web Framework, Version 2.0.2

property descriptor. If callable is a property descriptor, it has to be an


instance of a class which is a subclass of property. If name is None, the
name of the property will be computed from the name of the callable.

If the callable is a property descriptor a ValueError will be raised


if name is None or reify is True.

See pyramid.request.Request.set_property() for more de-


tails on property vs reify. When reify is True, the value of
property is assumed to also be True.

In all cases, callable may also be a dotted Python name which refers to
either a callable or a property descriptor.

If callable is None then the method is only used to assist in conflict


detection between different addons requesting the same attribute on the re-
quest object.

This is the recommended method for extending the request


object and should be used in favor of providing a custom
request factory via pyramid.config.Configurator.
set_request_factory().

New in version 1.4.

Using I18N

add_translation_dirs(*specs, **kw)
Add one or more translation directory paths to the current configuration
state. The specs argument is a sequence that may contain absolute di-
rectory paths (e.g. /usr/share/locale) or asset specification names
naming a directory path (e.g. some.package:locale) or a combina-
tion of the two.

Example:

config.add_translation_dirs('/usr/share/locale',
'some.package:locale')

766 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The translation directories are defined as a list in which translations defined


later have precedence over translations defined earlier.

By default, consecutive calls to add_translation_dirs will add


directories to the start of the list. This means later calls to
add_translation_dirs will have their translations trumped by ear-
lier calls. If you explicitly need this call to trump an earlier call then you
may set override to True.

If multiple specs are provided in a single call to


add_translation_dirs, the directories will be inserted in the
order they’re provided (earlier items are trumped by later items).

Changed in version 1.8: The override parameter was added to allow a


later call to add_translation_dirs to override an earlier call, insert-
ing folders at the beginning of the translation directory list.

set_locale_negotiator(negotiator)
Set the locale negotiator for this application. The locale negotiator is a
callable which accepts a request object and which returns a locale name.
The negotiator argument should be the locale negotiator implementa-
tion or a dotted Python name which refers to such an implementation.

Later calls to this method override earlier calls; there can be only one locale
negotiator active at a time within an application. See Activating Translation
for more information.

Using the locale_negotiator argument to the pyramid.


config.Configurator constructor can be used to achieve the same
purpose.

Overriding Assets

override_asset(to_override, override_with)
Add a Pyramid asset override to the current configuration state.

to_override is an asset specification to the asset being overridden.

override_with is an asset specification to the asset that is performing


the override. This may also be an absolute path.

See Static Assets for more information about asset overrides.

Getting and Adding Settings

0.4. API Documentation 767


The Pyramid Web Framework, Version 2.0.2

add_settings(settings=None, **kw)
Augment the deployment settings with one or more key/value pairs.

You may pass a dictionary:

config.add_settings({'external_uri':'http://example.
,→com'})

Or a set of key/value pairs:

config.add_settings(external_uri='http://example.com
,→')

This function is useful when you need to test code that accesses
the pyramid.registry.Registry.settings API (or the
pyramid.config.Configurator.get_settings() API) and
which uses values from that API.

get_settings()
Return a deployment settings object for the current application. A de-
ployment settings object is a dictionary-like object that contains key/value
pairs based on the dictionary passed as the settings argument to the
pyramid.config.Configurator constructor.

the pyramid.registry.Registry.settings API performs


the same duty.

Hooking Pyramid Behavior

add_accept_view_order(value, weighs_more_than=None,
weighs_less_than=None)
Specify an ordering preference for the accept view option used during
view lookup.

By default, if two views have different accept options and a request spec-
ifies Accept: */* or omits the header entirely then it is random which
view will be selected. This method provides a way to specify a server-side,
relative ordering between accept media types.

768 CONTENTS
The Pyramid Web Framework, Version 2.0.2

value should be a media type as specified by RFC 7231#section-5.3.2.


For example, text/plain;charset=utf8, application/json
or text/html.

weighs_more_than and weighs_less_than control the ordering


of media types. Each value may be a string or a list of strings. If all options
for weighs_more_than (or weighs_less_than) cannot be found,
it is an error.

Earlier calls to add_accept_view_order are given higher priority


over later calls, assuming similar constraints but standard conflict resolu-
tion mechanisms can be used to override constraints.

See Accept Header Content Negotiation for more information.

New in version 1.10.

add_renderer(name, factory)
Add a Pyramid renderer factory to the current configuration state.

The name argument is the renderer name. Use None to represent the de-
fault renderer (a renderer which will be used for all views unless they name
another renderer specifically).

The factory argument is Python reference to an implementation of a


renderer factory or a dotted Python name to same.

add_resource_url_adapter(adapter, resource_iface=None)
New in version 1.3.

When you add a traverser as described in Changing the Traverser, it’s


convenient to continue to use the pyramid.request.Request.
resource_url() API. However, since the way traversal is done may
have been modified, the URLs that resource_url generates by default
may be incorrect when resources are returned by a custom traverser.

If you’ve added a traverser, you can change how resource_url() gen-


erates a URL for a specific type of resource by calling this method.

The adapter argument represents a class that implements the IRe-


sourceURL interface. The class constructor should accept two arguments
in its constructor (the resource and the request) and the resulting instance

0.4. API Documentation 769


The Pyramid Web Framework, Version 2.0.2

should provide the attributes detailed in that interface (virtual_path


and physical_path, in particular).

The resource_iface argument represents a class or interface that


the resource should possess for this url adapter to be used when
pyramid.request.Request.resource_url() looks up a re-
source url adapter. If resource_iface is not passed, or it is passed
as None, the url adapter will be used for every type of resource.

See Changing How pyramid.request.Request.resource_url() Generates a


URL for more information.

add_response_adapter(adapter, type_or_iface)
When an object of type (or interface) type_or_iface is returned from
a view callable, Pyramid will use the adapter adapter to convert it into
an object which implements the pyramid.interfaces.IResponse
interface. If adapter is None, an object returned of type (or interface)
type_or_iface will itself be used as a response object.

adapter and type_or_interface may be Python objects or strings


representing dotted names to importable Python global objects.

See Changing How Pyramid Treats View Responses for more information.

add_traverser(adapter, iface=None)
The superdefault traversal algorithm that Pyramid uses is explained in The
Traversal Algorithm. Though it is rarely necessary, this default algorithm
can be swapped out selectively for a different traversal pattern via configu-
ration. The section entitled Changing the Traverser details how to create a
traverser class.

For example, to override the superdefault traverser used by Pyramid, you


might do something like this:

from myapp.traversal import MyCustomTraverser


config.add_traverser(MyCustomTraverser)

This would cause the Pyramid superdefault traverser to never be used; in-
stead all traversal would be done using your MyCustomTraverser class,
no matter which object was returned by the root factory of this applica-
tion. Note that we passed no arguments to the iface keyword parameter.
The default value of iface, None represents that the registered traverser

770 CONTENTS
The Pyramid Web Framework, Version 2.0.2

should be used when no other more specific traverser is available for the
object returned by the root factory.

However, more than one traversal algorithm can be active at the same time.
The traverser used can depend on the result of the root factory. For instance,
if your root factory returns more than one type of object conditionally, you
could claim that an alternate traverser adapter should be used against one
particular class or interface returned by that root factory. When the root
factory returned an object that implemented that class or interface, a custom
traverser would be used. Otherwise, the default traverser would be used.
The iface argument represents the class of the object that the root factory
might return or an interface that the object might implement.

To use a particular traverser only when the root factory returns a particular
class:

config.add_traverser(MyCustomTraverser, MyRootClass)

When more than one traverser is active, the ”most specific” traverser will
be used (the one that matches the class or interface of the value returned by
the root factory most closely).

Note that either adapter or iface can be a dotted Python name or a


Python object.

See Changing the Traverser for more information.

add_tween(tween_factory, under=None, over=None)


New in version 1.2.

Add a ’tween factory’. A tween (a contraction of ’between’) is a bit of code


that sits between the Pyramid router’s main request handling function and
the upstream WSGI component that uses Pyramid as its ’app’. Tweens are
a feature that may be used by Pyramid framework extensions, to provide,
for example, Pyramid-specific view timing support, bookkeeping code that
examines exceptions before they are returned to the upstream WSGI ap-
plication, or a variety of other features. Tweens behave a bit like WSGI
’middleware’ but they have the benefit of running in a context in which
they have access to the Pyramid application registry as well as the Pyramid
rendering machinery.

0.4. API Documentation 771


The Pyramid Web Framework, Version 2.0.2

You can view the tween ordering configured into a given Pyramid
application by using the ptweens command. See ptweens: Displaying
”Tweens”.

The tween_factory argument must be a dotted Python name to a global


object representing the tween factory.

The under and over arguments allow the caller of add_tween to pro-
vide a hint about where in the tween chain this tween factory should be
placed when an implicit tween chain is used. These hints are only used
when an explicit tween chain is not used (when the pyramid.tweens
configuration value is not set). Allowable values for under or over (or
both) are:
• None (the default).
• A dotted Python name to a tween factory: a string representing the dotted
name of a tween factory added in a call to add_tween in the same
configuration session.
• One of the constants pyramid.tweens.MAIN, pyramid.
tweens.INGRESS, or pyramid.tweens.EXCVIEW .
• An iterable of any combination of the above. This allows the user to spec-
ify fallbacks if the desired tween is not included, as well as compatibility
with multiple other tweens.
under means ’closer to the main Pyramid application than’, over means
’closer to the request ingress than’.

For example, calling add_tween('myapp.tfactory',


over=pyramid.tweens.MAIN) will attempt to place the tween
factory represented by the dotted name myapp.tfactory directly
’above’ (in ptweens order) the main Pyramid request handler. Likewise,
calling add_tween('myapp.tfactory', over=pyramid.
tweens.MAIN, under='mypkg.someothertween') will
attempt to place this tween factory ’above’ the main handler but ’below’
(a fictional) ’mypkg.someothertween’ tween factory.

If all options for under (or over) cannot be found in the current con-
figuration, it is an error. If some options are specified purely for com-
patibility with other tweens, just add a fallback of MAIN or INGRESS.
For example, under=('mypkg.someothertween', 'mypkg.
someothertween2', INGRESS). This constraint will require the
tween to be located under both the ’mypkg.someothertween’ tween, the
’mypkg.someothertween2’ tween, and INGRESS. If any of these is not in

772 CONTENTS
The Pyramid Web Framework, Version 2.0.2

the current configuration, this constraint will only organize itself based on
the tweens that are present.
Specifying neither over nor under is equivalent to specifying un-
der=INGRESS.
Implicit tween ordering is obviously only best-effort. Pyramid will attempt
to present an implicit order of tweens as best it can, but the only surefire way
to get any particular ordering is to use an explicit tween order. A user may
always override the implicit tween ordering by using an explicit pyramid.
tweens configuration value setting.
under, and over arguments are ignored when an explicit tween chain is
specified using the pyramid.tweens configuration value.
For more information, see Registering Tweens.
add_route_predicate(name, factory, weighs_more_than=None,
weighs_less_than=None)
Adds a route predicate factory. The view predicate can later be named
as a keyword argument to pyramid.config.Configurator.
add_route().
name should be the name of the predicate. It must be a valid Python iden-
tifier (it will be used as a keyword argument to add_route).
factory should be a predicate factory or dotted Python name which
refers to a predicate factory.
See View and Route Predicates for more information.
New in version 1.4.
add_subscriber_predicate(name, factory,
weighs_more_than=None,
weighs_less_than=None)
New in version 1.4.
Adds a subscriber predicate factory. The associated subscriber pred-
icate can later be named as a keyword argument to pyramid.
config.Configurator.add_subscriber() in the **predi-
cates anonymous keyword argument dictionary.
name should be the name of the predicate. It must be a valid Python
identifier (it will be used as a **predicates keyword argument to
add_subscriber()).
factory should be a predicate factory or dotted Python name which
refers to a predicate factory.
See Subscriber Predicates for more information.

0.4. API Documentation 773


The Pyramid Web Framework, Version 2.0.2

add_view_predicate(name, factory, weighs_more_than=None,


weighs_less_than=None)
New in version 1.4.
Adds a view predicate factory. The associated view predicate can
later be named as a keyword argument to pyramid.config.
Configurator.add_view() in the predicates anonyous key-
word argument dictionary.
name should be the name of the predicate. It must be a valid Python iden-
tifier (it will be used as a keyword argument to add_view by others).
factory should be a predicate factory or dotted Python name which
refers to a predicate factory.
See View and Route Predicates for more information.
add_view_deriver(deriver, name=None, under=None, over=None)
New in version 1.7.
Add a view deriver to the view pipeline. View derivers are a feature used
by extension authors to wrap views in custom code controllable by view-
specific options.
deriver should be a callable conforming to the pyramid.
interfaces.IViewDeriver interface.
name should be the name of the view deriver. There are no restrictions on
the name of a view deriver. If left unspecified, the name will be constructed
from the name of the deriver.
The under and over options can be used to control the ordering of view
derivers by providing hints about where in the view pipeline the deriver is
used. Each option may be a string or a list of strings. At least one view
deriver in each, the over and under directions, must exist to fully satisfy the
constraints.
under means closer to the user-defined view callable, and over means
closer to view pipeline ingress.
The default value for over is rendered_view and under is deco-
rated_view. This places the deriver somewhere between the two in the
view pipeline. If the deriver should be placed elsewhere in the pipeline,
such as above decorated_view, then you MUST also specify under
to something earlier in the order, or a CyclicDependencyError will
be raised when trying to sort the derivers.
See View Derivers for more information.

774 CONTENTS
The Pyramid Web Framework, Version 2.0.2

set_execution_policy(policy)
Override the Pyramid execution policy in the current configuration. The
policy argument must be an instance of an pyramid.interfaces.
IExecutionPolicy or a dotted Python name that points at an instance
of an execution policy.

set_request_factory(factory)
The object passed as factory should be an object (or a dotted Python
name which refers to an object) which will be used by the Pyramid router to
create all request objects. This factory object must have the same methods
and attributes as the pyramid.request.Request class (particularly
__call__, and blank).

See pyramid.config.Configurator.
add_request_method() for a less intrusive way to extend the
request objects with custom methods and properties.

Using the request_factory argument to the pyramid.


config.Configurator constructor can be used to achieve the same
purpose.

set_root_factory(factory)
Add a root factory to the current configuration state. If the factory ar-
gument is None a default root factory will be registered.

Using the root_factory argument to the pyramid.config.


Configurator constructor can be used to achieve the same purpose.

set_session_factory(factory)
Configure the application with a session factory. If this method is called,
the factory argument must be a session factory callable or a dotted
Python name to that factory.

Using the session_factory argument to the pyramid.


config.Configurator constructor can be used to achieve the same
purpose.

0.4. API Documentation 775


The Pyramid Web Framework, Version 2.0.2

set_view_mapper(mapper)
Setting a view mapper makes it possible to make use of view callable ob-
jects which implement different call signatures than the ones supported by
Pyramid as described in its narrative documentation.

The mapper argument should be an object implementing pyramid.


interfaces.IViewMapperFactory or a dotted Python name to
such an object. The provided mapper will become the default view map-
per to be used by all subsequent view configuration registrations.

See also:

See also Using a View Mapper.

Using the default_view_mapper argument to the pyramid.


config.Configurator constructor can be used to achieve the same
purpose.

Extension Author APIs

action(discriminator, callable=None, args=(), kw=None, order=0,


introspectables=(), **extra)
Register an action which will be executed when pyramid.config.
Configurator.commit() is called (or executed immediately if au-
tocommit is True).

This method is typically only used by Pyramid framework exten-


sion authors, not by Pyramid application developers.

The discriminator uniquely identifies the action. It must be given,


but it can be None, to indicate that the action never conflicts. It must be a
hashable value.

The callable is a callable object which performs the task associated


with the action when the action is executed. It is optional.

args and kw are tuple and dict objects respectively, which are passed to
callable when this action is executed. Both are optional.

776 CONTENTS
The Pyramid Web Framework, Version 2.0.2

order is a grouping mechanism; an action with a lower order will be exe-


cuted before an action with a higher order (has no effect when autocommit
is True).

introspectables is a sequence of introspectable objects (or the empty


sequence if no introspectable objects are associated with this action). If this
configurator’s introspection attribute is False, these introspecta-
bles will be ignored.

extra provides a facility for inserting extra keys and values into an action
dictionary.

add_directive(name, directive, action_wrap=True)


Add a directive method to the configurator.

This method is typically only used by Pyramid framework exten-


sion authors, not by Pyramid application developers.

Framework extenders can add directive methods to a con-


figurator by instructing their users to call config.
add_directive('somename', 'some.callable'). This
will make some.callable accessible as config.somename.
some.callable should be a function which accepts config as a
first argument, and arbitrary positional and keyword arguments following.
It should use config.action as necessary to perform actions. Directive
methods can then be invoked like ’built-in’ directives such as add_view,
add_route, etc.

The action_wrap argument should be True for directives which per-


form config.action with potentially conflicting discriminators. ac-
tion_wrap will cause the directive to be wrapped in a decorator which
provides more accurate conflict cause information.

add_directive does not participate in conflict detection, and later calls


to add_directive will override earlier calls.

with_package(package)
Return a new Configurator instance with the same registry as this configura-
tor. package may be an actual Python package object or a dotted Python
name representing a package.

0.4. API Documentation 777


The Pyramid Web Framework, Version 2.0.2

derive_view(view, attr=None, renderer=None)


Create a view callable using the function, instance, or class (or dotted
Python name referring to the same) provided as view object.

This method is typically only used by Pyramid framework exten-


sion authors, not by Pyramid application developers.

This is API is useful to framework extenders who create pluggable systems


which need to register ’proxy’ view callables for functions, instances, or
classes which meet the requirements of being a Pyramid view callable. For
example, a some_other_framework function in another framework
may want to allow a user to supply a view callable, but he may want to wrap
the view callable in his own before registering the wrapper as a Pyramid
view callable. Because a Pyramid view callable can be any of a number of
valid objects, the framework extender will not know how to call the user-
supplied object. Running it through derive_view normalizes it to a
callable which accepts two arguments: context and request.

For example:

def some_other_framework(user_supplied_view):
config = Configurator(reg)
proxy_view = config.derive_view(user_supplied_
,→view)

def my_wrapper(context, request):


do_something_that_mutates(request)
return proxy_view(context, request)
config.add_view(my_wrapper)

The view object provided should be one of the following:


• A function or another non-class callable object that accepts a request as
a single positional argument and which returns a response object.
• A function or other non-class callable object that accepts two positional
arguments, context, request and which returns a response object.
• A class which accepts a single positional argument in its constructor
named request, and which has a __call__ method that accepts no
arguments that returns a response object.
• A class which accepts two positional arguments named context,
request, and which has a __call__ method that accepts no argu-
ments that returns a response object.

778 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• A dotted Python name which refers to any of the kinds of objects above.
This API returns a callable which accepts the arguments context, re-
quest and which returns the result of calling the provided view object.

The attr keyword argument is most useful when the view object is a class.
It names the method that should be used as the callable. If attr is not
provided, the attribute effectively defaults to __call__. See Defining a
View Callable as a Class for more information.

The renderer keyword argument should be a renderer name. If supplied,


it will cause the returned callable to use a renderer to convert the user-
supplied view result to a response object. If a renderer argument is not
supplied, the user-supplied view must itself return a response object.

Utility Methods

absolute_asset_spec(relative_spec)
Resolve the potentially relative asset specification string passed as rel-
ative_spec into an absolute asset specification string and return the
string. Use the package of this configurator as the package to which the
asset specification will be considered relative when generating an absolute
asset specification. If the provided relative_spec argument is already
absolute, or if the relative_spec is not a string, it is simply returned.

maybe_dotted(dotted)
Resolve the dotted Python name dotted to a global Python object. If
dotted is not a string, return it without attempting to do any name res-
olution. If dotted is a relative dotted name (e.g. .foo.bar, consider
it relative to the package argument supplied to this Configurator’s con-
structor.

ZCA-Related APIs

hook_zca()
Call zope.component.getSiteManager.sethook() with the
argument pyramid.threadlocal.get_current_registry,
causing the Zope Component Architecture ’global’ APIs such as
zope.component.getSiteManager(), zope.component.
getAdapter() and others to use the Pyramid application registry
rather than the Zope ’global’ registry.

0.4. API Documentation 779


The Pyramid Web Framework, Version 2.0.2

unhook_zca()
Call zope.component.getSiteManager.reset() to undo the
action of pyramid.config.Configurator.hook_zca().

setup_registry(settings=None, root_factory=None,
security_policy=None, authentication_policy=None,
authorization_policy=None, renderers=None,
debug_logger=None, locale_negotiator=None,
request_factory=None, response_factory=None,
default_permission=None, session_factory=None,
default_view_mapper=None,
exceptionresponse_view=<function
default_exceptionresponse_view>)
When you pass a non-None registry argument to the Configurator
constructor, no initial setup is performed against the registry. This is be-
cause the registry you pass in may have already been initialized for use
under Pyramid via a different configurator. However, in some circum-
stances (such as when you want to use a global registry instead of a reg-
istry created as a result of the Configurator constructor), or when you want
to reset the initial setup of a registry, you do want to explicitly initialize
the registry associated with a Configurator for use under Pyramid. Use
setup_registry to do this initialization.

setup_registry configures settings, a root factory, security policies,


renderers, a debug logger, a locale negotiator, and various other settings
using the configurator’s current registry, as per the descriptions in the Con-
figurator constructor.

Testing Helper APIs

testing_add_renderer(path, renderer=None)
Unit/integration testing helper: register a renderer at path (usually a rela-
tive filename ala templates/foo.pt or an asset specification) and re-
turn the renderer object. If the renderer argument is None, a ’dummy’
renderer will be used. This function is useful when testing code that
calls the pyramid.renderers.render() function or pyramid.
renderers.render_to_response() function or any other ren-
der_* or get_* API of the pyramid.renderers module.

Note that calling this method for with a path argument representing a ren-
derer factory type (e.g. for foo.pt usually implies the chameleon_zpt
renderer factory) clobbers any existing renderer factory registered for that
type.

780 CONTENTS
The Pyramid Web Framework, Version 2.0.2

This method is also available under the alias test-


ing_add_template (an older name for it).

testing_add_subscriber(event_iface=None)
Unit/integration testing helper: Registers a subscriber which listens for
events of the type event_iface. This method returns a list object which
is appended to by the subscriber whenever an event is captured.

When an event is dispatched that matches the value implied by the


event_iface argument, that event will be appended to the list.
You can then compare the values in the list to expected event no-
tifications. This method is useful when testing code that wants
to call pyramid.registry.Registry.notify(), or zope.
component.event.dispatch().

The default value of event_iface (None) implies a subscriber regis-


tered for any kind of event.

testing_resources(resources)
Unit/integration testing helper: registers a dictionary of resource
objects that can be resolved via the pyramid.traversal.
find_resource() API.

The pyramid.traversal.find_resource() API is called with a


path as one of its arguments. If the dictionary you register when calling
this method contains that path as a string key (e.g. /foo/bar or foo/
bar), the corresponding value will be returned to find_resource (and
thus to your code) when pyramid.traversal.find_resource()
is called with an equivalent path string or tuple.

testing_securitypolicy(userid=None, identity=None,
permissive=True, remember_result=None,
forget_result=None)
Unit/integration testing helper. Registers a faux security policy.

This function is most useful when testing code that uses the secu-
rity APIs, such as pyramid.request.Request.identity(),
pyramid.request.Request.authenticated_userid, or
pyramid.request.Request.has_permission(),

The behavior of the registered security policy depends on the arguments


passed to this method.

0.4. API Documentation 781


The Pyramid Web Framework, Version 2.0.2

Parameters
• userid (str) -- If provided, the policy’s au-
thenticated_userid method will return this
value. As a result, pyramid.request.Request.
authenticated_userid will have this value as well.
• identity (object) -- If provided, the policy’s iden-
tity method will return this value. As a result, pyramid.
request.Request.identity` will have this value.
• permissive (bool) -- If true, the policy will allow access to
any user for any permission. If false, the policy will deny all
access.
• remember_result (list) -- If provided, the policy’s re-
member method will return this value. Otherwise, remember
will return an empty list.
• forget_result (list) -- If provided, the policy’s forget
method will return this value. Otherwise, forget will return
an empty list.
New in version 1.4: The remember_result argument.

New in version 1.4: The forget_result argument.

Changed in version 2.0: Removed groupids argument and add identity


argument.

Attributes

introspectable
A shortcut attribute which points to the pyramid.registry.
Introspectable class (used during directives to provide introspec-
tion to actions).

New in version 1.3.

introspector
The introspector related to this configuration. It is an instance imple-
menting the pyramid.interfaces.IIntrospector interface.

New in version 1.3.

registry
The application registry which holds the configuration associated with
this configurator.

782 CONTENTS
The Pyramid Web Framework, Version 2.0.2

global_registries
The set of registries that have been created for Pyramid applications, one for each call to pyramid.
config.Configurator.make_wsgi_app() in the current process. The object itself sup-
ports iteration and has a last property containing the last registry loaded.
The registries contained in this object are stored as weakrefs, thus they will only exist for the lifetime
of the actual applications for which they are being used.

class not_(value)
You can invert the meaning of any predicate value by wrapping it in a call to pyramid.config.
not_.

1 from pyramid.config import not_


2

3 config.add_view(
4 'mypackage.views.my_view',
5 route_name='ok',
6 request_method=not_('POST')
7 )

The above example will ensure that the view is called if the request method is not POST, at least if
no other view is more specific.
This technique of wrapping a predicate value in not_ can be used anywhere predicate values are
accepted:
• pyramid.config.Configurator.add_view()
• pyramid.config.Configurator.add_route()
• pyramid.config.Configurator.add_subscriber()
• pyramid.view.view_config()
• pyramid.events.subscriber()
New in version 1.5.

PHASE0_CONFIG

PHASE1_CONFIG

PHASE2_CONFIG

PHASE3_CONFIG

0.4. API Documentation 783


The Pyramid Web Framework, Version 2.0.2

pyramid.csrf

class LegacySessionCSRFStoragePolicy
A CSRF storage policy that defers control of CSRF storage to the session.
This policy maintains compatibility with legacy ISession implementations that know how
to manage CSRF tokens themselves via ISession.new_csrf_token and ISession.
get_csrf_token.
Note that using this CSRF implementation requires that a session factory is configured.
New in version 1.9.
check_csrf_token(request, supplied_token)
Returns True if the supplied_token is valid.
get_csrf_token(request)
Returns the currently active CSRF token from the session, generating a new one if needed.
new_csrf_token(request)
Sets a new CSRF token into the session and returns it.
class SessionCSRFStoragePolicy(key=’_csrft_’)
A CSRF storage policy that persists the CSRF token in the session.
Note that using this CSRF implementation requires that a session factory is configured.
key
The session key where the CSRF token will be stored. Default: _csrft_.
New in version 1.9.
check_csrf_token(request, supplied_token)
Returns True if the supplied_token is valid.
get_csrf_token(request)
Returns the currently active CSRF token from the session, generating a new one if needed.
new_csrf_token(request)
Sets a new CSRF token into the session and returns it.
class CookieCSRFStoragePolicy(cookie_name=’csrf_token’, secure=False, httponly=False,
domain=None, max_age=None, path=’/’, samesite=’Lax’)
An alternative CSRF implementation that stores its information in unauthenticated cookies, known
as the ’Double Submit Cookie’ method in the OWASP CSRF guidelines. This gives some additional
flexibility with regards to scaling as the tokens can be generated and verified by a front-end server.
New in version 1.9.

784 CONTENTS
The Pyramid Web Framework, Version 2.0.2

check_csrf_token(request, supplied_token)
Returns True if the supplied_token is valid.
get_csrf_token(request)
Returns the currently active CSRF token by checking the cookies sent with the current request.
new_csrf_token(request)
Sets a new CSRF token into the request and returns it.

get_csrf_token(request)
Get the currently active CSRF token for the request passed, generating a new one using
new_csrf_token(request) if one does not exist. This calls the equivalent method in the
chosen CSRF protection implementation.
New in version 1.9.

new_csrf_token(request)
Generate a new CSRF token for the request passed and persist it in an implementation defined man-
ner. This calls the equivalent method in the chosen CSRF protection implementation.
New in version 1.9.

check_csrf_origin(request, *, trusted_origins=None, allow_no_origin=False, raises=True)


Check the Origin of the request to see if it is a cross site request or not.
If the value supplied by the Origin or Referer header isn’t one of the trusted origins and
raises is True, this function will raise a pyramid.exceptions.BadCSRFOrigin excep-
tion, but if raises is False, this function will return False instead. If the CSRF origin checks
are successful this function will return True unconditionally.
Additional trusted origins may be added by passing a list of domain (and ports if non-standard
like ['example.com', 'dev.example.com:8080']) in with the trusted_origins
parameter. If trusted_origins is None (the default) this list of additional domains will be
pulled from the pyramid.csrf_trusted_origins setting.
allow_no_origin determines whether to return True when the origin cannot be determined
via either the Referer or Origin header. The default is False which will reject the check.
Note that this function will do nothing if request.scheme is not https.
New in version 1.7.
Changed in version 1.9: Moved from pyramid.session to pyramid.csrf
Changed in version 2.0: Added the allow_no_origin option.

0.4. API Documentation 785


The Pyramid Web Framework, Version 2.0.2

check_csrf_token(request, token=’csrf_token’, header=’X-CSRF-Token’, raises=True)


Check the CSRF token returned by the pyramid.interfaces.ICSRFStoragePolicy
implementation against the value in request.POST.get(token) (if a POST request) or
request.headers.get(header). If a token keyword is not supplied to this function, the
string csrf_token will be used to look up the token in request.POST. If a header keyword
is not supplied to this function, the string X-CSRF-Token will be used to look up the token in
request.headers.
If the value supplied by post or by header cannot be verified by the pyramid.interfaces.
ICSRFStoragePolicy, and raises is True, this function will raise an pyramid.
exceptions.BadCSRFToken exception. If the values differ and raises is False, this func-
tion will return False. If the CSRF check is successful, this function will return True uncondi-
tionally.
See Checking CSRF Tokens Automatically for information about how to secure your application
automatically against CSRF attacks.
New in version 1.4a2.
Changed in version 1.7a1: A CSRF token passed in the query string of the request is no longer
considered valid. It must be passed in either the request body or a header.
Changed in version 1.9: Moved from pyramid.session to pyramid.csrf and updated to use
the configured pyramid.interfaces.ICSRFStoragePolicy to verify the CSRF token.

pyramid.decorator

reify(wrapped)
Use as a class method decorator. It operates almost exactly like the Python @property decorator,
but it puts the result of the method it decorates into the instance dict after the first call, effectively
replacing the function it decorates with an instance variable. It is, in Python parlance, a non-data
descriptor. The following is an example and its usage:

>>> from pyramid.decorator import reify

>>> class Foo:


... @reify
... def jammy(self):
... print('jammy called')
... return 1

>>> f = Foo()
>>> v = f.jammy
jammy called
(continues on next page)

786 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


>>> print(v)
1
>>> f.jammy
1
>>> # jammy func not called the second time; it replaced itself with 1
>>> # Note: reassignment is possible
>>> f.jammy = 2
>>> f.jammy
2

pyramid.events

Functions

subscriber(*ifaces, **predicates)
Decorator activated via a scan which treats the function being decorated as an event subscriber for
the set of interfaces passed as *ifaces and the set of predicate terms passed as **predicates
to the decorator constructor.
For example:

from pyramid.events import NewRequest


from pyramid.events import subscriber

@subscriber(NewRequest)
def mysubscriber(event):
event.request.foo = 1

More than one event type can be passed as a constructor argument. The decorated subscriber will
be called for each event type.

from pyramid.events import NewRequest, NewResponse


from pyramid.events import subscriber

@subscriber(NewRequest, NewResponse)
def mysubscriber(event):
print(event)

When the subscriber decorator is used without passing an arguments, the function it decorates
is called for every event sent:

0.4. API Documentation 787


The Pyramid Web Framework, Version 2.0.2

from pyramid.events import subscriber

@subscriber()
def mysubscriber(event):
print(event)

This method will have no effect until a scan is performed against the package or module which
contains it, ala:

from pyramid.config import Configurator


config = Configurator()
config.scan('somepackage_containing_subscribers')

Any **predicate arguments will be passed along to pyramid.config.Configurator.


add_subscriber(). See Subscriber Predicates for a description of how predicates can narrow
the set of circumstances in which a subscriber will be called.
Two additional keyword arguments which will be passed to the venusian attach function are
_depth and _category.
_depth is provided for people who wish to reuse this class from another decorator. The default
value is 0 and should be specified relative to the subscriber invocation. It will be passed in to the
venusian attach function as the depth of the callstack when Venusian checks if the decorator is
being used in a class or module context. It’s not often used, but it can be useful in this circumstance.
_category sets the decorator category name. It can be useful in combination with the category
argument of scan to control which views should be processed.
See the venusian.attach() function in Venusian for more information about the _depth and
_category arguments.
Changed in version 1.9.1: Added the _depth and _category arguments.

Event Types

class ApplicationCreated(app)
An instance of this class is emitted as an event when the pyramid.config.Configurator.
make_wsgi_app() is called. The instance has an attribute, app, which is an instance of the
router that will handle WSGI requests. This class implements the pyramid.interfaces.
IApplicationCreated interface.

788 CONTENTS
The Pyramid Web Framework, Version 2.0.2

For backwards compatibility purposes, this class can also be imported as pyramid.
events.WSGIApplicationCreatedEvent. This was the name of the event class before
Pyramid 1.0.

class NewRequest(request)
An instance of this class is emitted as an event whenever Pyramid begins to process a new request.
The event instance has an attribute, request, which is a request object. This event class imple-
ments the pyramid.interfaces.INewRequest interface.

class ContextFound(request)
An instance of this class is emitted as an event after the Pyramid router finds a context object (after it
performs traversal) but before any view code is executed. The instance has an attribute, request,
which is the request object generated by Pyramid.
Notably, the request object will have an attribute named context, which is the context that will be
provided to the view which will eventually be called, as well as other attributes attached by context-
finding code.
This class implements the pyramid.interfaces.IContextFound interface.

As of Pyramid 1.0, for backwards compatibility purposes, this event may also be imported as
pyramid.events.AfterTraversal.

class BeforeTraversal(request)
An instance of this class is emitted as an event after the Pyramid router has attempted to find a route
object but before any traversal or view code is executed. The instance has an attribute, request,
which is the request object generated by Pyramid.
Notably, the request object may have an attribute named matched_route, which is the matched
route if found. If no route matched, this attribute is not available.
This class implements the pyramid.interfaces.IBeforeTraversal interface.

class NewResponse(request, response)


An instance of this class is emitted as an event whenever any Pyramid view or exception view returns
a response.
The instance has two attributes:request, which is the request which caused the response, and
response, which is the response object returned by a view or renderer.

0.4. API Documentation 789


The Pyramid Web Framework, Version 2.0.2

If the response was generated by an exception view, the request will have an attribute named
exception, which is the exception object which caused the exception view to be executed. If the
response was generated by a ’normal’ view, this attribute of the request will be None.
This event will not be generated if a response cannot be created due to an exception that is not caught
by an exception view (no response is created under this circumstace).
This class implements the pyramid.interfaces.INewResponse interface.

Postprocessing a response is usually better handled in a WSGI middleware component than


in subscriber code that is called by a pyramid.interfaces.INewResponse event. The
pyramid.interfaces.INewResponse event exists almost purely for symmetry with the
pyramid.interfaces.INewRequest event.

class BeforeRender(system, rendering_val=None)


Subscribers to this event may introspect and modify the set of renderer globals before they are passed
to a renderer. This event object itself has a dictionary-like interface that can be used for this purpose.
For example:

from pyramid.events import subscriber


from pyramid.events import BeforeRender

@subscriber(BeforeRender)
def add_global(event):
event['mykey'] = 'foo'

An object of this type is sent as an event just before a renderer is invoked.


If a subscriber adds a key via __setitem__ that already exists in the renderer globals dictio-
nary, it will overwrite the older value there. This can be problematic because event subscribers to
the BeforeRender event do not possess any relative ordering. For maximum interoperability with
other third-party subscribers, if you write an event subscriber meant to be used as a BeforeRender
subscriber, your subscriber code will need to ensure no value already exists in the renderer globals
dictionary before setting an overriding value (which can be done using .get or __contains__
of the event object).
The dictionary returned from the view is accessible through the rendering_val attribute of a
BeforeRender event.
Suppose you return {'mykey': 'somevalue', 'mykey2': 'somevalue2'} from
your view callable, like so:

790 CONTENTS
The Pyramid Web Framework, Version 2.0.2

from pyramid.view import view_config

@view_config(renderer='some_renderer')
def myview(request):
return {'mykey': 'somevalue', 'mykey2': 'somevalue2'}

rendering_val can be used to access these values from the BeforeRender object:

from pyramid.events import subscriber


from pyramid.events import BeforeRender

@subscriber(BeforeRender)
def read_return(event):
# {'mykey': 'somevalue'} is returned from the view
print(event.rendering_val['mykey'])

In other words, rendering_val is the (non-system) value returned by a view or passed to ren-
der* as value. This feature is new in Pyramid 1.2.
For a description of the values present in the renderer globals dictionary, see System Values Used
During Rendering.
See also:
See also pyramid.interfaces.IBeforeRender.
update(E, **F)
Update D from dict/iterable E and F. If E has a .keys() method, does: for k in E: D[k] = E[k]
If E lacks .keys() method, does: for (k, v) in E: D[k] = v. In either case, this is followed by:
for k in F: D[k] = F[k].
clear() → None. Remove all items from D.

copy() → a shallow copy of D

fromkeys(value=None, / )
Create a new dictionary with keys from iterable and values set to value.
get(key, default=None, / )
Return the value for key if key is in the dictionary, else default.
items() → a set-like object providing a view on D’s items

keys() → a set-like object providing a view on D’s keys

0.4. API Documentation 791


The Pyramid Web Framework, Version 2.0.2

pop(k [, d ]) → v, remove specified key and return the corresponding value.


If the key is not found, return the default if given; otherwise, raise a KeyError.
popitem()
Remove and return a (key, value) pair as a 2-tuple.
Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.
setdefault(key, default=None, / )
Insert key with a value of default if key is not in the dictionary.
Return the value for key if key is in the dictionary, else default.
values() → an object providing a view on D’s values

See Using Events for more information about how to register code which subscribes to these events.

pyramid.exceptions

exception BadCSRFOrigin(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
This exception indicates the request has failed cross-site request forgery origin validation.
exception BadCSRFToken(detail=None, headers=None, comment=None, body_template=None,
json_formatter=None, **kw)
This exception indicates the request has failed cross-site request forgery token validation.
exception PredicateMismatch(detail=None, headers=None, comment=None,
body_template=None, json_formatter=None, **kw)
This exception is raised by multiviews when no view matches all given predicates.
This exception subclasses the HTTPNotFound exception for a specific reason: if it reaches the main
exception handler, it should be treated as HTTPNotFound` by any exception view registrations.
Thus, typically, this exception will not be seen publicly.
However, this exception will be raised if the predicates of all views configured to handle another
exception context cannot be successfully matched. For instance, if a view is configured to han-
dle a context of HTTPForbidden and the configured with additional predicates, then Predi-
cateMismatch will be raised if:
• An original view callable has raised HTTPForbidden (thus invoking an exception view);
and
• The given request fails to match all predicates for said exception view associated with HTTP-
Forbidden.
The same applies to any type of exception being handled by an exception view.

792 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Forbidden
alias of HTTPForbidden

NotFound
alias of HTTPNotFound

exception ConfigurationError
Raised when inappropriate input values are supplied to an API method of a Configurator

exception URLDecodeError
This exception is raised when Pyramid cannot successfully decode a URL or a URL path segment.
This exception behaves just like the Python builtin UnicodeDecodeError. It is a subclass of
the builtin UnicodeDecodeError exception only for identity purposes, mostly so an exception
view can be registered when a URL cannot be decoded.

pyramid.httpexceptions

HTTP Exceptions

This module contains Pyramid HTTP exception classes. Each class relates to a single HTTP status code.
Each class is a subclass of the HTTPException. Each exception class is also a response object.

Each exception class has a status code according to RFC 2068 or RFC 7538: codes with 100-300 are not
really errors; 400s are client errors, and 500s are server errors.

Exception
HTTPException
HTTPSuccessful
• 200 - HTTPOk
• 201 - HTTPCreated
• 202 - HTTPAccepted
• 203 - HTTPNonAuthoritativeInformation
• 204 - HTTPNoContent
• 205 - HTTPResetContent
• 206 - HTTPPartialContent

0.4. API Documentation 793


The Pyramid Web Framework, Version 2.0.2

HTTPRedirection
• 300 - HTTPMultipleChoices
• 301 - HTTPMovedPermanently
• 302 - HTTPFound
• 303 - HTTPSeeOther
• 304 - HTTPNotModified
• 305 - HTTPUseProxy
• 307 - HTTPTemporaryRedirect
• 308 - HTTPPermanentRedirect
HTTPError
HTTPClientError
• 400 - HTTPBadRequest
• 401 - HTTPUnauthorized
• 402 - HTTPPaymentRequired
• 403 - HTTPForbidden
• 404 - HTTPNotFound
• 405 - HTTPMethodNotAllowed
• 406 - HTTPNotAcceptable
• 407 - HTTPProxyAuthenticationRequired
• 408 - HTTPRequestTimeout
• 409 - HTTPConflict
• 410 - HTTPGone
• 411 - HTTPLengthRequired
• 412 - HTTPPreconditionFailed
• 413 - HTTPRequestEntityTooLarge
• 414 - HTTPRequestURITooLong
• 415 - HTTPUnsupportedMediaType
• 416 - HTTPRequestRangeNotSatisfiable
• 417 - HTTPExpectationFailed

794 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• 418 - HTTPImATeapot
• 422 - HTTPUnprocessableEntity
• 423 - HTTPLocked
• 424 - HTTPFailedDependency
• 428 - HTTPPreconditionRequired
• 429 - HTTPTooManyRequests
• 431 - HTTPRequestHeaderFieldsTooLarge
HTTPServerError
• 500 - HTTPInternalServerError
• 501 - HTTPNotImplemented
• 502 - HTTPBadGateway
• 503 - HTTPServiceUnavailable
• 504 - HTTPGatewayTimeout
• 505 - HTTPVersionNotSupported
• 507 - HTTPInsufficientStorage

HTTP exceptions are also response objects, thus they accept most of the same parameters that can be
passed to a regular Response. Each HTTP exception also has the following attributes:

code
the HTTP status code for the exception
title
remainder of the status line (stuff after the code)
explanation
a plain-text explanation of the error message that is not subject to environment or header
substitutions; it is accessible in the template via ${explanation}
detail
a plain-text message customization that is not subject to environment or header substi-
tutions; accessible in the template via ${detail}
body_template
a String.template-format content fragment used for environment and header sub-
stitution; the default template includes both the explanation and further detail provided
in the message.

0.4. API Documentation 795


The Pyramid Web Framework, Version 2.0.2

Each HTTP exception accepts the following parameters, any others will be forwarded to its Response
superclass:

detail
a plain-text override of the default detail
headers
a list of (k,v) header pairs, or a dict, to be added to the response; use the con-
tent_type=’application/json’ kwarg and other similar kwargs to to change properties
of the response supported by the pyramid.response.Response superclass
comment
a plain-text additional information which is usually stripped/hidden for end-users
body_template
a string.Template object containing a content fragment in HTML that frames the
explanation and further detail
body
a string that will override the body_template and be used as the body of the re-
sponse.

Substitution of response headers into template values is always performed. Substitution of WSGI environ-
ment values is performed if a request is passed to the exception’s constructor.

The subclasses of _HTTPMove (HTTPMultipleChoices, HTTPMovedPermanently, HTTP-


Found, HTTPSeeOther, HTTPUseProxy, HTTPTemporaryRedirect, and :class: ~HTTPPer-
manentRedirect) are redirections that require a “Location‘ field. Reflecting this, these subclasses have
one additional keyword argument: location, which indicates the location to which to redirect.

status_map
A mapping of integer status code to HTTP exception class (eg. the integer ”401” maps to
pyramid.httpexceptions.HTTPUnauthorized). All mapped exception classes are chil-
dren of pyramid.httpexceptions,

exception_response(status_code, **kw)
Creates an HTTP exception based on a status code. Example:

raise exception_response(404) # raises an HTTPNotFound exception.

The values passed as kw are provided to the exception’s constructor.

exception HTTPException(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)

796 CONTENTS
The Pyramid Web Framework, Version 2.0.2

exception HTTPOk(detail=None, headers=None, comment=None, body_template=None,


json_formatter=None, **kw)
subclass of HTTPSuccessful
Indicates that the request has succeeded.
code: 200, title: OK

exception HTTPRedirection(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
base class for exceptions with status codes in the 300s (redirections)
This is an abstract base class for 3xx redirection. It indicates that further action needs to be taken
by the user agent in order to fulfill the request. It does not necessarily signal an error condition.

exception HTTPError(detail=None, headers=None, comment=None, body_template=None,


json_formatter=None, **kw)
base class for exceptions with status codes in the 400s and 500s
This is an exception which indicates that an error has occurred, and that any work in progress should
not be committed.

exception HTTPClientError(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
base class for the 400s, where the client is in error
This is an error condition in which the client is presumed to be in-error. This is an expected problem,
and thus is not considered a bug. A server-side traceback is not warranted. Unless specialized, this
is a ’400 Bad Request’

exception HTTPServerError(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
base class for the 500s, where the server is in-error
This is an error condition in which the server is presumed to be in-error. Unless specialized, this is
a ’500 Internal Server Error’.

exception HTTPCreated(detail=None, headers=None, comment=None, body_template=None,


json_formatter=None, **kw)
subclass of HTTPSuccessful
This indicates that request has been fulfilled and resulted in a new resource being created.
code: 201, title: Created

0.4. API Documentation 797


The Pyramid Web Framework, Version 2.0.2

exception HTTPAccepted(detail=None, headers=None, comment=None, body_template=None,


json_formatter=None, **kw)
subclass of HTTPSuccessful
This indicates that the request has been accepted for processing, but the processing has not been
completed.
code: 202, title: Accepted

exception HTTPNonAuthoritativeInformation(detail=None, headers=None,


comment=None, body_template=None,
json_formatter=None, **kw)
subclass of HTTPSuccessful
This indicates that the returned metainformation in the entity-header is not the definitive set as avail-
able from the origin server, but is gathered from a local or a third-party copy.
code: 203, title: Non-Authoritative Information

exception HTTPNoContent(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPSuccessful
This indicates that the server has fulfilled the request but does not need to return an entity-body, and
might want to return updated metainformation.
code: 204, title: No Content

exception HTTPResetContent(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPSuccessful
This indicates that the server has fulfilled the request and the user agent SHOULD reset the document
view which caused the request to be sent.
code: 205, title: Reset Content

exception HTTPPartialContent(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPSuccessful
This indicates that the server has fulfilled the partial GET request for the resource.
code: 206, title: Partial Content

798 CONTENTS
The Pyramid Web Framework, Version 2.0.2

exception HTTPMultipleChoices(location=”, detail=None, headers=None, comment=None,


body_template=None, **kw)
subclass of _HTTPMove
This indicates that the requested resource corresponds to any one of a set of representations, each
with its own specific location, and agent-driven negotiation information is being provided so that the
user can select a preferred representation and redirect its request to that location.
code: 300, title: Multiple Choices

exception HTTPMovedPermanently(location=”, detail=None, headers=None,


comment=None, body_template=None, **kw)
subclass of _HTTPMove
This indicates that the requested resource has been assigned a new permanent URI and any future
references to this resource SHOULD use one of the returned URIs.
code: 301, title: Moved Permanently

exception HTTPFound(location=”, detail=None, headers=None, comment=None,


body_template=None, **kw)
subclass of _HTTPMove
This indicates that the requested resource resides temporarily under a different URI.
code: 302, title: Found

exception HTTPSeeOther(location=”, detail=None, headers=None, comment=None,


body_template=None, **kw)
subclass of _HTTPMove
This indicates that the response to the request can be found under a different URI and SHOULD be
retrieved using a GET method on that resource.
code: 303, title: See Other

exception HTTPNotModified(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPRedirection
This indicates that if the client has performed a conditional GET request and access is allowed, but
the document has not been modified, the server SHOULD respond with this status code.
code: 304, title: Not Modified

0.4. API Documentation 799


The Pyramid Web Framework, Version 2.0.2

exception HTTPUseProxy(location=”, detail=None, headers=None, comment=None,


body_template=None, **kw)
subclass of _HTTPMove
This indicates that the requested resource MUST be accessed through the proxy given by the Location
field.
code: 305, title: Use Proxy

exception HTTPTemporaryRedirect(location=”, detail=None, headers=None,


comment=None, body_template=None, **kw)
subclass of _HTTPMove
This indicates that the requested resource resides temporarily under a different URI.
code: 307, title: Temporary Redirect

exception HTTPPermanentRedirect(location=”, detail=None, headers=None,


comment=None, body_template=None, **kw)
subclass of _HTTPMove
This indicates that the requested resource resides permanently under a different URI and that the
request method must not be changed.
code: 308, title: Permanent Redirect

exception HTTPBadRequest(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the body or headers failed validity checks, preventing the server from being able
to continue processing.
code: 400, title: Bad Request

exception HTTPUnauthorized(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the request requires user authentication.
code: 401, title: Unauthorized

exception HTTPPaymentRequired(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
code: 402, title: Payment Required

800 CONTENTS
The Pyramid Web Framework, Version 2.0.2

exception HTTPForbidden(detail=None, headers=None, comment=None,


body_template=None, result=None, **kw)
subclass of HTTPClientError
This indicates that the server understood the request, but is refusing to fulfill it.
code: 403, title: Forbidden
Raise this exception within view code to immediately return the forbidden view to the invoking
user. Usually this is a basic 403 page, but the forbidden view can be customized as necessary. See
Changing the Forbidden View. A Forbidden exception will be the context of a Forbidden
View.
This exception’s constructor treats two arguments specially. The first argument, detail, should
be a string. The value of this string will be used as the message attribute of the exception object.
The second special keyword argument, result is usually an instance of pyramid.security.
Denied or pyramid.authorization.ACLDenied each of which indicates a reason for the
forbidden error. However, result is also permitted to be just a plain boolean False object or
None. The result value will be used as the result attribute of the exception object. It defaults
to None.
The Forbidden View can use the attributes of a Forbidden exception as necessary to provide extended
information in an error report shown to a user.

exception HTTPNotFound(detail=None, headers=None, comment=None, body_template=None,


json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the server did not find anything matching the Request-URI.
code: 404, title: Not Found
Raise this exception within view code to immediately return the Not Found View to the invoking
user. Usually this is a basic 404 page, but the Not Found View can be customized as necessary. See
Changing the Not Found View.
This exception’s constructor accepts a detail argument (the first argument), which should be a
string. The value of this string will be available as the message attribute of this exception, for
availability to the Not Found View.

exception HTTPMethodNotAllowed(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the method specified in the Request-Line is not allowed for the resource identified
by the Request-URI.
code: 405, title: Method Not Allowed

0.4. API Documentation 801


The Pyramid Web Framework, Version 2.0.2

exception HTTPNotAcceptable(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates the resource identified by the request is only capable of generating response entities
which have content characteristics not acceptable according to the accept headers sent in the request.
code: 406, title: Not Acceptable

exception HTTPProxyAuthenticationRequired(detail=None, headers=None,


comment=None, body_template=None,
json_formatter=None, **kw)
subclass of HTTPClientError
This is similar to 401, but indicates that the client must first authenticate itself with the proxy.
code: 407, title: Proxy Authentication Required

exception HTTPRequestTimeout(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the client did not produce a request within the time that the server was prepared
to wait.
code: 408, title: Request Timeout

exception HTTPConflict(detail=None, headers=None, comment=None, body_template=None,


json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the request could not be completed due to a conflict with the current state of the
resource.
code: 409, title: Conflict

exception HTTPGone(detail=None, headers=None, comment=None, body_template=None,


json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the requested resource is no longer available at the server and no forwarding
address is known.
code: 410, title: Gone

802 CONTENTS
The Pyramid Web Framework, Version 2.0.2

exception HTTPLengthRequired(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the server refuses to accept the request without a defined Content-Length.
code: 411, title: Length Required

exception HTTPPreconditionFailed(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the precondition given in one or more of the request-header fields evaluated to
false when it was tested on the server.
code: 412, title: Precondition Failed

exception HTTPRequestEntityTooLarge(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None,
**kw)
subclass of HTTPClientError
This indicates that the server is refusing to process a request because the request entity is larger than
the server is willing or able to process.
code: 413, title: Request Entity Too Large

exception HTTPRequestURITooLong(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the server is refusing to service the request because the Request-URI is longer
than the server is willing to interpret.
code: 414, title: Request-URI Too Long

exception HTTPUnsupportedMediaType(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None,
**kw)
subclass of HTTPClientError
This indicates that the server is refusing to service the request because the entity of the request is in
a format not supported by the requested resource for the requested method.
code: 415, title: Unsupported Media Type

0.4. API Documentation 803


The Pyramid Web Framework, Version 2.0.2

exception HTTPRequestRangeNotSatisfiable(detail=None, headers=None,


comment=None, body_template=None,
json_formatter=None, **kw)
subclass of HTTPClientError
The server SHOULD return a response with this status code if a request included a Range request-
header field, and none of the range-specifier values in this field overlap the current extent of the
selected resource, and the request did not include an If-Range request-header field.
code: 416, title: Request Range Not Satisfiable
exception HTTPExpectationFailed(detail=None, headers=None, comment=None,
body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the expectation given in an Expect request-header field could not be met by this
server.
code: 417, title: Expectation Failed
exception HTTPUnprocessableEntity(detail=None, headers=None, comment=None,
body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the server is unable to process the contained instructions.
May be used to notify the client that their JSON/XML is well formed, but not correct for the current
request.
See RFC4918 section 11 for more information.
code: 422, title: Unprocessable Entity
exception HTTPLocked(detail=None, headers=None, comment=None, body_template=None,
json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the resource is locked.
code: 423, title: Locked
exception HTTPFailedDependency(detail=None, headers=None, comment=None,
body_template=None, json_formatter=None, **kw)
subclass of HTTPClientError
This indicates that the method could not be performed because the requested action depended on
another action and that action failed.
code: 424, title: Failed Dependency

804 CONTENTS
The Pyramid Web Framework, Version 2.0.2

exception HTTPInternalServerError(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPServerError
This indicates that the server encountered an unexpected condition which prevented it from fulfilling
the request.
code: 500, title: Internal Server Error

exception HTTPNotImplemented(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPServerError
This indicates that the server does not support the functionality required to fulfill the request.
code: 501, title: Not Implemented

exception HTTPBadGateway(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPServerError
This indicates that the server, while acting as a gateway or proxy, received an invalid response from
the upstream server it accessed in attempting to fulfill the request.
code: 502, title: Bad Gateway

exception HTTPServiceUnavailable(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPServerError
This indicates that the server is currently unable to handle the request due to a temporary overloading
or maintenance of the server.
code: 503, title: Service Unavailable

exception HTTPGatewayTimeout(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPServerError
This indicates that the server, while acting as a gateway or proxy, did not receive a timely response
from the upstream server specified by the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary
server (e.g. DNS) it needed to access in attempting to complete the request.
code: 504, title: Gateway Timeout

0.4. API Documentation 805


The Pyramid Web Framework, Version 2.0.2

exception HTTPVersionNotSupported(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPServerError
This indicates that the server does not support, or refuses to support, the HTTP protocol version that
was used in the request message.
code: 505, title: HTTP Version Not Supported

exception HTTPInsufficientStorage(detail=None, headers=None, comment=None,


body_template=None, json_formatter=None, **kw)
subclass of HTTPServerError
This indicates that the server does not have enough space to save the resource.
code: 507, title: Insufficient Storage

pyramid.i18n

class TranslationString(msgid, domain=None, default=None, mapping=None,


context=None)
The constructor for a translation string. A translation string is a Unicode-like object that has some
extra metadata.
This constructor accepts one required argument named msgid. msgid must be the message iden-
tifier for the translation string. It must be a unicode object or a str object encoded in the default
system encoding.
Optional keyword arguments to this object’s constructor include domain, default, and map-
ping.
domain represents the translation domain. By default, the translation domain is None, indicating
that this translation string is associated with the default translation domain (usually messages).
default represents an explicit default text for this translation string. Default text appears when
the translation string cannot be translated. Usually, the msgid of a translation string serves double
duty as its default text. However, using this option you can provide a different default text for this
translation string. This feature is useful when the default of a translation string is too complicated
or too long to be used as a message identifier. If default is provided, it must be a unicode
object or a str object encoded in the default system encoding (usually means ASCII). If default
is None (its default value), the msgid value used by this translation string will be assumed to be
the value of default.
mapping, if supplied, must be a dictionary-like object which represents the replacement values for
any translation string replacement marker instances found within the msgid (or default) value
of this translation string.

806 CONTENTS
The Pyramid Web Framework, Version 2.0.2

context represents the translation context. By default, the translation context is None.
After a translation string is constructed, it behaves like most other unicode objects; its msgid
value will be displayed when it is treated like a unicode object. Only when its ugettext method
is called will it be translated.
Its default value is available as the default attribute of the object, its translation domain is avail-
able as the domain attribute, and the mapping is available as the mapping attribute. The object
otherwise behaves much like a Unicode string.

TranslationStringFactory(factory_domain)
Create a factory which will generate translation strings without requiring that each call to the factory
be passed a domain value. A single argument is passed to this class’ constructor: domain. This
value will be used as the domain values of translationstring.TranslationString
objects generated by the __call__ of this class. The msgid, mapping, and default values
provided to the __call__ method of an instance of this class have the meaning as described by
the constructor of the translationstring.TranslationString

class Localizer(locale_name, translations)


An object providing translation and pluralizations related to the current request’s locale
name. A pyramid.i18n.Localizer object is created using the pyramid.i18n.
get_localizer() function.
locale_name
The locale name for this localizer (e.g. en or en_US).
pluralize(singular, plural, n, domain=None, mapping=None)
Return a string translation by using two message identifier objects as a singular/plural pair
and an n value representing the number that appears in the message using gettext plural forms
support. The singular and plural objects should be strings. There is no reason to use
translation string objects as arguments as all metadata is ignored.
n represents the number of elements. domain is the translation domain to use to do the
pluralization, and mapping is the interpolation mapping that should be used on the result.
If the domain is not supplied, a default domain is used (usually messages).
Example:

num = 1
translated = localizer.pluralize('Add ${num} item',
'Add ${num} items',
num,
mapping={'num':num})

0.4. API Documentation 807


The Pyramid Web Framework, Version 2.0.2

If using the gettext plural support, which is required for languages that have pluralisation rules
other than n != 1, the singular argument must be the message_id defined in the translation
file. The plural argument is not used in this case.
Example:

num = 1
translated = localizer.pluralize('item_plural',
'',
num,
mapping={'num':num})

translate(tstring, domain=None, mapping=None)


Translate a translation string to the current language and interpolate any replacement mark-
ers in the result. The translate method accepts three arguments: tstring (required),
domain (optional) and mapping (optional). When called, it will translate the tstring
translation string using the current locale. If the current locale could not be determined, the
result of interpolation of the default value is returned. The optional domain argument can be
used to specify or override the domain of the tstring (useful when tstring is a normal
string rather than a translation string). The optional mapping argument can specify or over-
ride the tstring interpolation mapping, useful when the tstring argument is a simple
string instead of a translation string.
Example:

from pyramid.i18n import TranslationString


ts = TranslationString('Add ${item}', domain='mypackage',
mapping={'item':'Item'})
translated = localizer.translate(ts)

Example:

translated = localizer.translate('Add ${item}', domain='mypackage


,→',

mapping={'item':'Item'})

get_localizer(request)
Deprecated since version 1.5: Use the pyramid.request.Request.localizer attribute
directly instead. Retrieve a pyramid.i18n.Localizer object corresponding to the current
request’s locale name.

negotiate_locale_name(request)
Negotiate and return the locale name associated with the current request.

808 CONTENTS
The Pyramid Web Framework, Version 2.0.2

get_locale_name(request)
Deprecated since version 1.5: Use pyramid.request.Request.locale_name directly in-
stead. Return the locale name associated with the current request.

default_locale_negotiator(request)
The default locale negotiator. Returns a locale name or None.
• First, the negotiator looks for the _LOCALE_ attribute of the request object (possibly set by
a view or a listener for an event). If the attribute exists and it is not None, its value will be
used.
• Then it looks for the request.params['_LOCALE_'] value.
• Then it looks for the request.cookies['_LOCALE_'] value.
• Finally, the negotiator returns None if the locale could not be determined via any of the pre-
vious checks (when a locale negotiator returns None, it signifies that the default locale name
should be used.)

make_localizer(current_locale_name, translation_directories)
Create a pyramid.i18n.Localizer object corresponding to the provided locale name from
the translations found in the list of translation directories.

See Internationalization and Localization for more information about using Pyramid internationalization
and localization services within an application.

pyramid.interfaces

Event-Related Interfaces

interface IApplicationCreated
Event issued when the pyramid.config.Configurator.
make_wsgi_app() method is called. See the documentation attached to
pyramid.events.ApplicationCreated for more information.

For backwards compatibility with Pyramid versions before


1.0, this interface can also be imported as pyramid.interfaces.
IWSGIApplicationCreatedEvent.

0.4. API Documentation 809


The Pyramid Web Framework, Version 2.0.2

app
Created application
interface INewRequest
An event type that is emitted whenever Pyramid begins to process a new request. See the
documentation attached to pyramid.events.NewRequest for more information.

request
The request object
interface IContextFound
An event type that is emitted after Pyramid finds a context object but before it calls any
view code. See the documentation attached to pyramid.events.ContextFound
for more information.

For backwards compatibility with versions of Pyramid before 1.0, this event
interface can also be imported as pyramid.interfaces.IAfterTraversal.

request
The request object
interface IBeforeTraversal
An event type that is emitted after Pyramid attempted to find a route but before it calls
any traversal or view code. See the documentation attached to pyramid.events.
Routefound for more information.
request
The request object
interface INewResponse
An event type that is emitted whenever any Pyramid view returns a response. See the
documentation attached to pyramid.events.NewResponse for more informa-
tion.
request
The request object
response
The response object
interface IBeforeRender
Extends: pyramid.interfaces.IDict

810 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Subscribers to this event may introspect and modify the set of renderer globals before
they are passed to a renderer. The event object itself provides a dictionary-like interface
for adding and removing renderer globals. The keys and values of the dictionary are
those globals. For example:

from repoze.events import subscriber


from pyramid.interfaces import IBeforeRender

@subscriber(IBeforeRender)
def add_global(event):
event['mykey'] = 'foo'

See also:
See also Using the Before Render Event.
rendering_val
The value returned by a view or passed to a render method for this rendering.
This feature is new in Pyramid 1.2.

Other Interfaces

interface ISecurityPolicy

authenticated_userid(request)
Return a userid string identifying the trusted and verified user, or None if unau-
thenticated.
If the result is None, then pyramid.request.Request.
is_authenticated will return False.
forget(request, **kw)
Return a set of headers suitable for ’forgetting’ the current user on subsequent
requests. An individual security policy and its consumers can decide on the com-
position and meaning of **kw.
identity(request)
Return the identity of the current user. The object can be of any shape, such as a
simple ID string or an ORM object.
permits(request, context, permission)
Return an instance of pyramid.security.Allowed if a user of the given
identity is allowed the permission in the current context, else return an
instance of pyramid.security.Denied.

0.4. API Documentation 811


The Pyramid Web Framework, Version 2.0.2

remember(request, userid, **kw)


Return a set of headers suitable for ’remembering’ the userid named userid
when set in a response. An individual security policy and its consumers can decide
on the composition and meaning of **kw.
interface IAuthenticationPolicy
An object representing a Pyramid authentication policy.
Deprecated since version 2.0: Authentication policies have been removed in favor of
security policies. See upgrading_auth_20 for more information.
authenticated_userid(request)
Return the authenticated userid or None if no authenticated userid can be found.
This method of the policy should ensure that a record exists in whatever persistent
store is used related to the user (the user should not have been deleted); if a record
associated with the current id does not exist in a persistent store, it should return
None.
effective_principals(request)
Return a sequence representing the effective principals typically including the
userid and any groups belonged to by the current user, always including ’system’
groups such as pyramid.authorization.Everyone and pyramid.
authorization.Authenticated.
forget(request)
Return a set of headers suitable for ’forgetting’ the current user on subsequent
requests.
remember(request, userid, **kw)
Return a set of headers suitable for ’remembering’ the userid named userid
when set in a response. An individual authentication policy and its consumers
can decide on the composition and meaning of **kw.
unauthenticated_userid(request)
Return the unauthenticated userid. This method performs the same duty as au-
thenticated_userid but is permitted to return the userid based only on data
present in the request; it needn’t (and shouldn’t) check any persistent store to en-
sure that the user record related to the request userid exists.
This method is intended primarily a helper to assist the authenti-
cated_userid method in pulling credentials out of the request data, abstract-
ing away the specific headers, query strings, etc that are used to authenticate the
request.
interface IAuthorizationPolicy
An object representing a Pyramid authorization policy.

812 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Deprecated since version 2.0: Authentication policies have been removed in favor of
security policies. See upgrading_auth_20 for more information.
permits(context, principals, permission)
Return an instance of pyramid.security.Allowed if any of the prin-
cipals is allowed the permission in the current context, else return an
instance of pyramid.security.Denied.
principals_allowed_by_permission(context, permission)
Return a set of principal identifiers allowed by the permission in con-
text. This behavior is optional; if you choose to not implement it you
should define this method as something which raises a NotImplemented-
Error. This method will only be called when the pyramid.security.
principals_allowed_by_permission API is used.
interface IExceptionResponse
Extends: pyramid.interfaces.IException, pyramid.interfaces.
IResponse
An interface representing a WSGI response which is also an exception object. Regis-
ter an exception view using this interface as a context to apply the registered view
for all exception types raised by Pyramid internally (any exception that inherits from
pyramid.response.Response, including pyramid.httpexceptions.
HTTPNotFound and pyramid.httpexceptions.HTTPForbidden).
prepare(environ)
Prepares the response for being called as a WSGI application
interface IRoute
Interface representing the type of object returned from IRoutesMapper.
get_route
factory
The root factory used by the Pyramid router when this route matches (or None)
generate(kw)
Generate a URL based on filling in the dynamic segment markers in the pattern
using the kw dictionary provided.
match(path)
If the path passed to this function can be matched by the pattern of this route,
return a dictionary (the ’matchdict’), which will contain keys representing the dy-
namic segment markers in the pattern mapped to values extracted from the pro-
vided path.
If the path passed to this function cannot be matched by the pattern of this
route, return None.

0.4. API Documentation 813


The Pyramid Web Framework, Version 2.0.2

name
The route name
pattern
The route pattern
predicates
A sequence of route predicate objects used to determine if a request matches this
route or not after basic pattern matching has been completed.
pregenerator
This attribute should either be None or a callable object implementing the
IRoutePregenerator interface
interface IRoutePregenerator

__call__(request, elements, kw)


A pregenerator is a function associated by a developer with a route. The pregener-
ator for a route is called by pyramid.request.Request.route_url()
in order to adjust the set of arguments passed to it by the user for special pur-
poses, such as Pylons ’subdomain’ support. It will influence the URL returned
by route_url.
A pregenerator should return a two-tuple of (elements, kw) after examin-
ing the originals passed to this function, which are the arguments (request,
elements, kw). The simplest pregenerator is:

def pregenerator(request, elements, kw):


return elements, kw

You can employ a pregenerator by passing a pregenerator argument to the


pyramid.config.Configurator.add_route() function.
interface ICSRFStoragePolicy
An object that offers the ability to verify CSRF tokens and generate new ones.
check_csrf_token(request, token)
Determine if the supplied token is valid. Most implementations should simply
compare the token to the current value of get_csrf_token but it is possible
to verify the token using any mechanism necessary using this method.
Returns True if the token is valid, otherwise False.
get_csrf_token(request)
Return a cross-site request forgery protection token. It will be an ascii-
compatible unicode string. If a token was previously set for this user via

814 CONTENTS
The Pyramid Web Framework, Version 2.0.2

new_csrf_token, that token will be returned. If no CSRF token was pre-


viously set, new_csrf_token will be called, which will create and set a token,
and this token will be returned.
new_csrf_token(request)
Create and return a new, random cross-site request forgery protection token. The
token will be an ascii-compatible unicode string.
interface ISession
Extends: pyramid.interfaces.IDict
An interface representing a session (a web session object, usually accessed via
request.session.
Keys and values of a session must be JSON-serializable.

In Pyramid 2.0 the session was changed to only be required to support types
that can be serialized using JSON. It’s recommended to switch any session imple-
mentations to support only JSON and to only store primitive types in sessions. See
upgrading_session_20 for more information about why this change was made.

Changed in version 1.9: Sessions are no longer required to implement


get_csrf_token and new_csrf_token. CSRF token support was moved
to the pluggable pyramid.interfaces.ICSRFStoragePolicy configuration
hook.
Changed in version 2.0: Sessions now need to be JSON-serializable. This is more strict
than the previous requirement of pickleable objects.
changed()
Mark the session as changed. A user of a session should call this method after he or
she mutates a mutable object that is a value of the session (it should not be required
after mutating the session itself). For example, if the user has stored a dictionary
in the session under the key foo, and he or she does session['foo'] =
{}, changed() needn’t be called. However, if subsequently he or she does
session['foo']['a'] = 1, changed() must be called for the sessioning
machinery to notice the mutation of the internal dictionary.
created
Integer representing Epoch time when created.
flash(msg, queue=”, allow_duplicate=True)
Push a flash message onto the end of the flash queue represented by queue. An
alternate flash message queue can used by passing an optional queue, which

0.4. API Documentation 815


The Pyramid Web Framework, Version 2.0.2

must be a string. If allow_duplicate is false, if the msg already exists in the


queue, it will not be re-added.
invalidate()
Invalidate the session. The action caused by invalidate is implementation-
dependent, but it should have the effect of completely dissociating any data stored
in the session with the current request. It might set response values (such as one
which clears a cookie), or it might not.
An invalidated session may be used after the call to invalidate with the effect
that a new session is created to store the data. This enables workflows requiring an
entirely new session, such as in the case of changing privilege levels or preventing
fixation attacks.
new
Boolean attribute. If True, the session is new.
peek_flash(queue=”)
Peek at a queue in the flash storage. The queue remains in flash storage after this
message is called. The queue is returned; it is a list of flash messages added by
pyramid.interfaces.ISession.flash()
pop_flash(queue=”)
Pop a queue from the flash storage. The queue is removed from flash storage after
this message is called. The queue is returned; it is a list of flash messages added
by pyramid.interfaces.ISession.flash()
interface ISessionFactory
An interface representing a factory which accepts a request object and returns an ISes-
sion object
__call__(request)
Return an ISession object
interface IRendererInfo
An object implementing this interface is passed to every renderer factory constructor
as its only argument (conventionally named info)
clone()
Return a shallow copy that does not share any mutable state.
name
The value passed by the user as the renderer name
package
The ”current package” when the renderer configuration statement was found

816 CONTENTS
The Pyramid Web Framework, Version 2.0.2

registry
The ”current” application registry when the renderer was created
settings
The deployment settings dictionary related to the current application
type
The renderer type name
interface IRendererFactory

__call__(info)
Return an object that implements pyramid.interfaces.IRenderer.
info is an object that implements pyramid.interfaces.
IRendererInfo.
interface IRenderer

__call__(value, system)
Call the renderer with the result of the view (value) passed in and return a result
(a string or unicode object useful as a response body). Values computed by the
system are passed by the system in the system parameter, which is a dictionary.
Keys in the dictionary include: view (the view callable that returned the value),
renderer_name (the template name or simple name of the renderer), con-
text (the context object passed to the view), and request (the request object
passed to the view).
interface IRequestFactory
A utility which generates a request
__call__(environ)
Return an instance of pyramid.request.Request
blank(path)
Return an empty request object (see pyramid.request.Request.
blank())
interface IResponseFactory
A utility which generates a response
__call__(request)
Return a response object implementing IResponse, e.g. pyramid.response.
Response). It should handle the case when request is None.
interface IRouter
WSGI application which routes requests to ’view’ code based on a view registry.

0.4. API Documentation 817


The Pyramid Web Framework, Version 2.0.2

invoke_request(request)
Invoke the Pyramid request pipeline.
See Request Processing for information on the request pipeline.
The output should be a pyramid.interfaces.IResponse object or a
raised exception.
registry
Component architecture registry local to this application.
request_context(environ)
Create a new request context from a WSGI environ.
The request context is used to push/pop the threadlocals required when process-
ing the request. It also contains an initialized pyramid.interfaces.
IRequest instance using the registered pyramid.interfaces.
IRequestFactory. The context may be used as a context manager to
control the threadlocal lifecycle:

with router.request_context(environ) as request:


...

Alternatively, the context may be used without the with statement by manually
invoking its begin() and end() methods.

ctx = router.request_context(environ)
request = ctx.begin()
try:
...
finally:
ctx.end()

interface IViewMapperFactory

__call__(self , **kw)
Return an object which implements pyramid.interfaces.
IViewMapper. kw will be a dictionary containing view-specific arguments,
such as permission, predicates, attr, renderer, and other items.
An IViewMapperFactory is used by pyramid.config.Configurator.
add_view() to provide a plugpoint to extension developers who want to
modify potential view callable invocation signatures and response values.
interface IViewMapper

818 CONTENTS
The Pyramid Web Framework, Version 2.0.2

__call__(self , object)
Provided with an arbitrary object (a function, class, or instance), returns a callable
with the call signature (context, request). The callable returned should
itself return a Response object. An IViewMapper is returned by pyramid.
interfaces.IViewMapperFactory.
interface IDict

__contains__(k)
Return True if key k exists in the dictionary.
__delitem__(k)
Delete an item from the dictionary which is passed to the renderer as the renderer
globals dictionary.
__getitem__(k)
Return the value for key k from the dictionary or raise a KeyError if the key doesn’t
exist
__iter__()
Return an iterator over the keys of this dictionary
__setitem__(k, value)
Set a key/value pair into the dictionary
clear()
Clear all values from the dictionary
get(k, default=None)
Return the value for key k from the renderer dictionary, or the default if no such
value exists.
items()
Return a list of [(k,v)] pairs from the dictionary
keys()
Return a list of keys from the dictionary
pop(k, default=None)
Pop the key k from the dictionary and return its value. If k doesn’t exist, and default
is provided, return the default. If k doesn’t exist and default is not provided, raise
a KeyError.
popitem()
Pop the item with key k from the dictionary and return it as a two-tuple (k, v). If
k doesn’t exist, raise a KeyError.

0.4. API Documentation 819


The Pyramid Web Framework, Version 2.0.2

setdefault(k, default=None)
Return the existing value for key k in the dictionary. If no value with k exists
in the dictionary, set the default value into the dictionary under the k name
passed. If a value already existed in the dictionary, return it. If a value did not
exist in the dictionary, return the default
update(d)
Update the renderer dictionary with another dictionary d.
values()
Return a list of values from the dictionary
interface IMultiDict
Extends: pyramid.interfaces.IDict
An ordered dictionary that can have multiple values for each key. A multidict adds the
methods getall, getone, mixed, extend, add, and dict_of_lists to the
normal dictionary interface. A multidict data structure is used as request.POST,
request.GET, and request.params within an Pyramid application.
add(key, value)
Add the key and value, not overwriting any previous value.
dict_of_lists()
Returns a dictionary where each key is associated with a list of values.
extend(other=None, **kwargs)
Add a set of keys and values, not overwriting any previous values. The other
structure may be a list of two-tuples or a dictionary. If **kwargs is passed, its
value will overwrite existing values.
getall(key)
Return a list of all values matching the key (may be an empty list)
getone(key)
Get one value matching the key, raising a KeyError if multiple values were found.
mixed()
Returns a dictionary where the values are either single values, or a list of values
when a key/value appears more than once in this dictionary. This is similar to the
kind of dictionary often used to represent the variables in a web request.
interface IResponse
Represents a WSGI response using the WebOb response interface. Some attribute and
method documentation of this interface references RFC 2616.

820 CONTENTS
The Pyramid Web Framework, Version 2.0.2

This interface is most famously implemented by pyramid.response.Response


and the HTTP exception classes in pyramid.httpexceptions.
RequestClass
Alias for pyramid.request.Request
__call__(environ, start_response)
WSGI call interface, should call the start_response callback and should return an
iterable
accept_ranges
Gets and sets and deletes the Accept-Ranges header. For more information on
Accept-Ranges see RFC 2616, section 14.5
age
Gets and sets and deletes the Age header. Converts using int. For more informa-
tion on Age see RFC 2616, section 14.6.
allow
Gets and sets and deletes the Allow header. Converts using list. For more infor-
mation on Allow see RFC 2616, Section 14.7.
app_iter
Returns the app_iter of the response.
If body was set, this will create an app_iter from that body (a single-item list)
app_iter_range(start, stop)
Return a new app_iter built from the response app_iter that serves up only the
given start:stop range.
authenticated_userid
A string to identify the authenticated user or None.
body
The body of the response, as a str. This will read in the entire app_iter if necessary.
body_file
A file-like object that can be used to write to the body. If you passed in a list
app_iter, that app_iter will be modified by writes.
cache_control
Get/set/modify the Cache-Control header (RFC 2616 section 14.9)
cache_expires
Get/set the Cache-Control and Expires headers. This sets the response to expire
in the number of seconds passed when set.

0.4. API Documentation 821


The Pyramid Web Framework, Version 2.0.2

charset
Get/set the charset (in the Content-Type)
conditional_response_app(environ, start_response)
Like the normal __call__ interface, but checks conditional headers:
• If-Modified-Since (304 Not Modified; only on GET, HEAD)
• If-None-Match (304 Not Modified; only on GET, HEAD)
• Range (406 Partial Content; only on GET, HEAD)
content_disposition
Gets and sets and deletes the Content-Disposition header. For more information
on Content-Disposition see RFC 2616 section 19.5.1.
content_encoding
Gets and sets and deletes the Content-Encoding header. For more information
about Content-Encoding see RFC 2616 section 14.11.
content_language
Gets and sets and deletes the Content-Language header. Converts using list. For
more information about Content-Language see RFC 2616 section 14.12.
content_length
Gets and sets and deletes the Content-Length header. For more information on
Content-Length see RFC 2616 section 14.17. Converts using int.
content_location
Gets and sets and deletes the Content-Location header. For more information on
Content-Location see RFC 2616 section 14.14.
content_md5
Gets and sets and deletes the Content-MD5 header. For more information on
Content-MD5 see RFC 2616 section 14.14.
content_range
Gets and sets and deletes the Content-Range header. For more information on
Content-Range see section 14.16. Converts using ContentRange object.
content_type
Get/set the Content-Type header (or None), without the charset or any parameters.
If you include parameters (or ; at all) when setting the content_type, any existing
parameters will be deleted; otherwise they will be preserved.
content_type_params
A dictionary of all the parameters in the content type. This is not a view, set to
change, modifications of the dict would not be applied otherwise.

822 CONTENTS
The Pyramid Web Framework, Version 2.0.2

copy()
Makes a copy of the response and returns the copy.
date
Gets and sets and deletes the Date header. For more information on Date see RFC
2616 section 14.18. Converts using HTTP date.
delete_cookie(name, path=’/’, domain=None)
Delete a cookie from the client. Note that path and domain must match how the
cookie was originally set. This sets the cookie to the empty string, and max_age=0
so that it should expire immediately.
encode_content(encoding=’gzip’, lazy=False)
Encode the content with the given encoding (only gzip and identity are supported).
environ
Get/set the request environ associated with this response, if any.
etag
Gets and sets and deletes the ETag header. For more information on ETag see
RFC 2616 section 14.19. Converts using Entity tag.
expires
Gets and sets and deletes the Expires header. For more information on Expires
see RFC 2616 section 14.21. Converts using HTTP date.
headerlist
The list of response headers.
headers
The headers in a dictionary-like object
identity
An object containing authentication information related to the current request. The
object’s type and meaning is defined by the configured security policy.
is_authenticated
A boolean indicating whether the request has an authenticated user, as determined
by the security policy in use.
The value is determined by the result of pyramid.request.Request.
authenticated_userid.
last_modified
Gets and sets and deletes the Last-Modified header. For more information on
Last-Modified see RFC 2616 section 14.29. Converts using HTTP date.

0.4. API Documentation 823


The Pyramid Web Framework, Version 2.0.2

location
Gets and sets and deletes the Location header. For more information on Location
see RFC 2616 section 14.30.
md5_etag(body=None, set_content_md5=False)
Generate an etag for the response object using an MD5 hash of the body (the body
parameter, or self.body if not given). Sets self.etag. If set_content_md5 is True
sets self.content_md5 as well
merge_cookies(resp)
Merge the cookies that were set on this response with the given resp object (which
can be any WSGI application). If the resp is a webob.Response object, then the
other object will be modified in-place.
pragma
Gets and sets and deletes the Pragma header. For more information on Pragma
see RFC 2616 section 14.32.
request
Return the request associated with this response if any.
retry_after
Gets and sets and deletes the Retry-After header. For more information on Retry-
After see RFC 2616 section 14.37. Converts using HTTP date or delta seconds.
server
Gets and sets and deletes the Server header. For more information on Server see
RFC216 section 14.38.
set_cookie(name, value=”, max_age=None, path=’/’, domain=None,
secure=False, httponly=False, comment=None, expires=None,
overwrite=False)
Set (add) a cookie for the response
status
The status string.
status_int
The status as an integer
unicode_body
Get/set the unicode value of the body (using the charset of the Content-Type)
unset_cookie(name, strict=True)
Unset a cookie with the given name (remove it from the response).

824 CONTENTS
The Pyramid Web Framework, Version 2.0.2

vary
Gets and sets and deletes the Vary header. For more information on Vary see
section 14.44. Converts using list.
www_authenticate
Gets and sets and deletes the WWW-Authenticate header. For more information
on WWW-Authenticate see RFC 2616 section 14.47. Converts using ’parse_auth’
and ’serialize_auth’.
interface IIntrospectable
An introspectable object used for configuration introspection. In addition to the meth-
ods below, objects which implement this interface must also implement all the methods
of Python’s collections.MutableMapping (the ”dictionary interface”), and
must be hashable.
__hash__()
Introspectables must be hashable. The typical implementation of an in-
trosepectable’s __hash__ is:

return hash((self.category_name,) + (self.discriminator,


,→))

action_info
An IActionInfo object representing the caller that invoked the creation of this in-
trospectable (usually a sentinel until updated during self.register)
category_name
introspection category name
discriminator
introspectable discriminator (within category) (must be hashable)
discriminator_hash
an integer hash of the discriminator
order
integer order in which registered with introspector (managed by introspector, usu-
ally)
register(introspector, action_info)
Register this IIntrospectable with an introspector. This method is invoked
during action execution. Adds the introspectable and its relations to the in-
trospector. introspector should be an object implementing IIntrospec-
tor. action_info should be a object implementing the interface pyramid.
interfaces.IActionInfo representing the call that registered this intro-
spectable. Pseudocode for an implementation of this method:

0.4. API Documentation 825


The Pyramid Web Framework, Version 2.0.2

def register(self, introspector, action_info):


self.action_info = action_info
introspector.add(self)
for methodname, category_name, discriminator in self.
,→_relations:

method = getattr(introspector, methodname)


method((i.category_name, i.discriminator),
(category_name, discriminator))

relate(category_name, discriminator)
Indicate an intent to relate this IIntrospectable with another IIntrospectable (the
one associated with the category_name and discriminator) during ac-
tion execution.
title
Text title describing this introspectable
type_name
Text type name describing this introspectable
unrelate(category_name, discriminator)
Indicate an intent to break the relationship between this IIntrospectable with an-
other IIntrospectable (the one associated with the category_name and dis-
criminator) during action execution.
interface IIntrospector

add(intr)
Add the IIntrospectable intr (use instead of pyramid.interfaces.
IIntrospector.add() when you have a custom IIntrospectable). Replaces
any existing introspectable registered using the same category/discriminator.
This method is not typically called directly, instead it’s called indirectly by
pyramid.interfaces.IIntrospector.register()
categories()
Return a sorted sequence of category names known by this introspector
categorized(sort_key=None)
Get a sequence of tuples in the form [(category_name,
[{'introspectable':IIntrospectable, 're-
lated':[sequence of related IIntrospectables]}, ...])]
representing all known introspectables. If sort_key is None, each intro-
spectables sequence will be returned in the order the introspectables were added
to the introspector. Otherwise, sort_key should be a function that accepts an

826 CONTENTS
The Pyramid Web Framework, Version 2.0.2

IIntrospectable and returns a value from it (ala the key function of Python’s
sorted callable).
get(category_name, discriminator, default=None)
Get the IIntrospectable related to the category_name and the discriminator (or
discriminator hash) discriminator. If it does not exist in the introspector,
return the value of default
get_category(category_name, default=None, sort_key=None)
Get a sequence of dictionaries in the form
[{'introspectable':IIntrospectable, 're-
lated':[sequence of related IIntrospectables]}, ...]
where each introspectable is part of the category associated with cate-
gory_name .
If the category named category_name does not exist in the introspector the
value passed as default will be returned.
If sort_key is None, the sequence will be returned in the order the introspecta-
bles were added to the introspector. Otherwise, sort_key should be a function that
accepts an IIntrospectable and returns a value from it (ala the key function of
Python’s sorted callable).
relate(*pairs)
Given any number of (category_name, discriminator) pairs passed
as positional arguments, relate the associated introspectables to each other. The
introspectable related to each pair must have already been added via .add or .
add_intr; a KeyError will result if this is not true. An error will not be raised
if any pair has already been associated with another.
This method is not typically called directly, instead it’s called indirectly by
pyramid.interfaces.IIntrospector.register()
related(intr)
Return a sequence of IIntrospectables related to the IIntrospectable intr. Return
the empty sequence if no relations for exist.
remove(category_name, discriminator)
Remove the IIntrospectable related to category_name and discriminator
from the introspector, and fix up any relations that the introspectable participates
in. This method will not raise an error if an introspectable related to the category
name and discriminator does not exist.
unrelate(*pairs)
Given any number of (category_name, discriminator) pairs passed
as positional arguments, unrelate the associated introspectables from each other.
The introspectable related to each pair must have already been added via .add

0.4. API Documentation 827


The Pyramid Web Framework, Version 2.0.2

or .add_intr; a KeyError will result if this is not true. An error will not be
raised if any pair is not already related to another.
This method is not typically called directly, instead it’s called indirectly by
pyramid.interfaces.IIntrospector.register()
interface IActionInfo
Class which provides code introspection capability associated with an action. The
ParserInfo class used by ZCML implements the same interface.
__str__()
Return a representation of the action information (including source code from file,
if possible)
file
Filename of action-invoking code as a string
line
Starting line number in file (as an integer) of action-invoking code.This will be
None if the value could not be determined.
interface IAssetDescriptor
Describes an asset.
abspath()
Returns an absolute path in the filesystem to the asset.
absspec()
Returns the absolute asset specification for this asset (e.g.
mypackage:templates/foo.pt).
exists()
Returns True if asset exists, otherwise returns False.
isdir()
Returns True if the asset is a directory, otherwise returns False.
listdir()
Returns iterable of filenames of directory contents. Raises an exception if asset is
not a directory.
stream()
Returns an input stream for reading asset contents. Raises an exception if the asset
is a directory or does not exist.
interface IResourceURL

828 CONTENTS
The Pyramid Web Framework, Version 2.0.2

physical_path
The physical url path of the resource as a string.
physical_path_tuple
The physical url path of the resource as a tuple. (New in 1.5)
virtual_path
The virtual url path of the resource as a string.
virtual_path_tuple
The virtual url path of the resource as a tuple. (New in 1.5)
interface ICacheBuster
A cache buster modifies the URL generation machinery for static_url(). See
Cache Busting.
New in version 1.6.
__call__(request, subpath, kw)
Modifies a subpath and/or keyword arguments from which a static asset URL will
be computed during URL generation.
The subpath argument is a path of /-delimited segments that represent the por-
tion of the asset URL which is used to find the asset. The kw argument is a dict
of keywords that are to be passed eventually to static_url() for URL gen-
eration. The return value should be a two-tuple of (subpath, kw) where
subpath is the relative URL from where the file is served and kw is the same
input argument. The return value should be modified to include the cache bust
token in the generated URL.
The kw dictionary contains extra arguments passed to static_url() as well
as some extra items that may be usful including:
• pathspec is the path specification for the resource to be cache busted.
• rawspec is the original location of the file, ignoring any calls to pyramid.
config.Configurator.override_asset().
The pathspec and rawspec values are only different in cases where
an asset has been mounted into a virtual location using pyramid.
config.Configurator.override_asset(). For example, with
a call to request.static_url('myapp:static/foo.png'),
the ``pathspec is myapp:static/foo.png whereas the
rawspec may be themepkg:bar.png, assuming a call to config.
override_asset('myapp:static/foo.png', 'themepkg:bar.
png').

0.4. API Documentation 829


The Pyramid Web Framework, Version 2.0.2

interface IViewDeriver

__call__(view, info)
Derive a new view from the supplied view.
View options, package information and registry are available on info, an instance
of pyramid.interfaces.IViewDeriverInfo.
The view is a callable accepting (context, request).
options
A list of supported options to be passed to pyramid.config.
Configurator.add_view(). This attribute is optional.
interface IViewDeriverInfo
An object implementing this interface is passed to every view deriver during configu-
ration.
exception_only
The view will only be invoked for exceptions
options
The view options passed to the view, including any default values that were not
overriden
original_view
The original view object being wrapped
package
The ”current package” where the view configuration statement was found
predicates
The list of predicates active on the view
registry
The ”current” application registry where the view was created
settings
The deployment settings dictionary related to the current application
interface IPredicateFactory

__call__(value, info)
Create a a IPredicate instance for a specific value.
interface IPredicateInfo

830 CONTENTS
The Pyramid Web Framework, Version 2.0.2

maybe_dotted(value)
Resolve the dotted Python name dotted to a global Python object. If dotted
is not a string, return it without attempting to do any name resolution. If dotted
is a relative dotted name (e.g. .foo.bar, consider it relative to the package.
package
The ”current package” where the predicate configuration statement was found
registry
The ”current” application registry where the predicate was invoked
settings
The deployment settings dictionary related to the current application
interface IPredicate

phash()
A unique string for the predicate containing both the name and value.
Often implementations simply set phash = text.
text()
A textual description of the predicate used in the introspector.
For example, 'content_type = application/json' for a Content-
TypePredicate with a value == 'application/json'.
interface IRoutePredicate
Extends: pyramid.interfaces.IPredicate
__call__(info, request)
The info object is a dictionary containing two keys:
• ”match” is a dictionary of parameters that becomes request.matchdict
if the route is selected (all route predicates match).
• ”route” is the IRoute object being matched.
Return True if the route should be selected or False otherwise.
interface ISubscriberPredicate
Extends: pyramid.interfaces.IPredicate
__call__(*args)
The args is usually just a single event argument sent to registry.notify.
Return True if the subscriber should be executed for the given arguments or
False otherwise.

0.4. API Documentation 831


The Pyramid Web Framework, Version 2.0.2

interface IViewPredicate
Extends: pyramid.interfaces.IPredicate
__call__(context, request)
Return True if the view should be selected for the given arguments or False
otherwise.

pyramid.location

lineage(resource)
Return a generator representing the lineage of the resource object implied by the resource ar-
gument. The generator first returns resource unconditionally. Then, if resource supplies a
__parent__ attribute, return the resource represented by resource.__parent__. If that
resource has a __parent__ attribute, return that resource’s parent, and so on, until the resource
being inspected either has no __parent__ attribute or which has a __parent__ attribute of
None. For example, if the resource tree is:

thing1 = Thing()
thing2 = Thing()
thing2.__parent__ = thing1

Calling lineage(thing2) will return a generator. When we turn it into a list, we will get:

list(lineage(thing2))
[ <Thing object at thing2>, <Thing object at thing1> ]

inside(resource1, resource2)
Is resource1 ’inside’ resource2? Return True if so, else False.
resource1 is ’inside’ resource2 if resource2 is a lineage ancestor of resource1. It is
a lineage ancestor if its parent (or one of its parent’s parents, etc.) is an ancestor.

pyramid.paster

832 CONTENTS
The Pyramid Web Framework, Version 2.0.2

bootstrap(config_uri, request=None, options=None)


Load a WSGI application from the PasteDeploy config file specified by config_uri. The envi-
ronment will be configured as if it is currently serving request, leaving a natural environment in
place to write scripts that can generate URLs and utilize renderers.
This function returns a dictionary with app, root, closer, request, and registry keys.
app is the WSGI app loaded (based on the config_uri), root is the traversal root resource
of the Pyramid application, and closer is a parameterless callback that may be called when your
script is complete (it pops a threadlocal stack).

Most operations within Pyramid expect to be invoked within the context of a WSGI request,
thus it’s important when loading your application to anchor it when executing scripts and other code
that is not normally invoked during active WSGI requests.

For a complex config file containing multiple Pyramid applications, this function will
setup the environment under the context of the last-loaded Pyramid application. You may
load a specific application yourself by using the lower-level functions pyramid.paster.
get_app() and pyramid.scripting.prepare() in conjunction with pyramid.
config.global_registries.

config_uri -- specifies the PasteDeploy config file to use for the interactive shell. The format is
inifile#name. If the name is left off, main will be assumed.
request -- specified to anchor the script to a given set of WSGI parameters. For example, most
people would want to specify the host, scheme and port such that their script will generate URLs
in relation to those parameters. A request with default parameters is constructed for you if none is
provided. You can mutate the request’s environ later to setup a specific host/port/scheme/etc.
options Is passed to get_app for use as variable assignments like {’http_port’: 8080} and then
use %(http_port)s in the config file.
This function may be used as a context manager to call the closer automatically:

with bootstrap('development.ini') as env:


request = env['request']
# ...

See Writing a Script for more information about how to use this function.
Changed in version 1.8: Added the ability to use the return value as a context manager.
Changed in version 2.0: Request finished callbacks added via pyramid.request.Request.
add_finished_callback() will be invoked by the closer.

0.4. API Documentation 833


The Pyramid Web Framework, Version 2.0.2

get_app(config_uri, name=None, options=None)


Return the WSGI application named name in the PasteDeploy config file specified by con-
fig_uri.
options, if passed, should be a dictionary used as variable assignments like {'http_port':
8080}. This is useful if e.g. %(http_port)s is used in the config file.
If the name is None, this will attempt to parse the name from the config_uri string expecting
the format inifile#name. If no name is found, the name will default to ”main”.

get_appsettings(config_uri, name=None, options=None)


Return a dictionary representing the key/value pairs in an app section within the file represented by
config_uri.
options, if passed, should be a dictionary used as variable assignments like {'http_port':
8080}. This is useful if e.g. %(http_port)s is used in the config file.
If the name is None, this will attempt to parse the name from the config_uri string expecting
the format inifile#name. If no name is found, the name will default to ”main”.

setup_logging(config_uri, global_conf=None)
Set up Python logging with the filename specified via config_uri (a string in the form file-
name#sectionname).
Extra defaults can optionally be specified as a dict in global_conf.

pyramid.path

CALLER_PACKAGE
A constant used by the constructor of pyramid.path.DottedNameResolver and
pyramid.path.AssetResolver.

class DottedNameResolver(package=pyramid.path.CALLER_PACKAGE)
A class used to resolve a dotted Python name to a package or module object.
New in version 1.3.
The constructor accepts a single argument named package which may be any of:
• A fully qualified (not relative) dotted name to a module or package
• a Python module or package object
• The value None
• The constant value pyramid.path.CALLER_PACKAGE.

834 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The default value is pyramid.path.CALLER_PACKAGE.


The package is used when a relative dotted name is supplied to the resolve() method. A
dotted name which has a . (dot) or : (colon) as its first character is treated as relative.
If package is None, the resolver will only be able to resolve fully qualified (not relative) names.
Any attempt to resolve a relative name will result in an ValueError exception.
If package is pyramid.path.CALLER_PACKAGE, the resolver will treat relative dotted names
as relative to the caller of the resolve() method.
If package is a module or module name (as opposed to a package or package name), its containing
package is computed and this package used to derive the package name (all names are resolved rela-
tive to packages, never to modules). For example, if the package argument to this type was passed
the string xml.dom.expatbuilder, and .mindom is supplied to the resolve() method, the
resulting import would be for xml.minidom, because xml.dom.expatbuilder is a module
object, not a package object.
If package is a package or package name (as opposed to a module or module name), this package
will be used to relative compute dotted names. For example, if the package argument to this
type was passed the string xml.dom, and .minidom is supplied to the resolve() method, the
resulting import would be for xml.minidom.
maybe_resolve(dotted)
This method behaves just like resolve(), except if the dotted value passed is not a string,
it is simply returned. For example:

import xml
r = DottedNameResolver()
v = r.maybe_resolve(xml)
# v is the xml module; no exception raised

resolve(dotted)
This method resolves a dotted name reference to a global Python object (an object which can
be imported) to the object itself.
Two dotted name styles are supported:
• pkg_resources-style dotted names where non-module attributes of a package are
separated from the rest of the path using a : e.g. package.module:attr.
• zope.dottedname-style dotted names where non-module attributes of a package are
separated from the rest of the path using a . e.g. package.module.attr.
These styles can be used interchangeably. If the supplied name contains a : (colon),
the pkg_resources resolution mechanism will be chosen, otherwise the zope.
dottedname resolution mechanism will be chosen.

0.4. API Documentation 835


The Pyramid Web Framework, Version 2.0.2

If the dotted argument passed to this method is not a string, a ValueError will be raised.
When a dotted name cannot be resolved, a ValueError error is raised.
Example:

r = DottedNameResolver()
v = r.resolve('xml') # v is the xml module

class AssetResolver(package=pyramid.path.CALLER_PACKAGE)
A class used to resolve an asset specification to an asset descriptor.
New in version 1.3.
The constructor accepts a single argument named package which may be any of:
• A fully qualified (not relative) dotted name to a module or package
• a Python module or package object
• The value None
• The constant value pyramid.path.CALLER_PACKAGE.
The default value is pyramid.path.CALLER_PACKAGE.
The package is used when a relative asset specification is supplied to the resolve() method.
An asset specification without a colon in it is treated as relative.
If package is None, the resolver will only be able to resolve fully qualified (not relative) asset
specifications. Any attempt to resolve a relative asset specification will result in an ValueError
exception.
If package is pyramid.path.CALLER_PACKAGE, the resolver will treat relative asset speci-
fications as relative to the caller of the resolve() method.
If package is a module or module name (as opposed to a package or package name), its con-
taining package is computed and this package is used to derive the package name (all names are
resolved relative to packages, never to modules). For example, if the package argument to this
type was passed the string xml.dom.expatbuilder, and template.pt is supplied to the
resolve() method, the resulting absolute asset spec would be xml.minidom:template.
pt, because xml.dom.expatbuilder is a module object, not a package object.
If package is a package or package name (as opposed to a module or module name), this package
will be used to compute relative asset specifications. For example, if the package argument to this
type was passed the string xml.dom, and template.pt is supplied to the resolve() method,
the resulting absolute asset spec would be xml.minidom:template.pt.

836 CONTENTS
The Pyramid Web Framework, Version 2.0.2

resolve(spec)
Resolve the asset spec named as spec to an object that has the attributes and methods de-
scribed in pyramid.interfaces.IAssetDescriptor.
If spec is an absolute filename (e.g. /path/to/myproject/templates/foo.pt)
or an absolute asset spec (e.g. myproject:templates.foo.pt), an asset descriptor is
returned without taking into account the package passed to this class’ constructor.
If spec is a relative asset specification (an asset specification without a : in it, e.g.
templates/foo.pt), the package argument of the constructor is used as the package
portion of the asset spec. For example:

a = AssetResolver('myproject')
resolver = a.resolve('templates/foo.pt')
print(resolver.abspath())
# -> /path/to/myproject/templates/foo.pt

If the AssetResolver is constructed without a package argument of None, and a relative


asset specification is passed to resolve, an ValueError exception is raised.

pyramid.registry

class Registry(package_name=pyramid.path.CALLER_PACKAGE, *args, **kw)


A registry object is an application registry.
It is used by the framework itself to perform mappings of URLs to view callables, as well as servic-
ing other various framework duties. A registry has its own internal API, but this API is rarely used
by Pyramid application developers (it’s usually only used by developers of the Pyramid framework
and Pyramid addons). But it has a number of attributes that may be useful to application devel-
opers within application code, such as settings, which is a dictionary containing application
deployment settings.
For information about the purpose and usage of the application registry, see Using the Zope Com-
ponent Architecture in Pyramid.
The registry may be used both as an pyramid.interfaces.IDict and as a Zope component
registry. These two ways of storing configuration are independent. Applications will tend to prefer
to store information as key-values whereas addons may prefer to use the component registry to avoid
naming conflicts and to provide more complex lookup mechanisms.
The application registry is usually accessed as request.registry in application code. By the
time a registry is used to handle requests it should be considered frozen and read-only. Any changes
to its internal state should be done with caution and concern for thread-safety.

0.4. API Documentation 837


The Pyramid Web Framework, Version 2.0.2

settings
The dictionary-like deployment settings object. See Deployment Settings for information. This
object is often accessed as request.registry.settings or config.registry.
settings in a typical Pyramid application.
package_name
New in version 1.6.
When a registry is set up (or created) by a Configurator, this attribute will be the shortcut for
pyramid.config.Configurator.package_name.
This attribute is often accessed as request.registry.package_name or config.
registry.package_name or config.package_name in a typical Pyramid applica-
tion.
introspector
New in version 1.3.
When a registry is set up (or created) by a Configurator, the registry will be decorated
with an instance named introspector implementing the pyramid.interfaces.
IIntrospector interface.
See also:
See also pyramid.config.Configurator.introspector.
When a registry is created ”by hand”, however, this attribute will not exist until set up by a
configurator.
This attribute is often accessed as request.registry.introspector in a typical
Pyramid application.
notify(*events)
Fire one or more events. All event subscribers to the event(s) will be notified. The subscribers
will be called synchronously. This method is often accessed as request.registry.
notify in Pyramid applications to fire custom events. See Creating Your Own Events for
more information.

class Introspectable
New in version 1.3.
The default implementation of the interface pyramid.interfaces.IIntrospectable
used by framework exenders. An instance of this class is created when pyramid.config.
Configurator.introspectable is called.

838 CONTENTS
The Pyramid Web Framework, Version 2.0.2

class Deferred(func)
Can be used by a third-party configuration extender to wrap a discriminator during configuration if
an immediately hashable discriminator cannot be computed because it relies on unresolved values.
The function should accept no arguments and should return a hashable discriminator.
New in version 1.4.

undefer(v)
Function which accepts an object and returns it unless it is a pyramid.registry.Deferred
instance. If it is an instance of that class, its resolve method is called, and the result of the method
is returned.
New in version 1.4.

class predvalseq(iterable=(), / )
A subtype of tuple used to represent a sequence of predicate values
New in version 1.4.

pyramid.renderers

get_renderer(renderer_name, package=None, registry=None)


Return the renderer object for the renderer renderer_name.
You may supply a relative asset spec as renderer_name. If the package argument is supplied,
a relative renderer name will be converted to an absolute asset specification by combining the pack-
age package with the relative asset specification renderer_name. If package is None (the
default), the package name of the caller of this function will be used as the package.
You may directly supply an application registry using the registry argument, and it will
be used to look up the renderer. Otherwise, the current thread-local registry (obtained via
get_current_registry()) will be used.

render(renderer_name, value, request=None, package=None)


Using the renderer renderer_name (a template or a static renderer), render the value (or set of
values) present in value. Return the result of the renderer’s __call__ method (usually a string
or Unicode).
If the renderer_name refers to a file on disk, such as when the renderer is a template, it’s usually
best to supply the name as an asset specification (e.g. packagename:path/to/template.
pt).

0.4. API Documentation 839


The Pyramid Web Framework, Version 2.0.2

You may supply a relative asset spec as renderer_name. If the package argument is supplied,
a relative renderer path will be converted to an absolute asset specification by combining the pack-
age package with the relative asset specification renderer_name. If package is None (the
default), the package name of the caller of this function will be used as the package.
The value provided will be supplied as the input to the renderer. Usually, for template renderings,
this should be a dictionary. For other renderers, this will need to be whatever sort of value the
renderer expects.
The ’system’ values supplied to the renderer will include a basic set of top-level system names,
such as request, context, renderer_name, and view. See System Values Used During
Rendering for the full list. If renderer globals have been specified, these will also be used to augment
the value.
Supply a request parameter in order to provide the renderer with the most correct ’system’ values
(request and context in particular).

render_to_response(renderer_name, value, request=None, package=None, response=None)


Using the renderer renderer_name (a template or a static renderer), render the value (or set of
values) using the result of the renderer’s __call__ method (usually a string or Unicode) as the
response body.
If the renderer name refers to a file on disk (such as when the renderer is a template), it’s usually
best to supply the name as a asset specification.
You may supply a relative asset spec as renderer_name. If the package argument is supplied, a
relative renderer name will be converted to an absolute asset specification by combining the package
package with the relative asset specification renderer_name. If you do not supply a package
(or package is None) the package name of the caller of this function will be used as the package.
The value provided will be supplied as the input to the renderer. Usually, for template renderings,
this should be a dictionary. For other renderers, this will need to be whatever sort of value the
renderer expects.
The ’system’ values supplied to the renderer will include a basic set of top-level system names,
such as request, context, renderer_name, and view. See System Values Used During
Rendering for the full list. If renderer globals have been specified, these will also be used to argument
the value.
Supply a request parameter in order to provide the renderer with the most correct ’system’ val-
ues (request and context in particular). Keep in mind that any changes made to request.
response prior to calling this function will not be reflected in the resulting response object. A
new response object will be created for each call unless one is passed as the response argument.
Changed in version 1.6: In previous versions, any changes made to request.response outside
of this function call would affect the returned response. This is no longer the case. If you wish to
send in a pre-initialized response then you may pass one in the response argument.

840 CONTENTS
The Pyramid Web Framework, Version 2.0.2

class JSON(serializer=<function dumps>, adapters=(), **kw)


Renderer that returns a JSON-encoded string.
Configure a custom JSON renderer using the add_renderer() API at application startup time:

from pyramid.config import Configurator

config = Configurator()
config.add_renderer('myjson', JSON(indent=4))

Once this renderer is registered as above, you can use myjson as the renderer= parameter to
@view_config or add_view():

from pyramid.view import view_config

@view_config(renderer='myjson')
def myview(request):
return {'greeting':'Hello world'}

Custom objects can be serialized using the renderer by either implementing the __json__ magic
method, or by registering adapters with the renderer. See Serializing Custom Objects for more in-
formation.

The default serializer uses json.JSONEncoder. A different serializer can be specified via
the serializer argument. Custom serializers should accept the object, a callback default,
and any extra kw keyword arguments passed during renderer construction. This feature isn’t widely
used but it can be used to replace the stock JSON serializer with, say, simplejson. If all you want to
do, however, is serialize custom objects, you should use the method explained in Serializing Custom
Objects instead of replacing the serializer.

New in version 1.4: Prior to this version, there was no public API for supplying options to the
underlying serializer without defining a custom renderer.
add_adapter(type_or_iface, adapter)
When an object of the type (or interface) type_or_iface fails to automatically encode
using the serializer, the renderer will use the adapter adapter to convert it into a JSON-
serializable object. The adapter must accept two arguments: the object and the currently
active request.

class Foo:
x = 5

(continues on next page)

0.4. API Documentation 841


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


def foo_adapter(obj, request):
return obj.x

renderer = JSON(indent=4)
renderer.add_adapter(Foo, foo_adapter)

When you’ve done this, the JSON renderer will be able to serialize instances of the Foo class
when they’re encountered in your view results.

class JSONP(param_name=’callback’, **kw)


JSONP renderer factory helper which implements a hybrid json/jsonp renderer. JSONP is useful for
making cross-domain AJAX requests.
Configure a JSONP renderer using the pyramid.config.Configurator.
add_renderer() API at application startup time:

from pyramid.config import Configurator

config = Configurator()
config.add_renderer('jsonp', JSONP(param_name='callback'))

The class’ constructor also accepts arbitrary keyword arguments. All keyword arguments except
param_name are passed to the json.dumps function as its keyword arguments.

from pyramid.config import Configurator

config = Configurator()
config.add_renderer('jsonp', JSONP(param_name='callback', indent=4))

Changed in version 1.4: The ability of this class to accept a **kw in its constructor.
The arguments passed to this class’ constructor mean the same thing as the arguments passed to
pyramid.renderers.JSON (including serializer and adapters).
Once this renderer is registered via add_renderer() as above, you can use jsonp as
the renderer= parameter to @view_config or pyramid.config.Configurator.
add_view`():

from pyramid.view import view_config

@view_config(renderer='jsonp')
def myview(request):
return {'greeting':'Hello world'}

842 CONTENTS
The Pyramid Web Framework, Version 2.0.2

When a view is called that uses the JSONP renderer:


• If there is a parameter in the request’s HTTP query string that matches the param_name
of the registered JSONP renderer (by default, callback), the renderer will return a JSONP
response.
• If there is no callback parameter in the request’s query string, the renderer will return a ’plain’
JSON response.
New in version 1.1.
See also:
See also JSONP Renderer.
add_adapter(type_or_iface, adapter)
When an object of the type (or interface) type_or_iface fails to automatically encode
using the serializer, the renderer will use the adapter adapter to convert it into a JSON-
serializable object. The adapter must accept two arguments: the object and the currently
active request.

class Foo:
x = 5

def foo_adapter(obj, request):


return obj.x

renderer = JSON(indent=4)
renderer.add_adapter(Foo, foo_adapter)

When you’ve done this, the JSON renderer will be able to serialize instances of the Foo class
when they’re encountered in your view results.

null_renderer
An object that can be used in advanced integration cases as input to the view configuration ren-
derer= argument. When the null renderer is used as a view renderer argument, Pyramid avoids
converting the view callable result into a Response object. This is useful if you want to reuse the
view configuration and lookup machinery outside the context of its use by the Pyramid router.

0.4. API Documentation 843


The Pyramid Web Framework, Version 2.0.2

pyramid.request

class Request(environ, charset=None, unicode_errors=None, decode_param_names=None,


**kw)
A subclass of the WebOb Request class. An instance of this class is created by the router and is
provided to a view callable (and to other subsystems) as the request argument.
The documentation below (save for the add_response_callback and
add_finished_callback methods, which are defined in this subclass itself, and the attributes
context, registry, root, subpath, traversed, view_name, virtual_root , and
virtual_root_path, each of which is added to the request by the router at request ingress
time) are autogenerated from the WebOb source code used when this documentation was generated.
Due to technical constraints, we can’t yet display the WebOb version number from which this doc-
umentation is autogenerated, but it will be the ’prevailing WebOb version’ at the time of the release
of this Pyramid version. See https://webob.org/ for further information.
context
The context will be available as the context attribute of the request object. It will be the
context object implied by the current request. See Traversal for information about context
objects.
registry
The application registry will be available as the registry attribute of the request object.
See Using the Zope Component Architecture in Pyramid for more information about the ap-
plication registry.
root
The root object will be available as the root attribute of the request object. It will be the
resource object at which traversal started (the root). See Traversal for information about root
objects.
subpath
The traversal subpath will be available as the subpath attribute of the request object. It
will be a sequence containing zero or more elements (which will be Unicode objects). See
Traversal for information about the subpath.
traversed
The ”traversal path” will be available as the traversed attribute of the request object. It
will be a sequence representing the ordered set of names that were used to traverse to the
context, not including the view name or subpath. If there is a virtual root associated with the
request, the virtual root path is included within the traversal path. See Traversal for more
information.

844 CONTENTS
The Pyramid Web Framework, Version 2.0.2

view_name
The view name will be available as the view_name attribute of the request object. It will be
a single string (possibly the empty string if we’re rendering a default view). See Traversal for
information about view names.
virtual_root
The virtual root will be available as the virtual_root attribute of the request object. It
will be the virtual root object implied by the current request. See Virtual Hosting for more
information about virtual roots.
virtual_root_path
The virtual root path will be available as the virtual_root_path attribute of the request
object. It will be a sequence representing the ordered set of names that were used to traverse
to the virtual root object. See Virtual Hosting for more information about virtual roots.
exception
If an exception was raised by a root factory or a view callable, or at various other points
where Pyramid executes user-defined code during the processing of a request, the exception
object which was caught will be available as the exception attribute of the request within a
exception view, a response callback or a finished callback. If no exception occurred, the value
of request.exception will be None within response and finished callbacks.
exc_info
If an exception was raised by a root factory or a view callable, or at various other points
where Pyramid executes user-defined code during the processing of a request, result of sys.
exc_info() will be available as the exc_info attribute of the request within a excep-
tion view, a response callback or a finished callback. If no exception occurred, the value of
request.exc_info will be None within response and finished callbacks.
response
This attribute is actually a ”reified” property which returns an instance of the pyramid.
response.Response class. The response object returned does not exist until this attribute
is accessed. Once it is accessed, subsequent accesses to this request object will return the same
Response object.
The request.response API can is used by renderers. A render obtains the response
object it will return from a view that uses that renderer by accessing request.response.
Therefore, it’s possible to use the request.response API to set up a response object
with ”the right” attributes (e.g. by calling request.response.set_cookie(...)
or request.response.content_type = 'text/plain', etc) within a view that
uses a renderer. For example, within a view that uses a renderer:

response = request.response
response.set_cookie('mycookie', 'mine, all mine!')
return {'text':'Value that will be used by the renderer'}

0.4. API Documentation 845


The Pyramid Web Framework, Version 2.0.2

Mutations to this response object will be preserved in the response sent to the client after
rendering. For more information about using request.response in conjunction with a
renderer, see Varying Attributes of Rendered Responses.
Non-renderer code can also make use of request.response instead of creating a response ”by
hand”. For example, in view code:

response = request.response
response.body = 'Hello!'
response.content_type = 'text/plain'
return response

Note that the response in this circumstance is not ”global”; it still must be returned from the
view code if a renderer is not used.
session
If a session factory has been configured, this attribute will represent the current user’s session
object. If a session factory has not been configured, requesting the request.session
attribute will cause a pyramid.exceptions.ConfigurationError to be raised.
matchdict
If a route has matched during this request, this attribute will be a dictionary containing the
values matched by the URL pattern associated with the route. If a route has not matched
during this request, the value of this attribute will be None. See The Matchdict.
matched_route
If a route has matched during this request, this attribute will be an object representing the route
matched by the URL pattern associated with the route. If a route has not matched during this
request, the value of this attribute will be None. See The Matched Route.
authenticated_userid
A property which returns the userid of the currently authenticated user or None if there is no
security policy in effect or there is no currently authenticated user.
unauthenticated_userid
Deprecated since version 2.0: unauthenticated_userid has been deprecated in ver-
sion 2.0. Use authenticated_userid or identity instead. See upgrading_auth_20
for more information.
A property which returns a value which represents the claimed (not verified) userid of the cre-
dentials present in the request. None if there is no authentication policy in effect or there is no
user data associated with the current request. This differs from authenticated_userid,
because the effective authentication policy will not ensure that a record associated with the
userid exists in persistent storage. Even if the userid does not exist in persistent storage, this
value will be the value of the userid claimed by the request data.

846 CONTENTS
The Pyramid Web Framework, Version 2.0.2

effective_principals
Deprecated since version 2.0: The new security policy has removed the concept of principals.
See upgrading_auth_20 for more information.
A property which returns the list of ’effective’ principal identifiers for this request. This list
typically includes the userid of the currently authenticated user if a user is currently authen-
ticated, but this depends on the authentication policy in effect. If no authentication policy
is in effect, this will return a sequence containing only the pyramid.authorization.
Everyone principal.
invoke_subrequest(request, use_tweens=False)
New in version 1.4a1.
Obtain a response object from the Pyramid application based on information in the request
object provided. The request object must be an object that implements the Pyramid re-
quest interface (such as a pyramid.request.Request instance). If use_tweens is
True, the request will be sent to the tween in the tween stack closest to the request ingress. If
use_tweens is False, the request will be sent to the main router handler, and no tweens
will be invoked.
This function also:
• manages the threadlocal stack (so that get_current_request() and
get_current_registry() work during a request)
• Adds a registry attribute (the current Pyramid registry) and a in-
voke_subrequest attribute (a callable) to the request object it’s handed.
• sets request extensions (such as those added via add_request_method()) on the
request it’s passed.
• causes a NewRequest event to be sent at the beginning of request processing.
• causes a ContextFound event to be sent when a context resource is found.
• Ensures that the user implied by the request passed has the necessary authorization to
invoke view callable before calling it.
• Calls any response callback functions defined within the request’s lifetime if a response
is obtained from the Pyramid application.
• causes a NewResponse event to be sent if a response is obtained.
• Calls any finished callback functions defined within the request’s lifetime.
invoke_subrequest isn’t actually a method of the Request object; it’s a callable added
when the Pyramid router is invoked, or when a subrequest is invoked. This means that it’s not
available for use on a request provided by e.g. the pshell environment.

0.4. API Documentation 847


The Pyramid Web Framework, Version 2.0.2

See also:
See also Invoking a Subrequest.
invoke_exception_view(exc_info=None, request=None, secure=True, reraise=False)
Executes an exception view related to the request it’s called upon. The arguments it takes are
these:
exc_info
If provided, should be a 3-tuple in the form provided by sys.exc_info(). If
not provided, sys.exc_info() will be called to obtain the current interpreter
exception information. Default: None.
request
If the request to be used is not the same one as the instance that this method is
called upon, it may be passed here. Default: None.
secure
If the exception view should not be rendered if the current user does not have the
appropriate permission, this should be True. Default: True.
reraise
A boolean indicating whether the original error should be reraised if a response
object could not be created. If False then an pyramid.httpexceptions.
HTTPNotFound` exception will be raised. Default: False.
If a response is generated then request.exception and request.exc_info will be
left at the values used to render the response. Otherwise the previous values for request.
exception and request.exc_info will be restored.
New in version 1.7.
Changed in version 1.9: The request.exception and request.exc_info proper-
ties will reflect the exception used to render the response where previously they were reset to
the values prior to invoking the method.
Also added the reraise argument.
has_permission(permission, context=None)
Given a permission and an optional context, returns an instance of pyramid.security.
Allowed if the permission is granted to this request with the provided context, or the
context already associated with the request. Otherwise, returns an instance of pyramid.
security.Denied. This method delegates to the current security policy. Returns
pyramid.security.Allowed unconditionally if no security policy has been registered
for this request. If context is not supplied or is supplied as None, the context used is the
request.context attribute.

848 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Parameters
• permission (str) -- Does this request have the given permission?
• context (object) -- A resource object or None
Returns
Either pyramid.security.Allowed or pyramid.security.
Denied.
add_response_callback(callback)
Add a callback to the set of callbacks to be called by the router at a point after a response object
is successfully created. Pyramid does not have a global response object: this functionality
allows an application to register an action to be performed against the response once one is
created.
A ’callback’ is a callable which accepts two positional parameters: request and re-
sponse. For example:

1 def cache_callback(request, response):


2 'Set the cache_control max_age for the response'
3 response.cache_control.max_age = 360
4 request.add_response_callback(cache_callback)

Response callbacks are called in the order they’re added (first-to-most-recently-added). No


response callback is called if an exception happens in application code, or if the response
object returned by view code is invalid.
All response callbacks are called after the tweens and before the pyramid.events.
NewResponse event is sent.
Errors raised by callbacks are not handled specially. They will be propagated to the caller of
the Pyramid router application.
See also:
See also Using Response Callbacks.
add_finished_callback(callback)
Add a callback to the set of callbacks to be called unconditionally by the router at the very
end of request processing.
callback is a callable which accepts a single positional parameter: request. For exam-
ple:

1 import transaction
2

3 def commit_callback(request):
(continues on next page)

0.4. API Documentation 849


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


4 '''commit or abort the transaction associated with request'''
5 if request.exception is not None:
6 transaction.abort()
7 else:
8 transaction.commit()
9 request.add_finished_callback(commit_callback)

Finished callbacks are called in the order they’re added ( first- to most-recently- added). Fin-
ished callbacks (unlike response callbacks) are always called, even if an exception happens in
application code that prevents a response from being generated.
The set of finished callbacks associated with a request are called very late in the processing
of that request; they are essentially the last thing called by the router. They are called after
response processing has already occurred in a top-level finally: block within the router
request processing code. As a result, mutations performed to the request provided to a fin-
ished callback will have no meaningful effect, because response processing will have already
occurred, and the request’s scope will expire almost immediately after all finished callbacks
have been processed.
Errors raised by finished callbacks are not handled specially. They will be propagated to the
caller of the Pyramid router application.
See also:
See also Using Finished Callbacks.
route_url(route_name, *elements, **kw)
Generates a fully qualified URL for a named Pyramid route configuration.
Use the route’s name as the first positional argument. Additional positional arguments
(*elements) are appended to the URL as path segments after it is generated.
Use keyword arguments to supply values which match any dynamic path elements in the route
definition. Raises a KeyError exception if the URL cannot be generated for any reason (not
enough arguments, for example).
For example, if you’ve defined a route named ”foobar” with the path {foo}/{bar}/
*traverse:

request.route_url('foobar',
foo='1') => <KeyError exception>
request.route_url('foobar',
foo='1',
bar='2') => <KeyError exception>
request.route_url('foobar',
foo='1',
(continues on next page)

850 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


bar='2',
traverse=('a','b')) => http://e.com/1/2/a/b
request.route_url('foobar',
foo='1',
bar='2',
traverse='/a/b') => http://e.com/1/2/a/b

Values replacing :segment arguments can be passed as strings or Unicode objects. They
will be encoded to UTF-8 and URL-quoted before being placed into the generated URL.
Values replacing *remainder arguments can be passed as strings or tuples of Uni-
code/string values. If a tuple is passed as a *remainder replacement value, its values are
URL-quoted and encoded to UTF-8. The resulting strings are joined with slashes and ren-
dered into the URL. If a string is passed as a *remainder replacement value, it is tacked
on to the URL after being URL-quoted-except-for-embedded-slashes.
If _query is provided, it will be used to compose a query string that will be tacked on
to the end of the URL. The value of _query may be a sequence of two-tuples or a data
structure with an .items() method that returns a sequence of two-tuples (presumably a
dictionary). This data structure will be turned into a query string per the documentation
of the pyramid.url.urlencode() function. This will produce a query string in the
x-www-form-urlencoded format. A non-x-www-form-urlencoded query string
may be used by passing a string value as _query in which case it will be URL-quoted (e.g.
query=”foo bar” will become ”foo%20bar”). However, the result will not need to be in k=v
form as required by x-www-form-urlencoded. After the query data is turned into a
query string, a leading ? is prepended, and the resulting string is appended to the generated
URL.

Python data structures that are passed as _query which are sequences or dictionaries
are turned into a string under the same rules as when run through urllib.urlencode()
with the doseq argument equal to True. This means that sequences can be passed as values,
and a k=v pair will be placed into the query string for each value.

If a keyword argument _anchor is present, its string representation will be quoted per RFC
3986#section-3.5 and used as a named anchor in the generated URL (e.g. if _anchor is
passed as foo and the route URL is http://example.com/route/url, the resulting
generated URL will be http://example.com/route/url#foo).

If _anchor is passed as a string, it should be UTF-8 encoded. If _anchor is passed


as a Unicode object, it will be converted to UTF-8 before being appended to the URL.

0.4. API Documentation 851


The Pyramid Web Framework, Version 2.0.2

If both _anchor and _query are specified, the anchor element will always follow the query
element, e.g. http://example.com?foo=1#bar.
If any of the keyword arguments _scheme, _host, or _port is passed and is non-None,
the provided value will replace the named portion in the generated URL. For example, if you
pass _host='foo.com', and the URL that would have been generated without the host
replacement is http://example.com/a, the result will be http://foo.com/a.
Note that if _scheme is passed as https, and _port is not passed, the _port value is
assumed to have been passed as 443. Likewise, if _scheme is passed as http and _port
is not passed, the _port value is assumed to have been passed as 80. To avoid this behavior,
always explicitly pass _port whenever you pass _scheme.
If a keyword _app_url is present, it will be used as the protocol/hostname/port/leading path
prefix of the generated URL. For example, using an _app_url of http://example.
com:8080/foo would cause the URL http://example.com:8080/foo/fleeb/
flub to be returned from this function if the expansion of the route pattern associated with
the route_name expanded to /fleeb/flub. If _app_url is not specified, the result of
request.application_url will be used as the prefix (the default).
If both _app_url and any of _scheme, _host, or _port are passed, _app_url takes
precedence and any values passed for _scheme, _host, and _port will be ignored.
This function raises a KeyError if the URL cannot be generated due to missing replacement
names. Extra replacement names are ignored.
If the route object which matches the route_name argument has a pregenerator, the *el-
ements and **kw arguments passed to this function might be augmented or changed.
Changed in version 1.5: Allow the _query option to be a string to enable alternative encod-
ings.
The _anchor option will be escaped instead of using its raw string representation.
Changed in version 1.9: If _query or _anchor are falsey (such as None or an empty string)
they will not be included in the generated url.
route_path(route_name, *elements, **kw)
Generates a path (aka a ’relative URL’, a URL minus the host, scheme, and port) for a named
Pyramid route configuration.
This function accepts the same argument as pyramid.request.Request.
route_url() and performs the same duty. It just omits the host, port, and scheme
information in the return value; only the script_name, path, query parameters, and anchor
data are present in the returned string.
For example, if you’ve defined a route named ’foobar’ with the path /{foo}/{bar}, this
call to route_path:

852 CONTENTS
The Pyramid Web Framework, Version 2.0.2

request.route_path('foobar', foo='1', bar='2')

Will return the string /1/2.

Calling request.route_path('route') is the same as calling request.


route_url('route', _app_url=request.script_name). pyramid.
request.Request.route_path() is, in fact, implemented in terms of pyramid.
request.Request.route_url() in just this way. As a result, any _app_url passed
within the **kw values to route_path will be ignored.

current_route_url(*elements, **kw)
Generates a fully qualified URL for a named Pyramid route configuration based on the ’current
route’.
This function supplements pyramid.request.Request.route_url(). It presents
an easy way to generate a URL for the ’current route’ (defined as the route which matched
when the request was generated).
The arguments to this method have the same meaning as those with the same names passed to
pyramid.request.Request.route_url(). It also understands an extra argument
which route_url does not named _route_name.
The route name used to generate a URL is taken from either the _route_name key-
word argument or the name of the route which is currently associated with the request if
_route_name was not passed. Keys and values from the current request matchdict are
combined with the kw arguments to form a set of defaults named newkw. Then request.
route_url(route_name, *elements, **newkw) is called, returning a URL.
Examples follow.
If the ’current route’ has the route pattern /foo/{page} and the current url path
is /foo/1 , the matchdict will be {'page':'1'}. The result of request.
current_route_url() in this situation will be /foo/1.
If the ’current route’ has the route pattern /foo/{page} and the current url path
is /foo/1, the matchdict will be {'page':'1'}. The result of request.
current_route_url(page='2') in this situation will be /foo/2.
Usage of the _route_name keyword argument: if our routing table defines routes /
foo/{action} named ’foo’ and /foo/{action}/{page} named fooaction, and
the current url pattern is /foo/view (which has matched the /foo/{action} route),
we may want to use the matchdict args to generate a URL to the fooaction route.
In this scenario, request.current_route_url(_route_name='fooaction',
page='5') Will return string like: /foo/view/5.

0.4. API Documentation 853


The Pyramid Web Framework, Version 2.0.2

current_route_path(*elements, **kw)
Generates a path (aka a ’relative URL’, a URL minus the host, scheme, and port) for the
Pyramid route configuration matched by the current request.
This function accepts the same argument as pyramid.request.Request.
current_route_url() and performs the same duty. It just omits the host, port,
and scheme information in the return value; only the script_name, path, query parameters,
and anchor data are present in the returned string.
For example, if the route matched by the current request has the pattern /{foo}/{bar},
this call to current_route_path:

request.current_route_path(foo='1', bar='2')

Will return the string /1/2.

Calling request.current_route_path('route') is the same as


calling request.current_route_url('route', _app_url=request.
script_name). pyramid.request.Request.current_route_path()
is, in fact, implemented in terms of pyramid.request.Request.
current_route_url() in just this way. As a result, any _app_url passed within the
**kw values to current_route_path will be ignored.

static_url(path, **kw)
Generates a fully qualified URL for a static asset. The asset must live within a location de-
fined via the pyramid.config.Configurator.add_static_view() configura-
tion declaration (see Serving Static Assets).
Example:

request.static_url('mypackage:static/foo.css') =>

http://example.com/static/foo.css

The path argument points at a file or directory on disk which a URL should be generated for.
The path may be either a relative path (e.g. static/foo.css) or an absolute path (e.g. /
abspath/to/static/foo.css) or a asset specification (e.g. mypackage:static/
foo.css).
The purpose of the **kw argument is the same as the purpose of the pyramid.request.
Request.route_url() **kw argument. See the documentation for that function to
understand the arguments which you can provide to it. However, typically, you don’t need to
pass anything as *kw when generating a static asset URL.

854 CONTENTS
The Pyramid Web Framework, Version 2.0.2

This function raises a ValueError if a static view definition cannot be found which matches
the path specification.
static_path(path, **kw)
Generates a path (aka a ’relative URL’, a URL minus the host, scheme, and port) for a static
resource.
This function accepts the same argument as pyramid.request.Request.
static_url() and performs the same duty. It just omits the host, port, and scheme
information in the return value; only the script_name, path, query parameters, and anchor
data are present in the returned string.
Example:

request.static_path('mypackage:static/foo.css') =>

/static/foo.css

Calling request.static_path(apath) is the same as calling request.


static_url(apath, _app_url=request.script_name). pyramid.
request.Request.static_path() is, in fact, implemented in terms of pyramid.
request.Request.static_url() in just this way. As a result, any _app_url
passed within the **kw values to static_path will be ignored.

resource_url(resource, *elements, **kw)


Generate a string representing the absolute URL of the resource object based on the wsgi.
url_scheme, HTTP_HOST or SERVER_NAME in the request, plus any SCRIPT_NAME.
The overall result of this method is always a UTF-8 encoded string.
Examples:

request.resource_url(resource) =>

http://example.com/

request.resource_url(resource, 'a.html') =>

http://example.com/a.html

request.resource_url(resource, 'a.html', query={'q':'1'}) =>

http://example.com/a.html?q=1

(continues on next page)

0.4. API Documentation 855


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


request.resource_url(resource, 'a.html', anchor='abc') =>

http://example.com/a.html#abc

request.resource_url(resource, app_url='') =>

Any positional arguments passed in as elements must be strings Unicode objects, or integer
objects. These will be joined by slashes and appended to the generated resource URL. Each
of the elements passed in is URL-quoted before being appended; if any element is Unicode, it
will converted to a UTF-8 bytestring before being URL-quoted. If any element is an integer,
it will be converted to its string representation before being URL-quoted.

if no elements arguments are specified, the resource URL will end with a trailing
slash. If any elements are used, the generated URL will not end in a trailing slash.

If query is provided, it will be used to compose a query string that will be tacked on
to the end of the URL. The value of query may be a sequence of two-tuples or a data
structure with an .items() method that returns a sequence of two-tuples (presumably a
dictionary). This data structure will be turned into a query string per the documentation
of the pyramid.url.urlencode() function. This will produce a query string in the
x-www-form-urlencoded format. A non-x-www-form-urlencoded query string
may be used by passing a string value as query in which case it will be URL-quoted (e.g.
query=”foo bar” will become ”foo%20bar”). However, the result will not need to be in k=v
form as required by x-www-form-urlencoded. After the query data is turned into a
query string, a leading ? is prepended, and the resulting string is appended to the generated
URL.

Python data structures that are passed as query which are sequences or dictionaries
are turned into a string under the same rules as when run through urllib.urlencode()
with the doseq argument equal to True. This means that sequences can be passed as values,
and a k=v pair will be placed into the query string for each value.

If a keyword argument anchor is present, its string representation will be used as a named
anchor in the generated URL (e.g. if anchor is passed as foo and the resource URL is
http://example.com/resource/url, the resulting generated URL will be http:/
/example.com/resource/url#foo).

856 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If anchor is passed as a string, it should be UTF-8 encoded. If anchor is passed as


a Unicode object, it will be converted to UTF-8 before being appended to the URL.

If both anchor and query are specified, the anchor element will always follow the query
element, e.g. http://example.com?foo=1#bar.
If any of the keyword arguments scheme, host, or port is passed and is non-None, the
provided value will replace the named portion in the generated URL. For example, if you
pass host='foo.com', and the URL that would have been generated without the host
replacement is http://example.com/a, the result will be http://foo.com/a.
If scheme is passed as https, and an explicit port is not passed, the port value is as-
sumed to have been passed as 443. Likewise, if scheme is passed as http and port is not
passed, the port value is assumed to have been passed as 80. To avoid this behavior, always
explicitly pass port whenever you pass scheme.
If a keyword argument app_url is passed and is not None, it should be a string that will
be used as the port/hostname/initial path portion of the generated URL instead of the default
request application URL. For example, if app_url='http://foo', then the resulting url
of a resource that has a path of /baz/bar will be http://foo/baz/bar. If you want
to generate completely relative URLs with no leading scheme, host, port, or initial path, you
can pass app_url=''. Passing app_url='' when the resource path is /baz/bar will
return /baz/bar.
If app_url is passed and any of scheme, port, or host are also passed, app_url will
take precedence and the values passed for scheme, host, and/or port will be ignored.
If the resource passed in has a __resource_url__ method, it will be used to gener-
ate the URL (scheme, host, port, path) for the base resource which is operated upon by this
function.
See also:
See also Overriding Resource URL Generation.
If route_name is passed, this function will delegate its URL production to the route_url
function. Calling resource_url(someresource, 'element1', 'element2',
query={'a':1}, route_name='blogentry') is roughly equivalent to doing:

traversal_path = request.resource_path(someobject)
url = request.route_url(
'blogentry',
'element1',
'element2',
_query={'a':'1'},
(continues on next page)

0.4. API Documentation 857


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


traverse=traversal_path,
)

It is only sensible to pass route_name if the route being named has a *remainder stararg
value such as *traverse. The remainder value will be ignored in the output otherwise.
By default, the resource path value will be passed as the name traverse when route_url
is called. You can influence this by passing a different route_remainder_name value
if the route has a different *stararg value at its end. For example if the route pattern you
want to replace has a *subpath stararg ala /foo*subpath:

request.resource_url(
resource,
route_name='myroute',
route_remainder_name='subpath'
)

If route_name is passed, it is also permissible to pass route_kw,


which will passed as additional keyword arguments to route_url. Say-
ing resource_url(someresource, 'element1', 'element2',
route_name='blogentry', route_kw={'id':'4'}, _query={'a':'1'})
is roughly equivalent to:

traversal_path = request.resource_path_tuple(someobject)
kw = {'id':'4', '_query':{'a':'1'}, 'traverse':traversal_path}
url = request.route_url(
'blogentry',
'element1',
'element2',
**kw,
)

If route_kw or route_remainder_name is passed, but route_name is not passed,


both route_kw and route_remainder_name will be ignored. If route_name is
passed, the __resource_url__ method of the resource passed is ignored uncondition-
ally. This feature is incompatible with resources which generate their own URLs.

If the resource used is the result of a traversal, it must be location-aware. The resource
can also be the context of a URL dispatch; contexts found this way do not need to be location-
aware.

858 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If a ’virtual root path’ is present in the request environment (the value of the WSGI
environ key HTTP_X_VHM_ROOT), and the resource was obtained via traversal, the URL
path will not include the virtual root prefix (it will be stripped off the left hand side of the
generated URL).

For backwards compatibility purposes, this method is also aliased as the model_url
method of request.

Changed in version 1.3: Added the app_url keyword argument.


Changed in version 1.5: Allow the query option to be a string to enable alternative encodings.
The anchor option will be escaped instead of using its raw string representation.
Added the route_name, route_kw, and route_remainder_name keyword argu-
ments.
Changed in version 1.9: If query or anchor are falsey (such as None or an empty string)
they will not be included in the generated url.
resource_path(resource, *elements, **kw)
Generates a path (aka a ’relative URL’, a URL minus the host, scheme, and port) for a resource.
This function accepts the same argument as pyramid.request.Request.
resource_url() and performs the same duty. It just omits the host, port, and
scheme information in the return value; only the script_name, path, query parameters, and
anchor data are present in the returned string.

Calling request.resource_path(resource) is the same as calling


request.resource_path(resource, app_url=request.script_name).
pyramid.request.Request.resource_path() is, in fact, implemented in terms
of pyramid.request.Request.resource_url() in just this way. As a result, any
app_url passed within the **kw values to route_path will be ignored. scheme, host,
and port are also ignored.

set_property(callable, name=None, reify=False)


Add a callable or a property descriptor to the request instance.
Properties, unlike attributes, are lazily evaluated by executing an underlying callable when
accessed. They can be useful for adding features to an object without any cost if those features
go unused.

0.4. API Documentation 859


The Pyramid Web Framework, Version 2.0.2

A property may also be reified via the pyramid.decorator.reify decorator by setting


reify=True, allowing the result of the evaluation to be cached. Thus the value of the
property is only computed once for the lifetime of the object.
callable can either be a callable that accepts the request as its single positional parameter,
or it can be a property descriptor.
If the callable is a property descriptor a ValueError will be raised if name is None
or reify is True.
If name is None, the name of the property will be computed from the name of the callable.

1 def _connect(request):
2 conn = request.registry.dbsession()
3 def cleanup(request):
4 # since version 1.5, request.exception is no
5 # longer eagerly cleared
6 if request.exception is not None:
7 conn.rollback()
8 else:
9 conn.commit()
10 conn.close()
11 request.add_finished_callback(cleanup)
12 return conn
13

14 @subscriber(NewRequest)
15 def new_request(event):
16 request = event.request
17 request.set_property(_connect, 'db', reify=True)

The subscriber doesn’t actually connect to the database, it just provides the API which, when
accessed via request.db, will create the connection. Thanks to reify, only one connection
is made per-request even if request.db is accessed many times.
This pattern provides a way to augment the request object without having to subclass it,
which can be useful for extension authors.
New in version 1.3.
localizer
A localizer which will use the current locale name to translate values.
New in version 1.5.
locale_name
The locale name of the current request as computed by the locale negotiator.
New in version 1.5.

860 CONTENTS
The Pyramid Web Framework, Version 2.0.2

property GET
Return a MultiDict containing all the variables from the QUERY_STRING.
property POST
Return a MultiDict containing all the variables from a form request. Returns an empty dict-like
object for non-form requests.
Form requests are typically POST requests, however any other requests with an appropriate
Content-Type are also supported.
ResponseClass
alias of Response
property accept
Property representing the Accept header.
(RFC 7231, section 5.3.2)
The header value in the request environ is parsed and a new object representing the header is
created every time we get the value of the property. (set and del change the header value in
the request environ, and do not involve parsing.)
property accept_charset
Property representing the Accept-Charset header.
(RFC 7231, section 5.3.3)
The header value in the request environ is parsed and a new object representing the header is
created every time we get the value of the property. (set and del change the header value in
the request environ, and do not involve parsing.)
property accept_encoding
Property representing the Accept-Encoding header.
(RFC 7231, section 5.3.4)
The header value in the request environ is parsed and a new object representing the header is
created every time we get the value of the property. (set and del change the header value in
the request environ, and do not involve parsing.)
property accept_language
Property representing the Accept-Language header.
(RFC 7231, section 5.3.5)
The header value in the request environ is parsed and a new object representing the header is
created every time we get the value of the property. (set and del change the header value in
the request environ, and do not involve parsing.)

0.4. API Documentation 861


The Pyramid Web Framework, Version 2.0.2

property application_url
The URL including SCRIPT_NAME (no PATH_INFO or query string)
as_bytes(skip_body=False)
Return HTTP bytes representing this request. If skip_body is True, exclude the body. If
skip_body is an integer larger than one, skip body only if its length is bigger than that number.
property authorization
Gets and sets the Authorization header (HTTP spec section 14.8). Converts it using
parse_auth and serialize_auth.
classmethod blank(path, environ=None, base_url=None, headers=None, POST=None,
**kw)
Create a blank request environ (and Request wrapper) with the given path (path should be
urlencoded), and any keys from environ.
The path will become path_info, with any query string split off and used.
All necessary keys will be added to the environ, but the values you pass in will take precedence.
If you pass in base_url then wsgi.url_scheme, HTTP_HOST, and SCRIPT_NAME will be
filled in from that value.
Any extra keyword will be passed to __init__.
property body
Return the content of the request body.
property body_file
Input stream of the request (wsgi.input). Setting this property resets the content_length and
seekable flag (unlike setting req.body_file_raw).
property body_file_raw
Gets and sets the wsgi.input key in the environment.
property body_file_seekable
Get the body of the request (wsgi.input) as a seekable file-like object. Middleware and routing
applications should use this attribute over .body_file.
If you access this value, CONTENT_LENGTH will also be updated.
property cache_control
Get/set/modify the Cache-Control header (HTTP spec section 14.9)
call_application(application, catch_exc_info=False)
Call the given WSGI application, returning (status_string, headerlist,
app_iter)
Be sure to call app_iter.close() if it’s there.

862 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If catch_exc_info is true, then returns (status_string, headerlist, app_iter,


exc_info), where the fourth item may be None, but won’t be if there was an exception. If
you don’t do this and there was an exception, the exception will be raised directly.
property client_addr
The effective client IP address as a string. If the HTTP_X_FORWARDED_FOR header exists
in the WSGI environ, this attribute returns the client IP address present in that header (e.g. if
the header value is 192.168.1.1, 192.168.1.2, the value will be 192.168.1.1).
If no HTTP_X_FORWARDED_FOR header is present in the environ at all, this attribute will
return the value of the REMOTE_ADDR header. If the REMOTE_ADDR header is unset, this
attribute will return the value None.

It is possible for user agents to put someone else’s IP or just any string in
HTTP_X_FORWARDED_FOR as it is a normal HTTP header. Forward proxies can
also provide incorrect values (private IP addresses etc). You cannot ”blindly” trust
the result of this method to provide you with valid data unless you’re certain that
HTTP_X_FORWARDED_FOR has the correct values. The WSGI server must be behind a
trusted proxy for this to be true.

property content_length
Gets and sets the Content-Length header (HTTP spec section 14.13). Converts it using
int.
property content_type
Return the content type, but leaving off any parameters (like charset, but also things like the
type in application/atom+xml; type=entry)
If you set this property, you can include parameters, or if you don’t include any parameters in
the value then existing parameters will be preserved.
property cookies
Return a dictionary of cookies as found in the request.
copy()
Copy the request and environment object.
This only does a shallow copy, except of wsgi.input
copy_body()
Copies the body, in cases where it might be shared with another request object and that is not
desired.
This copies the body either into a BytesIO object (through setting req.body) or a temporary
file.

0.4. API Documentation 863


The Pyramid Web Framework, Version 2.0.2

copy_get()
Copies the request and environment object, but turning this request into a GET along the way.
If this was a POST request (or any other verb) then it becomes GET, and the request body is
thrown away.
property date
Gets and sets the Date header (HTTP spec section 14.8). Converts it using HTTP date.
property domain
Returns the domain portion of the host value. Equivalent to:

domain = request.host
if ':' in domain and domain[-1] != ']': # Check for ] because of␣
,→IPv6

domain = domain.rsplit(':', 1)[0]

This will be equivalent to the domain portion of the HTTP_HOST value in the environment
if it exists, or the SERVER_NAME value in the environment if it doesn’t. For example, if the
environment contains an HTTP_HOST value of foo.example.com:8000, request.
domain will return foo.example.com.
Note that this value cannot be set on the request. To set the host value use webob.request.
Request.host() instead.
classmethod from_bytes(b)
Create a request from HTTP bytes data. If the bytes contain extra data after the request, raise
a ValueError.
classmethod from_file(fp)
Read a request from a file-like object (it must implement .read(size) and .
readline()).
It will read up to the end of the request, not the end of the file (unless the request is a POST
or PUT and has no Content-Length, in that case, the entire file is read).
This reads the request as represented by str(req); it may not read every valid HTTP request
properly.
get_response(application=None, catch_exc_info=False)
Like .call_application(application), except returns a response object with .
status, .headers, and .body attributes.
This will use self.ResponseClass to figure out the class of the response object to return.
If application is not given, this will send the request to self.
make_default_send_app()

864 CONTENTS
The Pyramid Web Framework, Version 2.0.2

property headers
All the request headers as a case-insensitive dictionary-like object.
property host
Host name provided in HTTP_HOST, with fall-back to SERVER_NAME
property host_port
The effective server port number as a string. If the HTTP_HOST header exists in the WSGI
environ, this attribute returns the port number present in that header. If the HTTP_HOST
header exists but contains no explicit port number: if the WSGI url scheme is ”https” , this
attribute returns ”443”, if the WSGI url scheme is ”http”, this attribute returns ”80” . If no
HTTP_HOST header is present in the environ at all, this attribute will return the value of the
SERVER_PORT header (which is guaranteed to be present).
property host_url
The URL through the host (no path)
property http_version
Gets and sets the SERVER_PROTOCOL key in the environment.
property identity
Return an opaque object identifying the current user or None if no user is authenticated or
there is no security policy in effect.
property if_match
Gets and sets the If-Match header (HTTP spec section 14.24). Converts it as a Etag.
property if_modified_since
Gets and sets the If-Modified-Since header (HTTP spec section 14.25). Converts it
using HTTP date.
property if_none_match
Gets and sets the If-None-Match header (HTTP spec section 14.26). Converts it as a
Etag.
property if_range
Gets and sets the If-Range header (HTTP spec section 14.27). Converts it using IfRange
object.
property if_unmodified_since
Gets and sets the If-Unmodified-Since header (HTTP spec section 14.28). Converts
it using HTTP date.
property is_authenticated
Return True if a user is authenticated for this request.

0.4. API Documentation 865


The Pyramid Web Framework, Version 2.0.2

property is_body_readable
webob.is_body_readable is a flag that tells us that we can read the input stream even though
CONTENT_LENGTH is missing.
property is_body_seekable
Gets and sets the webob.is_body_seekable key in the environment.
is_response(ob)
Return True if the object passed as ob is a valid response object, False otherwise.
property is_xhr
Is X-Requested-With header present and equal to XMLHttpRequest?
Note: this isn’t set by every XMLHttpRequest request, it is only set if you are using a Javascript
library that sets it (or you set the header yourself manually). Currently Prototype and jQuery
are known to set this header.
property json
Access the body of the request as JSON
property json_body
Access the body of the request as JSON
make_body_seekable()
This forces environ['wsgi.input'] to be seekable. That means that, the content is
copied into a BytesIO or temporary file and flagged as seekable, so that it will not be unnec-
essarily copied again.
After calling this method the .body_file is always seeked to the start of file and .content_length
is not None.
The choice to copy to BytesIO is made from self.request_body_tempfile_limit
make_tempfile()
Create a tempfile to store big request body. This API is not stable yet. A ’size’ argument might
be added.
property max_forwards
Gets and sets the Max-Forwards header (HTTP spec section 14.31). Converts it using int.
property method
Gets and sets the REQUEST_METHOD key in the environment.
property params
A dictionary-like object containing both the parameters from the query string and request
body.

866 CONTENTS
The Pyramid Web Framework, Version 2.0.2

property path
The path of the request, without host or query string
property path_info
Gets and sets the PATH_INFO key in the environment.
path_info_peek()
Returns the next segment on PATH_INFO, or None if there is no next segment. Doesn’t
modify the environment.
path_info_pop(pattern=None)
’Pops’ off the next segment of PATH_INFO, pushing it onto SCRIPT_NAME, and returning
the popped segment. Returns None if there is nothing left on PATH_INFO.
Does not return '' when there’s an empty segment (like /path//path); these segments
are just ignored.
Optional pattern argument is a regexp to match the return value before returning. If there
is no match, no changes are made to the request and None is returned.
property path_qs
The path of the request, without host but with query string
property path_url
The URL including SCRIPT_NAME and PATH_INFO, but not QUERY_STRING
property pragma
Gets and sets the Pragma header (HTTP spec section 14.32).
property query_string
Gets and sets the QUERY_STRING key in the environment.
property range
Gets and sets the Range header (HTTP spec section 14.35). Converts it using Range object.
property referer
Gets and sets the Referer header (HTTP spec section 14.36).
property referrer
Gets and sets the Referer header (HTTP spec section 14.36).
relative_url(other_url, to_application=False)
Resolve other_url relative to the request URL.
If to_application is True, then resolve it relative to the URL with only SCRIPT_NAME
property remote_addr
Gets and sets the REMOTE_ADDR key in the environment.

0.4. API Documentation 867


The Pyramid Web Framework, Version 2.0.2

property remote_host
Gets and sets the REMOTE_HOST key in the environment.
property remote_user
Gets and sets the REMOTE_USER key in the environment.
remove_conditional_headers(remove_encoding=True, remove_range=True,
remove_match=True, remove_modified=True)
Remove headers that make the request conditional.
These headers can cause the response to be 304 Not Modified, which in some cases you may
not want to be possible.
This does not remove headers like If-Match, which are used for conflict detection.
request_iface
alias of IRequest
property scheme
Gets and sets the wsgi.url_scheme key in the environment.
property script_name
Gets and sets the SCRIPT_NAME key in the environment.
send(application=None, catch_exc_info=False)
Like .call_application(application), except returns a response object with .
status, .headers, and .body attributes.
This will use self.ResponseClass to figure out the class of the response object to return.
If application is not given, this will send the request to self.
make_default_send_app()
property server_name
Gets and sets the SERVER_NAME key in the environment.
property server_port
Gets and sets the SERVER_PORT key in the environment. Converts it using int.
property text
Get/set the text value of the body
property upath_info
Gets and sets the PATH_INFO key in the environment.
property url
The full request URL, including QUERY_STRING

868 CONTENTS
The Pyramid Web Framework, Version 2.0.2

property url_encoding
Gets and sets the webob.url_encoding key in the environment.
property urlargs
Return any positional variables matched in the URL.
Takes values from environ['wsgiorg.routing_args']. Systems like routes set
this value.
property urlvars
Return any named variables matched in the URL.
Takes values from environ['wsgiorg.routing_args']. Systems like routes set
this value.
property uscript_name
Gets and sets the SCRIPT_NAME key in the environment.
property user_agent
Gets and sets the User-Agent header (HTTP spec section 14.43).

For information about the API of a multidict structure (such as that used as request.GET,
request.POST, and request.params), see pyramid.interfaces.IMultiDict.

apply_request_extensions(request)
Apply request extensions (methods and properties) to an instance of pyramid.interfaces.
IRequest. This method is dependent on the request containing a properly initialized registry.
After invoking this method, the request should have the methods and properties that were defined
using pyramid.config.Configurator.add_request_method().

class RequestLocalCache(creator=None)
A store that caches values during for the lifecycle of a request.
Wrapping Functions
Instantiate and use it to decorate functions that accept a request parameter. The result is cached and
returned in subsequent invocations of the function.

@RequestLocalCache()
def get_user(request):
result = ... # do some expensive computations
return result
(continues on next page)

0.4. API Documentation 869


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)

value = get_user(request)

# manipulate the cache directly


get_user.cache.clear(request)

The cache instance is attached to the resulting function as the cache attribute such that the function
may be used to manipulate the cache.
Wrapping Methods
A method can be used as the creator function but it needs to be bound to an instance such that it only
accepts one argument - the request. An easy way to do this is to bind the creator in the constructor
and then use get_or_create():

class SecurityPolicy:
def __init__(self):
self.identity_cache = RequestLocalCache(self.load_identity)

def load_identity(self, request):


result = ... # do some expensive computations
return result

def identity(self, request):


return self.identity_cache.get_or_create(request)

The cache maintains a weakref to each request and will release the cached values when the request
is garbage-collected. However, in most scenarios, it will release resources earlier via pyramid.
request.Request.add_finished_callback().
New in version 2.0.
clear(request)
Delete the value from the cache.
The cached value is returned or NO_VALUE.
get(request, default=NO_VALUE)
Return the value from the cache.
The cached value is returned or default.
get_or_create(request, creator=None)
Return the value from the cache. Compute if necessary.
If no value is cached then execute the creator, cache the result, and return it.

870 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The creator may be passed in as an argument or bound to the cache by decorating a function
or supplied as a constructor argument.
set(request, value)
Update the cache with a new value.

pyramid.response

class Response(body=None, status=None, headerlist=None, app_iter=None, content_type=None,


conditional_response=None, charset=<object object>, **kw)

property accept_ranges
Gets and sets the Accept-Ranges header (HTTP spec section 14.5).
property age
Gets and sets the Age header (HTTP spec section 14.6). Converts it using int.
property allow
Gets and sets the Allow header (HTTP spec section 14.7). Converts it using list.
property app_iter
Returns the app_iter of the response.
If body was set, this will create an app_iter from that body (a single-item list).
app_iter_range(start, stop)
Return a new app_iter built from the response app_iter, that serves up only the given
start:stop range.
property body
The body of the response, as a bytes. This will read in the entire app_iter if necessary.
property body_file
A file-like object that can be used to write to the body. If you passed in a list app_iter, that
app_iter will be modified by writes.
property cache_control
Get/set/modify the Cache-Control header (HTTP spec section 14.9).
property charset
Get/set the charset specified in Content-Type.
There is no checking to validate that a content_type actually allows for a charset
parameter.

0.4. API Documentation 871


The Pyramid Web Framework, Version 2.0.2

conditional_response_app(environ, start_response)
Like the normal __call__ interface, but checks conditional headers:
• If-Modified-Since (304 Not Modified; only on GET, HEAD)
• If-None-Match (304 Not Modified; only on GET, HEAD)
• Range (406 Partial Content; only on GET, HEAD)
property content_disposition
Gets and sets the Content-Disposition header (HTTP spec section 19.5.1).
property content_encoding
Gets and sets the Content-Encoding header (HTTP spec section 14.11).
property content_language
Gets and sets the Content-Language header (HTTP spec section 14.12). Converts it
using list.
property content_length
Gets and sets the Content-Length header (HTTP spec section 14.17). Converts it using
int.
property content_location
Gets and sets the Content-Location header (HTTP spec section 14.14).
property content_md5
Gets and sets the Content-MD5 header (HTTP spec section 14.14).
property content_range
Gets and sets the Content-Range header (HTTP spec section 14.16). Converts it using
ContentRange object.
property content_type
Get/set the Content-Type header. If no Content-Type header is set, this will return
None.
Changed in version 1.7: Setting a new Content-Type will remove all Content-Type
parameters and reset the charset to the default if the Content-Type is text/* or XML
(application/xml or */*+xml).
To preserve all Content-Type parameters, you may use the following code:

resp = Response()
params = resp.content_type_params
resp.content_type = 'application/something'
resp.content_type_params = params

872 CONTENTS
The Pyramid Web Framework, Version 2.0.2

property content_type_params
A dictionary of all the parameters in the content type.
(This is not a view, set to change, modifications of the dict will not be applied otherwise.)
copy()
Makes a copy of the response.
property date
Gets and sets the Date header (HTTP spec section 14.18). Converts it using HTTP date.
delete_cookie(name, path=’/’, domain=None)
Delete a cookie from the client. Note that path and domain must match how the cookie
was originally set.
This sets the cookie to the empty string, and max_age=0 so that it should expire immediately.
encode_content(encoding=’gzip’, lazy=False)
Encode the content with the given encoding (only gzip and identity are supported).
property etag
Gets and sets the ETag header (HTTP spec section 14.19). Converts it using Entity tag.
property expires
Gets and sets the Expires header (HTTP spec section 14.21). Converts it using HTTP date.
classmethod from_file(fp)
Reads a response from a file-like object (it must implement .read(size) and .
readline()).
It will read up to the end of the response, not the end of the file.
This reads the response as represented by str(resp); it may not read every valid HTTP
response properly. Responses must have a Content-Length.
property has_body
Determine if the the response has a body. In contrast to simply accessing body, this method
will not read the underlying app_iter.
property headerlist
The list of response headers.
property headers
The headers in a dictionary-like object.

0.4. API Documentation 873


The Pyramid Web Framework, Version 2.0.2

property json
Set/get the body of the response as JSON.

This will automatically decode() the body as UTF-8 on get, and encode() the
json.dumps() as UTF-8 before assigning to body.

property json_body
Set/get the body of the response as JSON.

This will automatically decode() the body as UTF-8 on get, and encode() the
json.dumps() as UTF-8 before assigning to body.

property last_modified
Gets and sets the Last-Modified header (HTTP spec section 14.29). Converts it using
HTTP date.
property location
Gets and sets the Location header (HTTP spec section 14.30).
md5_etag(body=None, set_content_md5=False)
Generate an etag for the response object using an MD5 hash of the body (the body parameter,
or self.body if not given).
Sets self.etag.
If set_content_md5 is True, sets self.content_md5 as well.
merge_cookies(resp)
Merge the cookies that were set on this response with the given resp object (which can be
any WSGI application).
If the resp is a webob.Response object, then the other object will be modified in-place.
property pragma
Gets and sets the Pragma header (HTTP spec section 14.32).
property retry_after
Gets and sets the Retry-After header (HTTP spec section 14.37). Converts it using HTTP
date or delta seconds.
property server
Gets and sets the Server header (HTTP spec section 14.38).

874 CONTENTS
The Pyramid Web Framework, Version 2.0.2

set_cookie(name, value=”, max_age=None, path=’/’, domain=None, secure=False,


httponly=False, comment=None, expires=None, overwrite=False,
samesite=None)
Set (add) a cookie for the response.
Arguments are:
name
The cookie name.
value
The cookie value, which should be a string or None. If value is None, it’s
equivalent to calling the webob.response.Response.unset_cookie()
method for this cookie key (it effectively deletes the cookie on the client).
max_age
An integer representing a number of seconds, datetime.timedelta, or
None. This value is used as the Max-Age of the generated cookie. If expires
is not passed and this value is not None, the max_age value will also influence
the Expires value of the cookie (Expires will be set to now + max_age). If
this value is None, the cookie will not have a Max-Age value (unless expires
is set). If both max_age and expires are set, this value takes precedence.
path
A string representing the cookie Path value. It defaults to /.
domain
A string representing the cookie Domain, or None. If domain is None, no Do-
main value will be sent in the cookie.
secure
A boolean. If it’s True, the secure flag will be sent in the cookie, if it’s False,
the secure flag will not be sent in the cookie.
httponly
A boolean. If it’s True, the HttpOnly flag will be sent in the cookie, if it’s
False, the HttpOnly flag will not be sent in the cookie.
samesite
A string representing the SameSite attribute of the cookie or None. If same-
site is None no SameSite value will be sent in the cookie. Should only be
"strict", "lax", or "none".
comment

0.4. API Documentation 875


The Pyramid Web Framework, Version 2.0.2

A string representing the cookie Comment value, or None. If comment is None,


no Comment value will be sent in the cookie.
expires
A datetime.timedelta object representing an amount of time, datetime.
datetime or None. A non-None value is used to generate the Expires value
of the generated cookie. If max_age is not passed, but this value is not None, it
will influence the Max-Age header. If this value is None, the Expires cookie
value will be unset (unless max_age is set). If max_age is set, it will be used to
generate the expires and this value is ignored.
If a datetime.datetime is provided it has to either be timezone aware or be
based on UTC. datetime.datetime objects that are local time are not sup-
ported. Timezone aware datetime.datetime objects are converted to UTC.
This argument will be removed in future versions of WebOb (version 1.9).
overwrite
If this key is True, before setting the cookie, unset any existing cookie.
property status
The status string.
property status_code
The status as an integer.
property status_int
The status as an integer.
property text
Get/set the text value of the body using the charset of the Content-Type or the de-
fault_body_encoding.
property ubody
Deprecated alias for .text
property unicode_body
Deprecated alias for .text
unset_cookie(name, strict=True)
Unset a cookie with the given name (remove it from the response).
property vary
Gets and sets the Vary header (HTTP spec section 14.44). Converts it using list.

876 CONTENTS
The Pyramid Web Framework, Version 2.0.2

property www_authenticate
Gets and sets the WWW-Authenticate header (HTTP spec section 14.47). Converts it
using parse_auth and serialize_auth.

class FileResponse(path, request=None, cache_max_age=None, content_type=None,


content_encoding=None)
A Response object that can be used to serve a static file from disk simply.
path is a file path on disk.
request must be a Pyramid request object. Note that a request must be passed if the response is
meant to attempt to use the wsgi.file_wrapper feature of the web server that you’re using to
serve your Pyramid application.
cache_max_age is the number of seconds that should be used to HTTP cache this response.
content_type is the content_type of the response.
content_encoding is the content_encoding of the response. It’s generally safe to leave this
set to None if you’re serving a binary file. This argument will be ignored if you also leave
content-type as None.

class FileIter(file, block_size=262144)


A fixed-block-size iterator for use as a WSGI app_iter.
file is a Python file pointer (or at least an object with a read method that takes a size hint).
block_size is an optional block size for iteration.

Functions

response_adapter(*types_or_ifaces, **kwargs)
Decorator activated via a scan which treats the function being decorated as a response adapter for
the set of types or interfaces passed as *types_or_ifaces to the decorator constructor.
For example, if you scan the following response adapter:

from pyramid.response import Response


from pyramid.response import response_adapter

@response_adapter(int)
def myadapter(i):
return Response(status=i)

0.4. API Documentation 877


The Pyramid Web Framework, Version 2.0.2

You can then return an integer from your view callables, and it will be converted into a response
with the integer as the status code.
More than one type or interface can be passed as a constructor argument. The decorated response
adapter will be called for each type or interface.

import json

from pyramid.response import Response


from pyramid.response import response_adapter

@response_adapter(dict, list)
def myadapter(ob):
return Response(json.dumps(ob))

This method will have no effect until a scan is performed agains the package or module which
contains it, ala:

from pyramid.config import Configurator


config = Configurator()
config.scan('somepackage_containing_adapters')

Two additional keyword arguments which will be passed to the venusian attach function are
_depth and _category.
_depth is provided for people who wish to reuse this class from another decorator. The default
value is 0 and should be specified relative to the response_adapter invocation. It will be
passed in to the venusian attach function as the depth of the callstack when Venusian checks if
the decorator is being used in a class or module context. It’s not often used, but it can be useful in
this circumstance.
_category sets the decorator category name. It can be useful in combination with the category
argument of scan to control which views should be processed.
See the venusian.attach() function in Venusian for more information about the _depth and
_category arguments.
Changed in version 1.9.1: Added the _depth and _category arguments.

878 CONTENTS
The Pyramid Web Framework, Version 2.0.2

pyramid.scripting

get_root(app, request=None)
Return a tuple composed of (root, closer) when provided a router instance as the app
argument. The root returned is the application root object. The closer returned is a callable
(accepting no arguments) that should be called when your scripting application is finished using the
root.
request is passed to the Pyramid application root factory to compute the root. If request
is None, a default will be constructed using the registry’s Request Factory via the pyramid.
interfaces.IRequestFactory.blank() method.

prepare(request=None, registry=None)
This function pushes data onto the Pyramid threadlocal stack (request and registry), making those
objects ’current’. It returns a dictionary useful for bootstrapping a Pyramid application in a scripting
environment.
request is passed to the Pyramid application root factory to compute the root. If request
is None, a default will be constructed using the registry’s Request Factory via the pyramid.
interfaces.IRequestFactory.blank() method.
If registry is not supplied, the last registry loaded from pyramid.config.
global_registries will be used. If you have loaded more than one Pyramid application
in the current process, you may not want to use the last registry loaded, thus you can search the
global_registries and supply the appropriate one based on your own criteria.
The function returns a dictionary composed of root, closer, registry, request and
root_factory. The root returned is the application’s root resource object. The closer re-
turned is a callable (accepting no arguments) that should be called when your scripting application
is finished using the root. registry is the resolved registry object. request is the request object
passed or the constructed request if no request is passed. root_factory is the root factory used
to construct the root.
This function may be used as a context manager to call the closer automatically:

registry = config.registry
with prepare(registry) as env:
request = env['request']
# ...

Changed in version 1.8: Added the ability to use the return value as a context manager.
Changed in version 2.0: Request finished callbacks added via pyramid.request.Request.
add_finished_callback() will be invoked by the closer.

0.4. API Documentation 879


The Pyramid Web Framework, Version 2.0.2

pyramid.security

Authentication API Functions

forget(request, **kw)
Return a sequence of header tuples (e.g. [('Set-Cookie', 'foo=abc')]) suitable for ’for-
getting’ the set of credentials possessed by the currently authenticated user. A common usage might
look like so within the body of a view function (response is assumed to be an WebOb -style
response object computed previously by the view code):

from pyramid.security import forget


headers = forget(request)
response.headerlist.extend(headers)
return response

If no security policy is in use, this function will always return an empty sequence.

remember(request, userid, **kw)


Returns a sequence of header tuples (e.g. [('Set-Cookie', 'foo=abc')]) on this request’s
response. These headers are suitable for ’remembering’ a set of credentials implied by the data
passed as userid and *kw using the current security policy. Common usage might look like so
within the body of a view function (response is assumed to be a WebOb -style response object
computed previously by the view code):

from pyramid.security import remember


headers = remember(request, 'chrism', password='123', max_age='86400')
response = request.response
response.headerlist.extend(headers)
return response

If no security policy is in use, this function will always return an empty sequence. If used, the
composition and meaning of **kw must be agreed upon by the calling code and the effective security
policy.
Changed in version 1.6: Deprecated the principal argument in favor of userid to clarify its
relationship to the security policy.
Changed in version 1.10: Removed the deprecated principal argument.

880 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Authorization API Functions

principals_allowed_by_permission(context, permission)
Deprecated since version 2.0: The new security policy has removed the concept of principals. See
upgrading_auth_20 for more information.
Provided a context (a resource object), and a permission string, if an authorization policy
is in effect, return a sequence of principal ids that possess the permission in the context. If
no authorization policy is in effect, this will return a sequence with the single value pyramid.
authorization.Everyone (the special principal identifier representing all principals).

Even if an authorization policy is in effect, some (exotic) authorization policies may not
implement the required machinery for this function; those will cause a NotImplementedError
exception to be raised when this function is invoked.

view_execution_permitted(context, request, name=”)


If the view specified by context and name is protected by a permission, check the permission as-
sociated with the view using the effective authentication/authorization policies and the request.
Return a boolean result. If no security policy is in effect, or if the view is not protected by a permis-
sion, return True. If no view can view found, an exception will be raised.
Changed in version 1.4a4: An exception is raised if no view is found.

Constants

NO_PERMISSION_REQUIRED
A special permission which indicates that the view should always be executable by entirely anony-
mous users, regardless of the default permission, bypassing any authorization policy that may be in
effect. Its actual value is the string '__no_permission_required__'.

Everyone
The special principal id named Everyone. This principal id is granted to all requests. Its actual
value is the string 'system.Everyone'.
Deprecated since version 2.0: Moved to pyramid.authorization.Everyone.

0.4. API Documentation 881


The Pyramid Web Framework, Version 2.0.2

Authenticated
The special principal id named Authenticated. This principal id is granted to all requests which
contain any other non-Everyone principal id (according to the authentication policy). Its actual value
is the string 'system.Authenticated'.
Deprecated since version 2.0: Moved to pyramid.authorization.Authenticated.

ALL_PERMISSIONS
An object that can be used as the permission member of an ACE which matches all permissions
unconditionally. For example, an ACE that uses ALL_PERMISSIONS might be composed like so:
('Deny', 'system.Everyone', ALL_PERMISSIONS).
Deprecated since version 2.0: Moved to pyramid.authorization.ALL_PERMISSIONS.

DENY_ALL
A convenience shorthand ACE that defines ('Deny', 'system.Everyone',
ALL_PERMISSIONS). This is often used as the last ACE in an ACL in systems that use
an ”inheriting” security policy, representing the concept ”don’t inherit any other ACEs”.
Deprecated since version 2.0: Moved to pyramid.authorization.DENY_ALL.

Return Values

Allow
The ACE ”action” (the first element in an ACE e.g. (Allow, Everyone, 'read') that means
allow access. A sequence of ACEs makes up an ACL. It is a string, and its actual value is 'Allow'.
Deprecated since version 2.0: Moved to pyramid.authorization.Allow.

Deny
The ACE ”action” (the first element in an ACE e.g. (Deny, 'george', 'read') that means
deny access. A sequence of ACEs makes up an ACL. It is a string, and its actual value is 'Deny'.
Deprecated since version 2.0: Moved to pyramid.authorization.Deny.

class Denied(s, *args)


An instance of Denied is returned when a security-related API or other Pyramid code denies an
action unrelated to an ACL check. It evaluates equal to all boolean false types. It has an attribute
named msg describing the circumstances for the deny.

882 CONTENTS
The Pyramid Web Framework, Version 2.0.2

static __new__(cls, s, *args)


Create a new instance.
Parameters
• fmt -- A format string explaining the reason for denial.
• args -- Arguments are stored and used with the format string to generate
the msg.
property msg
A string indicating why the result was generated.

class Allowed(s, *args)


An instance of Allowed is returned when a security-related API or other Pyramid code allows an
action unrelated to an ACL check. It evaluates equal to all boolean true types. It has an attribute
named msg describing the circumstances for the allow.
static __new__(cls, s, *args)
Create a new instance.
Parameters
• fmt -- A format string explaining the reason for denial.
• args -- Arguments are stored and used with the format string to generate
the msg.
property msg
A string indicating why the result was generated.

class ACLDenied(ace, acl, permission, principals, context)


An instance of ACLDenied is a specialization of pyramid.security.Denied that represents
that a security check made explicitly against ACL was denied. It evaluates equal to all boolean
false types. It also has the following attributes: acl, ace, permission, principals, and
context. These attributes indicate the security values involved in the request. Its __str__
method prints a summary of these attributes for debugging purposes. The same summary is available
as the msg attribute.
Deprecated since version 2.0: Moved to pyramid.authorization.
ACLDenied.
static __new__(cls, ace, acl, permission, principals, context)
Create a new instance.
Parameters
• ace -- The ACE that matched, triggering the result.

0.4. API Documentation 883


The Pyramid Web Framework, Version 2.0.2

• acl -- The ACL containing ace.


• permission -- The required permission.
• principals -- The list of principals provided.
• context -- The context providing the lineage searched.
property msg
A string indicating why the result was generated.

class ACLAllowed(ace, acl, permission, principals, context)


An instance of ACLAllowed is a specialization of pyramid.security.Allowed that rep-
resents that a security check made explicitly against ACL was allowed. It evaluates equal to all
boolean true types. It also has the following attributes: acl, ace, permission, principals,
and context. These attributes indicate the security values involved in the request. Its __str__
method prints a summary of these attributes for debugging purposes. The same summary is available
as the msg attribute.
Deprecated since version 2.0: Moved to pyramid.authorization.
ACLAllowed.
static __new__(cls, ace, acl, permission, principals, context)
Create a new instance.
Parameters
• ace -- The ACE that matched, triggering the result.
• acl -- The ACL containing ace.
• permission -- The required permission.
• principals -- The list of principals provided.
• context -- The context providing the lineage searched.
property msg
A string indicating why the result was generated.

pyramid.session

SignedCookieSessionFactory(secret, cookie_name=’session’, max_age=None, path=’/’,


domain=None, secure=False, httponly=False, samesite=’Lax’,
set_on_exception=True, timeout=1200, reissue_time=0,
hashalg=’sha512’, salt=’pyramid.session.’, serializer=None)

884 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Configure a session factory which will provide signed cookie-based sessions. The return value of
this function is a session factory, which may be provided as the session_factory argument of
a pyramid.config.Configurator constructor, or used as the session_factory argu-
ment of the pyramid.config.Configurator.set_session_factory() method.
The session factory returned by this function will create sessions which are limited to storing fewer
than 4000 bytes of data (as the payload must fit into a single cookie).
Parameters:
secret
A string which is used to sign the cookie. The secret should be at least as long as the block
size of the selected hash algorithm. For sha512 this would mean a 512 bit (64 character)
secret. It should be unique within the set of secret values provided to Pyramid for its various
subsystems (see Admonishment Against Secret-Sharing).
hashalg
The HMAC digest algorithm to use for signing. The algorithm must be supported by the
hashlib library. Default: 'sha512'.
salt
A namespace to avoid collisions between different uses of a shared secret. Reusing a secret for
different parts of an application is strongly discouraged (see Admonishment Against Secret-
Sharing). Default: 'pyramid.session.'.
cookie_name
The name of the cookie used for sessioning. Default: 'session'.
max_age
The maximum age of the cookie used for sessioning (in seconds). Default: None (browser
scope).
path
The path used for the session cookie. Default: '/'.
domain
The domain used for the session cookie. Default: None (no domain).
secure
The ’secure’ flag of the session cookie. Default: False.
httponly
Hide the cookie from Javascript by setting the ’HttpOnly’ flag of the session cookie. Default:
False.
samesite
The ’samesite’ option of the session cookie. Set the value to None to turn off the samesite
option. Default: 'Lax'.

0.4. API Documentation 885


The Pyramid Web Framework, Version 2.0.2

timeout
A number of seconds of inactivity before a session times out. If None then the cookie never
expires. This lifetime only applies to the value within the cookie. Meaning that if the cookie
expires due to a lower max_age, then this setting has no effect. Default: 1200.
reissue_time
The number of seconds that must pass before the cookie is automatically reissued as the result
of accessing the session. The duration is measured as the number of seconds since the last
session cookie was issued and ’now’. If this value is 0, a new cookie will be reissued on every
request accessing the session. If None then the cookie’s lifetime will never be extended.
A good rule of thumb: if you want auto-expired cookies based on inactivity: set the time-
out value to 1200 (20 mins) and set the reissue_time value to perhaps a tenth of the
timeout value (120 or 2 mins). It’s nonsensical to set the timeout value lower than the
reissue_time value, as the ticket will never be reissued. However, such a configuration
is not explicitly prevented.
Default: 0.
set_on_exception
If True, set a session cookie even if an exception occurs while rendering a view. Default:
True.
serializer
An object with two methods: loads and dumps. The loads method should accept bytes
and return a Python object. The dumps method should accept a Python object and return
bytes. A ValueError should be raised for malformed inputs. If a serializer is not passed,
the pyramid.session.JSONSerializer serializer will be used.

In Pyramid 2.0 the default serializer option changed to use pyramid.session.


JSONSerializer. See upgrading_session_20 for more information about why this change
was made.

BaseCookieSessionFactory(serializer, cookie_name=’session’, max_age=None, path=’/’,


domain=None, secure=False, httponly=False, samesite=’Lax’,
timeout=1200, reissue_time=0, set_on_exception=True)
Configure a session factory which will provide cookie-based sessions. The return value of this
function is a session factory, which may be provided as the session_factory argument of
a pyramid.config.Configurator constructor, or used as the session_factory argu-
ment of the pyramid.config.Configurator.set_session_factory() method.
The session factory returned by this function will create sessions which are limited to storing fewer
than 4000 bytes of data (as the payload must fit into a single cookie).
Parameters:

886 CONTENTS
The Pyramid Web Framework, Version 2.0.2

serializer
An object with two methods: loads and dumps. The loads method should accept bytes
and return a Python object. The dumps method should accept a Python object and return
bytes. A ValueError should be raised for malformed inputs.
cookie_name
The name of the cookie used for sessioning. Default: 'session'.
max_age
The maximum age of the cookie used for sessioning (in seconds). Default: None (browser
scope).
path
The path used for the session cookie. Default: '/'.
domain
The domain used for the session cookie. Default: None (no domain).
secure
The ’secure’ flag of the session cookie. Default: False.
httponly
Hide the cookie from Javascript by setting the ’HttpOnly’ flag of the session cookie. Default:
False.
samesite
The ’samesite’ option of the session cookie. Set the value to None to turn off the samesite
option. Default: 'Lax'.
timeout
A number of seconds of inactivity before a session times out. If None then the cookie never
expires. This lifetime only applies to the value within the cookie. Meaning that if the cookie
expires due to a lower max_age, then this setting has no effect. Default: 1200.
reissue_time
The number of seconds that must pass before the cookie is automatically reissued as the result
of a request which accesses the session. The duration is measured as the number of seconds
since the last session cookie was issued and ’now’. If this value is 0, a new cookie will be
reissued on every request accessing the session. If None then the cookie’s lifetime will never
be extended.
A good rule of thumb: if you want auto-expired cookies based on inactivity: set the time-
out value to 1200 (20 mins) and set the reissue_time value to perhaps a tenth of the
timeout value (120 or 2 mins). It’s nonsensical to set the timeout value lower than the
reissue_time value, as the ticket will never be reissued. However, such a configuration
is not explicitly prevented.
Default: 0.

0.4. API Documentation 887


The Pyramid Web Framework, Version 2.0.2

set_on_exception
If True, set a session cookie even if an exception occurs while rendering a view. Default:
True.

class JSONSerializer
A serializer which uses json.dumps‘ and json.loads

class PickleSerializer(protocol=5)
Deprecated since version 2.0.

In Pyramid 2.0 the default serializer option changed to use pyramid.session.


JSONSerializer, and PickleSerializer has been been removed from active Pyramid
code.
Pyramid will require JSON-serializable objects in Pyramid 2.0.
Please see upgrading_session_20.

A serializer that uses the pickle protocol to dump Python data to bytes.
This was the default serializer used by Pyramid, but has been deprecated.
protocol may be specified to control the version of pickle used. Defaults to pickle.
HIGHEST_PROTOCOL.

pyramid.settings

asbool(s)
Return the boolean value True if the case-lowered value of string input s is a truthy string. If s is
already one of the boolean values True or False, return it.

aslist(value, flatten=True)
Return a list, separating the input based on newlines. Also if flatten is True (the default), and
if the line is a string, then the line will be split on spaces.

888 CONTENTS
The Pyramid Web Framework, Version 2.0.2

pyramid.static

class static_view(root_dir, cache_max_age=3600, package_name=None, use_subpath=False,


index=’index.html’, reload=False, content_encodings=())
An instance of this class is a callable which can act as a Pyramid view callable; this view will serve
static files from a directory on disk based on the root_dir you provide to its constructor.
The directory may contain subdirectories (recursively); the static view implementation will descend
into these directories as necessary based on the components of the URL in order to resolve a path
into a response.
You may pass an absolute or relative filesystem path or a asset specification representing the directory
containing static files as the root_dir argument to this class’ constructor.
If the root_dir path is relative, and the package_name argument is None, root_dir will
be considered relative to the directory in which the Python file which calls static resides. If
the package_name name argument is provided, and a relative root_dir is provided, the
root_dir will be considered relative to the Python package specified by package_name (a
dotted path to a Python package).
cache_max_age influences the Expires and Max-Age response headers returned by the view
(default is 3600 seconds or one hour).
use_subpath influences whether request.subpath will be used as PATH_INFO when call-
ing the underlying WSGI application which actually serves the static files. If it is True, the static
application will consider request.subpath as PATH_INFO input. If it is False, the static
application will consider request.environ[PATH_INFO] as PATH_INFO input. By default, this is
False.
reload controls whether a cache of files is maintained or the asset subsystem is queried per-request
to determine what files are available. By default, this is False and new files added while the process
is running are not recognized.
content_encodings is a list of alternative file encodings supported in the
Accept-Encoding HTTP Header. Alternative files are found using file extensions de-
fined in mimetypes.encodings_map. An encoded asset will be returned with the
Content-Encoding header set to the selected encoding. If the asset contains alternative
encodings then the Accept-Encoding value will be added to the response’s Vary header. By
default, the list is empty and no alternatives will be supported.

If the root_dir is relative to a package, or is a asset specification the Pyramid pyramid.


config.Configurator method can be used to override assets within the named root_dir
package-relative directory. However, if the root_dir is absolute, configuration will not be able to
override the assets it contains.

0.4. API Documentation 889


The Pyramid Web Framework, Version 2.0.2

Changed in version 2.0: Added reload and content_encodings options.


find_best_match(request, files)
Return (path | None, encoding).
find_resource_path(name)
Return the absolute path to the resource or None if it doesn’t exist.
get_possible_files(resource_name)
Return a sorted list of (size, encoding, path) entries.
get_resource_name(request)
Return the computed name of the requested resource.
The returned file is not guaranteed to exist.

class ManifestCacheBuster(manifest_spec, reload=False)


An implementation of ICacheBuster which uses a supplied manifest file to map an asset path to
a cache-busted version of the path.
The manifest_spec can be an absolute path or a asset specification pointing to a package-relative
file.
The manifest file is expected to conform to the following simple JSON format:

{
"css/main.css": "css/main-678b7c80.css",
"images/background.png": "images/background-a8169106.png",
}

By default, it is a JSON-serialized dictionary where the keys are the source asset paths used in calls
to static_url(). For example:

>>> request.static_url('myapp:static/css/main.css')
"http://www.example.com/static/css/main-678b7c80.css"

The file format and location can be changed by subclassing and overriding parse_manifest().
If a path is not found in the manifest it will pass through unchanged.
If reload is True then the manifest file will be reloaded when changed. It is not recommended
to leave this enabled in production.
If the manifest file cannot be found on disk it will be treated as an empty mapping unless reload
is False.
New in version 1.6.

890 CONTENTS
The Pyramid Web Framework, Version 2.0.2

static exists(path)
Test whether a path exists. Returns False for broken symbolic links
static getmtime(filename)
Return the last modification time of a file, reported by os.stat().
property manifest
The current manifest dictionary.
parse_manifest(content)
Parse the content read from the manifest_path into a dictionary mapping.
Subclasses may override this method to use something other than json.loads to load any
type of file format and return a conforming dictionary.

class QueryStringCacheBuster(param=’x’)
An implementation of ICacheBuster which adds a token for cache busting in the query string
of an asset URL.
The optional param argument determines the name of the parameter added to the query string and
defaults to 'x'.
To use this class, subclass it and provide a tokenize method which accepts request,
pathspec, kw and returns a token.
New in version 1.6.

class QueryStringConstantCacheBuster(token, param=’x’)


An implementation of ICacheBuster which adds an arbitrary token for cache busting in the
query string of an asset URL.
The token parameter is the token string to use for cache busting and will be the same for every
request.
The optional param argument determines the name of the parameter added to the query string and
defaults to 'x'.
New in version 1.6.

pyramid.testing

0.4. API Documentation 891


The Pyramid Web Framework, Version 2.0.2

setUp(registry=None, request=None, hook_zca=True, autocommit=True, settings=None,


package=None)
Set Pyramid registry and request thread locals for the duration of a single unit test.
Use this function in the setUp method of a unittest test case which directly or indirectly uses:
• any method of the pyramid.config.Configurator object returned by this function.
• the pyramid.threadlocal.get_current_registry() or pyramid.
threadlocal.get_current_request() functions.
If you use the get_current_* functions (or call Pyramid code that uses these functions) without
calling setUp, pyramid.threadlocal.get_current_registry() will return a global
application registry, which may cause unit tests to not be isolated with respect to registrations they
perform.
If the registry argument is None, a new empty application registry will be created (an instance
of the pyramid.registry.Registry class). If the registry argument is not None, the
value passed in should be an instance of the pyramid.registry.Registry class or a suitable
testing analogue.
After setUp is finished, the registry returned by the pyramid.threadlocal.
get_current_registry() function will be the passed (or constructed) registry until
pyramid.testing.tearDown() is called (or pyramid.testing.setUp() is called
again) .
If the hook_zca argument is True, setUp will attempt to perform the operation
zope.component.getSiteManager.sethook( pyramid.threadlocal.
get_current_registry), which will cause the Zope Component Architecture global
API (e.g. zope.component.getSiteManager(), zope.component.getAdapter(),
and so on) to use the registry constructed by setUp as the value it returns from zope.
component.getSiteManager(). If the zope.component package cannot be imported,
or if hook_zca is False, the hook will not be set.
If settings is not None, it must be a dictionary representing the values passed to a Configurator
as its settings= argument.
If package is None it will be set to the caller’s package. The package setting in the
pyramid.config.Configurator will affect any relative imports made via pyramid.
config.Configurator.include() or pyramid.config.Configurator.
maybe_dotted().
This function returns an instance of the pyramid.config.Configurator class, which
can be used for further configuration to set up an environment suitable for a unit or integra-
tion test. The registry attribute attached to the Configurator instance represents the ’cur-
rent’ application registry; the same registry will be returned by pyramid.threadlocal.
get_current_registry() during the execution of the test.

892 CONTENTS
The Pyramid Web Framework, Version 2.0.2

tearDown(unhook_zca=True)
Undo the effects of pyramid.testing.setUp(). Use this function in the tearDown method
of a unit test that uses pyramid.testing.setUp() in its setUp method.
If the unhook_zca argument is True (the default), call zope.component.
getSiteManager.reset(). This undoes the action of pyramid.testing.setUp()
when called with the argument hook_zca=True. If zope.component cannot be imported,
unhook_zca is set to False.

testConfig(registry=None, request=None, hook_zca=True, autocommit=True, settings=None)


Returns a context manager for test set up.
This context manager calls pyramid.testing.setUp() when entering and pyramid.
testing.tearDown() when exiting.
All arguments are passed directly to pyramid.testing.setUp(). If the ZCA is hooked, it
will always be un-hooked in tearDown.
This context manager allows you to write test code like this:

1 with testConfig() as config:


2 config.add_route('bar', '/bar/{id}')
3 req = DummyRequest()
4 resp = myview(req)

cleanUp(*arg, **kw)
An alias for pyramid.testing.setUp().

class DummyResource(__name__=None, __parent__=None, __provides__=None, **kw)


A dummy Pyramid resource object.
clone(__name__=<object object>, __parent__=<object object>, **kw)
Create a clone of the resource object. If __name__ or __parent__ arguments are passed,
use these values to override the existing __name__ or __parent__ of the resource. If
any extra keyword args are passed in via the kw argument, use these keywords to add to or
override existing resource keywords (attributes).
items()
Return the items set by __setitem__
keys()
Return the keys set by __setitem__
values()
Return the values set by __setitem__

0.4. API Documentation 893


The Pyramid Web Framework, Version 2.0.2

class DummyRequest(params=None, environ=None, headers=None, path=’/’, cookies=None,


post=None, accept=None, **kw)
A DummyRequest object (incompletely) imitates a request object.
The params, environ, headers, path, and cookies arguments correspond to their WebOb
equivalents.
The post argument, if passed, populates the request’s POST attribute, but not params, in order
to allow testing that the app accepts data for a given view only from POST requests. This argument
also sets self.method to ”POST”.
Extra keyword arguments are assigned as attributes of the request itself.
Note that DummyRequest does not have complete fidelity with a ”real” request. For example, by
default, the DummyRequest GET and POST attributes are of type dict, unlike a normal Request’s
GET and POST, which are of type MultiDict. If your code uses the features of MultiDict, you
should either use a real pyramid.request.Request or adapt your DummyRequest by replac-
ing the attributes with MultiDict instances.
Other similar incompatibilities exist. If you need all the features of a Request, use the pyramid.
request.Request class itself rather than this class while writing tests.
request_iface
alias of IRequest
class DummyTemplateRenderer(string_response=”)
An instance of this class is returned from pyramid.config.Configurator.
testing_add_renderer(). It has a helper function (assert_) that makes it possible
to make an assertion which compares data passed to the renderer by the view function against
expected key/value pairs.
assert_(**kw)
Accept an arbitrary set of assertion key/value pairs. For each assertion key/value pair assert
that the renderer (eg. pyramid.renderers.render_to_response()) received the
key with a value that equals the asserted value. If the renderer did not receive the key at all, or
the value received by the renderer doesn’t match the assertion value, raise an Assertion-
Error.

pyramid.threadlocal

get_current_request()
Return the currently active request or None if no request is currently active.
This function should be used extremely sparingly, usually only in unit testing code. It’s almost
always usually a mistake to use get_current_request outside a testing context because its
usage makes it possible to write code that can be neither easily tested nor scripted.

894 CONTENTS
The Pyramid Web Framework, Version 2.0.2

get_current_registry()
Return the currently active application registry or the global application registry if no request is
currently active.
This function should be used extremely sparingly, usually only in unit testing code. It’s almost always
usually a mistake to use get_current_registry outside a testing context because its usage
makes it possible to write code that can be neither easily tested nor scripted.

pyramid.traversal

find_interface(resource, class_or_interface)
Return the first resource found in the lineage of resource which, a) if class_or_interface
is a Python class object, is an instance of the class or any subclass of that class or b) if
class_or_interface is a interface, provides the specified interface. Return None if no re-
source providing interface_or_class can be found in the lineage. The resource passed
in must be location-aware.

find_resource(resource, path)
Given a resource object and a string or tuple representing a path (such as the re-
turn value of pyramid.traversal.resource_path() or pyramid.traversal.
resource_path_tuple()), return a resource in this application’s resource tree at the specified
path. The resource passed in must be location-aware. If the path cannot be resolved (if the respective
node in the resource tree does not exist), a KeyError will be raised.
This function is the logical inverse of pyramid.traversal.resource_path() and
pyramid.traversal.resource_path_tuple(); it can resolve any path string or tuple
generated by either of those functions.
Rules for passing a string as the path argument: if the first character in the path string is the /
character, the path is considered absolute and the resource tree traversal will start at the root re-
source. If the first character of the path string is not the / character, the path is considered relative
and resource tree traversal will begin at the resource object supplied to the function as the re-
source argument. If an empty string is passed as path, the resource passed in will be re-
turned. Resource path strings must be escaped in the following manner: each path segment must be
UTF-8 encoded and escaped via Python’s urllib.quote. For example, /path/to%20the/
La%20Pe%C3%B1a (absolute) or to%20the/La%20Pe%C3%B1a (relative). The pyramid.
traversal.resource_path() function generates strings which follow these rules (albeit
only absolute ones). The text may not have any non-ASCII characters in it.
Rules for passing a tuple as the path argument: if the first element in the path tuple is the empty
string (for example ('', 'a', 'b', 'c'), the path is considered absolute and the resource
tree traversal will start at the resource tree root object. If the first element in the path tuple is not
the empty string (for example ('a', 'b', 'c')), the path is considered relative and resource

0.4. API Documentation 895


The Pyramid Web Framework, Version 2.0.2

tree traversal will begin at the resource object supplied to the function as the resource argument.
If an empty sequence is passed as path, the resource passed in itself will be returned. No
URL-quoting of individual path segments within the tuple is required (each segment may be any
string representing a resource name). Resource path tuples generated by pyramid.traversal.
resource_path_tuple() can always be resolved by find_resource.

find_root(resource)
Find the root node in the resource tree to which resource belongs. Note that resource should
be location-aware. Note that the root resource is available in the request object by accessing the
request.root attribute.

resource_path(resource, *elements)
Return a string object representing the absolute physical path of the resource object based on its
position in the resource tree, e.g /foo/bar. Any positional arguments passed in as elements
will be appended as path segments to the end of the resource path. For instance, if the resource’s
path is /foo/bar and elements equals ('a', 'b'), the returned string will be /foo/bar/
a/b. The first character in the string will always be the / character (a leading / character in a path
string represents that the path is absolute).
Resource path strings returned will be escaped in the following manner: each path segment
will be encoded as UTF-8 and escaped via Python’s urllib.quote. For example, /path/
to%20the/La%20Pe%C3%B1a.
This function is a logical inverse of pyramid.traversal.find_resource: it can be used
to generate path references that can later be resolved via that function.
The resource passed in must be location-aware.

Each segment in the path string returned will use the __name__ attribute of the resource it
represents within the resource tree. Each of these segments should be a string (as per the contract
of location-awareness). However, no conversion or safety checking of resource names is performed.
For instance, if one of the resources in your tree has a __name__ which (by error) is a dictionary,
the pyramid.traversal.resource_path() function will attempt to append it to a string
and it will cause a pyramid.exceptions.URLDecodeError.

The root resource must have a __name__ attribute with a value of either None or the empty
string for paths to be generated properly. If the root resource has a non-null __name__ attribute,
its name will be prepended to the generated path rather than a single leading ’/’ character.

896 CONTENTS
The Pyramid Web Framework, Version 2.0.2

resource_path_tuple(resource, *elements)
Return a tuple representing the absolute physical path of the resource object based on its po-
sition in a resource tree, e.g ('', 'foo', 'bar'). Any positional arguments passed in as
elements will be appended as elements in the tuple representing the resource path. For instance,
if the resource’s path is ('', 'foo', 'bar') and elements equals ('a', 'b'), the returned
tuple will be ('', 'foo', 'bar', 'a', 'b'). The first element of this tuple will always be
the empty string (a leading empty string element in a path tuple represents that the path is absolute).
This function is a logical inverse of pyramid.traversal.find_resource(): it can be used
to generate path references that can later be resolved by that function.
The resource passed in must be location-aware.

Each segment in the path tuple returned will equal the __name__ attribute of the resource it
represents within the resource tree. Each of these segments should be a string (as per the contract
of location-awareness). However, no conversion or safety checking of resource names is performed.
For instance, if one of the resources in your tree has a __name__ which (by error) is a dictionary,
that dictionary will be placed in the path tuple; no warning or error will be given.

The root resource must have a __name__ attribute with a value of either None or the
empty string for path tuples to be generated properly. If the root resource has a non-null __name__
attribute, its name will be the first element in the generated path tuple rather than the empty string.

quote_path_segment(segment, safe=”~!$&’()*+,;=:@”)
Return a quoted representation of a ’path segment’ (such as the string __name__ attribute of a
resource) as a string. If the segment passed in is a bytes object, it is decoded as a UTF-8 string.
The result is then URL-quoted using Python’s urllib.quote. If the segment passed in is not
bytes nor a string, an error will be raised. The return value of quote_path_segment is always
a string.
You may pass a string of characters that need not be encoded as the safe argument to this function.
This corresponds to the safe argument to urllib.quote.

The return value for each segment passed to this function is cached in a module-scope dic-
tionary for speed: the cached version is returned when possible rather than recomputing the quoted
version. No cache emptying is ever done for the lifetime of an application, however. If you pass
arbitrary user-supplied strings to this function (as opposed to some bounded set of values from a
’working set’ known to your application), it may become a memory leak.

0.4. API Documentation 897


The Pyramid Web Framework, Version 2.0.2

virtual_root(resource, request)
Provided any resource and a request object, return the resource object representing the virtual root
of the current request. Using a virtual root in a traversal -based Pyramid application permits rooting.
For example, the resource at the traversal path /cms will be found at http://example.com/
instead of rooting it at http://example.com/cms/.
If the resource passed in is a context obtained via traversal, and if the HTTP_X_VHM_ROOT
key is in the WSGI environment, the value of this key will be treated as a ’virtual root path’: the
pyramid.traversal.find_resource() API will be used to find the virtual root resource
using this path; if the resource is found, it will be returned. If the HTTP_X_VHM_ROOT key is not
present in the WSGI environment, the physical root of the resource tree will be returned instead.
Virtual roots are not useful at all in applications that use URL dispatch. Contexts obtained via
URL dispatch don’t really support being virtually rooted (each URL dispatch context is both its own
physical and virtual root). However if this API is called with a resource argument which is a
context obtained via URL dispatch, the resource passed in will be returned unconditionally.

traverse(resource, path)
Given a resource object as resource and a string or tuple representing a path as path (such as
the return value of pyramid.traversal.resource_path() or pyramid.traversal.
resource_path_tuple() or the value of request.environ['PATH_INFO']), return
a dictionary with the keys context, root, view_name, subpath, traversed, vir-
tual_root, and virtual_root_path.
A definition of each value in the returned dictionary:
• context: The context (a resource object) found via traversal or URL dispatch. If the path
passed in is the empty string, the value of the resource argument passed to this function is
returned.
• root: The resource object at which traversal begins. If the resource passed in was found
via URL dispatch or if the path passed in was relative (non-absolute), the value of the re-
source argument passed to this function is returned.
• view_name: The view name found during traversal or URL dispatch; if the resource was
found via traversal, this is usually a representation of the path segment which directly follows
the path to the context in the path. The view_name will be a string. The view_name
will be the empty string if there is no element which follows the context path. An example:
if the path passed is /foo/bar, and a resource object is found at /foo (but not at /foo/
bar), the ’view name’ will be 'bar'. If the resource was found via URL dispatch, the
view_name will be the empty string unless the traverse predicate was specified or the
*traverse route pattern was used, at which point normal traversal rules dictate the result.
• subpath: For a resource found via traversal, this is a sequence of path segments found
in the path that follow the view_name (if any). Each of these items is a string. If no path
segments follow the view_name, the subpath will be the empty sequence. An example: if
the path passed is /foo/bar/baz/buz, and a resource object is found at /foo (but not

898 CONTENTS
The Pyramid Web Framework, Version 2.0.2

/foo/bar), the ’view name’ will be 'bar' and the subpath will be ['baz', 'buz'].
For a resource found via URL dispatch, the subpath will be a sequence of values discerned
from *subpath in the route pattern matched or the empty sequence.
• traversed: The sequence of path elements traversed from the root to find the context
object during traversal. Each of these items is a string. If no path segments were traversed to
find the context object (e.g. if the path provided is the empty string), the traversed
value will be the empty sequence. If the resource is a resource found via URL dispatch,
traversed will be None.
• virtual_root: A resource object representing the ’virtual’ root of the resource tree being
traversed during traversal. See Virtual Hosting for a definition of the virtual root object. If
no virtual hosting is in effect, and the path passed in was absolute, the virtual_root
will be the physical root resource object (the object at which traversal begins). If the re-
source passed in was found via URL dispatch or if the path passed in was relative, the
virtual_root will always equal the root object (the resource passed in).
• virtual_root_path -- If traversal was used to find the resource, this will be the
sequence of path elements traversed to find the virtual_root resource. Each of these
items is a string. If no path segments were traversed to find the virtual_root resource
(e.g. if virtual hosting is not in effect), the traversed value will be the empty list. If URL
dispatch was used to find the resource, this will be None.
If the path cannot be resolved, a KeyError will be raised.
Rules for passing a string as the path argument: if the first character in the path string is the
with the / character, the path will considered absolute and the resource tree traversal will start at
the root resource. If the first character of the path string is not the / character, the path is con-
sidered relative and resource tree traversal will begin at the resource object supplied to the func-
tion as the resource argument. If an empty string is passed as path, the resource passed
in will be returned. Resource path strings must be escaped in the following manner: each path
segment must be encoded as UTF-8 and escaped via Python’s urllib.quote. For example,
/path/to%20the/La%20Pe%C3%B1a (absolute) or to%20the/La%20Pe%C3%B1a (rela-
tive). The pyramid.traversal.resource_path() function generates strings which follow
these rules (albeit only absolute ones).
Rules for passing a tuple as the path argument: if the first element in the path tuple is the empty
string (for example ('', 'a', 'b', 'c'), the path is considered absolute and the resource
tree traversal will start at the resource tree root object. If the first element in the path tuple is not the
empty string (for example ('a', 'b', 'c')), the path is considered relative and resource tree
traversal will begin at the resource object supplied to the function as the resource argument. If
an empty sequence is passed as path, the resource passed in itself will be returned. No URL-
quoting or UTF-8-encoding of individual path segments within the tuple is required (each segment
may be any string representing a resource name).
Explanation of the decoding of path segment values during traversal: Each segment is URL-
unquoted, and UTF-8 decoded. Each segment is assumed to be encoded using the UTF-8 encoding

0.4. API Documentation 899


The Pyramid Web Framework, Version 2.0.2

(or a subset, such as ASCII); a pyramid.exceptions.URLDecodeError is raised if a seg-


ment cannot be decoded. If a segment name is empty or if it is ., it is ignored. If a segment name
is .., the previous segment is deleted, and the .. is ignored. As a result of this process, the re-
turn values view_name, each element in the subpath, each element in traversed, and each
element in the virtual_root_path will be decoded strings.

traversal_path(path)
Variant of pyramid.traversal.traversal_path_info() suitable for decoding paths
that are URL-encoded.
If this function is passed a string, it must be directly encodeable to ASCII. For example, ’/foo’ will
work but ’/<unprintable unicode>’ (a string object with characters that cannot be encoded to ASCII)
will not. A UnicodeEncodeError will be raised if the string cannot be encoded directly to
ASCII.

pyramid.tweens

excview_tween_factory(handler, registry)
A tween factory which produces a tween that catches an exception raised by downstream tweens (or
the main Pyramid request handler) and, if possible, converts it into a Response using an exception
view.
Changed in version 1.9: The request.response will be remain unchanged even if the tween
handles an exception. Previously it was deleted after handling an exception.
Also, request.exception and request.exc_info are only set if the tween handles an
exception and returns a response otherwise they are left at their original values.

MAIN
Constant representing the main Pyramid handling function, for use in under and over arguments
to pyramid.config.Configurator.add_tween().

INGRESS
Constant representing the request ingress, for use in under and over arguments to pyramid.
config.Configurator.add_tween().

EXCVIEW
Constant representing the exception view tween, for use in under and over arguments to
pyramid.config.Configurator.add_tween().

900 CONTENTS
The Pyramid Web Framework, Version 2.0.2

pyramid.url

Utility functions for dealing with URLs in pyramid

resource_url(resource, request, *elements, **kw)


This is a backwards compatibility function. Its result is the same as calling:

request.resource_url(resource, *elements, **kw)

See pyramid.request.Request.resource_url() for more information.

route_url(route_name, request, *elements, **kw)


This is a backwards compatibility function. Its result is the same as calling:

request.route_url(route_name, *elements, **kw)

See pyramid.request.Request.route_url() for more information.

current_route_url(request, *elements, **kw)


This is a backwards compatibility function. Its result is the same as calling:

request.current_route_url(*elements, **kw)

See pyramid.request.Request.current_route_url() for more information.

route_path(route_name, request, *elements, **kw)


This is a backwards compatibility function. Its result is the same as calling:

request.route_path(route_name, *elements, **kw)

See pyramid.request.Request.route_path() for more information.

current_route_path(request, *elements, **kw)


This is a backwards compatibility function. Its result is the same as calling:

request.current_route_path(*elements, **kw)

See pyramid.request.Request.current_route_path() for more information.

static_url(path, request, **kw)


This is a backwards compatibility function. Its result is the same as calling:

0.4. API Documentation 901


The Pyramid Web Framework, Version 2.0.2

request.static_url(path, **kw)

See pyramid.request.Request.static_url() for more information.

static_path(path, request, **kw)


This is a backwards compatibility function. Its result is the same as calling:

request.static_path(path, **kw)

See pyramid.request.Request.static_path() for more information.

urlencode(query, doseq=True, quote_via=<function quote_plus>)


An alternate implementation of Python’s stdlib urllib.parse.urlencode() function which
accepts string keys and values within the query dict/sequence; all string keys and values are first
converted to UTF-8 before being used to compose the query string.
The value of query must be a sequence of two-tuples representing key/value pairs or an object
(often a dictionary) with an .items() method that returns a sequence of two-tuples representing
key/value pairs.
For minimal calling convention backwards compatibility, this version of urlencode accepts but ig-
nores a second argument conventionally named doseq. The Python stdlib version behaves differ-
ently when doseq is False and when a sequence is presented as one of the values. This version
always behaves in the doseq=True mode, no matter what the value of the second argument.
Both the key and value are encoded using the quote_via function which by default is using a
similar algorithm to urllib.parse.quote_plus() which converts spaces into ’+’ characters
and ’/’ into ’%2F’.
Changed in version 1.5: In a key/value pair, if the value is None then it will be dropped from the
resulting output.
Changed in version 1.9: Added the quote_via argument to allow alternate quoting algorithms to
be used.

pyramid.view

render_view_to_response(context, request, name=”, secure=True)


Call the view callable configured with a view configuration that matches the view name name regis-
tered against the specified context and request and return a response object. This function will
return None if a corresponding view callable cannot be found (when no view configuration matches
the combination of name / context / and request).

902 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If secure‘ is True, and the view callable found is protected by a permission, the permission will be
checked before calling the view function. If the permission check disallows view execution (based on
the current authorization policy), a pyramid.httpexceptions.HTTPForbidden exception
will be raised. The exception’s args attribute explains why the view access was disallowed.
If secure is False, no permission checking is done.

render_view_to_iterable(context, request, name=”, secure=True)


Call the view callable configured with a view configuration that matches the view name name regis-
tered against the specified context and request and return an iterable object which represents
the body of a response. This function will return None if a corresponding view callable cannot be
found (when no view configuration matches the combination of name / context / and request).
Additionally, this function will raise a ValueError if a view function is found and called but the
view function’s result does not have an app_iter attribute.
You can usually get the bytestring representation of the return value of this function by calling b''.
join(iterable), or just use pyramid.view.render_view() instead.
If secure is True, and the view is protected by a permission, the permission will be checked
before the view function is invoked. If the permission check disallows view execution (based on the
current security policy), a pyramid.httpexceptions.HTTPForbidden exception will be
raised; its args attribute explains why the view access was disallowed.
If secure is False, no permission checking is done.

render_view(context, request, name=”, secure=True)


Call the view callable configured with a view configuration that matches the view name name reg-
istered against the specified context and request and unwind the view response’s app_iter
(see View Callable Responses) into a single bytestring. This function will return None if a corre-
sponding view callable cannot be found (when no view configuration matches the combination of
name / context / and request). Additionally, this function will raise a ValueError if a view
function is found and called but the view function’s result does not have an app_iter attribute.
This function will return None if a corresponding view cannot be found.
If secure is True, and the view is protected by a permission, the permission will be checked
before the view is invoked. If the permission check disallows view execution (based on the cur-
rent authorization policy), a pyramid.httpexceptions.HTTPForbidden exception will
be raised; its args attribute explains why the view access was disallowed.
If secure is False, no permission checking is done.

class view_config(**settings)
A function, class or method decorator which allows a developer to create view registrations nearer
to a view callable definition than use imperative configuration to do the same.
For example, this code in a module views.py:

0.4. API Documentation 903


The Pyramid Web Framework, Version 2.0.2

from resources import MyResource

@view_config(name='my_view', context=MyResource, permission='read',


route_name='site1')
def my_view(context, request):
return 'OK'

Might replace the following call to the pyramid.config.Configurator.add_view()


method:

import views
from resources import MyResource
config.add_view(views.my_view, context=MyResource, name='my_view',
permission='read', route_name='site1')

pyramid.view.view_config supports the following keyword arguments: con-


text, exception, permission, name, request_type, route_name, re-
quest_method, request_param, containment, xhr, accept, header, path_info,
custom_predicates, decorator, mapper, http_cache, require_csrf,
match_param, physical_path, and view_options.
The meanings of these arguments are the same as the arguments passed to pyramid.config.
Configurator.add_view(). If any argument is left out, its default will be the equivalent
add_view default.
Two additional keyword arguments which will be passed to the venusian attach function are
_depth and _category.
_depth is provided for people who wish to reuse this class from another decorator. The default
value is 0 and should be specified relative to the view_config invocation. It will be passed in to
the venusian attach function as the depth of the callstack when Venusian checks if the decorator is
being used in a class or module context. It’s not often used, but it can be useful in this circumstance.
_category sets the decorator category name. It can be useful in combination with the category
argument of scan to control which views should be processed.
See the venusian.attach() function in Venusian for more information about the _depth and
_category arguments.
See also:
See also Adding View Configuration Using the @view_config Decorator for details about using
pyramid.view.view_config.

Because of a limitation with venusian.Scanner.scan, note that view_config will

904 CONTENTS
The Pyramid Web Framework, Version 2.0.2

work only for the following conditions.


• In Python packages that have an __init__.py file in their directory.
See also:
See also https://github.com/Pylons/venusian/issues/68
• On module top level members.
• On Python source (.py) files. Compiled Python files (.pyc, .pyo) without a corresponding
source file are ignored.
See also:
See also the Venusian documentation.

view_defaults(**settings)
A class decorator which, when applied to a class, will provide defaults for all view configura-
tions that use the class. This decorator accepts all the arguments accepted by pyramid.view.
view_config(), and each has the same meaning.
See @view_defaults Class Decorator for more information.

class notfound_view_config(**settings)
New in version 1.3.
An analogue of pyramid.view.view_config which registers a Not Found View using
pyramid.config.Configurator.add_notfound_view().
The notfound_view_config constructor accepts most of the same arguments as the construc-
tor of pyramid.view.view_config. It can be used in the same places, and behaves in largely
the same way, except it always registers a not found exception view instead of a ’normal’ view.
Example:

from pyramid.view import notfound_view_config


from pyramid.response import Response

@notfound_view_config()
def notfound(request):
return Response('Not found!', status='404 Not Found')

All arguments except append_slash have the same meaning as pyramid.view.


view_config() and each predicate argument restricts the set of circumstances under which this
notfound view will be invoked.

0.4. API Documentation 905


The Pyramid Web Framework, Version 2.0.2

If append_slash is True, when the Not Found View is invoked, and the current path info does
not end in a slash, the notfound logic will attempt to find a route that matches the request’s path info
suffixed with a slash. If such a route exists, Pyramid will issue a redirect to the URL implied by the
route; if it does not, Pyramid will return the result of the view callable provided as view, as normal.
If the argument provided as append_slash is not a boolean but instead implements IResponse,
the append_slash logic will behave as if append_slash=True was passed, but the provided class
will be used as the response class instead of the default HTTPTemporaryRedirect response
class when a redirect is performed. For example:

from pyramid.httpexceptions import (


HTTPMovedPermanently,
HTTPNotFound
)

@notfound_view_config(append_slash=HTTPMovedPermanently)
def aview(request):
return HTTPNotFound('not found')

The above means that a redirect to a slash-appended route will be attempted, but instead of
HTTPTemporaryRedirect being used, HTTPMovedPermanently will be used for
the redirect response if a slash-appended route is found.
See Changing the Not Found View for detailed usage information.
Changed in version 1.9.1: Added the _depth and _category arguments.

class forbidden_view_config(**settings)
New in version 1.3.
An analogue of pyramid.view.view_config which registers a forbidden view using
pyramid.config.Configurator.add_forbidden_view().
The forbidden_view_config constructor accepts most of the same arguments as the constructor of
pyramid.view.view_config. It can be used in the same places, and behaves in largely the
same way, except it always registers a forbidden exception view instead of a ’normal’ view.
Example:

from pyramid.view import forbidden_view_config


from pyramid.response import Response

@forbidden_view_config()
def forbidden(request):
return Response('You are not allowed', status='403 Forbidden')

906 CONTENTS
The Pyramid Web Framework, Version 2.0.2

All arguments passed to this function have the same meaning as pyramid.view.
view_config() and each predicate argument restricts the set of circumstances under which this
notfound view will be invoked.
See Changing the Forbidden View for detailed usage information.
Changed in version 1.9.1: Added the _depth and _category arguments.

class exception_view_config(*args, **settings)


New in version 1.8.
An analogue of pyramid.view.view_config which registers an exception view using
pyramid.config.Configurator.add_exception_view().
The exception_view_config constructor requires an exception context, and additionally ac-
cepts most of the same arguments as the constructor of pyramid.view.view_config. It can
be used in the same places, and behaves in largely the same way, except it always registers an excep-
tion view instead of a ”normal” view that dispatches on the request context.
Example:

from pyramid.view import exception_view_config


from pyramid.response import Response

@exception_view_config(ValueError, renderer='json')
def error_view(request):
return {'error': str(request.exception)}

All arguments passed to this function have the same meaning as pyramid.view.
view_config(), and each predicate argument restricts the set of circumstances under which
this exception view will be invoked.
Changed in version 1.9.1: Added the _depth and _category arguments.

pyramid.viewderivers

INGRESS
Constant representing the request ingress, for use in under arguments to pyramid.config.
Configurator.add_view_deriver().

VIEW
Constant representing the view callable at the end of the view pipeline, for use in over arguments
to pyramid.config.Configurator.add_view_deriver().

0.4. API Documentation 907


The Pyramid Web Framework, Version 2.0.2

pyramid.wsgi

wsgiapp(wrapped)
Decorator to turn a WSGI application into a Pyramid view callable. This decorator differs
from the pyramid.wsgi.wsgiapp2() decorator inasmuch as fixups of PATH_INFO and
SCRIPT_NAME within the WSGI environment are not performed before the application is invoked.
E.g., the following in a views.py module:

@wsgiapp
def hello_world(environ, start_response):
body = 'Hello world'
start_response('200 OK', [ ('Content-Type', 'text/plain'),
('Content-Length', len(body)) ] )
return [body]

Allows the following call to pyramid.config.Configurator.add_view():

from views import hello_world


config.add_view(hello_world, name='hello_world.txt')

The wsgiapp decorator will convert the result of the WSGI application to a Response and return
it to Pyramid as if the WSGI app were a Pyramid view.

wsgiapp2(wrapped)
Decorator to turn a WSGI application into a Pyramid view callable. This decorator differs
from the pyramid.wsgi.wsgiapp() decorator inasmuch as fixups of PATH_INFO and
SCRIPT_NAME within the WSGI environment are performed before the application is invoked.
E.g. the following in a views.py module:

@wsgiapp2
def hello_world(environ, start_response):
body = 'Hello world'
start_response('200 OK', [ ('Content-Type', 'text/plain'),
('Content-Length', len(body)) ] )
return [body]

Allows the following call to pyramid.config.Configurator.add_view():

from views import hello_world


config.add_view(hello_world, name='hello_world.txt')

908 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The wsgiapp2 decorator will convert the result of the WSGI application to a Response and return it
to Pyramid as if the WSGI app were a Pyramid view. The SCRIPT_NAME and PATH_INFO values
present in the WSGI environment are fixed up before the application is invoked. In particular, a new
WSGI environment is generated, and the subpath of the request passed to wsgiapp2 is used as the
new request’s PATH_INFO and everything preceding the subpath is used as the SCRIPT_NAME.
The new environment is passed to the downstream WSGI application.

0.5 p* Scripts Documentation

0.5.1 p* Scripts Documentation

Command line programs (p* scripts) included with Pyramid.

pdistreport

Show Python distribution versions and locations in use

usage: pdistreport [-h]

-h, --help
show this help message and exit

See also:

pdistreport: Showing All Installed Distributions and Their Versions and Running p-scripts.

prequest

Submit a HTTP request to a web application.

This command makes an artificial request to a web application that uses a PasteDeploy (.ini) configuration
file for the server and application.

Use ”prequest config.ini /path” to request ”/path”.

0.5. p* Scripts Documentation 909


The Pyramid Web Framework, Version 2.0.2

Use ”prequest --method=POST config.ini /path < data” to do a POST with the given request body.

Use ”prequest --method=PUT config.ini /path < data” to do a PUT with the given request body.

Use ”prequest --method=PATCH config.ini /path < data” to do a PATCH with the given request body.

Use ”prequest --method=OPTIONS config.ini /path” to do an OPTIONS request.

Use ”prequest --method=PROPFIND config.ini /path” to do a PROPFIND request.

If the path is relative (doesn’t begin with ”/”) it is interpreted as relative to ”/”. The path passed to this
script should be URL-quoted. The path can be succeeded with a query string (e.g. ’/path?a=1&=b2’).

The variable ”environ[’paste.command_request’]” will be set to ”True” in the request’s WSGI environment,
so your application can distinguish these calls from normal requests.

usage: prequest [-h] [-n NAME] [--header NAME:VALUE] [-d]


[-m {GET,HEAD,POST,PUT,PATCH,DELETE,PROPFIND,OPTIONS}]
[-l LOGIN]
[config_uri] [path_info] [config_vars ...]

config_uri
The URI to the configuration file.

path_info
The path of the request.

config_vars
Variables required by the config file. For example, http_port=%(http_port)s would expect
http_port=8080 to be passed here.

-h, --help
show this help message and exit

-n <name>, --app-name <name>


Load the named application from the config file (default ’main’)

--header <name:value>
Header to add to request (you can use this option multiple times)

910 CONTENTS
The Pyramid Web Framework, Version 2.0.2

-d, --display-headers
Display status and headers before the response body
-m {GET,HEAD,POST,PUT,PATCH,DELETE,PROPFIND,OPTIONS}, --method {GET,
HEAD,POST,PUT,PATCH,DELETE,PROPFIND,OPTIONS}
Request method type (GET, POST, PUT, PATCH, DELETE, PROPFIND, OPTIONS)
-l <login>, --login <login>
HTTP basic auth username:password pair
See also:
prequest: Invoking a Request and Running p-scripts.

proutes

Print all URL dispatch routes used by a Pyramid application in the order in which they are evaluated. Each
route includes the name of the route, the pattern of the route, and the view callable which will be invoked
when the route is matched.
This command accepts one positional argument named ’config_uri’. It specifies the PasteDeploy config
file to use for the interactive shell. The format is ’inifile#name’. If the name is left off, ’main’ will be
assumed. Example: ’proutes myapp.ini’.

usage: proutes [-h] [-g GLOB] [-f FORMAT] [config_uri] [config_vars ...]

config_uri
The URI to the configuration file.
config_vars
Variables required by the config file. For example, http_port=%(http_port)s would expect
http_port=8080 to be passed here.
-h, --help
show this help message and exit
-g <glob>, --glob <glob>
Display routes matching glob pattern
-f <format>, --format <format>
Choose which columns to display, this will override the format key in the [proutes] ini section
See also:
proutes: Displaying All Application Routes and Running p-scripts.

0.5. p* Scripts Documentation 911


The Pyramid Web Framework, Version 2.0.2

pserve

This command serves a web application that uses a PasteDeploy configuration file for the server and ap-
plication.
You can also include variable assignments like ’http_port=8080’ and then use %(http_port)s in your config
files.

usage: pserve [-h] [-n NAME] [-s SERVER_TYPE] [--server-name SECTION_NAME]


[--reload] [--reload-interval RELOAD_INTERVAL] [-b] [-v] [-q]
[config_uri] [config_vars ...]

config_uri
The URI to the configuration file.
config_vars
Variables required by the config file. For example, http_port=%(http_port)s would expect
http_port=8080 to be passed here.
-h, --help
show this help message and exit
-n <name>, --app-name <name>
Load the named application (default main)
-s <server_type>, --server <server_type>
Use the named server.
--server-name <section_name>
Use the named server as defined in the configuration file (default: main)
--reload
Use auto-restart file monitor
--reload-interval <reload_interval>
Seconds between checking files (low number can cause significant CPU usage)
-b, --browser
Open a web browser to the server url. The server url is determined from the ’open_url’ setting in the
’pserve’ section of the configuration file.
-v, --verbose
Set verbose level (default 1)
-q, --quiet
Suppress verbose output
See also:
Running the Project Application and Running p-scripts.

912 CONTENTS
The Pyramid Web Framework, Version 2.0.2

pshell

Open an interactive shell with a Pyramid app loaded. This command accepts one positional argument
named ”config_uri” which specifies the PasteDeploy config file to use for the interactive shell. The format
is ”inifile#name”. If the name is left off, the Pyramid default application will be assumed. Example:
”pshell myapp.ini#main”.

If you do not point the loader directly at the section of the ini file containing your Pyramid application, the
command will attempt to find the app for you. If you are loading a pipeline that contains more than one
Pyramid application within it, the loader will use the last one.

usage: pshell [-h] [-p PYTHON_SHELL] [-l] [--setup SETUP]


[config_uri] [config_vars ...]

config_uri
The URI to the configuration file.

config_vars
Variables required by the config file. For example, http_port=%(http_port)s would expect
http_port=8080 to be passed here.

-h, --help
show this help message and exit

-p <python_shell>, --python-shell <python_shell>


Select the shell to use. A list of possible shells is available using the --list-shells option.

-l, --list-shells
List all available shells.

--setup <setup>
A callable that will be passed the environment before it is made available to the shell. This option
will override the ’setup’ key in the [pshell] ini section.

See also:

pshell: The Interactive Shell and Running p-scripts.

0.5. p* Scripts Documentation 913


The Pyramid Web Framework, Version 2.0.2

ptweens

Print all implicit and explicit tween objects used by a Pyramid application. The handler output includes
whether the system is using an explicit tweens ordering (will be true when the ”pyramid.tweens” deploy-
ment setting is used) or an implicit tweens ordering (will be true when the ”pyramid.tweens” deployment
setting is not used).

This command accepts one positional argument named ”config_uri” which specifies the PasteDeploy con-
fig file to use for the interactive shell. The format is ”inifile#name”. If the name is left off, ”main” will be
assumed. Example: ”ptweens myapp.ini#main”.

usage: ptweens [-h] [config_uri] [config_vars ...]

config_uri
The URI to the configuration file.

config_vars
Variables required by the config file. For example, http_port=%(http_port)s would expect
http_port=8080 to be passed here.

-h, --help
show this help message and exit

See also:

ptweens: Displaying ”Tweens” and Running p-scripts.

pviews

Print, for a given URL, the views that might match. Underneath each potentially matching route, list
the predicates required. Underneath each route+predicate set, print each view that might match and its
predicates.

This command accepts two positional arguments: ’config_uri’ specifies the PasteDeploy config file to use
for the interactive shell. The format is ’inifile#name’. If the name is left off, ’main’ will be assumed.
’url’ specifies the path info portion of a URL that will be used to find matching views. Example: ’proutes
myapp.ini#main /url’

914 CONTENTS
The Pyramid Web Framework, Version 2.0.2

usage: pviews [-h] [config_uri] [url] [config_vars ...]

config_uri
The URI to the configuration file.

url
The path info portion of the URL.

config_vars
Variables required by the config file. For example, http_port=%(http_port)s would expect
http_port=8080 to be passed here.

-h, --help
show this help message and exit

See also:

pviews: Displaying Matching Views for a Given URL and Running p-scripts.

0.6 Change History

0.6.1 What’s New in Pyramid 1.7

This article explains the new features in Pyramid version 1.7 as compared to its predecessor, Pyramid
1.6. It also documents backwards incompatibilities between the two versions and deprecations added to
Pyramid 1.7, as well as software dependency changes and notable documentation additions.

Backwards Incompatibilities

• The default hash algorithm for pyramid.authentication.


AuthTktAuthenticationPolicy has changed from md5 to sha512. If you are using the
authentication policy and need to continue using md5, please explicitly set hashalg='md5'.
If you are not currently specifying the hashalg option in your apps, then this change means any
existing auth tickets (and associated cookies) will no longer be valid, users will be logged out, and
have to login to their accounts again.
This change has been issuing a DeprecationWarning since Pyramid 1.4.
See https://github.com/Pylons/pyramid/pull/2496

0.6. Change History 915


The Pyramid Web Framework, Version 2.0.2

• Python 2.6 and 3.2 are no longer supported by Pyramid. See https://github.com/Pylons/pyramid/
issues/2368 and https://github.com/Pylons/pyramid/pull/2256
• The pyramid.session.check_csrf_token() function no longer validates a csrf token in
the query string of a request. Only headers and request bodies are supported. See https://github.
com/Pylons/pyramid/pull/2500
• A global permission set via pyramid.config.Configurator.
set_default_permission() will no longer affect exception views. A permission must be
set explicitly on the view for it to be enforced. See https://github.com/Pylons/pyramid/pull/2534

Feature Additions

• A new View Derivers concept has been added to Pyramid to allow framework authors to inject
elements into the standard Pyramid view pipeline and affect all views in an application. This is
similar to a decorator except that it has access to options passed to config.add_view and can
affect other stages of the pipeline such as the raw response from a view or prior to security checks.
See https://github.com/Pylons/pyramid/pull/2021
• Added a require_csrf view option which will enforce CSRF checks on requests with an unsafe
method as defined by RFC2616. If the CSRF check fails a BadCSRFToken exception will be raised
and may be caught by exception views (the default response is a 400 Bad Request). This option
should be used in place of the deprecated check_csrf view predicate which would normally
result in unexpected 404 Not Found response to the client instead of a catchable exception.
See Checking CSRF Tokens Automatically, https://github.com/Pylons/pyramid/pull/2413 and https:
//github.com/Pylons/pyramid/pull/2500
• Added a new method, pyramid.config.Configurator.
set_csrf_default_options(), for configuring CSRF checks used by the re-
quire_csrf=True view option. This method can be used to turn on CSRF checks glob-
ally for every view in the application. This should be considered a good default for websites
built on Pyramid. It is possible to opt-out of CSRF checks on a per-view basis by setting
require_csrf=False on those views. See Checking CSRF Tokens Automatically and
https://github.com/Pylons/pyramid/pull/2413 and https://github.com/Pylons/pyramid/pull/2518
• Added an additional CSRF validation that checks the origin/referrer of a request and makes sure it
matches the current request.domain. This particular check is only active when accessing a site
over HTTPS as otherwise browsers don’t always send the required information. If this additional
CSRF validation fails a BadCSRFOrigin exception will be raised and may be caught by exception
views (the default response is 400 Bad Request). Additional allowed origins may be configured
by setting pyramid.csrf_trusted_origins to a list of domain names (with ports if on a
non standard port) to allow. Subdomains are not allowed unless the domain name has been prefixed
with a .. See https://github.com/Pylons/pyramid/pull/2501

916 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Added a new pyramid.session.check_csrf_origin() API for validating the origin or


referrer headers against the request’s domain. See https://github.com/Pylons/pyramid/pull/2501
• Subclasses of pyramid.httpexceptions.HTTPException will now take into account the
best match for the clients Accept header, and depending on what is requested will return text/
html, application/json or text/plain. The default for */* is still text/html, but
if application/json is explicitly mentioned it will now receive a valid JSON response. See
https://github.com/Pylons/pyramid/pull/2489
• A new event, pyramid.events.BeforeTraversal, and interface pyramid.
interfaces.IBeforeTraversal have been introduced that will notify listeners before
traversal starts in the router. See Request Processing as well as https://github.com/Pylons/pyramid/
pull/2469 and https://github.com/Pylons/pyramid/pull/1876
• A new method, pyramid.request.Request.invoke_exception_view(), which can
be used to invoke an exception view and get back a response. This is useful for rendering an exception
view outside of the context of the EXCVIEW tween where you may need more control over the
request. See https://github.com/Pylons/pyramid/pull/2393
• A global permission set via pyramid.config.Configurator.
set_default_permission() will no longer affect exception views. A permission must be
set explicitly on the view for it to be enforced. See https://github.com/Pylons/pyramid/pull/2534
• Allow a leading = on the key of the request param predicate. For example, '=abc=1' is equivalent
down to request.params['=abc'] == '1'. See https://github.com/Pylons/pyramid/pull/
1370
• Allow using variable substitutions like %(LOGGING_LOGGER_ROOT_LEVEL)s for logging sec-
tions of the .ini file and populate these variables from the pserve command line -- e.g.:
pserve development.ini LOGGING_LOGGER_ROOT_LEVEL=DEBUG
This support is thanks to the new global_conf option on pyramid.paster.
setup_logging(). See https://github.com/Pylons/pyramid/pull/2399
• The pyramid.tweens.EXCVIEW tween will now re-raise the original exception if no exception
view could be found to handle it. This allows the exception to be handled upstream by another tween
or middleware. See https://github.com/Pylons/pyramid/pull/2567

Deprecations

• The check_csrf view predicate has been deprecated. Use the new require_csrf option or
the pyramid.require_default_csrf setting to ensure that the pyramid.exceptions.
BadCSRFToken exception is raised. See https://github.com/Pylons/pyramid/pull/2413
• Support for Python 3.3 will be removed in Pyramid 1.8. https://github.com/Pylons/pyramid/issues/
2477

0.6. Change History 917


The Pyramid Web Framework, Version 2.0.2

Scaffolding Enhancements

• A complete overhaul of the alchemy scaffold to show more modern best practices with regards
to SQLAlchemy session management, as well as a more modular approach to configuration, sepa-
rating routes into a separate module to illustrate uses of pyramid.config.Configurator.
include(). See https://github.com/Pylons/pyramid/pull/2024

Documentation Enhancements

A massive overhaul of the packaging and tools used in the documentation was completed in https://github.
com/Pylons/pyramid/pull/2468. A summary follows:

• All docs now recommend using pip instead of easy_install.


• The installation docs now expect the user to be using Python 3.4 or greater with access to the
python3 -m venv tool to create virtual environments.
• Tutorials now use py.test and pytest-cov instead of nose and coverage.
• Further updates to the scaffolds as well as tutorials and their src files.

Along with the overhaul of the alchemy scaffold came a total overhaul of the SQLAlchemy + URL
dispatch wiki tutorial tutorial to introduce more modern features into the usage of SQLAlchemy with
Pyramid and provide a better starting point for new projects. See https://github.com/Pylons/pyramid/pull/
2024 for more. Highlights were:

• New SQLAlchemy session management without any global DBSession. Replaced by a per-request
request.dbsession property.
• A new authentication chapter demonstrating how to get simple authentication bootstrapped quickly
in an application.
• Authorization was overhauled to show the use of per-route context factories which demonstrate
object-level authorization on top of simple group-level authorization. Did you want to restrict page
edits to only the owner but couldn’t figure it out before? Here you go!
• The users and groups are stored in the database now instead of within tutorial-specific global vari-
ables.
• User passwords are stored using bcrypt.

918 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.6.2 What’s New in Pyramid 1.6

This article explains the new features in Pyramid version 1.6 as compared to its predecessor, Pyramid
1.5. It also documents backwards incompatibilities between the two versions and deprecations added to
Pyramid 1.6, as well as software dependency changes and notable documentation additions.

Backwards Incompatibilities

• IPython and BPython support have been removed from pshell in the core. To continue using them
on Pyramid 1.6+, you must install the binding packages explicitly. One way to do this is by adding
pyramid_ipython (or pyramid_bpython) to the install_requires section of your
package’s setup.py file, then re-running setup.py develop:

setup(
#...
install_requires=[
'pyramid_ipython', # new dependency
'pyramid',
#...
],
)

• request.response will no longer be mutated when using the render_to_response()


API. It is now necessary to pass in a response= argument to render_to_response()
if you wish to supply the renderer with a custom response object. If you do not pass one,
then a response object will be created using the current response factory. Almost all render-
ers mutate the request.response response object (for example, the JSON renderer sets
request.response.content_type to application/json). However, when invoking
render_to_response, it is not expected that the response object being returned would be the
same one used later in the request. The response object returned from render_to_response is
now explicitly different from request.response. This does not change the API of a renderer.
See https://github.com/Pylons/pyramid/pull/1563
• In an effort to combat a common issue it is now a ConfigurationError to register a view
callable that is actually an unbound method when using the default view mapper. As unbound
methods do not exist in PY3+ possible errors are detected by checking if the first parameter is
named self. For example, config.add_view(ViewClass.some_method, ...) should actually be con-
fig.add_view(ViewClass, attr=’some_method)’. This was always an issue in Pyramid on PY2 but
the backward incompatibility is on PY3+ where you may not use a function with the first parameter
named self. In this case it looks too much like a common error and the exception will be raised.
See https://github.com/Pylons/pyramid/pull/1498

0.6. Change History 919


The Pyramid Web Framework, Version 2.0.2

Feature Additions

• Python 3.5 and pypy3 compatibility.


• pserve --reload will no longer crash on syntax errors. See https://github.com/Pylons/pyramid/
pull/2044
• Cache busting for static resources has been added and is available via a new pyramid.config.
Configurator.add_cache_buster() API. Core APIs are shipped for both cache busting
via query strings and via asset manifests for integrating into custom asset pipelines. See https://
github.com/Pylons/pyramid/pull/1380 and https://github.com/Pylons/pyramid/pull/1583 and https:
//github.com/Pylons/pyramid/pull/2171
• Assets can now be overidden by an absolute path on the filesystem when using the over-
ride_asset() API. This makes it possible to fully support serving up static content from a mu-
table directory while still being able to use the static_url() API and add_static_view().
Previously it was not possible to use add_static_view() with an absolute path and gen-
erate urls to the content. This change replaces the call, config.add_static_view('/
abs/path', 'static'), with config.add_static_view('myapp:static',
'static') and config.override_asset(to_override='myapp:static/
', override_with='/abs/path/'). The myapp:static asset spec is com-
pletely made up and does not need to exist—it is used for generating URLs via request.
static_url('myapp:static/foo.png'). See https://github.com/Pylons/pyramid/pull/
1252
• Added set_response_factory() and the response_factory keyword argument to the
constructor of Configurator for defining a factory that will return a custom Response class.
See https://github.com/Pylons/pyramid/pull/1499
• Added pyramid.config.Configurator.root_package attribute and init parameter to
assist with includible packages that wish to resolve resources relative to the package in which the
configurator was created. This is especially useful for add-ons that need to load asset specs from
settings, in which case it may be natural for a developer to define imports or assets relative to the
top-level package. See https://github.com/Pylons/pyramid/pull/1337
• Overall improvements for the proutes command. Added --format and --glob arguments
to the command, introduced the method column for displaying available request methods, and
improved the view output by showing the module instead of just __repr__. See https://github.
com/Pylons/pyramid/pull/1488
• pserve can now take a -b or --browser option to open the server URL in a web browser. See
https://github.com/Pylons/pyramid/pull/1533
• Support keyword-only arguments and function annotations in views in Python 3. See https://github.
com/Pylons/pyramid/pull/1556

920 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The append_slash argument of add_notfound_view() will now accept anything that im-
plements the IResponse interface and will use that as the response class instead of the default
HTTPFound. See https://github.com/Pylons/pyramid/pull/1610
• The Configurator has grown the ability to allow actions to call other actions during a commit
cycle. This enables much more logic to be placed into actions, such as the ability to invoke other
actions or group them for improved conflict detection. We have also exposed and documented the
configuration phases that Pyramid uses in order to further assist in building conforming add-ons.
See https://github.com/Pylons/pyramid/pull/1513
• Allow an iterator to be returned from a renderer. Previously it was only possible to return bytes or
unicode. See https://github.com/Pylons/pyramid/pull/1417
• Improve robustness to timing attacks in the AuthTktCookieHelper and the SignedCook-
ieSessionFactory classes by using the stdlib’s hmac.compare_digest if it is available
(such as Python 2.7.7+ and 3.3+). See https://github.com/Pylons/pyramid/pull/1457
• Improve the readability of the pcreate shell script output. See https://github.com/Pylons/
pyramid/pull/1453
• Make it simple to define notfound and forbidden views that wish to use the default exception-
response view, but with altered predicates and other configuration options. The view argument is
now optional in add_notfound_view() and add_forbidden_view() See https://github.
com/Pylons/pyramid/issues/494
• The pshell script will now load a PYTHONSTARTUP file if one is defined in the environment
prior to launching the interpreter. See https://github.com/Pylons/pyramid/pull/1448
• Add new HTTP exception objects for status codes 428 Precondition Required, 429
Too Many Requests and 431 Request Header Fields Too Large in pyramid.
httpexceptions. See https://github.com/Pylons/pyramid/pull/1372/files
• pcreate when run without a scaffold argument will now print information on the missing flag,
as well as a list of available scaffolds. See https://github.com/Pylons/pyramid/pull/1566 and https:
//github.com/Pylons/pyramid/issues/1297
• pcreate will now ask for confirmation if invoked with an argument for a project name that already
exists or is importable in the current environment. See https://github.com/Pylons/pyramid/issues/
1357 and https://github.com/Pylons/pyramid/pull/1837
• Add pyramid.request.apply_request_extensions() function which can be used in
testing to apply any request extensions configured via config.add_request_method. Pre-
viously it was only possible to test the extensions by going through Pyramid’s router. See https:
//github.com/Pylons/pyramid/pull/1581
• Make it possible to subclass pyramid.request.Request and also use pyramid.
request.Request.add_request.method. See https://github.com/Pylons/pyramid/
issues/1529

0.6. Change History 921


The Pyramid Web Framework, Version 2.0.2

• Additional shells for pshell can now be registered as entry points. See https://github.com/Pylons/
pyramid/pull/1891 and https://github.com/Pylons/pyramid/pull/2012
• The variables injected into pshell are now displayed with their docstrings instead of the default
str(obj) when possible. See https://github.com/Pylons/pyramid/pull/1929

Deprecations

• The pserve command’s daemonization features, as well as --monitor-restart, have been


deprecated. This includes the [start,stop,restart,status] subcommands, as well
as the --daemon, --stop-daemon, --pid-file, --status, --user, and --group
flags. See https://github.com/Pylons/pyramid/pull/2120 and https://github.com/Pylons/pyramid/
pull/2189 and https://github.com/Pylons/pyramid/pull/1641
Please use a real process manager in the future instead of relying on pserve to daemonize itself.
Many options exist, including your operating system’s services, such as Systemd or Upstart, as well
as Python-based solutions like Circus and Supervisor.
See https://github.com/Pylons/pyramid/pull/1641 and https://github.com/Pylons/pyramid/pull/
2120
• The principal argument to pyramid.security.remember() was renamed to userid.
Using principal as the argument name still works and will continue to work for the next few
releases, but a deprecation warning is printed.

Scaffolding Enhancements

• Added line numbers to the log formatters in the scaffolds to assist with debugging. See https://github.
com/Pylons/pyramid/pull/1326
• Updated scaffold generating machinery to return the version of Pyramid and its documentation for
use in scaffolds. Updated starter, alchemy and zodb templates to have links to correctly
versioned documentation, and to reflect which Pyramid was used to generate the scaffold.
• Removed non-ASCII copyright symbol from templates, as this was causing the scaffolds to fail for
project generation.

922 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation Enhancements

• Removed logging configuration from Quick Tutorial ini files, except for scaffolding- and logging-
related chapters, to avoid needing to explain it too early.
• Improve and clarify the documentation on what Pyramid defines as a principal and a userid
in its security APIs. See https://github.com/Pylons/pyramid/pull/1399
• Moved the documentation for accept on pyramid.config.Configurator.
add_view() to no longer be part of the predicate list. See https://github.com/Pylons/
pyramid/issues/1391 for a bug report stating not_ was failing on accept. Discussion
with @mcdonc led to the conclusion that it should not be documented as a predicate. See
https://github.com/Pylons/pyramid/pull/1487 for this PR.
• Clarify a previously-implied detail of the ISession.invalidate API documentation.
• Add documentation of command line programs (p* scripts). See https://github.com/Pylons/
pyramid/pull/2191

0.6.3 What’s New in Pyramid 1.5

This article explains the new features in Pyramid version 1.5 as compared to its predecessor, Pyramid
1.4. It also documents backwards incompatibilities between the two versions and deprecations added to
Pyramid 1.5, as well as software dependency changes and notable documentation additions.

Major Backwards Incompatibilities

• Pyramid no longer depends on or configures the Mako and Chameleon templating system renderers
by default. Disincluding these templating systems by default means that the Pyramid core has fewer
dependencies and can run on future platforms without immediate concern for the compatibility of
its templating add-ons. It also makes maintenance slightly more effective, as different people can
maintain the templating system add-ons that they understand and care about without needing commit
access to the Pyramid core, and it allows users who just don’t want to see any packages they don’t
use come along for the ride when they install Pyramid.
This means that upon upgrading to Pyramid 1.5a2+, projects that use either of these templating
systems will see a traceback that ends something like this when their application attempts to render
a Chameleon or Mako template:

ValueError: No such renderer factory .pt

Or:

0.6. Change History 923


The Pyramid Web Framework, Version 2.0.2

ValueError: No such renderer factory .mako

Or:

ValueError: No such renderer factory .mak

Support for Mako templating has been moved into an add-on package named pyramid_mako,
and support for Chameleon templating has been moved into an add-on package named pyra-
mid_chameleon. These packages are drop-in replacements for the old built-in support for these
templating langauges. All you have to do is install them and make them active in your configuration
to register renderer factories for .pt and/or .mako (or .mak) to make your application work again.
To re-add support for Chameleon and/or Mako template renderers into your existing projects, follow
the below steps.
If you depend on Mako templates:
– Make sure the pyramid_mako package is installed. One way to do this is by adding pyra-
mid_mako to the install_requires section of your package’s setup.py file and
afterwards rerunning setup.py develop:

setup(
#...
install_requires=[
'pyramid_mako', # new dependency
'pyramid',
#...
],
)

– Within the portion of your application which instantiates a Pyramid Configurator (of-
ten the main() function in your project’s __init__.py file), tell Pyramid to include the
pyramid_mako includeme:

config = Configurator(.....)
config.include('pyramid_mako')

If you depend on Chameleon templates:


– Make sure the pyramid_chameleon package is installed. One way to do this is by adding
pyramid_chameleon to the install_requires section of your package’s setup.
py file and afterwards rerunning setup.py develop:

924 CONTENTS
The Pyramid Web Framework, Version 2.0.2

setup(
#...
install_requires=[
'pyramid_chameleon', # new dependency
'pyramid',
#...
],
)

– Within the portion of your application which instantiates a Pyramid Configurator (of-
ten the main() function in your project’s __init__.py file), tell Pyramid to include the
pyramid_chameleon includeme:

config = Configurator(.....)
config.include('pyramid_chameleon')

Note that it’s also fine to install these packages into older Pyramids for forward compatibility pur-
poses. Even if you don’t upgrade to Pyramid 1.5 immediately, performing the above steps in a
Pyramid 1.4 installation is perfectly fine, won’t cause any difference, and will give you forward
compatibility when you eventually do upgrade to Pyramid 1.5.
With the removal of Mako and Chameleon support from the core, some unit tests that use
the pyramid.renderers.render* methods may begin to fail. If any of your unit
tests are invoking either pyramid.renderers.render() or pyramid.renderers.
render_to_response() with either Mako or Chameleon templates then the pyramid.
config.Configurator instance in effect during the unit test should be also be updated to
include the addons, as shown above. For example:

class ATest(unittest.TestCase):
def setUp(self):
self.config = pyramid.testing.setUp()
self.config.include('pyramid_mako')

def test_it(self):
result = pyramid.renderers.render('mypkg:templates/home.mako',
,→{})

Or:

class ATest(unittest.TestCase):
def setUp(self):
self.config = pyramid.testing.setUp()
self.config.include('pyramid_chameleon')
(continues on next page)

0.6. Change History 925


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)

def test_it(self):
result = pyramid.renderers.render('mypkg:templates/home.pt', {}
,→ )

• If you’re using the Pyramid debug toolbar, when you upgrade Pyramid to 1.5a2+, you’ll also need to
upgrade the pyramid_debugtoolbar package to at least version 1.0.8, as older toolbar versions
are not compatible with Pyramid 1.5a2+ due to the removal of Mako support from the core. It’s fine
to use this newer version of the toolbar code with older Pyramids too.

Feature Additions

The feature additions in Pyramid 1.5 follow.

• Python 3.4 compatibility.


• Add pdistreport script, which prints the Python version in use, the Pyramid version in use, and
the version number and location of all Python distributions currently installed.
• Add the ability to invert the result of any view, route, or subscriber predicate value using the not_
class. For example:

from pyramid.config import not_

@view_config(route_name='myroute', request_method=not_('POST'))
def myview(request): ...

The above example will ensure that the view is called if the request method is not POST, at least if
no other view is more specific.
The pyramid.config.not_ class can be used against any value that is a predicate value passed
in any of these contexts:
– pyramid.config.Configurator.add_view()
– pyramid.config.Configurator.add_route()
– pyramid.config.Configurator.add_subscriber()
– pyramid.view.view_config()
– pyramid.events.subscriber()

926 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• View lookup will now search for valid views based on the inheritance hierarchy of the context. It
tries to find views based on the most specific context first, and upon predicate failure, will move
up the inheritance chain to test views found by the super-type of the context. In the past, only the
most specific type containing views would be checked and if no matching view could be found then
a PredicateMismatch would be raised. Now predicate mismatches don’t hide valid views registered
on super-types. Here’s an example that now works:

class IResource(Interface):

...

@view_config(context=IResource)
def get(context, request):

...

@view_config(context=IResource, request_method='POST')
def post(context, request):

...

@view_config(context=IResource, request_method='DELETE')
def delete(context, request):

...

@implementer(IResource)
class MyResource:

...

@view_config(context=MyResource, request_method='POST')
def override_post(context, request):

...

Previously the override_post view registration would hide the get and delete views in the context of
MyResource -- leading to a predicate mismatch error when trying to use GET or DELETE meth-
ods. Now the views are found and no predicate mismatch is raised. See https://github.com/Pylons/
pyramid/pull/786 and https://github.com/Pylons/pyramid/pull/1004 and https://github.com/Pylons/
pyramid/pull/1046
• scripts/prequest.py (aka the prequest console script): added support for submitting
PUT and PATCH requests. See https://github.com/Pylons/pyramid/pull/1033. add support for sub-
mitting OPTIONS and PROPFIND requests, and allow users to specify basic authentication creden-
tials in the request via a --login argument to the script. See https://github.com/Pylons/pyramid/

0.6. Change History 927


The Pyramid Web Framework, Version 2.0.2

pull/1039.
• The pyramid.config.Configurator.add_route() method now supports being called
with an external URL as pattern. See https://github.com/Pylons/pyramid/issues/611 and the docu-
mentation section External Routes.
• pyramid.authorization.ACLAuthorizationPolicy supports __acl__ as a
callable. This removes the ambiguity between the potential AttributeError that would be
raised on the context when the property was not defined and the AttributeError that could
be raised from any user-defined code within a dynamic property. It is recommended to define a dy-
namic ACL as a callable to avoid this ambiguity. See https://github.com/Pylons/pyramid/issues/735.
• Allow a protocol-relative URL (e.g. //example.com/images) to be passed to pyramid.
config.Configurator.add_static_view(). This allows externally-hosted static URLs
to be generated based on the current protocol.
• The pyramid.authentication.AuthTktAuthenticationPolicy class has two new
options to configure its domain usage:
– parent_domain: if set the authentication cookie is set on the parent domain. This is useful
if you have multiple sites sharing the same domain.
– domain: if provided the cookie is always set for this domain, bypassing all usual logic.
See https://github.com/Pylons/pyramid/pull/1028, https://github.com/Pylons/pyramid/pull/1072
and https://github.com/Pylons/pyramid/pull/1078.
• The pyramid.authentication.AuthTktPolicy now supports IPv6 addresses when us-
ing the include_ip=True option. This is possibly incompatible with alternative auth_tkt
implementations, as the specification does not define how to properly handle IPv6. See https:
//github.com/Pylons/pyramid/issues/831.
• Make it possible to use variable arguments via pyramid.paster.get_appsettings().
This also allowed the generated initialize_db script from the alchemy scaffold to grow
support for options in the form a=1 b=2 so you can fill in values in a parameterized .ini file,
e.g. initialize_myapp_db etc/development.ini a=1 b=2. See https://github.com/
Pylons/pyramid/pull/911
• The request.session.check_csrf_token() method and the check_csrf view pred-
icate now take into account the value of the HTTP header named X-CSRF-Token (as well as the
csrf_token form parameter, which they always did). The header is tried when the form param-
eter does not exist.
• You can now generate ”hybrid” urldispatch/traversal URLs more easily by using the new
route_name, route_kw and route_remainder_name arguments to resource_url()
and resource_path(). See Generating Hybrid URLs.
• A new http exception superclass named HTTPSuccessful was added. You can use this class as
the context of an exception view to catch all 200-series ”exceptions” (e.g. ”raise HTTPOk”). This

928 CONTENTS
The Pyramid Web Framework, Version 2.0.2

also allows you to catch only the HTTPOk exception itself; previously this was impossible because
a number of other exceptions (such as HTTPNoContent) inherited from HTTPOk, but now they
do not.
• It is now possible to escape double braces in Pyramid scaffolds (unescaped, these represent replace-
ment values). You can use \{\{a\}\} to represent a ”bare” {{a}}. See https://github.com/
Pylons/pyramid/pull/862
• Add localizer and locale_name properties (reified) to pyramid.request.
Request. See https://github.com/Pylons/pyramid/issues/508. Note that the pyramid.
i18n.get_localizer() and pyramid.i18n.get_locale_name() functions now
simply look up these properties on the request.
• The pserve command now takes a -v (or --verbose) flag and a -q (or --quiet) flag. Output
from running pserve can be controlled using these flags. -v can be specified multiple times to
increase verbosity. -q sets verbosity to 0 unconditionally. The default verbosity level is 1.
• The alchemy scaffold tests now provide better coverage. See https://github.com/Pylons/pyramid/
pull/1029
• Users can now provide dotted Python names to as the factory argument the Con-
figurator methods named add_view_predicate(), add_route_predicate() and
add_subscriber_predicate(). Instead of passing the predicate factory directly, you can
pass a dotted name which refers to the factory.
• pyramid.path.package_name() no longer throws an exception when resolving the package
name for namespace packages that have no __file__ attribute.
• An authorization API has been added as a method of the request: pyramid.request.
Request.has_permission(). It is a method-based alternative to the pyramid.
security.has_permission() API and works exactly the same. The older API is now dep-
recated.
• Property API attributes have been added to the request for easier access to authentica-
tion data: pyramid.request.Request.authenticated_userid, pyramid.
request.Request.unauthenticated_userid, and pyramid.request.Request.
effective_principals. These are analogues, respectively, of pyramid.security.
authenticated_userid(), pyramid.security.unauthenticated_userid(),
and pyramid.security.effective_principals(). They operate exactly the same,
except they are attributes of the request instead of functions accepting a request. They are properties,
so they cannot be assigned to. The older function-based APIs are now deprecated.
• Pyramid’s console scripts (pserve, pviews, etc) can now be run directly, allowing custom argu-
ments to be sent to the python interpreter at runtime. For example:

python -3 -m pyramid.scripts.pserve development.ini

0.6. Change History 929


The Pyramid Web Framework, Version 2.0.2

• Added a specific subclass of pyramid.httpexceptions.HTTPBadRequest named


pyramid.exceptions.BadCSRFToken which will now be raised in response to failures in
the check_csrf_token view predicate. See https://github.com/Pylons/pyramid/pull/1149
• Added a new SignedCookieSessionFactory which is very similar to the Unencrypt-
edCookieSessionFactoryConfig but with a clearer focus on signing content. The custom
serializer arguments to this function should only focus on serializing, unlike its predecessor which
required the serializer to also perform signing. See https://github.com/Pylons/pyramid/pull/1142
. Note that cookies generated using SignedCookieSessionFactory are not compatible
with cookies generated using UnencryptedCookieSessionFactory, so existing user ses-
sion data will be destroyed if you switch to it.
• Added a new BaseCookieSessionFactory which acts as a generic cookie factory that can be
used by framework implementors to create their own session implementations. It provides a reusable
API which focuses strictly on providing a dictionary-like object that properly handles renewals, time-
outs, and conformance with the ISession API. See https://github.com/Pylons/pyramid/pull/1142
• We no longer eagerly clear request.exception and request.exc_info in the exception
view tween. This makes it possible to inspect exception information within a finished callback. See
https://github.com/Pylons/pyramid/issues/1223.

Other Backwards Incompatibilities

• Modified the current_route_url() method. The method previously returned the URL with-
out the query string by default, it now does attach the query string unless it is overriden.
• The route_url() and route_path() APIs no longer quote / to %2F when a replacement
value contains a /. This was pointless, as WSGI servers always unquote the slash anyway, and
Pyramid never sees the quoted value.
• It is no longer possible to set a locale_name attribute of the request, nor is it possible to set a
localizer attribute of the request. These are now ”reified” properties that look up a locale name
and localizer respectively using the machinery described in Internationalization and Localization.
• If you send an X-Vhm-Root header with a value that ends with any number of slashes, the trailing
slashes will be removed before the URL is generated when you use resource_url() or re-
source_path(). Previously the virtual root path would not have trailing slashes stripped, which
would influence URL generation.
• The pyramid.interfaces.IResourceURL interface has now grown two new attributes:
virtual_path_tuple and physical_path_tuple. These should be the tuple form of
the resource’s path (physical and virtual).
• Removed the request.response_* varying attributes (such as“request.response_headers“) .
These attributes had been deprecated since Pyramid 1.1, and as per the deprecation policy, have
now been removed.

930 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• request.response will no longer be mutated when using the pyramid.renderers.


render() API. Almost all renderers mutate the request.response response object (for
example, the JSON renderer sets request.response.content_type to application/
json), but this is only necessary when the renderer is generating a response; it was a bug when it
was done as a side effect of calling pyramid.renderers.render().
• Removed the bfg2pyramid fixer script.
• The pyramid.events.NewResponse event is now sent after response callbacks are executed.
It previously executed before response callbacks were executed. Rationale: it’s more useful to be
able to inspect the response after response callbacks have done their jobs instead of before.
• Removed the class named pyramid.view.static that had been deprecated since Pyramid 1.1.
Instead use pyramid.static.static_view with the use_subpath=True argument.
• Removed the pyramid.view.is_response function that had been deprecated since Pyramid
1.1. Use the pyramid.request.Request.is_response() method instead.
• Removed the ability to pass the following arguments to pyramid.config.Configurator.
add_route(): view, view_context. view_for, view_permission,
view_renderer, and view_attr. Using these arguments had been deprecated since
Pyramid 1.1. Instead of passing view-related arguments to add_route, use a separate call to
pyramid.config.Configurator.add_view() to associate a view with a route using its
route_name argument. Note that this impacts the pyramid.config.Configurator.
add_static_view() function too, because it delegates to“add_route“.
• Removed the ability to influence and query a pyramid.request.Request object as if it were a
dictionary. Previously it was possible to use methods like __getitem__, get, items, and other
dictlike methods to access values in the WSGI environment. This behavior had been deprecated
since Pyramid 1.1. Use methods of request.environ (a real dictionary) instead.
• Removed ancient backwards compatibility hack in pyramid.traversal.
DefaultRootFactory which populated the __dict__ of the factory with the matchdict
values for compatibility with BFG 0.9.
• The renderer_globals_factory argument to the pyramid.config.Configurator
constructor and the coresponding argument to setup_registry() has been removed. The
set_renderer_globals_factory method of Configurator has also been removed. The
(internal) pyramid.interfaces.IRendererGlobals interface was also removed. These
arguments, methods and interfaces had been deprecated since 1.1. Use a BeforeRender event
subscriber as documented in the ”Hooks” chapter of the Pyramid narrative documentation instead
of providing renderer globals values to the configurator.
• The key/values in the _query parameter of pyramid.request.Request.route_url()
and the query parameter of pyramid.request.Request.resource_url() (and their
variants), used to encode a value of None as the string 'None', leaving the resulting query string
to be a=b&key=None. The value is now dropped in this situation, leaving a query string of
a=b&key=. See https://github.com/Pylons/pyramid/issues/1119

0.6. Change History 931


The Pyramid Web Framework, Version 2.0.2

Deprecations

• Returning a ("defname", dict) tuple from a view which has a Mako renderer is now depre-
cated. Instead you should use the renderer spelling foo#defname.mak in the view configuration
definition and return a dict only.
• The pyramid.config.Configurator.set_request_property() method now issues
a deprecation warning when used. It had been docs-deprecated in 1.4 but did not issue a deprecation
warning when used.
• pyramid.security.has_permission() is now deprecated in favor of using pyramid.
request.Request.has_permission().
• The pyramid.security.authenticated_userid(), pyramid.
security.unauthenticated_userid(), and pyramid.security.
effective_principals() functions have been deprecated. Use pyramid.
request.Request.authenticated_userid, pyramid.request.
Request.unauthenticated_userid and pyramid.request.Request.
effective_principals instead.
• Deprecate the pyramid.interfaces.ITemplateRenderer interface. It was ill-defined
and became unused when Mako and Chameleon template bindings were split into their own pack-
ages.
• The pyramid.session.UnencryptedCookieSessionFactoryConfig
API has been deprecated and is superseded by the pyramid.session.
SignedCookieSessionFactory. Note that while the cookies generated by the Un-
encryptedCookieSessionFactoryConfig are compatible with cookies gener-
ated by old releases, cookies generated by the SignedCookieSessionFactory are not. See
https://github.com/Pylons/pyramid/pull/1142

Documentation Enhancements

• A new documentation chapter named Quick Tour of Pyramid was added. It describes starting out
with Pyramid from a high level.
• Added a Quick Tutorial for Pyramid to go with the Quick Tour
• Many other enhancements.

932 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Scaffolding Enhancements

• All scaffolds have a new HTML + CSS theme.


• Updated docs and scaffolds to keep in step with new 2.0 release of Lingua. This included removing
all setup.cfg files from scaffolds and documentation environments.

Dependency Changes

• Pyramid no longer depends upon Mako or Chameleon.


• Pyramid now depends on WebOb>=1.3 (it uses webob.cookies.CookieProfile from 1.3+).

0.6.4 What’s New in Pyramid 1.4

This article explains the new features in Pyramid version 1.4 as compared to its predecessor, Pyramid
1.3. It also documents backwards incompatibilities between the two versions and deprecations added to
Pyramid 1.4, as well as software dependency changes and notable documentation additions.

Major Feature Additions

The major feature additions in Pyramid 1.4 follow.

Third-Party Predicates

• Third-party custom view, route, and subscriber predicates can now be added for use by
view authors via pyramid.config.Configurator.add_view_predicate(),
pyramid.config.Configurator.add_route_predicate() and pyramid.
config.Configurator.add_subscriber_predicate(). So, for example, doing
this:

config.add_view_predicate('abc', my.package.ABCPredicate)

Might allow a view author to do this in an application that configured that predicate:

0.6. Change History 933


The Pyramid Web Framework, Version 2.0.2

@view_config(abc=1)

Similar features exist for pyramid.config.Configurator.add_route(), and


pyramid.config.Configurator.add_subscriber(). See Adding a Custom View,
Route, or Subscriber Predicate for more information.

Easy Custom JSON Serialization

• Views can now return custom objects which will be serialized to JSON by a JSON renderer by
defining a __json__ method on the object’s class. This method should return values natively
serializable by json.dumps (such as ints, lists, dictionaries, strings, and so forth). See Serializing
Custom Objects for more information. The JSON renderer now also allows for the definition of
custom type adapters to convert unknown objects to JSON serializations, in case you can’t add a
__json__ method to returned objects.

Partial Mako and Chameleon Template Renderings

• The Mako renderer now supports using a def name in an asset spec. When the def name is present
in the asset spec, the system will render the template named def within the template instead of
rendering the entire template. An example asset spec which names a def is package:path/to/
template#defname.mako. This will render the def named defname inside the template.
mako template instead of rendering the entire template. The old way of returning a tuple in the form
('defname', {}) from the view is supported for backward compatibility.
• The Chameleon ZPT renderer now supports using a macro name in an asset spec. When the macro
name is present in the asset spec, the system will render the macro listed as a define-macro and
return the result instead of rendering the entire template. An example asset spec: package:path/
to/template#macroname.pt. This will render the macro defined as macroname within the
template.pt template instead of the entire template.

Subrequest Support

• Developers may invoke a subrequest by using the pyramid.request.Request.


invoke_subrequest() API. This allows a developer to obtain a response from one view
callable by issuing a subrequest from within a different view callable. See Invoking a Subrequest
for more information.

934 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Minor Feature Additions

• pyramid.authentication.AuthTktAuthenticationPolicy has been updated to


support newer hashing algorithms such as sha512. Existing applications should consider updating
if possible for improved security over the default md5 hashing.
• pyramid.config.Configurator.add_directive() now accepts arbitrary callables
like partials or objects implementing __call__ which don’t have __name__ and __doc__
attributes. See https://github.com/Pylons/pyramid/issues/621 and https://github.com/Pylons/
pyramid/pull/647.
• As of this release, the request_method view/route predicate, when used,
will also imply that HEAD is implied when you use GET. For example, us-
ing @view_config(request_method='GET') is equivalent to us-
ing @view_config(request_method=('GET', 'HEAD')). Using
@view_config(request_method=('GET', 'POST') is equivalent to using
@view_config(request_method=('GET', 'HEAD', 'POST'). This is because
HEAD is a variant of GET that omits the body, and WebOb has special support to return an empty
body when a HEAD is used.
• pyramid.config.Configurator.add_request_method() has been intro-
duced to support extending request objects with arbitrary callables. This method ex-
pands on the now documentation-deprecated pyramid.config.Configurator.
set_request_property() by supporting methods as well as properties. This method also
causes less code to be executed at request construction time than set_request_property().
• The static view machinery now raises rather than returns pyramid.httpexceptions.
HTTPNotFound and pyramid.httpexceptions.HTTPMovedPermanently excep-
tions, so these can be caught by the Not Found View (and other exception views).
• When there is a predicate mismatch exception (seen when no view matches for a given request due
to predicates not working), the exception now contains a textual description of the predicate which
didn’t match.
• An pyramid.config.Configurator.add_permission() directive method was added
to the Configurator. This directive registers a free-standing permission introspectable into the Pyra-
mid introspection system. Frameworks built atop Pyramid can thus use the permissions intro-
spectable category data to build a comprehensive list of permissions supported by a running system.
Before this method was added, permissions were already registered in this introspectable category
as a side effect of naming them in an pyramid.config.Configurator.add_view() call,
this method just makes it possible to arrange for a permission to be put into the permissions in-
trospectable category without naming it along with an associated view. Here’s an example of usage
of add_permission:

config = Configurator()
config.add_permission('view')

0.6. Change History 935


The Pyramid Web Framework, Version 2.0.2

• The pyramid.session.UnencryptedCookieSessionFactoryConfig() function


now accepts signed_serialize and signed_deserialize hooks which may be used to
influence how the sessions are marshalled (by default this is done with HMAC+pickle).
• pyramid.testing.DummyRequest now supports methods supplied by the pyramid.
util.InstancePropertyMixin class such as set_property.
• Request properties and methods added via pyramid.config.Configurator.
add_request_method() or pyramid.config.Configurator.
set_request_property() are now available to tweens.
• Request properties and methods added via pyramid.config.Configurator.
add_request_method() or pyramid.config.Configurator.
set_request_property() are now available in the request object returned from pyramid.
paster.bootstrap().
• request.context of environment request during pyramid.paster.bootstrap() is now
the root object if a context isn’t already set on a provided request.
• pyramid.decorator.reify is now an API, and was added to the API documentation.
• Added the pyramid.testing.testConfig() context manager, which can be used to gener-
ate a configurator in a test, e.g. with testing.testConfig(...):.
• A new pyramid.session.check_csrf_token() convenience API function was added.
• A check_csrf view predicate was added. For example, you can now do config.
add_view(someview, check_csrf=True). When the predicate is checked, if the
csrf_token value in request.params matches the csrf token in the request’s session, the
view will be permitted to execute. Otherwise, it will not be permitted to execute.
• Add Base.metadata.bind = engine to alchemy scaffold, so that tables defined impera-
tively will work.
• Comments with references to documentation sections placed in scaffold .ini files.
• Allow multiple values to be specified to the request_param view/route predicate as a sequence.
Previously only a single string value was allowed. See https://github.com/Pylons/pyramid/pull/705
• Added an HTTP Basic authentication policy at pyramid.authentication.
BasicAuthAuthenticationPolicy.
• The pyramid.config.Configurator.testing_securitypolicy() method now re-
turns the policy object it creates.
• The DummySecurityPolicy created by pyramid.config.Configurator.
testing_securitypolicy() now sets a forgotten value on the policy (the value
True) when its forget method is called.

936 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The DummySecurityPolicy created by pyramid.config.Configurator.


testing_securitypolicy() now sets a remembered value on the policy, which is
the value of the principal argument it’s called with when its remember method is called.
• New physical_path view predicate. If specified, this value should be a string or a tuple
representing the physical traversal path of the context found via traversal for this predicate to
match as true. For example: physical_path='/' or physical_path='/a/b/c' or
physical_path=('', 'a', 'b', 'c'). It’s useful when you want to always potentially
show a view when some object is traversed to, but you can’t be sure about what kind of object it will
be, so you can’t use the context predicate.
• Added an effective_principals route and view predicate.
• Do not allow the userid returned from the pyramid.security.
authenticated_userid() or the userid that is one of the list of principals returned by
pyramid.security.effective_principals() to be either of the strings system.
Everyone or system.Authenticated when any of the built-in authorization policies that
live in pyramid.authentication are in use. These two strings are reserved for internal usage
by Pyramid and they will no longer be accepted as valid userids.
• Allow a _depth argument to pyramid.view.view_config, which will permit limited com-
position reuse of the decorator by other software that wants to provide custom decorators that are
much like view_config.
• Allow an iterable of decorators to be passed to pyramid.config.Configurator.
add_view(). This allows views to be wrapped by more than one decorator without requiring
combining the decorators yourself.
• pyramid.security.view_execution_permitted() used to return True if no view
could be found. It now raises a TypeError exception in that case, as it doesn’t make sense to assert
that a nonexistent view is execution-permitted. See https://github.com/Pylons/pyramid/issues/299.
• Small microspeed enhancement which anticipates that a pyramid.response.Response ob-
ject is likely to be returned from a view. Some code is shortcut if the class of the object returned by
a view is this class. A similar microoptimization was done to pyramid.request.Request.
is_response().
• Make it possible to use variable arguments on all p* commands (pserve, pshell, pviews,
etc) in the form a=1 b=2 so you can fill in values in parameterized .ini file, e.g. pshell
etc/development.ini http_port=8080.
• In order to allow people to ignore unused arguments to subscriber callables and to normalize the
relationship between event subscribers and subscriber predicates, we now allow both subscribers
and subscriber predicates to accept only a single event argument even if they’ve been subscribed
for notifications that involve multiple interfaces.

0.6. Change History 937


The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• The Pyramid router no longer adds the values bfg.routes.route or bfg.routes.


matchdict to the request’s WSGI environment dictionary. These values were docs-deprecated
in repoze.bfg 1.0 (effectively seven minor releases ago). If your code depended on these values,
use request.matched_route and request.matchdict instead.
• It is no longer possible to pass an environ dictionary directly to pyramid.traversal.
ResourceTreeTraverser.__call__ (aka ModelGraphTraverser.__call__). In-
stead, you must pass a request object. Passing an environment instead of a request has generated a
deprecation warning since Pyramid 1.1.
• Pyramid will no longer work properly if you use the webob.request.LegacyRequest as a
request factory. Instances of the LegacyRequest class have a request.path_info which re-
turn a string. This Pyramid release assumes that request.path_info will unconditionally be
Unicode.
• The functions from pyramid.chameleon_zpt and pyramid.chameleon_text
named get_renderer, get_template, render_template, and ren-
der_template_to_response have been removed. These have issued a deprecation warning
upon import since Pyramid 1.0. Use pyramid.renderers.get_renderer(), pyramid.
renderers.get_renderer().implementation(), pyramid.renderers.
render() or pyramid.renderers.render_to_response() respectively instead
of these functions.
• The pyramid.configuration module was removed. It had been deprecated since Pyramid
1.0 and printed a deprecation warning upon its use. Use pyramid.config instead.
• The pyramid.paster.PyramidTemplate API was removed. It had been deprecated since
Pyramid 1.1 and issued a warning on import. If your code depended on this, adjust your code to
import pyramid.scaffolds.PyramidTemplate instead.
• The pyramid.settings.get_settings() API was removed. It had been printing a
deprecation warning since Pyramid 1.0. If your code depended on this API, use pyramid.
threadlocal.get_current_registry().settings instead or use the settings at-
tribute of the registry available from the request (request.registry.settings).
• These APIs from the pyramid.testing module were removed. They have been printing depre-
cation warnings since Pyramid 1.0:
– registerDummySecurityPolicy, use pyramid.config.Configurator.
testing_securitypolicy() instead.
– registerResources (aka registerModels), use pyramid.config.
Configurator.testing_resources() instead.
– registerEventListener, use pyramid.config.Configurator.
testing_add_subscriber() instead.

938 CONTENTS
The Pyramid Web Framework, Version 2.0.2

– registerTemplateRenderer (aka registerDummyRenderer), use pyramid.


config.Configurator.testing_add_renderer() instead.
– registerView, use pyramid.config.Configurator.add_view() instead.
– registerUtility, use pyramid.config.Configurator.registry.
registerUtility() instead.
– registerAdapter, use pyramid.config.Configurator.registry.
registerAdapter() instead.
– registerSubscriber, use pyramid.config.Configurator.
add_subscriber() instead.
– registerRoute, use pyramid.config.Configurator.add_route() instead.
– registerSettings, use pyramid.config.Configurator.add_settings()
instead.
• In Pyramid 1.3 and previous, the __call__ method of a Response object returned by a view was
invoked before any finished callbacks were executed. As of this release, the __call__ method
of a Response object is invoked after finished callbacks are executed. This is in support of the
pyramid.request.Request.invoke_subrequest() feature.

Deprecations

• The pyramid.config.Configurator.set_request_property() directive has been


documentation-deprecated. The method remains usable but the more featureful pyramid.
config.Configurator.add_request_method() should be used in its place (it has all
of the same capabilities but can also extend the request object with methods).
• pyramid.authentication.AuthTktAuthenticationPolicy will emit a deprecation
warning if an application is using the policy without explicitly passing a hashalg argument. This
is because the default is ”md5” which is considered theoretically subject to collision attacks. If you
really want ”md5” then you must specify it explicitly to get rid of the warning.

Documentation Enhancements

• Added an Upgrading Pyramid chapter to the narrative documentation. It describes how to cope
with deprecations and removals of Pyramid APIs and how to show Pyramid-generated deprecation
warnings while running tests and while running a server.
• Added a Invoking a Subrequest chapter to the narrative documentation.
• All of the tutorials that use pyramid.authentication.
AuthTktAuthenticationPolicy now explicitly pass sha512 as a hashalg argument.
• Many cleanups and improvements to narrative and API docs.

0.6. Change History 939


The Pyramid Web Framework, Version 2.0.2

Dependency Changes

• Pyramid now requires WebOb 1.2b3+ (the prior Pyramid release only relied on 1.2dev+). This is to
ensure that we obtain a version of WebOb that returns request.path_info as text.

0.6.5 What’s New in Pyramid 1.3

This article explains the new features in Pyramid version 1.3 as compared to its predecessor, Pyramid
1.2. It also documents backwards incompatibilities between the two versions and deprecations added to
Pyramid 1.3, as well as software dependency changes and notable documentation additions.

Major Feature Additions

The major feature additions in Pyramid 1.3 follow.

Python 3 Compatibility

Pyramid continues to run on Python 2, but Pyramid is now also Python 3 compatible. To use Pyramid
under Python 3, Python 3.3 or better is required.
Many Pyramid add-ons are already Python 3 compatible. For example, pyramid_debugtoolbar,
pyramid_jinja2, pyramid_exclog, pyramid_tm, pyramid_mailer, and pyra-
mid_handlers are all Python 3-ready. But other add-ons are known to work only under Python
2. Also, some scaffolding dependencies (particularly ZODB) do not yet work under Python 3.
Please be patient as we gain full ecosystem support for Python 3. You can see more details about ongoing
porting efforts at https://github.com/Pylons/pyramid/wiki/Python-3-Porting .
Python 3 compatibility required dropping some package dependencies and support for older Python ver-
sions and platforms. See the ”Backwards Incompatibilities” section below for more information.

940 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The paster Command Has Been Replaced

We’ve replaced the paster command with Pyramid-specific analogues. Why? The libraries that sup-
ported the paster command named Paste and PasteScript do not run under Python 3, and we
were unwilling to port and maintain them ourselves. As a result, we’ve had to make some changes.
Previously (in Pyramid 1.0, 1.1 and 1.2), you created a Pyramid application using paster create, like
so:

$ $VENV/bin/paster create -t pyramid_starter foo

In 1.3, you’re now instead required to create an application using pcreate like so:

$ $VENV/bin/pcreate -s starter foo

pcreate is required to be used for internal Pyramid scaffolding; externally distributed scaffolding may
allow for both pcreate and/or paster create.
In previous Pyramid versions, you ran a Pyramid application like so:

$ $VENV/bin/paster serve development.ini

Instead, you now must use the pserve command in 1.3:

$ $VENV/bin/pserve development.ini

The ini configuration file format supported by Pyramid has not changed. As a result, Python 2-only users
can install PasteScript manually and use paster serve instead if they like. However, using pserve
will work under both Python 2 and Python 3.
Analogues of paster pshell, paster pviews, paster request and paster ptweens
also exist under the respective console script names pshell, pviews, prequest and ptweens.

paste.httpserver replaced by waitress in Scaffolds

Because the paste.httpserver server we used previously in scaffolds is not Python 3 compatible,
we’ve made the default WSGI server used by Pyramid scaffolding the waitress server. The waitress server
is both Python 2 and Python 3 compatible.
Once you create a project from a scaffold, its development.ini and production.ini will have
the following line:

0.6. Change History 941


The Pyramid Web Framework, Version 2.0.2

use = egg:waitress#main

Instead of this (which was the default in older versions):

use = egg:Paste#http

paste.httpserver ”helped” by converting header values that were Unicode into strings, which
was a feature that subverted the WSGI specification. The waitress server, on the other hand imple-
ments the WSGI spec more fully. This specifically may affect you if you are modifying headers on your
responses. The following error might be an indicator of this problem: AssertionError: Header val-
ues must be strings, please check the type of the header being returned. A common case would be
returning Unicode headers instead of string headers.

Compatibility Helper Library

A new pyramid.compat module was added which provides Python 2/3 straddling support for Pyramid
add-ons and development environments.

Introspection

A configuration introspection system was added; see Pyramid Configuration Introspection and Adding
Configuration Introspection for more information on using the introspection system as a developer.

The latest release of the pyramid debug toolbar (0.9.7+) provides an ”Introspection” panel that exposes
introspection information to a Pyramid application developer.

New APIs were added to support introspection pyramid.registry.Introspectable,


pyramid.config.Configurator.introspector, pyramid.config.Configurator.
introspectable, pyramid.registry.Registry.introspector.

942 CONTENTS
The Pyramid Web Framework, Version 2.0.2

@view_defaults Decorator

If you use a class as a view, you can use the new pyramid.view.view_defaults class decorator
on the class to provide defaults to the view configuration information used by every @view_config
decorator that decorates a method of that class.

For instance, if you’ve got a class that has methods that represent ”REST actions”, all which are mapped
to the same route, but different request methods, instead of this:

1 from pyramid.view import view_config


2 from pyramid.response import Response
3

4 class RESTView(object):
5 def __init__(self, request):
6 self.request = request
7

8 @view_config(route_name='rest', request_method='GET')
9 def get(self):
10 return Response('get')
11

12 @view_config(route_name='rest', request_method='POST')
13 def post(self):
14 return Response('post')
15

16 @view_config(route_name='rest', request_method='DELETE')
17 def delete(self):
18 return Response('delete')

You can do this:

1 from pyramid.view import view_defaults


2 from pyramid.view import view_config
3 from pyramid.response import Response
4

5 @view_defaults(route_name='rest')
6 class RESTView(object):
7 def __init__(self, request):
8 self.request = request
9

10 @view_config(request_method='GET')
11 def get(self):
12 return Response('get')
13

(continues on next page)

0.6. Change History 943


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


14 @view_config(request_method='POST')
15 def post(self):
16 return Response('post')
17

18 @view_config(request_method='DELETE')
19 def delete(self):
20 return Response('delete')

This also works for imperative view configurations that involve a class.

See @view_defaults Class Decorator for more information.

Extending a Request without Subclassing

It is now possible to extend a pyramid.request.Request object with property descriptors without


having to create a custom request factory. The new method pyramid.config.Configurator.
set_request_property() provides an entry point for addons to register properties which will be
added to each request. New properties may be reified, effectively caching the return value for the lifetime
of the instance. Common use-cases for this would be to get a database connection for the request or
identify the current user. The new method pyramid.request.Request.set_property() has
been added, as well, but the configurator method should be preferred as it provides conflict detection and
consistency in the lifetime of the properties.

Not Found and Forbidden View Helpers

Not Found helpers:

• New API: pyramid.config.Configurator.add_notfound_view(). This is a wrap-


per for pyramid.config.Configurator.add_view() which provides support for an ”ap-
pend_slash” feature as well as doing the right thing when it comes to permissions (a Not Found
View should always be public). It should be preferred over calling add_view directly with con-
text=HTTPNotFound as was previously recommended.
• New API: pyramid.view.notfound_view_config. This is a decorator construc-
tor like pyramid.view.view_config that calls pyramid.config.Configurator.
add_notfound_view() when scanned. It should be preferred over using pyramid.view.
view_config with context=HTTPNotFound as was previously recommended.

944 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Forbidden helpers:

• New API: pyramid.config.Configurator.add_forbidden_view(). This is a


wrapper for pyramid.config.Configurator.add_view() which does the right thing
about permissions. It should be preferred over calling add_view directly with con-
text=HTTPForbidden as was previously recommended.
• New API: pyramid.view.forbidden_view_config. This is a decorator construc-
tor like pyramid.view.view_config that calls pyramid.config.Configurator.
add_forbidden_view() when scanned. It should be preferred over using pyramid.view.
view_config with context=HTTPForbidden as was previously recommended.

Minor Feature Additions

• New APIs: pyramid.path.AssetResolver and pyramid.path.


DottedNameResolver. The former can be used to resolve an asset specification to an
API that can be used to read the asset’s data, the latter can be used to resolve a dotted Python name
to a module or a package.
• A mako.directories setting is no longer required to use Mako templates Rationale: Mako
template renderers can be specified using an absolute asset spec. An entire application can be written
with such asset specs, requiring no ordered lookup path.
• bpython interpreter compatibility in pshell. See Alternative Shells for more information.
• Added pyramid.paster.get_appsettings() API function. This function returns the set-
tings defined within an [app:...] section in a PasteDeploy ini file.
• Added pyramid.paster.setup_logging() API function. This function sets up Python
logging according to the logging configuration in a PasteDeploy ini file.
• Configuration conflict reporting is reported in a more understandable way (”Line 11 in file...” vs. a
repr of a tuple of similar info).
• We allow extra keyword arguments to be passed to the pyramid.config.Configurator.
action() method.
• Responses generated by Pyramid’s pyramid.static.static_view now
use a wsgi.file_wrapper (see https://www.python.org/dev/peps/pep-0333/
#optional-platform-specific-file-handling) when one is provided by the web server.
• The pyramid.config.Configurator.scan() method can be passed an ignore argu-
ment, which can be a string, a callable, or a list consisting of strings and/or callables. This fea-
ture allows submodules, subpackages, and global objects from being scanned. See https://docs.
pylonsproject.org/projects/venusian/en/latest/#ignore-scan-argument for more information about
how to use the ignore argument to scan.

0.6. Change History 945


The Pyramid Web Framework, Version 2.0.2

• Add pyramid.config.Configurator.add_traverser() API method. See Changing


the Traverser for more information. This is not a new feature, it just provides an API for adding a
traverser without needing to use the ZCA API.
• Add pyramid.config.Configurator.add_resource_url_adapter() API
method. See Changing How pyramid.request.Request.resource_url() Generates a URL for more
information. This is not a new feature, it just provides an API for adding a resource url adapter
without needing to use the ZCA API.
• Better error messages when a view callable returns a value that cannot be converted to a response
(for example, when a view callable returns a dictionary without a renderer defined, or doesn’t return
any value at all). The error message now contains information about the view callable itself as well
as the result of calling it.
• Better error message when a .pyc-only module is config.include -ed. This is not permitted due
to error reporting requirements, and a better error message is shown when it is attempted. Previously
it would fail with something like ”AttributeError: ’NoneType’ object has no attribute ’rfind’”.
• The system value req is now supplied to renderers as an alias for request. This means that
you can now, for example, in a template, do req.route_url(...) instead of request.
route_url(...). This is purely a change to reduce the amount of typing required to use request
methods and attributes from within templates. The value request is still available too, this is just
an alternative.
• A new interface was added: pyramid.interfaces.IResourceURL. An adapter implement-
ing its interface can be used to override resource URL generation when pyramid.request.
Request.resource_url() is called. This interface replaces the now-deprecated pyramid.
interfaces.IContextURL interface.
• The dictionary passed to a resource’s __resource_url__ method (see Overriding Resource
URL Generation) now contains an app_url key, representing the application URL generated dur-
ing pyramid.request.Request.resource_url(). It represents a potentially customized
URL prefix, containing potentially custom scheme, host and port information passed by the user
to request.resource_url. It should be used instead of request.application_url
where necessary.
• The pyramid.request.Request.resource_url() API now accepts these arguments:
app_url, scheme, host, and port. The app_url argument can be used to replace the URL
prefix wholesale during url generation. The scheme, host, and port arguments can be used to
replace the respective default values of request.application_url partially.
• A new API named pyramid.request.Request.resource_path() now exists. It works
like pyramid.request.Request.resource_url() but produces a relative URL rather
than an absolute one.
• The pyramid.request.Request.route_url() API now accepts these arguments:
_app_url, _scheme, _host, and _port. The _app_url argument can be used to replace

946 CONTENTS
The Pyramid Web Framework, Version 2.0.2

the URL prefix wholesale during url generation. The _scheme, _host, and _port arguments
can be used to replace the respective default values of request.application_url partially.
• New APIs: pyramid.response.FileResponse and pyramid.response.FileIter,
for usage in views that must serve files ”manually”.

Backwards Incompatibilities

• Pyramid no longer runs on Python 2.5. This includes the most recent release of Jython and the
Python 2.5 version of Google App Engine.
The reason? We could not easily ”straddle” Python 2 and 3 versions and support Python 2 versions
older than Python 2.6. You will need Python 2.6 or better to run this version of Pyramid. If you
need to use Python 2.5, you should use the most recent 1.2.X release of Pyramid.
• The names of available scaffolds have changed and the flags supported by pcreate are different
than those that were supported by paster create. For example, pyramid_alchemy is now
just alchemy.
• The paster command is no longer the documented way to create projects, start the server, or run
debugging commands. To create projects from scaffolds, paster create is replaced by the
pcreate console script. To serve up a project, paster serve is replaced by the pserve
console script. New console scripts named pshell, pviews, proutes, and ptweens do what
their paster <commandname> equivalents used to do. All relevant narrative documentation has
been updated. Rationale: the Paste and PasteScript packages do not run under Python 3.
• The default WSGI server run as the result of pserve from newly rendered scaffolding is now the
waitress WSGI server instead of the paste.httpserver server. Rationale: the Paste and
PasteScript packages do not run under Python 3.
• The pshell command (see ”paster pshell”) no longer accepts a --disable-ipython
command-line argument. Instead, it accepts a -p or --python-shell argument, which can
be any of the values python, ipython or bpython.
• Removed the pyramid.renderers.renderer_from_name function. It has been depre-
cated since Pyramid 1.0, and was never an API.
• To use ZCML with versions of Pyramid >= 1.3, you will need pyramid_zcml version >= 0.8
and zope.configuration version >= 3.8.0. The pyramid_zcml package version 0.8 is
backwards compatible all the way to Pyramid 1.0, so you won’t be warned if you have older versions
installed and upgrade Pyramid itself ”in-place”; it may simply break instead (particularly if you use
ZCML’s includeOverrides directive).
• String values passed to pyramid.request.Request.route_url() or pyramid.
request.Request.route_path() that are meant to replace ”remainder” matches will now
be URL-quoted except for embedded slashes. For example:

0.6. Change History 947


The Pyramid Web Framework, Version 2.0.2

config.add_route('remain', '/foo*remainder')
request.route_path('remain', remainder='abc / def')
# -> '/foo/abc%20/%20def'

Previously string values passed as remainder replacements were tacked on untouched, without any
URL-quoting. But this doesn’t really work logically if the value passed is Unicode (raw unicode
cannot be placed in a URL or in a path) and it is inconsistent with the rest of the URL generation
machinery if the value is a string (it won’t be quoted unless by the caller).
Some folks will have been relying on the older behavior to tack on query string elements and anchor
portions of the URL; sorry, you’ll need to change your code to use the _query and/or _anchor
arguments to route_path or route_url to do this now.
• If you pass a bytestring that contains non-ASCII characters to pyramid.config.
Configurator.add_route() as a pattern, it will now fail at startup time. Use Unicode
instead.
• The path_info route and view predicates now match against request.upath_info (Uni-
code) rather than request.path_info (indeterminate value based on Python 3 vs. Python 2).
This has to be done to normalize matching on Python 2 and Python 3.
• The match_param view predicate no longer accepts a dict. This will have no negative affect
because the implementation was broken for dict-based arguments.
• The pyramid.interfaces.IContextURL interface has been deprecated. People have been
instructed to use this to register a resource url adapter in the ”Hooks” chapter to use to influence
pyramid.request.Request.resource_url() URL generation for resources found via
custom traversers since Pyramid 1.0.
The interface still exists and registering an adapter using it as documented in older ver-
sions still works, but this interface will be removed from the software after a few ma-
jor Pyramid releases. You should replace it with an equivalent pyramid.interfaces.
IResourceURL adapter, registered using the new pyramid.config.Configurator.
add_resource_url_adapter() API. A deprecation warning is now emitted when
a pyramid.interfaces.IContextURL adapter is found when pyramid.request.
Request.resource_url() is called.
• Remove pyramid.config.Configurator.with_context class method. It was never an
API, it is only used by pyramid_zcml and its functionality has been moved to that package’s
latest release. This means that you’ll need to use the 0.9.2 or later release of pyramid_zcml with
this release of Pyramid.
• The older deprecated set_notfound_view Configurator method is now an alias for
the new add_notfound_view Configurator method. Likewise, the older deprecated
set_forbidden_view is now an alias for the new add_forbidden_view Config-
urator method. This has the following impact: the context sent to views with a

948 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(context, request) call signature registered via the set_notfound_view or


set_forbidden_view will now be an exception object instead of the actual resource con-
text found. Use request.context to get the actual resource context. It’s also recom-
mended to disuse set_notfound_view in favor of add_notfound_view, and disuse
set_forbidden_view in favor of add_forbidden_view despite the aliasing.

Deprecations

• The API documentation for pyramid.view.append_slash_notfound_view and


pyramid.view.AppendSlashNotFoundViewFactory was removed. These names
still exist and are still importable, but they are no longer APIs. Use pyramid.config.
Configurator.add_notfound_view(append_slash=True) or pyramid.view.
notfound_view_config(append_slash=True) to get the same behavior.
• The set_forbidden_view and set_notfound_view methods of the Configurator were
removed from the documentation. They have been deprecated since Pyramid 1.1.
• All references to the tmpl_context request variable were removed from the docs. Its existence in
Pyramid is confusing for people who were never Pylons users. It was added as a porting convenience
for Pylons users in Pyramid 1.0, but it never caught on because the Pyramid rendering system is a
lot different than Pylons’ was, and alternate ways exist to do what it was designed to offer in Pylons.
It will continue to exist ”forever” but it will not be recommended or mentioned in the docs.
• Remove references to do-nothing pyramid.debug_templates setting in all Pyramid-provided
.ini files. This setting previously told Chameleon to render better exceptions; now Chameleon always
renders nice exceptions regardless of the value of this setting.

Known Issues

• As of this writing (the release of Pyramid 1.3b2), if you attempt to install a Pyramid project that
used the alchemy scaffold via setup.py develop on Python 3.2, it will quit with an in-
stallation error while trying to install Pygments. If this happens, please just rerun the setup.
py develop command again, and it will complete successfully. This is due to a minor bug in
SQLAlchemy 0.7.5 under Python 3, and has been fixed in a later SQLAlchemy release. Keep an eye
on https://github.com/sqlalchemy/sqlalchemy/issues/2421

0.6. Change History 949


The Pyramid Web Framework, Version 2.0.2

Documentation Enhancements

• The SQLAlchemy + URL dispatch wiki tutorial has been updated. It now uses @view_config
decorators and an explicit database population script.
• Minor updates to the ZODB + Traversal Wiki Tutorial.
• A narrative documentation chapter named Extending Pyramid Configuration was added; it de-
scribes how to add a custom configuration directive, and how use the pyramid.config.
Configurator.action() method within custom directives. It also describes how to add in-
trospectable objects.
• A narrative documentation chapter named Pyramid Configuration Introspection was added. It de-
scribes how to query the introspection system.
• Added an API docs chapter for pyramid.scaffolds.
• Added a narrative docs chapter named ”Creating Pyramid Scaffolds”.
• Added a description of the prequest command-line script at prequest: Invoking a Request.
• Added a section to the ”Command-Line Pyramid” chapter named Making Your Script into a Console
Script.
• Removed the ”Running Pyramid on Google App Engine” tutorial from the main docs. It survives
on in the Pyramid Community Cookbook as Pyramid on Google’s App Engine (using appengine-
monkey). Rationale: it provides the correct info for the Python 2.5 version of GAE only, and this
version of Pyramid does not support Python 2.5.
• Updated the Changing the Forbidden View section, replacing explanations of registering a view
using add_view or view_config with ones using add_forbidden_view or forbid-
den_view_config.
• Updated the Changing the Not Found View section, replacing explanations of registering a
view using add_view or view_config with ones using add_notfound_view or not-
found_view_config.
• Updated the Redirecting to Slash-Appended Routes section, replacing explanations of registering
a view using add_view or view_config with ones using add_notfound_view or not-
found_view_config
• Updated all tutorials to use pyramid.view.forbidden_view_config rather than
pyramid.view.view_config with an HTTPForbidden context.

950 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Dependency Changes

• Pyramid no longer depends on the zope.component package, except as a testing dependency.


• Pyramid now depends on the following package versions: zope.interface>=3.8.0, WebOb>=1.2dev,
repoze.lru>=0.4, zope.deprecation>=3.5.0, translationstring>=0.4 for Python 3 compatibility pur-
poses. It also, as a testing dependency, depends on WebTest>=1.3.1 for the same reason.
• Pyramid no longer depends on the Paste or PasteScript packages. These packages are not
Python 3 compatible.
• Depend on venusian >= 1.0a3 to provide scan ignore support.

Scaffolding Changes

• Rendered scaffolds have now been changed to be more relocatable (fewer mentions of the package
name within files in the package).
• The routesalchemy scaffold has been renamed alchemy, replacing the older (traversal-based)
alchemy scaffold (which has been retired).
• The alchemy and starter scaffolds are Python 3 compatible.
• The starter scaffold now uses URL dispatch by default.

0.6.6 What’s New in Pyramid 1.2

This article explains the new features in Pyramid version 1.2 as compared to its predecessor, Pyramid
1.1. It also documents backwards incompatibilities between the two versions and deprecations added to
Pyramid 1.2, as well as software dependency changes and notable documentation additions.

Major Feature Additions

The major feature additions in Pyramid 1.2 follow.

Debug Toolbar

The scaffolding packages that come with Pyramid now include a debug toolbar component which can be
used to interactively debug an application. See The Debug Toolbar for more information.

0.6. Change History 951


The Pyramid Web Framework, Version 2.0.2

route_prefix Argument to include

The pyramid.config.Configurator.include() method now accepts a route_prefix ar-


gument. This argument allows you to compose URL dispatch applications together from disparate pack-
ages. See Using a Route Prefix to Compose Applications for more information.

Tweens

A tween is used to wrap the Pyramid router’s primary request handling function. This is a feature that can
be used by Pyramid framework extensions, to provide, for example, view timing support and can provide
a convenient place to hang bookkeeping code. Tweens are a little like WSGI middleware, but have access
to Pyramid functionality such as renderers and a full-featured request object.

To support this feature, a new configurator directive exists named pyramid.config.


Configurator.add_tween(). This directive adds a ”tween”.

Tweens are further described in Registering Tweens.

A new paster command now exists: paster ptweens. This command prints the current tween config-
uration for an application. See the section entitled ptweens: Displaying ”Tweens” for more info.

Scaffolding Changes

• All scaffolds now use the pyramid_tm package rather than the repoze.tm2 middleware to
manage transaction management.
• The ZODB scaffold now uses the pyramid_zodbconn package rather than the repoze.
zodbconn package to provide ZODB integration.
• All scaffolds now use the pyramid_debugtoolbar package rather than the WebError pack-
age to provide interactive debugging features.
• Projects created via a scaffold no longer depend on the WebError package at all; configuration
in the production.ini file which used to require its error_catcher middleware has been
removed. Configuring error catching / email sending is now the domain of the pyramid_exclog
package (see https://docs.pylonsproject.org/projects/pyramid_exclog/en/latest/).
• All scaffolds now send the cache_max_age parameter to the add_static_view method.

952 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Minor Feature Additions

• The [pshell] section in an ini configuration file now treats a setup key as a dotted name that
points to a callable that is passed the bootstrap environment. It can mutate the environment as
necessary during a paster pshell session. This feature is described in Writing a Script.
• A new configuration setting named pyramid.includes is now available. It is described in
Including Packages.
• Added a pyramid.security.NO_PERMISSION_REQUIRED constant for use in per-
mission= statements to view configuration. This constant has a value of the string
__no_permission_required__. This string value was previously referred to in documenta-
tion; now the documentation uses the constant.
• Added a decorator-based way to configure a response adapter: pyramid.response.
response_adapter. This decorator has the same use as pyramid.config.
Configurator.add_response_adapter() but it’s declarative.
• The pyramid.events.BeforeRender event now has an attribute named rendering_val.
This can be used to introspect the value returned by a view in a BeforeRender subscriber.
• The Pyramid debug logger now uses the standard logging configuration (usually set up by
Paste as part of startup). This means that output from e.g. debug_notfound, de-
bug_authorization, etc. will go to the normal logging channels. The logger name of the
debug logger will be the package name of the caller of the Configurator’s constructor.
• A new attribute is available on request objects: exc_info. Its value will be None until an excep-
tion is caught by the Pyramid router, after which it will be the result of sys.exc_info().
• pyramid.testing.DummyRequest now implements the add_finished_callback and
add_response_callback methods implemented by pyramid.request.Request.
• New methods of the pyramid.config.Configurator class:
set_authentication_policy() and set_authorization_policy(). These
are meant to be consumed mostly by add-on authors who wish to offer packages which register
security policies.
• New Configurator method: pyramid.config.Configurator.set_root_factory(),
which can set the root factory after the Configurator has been constructed.
• Pyramid no longer eagerly commits some default configuration statements at Configurator con-
struction time, which permits values passed in as constructor arguments (e.g. authentica-
tion_policy and authorization_policy) to override the same settings obtained via the
pyramid.config.Configurator.include() method.
• Better Mako rendering exceptions; the template line which caused the error is now shown when a
Mako rendering raises an exception.

0.6. Change History 953


The Pyramid Web Framework, Version 2.0.2

• New request methods: current_route_url(), current_route_path(), and


static_path().
• New functions in the pyramid.url module: current_route_path() and
static_path().
• The pyramid.request.Request.static_url() API (and its brethren pyramid.
request.Request.static_path(), pyramid.url.static_url(), and pyramid.
url.static_path()) now accept an absolute filename as a ”path” argument. This will generate
a URL to an asset as long as the filename is in a directory which was previously registered as a static
view. Previously, trying to generate a URL to an asset using an absolute file path would raise a
ValueError.
• The RemoteUserAuthenticationPolicy, AuthTktAuthenticationPolicy, and
SessionAuthenticationPolicy constructors now accept an additional keyword argument
named debug. By default, this keyword argument is False. When it is True, debug information
will be sent to the Pyramid debug logger (usually on stderr) when the authenticated_userid
or effective_principals method is called on any of these policies. The output produced
can be useful when trying to diagnose authentication-related problems.
• New view predicate: match_param. Example: a view added via config.add_view(aview,
match_param='action=edit') will be called only when the request.matchdict has
a value inside it named action with a value of edit.
• Support an onerror keyword argument to pyramid.config.Configurator.scan().
This argument is passed to venusian.Scanner.scan() to influence error behavior when an
exception is raised during scanning.
• The request_method predicate argument to pyramid.config.Configurator.
add_view() and pyramid.config.Configurator.add_route() is now permitted to
be a tuple of HTTP method names. Previously it was restricted to being a string representing a
single HTTP method name.
• Undeprecated pyramid.traversal.find_model, pyramid.traversal.
model_path, pyramid.traversal.model_path_tuple, and pyramid.url.
model_url, which were all deprecated in Pyramid 1.0. There’s just not much cost to keeping
them around forever as aliases to their renamed resource_* prefixed functions.
• Undeprecated pyramid.view.bfg_view, which was deprecated in Pyramid 1.0. This is a low-
cost alias to pyramid.view.view_config which we’ll just keep around forever.
• Route pattern replacement marker names can now begin with an underscore. See https://github.com/
Pylons/pyramid/issues/276.

954 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Deprecations

• All Pyramid-related deployment settings (e.g. debug_all, debug_notfound) are now meant to
be prefixed with the prefix pyramid.. For example: debug_all -> pyramid.debug_all.
The old non-prefixed settings will continue to work indefinitely but supplying them may print a
deprecation warning. All scaffolds and tutorials have been changed to use prefixed settings.
• The deployment settings dictionary now raises a deprecation warning when you attempt to access its
values via __getattr__ instead of via __getitem__.

Backwards Incompatibilities

• If a string is passed as the debug_logger parameter to a Configurator, that string is considered


to be the name of a global Python logger rather than a dotted name to an instance of a logger.
• The pyramid.config.Configurator.include() method now accepts only a single
callable argument. A sequence of callables used to be permitted. If you are passing more than
one callable to pyramid.config.Configurator.include(), it will break. You now
must now instead make a separate call to the method for each callable.
• It may be necessary to more strictly order configuration route and view statements when using an
”autocommitting” Configurator. In the past, it was possible to add a view which named a route name
before adding a route with that name when you used an autocommitting configurator. For example:

config = Configurator(autocommit=True)
config.add_view('my.pkg.someview', route_name='foo')
config.add_route('foo', '/foo')

The above will raise an exception when the view attempts to add itself. Now you must add the route
before adding the view:

config = Configurator(autocommit=True)
config.add_route('foo', '/foo')
config.add_view('my.pkg.someview', route_name='foo')

This won’t effect ”normal” users, only people who have legacy BFG codebases that used an autocom-
mitting configurator and possibly tests that use the configurator API (the configurator returned by
pyramid.testing.setUp() is an autocommitting configurator). The right way to get around
this is to use a default non-autocommitting configurator, which does not have these directive ordering
requirements:

0.6. Change History 955


The Pyramid Web Framework, Version 2.0.2

config = Configurator()
config.add_view('my.pkg.someview', route_name='foo')
config.add_route('foo', '/foo')

The above will work fine.

• The pyramid.config.Configurator.add_route() directive no longer returns a route


object. This change was required to make route vs. view configuration processing work properly.

Behavior Differences

• An ETag header is no longer set when serving a static file. A Last-Modified header is set instead.
• Static file serving no longer supports the wsgi.file_wrapper extension.
• Instead of returning a 403 Forbidden error when a static file is served that cannot be accessed
by the Pyramid process’ user due to file permissions, an IOError (or similar) will be raised.

Documentation Enhancements

• Narrative and API documentation which used the route_url, route_path, resource_url,
static_url, and current_route_url functions in the pyramid.url package have now
been changed to use eponymous methods of the request instead.
• Added a section entitled Using a Route Prefix to Compose Applications to the ”URL Dispatch”
narrative documentation chapter.
• Added a new module to the API docs: pyramid.tweens.
• Added a Registering Tweens section to the ”Hooks” narrative chapter.
• Added a ptweens: Displaying ”Tweens” section to the ”Command-Line Pyramid” narrative chapter.
• Added documentation for Explicit Tween Configuration and Including Packages to the ”Environment
Variables and .ini Files Settings” chapter.
• Added a Logging chapter to the narrative docs.
• All tutorials now use - The route_url, route_path, resource_url, static_url, and
current_route_url methods of the pyramid.request.Request rather than the func-
tion variants imported from pyramid.url.
• The ZODB wiki tutorial now uses the pyramid_zodbconn package rather than the repoze.
zodbconn package to provide ZODB integration.
• Added What makes Pyramid unique to the Introduction narrative chapter.

956 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Dependency Changes

• Pyramid now relies on PasteScript >= 1.7.4. This version contains a feature important for allowing
flexible logging configuration.
• Pyramid now requires Venusian 1.0a1 or better to support the onerror keyword argument to
pyramid.config.Configurator.scan().
• The zope.configuration package is no longer a dependency.

0.6.7 What’s New in Pyramid 1.1

This article explains the new features in Pyramid version 1.1 as compared to its predecessor, Pyramid
1.0. It also documents backwards incompatibilities between the two versions and deprecations added to
Pyramid 1.1, as well as software dependency changes and notable documentation additions.

Terminology Changes

The term ”template” used by the Pyramid documentation used to refer to both ”paster templates” and
”rendered templates” (templates created by a rendering engine. i.e. Mako, Chameleon, Jinja, etc.). ”Paster
templates” will now be referred to as ”scaffolds”, whereas the name for ”rendered templates” will remain
as ”templates.”

Major Feature Additions

The major feature additions in Pyramid 1.1 are:

• Support for the request.response attribute.


• New views introspection feature: paster pviews.
• Support for ”static” routes.
• Default HTTP exception view.
• http_cache view configuration parameter causes Pyramid to set HTTP caching headers.
• Features that make it easier to write scripts that work in a Pyramid environment.

0.6. Change History 957


The Pyramid Web Framework, Version 2.0.2

request.response

• Instances of the pyramid.request.Request class now have a response attribute.


The object passed to a view callable as request is an instance of pyramid.request.
Request. request.response is an instance of the class pyramid.response.
Response. View callables that are configured with a renderer will return this response object
to the Pyramid router. Therefore, code in a renderer-using view callable can set response attributes
such as request.response.content_type (before they return, e.g. a dictionary to the ren-
derer) and this will influence the HTTP return value of the view callable.
request.response can also be used in view callable code that is not configured to use a ren-
derer. For example, a view callable might do request.response.body = '123'; return
request.response. However, the response object that is produced by request.response
must be returned when a renderer is not in play in order to have any effect on the HTTP response (it
is not a ”global” response, and modifications to it are not somehow merged into a separately returned
response object).
The request.response object is lazily created, so its introduction does not negatively impact
performance.

paster pviews

• A new paster command named paster pviews was added. This command prints a summary of
potentially matching views for a given path. See the section entitled pviews: Displaying Matching
Views for a Given URL for more information.

Static Routes

• The add_route method of the Configurator now accepts a static argument. If this argument
is True, the added route will never be considered for matching when a request is handled. Instead,
it will only be useful for URL generation via route_url and route_path. See the section
entitled Static Routes for more information.

958 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Default HTTP Exception View

• A default exception view for the interface pyramid.interfaces.IExceptionResponse


is now registered by default. This means that an instance of any exception class imported from
pyramid.httpexceptions (such as HTTPFound) can now be raised from within view code;
when raised, this exception view will render the exception to a response.
To allow for configuration of this feature, the Configurator now accepts an additional keyword argu-
ment named exceptionresponse_view. By default, this argument is populated with a default
exception view function that will be used when an HTTP exception is raised. When None is passed
for this value, an exception view for HTTP exceptions will not be registered. Passing None returns
the behavior of raising an HTTP exception to that of Pyramid 1.0 (the exception will propagate to
middleware and to the WSGI server).

http_cache

A new value http_cache can be used as a view configuration parameter.

When you supply an http_cache value to a view configuration, the Expires and Cache-Control
headers of a response generated by the associated view callable are modified. The value for http_cache
may be one of the following:

• A nonzero integer. If it’s a nonzero integer, it’s treated as a number of seconds. This number of
seconds will be used to compute the Expires header and the Cache-Control: max-age pa-
rameter of responses to requests which call this view. For example: http_cache=3600 instructs
the requesting browser to ’cache this response for an hour, please’.
• A datetime.timedelta instance. If it’s a datetime.timedelta instance, it will be con-
verted into a number of seconds, and that number of seconds will be used to compute the Expires
header and the Cache-Control: max-age parameter of responses to requests which call this
view. For example: http_cache=datetime.timedelta(days=1) instructs the requesting
browser to ’cache this response for a day, please’.
• Zero (0). If the value is zero, the Cache-Control and Expires headers present in all responses
from this view will be composed such that client browser cache (and any intermediate caches) are
instructed to never cache the response.
• A two-tuple. If it’s a two tuple (e.g. http_cache=(1, {'public':True})), the first value in
the tuple may be a nonzero integer or a datetime.timedelta instance; in either case this value
will be used as the number of seconds to cache the response. The second value in the tuple must be
a dictionary. The values present in the dictionary will be used as input to the Cache-Control re-
sponse header. For example: http_cache=(3600, {'public':True}) means ’cache for

0.6. Change History 959


The Pyramid Web Framework, Version 2.0.2

an hour, and add public to the Cache-Control header of the response’. All keys and values sup-
ported by the webob.cachecontrol.CacheControl interface may be added to the dictio-
nary. Supplying {'public':True} is equivalent to calling response.cache_control.
public = True.

Providing a non-tuple value as http_cache is equivalent to calling response.


cache_expires(value) within your view’s body.

Providing a two-tuple value as http_cache is equivalent to calling response.


cache_expires(value[0], **value[1]) within your view’s body.

If you wish to avoid influencing, the Expires header, and instead wish to only influence
Cache-Control headers, pass a tuple as http_cache with the first element of None, e.g.: (None,
{'public':True}).

The environment setting PYRAMID_PREVENT_HTTP_CACHE and configuration file value pre-


vent_http_cache are synonymous and allow you to prevent HTTP cache headers from being set by
Pyramid’s http_cache machinery globally in a process. see Influencing HTTP Caching and Preventing
HTTP Caching.

Easier Scripting Writing

A new API function pyramid.paster.bootstrap() has been added to make writing scripts that
need to work under Pyramid environment easier, e.g.:

from pyramid.paster import bootstrap


info = bootstrap('/path/to/my/development.ini')
request = info['request']
print request.route_url('myroute')

See Writing a Script for more details.

Minor Feature Additions

• It is now possible to invoke paster pshell even if the paste ini file section name pointed to in
its argument is not actually a Pyramid WSGI application. The shell will work in a degraded mode,
and will warn the user. See ”The Interactive Shell” in the ”Creating a Pyramid Project” narrative
documentation section.

960 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The paster pshell, paster pviews, and paster proutes commands each now under
the hood uses pyramid.paster.bootstrap(), which makes it possible to supply an .ini
file without naming the ”right” section in the file that points at the actual Pyramid application.
Instead, you can generally just run paster {pshell|proutes|pviews} development.
ini and it will do mostly the right thing.
• It is now possible to add a [pshell] section to your application’s .ini configuration file, which
influences the global names available to a pshell session. See Extending the Shell.
• The pyramid.config.Configurator.scan() method has grown a **kw argument. kw
argument represents a set of keyword arguments to pass to the Venusian Scanner object created
by Pyramid. (See the Venusian documentation for more information about Scanner).
• New request property: json_body. This property will return the JSON-decoded variant of the
request body. If the request body is not well-formed JSON, this property will raise an exception.
• A JSONP renderer. See JSONP Renderer for more details.
• New authentication policy: pyramid.authentication.
SessionAuthenticationPolicy, which uses a session to store credentials.
• A function named pyramid.httpexceptions.exception_response() is a shortcut
that can be used to create HTTP exception response objects using an HTTP integer status code.
• Integers and longs passed as elements to pyramid.url.resource_url() or pyramid.
request.Request.resource_url() e.g. resource_url(context, request, 1,
2) (1 and 2 are the elements) will now be converted implicitly to strings in the result. Previously
passing integers or longs as elements would cause a TypeError.
• pyramid_alchemy scaffold now uses query.get rather than query.filter_by to take
better advantage of identity map caching.
• pyramid_alchemy scaffold now has unit tests.
• Added a pyramid.i18n.make_localizer() API.
• An exception raised by a pyramid.events.NewRequest event subscriber can now be caught
by an exception view.
• It is now possible to get information about why Pyramid raised a Forbidden exception from within an
exception view. The ACLDenied object returned by the permits method of each stock autho-
rization policy (pyramid.interfaces.IAuthorizationPolicy.permits()) is now
attached to the Forbidden exception as its result attribute. Therefore, if you’ve created a Forbid-
den exception view, you can see the ACE, ACL, permission, and principals involved in the request
as eg. context.result.permission, context.result.acl, etc within the logic of the
Forbidden exception view.
• Don’t explicitly prevent the timeout from being lower than the reissue_time when setting
up an pyramid.authentication.AuthTktAuthenticationPolicy (previously such

0.6. Change History 961


The Pyramid Web Framework, Version 2.0.2

a configuration would raise a ValueError, now it’s allowed, although typically nonsensical).
Allowing the nonsensical configuration made the code more understandable and required fewer tests.
• The pyramid.request.Request class now has a ResponseClass attribute which points
at pyramid.response.Response.
• The pyramid.response.Response class now has a RequestClass interface which points
at pyramid.request.Request.
• It is now possible to return an arbitrary object from a Pyramid view callable even if a renderer
is not used, as long as a suitable adapter to pyramid.interfaces.IResponse is regis-
tered for the type of the returned object by using the new pyramid.config.Configurator.
add_response_adapter() API. See the section in the Hooks chapter of the documentation
entitled Changing How Pyramid Treats View Responses.
• The Pyramid router will now, by default, call the __call__ method of response objects when
returning a WSGI response. This means that, among other things, the conditional_response
feature response objects inherited from WebOb will now behave properly.
• New method named pyramid.request.Request.is_response(). This method should
be used instead of the pyramid.view.is_response() function, which has been deprecated.
• pyramid.exceptions.NotFound is now just an alias for pyramid.httpexceptions.
HTTPNotFound.
• pyramid.exceptions.Forbidden is now just an alias for pyramid.
httpexceptions.HTTPForbidden.
• Added mako.preprocessor config file parameter; allows for a Mako preprocessor to be spec-
ified as a Python callable or Python dotted name. See https://github.com/Pylons/pyramid/pull/183
for rationale.
• New API class: pyramid.static.static_view. This supersedes the (now deprecated)
pyramid.view.static class. pyramid.static.static_view, by default, serves up
documents as the result of the request’s path_info, attribute rather than it’s subpath at-
tribute (the inverse was true of pyramid.view.static, and still is). pyramid.static.
static_view exposes a use_subpath flag for use when you want the static view to behave
like the older deprecated version.
• A new api function pyramid.scripting.prepare() has been added. It is a lower-level
analogue of pyramid.paster.bootstrap() that accepts a request and a registry instead of
a config file argument, and is used for the same purpose:

from pyramid.scripting import prepare


info = prepare(registry=myregistry)
request = info['request']
print request.route_url('myroute')

962 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• A new API function pyramid.scripting.make_request() has been added. The resulting


request will have a registry attribute. It is meant to be used in conjunction with pyramid.
scripting.prepare() and/or pyramid.paster.bootstrap() (both of which accept a
request as an argument):

from pyramid.scripting import make_request


request = make_request('/')

• New API attribute pyramid.config.global_registries is an iterable object that con-


tains references to every Pyramid registry loaded into the current process via pyramid.config.
Configurator.make_wsgi_app(). It also has a last attribute containing the last registry
loaded. This is used by the scripting machinery, and is available for introspection.
• Added the pyramid.renderers.null_renderer object as an API. The null renderer is an
object that can be used in advanced integration cases as input to the view configuration renderer=
argument. When the null renderer is used as a view renderer argument, Pyramid avoids converting
the view callable result into a Response object. This is useful if you want to reuse the view configu-
ration and lookup machinery outside the context of its use by the Pyramid router. (This feature was
added for consumption by the pyramid_rpc package, which uses view configuration and lookup
outside the context of a router in exactly this way.)

Backwards Incompatibilities

• Pyramid no longer supports Python 2.4. Python 2.5 or better is required to run Pyramid 1.1+. Pyra-
mid, however, does not work under any version of Python 3 yet.
• The Pyramid router now, by default, expects response objects returned from view callables to im-
plement the pyramid.interfaces.IResponse interface. Unlike the Pyramid 1.0 version of
this interface, objects which implement IResponse now must define a __call__ method that ac-
cepts environ and start_response, and which returns an app_iter iterable, among other
things. Previously, it was possible to return any object which had the three WebOb app_iter,
headerlist, and status attributes as a response, so this is a backwards incompatibility. It is
possible to get backwards compatibility back by registering an adapter to IResponse from the type
of object you’re now returning from view callables. See the section in the Hooks chapter of the
documentation entitled Changing How Pyramid Treats View Responses.
• The pyramid.interfaces.IResponse interface is now much more extensive. Previously
it defined only app_iter, status and headerlist; now it is basically intended to directly
mirror the webob.Response API, which has many methods and attributes.
• The pyramid.httpexceptions classes named HTTPFound, HTTPMultipleChoices,
HTTPMovedPermanently, HTTPSeeOther, HTTPUseProxy, and HTTPTempo-
raryRedirect now accept location as their first positional argument rather than

0.6. Change History 963


The Pyramid Web Framework, Version 2.0.2

detail. This means that you can do, e.g. return pyramid.httpexceptions.
HTTPFound('http://foo') rather than return pyramid.httpexceptions.
HTTPFound(location='http//foo') (the latter will of course continue to work).
• The pyramid Router attempted to set a value into the key environ['repoze.bfg.message']
when it caught a view-related exception for backwards compatibility with applications written for
repoze.bfg during error handling. It did this by using code that looked like so:

# "why" is an exception object


try:
msg = why[0]
except:
msg = ''

environ['repoze.bfg.message'] = msg

Use of the value environ['repoze.bfg.message'] was docs-deprecated in Pyramid 1.0.


Our standing policy is to not remove features after a deprecation for two full major releases, so this
code was originally slated to be removed in Pyramid 1.2. However, computing the repoze.bfg.
message value was the source of at least one bug found in the wild (https://github.com/Pylons/
pyramid/issues/199), and there isn’t a foolproof way to both preserve backwards compatibility and
to fix the bug. Therefore, the code which sets the value has been removed in this release. Code
in exception views which relies on this value’s presence in the environment should now use the
exception attribute of the request (e.g. request.exception[0]) to retrieve the message
instead of relying on request.environ['repoze.bfg.message'].

Deprecations and Behavior Differences

Under Python 2.7+, it’s necessary to pass the Python interpreter the correct warning flags to see
deprecation warnings emitted by Pyramid when porting your application from an older version of Pyramid.
Use the PYTHONWARNINGS environment variable with the value all in the shell you use to invoke
paster serve to see these warnings, e.g. on Unix, PYTHONWARNINGS=all $VENV/bin/paster
serve development.ini. Python 2.5 and 2.6 show deprecation warnings by default, so this is
unnecessary there. All deprecation warnings are emitted to the console.

• The pyramid.view.static class has been deprecated in favor of the newer pyramid.
static.static_view class. A deprecation warning is raised when it is used. You should re-
place it with a reference to pyramid.static.static_view with the use_subpath=True
argument.

964 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The paster pshell, paster proutes, and paster pviews commands now take a
single argument in the form /path/to/config.ini#sectionname rather than the previ-
ous 2-argument spelling /path/to/config.ini sectionname. #sectionname may be
omitted, in which case #main is assumed.
• The default Mako renderer is now configured to escape all HTML in expression tags. This is intended
to help prevent XSS attacks caused by rendering unsanitized input from users. To revert this behavior
in user’s templates, they need to filter the expression through the ’n’ filter:

${ myhtml | n }.

See https://github.com/Pylons/pyramid/issues/193.
• Deprecated all assignments to request.response_* attributes (for example request.
response_content_type = 'foo' is now deprecated). Assignments and mutations of
assignable request attributes that were considered by the framework for response influence are now
deprecated: response_content_type, response_headerlist, response_status,
response_charset, and response_cache_for. Instead of assigning these to the re-
quest object for later detection by the rendering machinery, users should use the appropri-
ate API of the Response object created by accessing request.response (e.g. code which
does request.response_content_type = 'abc' should be changed to request.
response.content_type = 'abc').
• Passing view-related parameters to pyramid.config.Configurator.add_route() is
now deprecated. Previously, a view was permitted to be connected to a route using a set of view*
parameters passed to the add_route method of the Configurator. This was a shorthand which
replaced the need to perform a subsequent call to add_view. For example, it was valid (and often
recommended) to do:

config.add_route('home', '/', view='mypackage.views.myview',


view_renderer='some/renderer.pt')

Passing view* arguments to add_route is now deprecated in favor of connecting a view to


a predefined route via pyramid.config.Configurator.add_view() using the route’s
route_name parameter. As a result, the above example should now be spelled:

config.add_route('home', '/')
config.add_view('mypackage.views.myview', route_name='home',
renderer='some/renderer.pt')

This deprecation was done to reduce confusion observed in IRC, as well as to (eventually) reduce
documentation burden. A deprecation warning is now issued when any view-related parameter is
passed to add_route.

0.6. Change History 965


The Pyramid Web Framework, Version 2.0.2

See also:
See also issue #164 on GitHub.
• Passing an environ dictionary to the __call__ method of a ”traverser” (e.g. an object
that implements pyramid.interfaces.ITraverser such as an instance of pyramid.
traversal.ResourceTreeTraverser) as its request argument now causes a depreca-
tion warning to be emitted. Consumer code should pass a request object instead. The fact that
passing an environ dict is permitted has been documentation-deprecated since repoze.bfg 1.1,
and this capability will be removed entirely in a future version.
• The following (undocumented, dictionary-like) methods of the pyramid.request.Request
object have been deprecated: __contains__, __delitem__, __getitem__, __iter__,
__setitem__, get, has_key, items, iteritems, itervalues, keys, pop, popitem,
setdefault, update, and values. Usage of any of these methods will cause a deprecation
warning to be emitted. These methods were added for internal compatibility in repoze.bfg 1.1
(code that currently expects a request object expected an environ object in BFG 1.0 and before). In
a future version, these methods will be removed entirely.
• A custom request factory is now required to return a request object that has a response attribute
(or ”reified”/lazy property) if the request is meant to be used in a view that uses a renderer. This
response attribute should be an instance of the class pyramid.response.Response.
• The JSON and string renderer factories now assign to request.response.content_type
rather than request.response_content_type.
• Each built-in renderer factory now determines whether it should change the content type of the
response by comparing the response’s content type against the response’s default content type; if
the content type is the default content type (usually text/html), the renderer changes the content
type (to application/json or text/plain for JSON and string renderers respectively).
• The pyramid.wsgi.wsgiapp2() now uses a slightly different method of figuring out how to
”fix” SCRIPT_NAME and PATH_INFO for the downstream application. As a result, those values
may differ slightly from the perspective of the downstream application (for example, SCRIPT_NAME
will now never possess a trailing slash).
• Previously, pyramid.request.Request inherited from webob.request.Request and
implemented __getattr__, __setattr__ and __delattr__ itself in order to override ”ad-
hoc attr” WebOb behavior where attributes of the request are stored in the environ. Now, pyramid.
request.Request inherits from (the more recent) webob.request.BaseRequest instead
of webob.request.Request, which provides the same behavior. pyramid.request.
Request no longer implements its own __getattr__, __setattr__ or __delattr__ as
a result.
• Deprecated pyramid.view.is_response() function in favor of (newly-added) pyramid.
request.Request.is_response() method. Determining if an object is truly a valid re-
sponse object now requires access to the registry, which is only easily available as a request attribute.

966 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The pyramid.view.is_response() function will still work until it is removed, but now may
return an incorrect answer under some (very uncommon) circumstances.
• pyramid.response.Response is now a subclass of webob.response.Response (in
order to directly implement the pyramid.interfaces.IResponse interface, to speed up re-
sponse generation).
• The ”exception response” objects importable from pyramid.httpexceptions (e.g. HTTP-
NotFound) are no longer just import aliases for classes that actually live in webob.exc. Instead,
we’ve defined our own exception classes within the module that mirror and emulate the webob.
exc exception response objects almost entirely. See Pyramid uses its own HTTP exception class
hierarchy rather than webob.exc in the Design Defense chapter for more information.
• When visiting a URL that represented a static view which resolved to a subdirectory, the index.
html of that subdirectory would not be served properly. Instead, a redirect to /subdir would be
issued. This has been fixed, and now visiting a subdirectory that contains an index.html within
a static view returns the index.html properly.
See also:
See also issue #67 on GitHub.
• Deprecated the pyramid.config.Configurator.set_renderer_globals_factory
method and the renderer_globals Configurator constructor parameter. Users should convert
code using this feature to use a BeforeRender event. See the section Using the Before Render Event
in the Hooks chapter.
• In Pyramid 1.0, the pyramid.events.subscriber directive behaved contrary to the docu-
mentation when passed more than one interface object to its constructor. For example, when the
following listener was registered:

@subscriber(IFoo, IBar)
def expects_ifoo_events_and_ibar_events(event):
print event

The Events chapter docs claimed that the listener would be registered and listening for both IFoo
and IBar events. Instead, it registered an ”object event” subscriber which would only be called if an
IObjectEvent was emitted where the object interface was IFoo and the event interface was IBar.
The behavior now matches the documentation. If you were relying on the buggy behavior of the
1.0 subscriber directive in order to register an object event subscriber, you must now pass a
sequence to indicate you’d like to register a subscriber for an object event. e.g.:

@subscriber([IFoo, IBar])
def expects_object_event(object, event):
print object, event

0.6. Change History 967


The Pyramid Web Framework, Version 2.0.2

• In 1.0, if a pyramid.events.BeforeRender event subscriber added a value via the


__setitem__ or update methods of the event object with a key that already existed
in the renderer globals dictionary, a KeyError was raised. With the deprecation of the
”add_renderer_globals” feature of the configurator, there was no way to override an existing value
in the renderer globals dictionary that already existed. Now, the event object will overwrite an older
value that is already in the globals dictionary when its __setitem__ or update is called (as well
as the new setdefault method), just like a plain old dictionary. As a result, for maximum inter-
operability with other third-party subscribers, if you write an event subscriber meant to be used as a
BeforeRender subscriber, your subscriber code will now need to (using .get or __contains__
of the event object) ensure no value already exists in the renderer globals dictionary before setting
an overriding value.
• The pyramid.config.Configurator.add_route() method allowed two routes with the
same route to be added without an intermediate call to pyramid.config.Configurator.
commit(). If you now receive a ConfigurationError at startup time that appears to be
add_route related, you’ll need to either a) ensure that all of your route names are unique or b)
call config.commit() before adding a second route with the name of a previously added name
or c) use a Configurator that works in autocommit mode.

Dependency Changes

• Pyramid now depends on WebOb >= 1.0.2 as tests depend on the bugfix in that release: ”Fix handling
of WSGI environs with missing SCRIPT_NAME”. (Note that in reality, everyone should probably
be using 1.0.4 or better though, as WebOb 1.0.2 and 1.0.3 were effectively brownbag releases.)

Documentation Enhancements

• Added a section entitled Writing a Script to the ”Command-Line Pyramid” chapter.


• The ZODB + Traversal Wiki Tutorial was updated slightly.
• The SQLAlchemy + URL dispatch wiki tutorial was updated slightly.
• Made pyramid.interfaces.IAuthenticationPolicy and pyramid.
interfaces.IAuthorizationPolicy public interfaces, and they are now referred to
within the pyramid.authentication and pyramid.authorization API docs.
• Render the function definitions for each exposed interface in pyramid.interfaces.
• Add missing docs reference to pyramid.config.Configurator.set_view_mapper()
and refer to it within the documentation section entitled Using a View Mapper.
• Added section to the ”Environment Variables and .ini File Settings” chapter in the narrative doc-
umentation section entitled Adding a Custom Setting.

968 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Added documentation for a multidict as pyramid.interfaces.IMultiDict.


• Added a section to the ”URL Dispatch” narrative chapter regarding the new ”static” route feature
entitled Static Routes.
• Added API docs for pyramid.httpexceptions.exception_response().
• Added HTTP Exceptions section to Views narrative chapter including a description of pyramid.
httpexceptions.exception_response().
• Added API docs for pyramid.authentication.SessionAuthenticationPolicy.

0.6.8 What’s New in Pyramid 1.0

This article explains the new features in Pyramid version 1.0 as compared to its predecessor, repoze.
bfg 1.3. It also documents backwards incompatibilities between the two versions and deprecations added
to Pyramid 1.0, as well as software dependency changes and notable documentation additions.

Major Feature Additions

The major feature additions in Pyramid 1.0 are:


• New name and branding association with the Pylons Project.
• BFG conversion script
• Scaffold improvements
• Terminology changes
• Better platform compatibility and support
• Direct built-in support for the Mako templating language.
• Built-in support for sessions.
• Updated URL dispatch features
• Better imperative extensibility
• ZCML externalized
• Better support for global template variables during rendering
• View mappers
• Testing system improvements
• Authentication support improvements
• Documentation improvements

0.6. Change History 969


The Pyramid Web Framework, Version 2.0.2

New Name and Branding

The name of repoze.bfg has been changed to Pyramid. The project is also now a subproject of a new
entity, ”The Pylons Project”. The Pylons Project is the project name for a collection of web-framework-
related technologies. Pyramid was the first package in the Pylons Project. Other packages to the collection
have been added over time, such as support packages useful for Pylons 1 users as well as ex-Zope users.
Pyramid is the successor to both repoze.bfg and Pylons version 1.

The Pyramid codebase is derived almost entirely from repoze.bfg with some changes made for the
sake of Pylons 1 compatibility.

Pyramid is technically backwards incompatible with repoze.bfg, as it has a new package name, so
older imports from the repoze.bfg module will fail if you do nothing to your existing repoze.bfg
application. However, you won’t have to do much to use your existing BFG applications on Pyramid.
There’s automation which will change most of your import statements and ZCML declarations. See https://
docs.pylonsproject.org/projects/pyramid/en/1.0-branch/tutorials/bfg/index.html for upgrade instructions.

Pylons 1 users will need to do more work to use Pyramid, as Pyramid shares no ”DNA” with Pylons. It is
hoped that over time documentation and upgrade code will be developed to help Pylons 1 users transition
to Pyramid more easily.

repoze.bfg version 1.3 will be its last major release. Minor updates will be made for critical bug fixes.
Pylons version 1 will continue to see maintenance releases, as well.

The Repoze project will continue to exist. Repoze will be able to regain its original focus: bringing Zope
technologies to WSGI. The popularity of repoze.bfg as its own web framework hindered this goal.

We hope that people are attracted at first by the spirit of cooperation demonstrated by the Pylons Project
and the merging of development communities. It takes humility to sacrifice a little sovereignty and work
together. The opposite, forking or splintering of projects, is much more common in the open source world.
We feel there is a limited amount of oxygen in the space of ”top-tier” Python web frameworks and we
don’t do the Python community a service by over-crowding. By merging the repoze.bfg and the
philosophically-similar Pylons communities, both gain an expanded audience and a stronger chance of
future success.

BFG Conversion Script

The bfg2pyramid conversion script performs a mostly automated conversion of an existing repoze.
bfg application to Pyramid. The process is described in ”Converting a BFG Application to Pyramid”.

970 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Scaffold Improvements

• The scaffolds now have much nicer CSS and graphics.


• The development.ini, generated by all scaffolds, is now configured to use the WebError inter-
active exception debugger by default.
• All scaffolds have been normalized: each now uses the name main to represent the function that
returns a WSGI application, and each now has roughly the same shape of development.ini style.
• All preexisting scaffolds now use ”imperative” configuration (starter, routesalchemy,
alchemy, zodb) instead of ZCML configuration.
• The pyramid_zodb, routesalchemy and pyramid_alchemy scaffolds now use a default
”commit veto” hook when configuring the repoze.tm2 transaction manager in development.
ini. This prevents a transaction from being committed when the response status code is within the
400 or 500 ranges.
See also:
See also https://repozetm2.readthedocs.io/en/latest/#using-a-commit-veto.

Terminology Changes

• The Pyramid concept previously known as ”model” is now known as ”resource”. As a result, the
following API renames have been made. Backwards compatibility shims for the old names have
been left in place in all cases:

pyramid.url.model_url ->
pyramid.url.resource_url

pyramid.traversal.find_model ->
pyramid.url.find_resource

pyramid.traversal.model_path ->
pyramid.traversal.resource_path

pyramid.traversal.model_path_tuple ->
pyramid.traversal.resource_path_tuple

pyramid.traversal.ModelGraphTraverser ->
pyramid.traversal.ResourceTreeTraverser

pyramid.config.Configurator.testing_models ->
(continues on next page)

0.6. Change History 971


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


pyramid.config.Configurator.testing_resources

pyramid.testing.registerModels ->
pyramid.testing.registerResources

pyramid.testing.DummyModel ->
pyramid.testing.DummyResource

• All documentation which previously referred to ”model” now refers to ”resource”.


• The starter scaffold now has a resources.py module instead of a models.py module.
• Positional argument names of various APIs have been changed from model to resource.
• The Pyramid concept previously known as ”resource” is now known as ”asset”. As a result, the
following API changes were made. Backwards compatibility shims have been left in place as nec-
essary:

pyramid.config.Configurator.absolute_resource_spec ->
pyramid.config.Configurator.absolute_asset_spec

pyramid.config.Configurator.override_resource ->
pyramid.config.Configurator.override_asset

• The (non-API) module previously known as pyramid.resource is now known as pyramid.


asset.
• All docs that previously referred to ”resource specification” now refer to ”asset specification”.
• The setting previously known as BFG_RELOAD_RESOURCES (envvar) or reload_resources
(config file) is now known, respectively, as PYRAMID_RELOAD_ASSETS and reload_assets.

Better Platform Compatibility and Support

We’ve made Pyramid’s test suite pass on both Jython and PyPy. However, Chameleon doesn’t work on
either, so you’ll need to use Mako or Jinja2 templates on these platforms.

972 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Sessions

Pyramid now has built-in sessioning support, documented in Sessions. The sessioning implementation is
pluggable. It also provides flash messaging and cross-site-scripting prevention features.

Using request.session now returns a (dictionary-like) session object if a session factory has been
configured.

A new argument to the Configurator constructor exists: session_factory and a new method on the
configurator exists: pyramid.config.Configurator.set_session_factory().

Mako

In addition to Chameleon templating, Pyramid now also provides built-in support for Mako templating.
See Available Add-On Template System Bindings for more information.

URL Dispatch

• URL Dispatch now allows for replacement markers to be located anywhere in the pattern, instead of
immediately following a /.
• URL Dispatch now uses the form {marker} to denote a replace marker in the route pattern instead
of :marker. The old colon-style marker syntax is still accepted for backwards compatibility. The
new format allows a regular expression for that marker location to be used instead of the default
[^/]+, for example {marker:\d+} is now valid to require the marker to be digits.
• Addded a new API pyramid.url.current_route_url(), which computes a URL based
on the ”current” route (if any) and its matchdict values.
• Added a paster proute command which displays a summary of the routing table. See the
narrative documentation section entitled proutes: Displaying All Application Routes.
• Added debug_routematch configuration setting (settable in your .ini file) that logs matched
routes including the matchdict and predicates.
• Add a pyramid.url.route_path() API, allowing folks to generate relative URLs. Call-
ing route_path is the same as calling pyramid.url.route_url() with the argument
_app_url equal to the empty string.
• Add a pyramid.request.Request.route_path() API. This is a convenience method of
the request which calls pyramid.url.route_url().
• Added class vars matchdict and matched_route to pyramid.request.Request. Each
is set to None when a route isn’t matched during a request.

0.6. Change History 973


The Pyramid Web Framework, Version 2.0.2

ZCML Externalized

• The load_zcml method of a Configurator has been removed from the Pyramid core. Loading
ZCML is now a feature of the pyramid_zcml package, which can be downloaded from PyPI. See
documentation for the package, which describes how to add a configuration statement to your main
block to reobtain this method. You will also need to add an install_requires dependency
upon the pyramid_zcml distribution to your setup.py file.
• The ”Declarative Configuration” narrative chapter has been removed (it was moved to the pyra-
mid_zcml package).
• Most references to ZCML in narrative chapters have been removed or redirected to pyramid_zcml
locations.
• The starter_zcml paster scaffold has been moved to the pyramid_zcml package.

Imperative Two-Phase Configuration

To support application extensibility, the Pyramid Configurator, by default, now detects configuration con-
flicts and allows you to include configuration imperatively from other packages or modules. It also, by
default, performs configuration in two separate phases. This allows you to ignore relative configuration
statement ordering in some circumstances. See Advanced Configuration for more information.
The pyramid.config.Configurator.add_directive() allows framework extenders to add
methods to the configurator, which allows extenders to avoid subclassing a Configurator just to add meth-
ods. See Adding Methods to the Configurator via add_directive for more info.
Surrounding application configuration with config.begin() and config.end() is no longer nec-
essary. All scaffolds have been changed to no longer call these functions.

Better Support for Global Template Variables During Rendering

A new event type named pyramid.interfaces.IBeforeRender is now sent as an event before


a renderer is invoked. Applications may now subscribe to the IBeforeRender event type in order to
introspect the and modify the set of renderer globals before they are passed to a renderer. The event object
iself has a dictionary-like interface that can be used for this purpose. For example:

from repoze.events import subscriber


from pyramid.interfaces import IRendererGlobalsEvent

@subscriber(IRendererGlobalsEvent)
def add_global(event):
event['mykey'] = 'foo'

974 CONTENTS
The Pyramid Web Framework, Version 2.0.2

View Mappers

A ”view mapper” subsystem has been extracted, which allows framework extenders to control how view
callables are constructed and called. This feature is not useful for ”civilians”, only for extension writers.
See Using a View Mapper for more information.

Testing Support Improvements

The pyramid.testing.setUp() and pyramid.testing.tearDown() APIs have been un-


deprecated. They are now the canonical setup and teardown APIs for test configuration, replacing ”direct”
creation of a Configurator. This is a change designed to provide a facade that will protect against any future
Configurator deprecations.

Authentication Support Improvements

• The pyramid.interfaces.IAuthenticationPolicy interface now specifies an unau-


thenticated_userid method. This method supports an important optimization required by
people who are using persistent storages which do not support object caching and whom want to
create a ”user object” as a request attribute.
• A new API has been added to the pyramid.security module named unauthenti-
cated_userid. This API function calls the unauthenticated_userid method of the ef-
fective security policy.
• The class pyramid.authentication.AuthTktCookieHelper is now an API. This class
can be used by third-party authentication policy developers to help in the mechanics of authentication
cookie-setting.
• The pyramid.authentication.AuthTktAuthenticationPolicy now accepts a to-
kens parameter via pyramid.security.remember(). The value must be a sequence of
strings. Tokens are placed into the auth_tkt ”tokens” field and returned in the auth_tkt cookie.
• Added a wild_domain argument to pyramid.authentication.
AuthTktAuthenticationPolicy, which defaults to True. If it is set to False, the
feature of the policy which sets a cookie with a wilcard domain will be turned off.

0.6. Change History 975


The Pyramid Web Framework, Version 2.0.2

Documentation Improvements

• Casey Duncan, a good friend, and an excellent technical writer has given us the gift of professionally
editing the entire Pyramid documentation set. Any faults in the documentation are the development
team’s, and all improvements are his.
• The ”Resource Location and View Lookup” chapter has been replaced with a variant of
Rob Miller’s ”Much Ado About Traversal” (originally published at https://web.archive.org/web/
20150603023226/http://blog.nonsequitarian.org/2010/much-ado-about-traversal/).
• Many users have contributed documentation fixes and improvements including Ben Bangert, Blaise
Laflamme, Rob Miller, Mike Orr, Carlos de la Guardia, Paul Everitt, Tres Seaver, John Shipman,
Marius Gedminas, Chris Rossi, Joachim Krebs, Xavier Spriet, Reed O’Brien, William Chambers,
Charlie Choiniere, and Jamaludin Ahmad.

Minor Feature Additions

• The settings dictionary passed to the Configurator is now available as config.registry.


settings in configuration code and request.registry.settings in view code).
• pyramid.config.Configurator.add_view() now accepts a decorator keyword ar-
gument, a callable which will decorate the view callable before it is added to the registry.
• Allow static renderer provided during view registration to be overridden at request time via a request
attribute named override_renderer, which should be the name of a previously registered ren-
derer. Useful to provide ”omnipresent” RPC using existing rendered views.
• If a resource implements a __resource_url__ method, it will be called as the result of invoking
the pyramid.url.resource_url() function to generate a URL, overriding the default logic.
See Generating the URL of a Resource for more information.
• The name registry is now available in a pshell environment by default. It is the application
registry object.
• Added support for json on Google App Engine by catching NotImplementedError and im-
porting simplejson from django.utils.
• Added the pyramid.httpexceptions module, which is a facade for the webob.exc module.
• New class: pyramid.response.Response. This is a pure facade for webob.Response
(old code need not change to use this facade, it’s existence is mostly for vanity and documentation-
generation purposes).
• The request now has a new attribute: tmpl_context for benefit of Pylons users.
• New API methods for pyramid.request.Request: model_url, route_url, and
static_url. These are simple passthroughs for their respective functions in pyramid.url.

976 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• When a pyramid.exceptions.Forbidden error is raised, its status code now 403 For-
bidden. It was previously 401 Unauthorized, for backwards compatibility purposes with
repoze.bfg. This change will cause problems for users of Pyramid with repoze.who, which
intercepts 401 Unauthorized by default, but allows 403 Forbidden to pass through. Those
deployments will need to configure repoze.who to also react to 403 Forbidden. To do so,
use a repoze.who challenge_decider that looks like this:

import zope.interface
from repoze.who.interfaces import IChallengeDecider

def challenge_decider(environ, status, headers):


return status.startswith('403') or status.startswith('401')
zope.interface.directlyProvides(challenge_decider, IChallengeDecider)

• The paster bfgshell command is now known as paster pshell.


• There is no longer an IDebugLogger object registered as a named utility with the name repoze.
bfg.debug.
• These deprecated APIs have been removed: pyramid.testing.
registerViewPermission, pyramid.testing.registerRoutesMapper,
pyramid.request.get_request, pyramid.security.Unauthorized, pyramid.
view.view_execution_permitted, pyramid.view.NotFound
• The Venusian ”category” for all built-in Venusian decorators (e.g. subscriber and
view_config/bfg_view) is now pyramid instead of bfg.
• The pyramid.renderers.rendered_response function removed; use pyramid.
renderers.render_to_response() instead.
• Renderer factories now accept a renderer info object rather than an absolute resource specification or
an absolute path. The object has the following attributes: name (the renderer= value), package
(the ’current package’ when the renderer configuration statement was found), type: the renderer
type, registry: the current registry, and settings: the deployment settings dictionary. Third-
party repoze.bfg renderer implementations that must be ported to Pyramid will need to account
for this. This change was made primarily to support more flexible Mako template rendering.
• The presence of the key repoze.bfg.message in the WSGI environment when an exception
occurs is now deprecated. Instead, code which relies on this environ value should use the excep-
tion attribute of the request (e.g. request.exception[0]) to retrieve the message.
• The values bfg_localizer and bfg_locale_name kept on the request during internation-
alization for caching purposes were never APIs. These however have changed to localizer and
locale_name, respectively.

0.6. Change History 977


The Pyramid Web Framework, Version 2.0.2

• The default cookie_name value of the pyramid.authentication.


AuthTktAuthenticationPolicy now defaults to auth_tkt (it used to default to
repoze.bfg.auth_tkt).
• The pyramid.testing.zcml_configure() API has been removed. It had been advertised
as removed since repoze.bfg 1.2a1, but hadn’t actually been.
• All environment variables which used to be prefixed with BFG_ are now prefixed with PYRAMID_
(e.g. BFG_DEBUG_NOTFOUND is now PYRAMID_DEBUG_NOTFOUND)
• Since the pyramid.interfaces.IAuthenticationPolicy interface now specifies that a
policy implementation must implement an unauthenticated_userid method, all third-party
custom authentication policies now must implement this method. It, however, will only be called
when the global function named pyramid.security.unauthenticated_userid() is
invoked, so if you’re not invoking that, you will not notice any issues.
• The configure_zcml setting within the deployment settings (within **settings passed to a
Pyramid main function) has ceased to have any meaning.
• The make_app function has been removed from the pyramid.router module. It continues
life within the pyramid_zcml package. This leaves the pyramid.router module without
any API functions.

Deprecations and Behavior Differences

• pyramid.configuration.Configurator is now deprecated. Use pyramid.config.


Configurator, passing its constructor autocommit=True instead. The pyramid.
configuration.Configurator alias will live for a long time, as every application uses
it, but its import now issues a deprecation warning. The pyramid.config.Configurator
class has the same API as the pyramid.configuration.Configurator class, which it
means to replace, except by default it is a non-autocommitting configurator. The now-deprecated
pyramid.configuration.Configurator will autocommit every time a configuration
method is called. The pyramid.configuration module remains, but it is deprecated. Use
pyramid.config instead.
• The pyramid.settings.get_settings() API is now deprecated. Use pyramid.
threadlocals.get_current_registry().settings instead or use the settings
attribute of the registry available from the request (request.registry.settings).
• The decorator previously known as pyramid.view.bfg_view is now known most formally as
pyramid.view.view_config in docs and scaffolds.
• Obtaining the settings object via registry.{get|query}Utility(ISettings) is
now deprecated. Instead, obtain the settings object via the registry.settings attribute.
A backwards compatibility shim was added to the registry object to register the settings object as
an ISettings utility when setattr(registry, 'settings', foo) is called, but it will be
removed in a later release.

978 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Obtaining the settings object via pyramid.settings.get_settings() is now depre-


cated. Obtain it instead as the settings attribute of the registry now (obtain the registry via
pyramid.threadlocal.get_registry() or as request.registry).

Dependency Changes

• Depend on Venusian >= 0.5 (for scanning conflict exception decoration).

Documentation Enhancements

• Added a pyramid.httpexceptions API documentation chapter.


• Added a pyramid.session API documentation chapter.
• Added an API chapter for the pyramid.response module.
• Added a Sessions narrative documentation chapter.
• All documentation which previously referred to webob.Response now uses pyramid.
response.Response instead.
• The documentation has been overhauled to use imperative configuration, moving declarative con-
figuration (ZCML) explanations to an external package, pyramid_zcml.
• Removed zodbsessions tutorial chapter. It’s still useful, but we now have a SessionFactory
abstraction which competes with it, and maintaining documentation on both ways to do it is a dis-
traction.
• Added an example of WebTest functional testing to the testing narrative chapter at Creating Func-
tional Tests.
• Extended the Resources chapter with examples of calls to resource-related APIs.
• Add ”Pyramid Provides More Than One Way to Do It” to Design Defense documentation.
• The (weak) ”Converting a CMF Application to Pyramid” tutorial has been removed from the tutori-
als section. It was moved to the pyramid_tutorials Github repository at https://github.com/
Pylons/pyramid_tutorials/commit/38351561b54a2b07e3af5bd43f83964f72d0c05e.
• Moved ”Using ZODB With ZEO” and ”Using repoze.catalog Within Pyramid” tutorials out of core
documentation and into the Pyramid Tutorials site (https://github.com/Pylons/pyramid_tutorials/
commit/86cfd11d8a4093b39cedc686fc6f005db4bccb00).
• Removed API documentation for deprecated pyramid.testing APIs named regis-
terDummySecurityPolicy, registerResources, registerModels, regis-
terEventListener, registerTemplateRenderer, registerDummyRenderer,
registerView, registerUtility, registerAdapter, registerSubscriber,
registerRoute, and registerSettings.

0.6. Change History 979


The Pyramid Web Framework, Version 2.0.2

0.6.9 Pyramid Change History

2.0.2 (2023-08-25)

Bug Fixes

• Removed support for null-bytes in the path when making a request for a file against a static_view.
Whille null-bytes are allowed by the HTTP specification, due to the handling of null-bytes potentially
leading to security vulnerabilities it is no longer supported.
This fixes a security vulnerability that is present due to a bug in Python 3.11.0 through 3.11.4,
thereby allowing the unintended disclosure of an index.html one directory up from the static
views path.
Thanks to Masashi Yamane of LAC Co., Ltd for reporting this issue.

Backward Incompatibilities

• Requests to a static_view are no longer allowed to contain a null-byte in any part of the path segment.

2.0.1 (2023-01-29)

• Add support for Python 3.10 and 3.11.


• Copy __name__ from decorated attribute when using pyramid.decorator.reify. See
https://github.com/Pylons/pyramid/pull/3660
• Fix method signatures in docs for pyramid.config.Configurator.add_static_view
and pyramid.config.Configurator.override_asset. See https://github.com/
Pylons/pyramid/pull/3699
• Remove obsolete stackframe hack used in Python 3.5.0 when showing configurator conflict errors.
See https://github.com/Pylons/pyramid/pull/3700
• Fix an error when injecting certain objects into the pshell env due to the use of !=. See https:
//github.com/Pylons/pyramid/pull/3704
• Pyramid drops support for l*gettext() methods in the i18n module. These have been depre-
cated in Python’s gettext module since 3.8, and removed in Python 3.11. They also shouldn’t be
used at all on Python 3. See https://github.com/Pylons/pyramid/pull/3717
• Avoid setDaemon(True) deprecation warning by updating threading API usage to .daemon =
True.

980 CONTENTS
The Pyramid Web Framework, Version 2.0.2

2.0 (2021-02-28)

• No changes from 2.0b1.

2.0b1 (2021-02-20)

• Break potential reference cycle between request and context. See https://github.com/Pylons/
pyramid/pull/3649
• Remove update_wrapper from pyramid.decorator.reify. See https://github.com/
Pylons/pyramid/pull/3657

2.0b0 (2020-12-15)

• Overhaul tutorials and update cookiecutter to de-emphasize request.user in favor of


request.identity for common use cases. See https://github.com/Pylons/pyramid/pull/3629
• Improve documentation and patterns with builtin fixtures shipped in the cookiecutters. See https:
//github.com/Pylons/pyramid/pull/3629

2.0a0 (2020-11-29)

Features

• Add support for Python 3.9. See https://github.com/Pylons/pyramid/issues/3622


• The aslist method now handles non-string objects when flattening. See https://github.com/
Pylons/pyramid/pull/3594
• It is now possible to pass multiple values to the header predicate for route and view configuration.
See https://github.com/Pylons/pyramid/pull/3576
• Add support for Python 3.8. See https://github.com/Pylons/pyramid/pull/3547
• New security APIs have been added to support a massive overhaul of the authentication and autho-
rization system. Read ”Upgrading Authentication/Authorization” in the ”What’s New in Pyramid
2.0” chapter of the documentation for information about using this new system.
– pyramid.config.Configurator.set_security_policy.
– pyramid.interfaces.ISecurityPolicy

0.6. Change History 981


The Pyramid Web Framework, Version 2.0.2

– pyramid.request.Request.identity.
– pyramid.request.Request.is_authenticated
– pyramid.authentication.SessionAuthenticationHelper
– pyramid.authorization.ACLHelper
– is_authenticated=True/False predicate for route and view configs
See https://github.com/Pylons/pyramid/pull/3465 and https://github.com/Pylons/pyramid/pull/
3598
• Changed the default serializer on pyramid.session.
SignedCookieSessionFactory to use pyramid.session.JSONSerializer
instead of pyramid.session.PickleSerializer. Read ”Upgrading Session Serializa-
tion” in the ”What’s New in Pyramid 2.0” chapter of the documentation for more information about
why this change was made. See https://github.com/Pylons/pyramid/pull/3413
• It is now possible to control whether a route pattern contains a trailing slash when it is composed with
a route prefix using config.include(..., route_prefix=...) or with config.
route_prefix_context(...). This can be done by specifying an empty pattern and setting
the new argument inherit_slash=True. For example:

with config.route_prefix_context('/users'):
config.add_route('users', '', inherit_slash=True)

In the example, the resulting pattern will be /users. Similarly, if the route prefix were /users/
then the final pattern would be /users/. If the pattern was '/', then the final pattern would
always be /users/. This new setting is only available if the pattern supplied to add_route is
the empty string (''). See https://github.com/Pylons/pyramid/pull/3420
• No longer define pyramid.request.Request.json_body which is already provided by
WebOb. This allows the attribute to now be settable. See https://github.com/Pylons/pyramid/pull/
3447
• Improve debugging info from pyramid.view.view_config decorator. See https://github.
com/Pylons/pyramid/pull/3483
• A new parameter, allow_no_origin, was added to pyramid.config.Configurator.
set_default_csrf_options as well as pyramid.csrf.check_csrf_origin. This
option controls whether a request is rejected if it has no Origin or Referer header - often
the result of a user configuring their browser not to send a Referer header for privacy rea-
sons even on same-domain requests. The default is to reject requests without a known origin. It
is also possible to allow the special Origin: null header by adding it to the pyramid.
csrf_trusted_origins list in the settings. See https://github.com/Pylons/pyramid/pull/3512
and https://github.com/Pylons/pyramid/pull/3518

982 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• A new parameter, check_origin, was added to pyramid.config.Configurator.


set_default_csrf_options which disables origin checking entirely. See https://github.
com/Pylons/pyramid/pull/3518
• Added pyramid.interfaces.IPredicateInfo which defines the object passed to predi-
cate factories as their second argument. See https://github.com/Pylons/pyramid/pull/3514
• Added support for serving pre-compressed static assets by using the content_encodings
argument of pyramid.config.Configurator.add_static_view and pyramid.
static.static_view. See https://github.com/Pylons/pyramid/pull/3537
• Fix DeprecationWarning emitted by using the imp module. See https://github.com/Pylons/
pyramid/pull/3553
• Properties created via config.add_request_method(..., property=True) or
request.set_property used to be readonly. They can now be overridden via request.
foo = ... and until the value is deleted it will return the overridden value. This is most useful
when mocking request properties in testing. See https://github.com/Pylons/pyramid/pull/3559
• Finished callbacks are now executed as part of the closer that is invoked as part of pyramid.
scripting.prepare and pyramid.paster.bootstrap. See https://github.com/Pylons/
pyramid/pull/3561
• Added pyramid.request.RequestLocalCache which can be used to create simple ob-
jects that are shared across requests and can be used to store per-request data. This is useful
when the source of data is external to the request itself. Often a reified property is used on
a request via pyramid.config.Configurator.add_request_method, or pyramid.
decorator.reify, and these work great when the data is generated on-demand when ac-
cessing the request property. However, often the case is that the data is generated when access-
ing some other system and then we want to cache the data for the duration of the request. See
https://github.com/Pylons/pyramid/pull/3561
• Exposed pyramid.authorization.ALL_PERMISSIONS and pyramid.
authorization.DENY_ALL such that all of the ACL-related constants are now importable from
the pyramid.authorization namespace. See https://github.com/Pylons/pyramid/pull/3563
• pserve now outputs verbose messaging to stderr instead of stdout to circumvent buffering issues
that exist by default on stdout. See https://github.com/Pylons/pyramid/pull/3593

0.6. Change History 983


The Pyramid Web Framework, Version 2.0.2

Deprecations

• Deprecated the authentication and authorization interfaces and principal-based support. See ”Up-
grading Authentication/Authorization” in the ”What’s New in Pyramid 2.0” chapter of the docu-
mentation for information on equivalent APIs and notes on upgrading. The following APIs are
deprecated as a result of this change:
– pyramid.config.Configurator.set_authentication_policy
– pyramid.config.Configurator.set_authorization_policy
– pyramid.interfaces.IAuthenticationPolicy
– pyramid.interfaces.IAuthorizationPolicy
– pyramid.request.Request.effective_principals
– pyramid.request.Request.unauthenticated_userid
– pyramid.authentication.AuthTktAuthenticationPolicy
– pyramid.authentication.RemoteUserAuthenticationPolicy
– pyramid.authentication.RepozeWho1AuthenticationPolicy
– pyramid.authentication.SessionAuthenticationPolicy
– pyramid.authentication.BasicAuthAuthenticationPolicy
– pyramid.authorization.ACLAuthorizationPolicy
– The effective_principals view and route predicates.
See https://github.com/Pylons/pyramid/pull/3465
• Deprecated pyramid.security.principals_allowed_by_permission.
This method continues to work with the deprecated pyramid.interfaces.
IAuthorizationPolicy interface but will not work with the new pyramid.interfaces.
ISecurityPolicy. See https://github.com/Pylons/pyramid/pull/3465
• Deprecated several ACL-related aspects of pyramid.security. Equivalent objects should now
be imported from the pyramid.authorization namespace. This includes:
– pyramid.security.Everyone
– pyramid.security.Authenticated
– pyramid.security.ALL_PERMISSIONS
– pyramid.security.DENY_ALL
– pyramid.security.ACLAllowed
– pyramid.security.ACLDenied

984 CONTENTS
The Pyramid Web Framework, Version 2.0.2

See https://github.com/Pylons/pyramid/pull/3563
• Deprecated pyramid.session.PickleSerializer. See https://github.com/pylons/
pyramid/issues/2709, and https://github.com/pylons/pyramid/pull/3353, and https://github.com/
pylons/pyramid/pull/3413

Backward Incompatibilities

• Drop support for Python 2.7, 3.4, and 3.5. See https://github.com/Pylons/pyramid/pull/3421, and
https://github.com/Pylons/pyramid/pull/3547, and https://github.com/Pylons/pyramid/pull/3634
• Removed the pyramid.compat module. Integrators should use the six module or vendor shims
they are using into their own codebases going forward. https://github.com/Pylons/pyramid/pull/3421
• pcreate and the builtin scaffolds have been removed in favor of using the cookiecutter tool
and the pyramid-cookiecutter-starter cookiecutter. The script and scaffolds were dep-
recated in Pyramid 1.8. See https://github.com/Pylons/pyramid/pull/3406
• Changed the default hashalg on pyramid.authentication.AuthTktCookieHelper
to sha512. See https://github.com/Pylons/pyramid/pull/3557
• Removed pyramid.interfaces.ITemplateRenderer. This interface was deprecated
since Pyramid 1.5 and was an interface used by libraries like pyramid_mako and pyra-
mid_chameleon but provided no functionality within Pyramid itself. See https://github.com/
Pylons/pyramid/pull/3409
• Removed pyramid.security.has_permission, pyramid.security.
authenticated_userid, pyramid.security.unauthenticated_userid,
and pyramid.security.effective_principals. These methods were deprecated
in Pyramid 1.5 and all have equivalents available as properties on the request. For example,
request.authenticated_userid. See https://github.com/Pylons/pyramid/pull/3410
• Removed support for supplying a media range to the accept predicate of both pyramid.
config.Configurator.add_view and pyramid.config.Configurator.
add_route. These options were deprecated in Pyramid 1.10 and WebOb 1.8 be-
cause they resulted in uncontrollable matching that was not compliant with the RFC. See
https://github.com/Pylons/pyramid/pull/3411
• Removed pyramid.session.UnencryptedCookieSessionFactoryConfig. This
session factory was replaced with pyramid.session.SignedCookieSessionFactory in
Pyramid 1.5 and has been deprecated since then. See https://github.com/Pylons/pyramid/pull/3412
• Removed pyramid.session.signed_serialize, and pyramid.session.
signed_deserialize. These methods were only used by the now-removed pyramid.
session.UnencryptedCookieSessionFactoryConfig and were coupled to the
vulnerable pickle serialization format which could lead to remove code execution if the secret key
is compromised. See https://github.com/Pylons/pyramid/pull/3412

0.6. Change History 985


The Pyramid Web Framework, Version 2.0.2

• Changed the default serializer on pyramid.session.


SignedCookieSessionFactory to use pyramid.session.JSONSerializer
instead of pyramid.session.PickleSerializer. Read ”Upgrading Session Serializa-
tion” in the ”What’s New in Pyramid 2.0” chapter of the documentation for more information about
why this change was made. See https://github.com/Pylons/pyramid/pull/3413
• pyramid.request.Request.invoke_exception_view will no longer be called by the
default execution policy. See https://github.com/Pylons/pyramid/pull/3496
• pyramid.config.Configurator.scan will no longer, by default, execute Venusian deco-
rator callbacks registered for categories other than 'pyramid'. To find any decorator regardless of
category, specify config.scan(..., categories=None). See https://github.com/Pylons/
pyramid/pull/3510
• The second argument to predicate factories has been changed from config to info, an instance
of pyramid.interfaces.IPredicateInfo. This limits the data available to predicates but
still provides the package, registry, settings and dotted-name resolver which should cover most use
cases and is largely backward compatible. See https://github.com/Pylons/pyramid/pull/3514
• Removed the check_csrf predicate. Instead, use pyramid.config.Configurator.
set_default_csrf_options and the require_csrf view option to enable automatic
CSRF checking. See https://github.com/Pylons/pyramid/pull/3521
• Update the default behavior of pyramid.authenticationAuthTktAuthenticationPolicy
and pyramid.authentication.AuthTktCookieHelper to only set a single cookie
without a domain parameter when no other domain constraints are specified. Prior to this change,
wild_domain=False (the default) was effectively treated the same as wild_domain=True,
in which a cookie was defined such that browsers would use it both for the request’s domain, as
well as any subdomain. In the new behavior, cookies will only affect the current domain, and not
subdomains, by default. See https://github.com/Pylons/pyramid/pull/3587

Documentation Changes

• Restore build of PDF on Read The Docs. See https://github.com/Pylons/pyramid/issues/3290


• Fix docs build for Sphinx 2.0. See https://github.com/Pylons/pyramid/pull/3480
• Significant updates to the wiki, wiki2 tutorials to demonstrate the new security policy usage as well
as a much more production-ready test harness. See https://github.com/Pylons/pyramid/pull/3557

986 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.10 (2018-10-31)

• No major changes from 1.10b1.

1.10b1 (2018-10-28)

Bug Fixes

• Fix the pyramid.testing.DummyRequest to support the new request.accept API so


that acceptable_offers is available even when code sets the value to a string. See https:
//github.com/Pylons/pyramid/pull/3396
• Fix deprecated escape sequences in preparation for Python 3.8. See https://github.com/Pylons/
pyramid/pull/3400

1.10a1 (2018-10-15)

Features

• Add a _depth and _category arguments to all of the venusian decorators. The _cat-
egory argument can be used to affect which actions are registered when performing a
config.scan(..., category=...) with a specific category. The _depth argument
should be used when wrapping the decorator in your own. This change affects pyramid.
view.view_config, pyramid.view.exception_view_config, pyramid.view.
forbidden_view_config, pyramid.view.notfound_view_config, pyramid.
events.subscriber and pyramid.response.response_adapter decorators. See
https://github.com/Pylons/pyramid/pull/3105 and https://github.com/Pylons/pyramid/pull/3122
• Fix the pyramid.request.Request class name after using set_property or config.
add_request_method such that the str(request.__class__) would appear as
pyramid.request.Request instead of pyramid.util.Request. See https://github.
com/Pylons/pyramid/pull/3129
• In cherrypy_server_runner, prefer imports from the cheroot package over the legacy
imports from cherrypy.wsgiserver. See https://github.com/Pylons/pyramid/pull/3235
• Add a context manager route_prefix_context to the pyramid.config.
Configurator to allow for convenient setting of the route_prefix for include and add_route
calls inside the context. See https://github.com/Pylons/pyramid/pull/3279

0.6. Change History 987


The Pyramid Web Framework, Version 2.0.2

• Modify the builtin session implementations to support SameSite options on cookies and set
the default to 'Lax'. This affects pyramid.session.BaseCookieSessionFactory,
pyramid.session.SignedCookieSessionFactory, and pyramid.session.
UnencryptedCookieSessionFactoryConfig. See https://github.com/Pylons/pyramid/
pull/3300
• Modify pyramid.authentication.AuthTktAuthenticationPolicy and
pyramid.csrf.CookieCSRFStoragePolicy to support the SameSite option on
cookies and set the default to 'Lax'. See https://github.com/Pylons/pyramid/pull/3319
• Added new pyramid.httpexceptions.HTTPPermanentRedirect exception/response
object for a HTTP 308 redirect. See https://github.com/Pylons/pyramid/pull/3302
• Within pshell, allow the user-defined setup function to be a generator, in which case it may
wrap the command’s lifecycle. See https://github.com/Pylons/pyramid/pull/3318
• Within pshell, variables defined by the [pshell] settings are available within the user-defined
setup function. See https://github.com/Pylons/pyramid/pull/3318
• Add support for Python 3.7. Add testing on Python 3.8 with allowed failures. See https://github.
com/Pylons/pyramid/pull/3333
• Added the pyramid.config.Configurator.add_accept_view_order directive, al-
lowing users to specify media type preferences in ambiguous situations such as when several views
match. A default ordering is defined for media types that prefers human-readable html/text responses
over JSON. See https://github.com/Pylons/pyramid/pull/3326
• Support a list of media types in the accept predicate used in pyramid.config.
Configurator.add_route. See https://github.com/Pylons/pyramid/pull/3326
• Added pyramid.session.JSONSerializer. See ”Upcoming Changes to ISession in Pyra-
mid 2.0” in the ”Sessions” chapter of the documentation for more information about this feature.
See https://github.com/Pylons/pyramid/pull/3353
• Add a registry argument to pyramid.renderers.get_renderer to allow users to avoid
threadlocals during renderer lookup. See https://github.com/Pylons/pyramid/pull/3358
• Pyramid’s test suite is no longer distributed with the universal wheel. See https://github.com/Pylons/
pyramid/pull/3387
• All Python code is now formatted automatically using black. See https://github.com/Pylons/
pyramid/pull/3388

988 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• Set appropriate code and title attributes on the HTTPClientError and HTTPServer-
Error exception classes. This prevents inadvertently returning a 520 error code. See https:
//github.com/Pylons/pyramid/pull/3280
• Replace webob.acceptparse.MIMEAccept from WebOb with webob.acceptparse.
create_accept_header in the HTTP exception handling code. The old MIMEAccept has
been deprecated. The new methods follow the RFC’s more closely. See https://github.com/Pylons/
pyramid/pull/3251
• Catch extra errors like AttributeError when unpickling ”trusted” session cookies with bad
pickle data in them. This would occur when sharing a secret between projects that shouldn’t actually
share session cookies, like when reusing secrets between projects in development. See https://github.
com/Pylons/pyramid/pull/3325

Deprecations

• The pyramid.interfaces.ISession interface will move to require JSON-serializable ob-


jects in Pyramid 2.0. See ”Upcoming Changes to ISession in Pyramid 2.0” in the ”Sessions” chap-
ter of the documentation for more information about this change. See https://github.com/Pylons/
pyramid/pull/3353
• The pyramid.session.signed_serialize and pyramid.session.
signed_deserialize functions will be removed in Pyramid 2.0, along with the removal
of pyramid.session.UnencryptedCookieSessionFactoryConfig which was
deprecated in Pyramid 1.5. Please switch to using the SignedCookieSessionFactory,
copying the code, or another session implementation if you’re still using these features. See
https://github.com/Pylons/pyramid/pull/3353
• Media ranges are deprecated in the accept argument of pyramid.config.Configurator.
add_route. Use a list of explicit media types to add_route to support multiple types.
• Media ranges are deprecated in the accept argument of pyramid.config.Configurator.
add_view. There is no replacement for ranges to add_view, but after much discussion the
workflow is fundamentally ambiguous in the face of various client-supplied values for the Accept
header. See https://github.com/Pylons/pyramid/pull/3326

0.6. Change History 989


The Pyramid Web Framework, Version 2.0.2

Backward Incompatibilities

• On Python 3.4+ the repoze.lru dependency is dropped. If you were using this package directly
in your apps you should make sure that you are depending on it directly within your project. See
https://github.com/Pylons/pyramid/pull/3140
• Remove the permission argument from pyramid.config.Configurator.
add_route. This was an argument left over from a feature removed in Pyramid 1.5 and
has had no effect since then. See https://github.com/Pylons/pyramid/pull/3299
• Modify the builtin session implementations to set SameSite='Lax' on cookies.
This affects pyramid.session.BaseCookieSessionFactory, pyramid.
session.SignedCookieSessionFactory, and pyramid.session.
UnencryptedCookieSessionFactoryConfig. See https://github.com/Pylons/pyramid/
pull/3300
• Variables defined in the [pshell] section of the settings will no longer override those set by the
setup function. See https://github.com/Pylons/pyramid/pull/3318
• pyramid.config.Configurator.add_notfound_view uses default redirect class ex-
ception pyramid.httpexceptions.HTTPTemporaryRedirect instead of previous
pyramid.httpexceptions.HTTPFound. See https://github.com/Pylons/pyramid/pull/3328
• Removed pyramid.config.Configurator.set_request_property which had
been deprecated since Pyramid 1.5. Instead use pyramid.config.Configurator.
add_request_method with reify=True or property=True. See https://github.com/
Pylons/pyramid/pull/3368
• Removed the principal keyword argument from pyramid.security.remember which
had been deprecated since Pyramid 1.6 and replaced by the userid argument. See https://github.
com/Pylons/pyramid/pull/3369
• Removed the pyramid.tests subpackage that used to contain the Pyramid test suite. These
changes also changed the format of the repository to move the code into a src folder. See https:
//github.com/Pylons/pyramid/pull/3387

Documentation Changes

• Ad support for Read The Docs Ethical Ads. See https://github.com/Pylons/pyramid/pull/3360 and
https://docs.readthedocs.io/en/latest/advertising/ethical-advertising.html
• Add support for alembic to the pyramid-cookiecutter-alchemy cookiecutter and update the wiki2 tu-
torial to explain how it works. See https://github.com/Pylons/pyramid/pull/3307 and https://github.
com/Pylons/pyramid-cookiecutter-alchemy/pull/7

990 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Bump Sphinx to >= 1.7.4 in setup.py to support emphasize-lines in PDFs and to pave the way
for xelatex support. See https://github.com/Pylons/pyramid/pull/3271, https://github.com/Pylons/
pyramid/issues/667, and https://github.com/Pylons/pyramid/issues/2572
• Added extra tests to the quick tutorial. See https://github.com/Pylons/pyramid/pull/3375

1.9 (2017-06-26)

• No major changes from 1.9b1.


• Updated documentation links for docs.pylonsproject.org to use HTTPS.

1.9b1 (2017-06-19)

• Add an informative error message when unknown predicates are supplied. The new message suggests
alternatives based on the list of known predicates. See https://github.com/Pylons/pyramid/pull/3054
• Added integrity attributes for JavaScripts in cookiecutters, scaffolds, and resulting source files in
tutorials. See https://github.com/Pylons/pyramid/issues/2548
• Update RELEASING.txt for updating cookiecutters. Change cookiecutter URLs to use shortcut.
See https://github.com/Pylons/pyramid/issues/3042
• Ensure the correct threadlocals are pushed during view execution when invoked from request.
invoke_exception_view. See https://github.com/Pylons/pyramid/pull/3060
• Fix a bug in which pyramid.security.ALL_PERMISSIONS failed to return a valid iterator
in its __iter__ implementation. See https://github.com/Pylons/pyramid/pull/3074
• Normalize the permission results to a proper class hierarchy. pyramid.security.
ACLAllowed is now a subclass of pyramid.security.Allowed and pyramid.
security.ACLDenied is now a subclass of pyramid.security.Denied. See https:
//github.com/Pylons/pyramid/pull/3084
• Add a quote_via argument to pyramid.encode.urlencode to follow the stdlib’s version
and enable custom quoting functions. See https://github.com/Pylons/pyramid/pull/3088
• Support _query=None and _anchor=None in request.route_url as well as query=None
and anchor=None in request.resource_url. Previously this would cause an ? and a
#, respectively, in the url with nothing after it. Now the unnecessary parts are dropped from the
generated URL. See https://github.com/Pylons/pyramid/pull/3034
• Revamp the IRouter API used by IExecutionPolicy to force pushing/popping the re-
quest threadlocals. The IRouter.make_request(environ) API has been replaced by
IRouter.request_context(environ) which should be used as a context manager. See
https://github.com/Pylons/pyramid/pull/3086

0.6. Change History 991


The Pyramid Web Framework, Version 2.0.2

1.9a2 (2017-05-09)

Backward Incompatibilities

• request.exception and request.exc_info will only be set if the response was generated
by the EXCVIEW tween. This is to avoid any confusion where a response was generated elsewhere
in the pipeline and not in direct relation to the original exception. If anyone upstream wants to
catch and render responses for exceptions they should set request.exception and request.
exc_info themselves to indicate the exception that was squashed when generating the response.
Similar behavior occurs with request.invoke_exception_view in which the exception
properties are set to reflect the exception if a response is successfully generated by the method.
This is a very minor incompatibility. Most tweens right now would give priority to the raised ex-
ception and ignore request.exception. This change just improves and clarifies that book-
keeping by trying to be more clear about the relationship between the response and its squashed ex-
ception. See https://github.com/Pylons/pyramid/pull/3029 and https://github.com/Pylons/pyramid/
pull/3031

1.9a1 (2017-05-01)

Major Features

• The file format used by all p* command line scripts such as pserve and pshell, as well as
the pyramid.paster.bootstrap function is now replaceable thanks to a new dependency on
plaster.
For now, Pyramid is still shipping with integrated support for the PasteDeploy INI format by de-
pending on the plaster_pastedeploy binding library. This may change in the future.
See https://github.com/Pylons/pyramid/pull/2985
• Added an execution policy hook to the request pipeline. An execution policy has the ability to control
creation and execution of the request objects before they enter the rest of the pipeline. This means
for a single request environ the policy may create more than one request object.
The first library to use this feature is pyramid_retry.
See https://github.com/Pylons/pyramid/pull/2964

992 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• CSRF support has been refactored out of sessions and into its own independent API
in the pyramid.csrf module. It supports a pluggable pyramid.interfaces.
ICSRFStoragePolicy which can be used to define your own mechanism for gener-
ating and validating CSRF tokens. By default, Pyramid continues to use the pyramid.
csrf.LegacySessionCSRFStoragePolicy that uses the request.session.
get_csrf_token and request.session.new_csrf_token APIs under the hood
to preserve compatibility. Two new policies are shipped as well, pyramid.csrf.
SessionCSRFStoragePolicy and pyramid.csrf.CookieCSRFStoragePolicy
which will store the CSRF tokens in the session and in a standalone cookie, respectively.
The storage policy can be changed by using the new pyramid.config.Configurator.
set_csrf_storage_policy config directive.
CSRF tokens should be used via the new pyramid.csrf.get_csrf_token, pyramid.
csrf.new_csrf_token and pyramid.csrf.check_csrf_token APIs in order to con-
tinue working if the storage policy is changed. Also, the pyramid.csrf.get_csrf_token
function is injected into templates to be used conveniently in UI code.
See https://github.com/Pylons/pyramid/pull/2854 and https://github.com/Pylons/pyramid/pull/
3019

Minor Features

• Support an open_url config setting in the pserve section of the config file. This url is
used to open a web browser when pserve --browser is invoked. When this setting
is unavailable the pserve script will attempt to guess the port the server is using from the
server:<server_name> section of the config file but there is no requirement that the server is
being run in this format so it may fail. See https://github.com/Pylons/pyramid/pull/2984
• The pyramid.config.Configurator can now be used as a context manager which will au-
tomatically push/pop threadlocals (similar to config.begin() and config.end()). It will
also automatically perform a config.commit() and thus it is only recommended to be used at
the top-level of your app. See https://github.com/Pylons/pyramid/pull/2874
• The threadlocals are now available inside any function invoked via config.include. This
means the only config-time code that cannot rely on threadlocals is code executed from non-
actions inside the main. This can be alleviated by invoking config.begin() and config.
end() appropriately or using the new context manager feature of the configurator. See https:
//github.com/Pylons/pyramid/pull/2989

0.6. Change History 993


The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• HTTPException’s accepts a detail kwarg that may be used to pass additional details to the exception.
You may now pass objects so long as they have a valid __str__ method. See https://github.com/
Pylons/pyramid/pull/2951
• Fix a reference cycle causing memory leaks in which the registry would keep a Configura-
tor instance alive even after the configurator was discarded. Another fix was also added for the
global_registries object in which the registry was stored in a closure preventing it from
being deallocated. See https://github.com/Pylons/pyramid/pull/2967
• Fix a bug directly invoking pyramid.scripts.pserve.main with the --reload option
in which sys.argv is always used in the subprocess instead of the supplied argv. See https:
//github.com/Pylons/pyramid/pull/2962

Deprecations

• Pyramid currently depends on plaster_pastedeploy to simplify the transition to plaster


by maintaining integrated support for INI files. This dependency on plaster_pastedeploy
should be considered subject to Pyramid’s deprecation policy and may be removed in the future.
Applications should depend on the appropriate plaster binding to satisfy their needs.
• Retrieving CSRF token from the session has been deprecated in favor of equivalent methods
in the pyramid.csrf module. The CSRF methods (ISession.get_csrf_token and
ISession.new_csrf_token) are no longer required on the ISession interface except when
using the default pyramid.csrf.LegacySessionCSRFStoragePolicy.
Also, pyramid.session.check_csrf_token is now located at pyramid.csrf.
check_csrf_token.
See https://github.com/Pylons/pyramid/pull/2854 and https://github.com/Pylons/pyramid/pull/
3019

Documentation Changes

• Added the execution policy to the routing diagram in the Request Processing chapter. See https:
//github.com/Pylons/pyramid/pull/2993

994 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.8 (2017-01-21)

• No major changes from 1.8b1.

1.8b1 (2017-01-17)

Features

• Added an override option to config.add_translation_dirs to allow later calls to place


translation directories at a higher priority than earlier calls. See https://github.com/Pylons/pyramid/
pull/2902

Documentation Changes

• Improve registry documentation to discuss uses as a component registry and as a dictionary. See
https://github.com/Pylons/pyramid/pull/2893
• Quick Tour, Quick Tutorial, and most other remaining documentation updated to use cookiecut-
ters instead of pcreate and scaffolds. See https://github.com/Pylons/pyramid/pull/2888 and https:
//github.com/Pylons/pyramid/pull/2889
• Fix unittests in wiki2 to work without different dependencies between py2 and py3. See https:
//github.com/Pylons/pyramid/pull/2899
• Update Windows documentation to track newer Python 3 improvements to the installer. See https:
//github.com/Pylons/pyramid/pull/2900
• Updated the mod_wsgi tutorial to use cookiecutters and Apache 2.4+. See https://github.com/
Pylons/pyramid/pull/2901

1.8a1 (2016-12-25)

Backward Incompatibilities

• Support for the IContextURL interface that was deprecated in Pyramid 1.3 has been removed.
See https://github.com/Pylons/pyramid/pull/2822

0.6. Change History 995


The Pyramid Web Framework, Version 2.0.2

• Following the Pyramid deprecation period (1.6 -> 1.8), daemon support for pserve has been removed.
This includes removing the daemon commands (start, stop, restart, status) as well as the following
arguments: --daemon, --pid-file, --log-file, --monitor-restart, --status,
--user, --group, --stop-daemon
To run your server as a daemon you should use a process manager instead of pserve.
See https://github.com/Pylons/pyramid/pull/2615
• pcreate is now interactive by default. You will be prompted if a file already exists with differ-
ent content. Previously if there were similar files it would silently skip them unless you specified
--interactive or --overwrite. See https://github.com/Pylons/pyramid/pull/2775
• Removed undocumented argument cachebust_match from pyramid.static.
static_view. This argument was shipped accidentally in Pyramid 1.6. See https:
//github.com/Pylons/pyramid/pull/2681
• Change static view to avoid setting the Content-Encoding response header to an encoding
guessed using Python’s mimetypes module. This was causing clients to decode the content of
gzipped files when downloading them. The client would end up with a foo.txt.gz file on disk
that was already decoded, thus should really be foo.txt. Also, the Content-Encoding should
only have been used if the client itself broadcast support for the encoding via Accept-Encoding
request headers. See https://github.com/Pylons/pyramid/pull/2810
• Settings are no longer accessible as attributes on the settings object (e.g. request.registry.
settings.foo). This was deprecated in Pyramid 1.2. See https://github.com/Pylons/pyramid/
pull/2823

Features

• Python 3.6 compatibility. https://github.com/Pylons/pyramid/issues/2835


• pcreate learned about --package-name to allow you to create a new project in an existing
folder with a different package name than the project name. See https://github.com/Pylons/pyramid/
pull/2783
• The _get_credentials private method of BasicAuthAuthenticationPolicy
has been extracted into standalone function extract_http_basic_credentials in
pyramid.authentication module, this function extracts HTTP Basic credentials from a
request object, and returns them as a named tuple. See https://github.com/Pylons/pyramid/pull/
2662
• Pyramid 1.4 silently dropped a feature of the configurator that has been restored. It’s again possible
for action discriminators to conflict across different action orders. See https://github.com/Pylons/
pyramid/pull/2757

996 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• pyramid.paster.bootstrap and its sibling pyramid.scripting.prepare can now


be used as context managers to automatically invoke the closer and pop threadlocals off of the
stack to prevent memory leaks. See https://github.com/Pylons/pyramid/pull/2760
• Added pyramid.config.Configurator.add_exception_view and the pyramid.
view.exception_view_config decorator. It is now possible using these methods or via the
new exception_only=True option to add_view to add a view which will only be matched
when handling an exception. Previously any exception views were also registered for a traversal
context that inherited from the exception class which prevented any exception-only optimizations.
See https://github.com/Pylons/pyramid/pull/2660
• Added the exception_only boolean to pyramid.interfaces.IViewDeriverInfo
which can be used by view derivers to determine if they are wrapping a view which only handles
exceptions. This means that it is no longer necessary to perform request-time checks for request.
exception to determine if the view is handling an exception - the pipeline can be optimized at
config-time. See https://github.com/Pylons/pyramid/pull/2660
• pserve should now work with gevent and other workers that need to monkeypatch the process,
assuming the server and / or the app do so as soon as possible before importing the rest of pyramid.
See https://github.com/Pylons/pyramid/pull/2797
• Pyramid no longer copies the settings object passed to the pyramid.config.
Configurator(settings=). The original dict is kept. See https://github.com/Pylons/
pyramid/pull/2823
• The csrf trusted origins setting may now be a whitespace-separated list of domains. Previously only a
python list was allowed. Also, it can now be set using the PYRAMID_CSRF_TRUSTED_ORIGINS
environment variable similar to other settings. See https://github.com/Pylons/pyramid/pull/2823
• pserve --reload now uses the hupper library to monitor file changes. This comes with many
improvements:
– If the watchdog package is installed then monitoring will be done using inotify instead of cpu
and disk-intensive polling.
– The monitor is now a separate process that will not crash and starts up before any of your
code.
– The monitor will not restart the process after a crash until a file is saved.
– The monitor works on windows.
– You can now trigger a reload manually from a pyramid view or any other code via hupper.
get_reloader().trigger_reload(). Kind of neat.
– You can trigger a reload by issuing a SIGHUP to the monitor process.
See https://github.com/Pylons/pyramid/pull/2805

0.6. Change History 997


The Pyramid Web Framework, Version 2.0.2

• A new [pserve] section is supported in your config files with a watch_files key that can con-
figure pserve --reload to monitor custom file paths. See https://github.com/Pylons/pyramid/
pull/2827
• Allow streaming responses to be made from subclasses of pyramid.httpexceptions.
HTTPException. Previously the response would be unrolled while testing for a body, making
it impossible to stream a response. See https://github.com/Pylons/pyramid/pull/2863
• Update starter, alchemy and zodb scaffolds to support IPv6 by using the new listen directives in
waitress. See https://github.com/Pylons/pyramid/pull/2853
• All p* scripts now use argparse instead of optparse. This improves their --help output as well as
enabling nicer documentation of their options. See https://github.com/Pylons/pyramid/pull/2864
• Any deferred configuration action registered via config.action may now depend on threadlocal
state, such as asset overrides, being active when the action is executed. See https://github.com/
Pylons/pyramid/pull/2873
• Asset specifications for directories passed to config.add_translation_dirs now support
overriding the entire asset specification, including the folder name. Previously only the package
name was supported and the folder would always need to have the same name. See https://github.
com/Pylons/pyramid/pull/2873
• config.begin() will propagate the current threadlocal request through as long as the registry
is the same. For example:

request = Request.blank(...)
config.begin(request) # pushes a request
config.begin() # propagates the previous request through␣
,→unchanged

assert get_current_request() is request

See https://github.com/Pylons/pyramid/pull/2873
• Added a new callback option to config.set_default_csrf_options which can be
used to determine per-request whether CSRF checking should be enabled to allow for a mix au-
thentication methods. Only cookie-based methods generally require CSRF checking. See https:
//github.com/Pylons/pyramid/pull/2778

998 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• Fixed bug in proutes such that it now shows the correct view when a class and attr is involved.
See: https://github.com/Pylons/pyramid/pull/2687
• Fix a FutureWarning in Python 3.5 when using re.split on the format setting to the
proutes script. See https://github.com/Pylons/pyramid/pull/2714
• Fix a RuntimeWarning emitted by WebOb when using arbitrary objects as the userid in the
AuthTktAuthenticationPolicy. This is now caught by the policy and the object is serial-
ized as a base64 string to avoid the cryptic warning. Since the userid will be read back as a string
on subsequent requests a more useful warning is emitted encouraging you to use a primitive type
instead. See https://github.com/Pylons/pyramid/pull/2715
• Pyramid 1.6 introduced the ability for an action to invoke another action. There was a bug in the
way that config.add_view would interact with custom view derivers introduced in Pyramid 1.7
because the view’s discriminator cannot be computed until view derivers and view predicates have
been created in earlier orders. Invoking an action from another action would trigger an unrolling of
the pipeline and would compute discriminators before they were ready. The new behavior respects
the order of the action and ensures the discriminators are not computed until dependent actions
from previous orders have executed. See https://github.com/Pylons/pyramid/pull/2757
• Fix bug in i18n where the default domain would always use the Germanic plural style, even if a
different plural function is defined in the relevant messages file. See https://github.com/Pylons/
pyramid/pull/2859
• The config.override_asset method now occurs during pyramid.config.
PHASE1_CONFIG such that it is ordered to execute before any calls to config.
add_translation_dirs. See https://github.com/Pylons/pyramid/pull/2873

Deprecations

• The pcreate script and related scaffolds have been deprecated in favor of the popular cookiecutter
project.
All of Pyramid’s official scaffolds as well as the tutorials have been ported to cookiecutters:
– pyramid-cookiecutter-starter
– pyramid-cookiecutter-alchemy
– pyramid-cookiecutter-zodb
See https://github.com/Pylons/pyramid/pull/2780

0.6. Change History 999


The Pyramid Web Framework, Version 2.0.2

Documentation Changes

• Update Typographical Conventions. https://github.com/Pylons/pyramid/pull/2838


• Add pyramid_nacl_session to session factories. See https://github.com/Pylons/pyramid/issues/2791
• Update HACKING.txt from stale branch that was never merged to master. See https://github.com/
Pylons/pyramid/pull/2782
• Updated Windows installation instructions and related bits. See https://github.com/Pylons/pyramid/
issues/2661
• Fix an inconsistency in the documentation between view predicates and route predicates and high-
light the differences in their APIs. See https://github.com/Pylons/pyramid/pull/2764
• Clarify a possible misuse of the headers kwarg to subclasses of pyramid.
httpexceptions.HTTPException in which more appropriate kwargs from the
parent class pyramid.response.Response should be used instead. See https:
//github.com/Pylons/pyramid/pull/2750
• The SQLAlchemy + URL Dispatch + Jinja2 (wiki2) and ZODB + Traversal + Chameleon (wiki)
tutorials have been updated to utilize the new cookiecutters and drop support for the pcreate
scaffolds.
See https://github.com/Pylons/pyramid/pull/2881 and https://github.com/Pylons/pyramid/pull/
2883.
• Improve output of p* script descriptions for help. See https://github.com/Pylons/pyramid/pull/2886
• Quick Tour updated to use cookiecutters instead of pcreate and scaffolds. See https://github.com/
Pylons/pyramid/pull/2888

1.7 (2016-05-19)

• Fix a bug in the wiki2 tutorial where bcrypt is always expecting byte strings. See https://github.com/
Pylons/pyramid/pull/2576
• Simplify windows detection code and remove some duplicated data. See https://github.com/Pylons/
pyramid/pull/2585 and https://github.com/Pylons/pyramid/pull/2586

1000 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.7b4 (2016-05-12)

• Fixed the exception view tween to re-raise the original exception if no exception view could be found
to handle the exception. This better allows tweens further up the chain to handle exceptions that were
left unhandled. Previously they would be converted into a PredicateMismatch exception if
predicates failed to allow the view to handle the exception. See https://github.com/Pylons/pyramid/
pull/2567
• Exposed the pyramid.interfaces.IRequestFactory interface to mirror the public
pyramid.interfaces.IResponseFactory interface.

1.7b3 (2016-05-10)

• Fix request.invoke_exception_view to raise an HTTPNotFound exception if no view


is matched. Previously None would be returned if no views were matched and a PredicateMis-
match would be raised if a view ”almost” matched (a view was found matching the context). See
https://github.com/Pylons/pyramid/pull/2564
• Add defaults for py.test configuration and coverage to all three scaffolds, and update documentation
accordingly. See https://github.com/Pylons/pyramid/pull/2550
• Add linkcheck to Makefile for Sphinx. To check the documentation for broken links, use the
command make linkcheck SPHINXBUILD=$VENV/bin/sphinx-build. Also removed
and fixed dozens of broken external links.
• Fix the internal runner for scaffold tests to ensure they work with pip and py.test. See https://github.
com/Pylons/pyramid/pull/2565

1.7b2 (2016-05-01)

• Removed inclusion of pyramid_tm in development.ini for alchemy scaffold See https://github.com/


Pylons/pyramid/issues/2538
• A default permission set via config.set_default_permission will no longer be enforced
on an exception view. This has been the case for a while with the default exception views (config.
add_notfound_view and config.add_forbidden_view), however for any other excep-
tion view a developer had to remember to set permission=NO_PERMISSION_REQUIRED or
be surprised when things didn’t work. It is still possible to force a permission check on an exception
view by setting the permission argument manually to config.add_view. This behavior
is consistent with the new CSRF features added in the 1.7 series. See https://github.com/Pylons/
pyramid/pull/2534

0.6. Change History 1001


The Pyramid Web Framework, Version 2.0.2

1.7b1 (2016-04-25)

• This release announces the beta period for 1.7.


• Fix an issue where some files were being included in the alchemy scafffold which had been removed
from the 1.7 series. See https://github.com/Pylons/pyramid/issues/2525

1.7a2 (2016-04-19)

Features

• Automatic CSRF checks are now disabled by default on exception views. They can be turned back on
by setting the appropriate require_csrf option on the view. See https://github.com/Pylons/pyramid/
pull/2517
• The automatic CSRF API was reworked to use a config directive for setting the options. The
pyramid.require_default_csrf setting is no longer supported. Instead, a new config.
set_default_csrf_options directive has been introduced that allows the developer to spec-
ify the default value for require_csrf as well as change the CSRF token, header and safe
request methods. The pyramid.csrf_trusted_origins setting is still supported. See
https://github.com/Pylons/pyramid/pull/2518

Bug fixes

• CSRF origin checks had a bug causing the checks to always fail. See https://github.com/Pylons/
pyramid/pull/2512
• Fix the test suite to pass on windows. See https://github.com/Pylons/pyramid/pull/2520

1.7a1 (2016-04-16)

Backward Incompatibilities

• Following the Pyramid deprecation period (1.4 -> 1.6), AuthTktAuthenticationPolicy’s default hash-
ing algorithm is changing from md5 to sha512. If you are using the authentication policy and need
to continue using md5, please explicitly set hashalg to ’md5’.
This change does mean that any existing auth tickets (and associated cookies) will no longer be valid,
and users will no longer be logged in, and have to login to their accounts again.
See https://github.com/Pylons/pyramid/pull/2496
• The check_csrf_token function no longer validates a csrf token in the query string of a request.
Only headers and request bodies are supported. See https://github.com/Pylons/pyramid/pull/2500

1002 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Features

• Added a new setting, pyramid.require_default_csrf which may be used to turn on CSRF


checks globally for every POST request in the application. This should be considered a good default
for websites built on Pyramid. It is possible to opt-out of CSRF checks on a per-view basis by setting
require_csrf=False on those views. See https://github.com/Pylons/pyramid/pull/2413
• Added a require_csrf view option which will enforce CSRF checks on any request with an
unsafe method as defined by RFC2616. If the CSRF check fails a BadCSRFToken exception will
be raised and may be caught by exception views (the default response is a 400 Bad Request).
This option should be used in place of the deprecated check_csrf view predicate which would
normally result in unexpected 404 Not Found response to the client instead of a catchable ex-
ception. See https://github.com/Pylons/pyramid/pull/2413 and https://github.com/Pylons/pyramid/
pull/2500
• Added an additional CSRF validation that checks the origin/referrer of a request and makes sure it
matches the current request.domain. This particular check is only active when accessing a site
over HTTPS as otherwise browsers don’t always send the required information. If this additional
CSRF validation fails a BadCSRFOrigin exception will be raised and may be caught by exception
views (the default response is 400 Bad Request). Additional allowed origins may be configured
by setting pyramid.csrf_trusted_origins to a list of domain names (with ports if on a
non standard port) to allow. Subdomains are not allowed unless the domain name has been prefixed
with a .. See https://github.com/Pylons/pyramid/pull/2501
• Added a new pyramid.session.check_csrf_origin API for validating the origin or re-
ferrer headers against the request’s domain. See https://github.com/Pylons/pyramid/pull/2501
• Pyramid HTTPExceptions will now take into account the best match for the clients Accept header,
and depending on what is requested will return text/html, application/json or text/plain. The default
for / is still text/html, but if application/json is explicitly mentioned it will now receive a valid JSON
response. See https://github.com/Pylons/pyramid/pull/2489
• A new event and interface (BeforeTraversal) has been introduced that will notify listeners before
traversal starts in the router. See https://github.com/Pylons/pyramid/pull/2469 and https://github.
com/Pylons/pyramid/pull/1876
• Add a new ”view deriver” concept to Pyramid to allow framework authors to inject elements into the
standard Pyramid view pipeline and affect all views in an application. This is similar to a decorator
except that it has access to options passed to config.add_view and can affect other stages of
the pipeline such as the raw response from a view or prior to security checks. See https://github.
com/Pylons/pyramid/pull/2021
• Allow a leading = on the key of the request param predicate. For example, ’=abc=1’ is equivalent
down to request.params['=abc'] == '1'. See https://github.com/Pylons/pyramid/pull/
1370

0.6. Change History 1003


The Pyramid Web Framework, Version 2.0.2

• A new request.invoke_exception_view(...) method which can be used to invoke an


exception view and get back a response. This is useful for rendering an exception view outside of
the context of the excview tween where you may need more control over the request. See https:
//github.com/Pylons/pyramid/pull/2393
• Allow using variable substitutions like %(LOGGING_LOGGER_ROOT_LEVEL)s for logging
sections of the .ini file and populate these variables from the pserve command line -- e.g.:
pserve development.ini LOGGING_LOGGER_ROOT_LEVEL=DEBUG See https://github.
com/Pylons/pyramid/pull/2399

Documentation Changes

• A complete overhaul of the docs:


– Use pip instead of easy_install.
– Become opinionated by preferring Python 3.4 or greater to simplify installation of Python and
its required packaging tools.
– Use venv for the tool, and virtual environment for the thing created, instead of virtualenv.
– Use py.test and pytest-cov instead of nose and coverage.
– Further updates to the scaffolds as well as tutorials and their src files.
See https://github.com/Pylons/pyramid/pull/2468
• A complete overhaul of the alchemy scaffold as well as the Wiki2 SQLAlchemy + URLDispatch
tutorial to introduce more modern features into the usage of SQLAlchemy with Pyramid and provide
a better starting point for new projects. See https://github.com/Pylons/pyramid/pull/2024

Bug Fixes

• Fix pserve --browser to use the --server-name instead of the app name when selecting
a section to use. This was only working for people who had server and app sections with the same
name, for example [app:main] and [server:main]. See https://github.com/Pylons/pyramid/
pull/2292

1004 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Deprecations

• The check_csrf view predicate has been deprecated. Use the new require_csrf option or
the pyramid.require_default_csrf setting to ensure that the BadCSRFToken exception
is raised. See https://github.com/Pylons/pyramid/pull/2413
• Support for Python 3.3 will be removed in Pyramid 1.8. https://github.com/Pylons/pyramid/issues/
2477
• Python 2.6 is no longer supported by Pyramid. See https://github.com/Pylons/pyramid/issues/2368
• Dropped Python 3.2 support. See https://github.com/Pylons/pyramid/pull/2256

1.6 (2016-01-03)

Deprecations

• Continue removal of pserve daemon/process management features by deprecating --user and


--group options. See https://github.com/Pylons/pyramid/pull/2190

1.6b3 (2015-12-17)

Backward Incompatibilities

• Remove the cachebust option from config.add_static_view. See config.


add_cache_buster for the new way to attach cache busters to static assets. See https://github.
com/Pylons/pyramid/pull/2186
• Modify the pyramid.interfaces.ICacheBuster API to be a simple callable instead of
an object with match and pregenerate methods. Cache busters are now focused solely on
generation. Matching has been dropped.
Note this affects usage of pyramid.static.QueryStringCacheBuster and pyramid.
static.ManifestCacheBuster.
See https://github.com/Pylons/pyramid/pull/2186

0.6. Change History 1005


The Pyramid Web Framework, Version 2.0.2

Features

• Add a new config.add_cache_buster API for attaching cache busters to static assets. See
https://github.com/Pylons/pyramid/pull/2186

Bug Fixes

• Ensure that IAssetDescriptor.abspath always returns an absolute path. There were cases
depending on the process CWD that a relative path would be returned. See https://github.com/
Pylons/pyramid/pull/2188

1.6b2 (2015-10-15)

Features

• Allow asset specifications to be supplied to pyramid.static.ManifestCacheBuster in-


stead of requiring a filesystem path.

1.6b1 (2015-10-15)

Backward Incompatibilities

• IPython and BPython support have been removed from pshell in the core. To continue using them
on Pyramid 1.6+ you must install the binding packages explicitly:

$ pip install pyramid_ipython

or

$ pip install pyramid_bpython

• Remove default cache busters introduced in 1.6a1 including PathSegmentCacheBuster,


PathSegmentMd5CacheBuster, and QueryStringMd5CacheBuster. See https://
github.com/Pylons/pyramid/pull/2116

1006 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Features

• Additional shells for pshell can now be registered as entrypoints. See https://github.com/Pylons/
pyramid/pull/1891 and https://github.com/Pylons/pyramid/pull/2012
• The variables injected into pshell are now displayed with their docstrings instead of the default
str(obj) when possible. See https://github.com/Pylons/pyramid/pull/1929
• Add new pyramid.static.ManifestCacheBuster for use with external asset pipelines as
well as examples of common usages in the narrative. See https://github.com/Pylons/pyramid/pull/
2116
• Fix pserve --reload to not crash on syntax errors!!! See https://github.com/Pylons/pyramid/
pull/2125
• Fix an issue when user passes unparsed strings to pyramid.session.CookieSession and
pyramid.authentication.AuthTktCookieHelper for time related parameters time-
out, reissue_time, max_age that expect an integer value. See https://github.com/Pylons/
pyramid/pull/2050

Bug Fixes

• pyramid.httpexceptions.HTTPException now defaults to 520 Unknown Error


instead of None None to conform with changes in WebOb 1.5. See https://github.com/Pylons/
pyramid/pull/1865
• pshell will now preserve the capitalization of variables in the [pshell] section of the INI file.
This makes exposing classes to the shell a little more straightforward. See https://github.com/Pylons/
pyramid/pull/1883
• Fixed usage of pserve --monitor-restart --daemon which would fail in horrible ways.
See https://github.com/Pylons/pyramid/pull/2118
• Explicitly prevent pserve --reload --daemon from being used. It’s never been supported
but would work and fail in weird ways. See https://github.com/Pylons/pyramid/pull/2119
• Fix an issue on Windows when running pserve --reload in which the process failed to fork
because it could not find the pserve script to run. See https://github.com/Pylons/pyramid/pull/2138

0.6. Change History 1007


The Pyramid Web Framework, Version 2.0.2

Deprecations

• Deprecate pserve --monitor-restart in favor of user’s using a real process manager such
as Systemd or Upstart as well as Python-based solutions like Circus and Supervisor. See https:
//github.com/Pylons/pyramid/pull/2120

1.6a2 (2015-06-30)

Bug Fixes

• Ensure that pyramid.httpexceptions.exception_response returns the appropriate


”concrete” class for 400 and 500 status codes. See https://github.com/Pylons/pyramid/issues/1832
• Fix an infinite recursion bug introduced in 1.6a1 when pyramid.view.
render_view_to_response was called directly or indirectly. See https://github.com/
Pylons/pyramid/issues/1643
• Further fix the JSONP renderer by prefixing the returned content with a comment. This should
mitigate attacks from Flash (See CVE-2014-4671). See https://github.com/Pylons/pyramid/pull/
1649
• Allow periods and brackets ([]) in the JSONP callback. The original fix was overly-restrictive and
broke Angular. See https://github.com/Pylons/pyramid/pull/1649

1.6a1 (2015-04-15)

Features

• pcreate will now ask for confirmation if invoked with an argument for a project name that already
exists or is importable in the current environment. See https://github.com/Pylons/pyramid/issues/
1357 and https://github.com/Pylons/pyramid/pull/1837
• Make it possible to subclass pyramid.request.Request and also use pyramid.
request.Request.add_request.method. See https://github.com/Pylons/pyramid/
issues/1529
• The pyramid.config.Configurator has grown the ability to allow actions to call other
actions during a commit-cycle. This enables much more logic to be placed into actions, such as the
ability to invoke other actions or group them for improved conflict detection. We have also exposed
and documented the config phases that Pyramid uses in order to further assist in building conforming
addons. See https://github.com/Pylons/pyramid/pull/1513

1008 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Add pyramid.request.apply_request_extensions function which can be used in


testing to apply any request extensions configured via config.add_request_method. Pre-
viously it was only possible to test the extensions by going through Pyramid’s router. See https:
//github.com/Pylons/pyramid/pull/1581
• pcreate when run without a scaffold argument will now print information on the missing flag, as
well as a list of available scaffolds. See https://github.com/Pylons/pyramid/pull/1566 and https:
//github.com/Pylons/pyramid/issues/1297
• Added support / testing for ’pypy3’ under Tox and Travis. See https://github.com/Pylons/pyramid/
pull/1469
• Automate code coverage metrics across py2 and py3 instead of just py2. See https://github.com/
Pylons/pyramid/pull/1471
• Cache busting for static resources has been added and is available via a new argument to pyramid.
config.Configurator.add_static_view: cachebust. Core APIs are shipped for
both cache busting via query strings and path segments and may be extended to fit into custom
asset pipelines. See https://github.com/Pylons/pyramid/pull/1380 and https://github.com/Pylons/
pyramid/pull/1583
• Add pyramid.config.Configurator.root_package attribute and init parameter to as-
sist with includeable packages that wish to resolve resources relative to the package in which the
Configurator was created. This is especially useful for addons that need to load asset specs
from settings, in which case it is may be natural for a developer to define imports or assets relative
to the top-level package. See https://github.com/Pylons/pyramid/pull/1337
• Added line numbers to the log formatters in the scaffolds to assist with debugging. See https://github.
com/Pylons/pyramid/pull/1326
• Add new HTTP exception objects for status codes 428 Precondition Required, 429
Too Many Requests and 431 Request Header Fields Too Large in pyramid.
httpexceptions. See https://github.com/Pylons/pyramid/pull/1372/files
• The pshell script will now load a PYTHONSTARTUP file if one is defined in the environment
prior to launching the interpreter. See https://github.com/Pylons/pyramid/pull/1448
• Make it simple to define notfound and forbidden views that wish to use the default exception-
response view but with altered predicates and other configuration options. The view argument
is now optional in config.add_notfound_view and config.add_forbidden_view..
See https://github.com/Pylons/pyramid/issues/494
• Greatly improve the readability of the pcreate shell script output. See https://github.com/Pylons/
pyramid/pull/1453
• Improve robustness to timing attacks in the AuthTktCookieHelper and the SignedCook-
ieSessionFactory classes by using the stdlib’s hmac.compare_digest if it is available
(such as Python 2.7.7+ and 3.3+). See https://github.com/Pylons/pyramid/pull/1457

0.6. Change History 1009


The Pyramid Web Framework, Version 2.0.2

• Assets can now be overidden by an absolute path on the filesystem when using the config.
override_asset API. This makes it possible to fully support serving up static con-
tent from a mutable directory while still being able to use the request.static_url
API and config.add_static_view. Previously it was not possible to use config.
add_static_view with an absolute path and generate urls to the content. This
change replaces the call, config.add_static_view('/abs/path', 'static'),
with config.add_static_view('myapp:static', 'static') and config.
override_asset(to_override='myapp:static/', override_with='/abs/
path/'). The myapp:static asset spec is completely made up and does not need to exist
- it is used for generating urls via request.static_url('myapp:static/foo.png').
See https://github.com/Pylons/pyramid/pull/1252
• Added pyramid.config.Configurator.set_response_factory and the re-
sponse_factory keyword argument to the Configurator for defining a factory that will
return a custom Response class. See https://github.com/Pylons/pyramid/pull/1499
• Allow an iterator to be returned from a renderer. Previously it was only possible to return bytes or
unicode. See https://github.com/Pylons/pyramid/pull/1417
• pserve can now take a -b or --browser option to open the server URL in a web browser. See
https://github.com/Pylons/pyramid/pull/1533
• Overall improvements for the proutes command. Added --format and --glob arguments
to the command, introduced the method column for displaying available request methods, and
improved the view output by showing the module instead of just __repr__. See https://github.
com/Pylons/pyramid/pull/1488
• Support keyword-only arguments and function annotations in views in Python 3. See https://github.
com/Pylons/pyramid/pull/1556
• request.response will no longer be mutated when using the pyramid.renderers.
render_to_response() API. It is now necessary to pass in a response= argument to ren-
der_to_response if you wish to supply the renderer with a custom response object for it to
use. If you do not pass one then a response object will be created using the application’s IRe-
sponseFactory. Almost all renderers mutate the request.response response object (for
example, the JSON renderer sets request.response.content_type to application/
json). However, when invoking render_to_response it is not expected that the response
object being returned would be the same one used later in the request. The response object returned
from render_to_response is now explicitly different from request.response. This does
not change the API of a renderer. See https://github.com/Pylons/pyramid/pull/1563
• The append_slash argument of `Configurator().add_notfound_view() will now
accept anything that implements the IResponse interface and will use that as the response class
instead of the default HTTPFound. See https://github.com/Pylons/pyramid/pull/1610

1010 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• The JSONP renderer created JavaScript code in such a way that a callback variable could be used to
arbitrarily inject javascript into the response object. https://github.com/Pylons/pyramid/pull/1627
• Work around an issue where pserve --reload would leave terminal echo disabled if it reloaded
during a pdb session. See https://github.com/Pylons/pyramid/pull/1577, https://github.com/Pylons/
pyramid/pull/1592
• pyramid.wsgi.wsgiapp and pyramid.wsgi.wsgiapp2 now raise ValueError when
accidentally passed None. See https://github.com/Pylons/pyramid/pull/1320
• Fix an issue whereby predicates would be resolved as maybe_dotted in the introspectable but not
when passed for registration. This would mean that add_route_predicate for example can
not take a string and turn it into the actual callable function. See https://github.com/Pylons/pyramid/
pull/1306
• Fix pyramid.testing.setUp to return a Configurator with a proper package. Previ-
ously it was not possible to do package-relative includes using the returned Configurator dur-
ing testing. There is now a package argument that can override this behavior as well. See
https://github.com/Pylons/pyramid/pull/1322
• Fix an issue where a pyramid.response.FileResponse may apply a charset where it does
not belong. See https://github.com/Pylons/pyramid/pull/1251
• Work around a bug introduced in Python 2.7.7 on Windows where mimetypes.guess_type
returns Unicode rather than str for the content type, unlike any previous version of Python. See
https://github.com/Pylons/pyramid/issues/1360 for more information.
• pcreate now normalizes the package name by converting hyphens to underscores. See https:
//github.com/Pylons/pyramid/pull/1376
• Fix an issue with the final response/finished callback being unable to add another callback to the
list. See https://github.com/Pylons/pyramid/pull/1373
• Fix a failing unittest caused by differing mimetypes across various OSs. See https://github.com/
Pylons/pyramid/issues/1405
• Fix route generation for static view asset specifications having no path. See https://github.com/
Pylons/pyramid/pull/1377
• Allow the pyramid.renderers.JSONP renderer to work even if there is no valid request ob-
ject. In this case it will not wrap the object in a callback and thus behave just like the pyramid.
renderers.JSON renderer. See https://github.com/Pylons/pyramid/pull/1561
• Prevent ”parameters to load are deprecated” DeprecationWarning from setuptools>=11.3. See
https://github.com/Pylons/pyramid/pull/1541

0.6. Change History 1011


The Pyramid Web Framework, Version 2.0.2

• Avoiding sharing the IRenderer objects across threads when attached to a view using the ren-
derer= argument. These renderers were instantiated at time of first render and shared between re-
quests, causing potentially subtle effects like pyramid.reload_templates = true failing to work in
pyramid_mako. See https://github.com/Pylons/pyramid/pull/1575 and https://github.com/Pylons/
pyramid/issues/1268
• Avoiding timing attacks against CSRF tokens. See https://github.com/Pylons/pyramid/pull/1574
• request.finished_callbacks and request.response_callbacks now default to
an iterable instead of None. It may be checked for a length of 0. This was the behavior in 1.5.

Deprecations

• The pserve command’s daemonization features have been deprecated. This includes
the [start,stop,restart,status] subcommands as well as the --daemon,
--stop-server, --pid-file, and --status flags.
Please use a real process manager in the future instead of relying on the pserve to daemonize itself.
Many options exist including your Operating System’s services such as Systemd or Upstart, as well
as Python-based solutions like Circus and Supervisor.
See https://github.com/Pylons/pyramid/pull/1641
• Renamed the principal argument to pyramid.security.remember() to userid in or-
der to clarify its intended purpose. See https://github.com/Pylons/pyramid/pull/1399

Docs

• Moved the documentation for accept on Configurator.add_view to no longer be part of


the predicate list. See https://github.com/Pylons/pyramid/issues/1391 for a bug report stating not_
was failing on accept. Discussion with @mcdonc led to the conclusion that it should not be
documented as a predicate. See https://github.com/Pylons/pyramid/pull/1487 for this PR
• Removed logging configuration from Quick Tutorial ini files except for scaffolding- and logging-
related chapters to avoid needing to explain it too early.
• Clarify a previously-implied detail of the ISession.invalidate API documentation.
• Improve and clarify the documentation on what Pyramid defines as a principal and a userid
in its security APIs. See https://github.com/Pylons/pyramid/pull/1399
• Add documentation of command line programs (p* scripts). See https://github.com/Pylons/
pyramid/pull/2191

1012 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Scaffolds

• Update scaffold generating machinery to return the version of pyramid and pyramid docs for use in
scaffolds. Updated starter, alchemy and zodb templates to have links to correctly versioned docu-
mentation and reflect which pyramid was used to generate the scaffold.
• Removed non-ascii copyright symbol from templates, as this was causing the scaffolds to fail for
project generation.
• You can now run the scaffolding func tests via tox py2-scaffolds and tox
py3-scaffolds.

1.5 (2014-04-08)

• Python 3.4 compatibility.


• Avoid crash in pserve --reload under Py3k, when iterating over possibly mutated sys.
modules.
• UnencryptedCookieSessionFactoryConfig failed if the secret contained higher order
characters. See https://github.com/Pylons/pyramid/issues/1246
• Fixed a bug in UnencryptedCookieSessionFactoryConfig and SignedCookieSes-
sionFactory where timeout=None would cause a new session to always be created. Also in
SignedCookieSessionFactory a reissue_time=None would cause an exception when
modifying the session. See https://github.com/Pylons/pyramid/issues/1247
• Updated docs and scaffolds to keep in step with new 2.0 release of Lingua. This included removing
all setup.cfg files from scaffolds and documentation environments.

1.5b1 (2014-02-08)

Features

• We no longer eagerly clear request.exception and request.exc_info in the exception


view tween. This makes it possible to inspect exception information within a finished callback. See
https://github.com/Pylons/pyramid/issues/1223.

0.6. Change History 1013


The Pyramid Web Framework, Version 2.0.2

1.5a4 (2014-01-28)

Features

• Updated scaffolds with new theme, fixed documentation and sample project.

Bug Fixes

• Depend on a newer version of WebOb so that we pull in some crucial bug-fixes that were showstop-
pers for functionality in Pyramid.
• Add a trailing semicolon to the JSONP response. This fixes JavaScript syntax errors for old IE
versions. See https://github.com/Pylons/pyramid/pull/1205
• Fix a memory leak when the configurator’s set_request_property method was used or when
the configurator’s add_request_method method was used with the property=True at-
tribute. See https://github.com/Pylons/pyramid/issues/1212 .

1.5a3 (2013-12-10)

Features

• An authorization API has been added as a method of the request: request.has_permission.


request.has_permission is a method-based alternative to the pyramid.security.
has_permission API and works exactly the same. The older API is now deprecated.
• Property API attributes have been added to the request for easier access to authentication
data: request.authenticated_userid, request.unauthenticated_userid, and
request.effective_principals.
These are analogues, respectively, of pyramid.security.authenticated_userid,
pyramid.security.unauthenticated_userid, and pyramid.security.
effective_principals. They operate exactly the same, except they are attributes of
the request instead of functions accepting a request. They are properties, so they cannot be assigned
to. The older function-based APIs are now deprecated.
• Pyramid’s console scripts (pserve, pviews, etc) can now be run directly, allowing custom argu-
ments to be sent to the python interpreter at runtime. For example:

1014 CONTENTS
The Pyramid Web Framework, Version 2.0.2

python -3 -m pyramid.scripts.pserve development.ini

• Added a specific subclass of HTTPBadRequest named pyramid.exceptions.


BadCSRFToken which will now be raised in response to failures in check_csrf_token. See
https://github.com/Pylons/pyramid/pull/1149
• Added a new SignedCookieSessionFactory which is very similar to the Unencrypt-
edCookieSessionFactoryConfig but with a clearer focus on signing content. The custom
serializer arguments to this function should only focus on serializing, unlike its predecessor which
required the serializer to also perform signing. See https://github.com/Pylons/pyramid/pull/1142
. Note that cookies generated using SignedCookieSessionFactory are not compatible
with cookies generated using UnencryptedCookieSessionFactory, so existing user ses-
sion data will be destroyed if you switch to it.
• Added a new BaseCookieSessionFactory which acts as a generic cookie factory that can be
used by framework implementors to create their own session implementations. It provides a reusable
API which focuses strictly on providing a dictionary-like object that properly handles renewals, time-
outs, and conformance with the ISession API. See https://github.com/Pylons/pyramid/pull/1142
• The anchor argument to pyramid.request.Request.route_url and pyramid.
request.Request.resource_url and their derivatives will now be escaped via URL quot-
ing to ensure minimal conformance. See https://github.com/Pylons/pyramid/pull/1183
• Allow sending of _query and _anchor options to pyramid.request.Request.
static_url when an external URL is being generated. See https://github.com/Pylons/pyramid/
pull/1183
• You can now send a string as the _query argument to pyramid.request.Request.
route_url and pyramid.request.Request.resource_url and their derivatives.
When a string is sent instead of a list or dictionary. it is URL-quoted however it does not need
to be in k=v form. This is useful if you want to be able to use a different query string format than
x-www-form-urlencoded. See https://github.com/Pylons/pyramid/pull/1183
• pyramid.testing.DummyRequest now has a domain attribute to match the new WebOb
1.3 API. Its value is example.com.

Bug Fixes

• Fix the pcreate script so that when the target directory name ends with a slash it does not produce
a non-working project directory structure. Previously saying pcreate -s starter /foo/
bar/ produced different output than saying pcreate -s starter /foo/bar. The former
did not work properly.

0.6. Change History 1015


The Pyramid Web Framework, Version 2.0.2

• Fix the principals_allowed_by_permission method of ACLAuthorizationPol-


icy so it anticipates a callable __acl__ on resources. Previously it did not try to call the __acl__
if it was callable.
• The pviews script did not work when a url required custom request methods in order to perform
traversal. Custom methods and descriptors added via pyramid.config.Configurator.
add_request_method will now be present, allowing traversal to continue. See https://github.
com/Pylons/pyramid/issues/1104
• Remove unused renderer argument from Configurator.add_route.
• Allow the BasicAuthenticationPolicy to work with non-ASCII usernames and passwords.
The charset is not passed as part of the header and different browsers alternate between UTF-8 and
Latin-1, so the policy now attempts to decode with UTF-8 first, and will fallback to Latin-1. See
https://github.com/Pylons/pyramid/pull/1170
• The @view_defaults now apply to notfound and forbidden views that are defined as methods
of a decorated class. See https://github.com/Pylons/pyramid/issues/1173

Documentation

• Added a ”Quick Tutorial” to go with the Quick Tour


• Removed mention of pyramid_beaker from docs. Beaker is no longer maintained. Point people
at pyramid_redis_sessions instead.
• Add documentation for pyramid.interfaces.IRendererFactory and pyramid.
interfaces.IRenderer.

Backwards Incompatibilities

• The key/values in the _query parameter of request.route_url and the query parameter
of request.resource_url (and their variants), used to encode a value of None as the string
'None', leaving the resulting query string to be a=b&key=None. The value is now dropped in this
situation, leaving a query string of a=b&key=. See https://github.com/Pylons/pyramid/issues/1119

Deprecations

• Deprecate the pyramid.interfaces.ITemplateRenderer interface. It was ill-defined


and became unused when Mako and Chameleon template bindings were split into their own pack-
ages.

1016 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The pyramid.session.UnencryptedCookieSessionFactoryConfig
API has been deprecated and is superseded by the pyramid.session.
SignedCookieSessionFactory. Note that while the cookies generated by the Un-
encryptedCookieSessionFactoryConfig are compatible with cookies gener-
ated by old releases, cookies generated by the SignedCookieSessionFactory are not. See
https://github.com/Pylons/pyramid/pull/1142
• The pyramid.security.has_permission API is now deprecated. Instead, use the newly-
added has_permission method of the request object.
• The pyramid.security.effective_principals API is now deprecated. Instead, use
the newly-added effective_principals attribute of the request object.
• The pyramid.security.authenticated_userid API is now deprecated. Instead, use
the newly-added authenticated_userid attribute of the request object.
• The pyramid.security.unauthenticated_userid API is now deprecated. Instead, use
the newly-added unauthenticated_userid attribute of the request object.

Dependencies

• Pyramid now depends on WebOb>=1.3 (it uses webob.cookies.CookieProfile from 1.3+).

1.5a2 (2013-09-22)

Features

• Users can now provide dotted Python names to as the factory argument the Configurator meth-
ods named add_{view,route,subscriber}_predicate (instead of passing the predicate
factory directly, you can pass a dotted name which refers to the factory).

Bug Fixes

• Fix an exception in pyramid.path.package_name when resolving the package name for


namespace packages that had no __file__ attribute.

0.6. Change History 1017


The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• Pyramid no longer depends on or configures the Mako and Chameleon templating system renderers
by default. Disincluding these templating systems by default means that the Pyramid core has fewer
dependencies and can run on future platforms without immediate concern for the compatibility of
its templating add-ons. It also makes maintenance slightly more effective, as different people can
maintain the templating system add-ons that they understand and care about without needing commit
access to the Pyramid core, and it allows users who just don’t want to see any packages they don’t
use come along for the ride when they install Pyramid.
This means that upon upgrading to Pyramid 1.5a2+, projects that use either of these templating
systems will see a traceback that ends something like this when their application attempts to render
a Chameleon or Mako template:

ValueError: No such renderer factory .pt

Or:

ValueError: No such renderer factory .mako

Or:

ValueError: No such renderer factory .mak

Support for Mako templating has been moved into an add-on package named pyramid_mako,
and support for Chameleon templating has been moved into an add-on package named pyra-
mid_chameleon. These packages are drop-in replacements for the old built-in support for these
templating langauges. All you have to do is install them and make them active in your configuration
to register renderer factories for .pt and/or .mako (or .mak) to make your application work again.
To re-add support for Chameleon and/or Mako template renderers into your existing projects, follow
the below steps.
If you depend on Mako templates:
– Make sure the pyramid_mako package is installed. One way to do this is by adding pyra-
mid_mako to the install_requires section of your package’s setup.py file and
afterwards rerunning setup.py develop:

setup(
#...
install_requires=[
'pyramid_mako', # new dependency
(continues on next page)

1018 CONTENTS
The Pyramid Web Framework, Version 2.0.2

(continued from previous page)


'pyramid',
#...
],
)

– Within the portion of your application which instantiates a Pyramid pyramid.config.


Configurator (often the main() function in your project’s __init__.py file), tell
Pyramid to include the pyramid_mako includeme:

config = Configurator(.....)
config.include('pyramid_mako')

If you depend on Chameleon templates:


– Make sure the pyramid_chameleon package is installed. One way to do this is by adding
pyramid_chameleon to the install_requires section of your package’s setup.
py file and afterwards rerunning setup.py develop:

setup(
#...
install_requires=[
'pyramid_chameleon', # new dependency
'pyramid',
#...
],
)

– Within the portion of your application which instantiates a Pyramid ~pyramid.config.


Configurator (often the main() function in your project’s __init__.py file), tell
Pyramid to include the pyramid_chameleon includeme:

config = Configurator(.....)
config.include('pyramid_chameleon')

Note that it’s also fine to install these packages into older Pyramids for forward compatibility pur-
poses. Even if you don’t upgrade to Pyramid 1.5 immediately, performing the above steps in a
Pyramid 1.4 installation is perfectly fine, won’t cause any difference, and will give you forward
compatibility when you eventually do upgrade to Pyramid 1.5.
With the removal of Mako and Chameleon support from the core, some unit tests that use
the pyramid.renderers.render* methods may begin to fail. If any of your unit
tests are invoking either pyramid.renderers.render() or pyramid.renderers.
render_to_response() with either Mako or Chameleon templates then the pyramid.

0.6. Change History 1019


The Pyramid Web Framework, Version 2.0.2

config.Configurator instance in effect during the unit test should be also be updated to
include the addons, as shown above. For example:

class ATest(unittest.TestCase):
def setUp(self):
self.config = pyramid.testing.setUp()
self.config.include('pyramid_mako')

def test_it(self):
result = pyramid.renderers.render('mypkg:templates/home.mako',
,→{})

Or:

class ATest(unittest.TestCase):
def setUp(self):
self.config = pyramid.testing.setUp()
self.config.include('pyramid_chameleon')

def test_it(self):
result = pyramid.renderers.render('mypkg:templates/home.pt', {}
,→ )

• If you’re using the Pyramid debug toolbar, when you upgrade Pyramid to 1.5a2+, you’ll also need to
upgrade the pyramid_debugtoolbar package to at least version 1.0.8, as older toolbar versions
are not compatible with Pyramid 1.5a2+ due to the removal of Mako support from the core. It’s fine
to use this newer version of the toolbar code with older Pyramids too.
• Removed the request.response_* varying attributes. These attributes have been deprecated
since Pyramid 1.1, and as per the deprecation policy, have now been removed.
• request.response will no longer be mutated when using the pyramid.renderers.
render() API. Almost all renderers mutate the request.response response object (for
example, the JSON renderer sets request.response.content_type to application/
json), but this is only necessary when the renderer is generating a response; it was a bug when it
was done as a side effect of calling pyramid.renderers.render().
• Removed the bfg2pyramid fixer script.
• The pyramid.events.NewResponse event is now sent after response callbacks are executed.
It previously executed before response callbacks were executed. Rationale: it’s more useful to be
able to inspect the response after response callbacks have done their jobs instead of before.
• Removed the class named pyramid.view.static that had been deprecated since Pyramid 1.1.
Instead use pyramid.static.static_view with use_subpath=True argument.

1020 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Removed the pyramid.view.is_response function that had been deprecated since Pyramid
1.1. Use the pyramid.request.Request.is_response method instead.
• Removed the ability to pass the following arguments to pyramid.config.Configurator.
add_route: view, view_context. view_for, view_permission, view_renderer,
and view_attr. Using these arguments had been deprecated since Pyramid 1.1. Instead of
passing view-related arguments to add_route, use a separate call to pyramid.config.
Configurator.add_view to associate a view with a route using its route_name argument.
Note that this impacts the pyramid.config.Configurator.add_static_view function
too, because it delegates to add_route.
• Removed the ability to influence and query a pyramid.request.Request object as if it were a
dictionary. Previously it was possible to use methods like __getitem__, get, items, and other
dictlike methods to access values in the WSGI environment. This behavior had been deprecated
since Pyramid 1.1. Use methods of request.environ (a real dictionary) instead.
• Removed ancient backwards compatibility hack in pyramid.traversal.
DefaultRootFactory which populated the __dict__ of the factory with the matchdict
values for compatibility with BFG 0.9.
• The renderer_globals_factory argument to the pyramid.config.Configurator`
constructor and its ``setup_registry method has been removed. The
set_renderer_globals_factory method of pyramid.config.Configurator has
also been removed. The (internal) pyramid.interfaces.IRendererGlobals interface
was also removed. These arguments, methods and interfaces had been deprecated since 1.1. Use a
BeforeRender event subscriber as documented in the ”Hooks” chapter of the Pyramid narrative
documentation instead of providing renderer globals values to the configurator.

Deprecations

• The pyramid.config.Configurator.set_request_property method now issues a


deprecation warning when used. It had been docs-deprecated in 1.4 but did not issue a deprecation
warning when used.

1.5a1 (2013-08-30)

Features

• A new http exception subclass named pyramid.httpexceptions.HTTPSuccessful was


added. You can use this class as the context of an exception view to catch all 200-series ”ex-
ceptions” (e.g. ”raise HTTPOk”). This also allows you to catch only the HTTPOk exception itself;
previously this was impossible because a number of other exceptions (such as HTTPNoContent)
inherited from HTTPOk, but now they do not.

0.6. Change History 1021


The Pyramid Web Framework, Version 2.0.2

• You can now generate ”hybrid” urldispatch/traversal URLs more easily by using the new
route_name, route_kw and route_remainder_name arguments to request.
resource_url and request.resource_path. See the new section of the ”Combining
Traversal and URL Dispatch” documentation chapter entitled ”Hybrid URL Generation”.
• It is now possible to escape double braces in Pyramid scaffolds (unescaped, these represent replace-
ment values). You can use \{\{a\}\} to represent a ”bare” {{a}}. See https://github.com/
Pylons/pyramid/pull/862
• Add localizer and locale_name properties (reified) to the request. See https://github.com/
Pylons/pyramid/issues/508. Note that the pyramid.i18n.get_localizer and pyramid.
i18n.get_locale_name functions now simply look up these properties on the request.
• Add pdistreport script, which prints the Python version in use, the Pyramid version in use, and
the version number and location of all Python distributions currently installed.
• Add the ability to invert the result of any view, route, or subscriber predicate using the not_ class.
For example:

from pyramid.config import not_

@view_config(route_name='myroute', request_method=not_('POST'))
def myview(request): ...

The above example will ensure that the view is called if the request method is not POST (at least if
no other view is more specific).
The pyramid.config.not_ class can be used against any value that is a predicate value passed
in any of these contexts:
– pyramid.config.Configurator.add_view
– pyramid.config.Configurator.add_route
– pyramid.config.Configurator.add_subscriber
– pyramid.view.view_config
– pyramid.events.subscriber
• scripts/prequest.py: add support for submitting PUT and PATCH requests. See https:
//github.com/Pylons/pyramid/pull/1033. add support for submitting OPTIONS and PROPFIND re-
quests, and allow users to specify basic authentication credentials in the request via a --login
argument to the script. See https://github.com/Pylons/pyramid/pull/1039.
• ACLAuthorizationPolicy supports __acl__ as a callable. This removes the ambiguity
between the potential AttributeError that would be raised on the context when the property
was not defined and the AttributeError that could be raised from any user-defined code within

1022 CONTENTS
The Pyramid Web Framework, Version 2.0.2

a dynamic property. It is recommended to define a dynamic ACL as a callable to avoid this ambiguity.
See https://github.com/Pylons/pyramid/issues/735.
• Allow a protocol-relative URL (e.g. //example.com/images) to be passed to pyramid.
config.Configurator.add_static_view. This allows externally-hosted static URLs to
be generated based on the current protocol.
• The AuthTktAuthenticationPolicy has two new options to configure its domain usage:
– parent_domain: if set the authentication cookie is set on the parent domain. This is useful
if you have multiple sites sharing the same domain.
– domain: if provided the cookie is always set for this domain, bypassing all usual logic.
See https://github.com/Pylons/pyramid/pull/1028, https://github.com/Pylons/pyramid/pull/1072
and https://github.com/Pylons/pyramid/pull/1078.
• The AuthTktAuthenticationPolicy now supports IPv6 addresses when using the in-
clude_ip=True option. This is possibly incompatible with alternative auth_tkt implemen-
tations, as the specification does not define how to properly handle IPv6. See https://github.com/
Pylons/pyramid/issues/831.
• Make it possible to use variable arguments via pyramid.paster.get_appsettings. This
also allowed the generated initialize_db script from the alchemy scaffold to grow support
for options in the form a=1 b=2 so you can fill in values in a parameterized .ini file, e.g. ini-
tialize_myapp_db etc/development.ini a=1 b=2. See https://github.com/Pylons/
pyramid/pull/911
• The request.session.check_csrf_token() method and the check_csrf view pred-
icate now take into account the value of the HTTP header named X-CSRF-Token (as well as the
csrf_token form parameter, which they always did). The header is tried when the form param-
eter does not exist.
• View lookup will now search for valid views based on the inheritance hierarchy of the context. It
tries to find views based on the most specific context first, and upon predicate failure, will move
up the inheritance chain to test views found by the super-type of the context. In the past, only the
most specific type containing views would be checked and if no matching view could be found then
a PredicateMismatch would be raised. Now predicate mismatches don’t hide valid views registered
on super-types. Here’s an example that now works:

class IResource(Interface):

...

@view_config(context=IResource)
def get(context, request):

...
(continues on next page)

0.6. Change History 1023


The Pyramid Web Framework, Version 2.0.2

(continued from previous page)

@view_config(context=IResource, request_method='POST')
def post(context, request):

...

@view_config(context=IResource, request_method='DELETE')
def delete(context, request):

...

@implementer(IResource)
class MyResource:

...

@view_config(context=MyResource, request_method='POST')
def override_post(context, request):

...

Previously the override_post view registration would hide the get and delete views in the context of
MyResource -- leading to a predicate mismatch error when trying to use GET or DELETE meth-
ods. Now the views are found and no predicate mismatch is raised. See https://github.com/Pylons/
pyramid/pull/786 and https://github.com/Pylons/pyramid/pull/1004 and https://github.com/Pylons/
pyramid/pull/1046
• The pserve command now takes a -v (or --verbose) flag and a -q (or --quiet) flag. Output
from running pserve can be controlled using these flags. -v can be specified multiple times to
increase verbosity. -q sets verbosity to 0 unconditionally. The default verbosity level is 1.
• The alchemy scaffold tests now provide better coverage. See https://github.com/Pylons/pyramid/
pull/1029
• The pyramid.config.Configurator.add_route method now supports being called with
an external URL as pattern. See https://github.com/Pylons/pyramid/issues/611 and the documenta-
tion section in the ”URL Dispatch” chapter entitled ”External Routes” for more information.

1024 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• It was not possible to use pyramid.httpexceptions.HTTPException as the context of


an exception view as very general catchall for http-related exceptions when you wanted that exception
view to override the default exception view. See https://github.com/Pylons/pyramid/issues/985
• When the pyramid.reload_templates setting was true, and a Chameleon template was
reloaded, and the renderer specification named a macro (e.g. foo#macroname.pt), renderings
of the template after the template was reloaded due to a file change would produce the entire template
body instead of just a rendering of the macro. See https://github.com/Pylons/pyramid/issues/1013.
• Fix an obscure problem when combining a virtual root with a route with a *traverse in its pat-
tern. Now the traversal path generated in such a configuration will be correct, instead of an element
missing a leading slash.
• Fixed a Mako renderer bug returning a tuple with a previous defname value in some circumstances.
See https://github.com/Pylons/pyramid/issues/1037 for more information.
• Make the pyramid.config.assets.PackageOverrides object implement the API for
__loader__ objects specified in PEP 302. Proxies to the __loader__ set by the importer,
if present; otherwise, raises NotImplementedError. This makes Pyramid static view over-
rides work properly under Python 3.3 (previously they would not). See https://github.com/Pylons/
pyramid/pull/1015 for more information.
• mako_templating: added defensive workaround for non-importability of mako due to upstream
markupsafe dropping Python 3.2 support. Mako templating will no longer work under the com-
bination of MarkupSafe 0.17 and Python 3.2 (although the combination of MarkupSafe 0.17 and
Python 3.3 or any supported Python 2 version will work OK).
• Spaces and dots may now be in mako renderer template paths. This was broken when support for
the new makodef syntax was added in 1.4a1. See https://github.com/Pylons/pyramid/issues/950
• pyramid.debug_authorization=true will now correctly print out Allowed for views
registered with NO_PERMISSION_REQUIRED instead of invoking the permits method of the
authorization policy. See https://github.com/Pylons/pyramid/issues/954
• Pyramid failed to install on some systems due to being packaged with some test files containing
higher order characters in their names. These files have now been removed. See https://github.com/
Pylons/pyramid/issues/981
• pyramid.testing.DummyResource didn’t define __bool__, so code under Python 3
would use __len__ to find truthiness; this usually caused an instance of DummyResource to be
”falsy” instead of ”truthy”. See https://github.com/Pylons/pyramid/pull/1032
• The alchemy scaffold would break when the database was MySQL during tables creation. See
https://github.com/Pylons/pyramid/pull/1049

0.6. Change History 1025


The Pyramid Web Framework, Version 2.0.2

• The current_route_url method now attaches the query string to the URL by default. See
https://github.com/Pylons/pyramid/issues/1040
• Make pserve.cherrypy_server_runner Python 3 compatible. See https://github.com/
Pylons/pyramid/issues/718

Backwards Incompatibilities

• Modified the current_route_url method in pyramid.Request. The method previously re-


turned the URL without the query string by default, it now does attach the query string unless it
is overriden.
• The route_url and route_path APIs no longer quote / to %2F when a replacement value
contains a /. This was pointless, as WSGI servers always unquote the slash anyway, and Pyramid
never sees the quoted value.
• It is no longer possible to set a locale_name attribute of the request, nor is it possible to set a
localizer attribute of the request. These are now ”reified” properties that look up a locale name
and localizer respectively using the machinery described in the ”Internationalization” chapter of the
documentation.
• If you send an X-Vhm-Root header with a value that ends with a slash (or any number of slashes),
the trailing slash(es) will be removed before a URL is generated when you use use request.
resource_url or request.resource_path. Previously the virtual root path would not
have trailing slashes stripped, which would influence URL generation.
• The pyramid.interfaces.IResourceURL interface has now grown two new attributes:
virtual_path_tuple and physical_path_tuple. These should be the tuple form of
the resource’s path (physical and virtual).

1.4 (2012-12-18)

Docs

• Fix functional tests in the ZODB tutorial

1.4b3 (2012-12-10)

• Packaging release only, no code changes. 1.4b2 was a brownbag release due to missing directories
in the tarball.

1026 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.4b2 (2012-12-10)

Docs

• Scaffolding is now PEP-8 compliant (at least for a brief shining moment).
• Tutorial improvements.

Backwards Incompatibilities

• Modified the _depth argument to pyramid.view.view_config to accept a value relative


to the invocation of view_config itself. Thus, when it was previously expecting a value of 1
or greater, to reflect that the caller of view_config is 1 stack frame away from venusian.
attach, this implementation detail is now hidden.
• Modified the _backframes argument to pyramid.util.action_method in a similar way
to the changes described to _depth above. This argument remains undocumented, but might be
used in the wild by some insane person.

1.4b1 (2012-11-21)

Features

• Small microspeed enhancement which anticipates that a pyramid.response.Response ob-


ject is likely to be returned from a view. Some code is shortcut if the class of the object returned by
a view is this class. A similar microoptimization was done to pyramid.request.Request.
is_response.
• Make it possible to use variable arguments on p* commands (pserve, pshell, pviews, etc)
in the form a=1 b=2 so you can fill in values in parameterized .ini file, e.g. pshell etc/
development.ini http_port=8080. See https://github.com/Pylons/pyramid/pull/714
• A somewhat advanced and obscure feature of Pyramid event handlers is their ability to handle ”multi-
interface” notifications. These notifications have traditionally presented multiple objects to the sub-
scriber callable. For instance, if an event was sent by code like this:

registry.notify(event, context)

In the past, in order to catch such an event, you were obligated to write and register an event subscriber
that mentioned both the event and the context in its argument list:

0.6. Change History 1027


The Pyramid Web Framework, Version 2.0.2

@subscriber([SomeEvent, SomeContextType])
def asubscriber(event, context):
pass

In many subscriber callables registered this way, it was common for the logic in the subscriber
callable to completely ignore the second and following arguments (e.g. context in the above
example might be ignored), because they usually existed as attributes of the event anyway. You
could usually get the same value by doing event.context or similar.
The fact that you needed to put an extra argument which you usually ignored in the subscriber
callable body was only a minor annoyance until we added ”subscriber predicates”, used to narrow
the set of circumstances under which a subscriber will be executed, in a prior 1.4 alpha release. Once
those were added, the annoyance was escalated, because subscriber predicates needed to accept the
same argument list and arity as the subscriber callables that they were configured against. So, for
example, if you had these two subscriber registrations in your code:

@subscriber([SomeEvent, SomeContextType])
def asubscriber(event, context):
pass

@subscriber(SomeOtherEvent)
def asubscriber(event):
pass

And you wanted to use a subscriber predicate:

@subscriber([SomeEvent, SomeContextType], mypredicate=True)


def asubscriber1(event, context):
pass

@subscriber(SomeOtherEvent, mypredicate=True)
def asubscriber2(event):
pass

If an existing mypredicate subscriber predicate had been written in such a way that it accepted
only one argument in its __call__, you could not use it against a subscription which named more
than one interface in its subscriber interface list. Similarly, if you had written a subscriber predicate
that accepted two arguments, you couldn’t use it against a registration that named only a single
interface type.
For example, if you created this predicate:

1028 CONTENTS
The Pyramid Web Framework, Version 2.0.2

class MyPredicate(object):
# portions elided...
def __call__(self, event):
return self.val == event.context.foo

It would not work against a multi-interface-registered subscription, so in the above example, when
you attempted to use it against asubscriber1, it would fail at runtime with a TypeError, claiming
something was attempting to call it with too many arguments.
To hack around this limitation, you were obligated to design the mypredicate predicate to expect
to receive in its __call__ either a single event argument (a SomeOtherEvent object) or a pair
of arguments (a SomeEvent object and a SomeContextType object), presumably by doing something
like this:

class MyPredicate(object):
# portions elided...
def __call__(self, event, context=None):
return self.val == event.context.foo

This was confusing and bad.


In order to allow people to ignore unused arguments to subscriber callables and to normalize the
relationship between event subscribers and subscriber predicates, we now allow both subscribers
and subscriber predicates to accept only a single event argument even if they’ve been subscribed
for notifications that involve multiple interfaces. Subscribers and subscriber predicates that accept
only one argument will receive the first object passed to notify; this is typically (but not always)
the event object. The other objects involved in the subscription lookup will be discarded. You can
now write an event subscriber that accepts only event even if it subscribes to multiple interfaces:

@subscriber([SomeEvent, SomeContextType])
def asubscriber(event):
# this will work!

This prevents you from needing to match the subscriber callable parameters to the subscription type
unnecessarily, especially when you don’t make use of any argument in your subscribers except for
the event object itself.
Note, however, that if the event object is not the first object in the call to notify, you’ll run into
trouble. For example, if notify is called with the context argument first:

registry.notify(context, event)

You won’t be able to take advantage of the event-only feature. It will ”work”, but the object received
by your event handler won’t be the event object, it will be the context object, which won’t be very

0.6. Change History 1029


The Pyramid Web Framework, Version 2.0.2

useful:

@subscriber([SomeContextType, SomeEvent])
def asubscriber(event):
# bzzt! you'll be getting the context here as ``event``, and it'll
# be useless

Existing multiple-argument subscribers continue to work without issue, so you should continue use
those if your system notifies using multiple interfaces and the first interface is not the event interface.
For example:

@subscriber([SomeContextType, SomeEvent])
def asubscriber(context, event):
# this will still work!

The event-only feature makes it possible to use a subscriber predicate that accepts only a request ar-
gument within both multiple-interface subscriber registrations and single-interface subscriber regis-
trations. You needn’t make slightly different variations of predicates depending on the subscription
type arguments. Instead, just write all your subscriber predicates so they only accept event in their
__call__ and they’ll be useful across all registrations for subscriptions that use an event as their
first argument, even ones which accept more than just event.
However, the same caveat applies to predicates as to subscriber callables: if you’re subscribing to
a multi-interface event, and the first interface is not the event interface, the predicate won’t work
properly. In such a case, you’ll need to match the predicate __call__ argument ordering and
composition to the ordering of the interfaces. For example, if the registration for the subscription
uses [SomeContext, SomeEvent], you’ll need to reflect that in the ordering of the parameters
of the predicate’s __call__ method:

def __call__(self, context, event):


return event.request.path.startswith(self.val)

tl;dr: 1) When using multi-interface subscriptions, always use the event type as the first subscription
registration argument and 2) When 1 is true, use only event in your subscriber and subscriber
predicate parameter lists, no matter how many interfaces the subscriber is notified with. This com-
bination will result in the maximum amount of reusability of subscriber predicates and the least
amount of thought on your part. Drink responsibly.

1030 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• A failure when trying to locate the attribute __text__ on route and view predicates existed when
the debug_routematch setting was true or when the pviews command was used. See https:
//github.com/Pylons/pyramid/pull/727

Documentation

• Sync up tutorial source files with the files that are rendered by the scaffold that each uses.

1.4a4 (2012-11-14)

Features

• pyramid.authentication.AuthTktAuthenticationPolicy has been updated to


support newer hashing algorithms such as sha512. Existing applications should consider updating
if possible for improved security over the default md5 hashing.
• Added an effective_principals route and view predicate.
• Do not allow the userid returned from the authenticated_userid or the userid that is one of
the list of principals returned by effective_principals to be either of the strings system.
Everyone or system.Authenticated when any of the built-in authorization policies that
live in pyramid.authentication are in use. These two strings are reserved for internal usage
by Pyramid and they will not be accepted as valid userids.
• Slightly better debug logging from pyramid.authentication.
RepozeWho1AuthenticationPolicy.
• pyramid.security.view_execution_permitted used to return True if no view could
be found. It now raises a TypeError exception in that case, as it doesn’t make sense to assert that
a nonexistent view is execution-permitted. See https://github.com/Pylons/pyramid/issues/299.
• Allow a _depth argument to pyramid.view.view_config, which will permit limited com-
position reuse of the decorator by other software that wants to provide custom decorators that are
much like view_config.
• Allow an iterable of decorators to be passed to pyramid.config.Configurator.
add_view. This allows views to be wrapped by more than one decorator without requiring com-
bining the decorators yourself.

0.6. Change History 1031


The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• In the past if a renderer returned None, the body of the resulting response would be set explicitly to
the empty string. Instead, now, the body is left unchanged, which allows the renderer to set a body
itself by using e.g. request.response.body = b'foo'. The body set by the renderer will
be unmolested on the way out. See https://github.com/Pylons/pyramid/issues/709
• In uncommon cases, the pyramid_excview_tween_factory might have inadvertently raised
a KeyError looking for request_iface as an attribute of the request. It no longer fails in this
case. See https://github.com/Pylons/pyramid/issues/700
• Be more tolerant of potential error conditions in match_param and physical_path predicate
implementations; instead of raising an exception, return False.
• pyramid.view.render_view was not functioning properly under Python 3.x due to a
byte/unicode discrepancy. See https://github.com/Pylons/pyramid/issues/721

Deprecations

• pyramid.authentication.AuthTktAuthenticationPolicy will emit a warning if


an application is using the policy without explicitly passing a hashalg argument. This is because
the default is ”md5” which is considered theoretically subject to collision attacks. If you really want
”md5” then you must specify it explicitly to get rid of the warning.

Documentation

• All of the tutorials that use pyramid.authentication.


AuthTktAuthenticationPolicy now explicitly pass sha512 as a hashalg argument.

Internals

• Move TopologicalSorter from pyramid.config.util to pyramid.util, move


CyclicDependencyError from pyramid.config.util to pyramid.exceptions,
rename Singleton to Sentinel and move from pyramid.config.util to pyramid.
util; this is in an effort to move that stuff that may be an API one day out of pyramid.config.
util, because that package should never be imported from non-Pyramid code. TopologicalSorter
is still not an API, but may become one.
• Get rid of shady monkeypatching of pyramid.request.Request and pyramid.
response.Response done within the __init__.py of Pyramid. Webob no longer relies
on this being done. Instead, the ResponseClass attribute of the Pyramid Request class is assigned
to the Pyramid response class; that’s enough to satisfy WebOb and behave as it did before with the
monkeypatching.

1032 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.4a3 (2012-10-26)

Bug Fixes

• The match_param predicate’s text method was fixed to sort its values. Part of https://github.com/
Pylons/pyramid/pull/705
• 1.4a pyramid.scripting.prepare behaved differently than 1.3 series function of same
name. In particular, if passed a request, it would not set the registry attribute of the request
like 1.3 did. A symptom would be that passing a request to pyramid.paster.bootstrap
(which uses the function) that did not have a registry attribute could assume that the registry
would be attached to the request by Pyramid. This assumption could be made in 1.3, but not in 1.4.
The assumption can now be made in 1.4 too (a registry is attached to a request passed to bootstrap
or prepare).
• When registering a view configuration that named a Chameleon ZPT renderer with a macro name in
it (e.g. renderer='some/template#somemacro.pt) as well as a view configuration with-
out a macro name in it that pointed to the same template (e.g. renderer='some/template.
pt'), internal caching could confuse the two, and your code might have rendered one instead of the
other.

Features

• Allow multiple values to be specified to the request_param view/route predicate as a sequence.


Previously only a single string value was allowed. See https://github.com/Pylons/pyramid/pull/705
• Comments with references to documentation sections placed in scaffold .ini files.
• Added an HTTP Basic authentication policy at pyramid.authentication.
BasicAuthAuthenticationPolicy.
• The Configurator testing_securitypolicy method now returns the policy object it creates.
• The Configurator testing_securitypolicy method accepts two new arguments: remem-
ber_result and forget_result. If supplied, these values influence the result of the policy’s
remember and forget methods, respectively.
• The DummySecurityPolicy created by testing_securitypolicy now sets a forgotten
value on the policy (the value True) when its forget method is called.
• The DummySecurityPolicy created by testing_securitypolicy now sets a remembered
value on the policy, which is the value of the principal argument it’s called with when its re-
member method is called.

0.6. Change History 1033


The Pyramid Web Framework, Version 2.0.2

• New physical_path view predicate. If specified, this value should be a string or a tuple
representing the physical traversal path of the context found via traversal for this predicate to
match as true. For example: physical_path='/' or physical_path='/a/b/c' or
physical_path=('', 'a', 'b', 'c'). This is not a path prefix match or a regex, it’s a
whole-path match. It’s useful when you want to always potentially show a view when some object is
traversed to, but you can’t be sure about what kind of object it will be, so you can’t use the context
predicate. The individual path elements in between slash characters or in tuple elements should be
the Unicode representation of the name of the resource and should not be encoded in any way.

1.4a2 (2012-09-27)

Bug Fixes

• When trying to determine Mako defnames and Chameleon macro names in asset specifications, take
into account that the filename may have a hyphen in it. See https://github.com/Pylons/pyramid/pull/
692

Features

• A new pyramid.session.check_csrf_token convenience function was added.


• A check_csrf view predicate was added. For example, you can now do config.
add_view(someview, check_csrf=True). When the predicate is checked, if the
csrf_token value in request.params matches the CSRF token in the request’s session, the
view will be permitted to execute. Otherwise, it will not be permitted to execute.
• Add Base.metadata.bind = engine to alchemy template, so that tables defined imperatively
will work.

Documentation

• update wiki2 SQLA tutorial with the changes required after inserting Base.metadata.bind =
engine into the alchemy scaffold.

1034 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.4a1 (2012-09-16)

Bug Fixes

• Forward port from 1.3 branch: When no authentication policy was configured, a call to pyramid.
security.effective_principals would unconditionally return the empty list. This was
incorrect, it should have unconditionally returned [Everyone], and now does.
• Explicit url dispatch regexes can now contain colons. https://github.com/Pylons/pyramid/issues/629
• On at least one 64-bit Ubuntu system under Python 3.2, using the view_config decorator caused
a RuntimeError: dictionary changed size during iteration exception. It no
longer does. See https://github.com/Pylons/pyramid/issues/635 for more information.
• In Mako Templates lookup, check if the uri is already adjusted and bring it back to an asset spec. Nor-
mally occurs with inherited templates or included components. https://github.com/Pylons/pyramid/
issues/606 https://github.com/Pylons/pyramid/pull/607
• In Mako Templates lookup, check for absolute uri (using mako directories) when mixing up inheri-
tance with asset specs. https://github.com/Pylons/pyramid/issues/662
• HTTP Accept headers were not being normalized causing potentially conflicting view registrations
to go unnoticed. Two views that only differ in the case (’text/html’ vs. ’text/HTML’) will now raise
an error. https://github.com/Pylons/pyramid/pull/620
• Forward-port from 1.3 branch: when registering multiple views with an accept predicate in a
Pyramid application running under Python 3, you might have received a TypeError: un-
orderable types: function() < function() exception.

Features

• Python 3.3 compatibility.


• Configurator.add_directive now accepts arbitrary callables like partials or objects implementing
__call__ which dont have __name__ and __doc__ attributes. See https://github.com/Pylons/
pyramid/issues/621 and https://github.com/Pylons/pyramid/pull/647.
• Third-party custom view, route, and subscriber predicates can now be added for use by view authors
via pyramid.config.Configurator.add_view_predicate, pyramid.config.
Configurator.add_route_predicate and pyramid.config.Configurator.
add_subscriber_predicate. So, for example, doing this:

config.add_view_predicate('abc', my.package.ABCPredicate)

0.6. Change History 1035


The Pyramid Web Framework, Version 2.0.2

Might allow a view author to do this in an application that configured that predicate:

@view_config(abc=1)

Similar features exist for add_route, and add_subscriber. See ”Adding A Custom View,
Route, or Subscriber Predicate” in the Hooks chapter for more information.
Note that changes made to support the above feature now means that only actions registered using the
same ”order” can conflict with one another. It used to be the case that actions registered at different
orders could potentially conflict, but to my knowledge nothing ever depended on this behavior (it
was a bit silly).
• Custom objects can be made easily JSON-serializable in Pyramid by defining a __json__ method
on the object’s class. This method should return values natively serializable by json.dumps (such
as ints, lists, dictionaries, strings, and so forth).
• The JSON renderer now allows for the definition of custom type adapters to convert unknown objects
to JSON serializations.
• As of this release, the request_method predicate, when used, will also imply that HEAD is im-
plied when you use GET. For example, using @view_config(request_method='GET')
is equivalent to using @view_config(request_method=('GET', 'HEAD')). Us-
ing @view_config(request_method=('GET', 'POST') is equivalent to using
@view_config(request_method=('GET', 'HEAD', 'POST'). This is because
HEAD is a variant of GET that omits the body, and WebOb has special support to return an empty
body when a HEAD is used.
• config.add_request_method has been introduced to support extending request objects with
arbitrary callables. This method expands on the previous config.set_request_property
by supporting methods as well as properties. This method now causes less code to be executed at
request construction time than config.set_request_property in version 1.3.
• Don’t add a ? to URLs generated by request.resource_url if the query argument is pro-
vided but empty.
• Don’t add a ? to URLs generated by request.route_url if the _query argument is provided
but empty.
• The static view machinery now raises (rather than returns) HTTPNotFound and HTTPMoved-
Permanently exceptions, so these can be caught by the Not Found View (and other exception
views).
• The Mako renderer now supports a def name in an asset spec. When the def name is present in the
asset spec, the system will render the template def within the template and will return the result.
An example asset spec is package:path/to/template#defname.mako. This will render
the def named defname inside the template.mako template instead of rendering the entire
template. The old way of returning a tuple in the form ('defname', {}) from the view is
supported for backward compatibility,

1036 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The Chameleon ZPT renderer now accepts a macro name in an asset spec. When the macro name is
present in the asset spec, the system will render the macro listed as a define-macro and return
the result instead of rendering the entire template. An example asset spec: package:path/to/
template#macroname.pt. This will render the macro defined as macroname within the
template.pt template instead of the entire templae.
• When there is a predicate mismatch exception (seen when no view matches for a given request due
to predicates not working), the exception now contains a textual description of the predicate which
didn’t match.
• An add_permission directive method was added to the Configurator. This directive registers
a free-standing permission introspectable into the Pyramid introspection system. Frameworks built
atop Pyramid can thus use the permissions introspectable category data to build a comprehensive
list of permissions supported by a running system. Before this method was added, permissions were
already registered in this introspectable category as a side effect of naming them in an add_view
call, this method just makes it possible to arrange for a permission to be put into the permissions
introspectable category without naming it along with an associated view. Here’s an example of usage
of add_permission:

config = Configurator()
config.add_permission('view')

• The UnencryptedCookieSessionFactoryConfig now accepts signed_serialize


and signed_deserialize hooks which may be used to influence how the sessions are mar-
shalled (by default this is done with HMAC+pickle).
• pyramid.testing.DummyRequest now supports methods supplied by the pyramid.
util.InstancePropertyMixin class such as set_property.
• Request properties and methods added via config.set_request_property or config.
add_request_method are now available to tweens.
• Request properties and methods added via config.set_request_property or config.
add_request_method are now available in the request object returned from pyramid.
paster.bootstrap.
• request.context of environment request during bootstrap is now the root object if a context
isn’t already set on a provided request.
• The pyramid.decorator.reify function is now an API, and was added to the API documen-
tation.
• Added the pyramid.testing.testConfig context manager, which can be used to generate
a configurator in a test, e.g. with testing.testConfig(...):.
• Users can now invoke a subrequest from within view code using a new request.
invoke_subrequest API.

0.6. Change History 1037


The Pyramid Web Framework, Version 2.0.2

Deprecations

• The pyramid.config.Configurator.set_request_property has been


documentation-deprecated. The method remains usable but the more featureful pyramid.
config.Configurator.add_request_method should be used in its place (it has all of
the same capabilities but can also extend the request object with methods).

Backwards Incompatibilities

• The Pyramid router no longer adds the values bfg.routes.route or bfg.routes.


matchdict to the request’s WSGI environment dictionary. These values were docs-deprecated
in repoze.bfg 1.0 (effectively seven minor releases ago). If your code depended on these values,
use request.matched_route and request.matchdict instead.
• It is no longer possible to pass an environ dictionary directly to pyramid.traversal.
ResourceTreeTraverser.__call__ (aka ModelGraphTraverser.__call__). In-
stead, you must pass a request object. Passing an environment instead of a request has generated a
deprecation warning since Pyramid 1.1.
• Pyramid will no longer work properly if you use the webob.request.LegacyRequest as a
request factory. Instances of the LegacyRequest class have a request.path_info which re-
turn a string. This Pyramid release assumes that request.path_info will unconditionally be
Unicode.
• The functions from pyramid.chameleon_zpt and pyramid.chameleon_text
named get_renderer, get_template, render_template, and ren-
der_template_to_response have been removed. These have issued a deprecation warning
upon import since Pyramid 1.0. Use pyramid.renderers.get_renderer(), pyramid.
renderers.get_renderer().implementation(), pyramid.renderers.
render() or pyramid.renderers.render_to_response respectively instead of
these functions.
• The pyramid.configuration module was removed. It had been deprecated since Pyramid
1.0 and printed a deprecation warning upon its use. Use pyramid.config instead.
• The pyramid.paster.PyramidTemplate API was removed. It had been deprecated since
Pyramid 1.1 and issued a warning on import. If your code depended on this, adjust your code to
import pyramid.scaffolds.PyramidTemplate instead.
• The pyramid.settings.get_settings() API was removed. It had been printing a
deprecation warning since Pyramid 1.0. If your code depended on this API, use pyramid.
threadlocal.get_current_registry().settings instead or use the settings at-
tribute of the registry available from the request (request.registry.settings).

1038 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• These APIs from the pyramid.testing module were removed. They have been printing depre-
cation warnings since Pyramid 1.0:
– registerDummySecurityPolicy, use pyramid.config.Configurator.
testing_securitypolicy instead.
– registerResources (aka registerModels, use pyramid.config.
Configurator.testing_resources instead.
– registerEventListener, use pyramid.config.Configurator.
testing_add_subscriber instead.
– registerTemplateRenderer (aka registerDummyRenderer‘), use pyramid.
config.Configurator.testing_add_template instead.
– registerView, use pyramid.config.Configurator.add_view instead.
– registerUtility, use pyramid.config.Configurator.registry.
registerUtility instead.
– registerAdapter, use pyramid.config.Configurator.registry.
registerAdapter instead.
– registerSubscriber, use pyramid.config.Configurator.
add_subscriber instead.
– registerRoute, use pyramid.config.Configurator.add_route instead.
– registerSettings, use pyramid.config.Configurator.add_settings in-
stead.
• In Pyramid 1.3 and previous, the __call__ method of a Response object was invoked before
any finished callbacks were executed. As of this release, the __call__ method of a Response
object is invoked after finished callbacks are executed. This is in support of the request.
invoke_subrequest feature.
• The 200-series exception responses named HTTPCreated, HTTPAccepted, HTTPNonAu-
thoritativeInformation, HTTPNoContent, HTTPResetContent, and HTTPPar-
tialContent in pyramid.httpexceptions no longer inherit from HTTPOk. Instead they
inherit from a new base class named HTTPSuccessful. This will have no effect on you unless
you’ve registered an exception view for HTTPOk and expect that exception view to catch all the
aforementioned exceptions.

0.6. Change History 1039


The Pyramid Web Framework, Version 2.0.2

Documentation

• Added an ”Upgrading Pyramid” chapter to the narrative documentation. It describes how to cope
with deprecations and removals of Pyramid APIs and how to show Pyramid-generated deprecation
warnings while running tests and while running a server.
• Added a ”Invoking a Subrequest” chapter to the documentation. It describes how to use the new
request.invoke_subrequest API.

Dependencies

• Pyramid now requires WebOb 1.2b3+ (the prior Pyramid release only relied on 1.2dev+). This is to
ensure that we obtain a version of WebOb that returns request.path_info as text.

1.3 (2012-03-21)

Bug Fixes

• When pyramid.wsgi.wsgiapp2 calls the downstream WSGI app, the app’s environ will
no longer have (deprecated and potentially misleading) bfg.routes.matchdict or bfg.
routes.route keys in it. A symptom of this bug would be a wsgiapp2-wrapped Pyramid
app finding the wrong view because it mistakenly detects that a route was matched when, in fact, it
was not.
• The fix for issue https://github.com/Pylons/pyramid/issues/461 (which made it possible for instance
methods to be used as view callables) introduced a backwards incompatibility when methods that
declared only a request argument were used. See https://github.com/Pylons/pyramid/issues/503

1.3b3 (2012-03-17)

Bug Fixes

• config.add_view(<aninstancemethod>) raised AttributeError involving __text__.


See https://github.com/Pylons/pyramid/issues/461
• Remove references to do-nothing pyramid.debug_templates setting in all Pyramid-provided
.ini files. This setting previously told Chameleon to render better exceptions; now Chameleon
always renders nice exceptions regardless of the value of this setting.

1040 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Scaffolds

• The alchemy scaffold now shows an informative error message in the browser if the person creating
the project forgets to run the initialization script.
• The alchemy scaffold initialization script is now called initialize_<projectname>_db
instead of populate_<projectname>.

Documentation

• Wiki tutorials improved due to collaboration at PyCon US 2012 sprints.

1.3b2 (2012-03-02)

Bug Fixes

• The method pyramid.request.Request.partial_application_url is no longer in


the API docs. It was meant to be a private method; its publication in the documentation as an API
method was a mistake, and it has been renamed to something private.
• When a static view was registered using an absolute filesystem path on Windows, the request.
static_url function did not work to generate URLs to its resources. Symptom: ”No static URL
definition matching c:\foo\bar\baz”.
• Make all tests pass on Windows XP.
• Bug in ACL authentication checking on Python 3: the permits and princi-
pals_allowed_by_permission method of pyramid.authorization.
ACLAuthenticationPolicy could return an inappropriate True value when a permission
on an ACL was a string rather than a sequence, and then only if the ACL permission string was a
substring of the permission value passed to the function.
This bug effects no Pyramid deployment under Python 2; it is a bug that exists only in deployments
running on Python 3. It has existed since Pyramid 1.3a1.
This bug was due to the presence of an __iter__ attribute on strings under Python 3 which is not
present under strings in Python 2.

0.6. Change History 1041


The Pyramid Web Framework, Version 2.0.2

1.3b1 (2012-02-26)

Bug Fixes

• pyramid.config.Configurator.with_package didn’t work if the Configurator was an


old-style pyramid.configuration.Configurator instance.
• Pyramid authorization policies did not show up in the introspector.

Deprecations

• All references to the tmpl_context request variable were removed from the docs. Its existence in
Pyramid is confusing for people who were never Pylons users. It was added as a porting convenience
for Pylons users in Pyramid 1.0, but it never caught on because the Pyramid rendering system is a
lot different than Pylons’ was, and alternate ways exist to do what it was designed to offer in Pylons.
It will continue to exist ”forever” but it will not be recommended or mentioned in the docs.

1.3a9 (2012-02-22)

Features

• Add an introspection boolean to the Configurator constructor. If this is True, actions reg-
istered using the Configurator will be registered with the introspector. If it is False, they won’t.
The default is True. Setting it to False during action processing will prevent introspection for
any following registration statements, and setting it to True will start them up again. This addi-
tion is to service a requirement that the debug toolbar’s own views and methods not show up in the
introspector.
• New API: pyramid.config.Configurator.add_notfound_view. This is a wrapper
for pyramid.Config.configurator.add_view which provides easy append_slash sup-
port and does the right thing about permissions. It should be preferred over calling add_view
directly with context=HTTPNotFound as was previously recommended.
• New API: pyramid.view.notfound_view_config. This is a decorator construc-
tor like pyramid.view.view_config that calls pyramid.config.Configurator.
add_notfound_view when scanned. It should be preferred over using pyramid.view.
view_config with context=HTTPNotFound as was previously recommended.

1042 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• New API: pyramid.config.Configurator.add_forbidden_view. This is a wrapper


for pyramid.Config.configurator.add_view which does the right thing about permis-
sions. It should be preferred over calling add_view directly with context=HTTPForbidden
as was previously recommended.
• New API: pyramid.view.forbidden_view_config. This is a decorator construc-
tor like pyramid.view.view_config that calls pyramid.config.Configurator.
add_forbidden_view when scanned. It should be preferred over using pyramid.view.
view_config with context=HTTPForbidden as was previously recommended.
• New APIs: pyramid.response.FileResponse and pyramid.response.FileIter,
for usage in views that must serve files ”manually”.

Backwards Incompatibilities

• Remove pyramid.config.Configurator.with_context class method. It was never an


API, it is only used by pyramid_zcml and its functionality has been moved to that package’s
latest release. This means that you’ll need to use the 0.9.2 or later release of pyramid_zcml with
this release of Pyramid.
• The introspector argument to the pyramid.config.Configurator constructor API
has been removed. It has been replaced by the boolean introspection flag.
• The pyramid.registry.noop_introspector API object has been removed.
• The older deprecated set_notfound_view Configurator method is now an alias for
the new add_notfound_view Configurator method. Likewise, the older deprecated
set_forbidden_view is now an alias for the new add_forbidden_view. This has
the following impact: the context sent to views with a (context, request) call sig-
nature registered via the set_notfound_view or set_forbidden_view will now be
an exception object instead of the actual resource context found. Use request.context
to get the actual resource context. It’s also recommended to disuse set_notfound_view
in favor of add_notfound_view, and disuse set_forbidden_view in favor of
add_forbidden_view despite the aliasing.

Deprecations

• The API documentation for pyramid.view.append_slash_notfound_view and


pyramid.view.AppendSlashNotFoundViewFactory was removed. These names
still exist and are still importable, but they are no longer APIs. Use pyramid.config.
Configurator.add_notfound_view(append_slash=True) or pyramid.view.
notfound_view_config(append_slash=True) to get the same behavior.
• The set_forbidden_view and set_notfound_view methods of the Configurator were
removed from the documentation. They have been deprecated since Pyramid 1.1.

0.6. Change History 1043


The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• The static file response object used by config.add_static_view opened the static file twice,
when it only needed to open it once.
• The AppendSlashNotFoundViewFactory used request.path to match routes. This was wrong because
request.path contains the script name, and this would cause it to fail in circumstances where the script
name was not empty. It should have used request.path_info, and now does.

Documentation

• Updated the ”Creating a Not Found View” section of the ”Hooks” chapter, replacing explanations of
registering a view using add_view or view_config with ones using add_notfound_view
or notfound_view_config.
• Updated the ”Creating a Not Forbidden View” section of the ”Hooks” chapter, replacing
explanations of registering a view using add_view or view_config with ones using
add_forbidden_view or forbidden_view_config.
• Updated the ”Redirecting to Slash-Appended Routes” section of the ”URL Dispatch” chapter, re-
placing explanations of registering a view using add_view or view_config with ones using
add_notfound_view or notfound_view_config
• Updated all tutorials to use pyramid.view.forbidden_view_config rather than
pyramid.view.view_config with an HTTPForbidden context.

1.3a8 (2012-02-19)

Features

• The scan method of a Configurator can be passed an ignore argument, which can be a
string, a callable, or a list consisting of strings and/or callables. This feature allows submodules,
subpackages, and global objects from being scanned. See https://venusian.readthedocs.io/en/latest/
#ignore-scan-argument for more information about how to use the ignore argument to scan.
• Better error messages when a view callable returns a value that cannot be converted to a response
(for example, when a view callable returns a dictionary without a renderer defined, or doesn’t return
any value at all). The error message now contains information about the view callable itself as well
as the result of calling it.

1044 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Better error message when a .pyc-only module is config.include -ed. This is not permitted due
to error reporting requirements, and a better error message is shown when it is attempted. Previously
it would fail with something like ”AttributeError: ’NoneType’ object has no attribute ’rfind’”.
• Add pyramid.config.Configurator.add_traverser API method. See the Hooks nar-
rative documentation section entitled ”Changing the Traverser” for more information. This is not a
new feature, it just provides an API for adding a traverser without needing to use the ZCA API.
• Add pyramid.config.Configurator.add_resource_url_adapter API
method. See the Hooks narrative documentation section entitled ”Changing How pyra-
mid.request.Request.resource_url Generates a URL” for more information. This is not a new
feature, it just provides an API for adding a resource url adapter without needing to use the ZCA
API.
• The system value req is now supplied to renderers as an alias for request. This means that
you can now, for example, in a template, do req.route_url(...) instead of request.
route_url(...). This is purely a change to reduce the amount of typing required to use request
methods and attributes from within templates. The value request is still available too, this is just
an alternative.
• A new interface was added: pyramid.interfaces.IResourceURL. An adapter im-
plementing its interface can be used to override resource URL generation when request.
resource_url is called. This interface replaces the now-deprecated pyramid.
interfaces.IContextURL interface.
• The dictionary passed to a resource’s __resource_url__ method (see ”Overriding Re-
source URL Generation” in the ”Resources” chapter) now contains an app_url key, represent-
ing the application URL generated during request.resource_url. It represents a poten-
tially customized URL prefix, containing potentially custom scheme, host and port information
passed by the user to request.resource_url. It should be used instead of request.
application_url where necessary.
• The request.resource_url API now accepts these arguments: app_url, scheme, host,
and port. The app_url argument can be used to replace the URL prefix wholesale during url
generation. The scheme, host, and port arguments can be used to replace the respective default
values of request.application_url partially.
• A new API named request.resource_path now exists. It works like request.
resource_url but produces a relative URL rather than an absolute one.
• The request.route_url API now accepts these arguments: _app_url, _scheme, _host,
and _port. The _app_url argument can be used to replace the URL prefix wholesale during url
generation. The _scheme, _host, and _port arguments can be used to replace the respective
default values of request.application_url partially.

0.6. Change History 1045


The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• The pyramid.interfaces.IContextURL interface has been deprecated. People have been


instructed to use this to register a resource url adapter in the ”Hooks” chapter to use to influence
request.resource_url URL generation for resources found via custom traversers since Pyra-
mid 1.0.
The interface still exists and registering such an adapter still works, but this interface will be
removed from the software after a few major Pyramid releases. You should replace it with
an equivalent pyramid.interfaces.IResourceURL adapter, registered using the new
pyramid.config.Configurator.add_resource_url_adapter API. A deprecation
warning is now emitted when a pyramid.interfaces.IContextURL adapter is found when
request.resource_url is called.

Documentation

• Don’t create a session instance in SQLA Wiki tutorial, use raw DBSession instead (this is more
common in real SQLA apps).

Scaffolding

• Put pyramid.includes targets within ini files in scaffolds on separate lines in order to be able
to tell people to comment out only the pyramid_debugtoolbar line when they want to disable
the toolbar.

Dependencies

• Depend on venusian >= 1.0a3 to provide scan ignore support.

Internal

• Create a ”MakoRendererFactoryHelper” that provides customizable settings key prefixes. Allows


settings prefixes other than ”mako.” to be used to create different factories that don’t use the global
mako settings. This will be useful for the debug toolbar, which can currently be sabotaged by some-
one using custom mako configuration settings.

1046 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.3a7 (2012-02-07)

Features

• More informative error message when a config.include cannot find an includeme. See
https://github.com/Pylons/pyramid/pull/392.
• Internal: catch unhashable discriminators early (raise an error instead of allowing them to find their
way into resolveConflicts).
• The match_param view predicate now accepts a string or a tuple. This replaces the broken behavior
of accepting a dict. See https://github.com/Pylons/pyramid/issues/425 for more information.

Bug Fixes

• The process will now restart when pserve is used with the --reload flag when the
development.ini file (or any other .ini file in use) is changed. See https://github.com/Pylons/
pyramid/issues/377 and https://github.com/Pylons/pyramid/pull/411
• The prequest script would fail when used against URLs which did not return HTML or text. See
https://github.com/Pylons/pyramid/issues/381

Backwards Incompatibilities

• The match_param view predicate no longer accepts a dict. This will have no negative affect because
the implementation was broken for dict-based arguments.

Documentation

• Add a traversal hello world example to the narrative docs.

0.6. Change History 1047


The Pyramid Web Framework, Version 2.0.2

1.3a6 (2012-01-20)

Features

• New API: pyramid.config.Configurator.set_request_property. Add lazy prop-


erty descriptors to a request without changing the request factory. This method provides conflict
detection and is the suggested way to add properties to a request.
• Responses generated by Pyramid’s static_view now use a wsgi.file_wrapper (see https:
//www.python.org/dev/peps/pep-0333/#optional-platform-specific-file-handling) when one is pro-
vided by the web server.

Bug Fixes

• Views registered with an accept could not be overridden correctly with a different view that had the
same predicate arguments. See https://github.com/Pylons/pyramid/pull/404 for more information.
• When using a dotted name for a view argument to Configurator.add_view that pointed
to a class with a view_defaults decorator, the view defaults would not be applied. See https:
//github.com/Pylons/pyramid/issues/396 .
• Static URL paths were URL-quoted twice. See https://github.com/Pylons/pyramid/issues/407 .

1.3a5 (2012-01-09)

Bug Fixes

• The pyramid.view.view_defaults decorator did not work properly when more than one
view relied on the defaults being different for configuration conflict resolution. See https://github.
com/Pylons/pyramid/issues/394.

Backwards Incompatibilities

• The path_info route and view predicates now match against request.upath_info (Uni-
code) rather than request.path_info (indeterminate value based on Python 3 vs. Python 2).
This has to be done to normalize matching on Python 2 and Python 3.

1048 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.3a4 (2012-01-05)

Features

• New API: pyramid.request.Request.set_property. Add lazy property descriptors to


a request without changing the request factory. New properties may be reified, effectively caching
the value for the lifetime of the instance. Common use-cases for this would be to get a database
connection for the request or identify the current user.
• Use the waitress WSGI server instead of wsgiref in scaffolding.

Bug Fixes

• The documentation of pyramid.events.subscriber indicated that using it as a decorator


with no arguments like this:

@subscriber()
def somefunc(event):
pass

Would register somefunc to receive all events sent via the registry, but this was untrue. Instead,
it would receive no events at all. This has now been fixed and the code matches the documentation.
See also https://github.com/Pylons/pyramid/issues/386
• Literal portions of route patterns were not URL-quoted when route_url or route_path was
used to generate a URL or path.
• The result of route_path or route_url might have been unicode or str depending on the
input. It is now guaranteed to always be str.
• URL matching when the pattern contained non-ASCII characters in literal parts was indeterminate.
Now the pattern supplied to add_route is assumed to be either: a unicode value, or a str
value that contains only ASCII characters. If you now want to match the path info from a URL that
contains high order characters, you can pass the Unicode representation of the decoded path portion
in the pattern.
• When using a traverse= route predicate, traversal would fail with a URLDecodeError if there
were any high-order characters in the traversal pattern or in the matched dynamic segments.
• Using a dynamic segment named traverse in a route pattern like this:

0.6. Change History 1049


The Pyramid Web Framework, Version 2.0.2

config.add_route('trav_route', 'traversal/{traverse:.*}')

Would cause a UnicodeDecodeError when the route was matched and the matched portion of
the URL contained any high-order characters. See https://github.com/Pylons/pyramid/issues/385 .
• When using a *traverse stararg in a route pattern, a URL that matched that possessed a @@ in its
name (signifying a view name) would be inappropriately quoted by the traversal machinery during
traversal, resulting in the view not being found properly. See https://github.com/Pylons/pyramid/
issues/382 and https://github.com/Pylons/pyramid/issues/375 .

Backwards Incompatibilities

• String values passed to route_url or route_path that are meant to replace ”remainder”
matches will now be URL-quoted except for embedded slashes. For example:

config.add_route('remain', '/foo*remainder')
request.route_path('remain', remainder='abc / def')
# -> '/foo/abc%20/%20def'

Previously string values passed as remainder replacements were tacked on untouched, without any
URL-quoting. But this doesn’t really work logically if the value passed is Unicode (raw unicode
cannot be placed in a URL or in a path) and it is inconsistent with the rest of the URL generation
machinery if the value is a string (it won’t be quoted unless by the caller).
Some folks will have been relying on the older behavior to tack on query string elements and anchor
portions of the URL; sorry, you’ll need to change your code to use the _query and/or _anchor
arguments to route_path or route_url to do this now.
• If you pass a bytestring that contains non-ASCII characters to add_route as a pattern, it will now
fail at startup time. Use Unicode instead.

1.3a3 (2011-12-21)

Features

• Added a prequest script (along the lines of paster request). It is documented in the
”Command-Line Pyramid” chapter in the section entitled ”Invoking a Request”.
• Add undocumented __discriminator__ API to derived view callables. e.g. adapters.
lookup(...).__discriminator__(context, request). It will be used by superdy-
namic systems that require the discriminator to be used for introspection after manual view lookup.

1050 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• Normalized exit values and -h output for all p* scripts (pviews, proutes, etc).

Documentation

• Added a section named ”Making Your Script into a Console Script” in the ”Command-Line Pyra-
mid” chapter.
• Removed the ”Running Pyramid on Google App Engine” tutorial from the main docs. It survives on
in the Cookbook (https://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/deployment/
gae.html). Rationale: it provides the correct info for the Python 2.5 version of GAE only, and this
version of Pyramid does not support Python 2.5.

1.3a2 (2011-12-14)

Features

• New API: pyramid.view.view_defaults. If you use a class as a view, you can use the
new view_defaults class decorator on the class to provide defaults to the view configuration
information used by every @view_config decorator that decorates a method of that class. It also
works against view configurations involving a class made imperatively.
• Added a backwards compatibility knob to pcreate to emulate paster create handling for
the --list-templates option.
• Changed scaffolding machinery around a bit to make it easier for people who want to have exten-
sion scaffolds that can work across Pyramid 1.0.X, 1.1.X, 1.2.X and 1.3.X. See the new ”Creating
Pyramid Scaffolds” chapter in the narrative documentation for more info.

Documentation

• Added documentation to ”View Configuration” narrative documentation chapter about


view_defaults class decorator.
• Added API docs for view_defaults class decorator.
• Added an API docs chapter for pyramid.scaffolds.
• Added a narrative docs chapter named ”Creating Pyramid Scaffolds”.

0.6. Change History 1051


The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• The template_renderer method of pyramid.scaffolds.PyramidScaffold was re-


named to render_template. If you were overriding it, you’re a bad person, because it wasn’t
an API before now. But we’re nice so we’re letting you know.

1.3a1 (2011-12-09)

Features

• Python 3.2 compatibility.


• New pyramid.compat module and API documentation which provides Python 2/3 straddling
support for Pyramid add-ons and development environments.
• A mako.directories setting is no longer required to use Mako templates Rationale: Mako
template renderers can be specified using an absolute asset spec. An entire application can be written
with such asset specs, requiring no ordered lookup path.
• bpython interpreter compatibility in pshell. See the ”Command-Line Pyramid” narrative docs
chapter for more information.
• Added get_appsettings API function to the pyramid.paster module. This function re-
turns the settings defined within an [app:...] section in a PasteDeploy ini file.
• Added setup_logging API function to the pyramid.paster module. This function sets up
Python logging according to the logging configuration in a PasteDeploy ini file.
• Configuration conflict reporting is reported in a more understandable way (”Line 11 in file...” vs. a
repr of a tuple of similar info).
• A configuration introspection system was added; see the narrative documentation chapter entitled
”Pyramid Configuration Introspection” for more information. New APIs: pyramid.registry.
Introspectable, pyramid.config.Configurator.introspector, pyramid.
config.Configurator.introspectable, pyramid.registry.Registry.
introspector.
• Allow extra keyword arguments to be passed to the pyramid.config.Configurator.
action method.
• New APIs: pyramid.path.AssetResolver and pyramid.path.
DottedNameResolver. The former can be used to resolve asset specifications, the latter
can be used to resolve dotted names to modules or packages.

1052 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• Make test suite pass on 32-bit systems; closes #286. closes #306. See also https://github.com/
Pylons/pyramid/issues/286
• The pyramid.view.view_config decorator did not accept a match_params predicate ar-
gument. See https://github.com/Pylons/pyramid/pull/308
• The AuthTktCookieHelper could potentially generate Unicode headers inappropriately when the
tokens argument to remember was used. See https://github.com/Pylons/pyramid/pull/314.
• The AuthTktAuthenticationPolicy did not use a timing-attack-aware string comparator. See https:
//github.com/Pylons/pyramid/pull/320 for more info.
• The DummySession in pyramid.testing now generates a new CSRF token if one doesn’t yet
exist.
• request.static_url now generates URL-quoted URLs when fed a path argument which
contains characters that are unsuitable for URLs. See https://github.com/Pylons/pyramid/issues/349
for more info.
• Prevent a scaffold rendering from being named site (conflicts with Python internal site.py).
• Support for using instances as targets of the pyramid.wsgi.wsgiapp and pryramid.wsgi.
wsgiapp2 functions. See https://github.com/Pylons/pyramid/pull/370 for more info.

Backwards Incompatibilities

• Pyramid no longer runs on Python 2.5 (which includes the most recent release of Jython and the
Python 2.5 version of GAE as of this writing).
• The paster command is no longer the documented way to create projects, start the server, or run
debugging commands. To create projects from scaffolds, paster create is replaced by the
pcreate console script. To serve up a project, paster serve is replaced by the pserve
console script. New console scripts named pshell, pviews, proutes, and ptweens do what
their paster <commandname> equivalents used to do. Rationale: the Paste and PasteScript
packages do not run under Python 3.
• The default WSGI server run as the result of pserve from newly rendered scaffolding is now the
wsgiref WSGI server instead of the paste.httpserver server. Rationale: Rationale: the
Paste and PasteScript packages do not run under Python 3.
• The pshell command (see ”paster pshell”) no longer accepts a --disable-ipython
command-line argument. Instead, it accepts a -p or --python-shell argument, which can
be any of the values python, ipython or bpython.

0.6. Change History 1053


The Pyramid Web Framework, Version 2.0.2

• Removed the pyramid.renderers.renderer_from_name function. It has been depre-


cated since Pyramid 1.0, and was never an API.
• To use ZCML with versions of Pyramid >= 1.3, you will need pyramid_zcml version >= 0.8
and zope.configuration version >= 3.8.0. The pyramid_zcml package version 0.8 is
backwards compatible all the way to Pyramid 1.0, so you won’t be warned if you have older versions
installed and upgrade Pyramid ”in-place”; it may simply break instead.

Dependencies

• Pyramid no longer depends on the zope.component package, except as a testing dependency.


• Pyramid now depends on a zope.interface>=3.8.0, WebOb>=1.2dev, repoze.lru>=0.4,
zope.deprecation>=3.5.0, translationstring>=0.4 (for Python 3 compatibility purposes). It
also, as a testing dependency, depends on WebTest>=1.3.1 for the same reason.
• Pyramid no longer depends on the Paste or PasteScript packages.

Documentation

• The SQLAlchemy Wiki tutorial has been updated. It now uses @view_config decorators and an
explicit database population script.
• Minor updates to the ZODB Wiki tutorial.
• A narrative documentation chapter named ”Extending Pyramid Configuration” was added; it de-
scribes how to add a new directive, and how use the pyramid.config.Configurator.
action method within custom directives. It also describes how to add introspectable objects.
• A narrative documentation chapter named ”Pyramid Configuration Introspection” was added. It
describes how to query the introspection system.

Scaffolds

• Rendered scaffolds have now been changed to be more relocatable (fewer mentions of the package
name within files in the package).
• The routesalchemy scaffold has been renamed alchemy, replacing the older (traversal-based)
alchemy scaffold (which has been retired).
• The starter scaffold now uses URL dispatch by default.

1054 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.2 (2011-09-12)

Features

• Route pattern replacement marker names can now begin with an underscore. See https://github.com/
Pylons/pyramid/issues/276.

1.2b3 (2011-09-11)

Bug Fixes

• The route prefix was not taken into account when a static view was added in an ”include”. See
https://github.com/Pylons/pyramid/issues/266 .

1.2b2 (2011-09-08)

Bug Fixes

• The 1.2b1 tarball was a brownbag (particularly for Windows users) because it contained filenames
with stray quotation marks in inappropriate places. We depend on setuptools-git to produce
release tarballs, and when it was run to produce the 1.2b1 tarball, it didn’t yet cope well with files
present in git repositories with high-order characters in their filenames.

Documentation

• Minor tweaks to the ”Introduction” narrative chapter example app and wording.

0.6. Change History 1055


The Pyramid Web Framework, Version 2.0.2

1.2b1 (2011-09-08)

Bug Fixes

• Sometimes falling back from territory translations (de_DE) to language translations (de) would not
work properly when using a localizer. See https://github.com/Pylons/pyramid/issues/263
• The static file serving machinery could not serve files that started with a . (dot) character.
• Static files with high-order (super-ASCII) characters in their names could not be served by a static
view. The static file serving machinery inappropriately URL-quoted path segments in filenames
when asking for files from the filesystem.
• Within pyramid.traversal.traversal_path , canonicalize URL segments from UTF-8
to Unicode before checking whether a segment matches literally one of ., the empty string, or ..
in case there’s some sneaky way someone might tunnel those strings via UTF-8 that don’t match the
literals before decoded.

Documentation

• Added a ”What Makes Pyramid Unique” section to the Introduction narrative chapter.

1.2a6 (2011-09-06)

Bug Fixes

• AuthTktAuthenticationPolicy with a reissue_time interfered with logout. See https://github.


com/Pylons/pyramid/issues/262.

Internal

• Internalize code previously depended upon as imports from the paste.auth module (future-
proof).
• Replaced use of paste.urlparser.StaticURLParser with a derivative of Chris Rossi’s
”happy” static file serving code (futureproof).
• Fixed test suite; on some systems tests would fail due to indeterminate test run ordering and a double-
push-single-pop of a shared test variable.

1056 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Behavior Differences

• An ETag header is no longer set when serving a static file. A Last-Modified header is set instead.
• Static file serving no longer supports the wsgi.file_wrapper extension.
• Instead of returning a 403 Forbidden error when a static file is served that cannot be accessed
by the Pyramid process’ user due to file permissions, an IOError (or similar) will be raised.

Scaffolds

• All scaffolds now send the cache_max_age parameter to the add_static_view method.

1.2a5 (2011-09-04)

Bug Fixes

• The route_prefix of a configurator was not properly taken into account when registering routes
in certain circumstances. See https://github.com/Pylons/pyramid/issues/260

Dependencies

• The zope.configuration package is no longer a dependency.

1.2a4 (2011-09-02)

Features

• Support an onerror keyword argument to pyramid.config.Configurator.scan().


This onerror keyword argument is passed to venusian.Scanner.scan() to influence error
behavior when an exception is raised during scanning.

0.6. Change History 1057


The Pyramid Web Framework, Version 2.0.2

• The request_method predicate argument to pyramid.config.Configurator.


add_view and pyramid.config.Configurator.add_route is now permitted to be a
tuple of HTTP method names. Previously it was restricted to being a string representing a single
HTTP method name.
• Undeprecated pyramid.traversal.find_model, pyramid.traversal.
model_path, pyramid.traversal.model_path_tuple, and pyramid.url.
model_url, which were all deprecated in Pyramid 1.0. There’s just not much cost to keeping
them around forever as aliases to their renamed resource_* prefixed functions.
• Undeprecated pyramid.view.bfg_view, which was deprecated in Pyramid 1.0. This is a low-
cost alias to pyramid.view.view_config which we’ll just keep around forever.

Dependencies

• Pyramid now requires Venusian 1.0a1 or better to support the onerror keyword argument to
pyramid.config.Configurator.scan.

1.2a3 (2011-08-29)

Bug Fixes

• Pyramid did not properly generate static URLs using pyramid.url.static_url when passed
a caller-package relative path due to a refactoring done in 1.2a1.
• The settings object emitted a deprecation warning any time __getattr__ was called upon
it. However, there are legitimate situations in which __getattr__ is called on arbitrary objects
(e.g. hasattr). Now, the settings object only emits the warning upon successful lookup.

Internal

• Use config.with_package in view_config decorator rather than manufacturing a new renderer


helper (cleanup).

1058 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.2a2 (2011-08-27)

Bug Fixes

• When a renderers= argument is not specified to the Configurator constructor, eagerly register
and commit the default renderer set. This permits the overriding of the default renderers, which was
broken in 1.2a1 without a commit directly after Configurator construction.
• Mako rendering exceptions had the wrong value for an error message.
• An include could not set a root factory successfully because the Configurator constructor uncondi-
tionally registered one that would be treated as if it were ”the word of the user”.

Features

• A session factory can now be passed in using the dotted name syntax.

1.2a1 (2011-08-24)

Features

• The [pshell] section in an ini configuration file now treats a setup key as a dotted name that
points to a callable that is passed the bootstrap environment. It can mutate the environment as
necessary for great justice.
• A new configuration setting named pyramid.includes is now available. It is described in the
”Environment Variables and .ini Files Settings” narrative documentation chapter.
• Added a route_prefix argument to the pyramid.config.Configurator.include
method. This argument allows you to compose URL dispatch applications together. See the section
entitled ”Using a Route Prefix to Compose Applications” in the ”URL Dispatch” narrative docu-
mentation chapter.
• Added a pyramid.security.NO_PERMISSION_REQUIRED constant for use in per-
mission= statements to view configuration. This constant has a value of the string
__no_permission_required__. This string value was previously referred to in documenta-
tion; now the documentation uses the constant.
• Added a decorator-based way to configure a response adapter: pyramid.response.
response_adapter. This decorator has the same use as pyramid.config.
Configurator.add_response_adapter but it’s declarative.

0.6. Change History 1059


The Pyramid Web Framework, Version 2.0.2

• The pyramid.events.BeforeRender event now has an attribute named rendering_val.


This can be used to introspect the value returned by a view in a BeforeRender subscriber.
• New configurator directive: pyramid.config.Configurator.add_tween. This directive
adds a ”tween”. A ”tween” is used to wrap the Pyramid router’s primary request handling function.
This is a feature may be used by Pyramid framework extensions, to provide, for example, view timing
support and as a convenient place to hang bookkeeping code.
Tweens are further described in the narrative docs section in the Hooks chapter, named ”Registering
Tweens”.
• New paster command paster ptweens, which prints the current ”tween” configuration for an
application. See the section entitled ”Displaying Tweens” in the Command-Line Pyramid chapter
of the narrative documentation for more info.
• The Pyramid debug logger now uses the standard logging configuration (usually set up by
Paste as part of startup). This means that output from e.g. debug_notfound, de-
bug_authorization, etc. will go to the normal logging channels. The logger name of the
debug logger will be the package name of the caller of the Configurator’s constructor.
• A new attribute is available on request objects: exc_info. Its value will be None until an excep-
tion is caught by the Pyramid router, after which it will be the result of sys.exc_info().
• pyramid.testing.DummyRequest now implements the add_finished_callback and
add_response_callback methods.
• New methods of the pyramid.config.Configurator class:
set_authentication_policy and set_authorization_policy. These are
meant to be consumed mostly by add-on authors.
• New Configurator method: set_root_factory.
• Pyramid no longer eagerly commits some default configuration statements at Configurator con-
struction time, which permits values passed in as constructor arguments (e.g. authentica-
tion_policy and authorization_policy) to override the same settings obtained via an
”include”.
• Better Mako rendering exceptions via pyramid.mako_templating.
MakoRenderingException
• New request methods: current_route_url, current_route_path, and static_path.
• New functions in pyramid.url: current_route_path and static_path.
• The pyramid.request.Request.static_url API (and its brethren pyramid.
request.Request.static_path, pyramid.url.static_url, and pyramid.url.
static_path) now accept an asbolute filename as a ”path” argument. This will generate a URL
to an asset as long as the filename is in a directory which was previously registered as a static
view. Previously, trying to generate a URL to an asset using an absolute file path would raise a
ValueError.

1060 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The RemoteUserAuthenticationPolicy ``, ``AuthTktAuthenticationPol-


icy, and SessionAuthenticationPolicy constructors now accept an additional keyword
argument named debug. By default, this keyword argument is False. When it is True, debug
information will be sent to the Pyramid debug logger (usually on stderr) when the authenti-
cated_userid or effective_principals method is called on any of these policies. The
output produced can be useful when trying to diagnose authentication-related problems.
• New view predicate: match_param. Example: a view added via config.add_view(aview,
match_param='action=edit') will be called only when the request.matchdict has
a value inside it named action with a value of edit.

Internal

• The Pyramid ”exception view” machinery is now implemented as a ”tween” (pyramid.tweens.


excview_tween_factory).
• WSGIHTTPException (HTTPFound, HTTPNotFound, etc) now has a new API named ”prepare”
which renders the body and content type when it is provided with a WSGI environ. Required for
debug toolbar.
• Once __call__ or prepare is called on a WSGIHTTPException, the body will be set, and sub-
sequent calls to __call__ will always return the same body. Delete the body attribute to rerender
the exception body.
• Previously the pyramid.events.BeforeRender event wrapped a dictionary (it addressed it
as its _system attribute). Now it is a dictionary (it inherits from dict), and it’s the value that is
passed to templates as a top-level dictionary.
• The route_url, route_path, resource_url, static_url, and cur-
rent_route_url functions in the pyramid.url package now delegate to a method on
the request they’ve been passed, instead of the other way around. The pyramid.request.Request
object now inherits from a mixin named pyramid.url.URLMethodsMixin to make this possible, and
all url/path generation logic is embedded in this mixin.
• Refactor pyramid.config into a package.
• Removed the _set_security_policies method of the Configurator.
• Moved the StaticURLInfo class from pyramid.static to pyramid.config.views.
• Move the Settings class from pyramid.settings to pyramid.config.settings.
• Move the OverrideProvider, PackageOverrides, DirectoryOverride, and
FileOverride classes from pyramid.asset to pyramid.config.assets.

0.6. Change History 1061


The Pyramid Web Framework, Version 2.0.2

Deprecations

• All Pyramid-related deployment settings (e.g. debug_all, debug_notfound) are now meant
to be prefixed with the prefix pyramid.. For example: debug_all -> pyramid.debug_all.
The old non-prefixed settings will continue to work indefinitely but supplying them may eventually
print a deprecation warning. All scaffolds and tutorials have been changed to use prefixed settings.
• The settings dictionary now raises a deprecation warning when you attempt to access its values
via __getattr__ instead of via __getitem__.

Backwards Incompatibilities

• If a string is passed as the debug_logger parameter to a Configurator, that string is considered


to be the name of a global Python logger rather than a dotted name to an instance of a logger.
• The pyramid.config.Configurator.include method now accepts only a single
callable argument (a sequence of callables used to be permitted). If you are passing more than
one callable to pyramid.config.Configurator.include, it will break. You now
must now instead make a separate call to the method for each callable. This change was introduced
to support the route_prefix feature of include.
• It may be necessary to more strictly order configuration route and view statements when using an
”autocommitting” Configurator. In the past, it was possible to add a view which named a route name
before adding a route with that name when you used an autocommitting configurator. For example:

config = Configurator(autocommit=True)
config.add_view('my.pkg.someview', route_name='foo')
config.add_route('foo', '/foo')

The above will raise an exception when the view attempts to add itself. Now you must add the route
before adding the view:

config = Configurator(autocommit=True)
config.add_route('foo', '/foo')
config.add_view('my.pkg.someview', route_name='foo')

This won’t effect ”normal” users, only people who have legacy BFG codebases that used an auto-
committing configurator and possibly tests that use the configurator API (the configurator returned
by pyramid.testing.setUp is an autocommitting configurator). The right way to get around
this is to use a non-autocommitting configurator (the default), which does not have these directive
ordering requirements.
• The pyramid.config.Configurator.add_route directive no longer returns a route ob-
ject. This change was required to make route vs. view configuration processing work properly.

1062 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• Narrative and API documentation which used the route_url, route_path, resource_url,
static_url, and current_route_url functions in the pyramid.url package have now
been changed to use eponymous methods of the request instead.
• Added a section entitled ”Using a Route Prefix to Compose Applications” to the ”URL Dispatch”
narrative documentation chapter.
• Added a new module to the API docs: pyramid.tweens.
• Added a ”Registering Tweens” section to the ”Hooks” narrative chapter.
• Added a ”Displaying Tweens” section to the ”Command-Line Pyramid” narrative chapter.
• Added documentation for the pyramid.tweens and pyramid.includes configuration set-
tings to the ”Environment Variables and .ini Files Settings” chapter.
• Added a Logging chapter to the narrative docs (based on the Pylons logging docs, thanks Phil).
• Added a Paste chapter to the narrative docs (moved content from the Project chapter).
• Added the pyramid.interfaces.IDict interface representing the methods of a dictionary,
for documentation purposes only (IMultiDict and IBeforeRender inherit from it).
• All tutorials now use - The route_url, route_path, resource_url, static_url, and
current_route_url methods of the request rather than the function variants imported from
pyramid.url.
• The ZODB wiki tutorial now uses the pyramid_zodbconn package rather than the repoze.
zodbconn package to provide ZODB integration.

Dependency Changes

• Pyramid now relies on PasteScript >= 1.7.4. This version contains a feature important for allowing
flexible logging configuration.

Scaffolds

• All scaffolds now use the pyramid_tm package rather than the repoze.tm2 middleware to
manage transaction management.
• The ZODB scaffold now uses the pyramid_zodbconn package rather than the repoze.
zodbconn package to provide ZODB integration.

0.6. Change History 1063


The Pyramid Web Framework, Version 2.0.2

• All scaffolds now use the pyramid_debugtoolbar package rather than the WebError pack-
age to provide interactive debugging features.
• Projects created via a scaffold no longer depend on the WebError package at all; configuration
in the production.ini file which used to require its error_catcher middleware has been
removed. Configuring error catching / email sending is now the domain of the pyramid_exclog
package (see https://docs.pylonsproject.org/projects/pyramid_exclog/en/latest/).

Bug Fixes

• Fixed an issue with the default renderer not working at certain times. See https://github.com/Pylons/
pyramid/issues/249

1.1 (2011-07-22)

Features

• Added the pyramid.renderers.null_renderer object as an API. The null renderer is an


object that can be used in advanced integration cases as input to the view configuration renderer=
argument. When the null renderer is used as a view renderer argument, Pyramid avoids converting
the view callable result into a Response object. This is useful if you want to reuse the view configu-
ration and lookup machinery outside the context of its use by the Pyramid router. This feature was
added for consumption by the pyramid_rpc package, which uses view configuration and lookup
outside the context of a router in exactly this way. pyramid_rpc has been broken under 1.1 since
1.1b1; adding it allows us to make it work again.
• Change all scaffolding templates that point to docs.pylonsproject.org to use /projects/
pyramid/current rather than /projects/pyramid/dev.

Internals

• Remove compat code that served only the purpose of providing backwards compatibility with
Python 2.4.
• Add a deprecation warning for non-API function pyramid.renderers.
renderer_from_name which has seen use in the wild.
• Add a clone method to pyramid.renderers.RendererHelper for use by the pyramid.
view.view_config decorator.

1064 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• Fixed two typos in wiki2 (SQLA + URL Dispatch) tutorial.


• Reordered chapters in narrative section for better new user friendliness.
• Added more indexing markers to sections in documentation.

1.1b4 (2011-07-18)

Documentation

• Added a section entitled ”Writing a Script” to the ”Command-Line Pyramid” chapter.

Backwards Incompatibilities

• We added the pyramid.scripting.make_request API too hastily in 1.1b3. It has been


removed. Sorry for any inconvenience. Use the pyramid.request.Request.blank API
instead.

Features

• The paster pshell, paster pviews, and paster proutes commands each now under
the hood uses pyramid.paster.bootstrap, which makes it possible to supply an .ini file
without naming the ”right” section in the file that points at the actual Pyramid application. Instead,
you can generally just run paster {pshell|proutes|pviews} development.ini and
it will do mostly the right thing.

Bug Fixes

• Omit custom environ variables when rendering a custom exception template in pyramid.
httpexceptions.WSGIHTTPException._set_default_attrs; stringifying thse may
trigger code that should not be executed; see https://github.com/Pylons/pyramid/issues/239

0.6. Change History 1065


The Pyramid Web Framework, Version 2.0.2

1.1b3 (2011-07-15)

Features

• Fix corner case to ease semifunctional testing of views: create a new rendererinfo to clear out old
registry on a rescan. See https://github.com/Pylons/pyramid/pull/234.
• New API class: pyramid.static.static_view. This supersedes the deprecated
pyramid.view.static class. pyramid.static.static_view by default serves up
documents as the result of the request’s path_info, attribute rather than it’s subpath at-
tribute (the inverse was true of pyramid.view.static, and still is). pyramid.static.
static_view exposes a use_subpath flag for use when you want the static view to behave
like the older deprecated version.
• A new API function pyramid.paster.bootstrap has been added to make writing scripts
that bootstrap a Pyramid environment easier, e.g.:

from pyramid.paster import bootstrap


info = bootstrap('/path/to/my/development.ini')
request = info['request']
print request.route_url('myroute')

• A new API function pyramid.scripting.prepare has been added. It is a lower-level ana-


logue of pyramid.paster.boostrap that accepts a request and a registry instead of a config
file argument, and is used for the same purpose:

from pyramid.scripting import prepare


info = prepare(registry=myregistry)
request = info['request']
print request.route_url('myroute')

• A new API function pyramid.scripting.make_request has been added. The resulting


request will have a registry attribute. It is meant to be used in conjunction with pyramid.
scripting.prepare and/or pyramid.paster.bootstrap (both of which accept a re-
quest as an argument):

from pyramid.scripting import make_request


request = make_request('/')

• New API attribute pyramid.config.global_registries is an iterable object that con-


tains references to every Pyramid registry loaded into the current process via pyramid.config.
Configurator.make_app. It also has a last attribute containing the last registry loaded.
This is used by the scripting machinery, and is available for introspection.

1066 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Deprecations

• The pyramid.view.static class has been deprecated in favor of the newer pyramid.
static.static_view class. A deprecation warning is raised when it is used. You should re-
place it with a reference to pyramid.static.static_view with the use_subpath=True
argument.

Bug Fixes

• Without a mo-file loaded for the combination of domain/locale, pyramid.i18n.Localizer.


pluralize run using that domain/locale combination raised an inscrutable ”translations object
has no attr ’plural’” error. Now, instead it ”works” (it uses a germanic pluralization by default).
It’s nonsensical to try to pluralize something without translations for that locale/domain available,
but this behavior matches the behavior of pyramid.i18n.Localizer.translate so it’s at
least consistent; see https://github.com/Pylons/pyramid/issues/235.

1.1b2 (2011-07-13)

Features

• New environment setting PYRAMID_PREVENT_HTTP_CACHE and new configuration file value


prevent_http_cache. These are synomymous and allow you to prevent HTTP cache headers
from being set by Pyramid’s http_cache machinery globally in a process. see the ”Influencing
HTTP Caching” section of the ”View Configuration” narrative chapter and the detailed documen-
tation for this setting in the ”Environment Variables and Configuration Settings” narrative chapter.

Behavior Changes

• Previously, If a BeforeRender event subscriber added a value via the __setitem__ or up-
date methods of the event object with a key that already existed in the renderer globals dictionary,
a KeyError was raised. With the deprecation of the ”add_renderer_globals” feature of the config-
urator, there was no way to override an existing value in the renderer globals dictionary that already
existed. Now, the event object will overwrite an older value that is already in the globals dictio-
nary when its __setitem__ or update is called (as well as the new setdefault method),
just like a plain old dictionary. As a result, for maximum interoperability with other third-party
subscribers, if you write an event subscriber meant to be used as a BeforeRender subscriber, your
subscriber code will now need to (using .get or __contains__ of the event object) ensure no
value already exists in the renderer globals dictionary before setting an overriding value.

0.6. Change History 1067


The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• The Configurator.add_route method allowed two routes with the same route to be added
without an intermediate config.commit(). If you now receive a ConfigurationError at
startup time that appears to be add_route related, you’ll need to either a) ensure that all of your
route names are unique or b) call config.commit() before adding a second route with the name
of a previously added name or c) use a Configurator that works in autocommit mode.
• The pyramid_routesalchemy and pyramid_alchemy scaffolds inappropriately used
DBSession.rollback() instead of transaction.abort() in one place.
• We now clear request.response before we invoke an exception view; an exception view will
be working with a request.response that has not been touched by any code prior to the exception.
• Views associated with routes with spaces in the route name may not have been looked up correctly
when using Pyramid with zope.interface 3.6.4 and better. See https://github.com/Pylons/
pyramid/issues/232.

Documentation

• Wiki2 (SQLAlchemy + URL Dispatch) tutorial models.initialize_sql didn’t match the


pyramid_routesalchemy scaffold function of the same name; it didn’t get synchronized when
it was changed in the scaffold.
• New documentation section in View Configuration narrative chapter: ”Influencing HTTP Caching”.

1.1b1 (2011-07-10)

Features

• It is now possible to invoke paster pshell even if the paste ini file section name pointed to in
its argument is not actually a Pyramid WSGI application. The shell will work in a degraded mode,
and will warn the user. See ”The Interactive Shell” in the ”Creating a Pyramid Project” narrative
documentation section.
• paster pshell now offers more built-in global variables by default (including app and set-
tings). See ”The Interactive Shell” in the ”Creating a Pyramid Project” narrative documentation
section.
• It is now possible to add a [pshell] section to your application’s .ini configuration file, which
influences the global names available to a pshell session. See ”Extending the Shell” in the ”Creating
a Pyramid Project” narrative documentation chapter.

1068 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The config.scan method has grown a **kw argument. kw argument represents a set of key-
word arguments to pass to the Venusian Scanner object created by Pyramid. (See the Venusian
documentation for more information about Scanner).
• New request property: json_body. This property will return the JSON-decoded variant of the
request body. If the request body is not well-formed JSON, this property will raise an exception.
• A new value http_cache can be used as a view configuration parameter.
When you supply an http_cache value to a view configuration, the Expires and
Cache-Control headers of a response generated by the associated view callable are modified.
The value for http_cache may be one of the following:
– A nonzero integer. If it’s a nonzero integer, it’s treated as a number of seconds. This num-
ber of seconds will be used to compute the Expires header and the Cache-Control:
max-age parameter of responses to requests which call this view. For example:
http_cache=3600 instructs the requesting browser to ’cache this response for an hour,
please’.
– A datetime.timedelta instance. If it’s a datetime.timedelta instance, it will
be converted into a number of seconds, and that number of seconds will be used to com-
pute the Expires header and the Cache-Control: max-age parameter of re-
sponses to requests which call this view. For example: http_cache=datetime.
timedelta(days=1) instructs the requesting browser to ’cache this response for a day,
please’.
– Zero (0). If the value is zero, the Cache-Control and Expires headers present in all re-
sponses from this view will be composed such that client browser cache (and any intermediate
caches) are instructed to never cache the response.
– A two-tuple. If it’s a two tuple (e.g. http_cache=(1, {'public':True})), the first
value in the tuple may be a nonzero integer or a datetime.timedelta instance; in either
case this value will be used as the number of seconds to cache the response. The second
value in the tuple must be a dictionary. The values present in the dictionary will be used
as input to the Cache-Control response header. For example: http_cache=(3600,
{'public':True}) means ’cache for an hour, and add public to the Cache-Control
header of the response’. All keys and values supported by the webob.cachecontrol.
CacheControl interface may be added to the dictionary. Supplying {'public':True}
is equivalent to calling response.cache_control.public = True.
Providing a non-tuple value as http_cache is equivalent to calling response.
cache_expires(value) within your view’s body.
Providing a two-tuple value as http_cache is equivalent to calling response.
cache_expires(value[0], **value[1]) within your view’s body.
If you wish to avoid influencing, the Expires header, and instead wish to only influence
Cache-Control headers, pass a tuple as http_cache with the first element of None, e.g.:

0.6. Change History 1069


The Pyramid Web Framework, Version 2.0.2

(None, {'public':True}).

Bug Fixes

• Framework wrappers of the original view (such as http_cached and so on) relied on being able to
trust that the response they were receiving was an IResponse. It wasn’t always, because the response
was resolved by the router instead of early in the view wrapping process. This has been fixed.

Documentation

• Added a section in the ”Webob” chapter named ”Dealing With A JSON-Encoded Request Body”
(usage of request.json_body).

Behavior Changes

• The paster pshell, paster proutes, and paster pviews commands now take a
single argument in the form /path/to/config.ini#sectionname rather than the previ-
ous 2-argument spelling /path/to/config.ini sectionname. #sectionname may be
omitted, in which case #main is assumed.

1.1a4 (2011-07-01)

Bug Fixes

• pyramid.testing.DummyRequest now raises deprecation warnings when attributes dep-


recated for pyramid.request.Request are accessed (like response_content_type).
This is for the benefit of folks running unit tests which use DummyRequest instead of a ”real” re-
quest, so they know things are deprecated without necessarily needing a functional test suite.
• The pyramid.events.subscriber directive behaved contrary to the documentation when
passed more than one interface object to its constructor. For example, when the following listener
was registered:

1070 CONTENTS
The Pyramid Web Framework, Version 2.0.2

@subscriber(IFoo, IBar)
def expects_ifoo_events_and_ibar_events(event):
print event

The Events chapter docs claimed that the listener would be registered and listening for both IFoo
and IBar events. Instead, it registered an ”object event” subscriber which would only be called if an
IObjectEvent was emitted where the object interface was IFoo and the event interface was IBar.
The behavior now matches the documentation. If you were relying on the buggy behavior of the
1.0 subscriber directive in order to register an object event subscriber, you must now pass a
sequence to indicate you’d like to register a subscriber for an object event. e.g.:

@subscriber([IFoo, IBar])
def expects_object_event(object, event):
print object, event

Features

• Add JSONP renderer (see ”JSONP renderer” in the Renderers chapter of the documentation).

Deprecations

• Deprecated the set_renderer_globals_factory method of the Configurator and the ren-


derer_globals Configurator constructor parameter.

Documentation

• The Wiki and Wiki2 tutorial ”Tests” chapters each had two bugs: neither did told the user to depend
on WebTest, and 2 tests failed in each as the result of changes to Pyramid itself. These issues have
been fixed.
• Move 1.0.X CHANGES.txt entries to HISTORY.txt.

0.6. Change History 1071


The Pyramid Web Framework, Version 2.0.2

1.1a3 (2011-06-26)

Features

• Added mako.preprocessor config file parameter; allows for a Mako preprocessor to be spec-
ified as a Python callable or Python dotted name. See https://github.com/Pylons/pyramid/pull/183
for rationale.

Bug fixes

• Pyramid would raise an AttributeError in the Configurator when attempting to set a __text__
attribute on a custom predicate that was actually a classmethod. See https://github.com/Pylons/
pyramid/pull/217 .
• Accessing or setting deprecated response_* attrs on request (e.g. response_content_type)
now issues a deprecation warning at access time rather than at rendering time.

1.1a2 (2011-06-22)

Bug Fixes

• 1.1a1 broke Akhet by not providing a backwards compatibility import shim for pyramid.
paster.PyramidTemplate. Now one has been added, although a deprecation warning is emit-
ted when Akhet imports it.
• If multiple specs were provided in a single call to config.add_translation_dirs, the di-
rectories were inserted into the beginning of the directory list in the wrong order: they were inserted
in the reverse of the order they were provided in the *specs list (items later in the list were added
before ones earlier in the list). This is now fixed.

Backwards Incompatibilities

• The pyramid Router attempted to set a value into the key environ['repoze.bfg.message']
when it caught a view-related exception for backwards compatibility with applications written for
repoze.bfg during error handling. It did this by using code that looked like so:

1072 CONTENTS
The Pyramid Web Framework, Version 2.0.2

# "why" is an exception object


try:
msg = why[0]
except:
msg = ''

environ['repoze.bfg.message'] = msg

Use of the value environ['repoze.bfg.message'] was docs-deprecated in Pyramid 1.0.


Our standing policy is to not remove features after a deprecation for two full major releases, so this
code was originally slated to be removed in Pyramid 1.2. However, computing the repoze.bfg.
message value was the source of at least one bug found in the wild (https://github.com/Pylons/
pyramid/issues/199), and there isn’t a foolproof way to both preserve backwards compatibility and
to fix the bug. Therefore, the code which sets the value has been removed in this release. Code
in exception views which relies on this value’s presence in the environment should now use the
exception attribute of the request (e.g. request.exception[0]) to retrieve the message
instead of relying on request.environ['repoze.bfg.message'].

1.1a1 (2011-06-20)

Documentation

• The term ”template” used to refer to both ”paster templates” and ”rendered templates” (templates
created by a rendering engine. i.e. Mako, Chameleon, Jinja, etc.). ”Paster templates” will now be
referred to as ”scaffolds”, whereas the name for ”rendered templates” will remain as ”templates.”
• The wiki (ZODB+Traversal) tutorial was updated slightly.
• The wiki2 (SQLA+URL Dispatch) tutorial was updated slightly.
• Make pyramid.interfaces.IAuthenticationPolicy and pyramid.
interfaces.IAuthorizationPolicy public interfaces, and refer to them within the
pyramid.authentication and pyramid.authorization API docs.
• Render the function definitions for each exposed interface in pyramid.interfaces.
• Add missing docs reference to pyramid.config.Configurator.set_view_mapper and
refer to it within Hooks chapter section named ”Using a View Mapper”.
• Added section to the ”Environment Variables and .ini File Settings” chapter in the narrative doc-
umentation section entitled ”Adding a Custom Setting”.
• Added documentation for a ”multidict” (e.g. the API of request.POST) as interface API docu-
mentation.

0.6. Change History 1073


The Pyramid Web Framework, Version 2.0.2

• Added a section to the ”URL Dispatch” narrative chapter regarding the new ”static” route feature.
• Added ”What’s New in Pyramid 1.1” to HTML rendering of documentation.
• Added API docs for pyramid.authentication.SessionAuthenticationPolicy.
• Added API docs for pyramid.httpexceptions.exception_response.
• Added ”HTTP Exceptions” section to Views narrative chapter including a description of pyramid.
httpexceptions.exception_response.

Features

• Add support for language fallbacks: when trying to translate for a specific territory (such as en_GB)
fall back to translations for the language (ie en). This brings the translation behaviour in line with
GNU gettext and fixes partially translated texts when using C extensions.
• New authentication policy: pyramid.authentication.
SessionAuthenticationPolicy, which uses a session to store credentials.
• Accessing the response attribute of a pyramid.request.Request object (e.g. request.
response within a view) now produces a new pyramid.response.Response object. This
feature is meant to be used mainly when a view configured with a renderer needs to set response
attributes: all renderers will use the Response object implied by request.response as the
response object returned to the router.
request.response can also be used by code in a view that does not use a renderer, however
the response object that is produced by request.response must be returned when a renderer
is not in play (it is not a ”global” response).
• Integers and longs passed as elements to pyramid.url.resource_url or pyramid.
request.Request.resource_url e.g. resource_url(context, request, 1,
2) (1 and 2 are the elements) will now be converted implicitly to strings in the result. Previ-
ously passing integers or longs as elements would cause a TypeError.
• pyramid_alchemy paster template now uses query.get rather than query.filter_by to
take better advantage of identity map caching.
• pyramid_alchemy paster template now has unit tests.
• Added pyramid.i18n.make_localizer API (broken out from get_localizer guts).
• An exception raised by a NewRequest event subscriber can now be caught by an exception view.
• It is now possible to get information about why Pyramid raised a Forbidden exception from within
an exception view. The ACLDenied object returned by the permits method of each stock au-
thorization policy (pyramid.interfaces.IAuthorizationPolicy.permits) is now

1074 CONTENTS
The Pyramid Web Framework, Version 2.0.2

attached to the Forbidden exception as its result attribute. Therefore, if you’ve created a Forbid-
den exception view, you can see the ACE, ACL, permission, and principals involved in the request
as eg. context.result.permission, context.result.acl, etc within the logic of the
Forbidden exception view.
• Don’t explicitly prevent the timeout from being lower than the reissue_time when setting
up an AuthTktAuthenticationPolicy (previously such a configuration would raise a Val-
ueError, now it’s allowed, although typically nonsensical). Allowing the nonsensical configura-
tion made the code more understandable and required fewer tests.
• A new paster command named paster pviews was added. This command prints a summary of
potentially matching views for a given path. See the section entitled ”Displaying Matching Views
for a Given URL” in the ”View Configuration” chapter of the narrative documentation for more
information.
• The add_route method of the Configurator now accepts a static argument. If this argument
is True, the added route will never be considered for matching when a request is handled. Instead,
it will only be useful for URL generation via route_url and route_path. See the section
entitled ”Static Routes” in the URL Dispatch narrative chapter for more information.
• A default exception view for the context pyramid.interfaces.IExceptionResponse is
now registered by default. This means that an instance of any exception response class imported
from pyramid.httpexceptions (such as HTTPFound) can now be raised from within view
code; when raised, this exception view will render the exception to a response.
• A function named pyramid.httpexceptions.exception_response is a shortcut that
can be used to create HTTP exception response objects using an HTTP integer status code.
• The Configurator now accepts an additional keyword argument named exceptionre-
sponse_view. By default, this argument is populated with a default exception view function
that will be used when a response is raised as an exception. When None is passed for this value, an
exception view for responses will not be registered. Passing None returns the behavior of raising
an HTTP exception to that of Pyramid 1.0 (the exception will propagate to middleware and to the
WSGI server).
• The pyramid.request.Request class now has a ResponseClass interface which points
at pyramid.response.Response.
• The pyramid.response.Response class now has a RequestClass interface which points
at pyramid.request.Request.
• It is now possible to return an arbitrary object from a Pyramid view callable even if a renderer
is not used, as long as a suitable adapter to pyramid.interfaces.IResponse is regis-
tered for the type of the returned object by using the new pyramid.config.Configurator.
add_response_adapter API. See the section in the Hooks chapter of the documentation en-
titled ”Changing How Pyramid Treats View Responses”.

0.6. Change History 1075


The Pyramid Web Framework, Version 2.0.2

• The Pyramid router will now, by default, call the __call__ method of WebOb response ob-
jects when returning a WSGI response. This means that, among other things, the condi-
tional_response feature of WebOb response objects will now behave properly.
• New method named pyramid.request.Request.is_response. This method should be
used instead of the pyramid.view.is_response function, which has been deprecated.

Bug Fixes

• URL pattern markers used in URL dispatch are permitted to specify a custom regex. For example,
the pattern /{foo:\d+} means to match /12345 (foo==12345 in the match dictionary) but not
/abc. However, custom regexes in a pattern marker which used squiggly brackets did not work.
For example, /{foo:\d{4}} would fail to match /1234 and /{foo:\d{1,2}} would fail
to match /1 or /11. One level of inner squiggly brackets is now recognized so that the prior two
patterns given as examples now work. See also https://github.com/Pylons/pyramid/issues/123.
• Don’t send port numbers along with domain information in cookies set by AuthTktCookieHelper
(see https://github.com/Pylons/pyramid/issues/131).
• pyramid.url.route_path (and the shortcut pyramid.request.Request.
route_url method) now include the WSGI SCRIPT_NAME at the front of the path if it
is not empty (see https://github.com/Pylons/pyramid/issues/135).
• pyramid.testing.DummyRequest now has a script_name attribute (the empty string).
• Don’t quote :@&+$, symbols in *elements passed to pyramid.url.route_url or
pyramid.url.resource_url (see https://github.com/Pylons/pyramid/pull/141).
• Include SCRIPT_NAME in redirects issued by pyramid.view.
append_slash_notfound_view (see https://github.com/Pylons/pyramid/issues/149).
• Static views registered with config.add_static_view which also included a permission
keyword argument would not work as expected, because add_static_view also registered a
route factory internally. Because a route factory was registered internally, the context checked by
the Pyramid permission machinery never had an ACL. add_static_view no longer registers a
route with a factory, so the default root factory will be used.
• config.add_static_view now passes extra keyword arguments it receives to config.
add_route (calling add_static_view is mostly logically equivalent to adding a view of the type
pyramid.static.static_view hooked up to a route with a subpath). This makes it possible
to pass e.g., factory= to add_static_view to protect a particular static view with a custom
ACL.
• testing.DummyRequest used the wrong registry (the global registry) as self.registry if
a dummy request was created before testing.setUp was executed (testing.setUp pushes a

1076 CONTENTS
The Pyramid Web Framework, Version 2.0.2

local registry onto the threadlocal stack). Fixed by implementing registry as a property for Dum-
myRequest instead of eagerly assigning an attribute. See also https://github.com/Pylons/pyramid/
issues/165
• When visiting a URL that represented a static view which resolved to a subdirectory, the index.
html of that subdirectory would not be served properly. Instead, a redirect to /subdir would be
issued. This has been fixed, and now visiting a subdirectory that contains an index.html within
a static view returns the index.html properly. See also https://github.com/Pylons/pyramid/issues/67.
• Redirects issued by a static view did not take into account any existing SCRIPT_NAME (such as one
set by a url mapping composite). Now they do.
• The pyramid.wsgi.wsgiapp2 decorator did not take into account the SCRIPT_NAME in the
origin request.
• The pyramid.wsgi.wsgiapp2 decorator effectively only worked when it decorated a view
found via traversal; it ignored the PATH_INFO that was part of a url-dispatch-matched view.

Deprecations

• Deprecated all assignments to request.response_* attributes (for example request.


response_content_type = 'foo' is now deprecated). Assignments and mutations of
assignable request attributes that were considered by the framework for response influence are now
deprecated: response_content_type, response_headerlist, response_status,
response_charset, and response_cache_for. Instead of assigning these to the re-
quest object for later detection by the rendering machinery, users should use the appropri-
ate API of the Response object created by accessing request.response (e.g. code which
does request.response_content_type = 'abc' should be changed to request.
response.content_type = 'abc').
• Passing view-related parameters to pyramid.config.Configurator.add_route is now
deprecated. Previously, a view was permitted to be connected to a route using a set of view*
parameters passed to the add_route method of the Configurator. This was a shorthand which
replaced the need to perform a subsequent call to add_view. For example, it was valid (and often
recommended) to do:

config.add_route('home', '/', view='mypackage.views.myview',


view_renderer='some/renderer.pt')

Passing view* arguments to add_route is now deprecated in favor of connecting a view to a


predefined route via Configurator.add_view using the route’s route_name parameter. As
a result, the above example should now be spelled:

0.6. Change History 1077


The Pyramid Web Framework, Version 2.0.2

config.add_route('home', '/')
config.add_view('mypackage.views.myview', route_name='home')
renderer='some/renderer.pt')

This deprecation was done to reduce confusion observed in IRC, as well as to (eventually) re-
duce documentation burden (see also https://github.com/Pylons/pyramid/issues/164). A depre-
cation warning is now issued when any view-related parameter is passed to Configurator.
add_route.
• Passing an environ dictionary to the __call__ method of a ”traverser” (e.g. an object
that implements pyramid.interfaces.ITraverser such as an instance of pyramid.
traversal.ResourceTreeTraverser) as its request argument now causes a depreca-
tion warning to be emitted. Consumer code should pass a request object instead. The fact that
passing an environ dict is permitted has been documentation-deprecated since repoze.bfg 1.1,
and this capability will be removed entirely in a future version.
• The following (undocumented, dictionary-like) methods of the pyramid.request.Request
object have been deprecated: __contains__, __delitem__, __getitem__, __iter__,
__setitem__, get, has_key, items, iteritems, itervalues, keys, pop, popitem,
setdefault, update, and values. Usage of any of these methods will cause a deprecation
warning to be emitted. These methods were added for internal compatibility in repoze.bfg 1.1
(code that currently expects a request object expected an environ object in BFG 1.0 and before). In
a future version, these methods will be removed entirely.
• Deprecated pyramid.view.is_response function in favor of (newly-added) pyramid.
request.Request.is_response method. Determining if an object is truly a valid response
object now requires access to the registry, which is only easily available as a request attribute. The
pyramid.view.is_response function will still work until it is removed, but now may return
an incorrect answer under some (very uncommon) circumstances.

Behavior Changes

• The default Mako renderer is now configured to escape all HTML in expression tags. This is intended
to help prevent XSS attacks caused by rendering unsanitized input from users. To revert this behavior
in user’s templates, they need to filter the expression through the ’n’ filter. For example, ${ myhtml
| n }. See https://github.com/Pylons/pyramid/issues/193.
• A custom request factory is now required to return a request object that has a response attribute
(or ”reified”/lazy property) if they the request is meant to be used in a view that uses a renderer.
This response attribute should be an instance of the class pyramid.response.Response.
• The JSON and string renderer factories now assign to request.response.content_type
rather than request.response_content_type.

1078 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Each built-in renderer factory now determines whether it should change the content type of the
response by comparing the response’s content type against the response’s default content type; if
the content type is the default content type (usually text/html), the renderer changes the content
type (to application/json or text/plain for JSON and string renderers respectively).
• The pyramid.wsgi.wsgiapp2 now uses a slightly different method of figuring out how to ”fix”
SCRIPT_NAME and PATH_INFO for the downstream application. As a result, those values may
differ slightly from the perspective of the downstream application (for example, SCRIPT_NAME
will now never possess a trailing slash).
• Previously, pyramid.request.Request inherited from webob.request.Request and
implemented __getattr__, __setattr__ and __delattr__ itself in order to overidde
”adhoc attr” WebOb behavior where attributes of the request are stored in the environ. Now,
pyramid.request.Request object inherits from (the more recent) webob.request.
BaseRequest instead of webob.request.Request, which provides the same behavior.
pyramid.request.Request no longer implements its own __getattr__, __setattr__
or __delattr__ as a result.
• pyramid.response.Response is now a subclass of webob.response.Response (in
order to directly implement the pyramid.interfaces.IResponse interface).
• The ”exception response” objects importable from pyramid.httpexceptions (e.g. HTTP-
NotFound) are no longer just import aliases for classes that actually live in webob.exc. Instead,
we’ve defined our own exception classes within the module that mirror and emulate the webob.exc
exception response objects almost entirely. See the ”Design Defense” doc section named ”Pyramid
Uses its Own HTTP Exception Classes” for more information.

Backwards Incompatibilities

• Pyramid no longer supports Python 2.4. Python 2.5 or better is required to run Pyramid 1.1+.
• The Pyramid router now, by default, expects response objects returned from view callables to im-
plement the pyramid.interfaces.IResponse interface. Unlike the Pyramid 1.0 version of
this interface, objects which implement IResponse now must define a __call__ method that ac-
cepts environ and start_response, and which returns an app_iter iterable, among other
things. Previously, it was possible to return any object which had the three WebOb app_iter,
headerlist, and status attributes as a response, so this is a backwards incompatibility. It is
possible to get backwards compatibility back by registering an adapter to IResponse from the type
of object you’re now returning from view callables. See the section in the Hooks chapter of the
documentation entitled ”Changing How Pyramid Treats View Responses”.
• The pyramid.interfaces.IResponse interface is now much more extensive. Previously
it defined only app_iter, status and headerlist; now it is basically intended to directly
mirror the webob.Response API, which has many methods and attributes.

0.6. Change History 1079


The Pyramid Web Framework, Version 2.0.2

• The pyramid.httpexceptions classes named HTTPFound, HTTPMultipleChoices,


HTTPMovedPermanently, HTTPSeeOther, HTTPUseProxy, and HTTPTempo-
raryRedirect now accept location as their first positional argument rather than
detail. This means that you can do, e.g. return pyramid.httpexceptions.
HTTPFound('http://foo') rather than return pyramid.httpexceptions.
HTTPFound(location='http//foo') (the latter will of course continue to work).

Dependencies

• Pyramid now depends on WebOb >= 1.0.2 as tests depend on the bugfix in that release: ”Fix handling
of WSGI environs with missing SCRIPT_NAME”. (Note that in reality, everyone should probably
be using 1.0.4 or better though, as WebOb 1.0.2 and 1.0.3 were effectively brownbag releases.)

1.0 (2011-01-30)

Documentation

• Fixed bug in ZODB Wiki tutorial (missing dependency on docutils in ”models” step within
setup.py).
• Removed API documentation for pyramid.testing APIs named registerDummySecu-
rityPolicy, registerResources, registerModels, registerEventListener,
registerTemplateRenderer, registerDummyRenderer, registerView, regis-
terUtility, registerAdapter, registerSubscriber, registerRoute, and reg-
isterSettings.
• Moved ”Using ZODB With ZEO” and ”Using repoze.catalog Within Pyramid” tutorials out of core
documentation and into the Pyramid Tutorials site (https://docs.pylonsproject.org/projects/pyramid_
tutorials/en/latest/).
• Changed ”Cleaning up After a Request” section in the URL Dispatch chapter to use request.
add_finished_callback instead of jamming an object with a __del__ into the WSGI en-
vironment.
• Remove duplication of add_route API documentation from URL Dispatch narrative chapter.
• Remove duplication of API and narrative documentation in pyramid.view.view_config API
docs by pointing to pyramid.config.add_view documentation and narrative chapter docu-
mentation.
• Removed some API documentation duplicated in narrative portions of documentation
• Removed ”Overall Flow of Authentication” from SQLAlchemy + URL Dispatch wiki tutorial due
to print space concerns (moved to Pyramid Tutorials site).

1080 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• Deprecated-since-BFG-1.2 APIs from pyramid.testing now properly emit deprecation warn-


ings.
• Added egg:repoze.retry#retry middleware to the WSGI pipeline in ZODB templates (retry
ZODB conflict errors which occur in normal operations).
• Removed duplicate implementations of is_response. Two competing implementations existed:
one in pyramid.config and one in pyramid.view. Now the one defined in pyramid.view
is used internally by pyramid.config and continues to be advertised as an API.

1.0b3 (2011-01-28)

Bug Fixes

• Use &copy; instead of copyright symbol in paster templates / tutorial templates for the benefit of
folks who cutnpaste and save to a non-UTF8 format.
• pyramid.view.append_slash_notfound_view now preserves GET query parameters
across redirects.

Documentation

• Beef up documentation related to set_default_permission: explicitly mention that default


permissions also protect exception views.
• Paster templates and tutorials now use spaces instead of tabs in their HTML templates.

1.0b2 (2011-01-24)

Bug Fixes

• The production.ini generated by all paster templates now have an effective logging level of
WARN, which prevents e.g. SQLAlchemy statement logging and other inappropriate output.

0.6. Change History 1081


The Pyramid Web Framework, Version 2.0.2

• The production.ini of the pyramid_routesalchemy and pyramid_alchemy


paster templates did not have a sqlalchemy logger section, preventing paster serve
production.ini from working.
• The pyramid_routesalchemy and pyramid_alchemy paster templates used the {{pack-
age}} variable in a place where it should have used the {{project}} variable, causing appli-
cations created with uppercase letters e.g. paster create -t pyramid_routesalchemy
Dibbus to fail to start when paster serve development.ini was used against the result.
See https://github.com/Pylons/pyramid/issues/107
• The render_view method of pyramid.renderers.RendererHelper passed an incor-
rect value into the renderer for renderer_info. It now passes an instance of Render-
erHelper instead of a dictionary, which is consistent with other usages. See https://github.com/
Pylons/pyramid/issues/106
• A bug existed in the pyramid.authentication.AuthTktCookieHelper which would
break any usage of an AuthTktAuthenticationPolicy when one was configured to reissue its tokens
(reissue_time < timeout / max_age). Symptom: ValueError: ('Invalid token
%r', ''). See https://github.com/Pylons/pyramid/issues/108.

1.0b1 (2011-01-21)

Features

• The AuthTktAuthenticationPolicy now accepts a tokens parameter via pyramid.security.


remember. The value must be a sequence of strings. Tokens are placed into the auth_tkt ”tokens”
field and returned in the auth_tkt cookie.
• Add wild_domain argument to AuthTktAuthenticationPolicy, which defaults to True. If it is set
to False, the feature of the policy which sets a cookie with a wildcard domain will be turned off.
• Add a MANIFEST.in file to each paster template. See https://github.com/Pylons/pyramid/issues/
95

Bug Fixes

• testing.setUp now adds a settings attribute to the registry (both when it’s passed a registry
without any settings and when it creates one).
• The testing.setUp function now takes a settings argument, which should be a dictionary.
Its values will subsequently be available on the returned config object as config.registry.
settings.

1082 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• Added ”What’s New in Pyramid 1.0” chapter to HTML rendering of documentation.


• Merged caseman-master narrative editing branch, many wording fixes and extensions.
• Fix deprecated example showing chameleon_zpt API call in testing narrative chapter.
• Added ”Adding Methods to the Configurator via add_directive” section to Advanced Config-
uration narrative chapter.
• Add docs for add_finished_callback, add_response_callback, route_path,
route_url, and static_url methods to pyramid.request.Request API docs.
• Add (minimal) documentation about using I18N within Mako templates to ”Internationalization and
Localization” narrative chapter.
• Move content of ”Forms” chapter back to ”Views” chapter; I can’t think of a better place to put it.
• Slightly improved interface docs for IAuthorizationPolicy.
• Minimally explain usage of custom regular expressions in URL dispatch replacement markers within
URL Dispatch chapter.

Deprecations

• Using the pyramid.view.bfg_view alias for pyramid.view.view_config (a back-


wards compatibility shim) now issues a deprecation warning.

Backwards Incompatibilities

• Using testing.setUp now registers an ISettings utility as a side effect. Some test code which
queries for this utility after testing.setUp via queryAdapter will expect a return value of None.
This code will need to be changed.
• When a pyramid.exceptions.Forbidden error is raised, its status code now 403 For-
bidden. It was previously 401 Unauthorized, for backwards compatibility purposes with
repoze.bfg. This change will cause problems for users of Pyramid with repoze.who, which
intercepts 401 Unauthorized by default, but allows 403 Forbidden to pass through. Those
deployments will need to configure repoze.who to also react to 403 Forbidden.
• The default value for the cookie_on_exception parameter to pyramid.session.
UnencryptedCookieSessionFactory is now True. This means that when view code
causes an exception to be raised, and the session has been mutated, a cookie will be sent back
in the response. Previously its default value was False.

0.6. Change History 1083


The Pyramid Web Framework, Version 2.0.2

Paster Templates

• The pyramid_zodb, pyramid_routesalchemy and pyramid_alchemy paster templates


now use a default ”commit veto” hook when configuring the repoze.tm2 transaction manager in
development.ini. This prevents a transaction from being committed when the response status
code is within the 400 or 500 ranges. See also https://repozetm2.readthedocs.io/en/latest/index.
html#using-a-commit-veto.

1.0a10 (2011-01-18)

Bug Fixes

• URL dispatch now properly handles a .* or * appearing in a regex match when used inside brackets.
Resolves issue #90.

Backwards Incompatibilities

• The add_handler method of a Configurator has been removed from the Pyramid core. Handlers
are now a feature of the pyramid_handlers package, which can be downloaded from PyPI. Doc-
umentation for the package should be available via https://docs.pylonsproject.org/projects/pyramid_
handlers/en/latest/, which describes how to add a configuration statement to your main block to re-
obtain this method. You will also need to add an install_requires dependency upon pyra-
mid_handlers to your setup.py file.
• The load_zcml method of a Configurator has been removed from the Pyramid core. Loading
ZCML is now a feature of the pyramid_zcml package, which can be downloaded from PyPI. Doc-
umentation for the package should be available via https://docs.pylonsproject.org/projects/pyramid_
zcml/en/latest/, which describes how to add a configuration statement to your main block to reob-
tain this method. You will also need to add an install_requires dependency upon pyra-
mid_zcml to your setup.py file.
• The pyramid.includes subpackage has been removed. ZCML files which use in-
clude the package pyramid.includes (e.g. <include package="pyramid.
includes"/>) now must include the pyramid_zcml package instead (e.g. <include
package="pyramid_zcml"/>).
• The pyramid.view.action decorator has been removed from the Pyramid core. Handlers are
now a feature of the pyramid_handlers package. It should now be imported from pyra-
mid_handlers e.g. from pyramid_handlers import action.

1084 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The handler ZCML directive has been removed. It is now a feature of the pyramid_handlers
package.
• The pylons_minimal, pylons_basic and pylons_sqla paster templates were removed.
Use pyramid_sqla (available from PyPI) as a generic replacement for Pylons-esque develop-
ment.
• The make_app function has been removed from the pyramid.router module. It continues
life within the pyramid_zcml package. This leaves the pyramid.router module without
any API functions.
• The configure_zcml setting within the deployment settings (within **settings passed to a
Pyramid main function) has ceased to have any meaning.

Features

• pyramid.testing.setUp and pyramid.testing.tearDown have been undeprecated.


They are now the canonical setup and teardown APIs for test configuration, replacing ”direct” cre-
ation of a Configurator. This is a change designed to provide a facade that will protect against any
future Configurator deprecations.
• Add charset attribute to pyramid.testing.DummyRequest (unconditionally UTF-8).
• Add add_directive method to configurator, which allows framework extenders to add methods
to the configurator (ala ZCML directives).
• When Configurator.include is passed a module as an argument, it defaults to attempting to
find and use a callable named includeme within that module. This makes it possible to use
config.include('some.module') rather than config.include('some.module.
somefunc') as long as the include function within some.module is named includeme.
• The bfg2pyramid script now converts ZCML include tags that have repoze.bfg.
includes as a package attribute to the value pyramid_zcml. For example, <include
package="repoze.bfg.includes"> will be converted to <include pack-
age="pyramid_zcml">.

Paster Templates

• All paster templates now use pyramid.testing.setUp and pyramid.testing.


tearDown rather than creating a Configurator ”by hand” within their tests.py module, as per
decision in features above.
• The starter_zcml paster template has been moved to the pyramid_zcml package.

0.6. Change History 1085


The Pyramid Web Framework, Version 2.0.2

Documentation

• The wiki and wiki2 tutorials now use pyramid.testing.setUp and pyramid.testing.
tearDown rather than creating a Configurator ”by hand”, as per decision in features above.
• The ”Testing” narrative chapter now explains pyramid.testing.setUp and pyramid.
testing.tearDown instead of Configurator creation and Configurator.begin() and
Configurator.end().
• Document the request.override_renderer attribute within the narrative ”Renderers”
chapter in a section named ”Overriding A Renderer at Runtime”.
• The ”Declarative Configuration” narrative chapter has been removed (it was moved to the pyra-
mid_zcml package).
• Most references to ZCML in narrative chapters have been removed or redirected to pyramid_zcml
locations.

Deprecations

• Deprecation warnings related to import of the following API functions were added:
pyramid.traversal.find_model, pyramid.traversal.model_path, pyramid.
traversal.model_path_tuple, pyramid.url.model_url. The instructions emitted
by the deprecation warnings instruct the developer to change these method spellings to their re-
source equivalents. This is a consequence of the mass concept rename of ”model” to ”resource”
performed in 1.0a7.

1.0a9 (2011-01-08)

Bug Fixes

• The proutes command tried too hard to resolve the view for printing, resulting in exceptions when
an exceptional root factory was encountered. Instead of trying to resolve the view, if it cannot, it will
now just print <unknown>.
• The self argument was included in new methods of the ISession interface signature, causing
pyramid_beaker tests to fail.
• Readd pyramid.traversal.model_path_tuple as an alias for pyramid.
traversal.resource_path_tuple for backwards compatibility.

1086 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Features

• Add a new API pyramid.url.current_route_url, which computes a URL based on the


”current” route (if any) and its matchdict values.
• config.add_view now accepts a decorator keyword argument, a callable which will deco-
rate the view callable before it is added to the registry.
• If a handler class provides an __action_decorator__ attribute (usually a classmethod or stat-
icmethod), use that as the decorator for each view registration for that handler.
• The pyramid.interfaces.IAuthenticationPolicy interface now specifies an unau-
thenticated_userid method. This method supports an important optimization required by
people who are using persistent storages which do not support object caching and whom want to
create a ”user object” as a request attribute.
• A new API has been added to the pyramid.security module named unauthenti-
cated_userid. This API function calls the unauthenticated_userid method of the ef-
fective security policy.
• An unauthenticated_userid method has been added to the dummy authentication policy
returned by pyramid.config.Configurator.testing_securitypolicy. It returns
the same thing as that the dummy authentication policy’s authenticated_userid method.
• The class pyramid.authentication.AuthTktCookieHelper is now an API. This class
can be used by third-party authentication policy developers to help in the mechanics of authentication
cookie-setting.
• New constructor argument to Configurator: default_view_mapper. Useful to create sys-
tems that have alternate view calling conventions. A view mapper allows objects that are meant
to be used as view callables to have an arbitrary argument list and an arbitrary result. The
object passed as default_view_mapper should implement the pyramid.interfaces.
IViewMapperFactory interface.
• add a set_view_mapper API to Configurator. Has the same result as passing de-
fault_view_mapper to the Configurator constructor.
• config.add_view now accepts a mapper keyword argument, which should either be None, a
string representing a Python dotted name, or an object which is an IViewMapperFactory. This
feature is not useful for ”civilians”, only for extension writers.
• Allow static renderer provided during view registration to be overridden at request time via a request
attribute named override_renderer, which should be the name of a previously registered ren-
derer. Useful to provide ”omnipresent” RPC using existing rendered views.
• Instances of pyramid.testing.DummyRequest now have a session object, which is
mostly a dictionary, but also implements the other session API methods for flash and CSRF.

0.6. Change History 1087


The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• Since the pyramid.interfaces.IAuthenticationPolicy interface now specifies that


a policy implementation must implement an unauthenticated_userid method, all third-
party custom authentication policies now must implement this method. It, however, will only be
called when the global function named pyramid.security.unauthenticated_userid
is invoked, so if you’re not invoking that, you will not notice any issues.
• pyramid.interfaces.ISession.get_csrf_token now mandates that an implementa-
tion should return a new token if one doesn’t already exist in the session (previously it would return
None). The internal sessioning implementation has been changed.

Documentation

• The (weak) ”Converting a CMF Application to Pyramid” tutorial has been removed from the tutorials
section. It was moved to the pyramid_tutorials Github repository.
• The ”Resource Location and View Lookup” chapter has been replaced with a variant of
Rob Miller’s ”Much Ado About Traversal” (originally published at https://web.archive.org/web/
20150321110754/http://blog.nonsequitarian.org/2010/much-ado-about-traversal/).
• Many minor wording tweaks and refactorings (merged Casey Duncan’s docs fork, in which he is
working on general editing).
• Added (weak) description of new view mapper feature to Hooks narrative chapter.
• Split views chapter into 2: View Callables and View Configuration.
• Reorder Renderers and Templates chapters after View Callables but before View Configuration.
• Merge Session Objects, Cross-Site Request Forgery, and Flash Messaging chapter into a single Ses-
sions chapter.
• The Wiki and Wiki2 tutorials now have much nicer CSS and graphics.

Internals

• The ”view derivation” code is now factored into a set of classes rather than a large number of stan-
dalone functions (a side effect of the view mapper refactoring).
• The pyramid.renderer.RendererHelper class has grown a render_view method,
which is used by the default view mapper (a side effect of the view mapper refactoring).

1088 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The object passed as renderer to the ”view deriver” is now an instance of pyramid.
renderers.RendererHelper rather than a dictionary (a side effect of view mapper refac-
toring).
• The class used as the ”page template” in pyramid.chameleon_text was removed, in prefer-
ence to using a Chameleon-inbuilt version.
• A view callable wrapper registered in the registry now contains an __original_view__ at-
tribute which references the original view callable (or class).
• The (non-API) method of all internal authentication policy implementations previously named
_get_userid is now named unauthenticated_userid, promoted to an API method. If
you were overriding this method, you’ll now need to override it as unauthenticated_userid
instead.
• Remove (non-API) function of config.py named _map_view.

1.0a8 (2010-12-27)

Bug Fixes

• The name registry was not available in the paster pshell environment under IPython.

Features

• If a resource implements a __resource_url__ method, it will be called as the result of invoking


the pyramid.url.resource_url function to generate a URL, overriding the default logic.
See the new ”Generating The URL Of A Resource” section within the Resources narrative chapter.
• Added flash messaging, as described in the ”Flash Messaging” narrative documentation chapter.
• Added CSRF token generation, as described in the narrative chapter entitled ”Preventing Cross-Site
Request Forgery Attacks”.
• Prevent misunderstanding of how the view and view_permission arguments to add_route
work by raising an exception during configuration if view-related arguments exist but no view
argument is passed.
• Add paster proute command which displays a summary of the routing table. See the narra-
tive documentation section within the ”URL Dispatch” chapter entitled ”Displaying All Application
Routes”.

0.6. Change History 1089


The Pyramid Web Framework, Version 2.0.2

Paster Templates

• The pyramid_zodb Paster template no longer employs ZCML. Instead, it is based on scanning.

Documentation

• Added ”Generating The URL Of A Resource” section to the Resources narrative chapter (includes
information about overriding URL generation using __resource_url__).
• Added ”Generating the Path To a Resource” section to the Resources narrative chapter.
• Added ”Finding a Resource by Path” section to the Resources narrative chapter.
• Added ”Obtaining the Lineage of a Resource” to the Resources narrative chapter.
• Added ”Determining if a Resource is In The Lineage of Another Resource” to Resources narrative
chapter.
• Added ”Finding the Root Resource” to Resources narrative chapter.
• Added ”Finding a Resource With a Class or Interface in Lineage” to Resources narrative chapter.
• Added a ”Flash Messaging” narrative documentation chapter.
• Added a narrative chapter entitled ”Preventing Cross-Site Request Forgery Attacks”.
• Changed the ”ZODB + Traversal Wiki Tutorial” based on changes to pyramid_zodb Paster tem-
plate.
• Added ”Advanced Configuration” narrative chapter which documents how to deal with configuration
conflicts, two-phase configuration, include and commit.
• Fix API documentation rendering for pyramid.view.static
• Add ”Pyramid Provides More Than One Way to Do It” to Design Defense documentation.
• Changed ”Static Assets” narrative chapter: clarify that name represents a prefix unless it’s a URL,
added an example of a root-relative static view fallback for URL dispatch, added an example of
creating a simple view that returns the body of a file.
• Move ZCML usage in Hooks chapter to Declarative Configuration chapter.
• Merge ”Static Assets” chapter into the ”Assets” chapter.
• Added narrative documentation section within the ”URL Dispatch” chapter entitled ”Displaying All
Application Routes” (for paster proutes command).

1090 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.0a7 (2010-12-20)

Terminology Changes

• The Pyramid concept previously known as ”model” is now known as ”resource”. As a result:
– The following API changes have been made:

pyramid.url.model_url ->
pyramid.url.resource_url

pyramid.traversal.find_model ->
pyramid.url.find_resource

pyramid.traversal.model_path ->
pyramid.traversal.resource_path

pyramid.traversal.model_path_tuple ->
pyramid.traversal.resource_path_tuple

pyramid.traversal.ModelGraphTraverser ->
pyramid.traversal.ResourceTreeTraverser

pyramid.config.Configurator.testing_models ->
pyramid.config.Configurator.testing_resources

pyramid.testing.registerModels ->
pyramid.testing.registerResources

pyramid.testing.DummyModel ->
pyramid.testing.DummyResource

– All documentation which previously referred to ”model” now refers to ”resource”.


– The starter and starter_zcml paster templates now have a resources.py module
instead of a models.py module.
– Positional argument names of various APIs have been changed from model to resource.
Backwards compatibility shims have been left in place in all cases. They will continue to work
”forever”.
• The Pyramid concept previously known as ”resource” is now known as ”asset”. As a result:
– The (non-API) module previously known as pyramid.resource is now known as
pyramid.asset.

0.6. Change History 1091


The Pyramid Web Framework, Version 2.0.2

– All docs that previously referred to ”resource specification” now refer to ”asset specification”.
– The following API changes were made:

pyramid.config.Configurator.absolute_resource_spec ->
pyramid.config.Configurator.absolute_asset_spec

pyramid.config.Configurator.override_resource ->
pyramid.config.Configurator.override_asset

– The ZCML directive previously known as resource is now known as asset.


– The setting previously known as BFG_RELOAD_RESOURCES (envvar) or
reload_resources (config file) is now known, respectively, as PYRA-
MID_RELOAD_ASSETS and reload_assets.
Backwards compatibility shims have been left in place in all cases. They will continue to work
”forever”.

Bug Fixes

• Make it possible to successfully run all tests via nosetests command directly (rather than indi-
rectly via python setup.py nosetests).
• When a configuration conflict is encountered during scanning, the conflict exception now shows the
decorator information that caused the conflict.

Features

• Added debug_routematch configuration setting that logs matched routes (including the match-
dict and predicates).
• The name registry is now available in a pshell environment by default. It is the application
registry object.

Environment

• All environment variables which used to be prefixed with BFG_ are now prefixed with PYRAMID_
(e.g. BFG_DEBUG_NOTFOUND is now PYRAMID_DEBUG_NOTFOUND)

1092 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• Added ”Debugging Route Matching” section to the urldispatch narrative documentation chapter.
• Added reference to PYRAMID_DEBUG_ROUTEMATCH envvar and debug_routematch config
file setting to the Environment narrative docs chapter.
• Changed ”Project” chapter slightly to expand on use of paster pshell.
• Direct Jython users to Mako rather than Jinja2 in ”Install” narrative chapter.
• Many changes to support terminological renaming of ”model” to ”resource” and ”resource” to ”as-
set”.
• Added an example of WebTest functional testing to the testing narrative chapter.
• Rearranged chapter ordering by popular demand (URL dispatch first, then traversal). Put hybrid
chapter after views chapter.
• Split off ”Renderers” as its own chapter from ”Views” chapter in narrative documentation.

Paster Templates

• Added debug_routematch = false to all paster templates.

Dependencies

• Depend on Venusian >= 0.5 (for scanning conflict exception decoration).

1.0a6 (2010-12-15)

Bug Fixes

• 1.0a5 introduced a bug when pyramid.config.Configurator.scan was used


without a package argument (e.g. config.scan() as opposed to config.
scan('packagename'). The symptoms were: lots of deprecation warnings printed to
the console about imports of deprecated Pyramid functions and classes and non-detection of view
callables decorated with view_config decorators. This has been fixed.
• Tests now pass on Windows (no bugs found, but a few tests in the test suite assumed UNIX path
segments in filenames).

0.6. Change History 1093


The Pyramid Web Framework, Version 2.0.2

Documentation

• If you followed it to-the-letter, the ZODB+Traversal Wiki tutorial would instruct you to run a test
which would fail because the view callable generated by the pyramid_zodb tutorial used a one-
arg view callable, but the test in the sample code used a two-arg call.
• Updated ZODB+Traversal tutorial setup.py of all steps to match what’s generated by pyra-
mid_zodb.
• Fix reference to repoze.bfg.traversalwrapper in ”Models” chapter (point at pyra-
mid_traversalwrapper instead).

1.0a5 (2010-12-14)

Features

• Add a handler ZCML directive. This directive does the same thing as pyramid.
configuration.add_handler.
• A new module named pyramid.config was added. It subsumes the duties of the older
pyramid.configuration module.
• The new pyramid.config.Configurator` class has API methods that the
older ``pyramid.configuration.Configurator class did not: with_context (a
classmethod), include, action, and commit. These methods exist for imperative application
extensibility purposes.
• The pyramid.testing.setUp function now accepts an autocommit keyword argument,
which defaults to True. If it is passed False, the Config object returned by setUp will be a
non-autocommitting Config object.
• Add logging configuration to all paster templates.
• pyramid_alchemy, pyramid_routesalchemy, and pylons_sqla paster templates now
use idiomatic SQLAlchemy configuration in their respective .ini files and Python code.
• pyramid.testing.DummyRequest now has a class variable, query_string, which de-
faults to the empty string.
• Add support for json on GAE by catching NotImplementedError and importing simplejson from
django.utils.
• The Mako renderer now accepts a resource specification for mako.module_directory.
• New boolean Mako settings variable mako.strict_undefined. See Mako Context Variables
for its meaning.

1094 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Dependencies

• Depend on Mako 0.3.6+ (we now require the strict_undefined feature).

Bug Fixes

• When creating a Configurator from within a paster pshell session, you were required to pass
a package argument although package is not actually required. If you didn’t pass pack-
age, you would receive an error something like KeyError: '__name__' emanating from
the pyramid.path.caller_module function. This has now been fixed.
• The pyramid_routesalchemy paster template’s unit tests failed (AssertionError:
'SomeProject' != 'someproject'). This is fixed.
• Make default renderer work (renderer factory registered with no name, which is active for every view
unless the view names a specific renderer).
• The Mako renderer did not properly turn the mako.imports, mako.default_filters, and
mako.imports settings into lists.
• The Mako renderer did not properly convert the mako.error_handler setting from a dotted
name to a callable.

Documentation

• Merged many wording, readability, and correctness changes to narrative documentation chapters
from https://github.com/caseman/pyramid (up to and including ”Models” narrative chapter).
• ”Sample Applications” section of docs changed to note existence of Cluegun, Shootout and Virginia
sample applications, ported from their repoze.bfg origin packages.
• SQLAlchemy+URLDispatch tutorial updated to integrate changes to pyra-
mid_routesalchemy template.
• Add pyramid.interfaces.ITemplateRenderer interface to Interfaces API chapter (has
implementation() method, required to be used when getting at Chameleon macros).
• Add a ”Modifying Package Structure” section to the project narrative documentation chapter (explain
turning a module into a package).
• Documentation was added for the new handler ZCML directive in the ZCML section.

0.6. Change History 1095


The Pyramid Web Framework, Version 2.0.2

Deprecations

• pyramid.configuration.Configurator is now deprecated. Use pyramid.config.


Configurator, passing its constructor autocommit=True instead. The pyramid.
configuration.Configurator alias will live for a long time, as every application uses it,
but its import now issues a deprecation warning. The pyramid.config.Configurator class
has the same API as pyramid.configuration.Configurator class, which it means to re-
place, except by default it is a non-autocommitting configurator. The now-deprecated pyramid.
configuration.Configurator will autocommit every time a configuration method is
called.
The pyramid.configuration module remains, but it is deprecated. Use pyramid.config
instead.

1.0a4 (2010-11-21)

Features

• URL Dispatch now allows for replacement markers to be located anywhere in the pattern, instead of
immediately following a /.
• URL Dispatch now uses the form {marker} to denote a replace marker in the route pattern instead
of :marker. The old colon-style marker syntax is still accepted for backwards compatibility. The
new format allows a regular expression for that marker location to be used instead of the default
[^/]+, for example {marker:\d+} is now valid to require the marker to be digits.
• Add a pyramid.url.route_path API, allowing folks to generate relative URLs. Calling
route_path is the same as calling pyramid.url.route_url with the argument _app_url
equal to the empty string.
• Add a pyramid.request.Request.route_path API. This is a convenience method of the
request which calls pyramid.url.route_url.
• Make test suite pass on Jython (requires PasteScript trunk, presumably to be 1.7.4).
• Make test suite pass on PyPy (Chameleon doesn’t work).
• Surrounding application configuration with config.begin() and config.end() is no longer
necessary. All paster templates have been changed to no longer call these functions.
• Fix configurator to not convert ImportError to ConfigurationError if the import that
failed was unrelated to the import requested via a dotted name when resolving dotted names (such
as view dotted names).

1096 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• SQLAlchemy+URLDispatch and ZODB+Traversal tutorials have been updated to not call


config.begin() or config.end().

Bug Fixes

• Add deprecation warnings to import of pyramid.chameleon_text and pyramid.


chameleon_zpt of get_renderer, get_template, render_template, and ren-
der_template_to_response.
• Add deprecation warning for import of pyramid.zcml.zcml_configure and pyramid.
zcml.file_configure.
• The pyramid_alchemy paster template had a typo, preventing an import from working.
• Fix apparent failures when calling pyramid.traversal.find_model(root, path) or
pyramid.traversal.traverse(path) when path is (erroneously) a Unicode object. The
user is meant to pass these APIs a string object, never a Unicode object. In practice, however, users
indeed pass Unicode. Because the string that is passed must be ASCII encodeable, now, if they pass
a Unicode object, its data is eagerly converted to an ASCII string rather than being passed along to
downstream code as a convenience to the user and to prevent puzzling second-order failures from
cropping up (all failures will occur within pyramid.traversal.traverse rather than later
down the line as the result of calling e.g. traversal_path).

Backwards Incompatibilities

• The pyramid.testing.zcml_configure API has been removed. It had been advertised as


removed since repoze.bfg 1.2a1, but hadn’t actually been.

Deprecations

• The pyramid.settings.get_settings API is now deprecated. Use pyramid.


threadlocals.get_current_registry().settings instead or use the settings
attribute of the registry available from the request (request.registry.settings).

0.6. Change History 1097


The Pyramid Web Framework, Version 2.0.2

Documentation

• Removed zodbsessions tutorial chapter. It’s still useful, but we now have a SessionFactory
abstraction which competes with it, and maintaining documentation on both ways to do it is a dis-
traction.

Internal

• Replace Twill with WebTest in internal integration tests (avoid deprecation warnings generated by
Twill).

1.0a3 (2010-11-16)

Features

• Added Mako TemplateLookup settings for mako.error_handler, mako.


default_filters, and mako.imports.
• Normalized all paster templates: each now uses the name main to represent the function that returns
a WSGI application, each now uses WebError, each now has roughly the same shape of develop-
ment.ini style.
• Added class vars matchdict and matched_route to pyramid.request.Request. Each
is set to None.
• New API method: pyramid.settings.asbool.
• New API methods for pyramid.request.Request: model_url, route_url, and
static_url. These are simple passthroughs for their respective functions in pyramid.url.
• The settings object which used to be available only when request.settings.
get_settings was called is now available as registry.settings (e.g. request.
registry.settings in view code).

Bug Fixes

• The pylons_* paster templates erroneously used the {squiggly} routing syntax as the pattern
supplied to add_route. This style of routing is not supported. They were replaced with :colon
style route patterns.
• The pylons_* paster template used the same string (your_app_secret_string) for the
session.secret setting in the generated development.ini. This was a security risk if
left unchanged in a project that used one of the templates to produce production applications. It now
uses a randomly generated string.

1098 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• ZODB+traversal wiki (wiki) tutorial updated due to changes to pyramid_zodb paster template.
• SQLAlchemy+urldispach wiki (wiki2) tutorial updated due to changes to pyra-
mid_routesalchemy paster template.
• Documented the matchdict and matched_route attributes of the request object in the Request
API documentation.

Deprecations

• Obtaining the settings object via registry.{get|query}Utility(ISettings) is


now deprecated. Instead, obtain the settings object via the registry.settings attribute.
A backwards compatibility shim was added to the registry object to register the settings object as
an ISettings utility when setattr(registry, 'settings', foo) is called, but it will be
removed in a later release.
• Obtaining the settings object via pyramid.settings.get_settings is now deprecated.
Obtain it as the settings attribute of the registry now (obtain the registry via pyramid.
threadlocal.get_registry or as request.registry).

Behavior Differences

• Internal: ZCML directives no longer call get_current_registry() if there’s a registry attribute on


the ZCML context (kill off use of threadlocals).
• Internal: Chameleon template renderers now accept two arguments: path and lookup. Lookup
will be an instance of a lookup class which supplies (late-bound) arguments for debug, reload, and
translate. Any third-party renderers which use (the non-API) function pyramid.renderers.
template_renderer_factory will need to adjust their implementations to obey the new call-
back argument list. This change was to kill off inappropriate use of threadlocals.

1.0a2 (2010-11-09)

Documentation

• All references to events by interface (e.g. pyramid.interfaces.INewRequest) have been


changed to reference their concrete classes (e.g. pyramid.events.NewRequest) in documen-
tation about making subscriptions.
• All references to Pyramid-the-application were changed from mod-pyramid to app-Pyramid. A
custom role setting was added to docs/conf.py to allow for this. (internal)

0.6. Change History 1099


The Pyramid Web Framework, Version 2.0.2

1.0a1 (2010-11-05)

Features (delta from BFG 1.3)

• Mako templating renderer supports resource specification format for template lookups and within
Mako templates. Absolute filenames must be used in Pyramid to avoid this lookup process.
• Add pyramid.httpexceptions module, which is a facade for the webob.exc module.
• Direct built-in support for the Mako templating language.
• A new configurator method exists: add_handler. This method adds a Pylons-style ”view han-
dler” (such a thing used to be called a ”controller” in Pylons 1.0).
• New argument to configurator: session_factory.
• New method on configurator: set_session_factory
• Using request.session now returns a (dictionary-like) session object if a session factory has
been configured.
• The request now has a new attribute: tmpl_context for benefit of Pylons users.
• The decorator previously known as pyramid.view.bfg_view is now known most formally as
pyramid.view.view_config in docs and paster templates. An import of pyramid.view.
bfg_view, however, will continue to work ”forever”.
• New API methods in pyramid.session: signed_serialize and
signed_deserialize.
• New interface: pyramid.interfaces.IRendererInfo. An object of this type is passed to
renderer factory constructors (see ”Backwards Incompatibilities”).
• New event type: pyramid.interfaces.IBeforeRender. An object of this type is sent as an
event before a renderer is invoked (but after the application-level renderer globals factory added via
pyramid.configurator.configuration.set_renderer_globals_factory, if
any, has injected its own keys). Applications may now subscribe to the IBeforeRender event
type in order to introspect the and modify the set of renderer globals before they are passed to a
renderer. The event object iself has a dictionary-like interface that can be used for this purpose. For
example:

from repoze.events import subscriber


from pyramid.interfaces import IRendererGlobalsEvent

@subscriber(IRendererGlobalsEvent)
def add_global(event):
event['mykey'] = 'foo'

1100 CONTENTS
The Pyramid Web Framework, Version 2.0.2

If a subscriber attempts to add a key that already exist in the renderer globals dictionary, a Key-
Error is raised. This limitation is due to the fact that subscribers cannot be ordered relative to
each other. The set of keys added to the renderer globals dictionary by all subscribers and app-level
globals factories must be unique.
• New class: pyramid.response.Response. This is a pure facade for webob.Response
(old code need not change to use this facade, it’s existence is mostly for vanity and documentation-
generation purposes).
• All preexisting paster templates (except zodb) now use ”imperative” configuration (starter,
routesalchemy, alchemy).
• A new paster template named pyramid_starter_zcml exists, which uses declarative configu-
ration.

Documentation (delta from BFG 1.3)

• Added a pyramid.httpexceptions API documentation chapter.


• Added a pyramid.session API documentation chapter.
• Added a Session Objects narrative documentation chapter.
• Added an API chapter for the pyramid.personality module.
• Added an API chapter for the pyramid.response module.
• All documentation which previously referred to webob.Response now uses pyramid.
response.Response instead.
• The documentation has been overhauled to use imperative configuration, moving declarative con-
figuration (ZCML) explanations to a separate narrative chapter declarative.rst.
• The ZODB Wiki tutorial was updated to take into account changes to the pyramid_zodb paster
template.
• The SQL Wiki tutorial was updated to take into account changes to the pyra-
mid_routesalchemy paster template.

Backwards Incompatibilities (with BFG 1.3)

• There is no longer an IDebugLogger registered as a named utility with the name repoze.bfg.
debug.
• The logger which used to have the name of repoze.bfg.debug now has the name pyramid.
debug.

0.6. Change History 1101


The Pyramid Web Framework, Version 2.0.2

• The deprecated API pyramid.testing.registerViewPermission has been removed.


• The deprecated API named pyramid.testing.registerRoutesMapper has been re-
moved.
• The deprecated API named pyramid.request.get_request was removed.
• The deprecated API named pyramid.security.Unauthorized was removed.
• The deprecated API named pyramid.view.view_execution_permitted was removed.
• The deprecated API named pyramid.view.NotFound was removed.
• The bfgshell paster command is now named pshell.
• The Venusian ”category” for all built-in Venusian decorators (e.g. subscriber and
view_config/bfg_view) is now pyramid instead of bfg.
• pyramid.renderers.rendered_response function removed; use render_pyramid.
renderers.render_to_response instead.
• Renderer factories now accept a renderer info object rather than an absolute resource specification or
an absolute path. The object has the following attributes: name (the renderer= value), package
(the ’current package’ when the renderer configuration statement was found), type: the renderer
type, registry: the current registry, and settings: the deployment settings dictionary.
Third-party repoze.bfg renderer implementations that must be ported to Pyramid will need to
account for this.
This change was made primarily to support more flexible Mako template rendering.
• The presence of the key repoze.bfg.message in the WSGI environment when an exception
occurs is now deprecated. Instead, code which relies on this environ value should use the excep-
tion attribute of the request (e.g. request.exception[0]) to retrieve the message.
• The values bfg_localizer and bfg_locale_name kept on the request during internation-
alization for caching purposes were never APIs. These however have changed to localizer and
locale_name, respectively.
• The default cookie_name value of the authtktauthenticationpolicy ZCML now de-
faults to auth_tkt (it used to default to repoze.bfg.auth_tkt).
• The default cookie_name value of the pyramid.authentication.
AuthTktAuthenticationPolicy constructor now defaults to auth_tkt (it used to
default to repoze.bfg.auth_tkt).
• The request_type argument to the view ZCML directive, the pyramid.configuration.
Configurator.add_view method, or the pyramid.view.view_config decorator (nee
bfg_view) is no longer permitted to be one of the strings GET, HEAD, PUT, POST or DELETE, and

1102 CONTENTS
The Pyramid Web Framework, Version 2.0.2

now must always be an interface. Accepting the method-strings as request_type was a back-
wards compatibility strategy servicing repoze.bfg 1.0 applications. Use the request_method
parameter instead to specify that a view a string request-method predicate.

0.6.10 repoze.bfg Change History (previous name for Pyramid)

1.3b1 (2010-10-25)

Features

• The paster template named bfg_routesalchemy has been updated to use SQLAlchemy
declarative syntax. Thanks to Ergo^.

Bug Fixes

• When a renderer factory could not be found, a misleading error message was raised if the renderer
name was not a string.

Documentation

• The ””bfgwiki2” (SQLAlchemy + url dispatch) tutorial has been updated slightly. In particular, the
source packages no longer attempt to use a private index, and the recommended Python version
is now 2.6. It was also updated to take into account the changes to the bfg_routesalchemy
template used to set up an environment.
• The ”bfgwiki” (ZODB + traversal) tutorial has been updated slightly. In particular, the source pack-
ages no longer attempt to use a private index, and the recommended Python version is now 2.6.

0.6. Change History 1103


The Pyramid Web Framework, Version 2.0.2

1.3a15 (2010-09-30)

Features

• The repoze.bfg.traversal.traversal_path API now eagerly attempts to encode a


Unicode path into ASCII before attempting to split it and decode its segments. This is for con-
venience, effectively to allow a (stored-as-Unicode-in-a-database, or retrieved-as-Unicode-from-a-
request-parameter) Unicode path to be passed to find_model, which eventually internally uses the
traversal_path function under the hood. In version 1.2 and prior, if the path was Unicode,
that Unicode was split on slashes and each resulting segment value was Unicode. An inappropriate
call to the decode() method of a resulting Unicode path segment could cause a UnicodeDe-
codeError to occur even if the Unicode representation of the path contained no ’high order’ char-
acters (it effectively did a ”double decode”). By converting the Unicode path argument to ASCII
before we attempt to decode and split, genuine errors will occur in a more obvious place while also
allowing us to handle (for convenience) the case that it’s a Unicode representation formed entirely
from ASCII-compatible characters.

1.3a14 (2010-09-14)

Bug Fixes

• If an exception view was registered through the legacy set_notfound_view or


set_forbidden_view APIs, the context sent to the view was incorrect (could be None
inappropriately).

Features

• Compatibility with WebOb 1.0.

Requirements

• Now requires WebOb >= 1.0.

1104 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• Due to changes introduced WebOb 1.0, the repoze.bfg.request.make_request_ascii


event subscriber no longer works, so it has been removed. This subscriber was meant to be used in a
deployment so that code written before BFG 0.7.0 could run unchanged. At this point, such code will
need to be rewritten to expect Unicode from request.GET, request.POST and request.
params or it will need to be changed to use request.str_POST, request.str_GET and/or
request.str_params instead of the non-str versions of same, as the non-str versions of
the same APIs always now perform decoding to Unicode.

Errata

• A prior changelog entry asserted that the INewResponse event was not sent to listeners if the
response was not ”valid” (if a view or renderer returned a response object that did not have a sta-
tus/headers/app_iter). This is not true in this release, nor was it true in 1.3a13.

1.3a13 (2010-09-14)

Bug Fixes

• The traverse route predicate could not successfully generate a traversal path.

Features

• In support of making it easier to configure applications which are ”secure by default”, a default
permission feature was added. If supplied, the default permission is used as the permission string to
all view registrations which don’t otherwise name a permission. These APIs are in support of that:
– A new constructor argument was added to the Configurator: default_permission.
– A new method was added to the Configurator: set_default_permission.
– A new ZCML directive was added: default_permission.
• Add a new request API: request.add_finished_callback. Finished callbacks are called
by the router unconditionally near the very end of request processing. See the ”Using Finished
Callbacks” section of the ”Hooks” narrative chapter of the documentation for more information.

0.6. Change History 1105


The Pyramid Web Framework, Version 2.0.2

• A request.matched_route attribute is now added to the request when a route has matched.
Its value is the ”route” object that matched (see the IRoute interface within repoze.bfg.
interfaces API documentation for the API of a route object).
• The exception attribute of the request is now set slightly earlier and in a slightly different set
of scenarios, for benefit of ”finished callbacks” and ”response callbacks”. In previous versions, the
exception attribute of the request was not set at all if an exception view was not found. In this
version, the request.exception attribute is set immediately when an exception is caught by
the router, even if an exception view could not be found.
• The add_route method of a Configurator now accepts a pregenerator argument. The pregen-
erator for the resulting route is called by route_url in order to adjust the set of arguments passed
to it by the user for special purposes, such as Pylons ’subdomain’ support. It will influence the URL
returned by route_url. See the repoze.bfg.interfaces.IRoutePregenerator in-
terface for more information.

Backwards Incompatibilities

• The router no longer sets the value wsgiorg.routing_args into the environ when a route
matches. The value used to be something like ((), matchdict). This functionality was only
ever obliquely referred to in change logs; it was never documented as an API.
• The exception attribute of the request now defaults to None. In prior versions, the request.
exception attribute did not exist if an exception was not raised by user code during request pro-
cessing; it only began existence once an exception view was found.

Deprecations

• The repoze.bfg.interfaces.IWSGIApplicationCreatedEvent event interface was


renamed to repoze.bfg.interfaces.IApplicationCreated. Likewise, the repoze.
bfg.events.WSGIApplicationCreatedEvent class was renamed to repoze.bfg.
events.ApplicationCreated. The older aliases will continue to work indefinitely.
• The repoze.bfg.interfaces.IAfterTraversal event interface was renamed to
repoze.bfg.interfaces.IContextFound. Likewise, the repoze.bfg.events.
AfterTraversal class was renamed to repoze.bfg.events.ContextFound. The older
aliases will continue to work indefinitely.
• References to the WSGI environment values bfg.routes.matchdict and bfg.routes.
route were removed from documentation. These will stick around internally for several more re-
leases, but it is request.matchdict and request.matched_route are now the ”official”
way to obtain the matchdict and the route object which resulted in the match.

1106 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• Added documentation for the default_permission ZCML directive.


• Added documentation for the default_permission constructor value and the
set_default_permission method in the Configurator API documentation.
• Added a new section to the ”security” chapter named ”Setting a Default Permission”.
• Document renderer_globals_factory and request_factory arguments to Configu-
rator constructor.
• Added two sections to the ”Hooks” chapter of the documentation: ”Using Response Callbacks” and
”Using Finished Callbacks”.
• Added documentation of the request.exception attribute to the repoze.bfg.request.
Request API documentation.
• Added glossary entries for ”response callback” and ”finished callback”.
• The ”Request Processing” narrative chapter has been updated to note finished and response callback
steps.
• New interface in interfaces API documentation: IRoutePregenerator.
• Added a ”The Matched Route” section to the URL Dispatch narrative docs chapter, detailing the
matched_route attribute.

1.3a12 (2010-09-08)

Bug Fixes

• Fix a bug in repoze.bfg.url.static_url URL generation: if two resource specifications


were used to create two separate static views, but they shared a common prefix, it was possible that
static_url would generate an incorrect URL.
• Fix another bug in repoze.bfg.static_url URL generation: too many slashes in generated
URL.
• Prevent a race condition which could result in a RuntimeError when rendering a Chameleon
template that has not already been rendered once. This would usually occur directly after a restart,
when more than one person or thread is trying to execute the same view at the same time: https:
//bugs.launchpad.net/karl3/+bug/621364

0.6. Change History 1107


The Pyramid Web Framework, Version 2.0.2

Features

• The argument to repoze.bfg.configuration.Configurator.add_route which was


previously called path is now called pattern for better explicability. For backwards compatibil-
ity purposes, passing a keyword argument named path to add_route will still work indefinitely.
• The path attribute to the ZCML route directive is now named pattern for better explicability.
The older path attribute will continue to work indefinitely.

Documentation

• All narrative, API, and tutorial docs which referred to a route pattern as a path have now been
updated to refer to them as a pattern.
• The repoze.bfg.interfaces API documentation page is now rendered via repoze.
sphinx.autointerface.
• The URL Dispatch narrative chapter now refers to the interfaces chapter to explain the API of
an IRoute object.

Paster Templates

• The routesalchemy template has been updated to use pattern in its route declarations rather than
path.

Dependencies

• tests_require now includes repoze.sphinx.autointerface as a dependency.

1108 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Internal

• Add an API to the Configurator named get_routes_mapper. This returns an object im-
plementing the IRoutesMapper interface.
• The repoze.bfg.urldispatch.RoutesMapper object now has a get_route method
which returns a single Route object or None.
• A new interface repoze.bfg.interfaces.IRoute was added. The repoze.bfg.
urldispatch.Route object implements this interface.
• The canonical attribute for accessing the routing pattern from a route object is now pattern rather
than path.
• Use hash() rather than id() when computing the ”phash” of a custom route/view predicate in
order to allow the custom predicate some control over which predicates are ”equal”.
• Use response.headerlist.append instead of response.headers.add in repoze.
bfg.request.add_global_response_headers in case the response is not a WebOb re-
sponse.
• The repoze.bfg.urldispatch.Route constructor (not an API) now accepts a different
ordering of arguments. Previously it was (pattern, name, factory=None, predi-
cates=()). It is now (name, pattern, factory=None, predicates=()). This is
in support of consistency with configurator.add_route.
• The repoze.bfg.urldispatch.RoutesMapper.connect method (not an API) now
accepts a different ordering of arguments. Previously it was (pattern, name,
factory=None, predicates=()). It is now (name, pattern, factory=None,
predicates=()). This is in support of consistency with configurator.add_route.

1.3a11 (2010-09-05)

Bug Fixes

• Process the response callbacks and the NewResponse event earlier, to enable mutations to the re-
sponse to take effect.

0.6. Change History 1109


The Pyramid Web Framework, Version 2.0.2

1.3a10 (2010-09-05)

Features

• A new repoze.bfg.request.Request.add_response_callback API has been


added. This method is documented in the new repoze.bfg.request API chapter. It can be
used to influence response values before a concrete response object has been created.
• The repoze.bfg.interfaces.INewResponse interface now includes a request at-
tribute; as a result, a handler for INewResponse now has access to the request which caused the
response.
• Each of the follow methods of the Configurator now allow the below-named arguments to be passed
as ”dotted name strings” (e.g. ”foo.bar.baz”) rather than as actual implementation objects that must
be imported:
setup_registry
root_factory, authentication_policy, authorization_policy, debug_logger, locale_negotiator,
request_factory, renderer_globals_factory
add_subscriber
subscriber, iface
derive_view
view
add_view
view, for_, context, request_type, containment
add_route()
view, view_for, factory, for_, view_context
scan
package
add_renderer
factory
set_forbidden_view
view
set_notfound_view
view
set_request_factory
factory
set_renderer_globals_factory()
factory

1110 CONTENTS
The Pyramid Web Framework, Version 2.0.2

set_locale_negotiator
negotiator
testing_add_subscriber
event_iface

Bug Fixes

• The route pattern registered internally for a local ”static view” (either via the static ZCML di-
rective or via the add_static_view method of the configurator) was incorrect. It was registered
for e.g. static*traverse, while it should have been registered for static/*traverse.
Symptom: two static views could not reliably be added to a system when they both shared the same
path prefix (e.g. /static and /static2).

Backwards Incompatibilities

• The INewResponse event is now not sent to listeners if the response returned by view code (or
a renderer) is not a ”real” response (e.g. if it does not have .status, .headerlist and .
app_iter attribtues).

Documentation

• Add an API chapter for the repoze.bfg.request module, which includes documentation for
the repoze.bfg.request.Request class (the ”request object”).
• Modify the ”Request and Response” narrative chapter to reference the new repoze.bfg.
request API chapter. Some content was moved from this chapter into the API documentation
itself.
• Various changes to denote that Python dotted names are now allowed as input to Configurator meth-
ods.

Internal

• The (internal) feature which made it possible to attach a global_response_headers attribute


to the request (which was assumed to contain a sequence of header key/value pairs which would later
be added to the response by the router), has been removed. The functionality of repoze.bfg.
request.Request.add_response_callback takes its place.
• The repoze.bfg.events.NewResponse class’s construct has changed: it now must be cre-
ated with (request, response) rather than simply (response).

0.6. Change History 1111


The Pyramid Web Framework, Version 2.0.2

1.3a9 (2010-08-22)

Features

• The Configurator now accepts a dotted name string to a package as a package constructor argu-
ment. The package argument was previously required to be a package object (not a dotted name
string).
• The repoze.bfg.configuration.Configurator.with_package method was added.
This method returns a new Configurator using the same application registry as the configurator object
it is called upon. The new configurator is created afresh with its package constructor argument set
to the value passed to with_package. This feature will make it easier for future BFG versions to
allow dotted names as arguments in places where currently only object references are allowed (the
work to allow dotted names instead of object references everywhere has not yet been done, however).
• The new repoze.bfg.configuration.Configurator.maybe_dotted method re-
solves a Python dotted name string supplied as its dotted argument to a global Python object.
If the value cannot be resolved, a repoze.bfg.configuration.ConfigurationError
is raised. If the value supplied as dotted is not a string, the value is returned unconditionally
without any resolution attempted.
• The new repoze.bfg.configuration.Configurator.
absolute_resource_spec method resolves a potentially relative ”resource specification”
string into an absolute version. If the value supplied as relative_spec is not a string, the value
is returned unconditionally without any resolution attempted.

Backwards Incompatibilities

• The functions in repoze.bfg.renderers named render and render_to_response in-


troduced in 1.3a6 previously took a set of **values arguments for the values to be passed to the
renderer. This was wrong, as renderers don’t need to accept only dictionaries (they can accept any
type of object). Now, the value sent to the renderer must be supplied as a positional argument named
value. The request argument is still a keyword argument, however.
• The functions in repoze.bfg.renderers named render and render_to_response
now accept an additional keyword argument named package.
• The get_renderer API in repoze.bfg.renderers now accepts a package argument.

1112 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• The ZCML include directive docs were incorrect: they specified filename rather than (the
correct) file as an allowable attribute.

Internal

• The repoze.bfg.resource.resolve_resource_spec function can now accept a pack-


age object as its pname argument instead of just a package name.
• The _renderer_factory_from_name and _renderer_from_name methods of the Con-
figurator were removed. These were never APIs.
• The _render, _render_to_response and _make_response functions with repoze.
bfg.render (added in 1.3a6) have been removed.
• A new helper class repoze.bfg.renderers.RendererHelper was added.
• The _map_view function of repoze.bfg.configuration now takes only a renderer_name
argument instead of both a renderer and renderer``_name argument. It also
takes a ``package argument now.
• Use imp.get_suffixes indirection in repoze.bfg.path.package_name instead of
hardcoded .py .pyc and .pyo to use for comparison when attempting to decide if a directory
is a package.
• Make tests runnable again under Jython (although they do not all pass currently).
• The reify decorator now maintains the docstring of the function it wraps.

1.3a8 (2010-08-08)

Features

• New public interface: repoze.bfg.exceptions.IExceptionResponse. This interface


is provided by all internal exception classes (such as repoze.bfg.exceptions.NotFound
and repoze.bfg.exceptions.Forbidden), instances of which are both exception objects
and can behave as WSGI response objects. This interface is made public so that exception classes
which are also valid WSGI response factories can be configured to implement them or exception
instances which are also or response instances can be configured to provide them.

0.6. Change History 1113


The Pyramid Web Framework, Version 2.0.2

• New API class: repoze.bfg.view.AppendSlashNotFoundViewFactory.


There can only be one Not Found view in any repoze.bfg application. Even if you use repoze.
bfg.view.append_slash_notfound_view as the Not Found view, repoze.bfg still
must generate a 404 Not Found response when it cannot redirect to a slash-appended URL;
this not found response will be visible to site users.
If you don’t care what this 404 response looks like, and you only need redirections to slash-appended
route URLs, you may use the repoze.bfg.view.append_slash_notfound_view object
as the Not Found view. However, if you wish to use a custom notfound view callable when a URL
cannot be redirected to a slash-appended URL, you may wish to use an instance of the repoze.
bfg.view.AppendSlashNotFoundViewFactory class as the Not Found view, supplying
the notfound view callable as the first argument to its constructor. For instance:

from repoze.bfg.exceptions import NotFound


from repoze.bfg.view import AppendSlashNotFoundViewFactory

def notfound_view(context, request):


return HTTPNotFound('It aint there, stop trying!')

custom_append_slash = AppendSlashNotFoundViewFactory(notfound_view)
config.add_view(custom_append_slash, context=NotFound)

The notfound_view supplied must adhere to the two-argument view callable calling convention
of (context, request) (context will be the exception object).

Documentation

• Expanded the ”Cleaning Up After a Request” section of the URL Dispatch narrative chapter.
• Expanded the ”Redirecting to Slash-Appended Routes” section of the URL Dispatch narrative chap-
ter.

Internal

• Previously, two default view functions were registered at Configurator setup (one for repoze.
bfg.exceptions.NotFound named default_notfound_view and one for repoze.
bfg.exceptions.Forbidden named default_forbidden_view) to render internal ex-
ception responses. Those default view functions have been removed, replaced with a generic default
view function which is registered at Configurator setup for the repoze.bfg.interfaces.
IExceptionResponse interface that simply returns the exception instance; the NotFound and
Forbidden classes are now still exception factories but they are also response factories which gen-
erate instances that implement the new repoze.bfg.interfaces.IExceptionResponse
interface.

1114 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.3a7 (2010-08-01)

Features

• The repoze.bfg.configuration.Configurator.add_route API now returns the


route object that was added.
• A repoze.bfg.events.subscriber decorator was added. This decorator decorates
module-scope functions, which are then treated as event listeners after a scan() is performed. See
the Events narrative documentation chapter and the repoze.bfg.events module documenta-
tion for more information.

Bug Fixes

• When adding a view for a route which did not yet exist (”did not yet exist” meaning, temporally, a
view was added with a route name for a route which had not yet been added via add_route), the value
of the custom_predicate argument to add_view was lost. Symptom: wrong view matches
when using URL dispatch and custom view predicates together.
• Pattern matches for a :segment marker in a URL dispatch route pattern now always match at least
one character. See ”Backwards Incompatibilities” below in this changelog.

Backwards Incompatibilities

• A bug existed in the regular expression to do URL matching. As an example, the URL matching
machinery would cause the pattern /{foo} to match the root URL / resulting in a match dictionary
of {'foo':u''} or the pattern /{fud}/edit might match the URL ``//edit
resulting in a match dictionary of {'fud':u''}. It was always the intent that :segment markers
in the pattern would need to match at least one character, and never match the empty string. This,
however, means that in certain circumstances, a routing match which your application inadvertently
depended upon may no longer happen.

Documentation

• Added description of the repoze.bfg.events.subscriber decorator to the Events narrative


chapter.
• Added repoze.bfg.events.subscriber API documentation to repoze.bfg.events
API docs.
• Added a section named ”Zope 3 Enforces ’TTW’ Authorization Checks By Default; BFG Does Not”
to the ”Design Defense” chapter.

0.6. Change History 1115


The Pyramid Web Framework, Version 2.0.2

1.3a6 (2010-07-25)

Features

• New argument to repoze.bfg.configuration.Configurator.add_route and the


route ZCML directive: traverse. If you would like to cause the context to be something
other than the root object when this route matches, you can spell a traversal pattern as the tra-
verse argument. This traversal pattern will be used as the traversal path: traversal will begin at
the root object implied by this route (either the global root, or the object returned by the factory
associated with this route).
The syntax of the traverse argument is the same as it is for path. For example, if the path pro-
vided is articles/:article/edit, and the traverse argument provided is /:article,
when a request comes in that causes the route to match in such a way that the article match value
is ’1’ (when the request URI is /articles/1/edit), the traversal path will be generated as /1.
This means that the root object’s __getitem__ will be called with the name 1 during the traversal
phase. If the 1 object exists, it will become the context of the request. The Traversal narrative
has more information about traversal.
If the traversal path contains segment marker names which are not present in the path argument, a
runtime error will occur. The traverse pattern should not contain segment markers that do not
exist in the path.
A similar combining of routing and traversal is available when a route is matched which contains a
*traverse remainder marker in its path. The traverse argument allows you to associate route
patterns with an arbitrary traversal path without using a *traverse remainder marker; instead
you can use other match information.
Note that the traverse argument is ignored when attached to a route that has a *traverse
remainder marker in its path.
• A new method of the Configurator exists: set_request_factory. If used, this method
will set the factory used by the repoze.bfg router to create all request objects.
• The Configurator constructor takes an additional argument: request_factory. If used,
this argument will set the factory used by the repoze.bfg router to create all request objects.
• The Configurator constructor takes an additional argument: request_factory. If used,
this argument will set the factory used by the repoze.bfg router to create all request objects.
• A new method of the Configurator exists: set_renderer_globals_factory. If used,
this method will set the factory used by the repoze.bfg router to create renderer globals.
• A new method of the Configurator exists: get_settings. If used, this method will
return the current settings object (performs the same job as the repoze.bfg.settings.
get_settings API).

1116 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The Configurator constructor takes an additional argument: ren-


derer_globals_factory. If used, this argument will set the factory used by the repoze.
bfg router to create renderer globals.
• Add repoze.bfg.renderers.render, repoze.bfg.renderers.
render_to_response and repoze.bfg.renderers.get_renderer functions.
These are imperative APIs which will use the same rendering machinery used by view configura-
tions with a renderer= attribute/argument to produce a rendering or renderer. Because these
APIs provide a central API for all rendering, they now form the preferred way to perform imperative
template rendering. Using functions named render_* from modules such as repoze.bfg.
chameleon_zpt and repoze.bfg.chameleon_text is now discouraged (although not
deprecated). The code the backing older templating-system-specific APIs now calls into the newer
repoze.bfg.renderer code.
• The repoze.bfg.configuration.Configurator.testing_add_template has
been renamed to testing_add_renderer. A backwards compatibility alias is present using
the old name.

Documentation

• The Hybrid narrative chapter now contains a description of the traverse route argument.
• The Hooks narrative chapter now contains sections about changing the request factory and adding
a renderer globals factory.
• The API documentation includes a new module: repoze.bfg.renderers.
• The Templates chapter was updated; all narrative that used templating-specific APIs
within examples to perform rendering (such as the repoze.bfg.chameleon_zpt.
render_template_to_response method) was changed to use repoze.bfg.
renderers.render_* functions.

Bug Fixes

• The header predicate (when used as either a view predicate or a route predicate) had a problem
when specified with a name/regex pair. When the header did not exist in the headers dictionary, the
regex match could be fed None, causing it to throw a TypeError: expected string or
buffer exception. Now, the predicate returns False as intended.

0.6. Change History 1117


The Pyramid Web Framework, Version 2.0.2

Deprecations

• The repoze.bfg.renderers.rendered_response function was never an official API,


but may have been imported by extensions in the wild. It is officially deprecated in this release. Use
repoze.bfg.renderers.render_to_response instead.
• The following APIs are documentation deprecated (meaning they are officially deprecated in doc-
umentation but do not raise a deprecation error upon their usage, and may continue to work for an
indefinite period of time):
In the repoze.bfg.chameleon_zpt module: get_renderer, get_template, ren-
der_template, render_template_to_response. The suggested alternatives are docu-
mented within the docstrings of those methods (which are still present in the documentation).
In the repoze.bfg.chameleon_text module: get_renderer, get_template, ren-
der_template, render_template_to_response. The suggested alternatives are docu-
mented within the docstrings of those methods (which are still present in the documentation).
In general, to perform template-related functions, one should now use the various methods in the
repoze.bfg.renderers module.

Backwards Incompatibilities

• A new internal exception class (not an API) named repoze.bfg.exceptions.


PredicateMismatch now exists. This exception is currently raised when no constituent
view of a multiview can be called (due to no predicate match). Previously, in this situation, a
repoze.bfg.exceptions.NotFound was raised. We provide backwards compatibility for
code that expected a NotFound to be raised when no predicates match by causing repoze.
bfg.exceptions.PredicateMismatch to inherit from NotFound. This will cause any
exception view registered for NotFound to be called when a predicate mismatch occurs, as was
the previous behavior.
There is however, one perverse case that will expose a backwards incompatibility. If 1) you had
a view that was registered as a member of a multiview 2) this view explicitly raised a NotFound
exception in order to proceed to the next predicate check in the multiview, that code will now behave
differently: rather than skipping to the next view match, a NotFound will be raised to the top-level
exception handling machinery instead. For code to be depending upon the behavior of a view raising
NotFound to proceed to the next predicate match, would be tragic, but not impossible, given that
NotFound is a public interface. repoze.bfg.exceptions.PredicateMismatch is not
a public API and cannot be depended upon by application code, so you should not change your
view code to raise PredicateMismatch. Instead, move the logic which raised the NotFound
exception in the view out into a custom view predicate.

1118 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• If, when you run your application’s unit test suite under BFG 1.3, a KeyError naming a tem-
plate or a ValueError indicating that a ’renderer factory’ is not registered may is raised (e.g.
ValueError: No factory for renderer named '.pt' when looking up
karl.views:templates/snippets.pt), you may need to perform some extra setup in your
test code.
The best solution is to use the repoze.bfg.configuration.Configurator.
testing_add_renderer (or, alternately the deprecated repoze.bfg.testing.
registerTemplateRenderer or registerDummyRenderer) API within the code
comprising each individual unit test suite to register a ”dummy” renderer for each of the templates
and renderers used by code under test. For example:

config = Configurator()
config.testing_add_renderer('karl.views:templates/snippets.pt')

This will register a basic dummy renderer for this particular missing template. The test-
ing_add_renderer API actually returns the renderer, but if you don’t care about how the render
is used, you don’t care about having a reference to it either.
A more rough way to solve the issue exists. It causes the ”real” template implementations to be used
while the system is under test, which is suboptimal, because tests will run slower, and unit tests won’t
actually be unit tests, but it is easier. Always ensure you call the setup_registry() method of
the Configurator . Eg:

reg = MyRegistry()
config = Configurator(registry=reg)
config.setup_registry()

Calling setup_registry only has an effect if you’re passing in a registry argument to the
Configurator constructor. setup_registry is called by the course of normal operations anyway
if you do not pass in a registry.
If your test suite isn’t using a Configurator yet, and is still using the older repoze.bfg.testing
APIs name setUp or cleanUp, these will register the renderers on your behalf.
A variant on the symptom for this theme exists: you may already be dutifully registering
a dummy template or renderer for a template used by the code you’re testing using test-
ing_register_renderer or registerTemplateRenderer, but (perhaps unbeknownst
to you) the code under test expects to be able to use a ”real” template renderer implementation to
retrieve or render another template that you forgot was being rendered as a side effect of calling the
code you’re testing. This happened to work because it found the real template while the system was
under test previously, and now it cannot. The solution is the same.
It may also help reduce confusion to use a resource specification to specify the template path in the
test suite and code rather than a relative path in either. A resource specification is unambiguous,

0.6. Change History 1119


The Pyramid Web Framework, Version 2.0.2

while a relative path needs to be relative to ”here”, where ”here” isn’t always well-defined (”here” in
a test suite may or may not be the same as ”here” in the code under test).

1.3a5 (2010-07-14)

Features

• New internal exception: repoze.bfg.exceptions.URLDecodeError. This URL is a sub-


class of the built-in Python exception named UnicodeDecodeError.
• When decoding a URL segment to Unicode fails, the exception raised is now repoze.bfg.
exceptions.URLDecodeError instead of UnicodeDecodeError. This makes it possible
to register an exception view invoked specifically when repoze.bfg cannot decode a URL.

Bug Fixes

• Fix regression in repoze.bfg.configuration.Configurator.add_static_view.


Before 1.3a4, view names that contained a slash were supported as route prefixes. 1.3a4 broke
this by trying to treat them as full URLs.

Documentation

• The repoze.bfg.exceptions.URLDecodeError exception was added to the exceptions


chapter of the API documentation.

Backwards Incompatibilities

• in previous releases, when a URL could not be decoded from UTF-8 during traversal, a
TypeError was raised. Now the error which is raised is a repoze.bfg.exceptions.
URLDecodeError.

1120 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.3a4 (2010-07-03)

Features

• Undocumented hook: make get_app and get_root of the repoze.bfg.paster.


BFGShellCommand hookable in cases where endware may interfere with the default versions.
• In earlier versions, a custom route predicate associated with a url dispatch route (each of the predicate
functions fed to the custom_predicates argument of repoze.bfg.configuration.
Configurator.add_route) has always required a 2-positional argument signature, e.g.
(context, request). Before this release, the context argument was always None.
As of this release, the first argument passed to a predicate is now a dictionary conventionally named
info consisting of route, and match. match is a dictionary: it represents the arguments
matched in the URL by the route. route is an object representing the route which was matched.
This is useful when predicates need access to the route match. For example:

def any_of(segment_name, *args):


def predicate(info, request):
if info['match'][segment_name] in args:
return True
return predicate

num_one_two_or_three = any_of('num, 'one', 'two', 'three')

add_route('num', '/:num', custom_predicates=(num_one_two_or_three,))

The route object is an object that has two useful attributes: name and path. The name attribute
is the route name. The path attribute is the route pattern. An example of using the route in a set
of route predicates:

def twenty_ten(info, request):


if info['route'].name in ('ymd', 'ym', 'y'):
return info['match']['year'] == '2010'

add_route('y', '/:year', custom_predicates=(twenty_ten,))


add_route('ym', '/:year/:month', custom_predicates=(twenty_ten,))
add_route('ymd', '/:year/:month:/day', custom_predicates=(twenty_ten,))

• The repoze.bfg.url.route_url API has changed. If a keyword _app_url is present in


the arguments passed to route_url, this value will be used as the protocol/hostname/port/leading
path prefix of the generated URL. For example, using an _app_url of http://example.
com:8080/foo would cause the URL http://example.com:8080/foo/fleeb/flub

0.6. Change History 1121


The Pyramid Web Framework, Version 2.0.2

to be returned from this function if the expansion of the route pattern associated with the
route_name expanded to /fleeb/flub.
• It is now possible to use a URL as the name argument fed to repoze.bfg.configuration.
Configurator.add_static_view. When the name argument is a URL, the repoze.
bfg.url.static_url API will generate join this URL (as a prefix) to a path including the
static file name. This makes it more possible to put static media on a separate webserver for produc-
tion, while keeping static media package-internal and served by the development webserver during
development.

Documentation

• The authorization chapter of the ZODB Wiki Tutorial (docs/tutorials/bfgwiki) was changed to
demonstrate authorization via a group rather than via a direct username (thanks to Alex Marandon).
• The authorization chapter of the SQLAlchemy Wiki Tutorial (docs/tutorials/bfgwiki2) was changed
to demonstrate authorization via a group rather than via a direct username.
• Redirect requests for tutorial sources to https://docs.pylonsproject.org/projects/pyramid/en/latest/
tutorials/wiki/index.html and https://docs.pylonsproject.org/projects/pyramid/en/latest/tutorials/
wiki2/index.html respectively.
• A section named Custom Route Predicates was added to the URL Dispatch narrative chap-
ter.
• The Static Resources chapter has been updated to mention using static_url to generate URLs
to external webservers.

Internal

• Removed repoze.bfg.static.StaticURLFactory in favor of a new abstraction revolving


around the (still-internal) repoze.bfg.static.StaticURLInfo helper class.

1.3a3 (2010-05-01)

Paster Templates

• The bfg_alchemy and bfg_routesalchemy templates no longer register a han-


dle_teardown event listener which calls DBSession.remove. This was found by Chris
Withers to be unnecessary.

1122 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• The ”bfgwiki2” (URL dispatch wiki) tutorial code and documentation was changed to remove the
handle_teardown event listener which calls DBSession.remove.
• Any mention of the handle_teardown event listener as used by the paster templates was removed
from the URL Dispatch narrative chapter.
• A section entitled Detecting Available Languages was added to the i18n narrative docs chapter.

1.3a2 (2010-04-28)

Features

• A locale negotiator no longer needs to be registered explicitly. The default locale negotiator at
repoze.bfg.i18n.default_locale_negotiator is now used unconditionally as... um,
the default locale negotiator.
• The default locale negotiator has become more complex.
– First, the negotiator looks for the _LOCALE_ attribute of the request object (possibly set by a
view or an event listener).
– Then it looks for the request.params['_LOCALE_'] value.
– Then it looks for the request.cookies['_LOCALE_'] value.

Backwards Incompatibilities

• The default locale negotiator now looks for the parameter named _LOCALE_ rather than a parameter
named locale in request.params.

Behavior Changes

• A locale negotiator may now return None, signifying that the default locale should be used.

0.6. Change History 1123


The Pyramid Web Framework, Version 2.0.2

Documentation

• Documentation concerning locale negotiation in the Internationalizationa and Localization chapter


was updated.
• Expanded portion of i18n narrative chapter docs which discuss working with gettext files.

1.3a1 (2010-04-26)

Features

• Added ”exception views”. When you use an exception (anything that inherits from the Python Ex-
ception builtin) as view context argument, e.g.:

from repoze.bfg.view import bfg_view


from repoze.bfg.exceptions import NotFound
from webob.exc import HTTPNotFound

@bfg_view(context=NotFound)
def notfound_view(request):
return HTTPNotFound()

For the above example, when the repoze.bfg.exceptions.NotFound exception is raised


by any view or any root factory, the notfound_view view callable will be invoked and its response
returned.
Other normal view predicates can also be used in combination with an exception view registration:

from repoze.bfg.view import bfg_view


from repoze.bfg.exceptions import NotFound
from webob.exc import HTTPNotFound

@bfg_view(context=NotFound, route_name='home')
def notfound_view(request):
return HTTPNotFound()

The above exception view names the route_name of home, meaning that it will only be called
when the route matched has a name of home. You can therefore have more than one exception view
for any given exception in the system: the ”most specific” one will be called when the set of request
circumstances which match the view registration. The only predicate that cannot be not be used
successfully is name. The name used to look up an exception view is always the empty string.

1124 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Existing (pre-1.3) normal views registered against objects inheriting from Exception will con-
tinue to work. Exception views used for user-defined exceptions and system exceptions used as
contexts will also work.
The feature can be used with any view registration mechanism (@bfg_view decorator, ZCML, or
imperative config.add_view styles).
This feature was kindly contributed by Andrey Popp.
• Use ”Venusian” (https://docs.pylonsproject.org/projects/venusian/en/latest/) to perform
bfg_view decorator scanning rather than relying on a BFG-internal decorator scanner. (Truth be
told, Venusian is really just a generalization of the BFG-internal decorator scanner).
• Internationalization and localization features as documented in the narrative documentation chapter
entitled Internationalization and Localization.
• A new deployment setting named default_locale_name was added. If this string is present
as a Paster .ini file option, it will be considered the default locale name. The default locale name
is used during locale-related operations such as language translation.
• It is now possible to turn on Chameleon template ”debugging mode” for all Chameleon BFG tem-
plates by setting a BFG-related Paster .ini file setting named debug_templates. The ex-
ceptions raised by Chameleon templates when a rendering fails are sometimes less than helpful.
debug_templates allows you to configure your application development environment so that
exceptions generated by Chameleon during template compilation and execution will contain more
helpful debugging information. This mode is on by default in all new projects.
• Add a new method of the Configurator named derive_view which can be used to generate
a BFG view callable from a user-supplied function, instance, or class. This useful for external
framework and plugin authors wishing to wrap callables supplied by their users which follow the
same calling conventions and response conventions as objects that can be supplied directly to BFG
as a view callable. See the derive_view method in the repoze.bfg.configuration.
Configurator docs.

ZCML

• Add a translationdir ZCML directive to support localization.


• Add a localenegotiator ZCML directive to support localization.

0.6. Change History 1125


The Pyramid Web Framework, Version 2.0.2

Deprecations

• The exception views feature replaces the need for the set_notfound_view and
set_forbidden_view methods of the Configurator as well as the notfound and
forbidden ZCML directives. Those methods and directives will continue to work for the
foreseeable future, but they are deprecated in the documentation.

Dependencies

• A new install-time dependency on the venusian distribution was added.


• A new install-time dependency on the translationstring distribution was added.
• Chameleon 1.2.3 or better is now required (internationalization and per-template debug settings).

Internal

• View registrations and lookups are now done with three ”requires” arguments instead of two to
accommodate orthogonality of exception views.
• The repoze.bfg.interfaces.IForbiddenView and repoze.bfg.interfaces.
INotFoundView interfaces were removed; they weren’t APIs and they became vestigial with the
addition of exception views.
• Remove repoze.bfg.compat.pkgutil_26.py and import alias repoze.bfg.compat.
walk_packages. These were only required by internal scanning machinery; Venusian replaced
the internal scanning machinery, so these are no longer required.

Documentation

• Exception view documentation was added to the Hooks narrative chapter.


• A new narrative chapter entitled Internationalization and Localization was added.
• The ”Environment Variables and ini File Settings” chapter was changed: documentation about the
default_locale_name setting was added.
• A new API chapter for the repoze.bfg.i18n module was added.
• Documentation for the new translationdir and localenegotiator ZCML directives
were added.
• A section was added to the Templates chapter entitled ”Nicer Exceptions in Templates” describing
the result of setting debug_templates = true.

1126 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Paster Templates

• All paster templates now create a setup.cfg which includes commands related to nose testing
and Babel message catalog extraction/compilation.
• A default_locale_name = en setting was added to each existing paster template.
• A debug_templates = true setting was added to each existing paster template.

Licensing

• The Edgewall (BSD) license was added to the LICENSES.txt file, as some code in the repoze.
bfg.i18n derives from Babel source.

1.2 (2010-02-10)

• No changes from 1.2b6.

1.2b6 (2010-02-06)

Backwards Incompatibilities

• Remove magical feature of repoze.bfg.url.model_url which prepended a fully-expanded


urldispatch route URL before a the model’s path if it was noticed that the request had matched a
route. This feature was ill-conceived, and didn’t work in all scenarios.

Bug Fixes

• More correct conversion of provided renderer values to resource specification values (internal).

0.6. Change History 1127


The Pyramid Web Framework, Version 2.0.2

1.2b5 (2010-02-04)

Bug Fixes

• 1.2b4 introduced a bug whereby views added via a route configuration that named a view callable
and also a view_attr became broken. Symptom: MyViewClass is not callable or the
__call__ of a class was being called instead of the method named via view_attr.
• Fix a bug whereby a renderer argument to the @bfg_view decorator that provided a package-
relative template filename might not have been resolved properly. Symptom: inappropriate Miss-
ing template resource errors.

1.2b4 (2010-02-03)

Documentation

• Update GAE tutorial to use Chameleon instead of Jinja2 (now that it’s possible).

Bug Fixes

• Ensure that secure flag for AuthTktAuthenticationPolicy constructor does what it’s documented
to do (merge Daniel Holth’s fancy-cookies-2 branch).

Features

• Add path and http_only options to AuthTktAuthenticationPolicy constructor (merge Daniel


Holth’s fancy-cookies-2 branch).

Backwards Incompatibilities

• Remove view_header, view_accept, view_xhr, view_path_info,


view_request_method, view_request_param, and view_containment predi-
cate arguments from the Configurator.add_route argument list. These arguments were
speculative. If you need the features exposed by these arguments, add a view associated with a
route using the route_name argument to the add_view method instead.
• Remove view_header, view_accept, view_xhr, view_path_info,
view_request_method, view_request_param, and view_containment predi-
cate arguments from the route ZCML directive attribute set. These attributes were speculative.
If you need the features exposed by these attributes, add a view associated with a route using the
route_name attribute of the view ZCML directive instead.

1128 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Dependencies

• Remove dependency on sourcecodegen (not depended upon by Chameleon 1.1.1+).

1.2b3 (2010-01-24)

Bug Fixes

• When ”hybrid mode” (both traversal and urldispatch) is in use, default to finding route-related views
even if a non-route-related view registration has been made with a more specific context. The default
used to be to find views with a more specific context first. Use the new use_global_views
argument to the route definition to get back the older behavior.

Features

• Add use_global_views argument to add_route method of Configurator. When this argu-


ment is true, views registered for no route will be found if no more specific view related to the route
is found.
• Add use_global_views attribute to ZCML <route> directive (see above).

Internal

• When registering a view, register the view adapter with the ”requires” interfaces as
(request_type, context_type) rather than (context_type, request_type).
This provides for saner lookup, because the registration will always be made with a specific request
interface, but registration may not be made with a specific context interface. In general, when cre-
ating multiadapters, you want to order the requires interfaces so that the elements which are more
likely to be registered using specific interfaces are ordered before those which are less likely.

0.6. Change History 1129


The Pyramid Web Framework, Version 2.0.2

1.2b2 (2010-01-21)

Bug Fixes

• When the Configurator is passed an instance of zope.component.registry.


Components as a registry constructor argument, fix the instance up to have the attributes
we expect of an instance of repoze.bfg.registry.Registry when setup_registry
is called. This makes it possible to use the global Zope component registry as a BFG application
registry.
• When WebOb 0.9.7.1 was used, a deprecation warning was issued for the class attribute named
charset within repoze.bfg.request.Request. BFG now requires WebOb >= 0.9.7, and
code was added so that this deprecation warning has disappeared.
• Fix a view lookup ordering bug whereby a view with a larger number of predicates registered first
(literally first, not ”earlier”) for a triad would lose during view lookup to one registered with fewer.
• Make sure views with exactly N custom predicates are always called before views with exactly N
non-custom predicates given all else is equal in the view configuration.

Documentation

• Change renderings of ZCML directive documentation.


• Add a narrative documentation chapter: ”Using the Zope Component Architecture in repoze.bfg”.

Dependencies

• Require WebOb >= 0.9.7

1.2b1 (2010-01-18)

Bug Fixes

• In bfg_routesalchemy, bfg_alchemy paster templates and the bfgwiki2 tutorial, clean


up the SQLAlchemy connection by registering a repoze.tm.after_end callback instead of
relying on a __del__ method of a Cleanup class added to the WSGI environment. The __del__
strategy was fragile and caused problems in the wild. Thanks to Daniel Holth for testing.

1130 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Features

• Read logging configuration from PasteDeploy config file loggers section (and related) when
paster bfgshell is invoked.

Documentation

• Major rework in preparation for book publication.

1.2a11 (2010-01-05)

Bug Fixes

• Make paster bfgshell and paster create -t bfg_xxx work on Jython (fix minor
incompatibility with treatment of __doc__ at the class level).
• Updated dependency on WebOb to require a version which supports features now used in tests.

Features

• Jython compatibility (at least when repoze.bfg.jinja2 is used as the templating engine; Chameleon
does not work under Jython).
• Show the derived abspath of template resource specifications in the traceback when a renderer tem-
plate cannot be found.
• Show the original traceback when a Chameleon template cannot be rendered due to a platform in-
compatibility.

0.6. Change History 1131


The Pyramid Web Framework, Version 2.0.2

1.2a10 (2010-01-04)

Features

• The Configurator.add_view method now accepts an argument named context. This is an


alias for the older argument named for_; it is preferred over for_, but for_ will continue to be
supported ”forever”.
• The view ZCML directive now accepts an attribute named context. This is an alias for the older
attribute named for; it is preferred over for, but for will continue to be supported ”forever”.
• The Configurator.add_route method now accepts an argument named view_context.
This is an alias for the older argument named view_for; it is preferred over view_for, but
view_for will continue to be supported ”forever”.
• The route ZCML directive now accepts an attribute named view_context. This is an alias
for the older attribute named view_for; it is preferred over view_for, but view_for will
continue to be supported ”forever”.

Documentation and Paster Templates

• LaTeX rendering tweaks.


• All uses of the Configurator.add_view method that used its for_ argument now use the
context argument instead.
• All uses of the Configurator.add_route method that used its view_for argument now
use the view_context argument instead.
• All uses of the view ZCML directive that used its for attribute now use the context attribute
instead.
• All uses of the route ZCML directive that used its view_for attribute now use the
view_context attribute instead.
• Add a (minimal) tutorial dealing with use of repoze.catalog in a repoze.bfg application.

Documentation Licensing

• Loosen the documentation licensing to allow derivative works: it is now offered under the Cre-
ative Commons Attribution-Noncommercial-Share Alike 3.0 United States License. This is only a
documentation licensing change; the repoze.bfg software continues to be offered under the Re-
poze Public License at https://web.archive.org/web/20190401024809/http://repoze.org/license.html
(BSD-like).

1132 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.2a9 (2009-12-27)

Documentation Licensing

• The documentation (the result of make <html|latex|htmlhelp> within the docs direc-
tory) in this release is now offered under the Creative Commons Attribution-Noncommercial-No
Derivative Works 3.0 United States License as described by https://creativecommons.org/licenses/
by-nc-nd/3.0/us/ . This is only a licensing change for the documentation; the repoze.bfg
software continues to be offered under the Repoze Public License at https://web.archive.org/web/
20190401024809/http://repoze.org/license.html (BSD-like).

Documentation

• Added manual index entries to generated index.


• Document the previously existing (but non-API) repoze.bfg.configuration.
Configurator.setup_registry method as an official API of a Configurator.
• Fix syntax errors in various documentation code blocks.
• Created new top-level documentation section: ”ZCML Directives”. This section contains detailed
ZCML directive information, some of which was removed from various narrative chapters.
• The LaTeX rendering of the documentation has been improved.
• Added a ”Fore-Matter” section with author, copyright, and licensing information.

1.2a8 (2009-12-24)

Features

• Add a **kw arg to the Configurator.add_settings API.


• Add hook_zca and unhook_zca methods to the Configurator API.
• The repoze.bfg.testing.setUp method now returns a Configurator instance which
can be used to do further configuration during unit tests.

0.6. Change History 1133


The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• The json renderer failed to set the response content type to application/json. It now does,
by setting request.response_content_type unless this attribute is already set.
• The string renderer failed to set the response content type to text/plain. It now does, by
setting request.response_content_type unless this attribute is already set.

Documentation

• General documentation improvements by using better Sphinx roles such as ”class”, ”func”, ”meth”,
and so on. This means that there are many more hyperlinks pointing to API documentation for API
definitions in all narrative, tutorial, and API documentation elements.
• Added a description of imperative configuration in various places which only described ZCML con-
figuration.
• A syntactical refreshing of various tutorials.
• Added the repoze.bfg.authentication, repoze.bfg.authorization, and
repoze.bfg.interfaces modules to API documentation.

Deprecations

• The repoze.bfg.testing.registerRoutesMapper API (added in an early 1.2 alpha)


was deprecated. Its import now generates a deprecation warning.

1.2a7 (2009-12-20)

Features

• Add four new testing-related APIs to the repoze.bfg.configuration.Configurator


class: testing_securitypolicy, testing_models, testing_add_subscriber,
and testing_add_template. These were added in order to provide more direct access to the
functionality of the repoze.bfg.testing APIs named registerDummySecurityPol-
icy, registerModels, registerEventListener, and registerTemplateRen-
derer when a configurator is used. The testing APIs named are nominally deprecated (although
they will likely remain around ”forever”, as they are in heavy use in the wild).

1134 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Add a new API to the repoze.bfg.configuration.Configurator class:


add_settings. This API can be used to add ”settings” (information returned within via
the repoze.bfg.settings.get_settings API) after the configurator has been initially
set up. This is most useful for testing purposes.
• Add a custom_predicates argument to the Configurator add_view method, the
bfg_view decorator and the attribute list of the ZCML view directive. If cus-
tom_predicates is specified, it must be a sequence of predicate callables (a predicate callable
accepts two arguments: context and request and returns True or False). The associated
view callable will only be invoked if all custom predicates return True. Use one or more custom
predicates when no existing predefined predicate is useful. Predefined and custom predicates can be
mixed freely.
• Add a custom_predicates argument to the Configurator add_route and the attribute
list of the ZCML route directive. If custom_predicates is specified, it must be a sequence
of predicate callables (a predicate callable accepts two arguments: context and request and
returns True or False). The associated route will match will only be invoked if all custom pred-
icates return True, else route matching continues. Note that the value context will always be
None when passed to a custom route predicate. Use one or more custom predicates when no exist-
ing predefined predicate is useful. Predefined and custom predicates can be mixed freely.

Internal

• Remove the repoze.bfg.testing.registerTraverser function. This function was


never an API.

Documentation

• Doc-deprecated most helper functions in the repoze.bfg.testing module. These helper func-
tions likely won’t be removed any time soon, nor will they generate a warning any time soon, due to
their heavy use in the wild, but equivalent behavior exists in methods of a Configurator.

1.2a6 (2009-12-18)

Features

• The Configurator object now has two new methods: begin and end. The begin method is
meant to be called before any ”configuration” begins (e.g. before add_view, et. al are called). The
end method is meant to be called after all ”configuration” is complete.

0.6. Change History 1135


The Pyramid Web Framework, Version 2.0.2

Previously, before there was imperative configuration at all (1.1 and prior), configuration begin and
end was invariably implied by the process of loading a ZCML file. When a ZCML load happened, the
threadlocal data structure containing the request and registry was modified before the load, and torn
down after the load, making sure that all framework code that needed get_current_registry
for the duration of the ZCML load was satisfied.
Some API methods called during imperative configuration, (such as Configurator.add_view
when a renderer is involved) end up for historical reasons calling get_current_registry.
However, in 1.2a5 and below, the Configurator supplied no functionality that allowed people to make
sure that get_current_registry returned the registry implied by the configurator being used.
begin now serves this purpose. Inversely, end pops the thread local stack, undoing the actions of
begin.
We make this boundary explicit to reduce the potential for confusion when the configurator is used
in different circumstances (e.g. in unit tests and app code vs. just in initial app setup).
Existing code written for 1.2a1-1.2a5 which does not call begin or end continues to work in the
same manner it did before. It is however suggested that this code be changed to call begin and end
to reduce the potential for confusion in the future.
• All paster templates which generate an application skeleton now make use of the new begin and
end methods of the Configurator they use in their respective copies of run.py and tests.py.

Documentation

• All documentation that makes use of a Configurator object to do application setup and test
setup now makes use of the new begin and end methods of the configurator.

Bug Fixes

• When a repoze.bfg.exceptions.NotFound or repoze.bfg.exceptions.


Forbidden class (as opposed to instance) was raised as an exception within a root factory
(or route root factory), the exception would not be caught properly by the repoze.bfg. Router
and it would propagate to up the call stack, as opposed to rendering the not found view or the
forbidden view as would have been expected.
• When Chameleon page or text templates used as renderers were added imperatively (via
Configurator.add_view or some derivative), they too-eagerly attempted to look up the
reload_templates setting via get_settings, meaning they were always registered in non-
auto-reload-mode (the default). Each now waits until its respective template attribute is accessed
to look up the value.
• When a route with the same name as a previously registered route was added, the old route was
not removed from the mapper’s routelist. Symptom: the old registered route would be used (and
possibly matched) during route lookup when it should not have had a chance to ever be used.

1136 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.2a5 (2009-12-10)

Features

• When the repoze.bfg.exceptions.NotFound or repoze.bfg.exceptions.


Forbidden error is raised from within a custom root factory or the factory of a route, the
appropriate response is now sent to the requesting user agent (the result of the notfound view or
the forbidden view, respectively). When these errors are raised from within a root factory, the
context passed to the notfound or forbidden view will be None. Also, the request will not be
decorated with view_name, subpath, context, etc. as would normally be the case if traversal
had been allowed to take place.

Internals

• The exception class representing the error raised by various methods of a Configurator is now
importable as repoze.bfg.exceptions.ConfigurationError.

Documentation

• General documentation freshening which takes imperative configuration into account in more places
and uses glossary references more liberally.
• Remove explanation of changing the request type in a new request event subscriber, as other predi-
cates are now usually an easier way to get this done.
• Added ”Thread Locals” narrative chapter to documentation, and added a API chapter documenting
the repoze.bfg.threadlocals module.
• Added a ”Special Exceptions” section to the ”Views” narrative documentation chapter explaining the
effect of raising repoze.bfg.exceptions.NotFound and repoze.bfg.exceptions.
Forbidden from within view code.

Dependencies

• A new dependency on the twill package was added to the setup.py tests_require ar-
gument (Twill will only be downloaded when repoze.bfg setup.py test or setup.py
nosetests is invoked).

0.6. Change History 1137


The Pyramid Web Framework, Version 2.0.2

1.2a4 (2009-12-07)

Features

• repoze.bfg.testing.DummyModel now accepts a new constructor keyword argument:


__provides__. If this constructor argument is provided, it should be an interface or a tuple
of interfaces. The resulting model will then provide these interfaces (they will be attached to the
constructed model via zope.interface.alsoProvides).

Bug Fixes

• Operation on GAE was broken, presumably because the repoze.bfg.configuration


module began to attempt to import the repoze.bfg.chameleon_zpt and repoze.bfg.
chameleon_text modules, and these cannot be used on non-CPython platforms. It now toler-
ates startup time import failures for these modules, and only raise an import error when a template
from one of these packages is actually used.

1.2a3 (2009-12-02)

Bug Fixes

• The repoze.bfg.url.route_url function inappropriately passed along _query and/or


_anchor arguments to the mapper.generate function, resulting in blowups.
• When two views were registered with differering for interfaces or classes, and the for of first view
registered was a superclass of the second, the repoze.bfg view machinery would incorrectly
associate the two views with the same ”multiview”. Multiviews are meant to be collections of views
that have exactly the same for/request/viewname values, without taking inheritance into account.
Symptom: wrong view callable found even when you had correctly specified a for_ interface/class
during view configuration for one or both view configurations.

Backwards Incompatibilities

• The repoze.bfg.templating module has been removed; it had been deprecated in 1.1 and
never actually had any APIs in it.

1138 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.2a2 (2009-11-29)

Bug Fixes

• The long description of this package (as shown on PyPI) was not valid reStructuredText, and so was
not renderable.
• Trying to use an HTTP method name string such as GET as a request_type predicate argument
caused a startup time failure when it was encountered in imperative configuration or in a decorator
(symptom: Type Error: Required specification must be a specification).
This now works again, although request_method is now the preferred predicate argument for
associating a view configuration with an HTTP request method.

Documentation

• Fixed ”Startup” narrative documentation chapter; it was explaining ”the old way” an application
constructor worked.

1.2a1 (2009-11-28)

Features

• An imperative configuration mode.


A repoze.bfg application can now begin its life as a single Python file. Later, the application
might evolve into a set of Python files in a package. Even later, it might start making use of other
configuration features, such as ZCML. But neither the use of a package nor the use of non-imperative
configuration is required to create a simple repoze.bfg application any longer.
Imperative configuration makes repoze.bfg competitive with ”microframeworks” such as Bottle
and Tornado. repoze.bfg has a good deal of functionality that most microframeworks lack, so
this is hopefully a ”best of both worlds” feature.
The simplest possible repoze.bfg application is now:

0.6. Change History 1139


The Pyramid Web Framework, Version 2.0.2

from webob import Response


from wsgiref import simple_server
from repoze.bfg.configuration import Configurator

def hello_world(request):
return Response('Hello world!')

if __name__ == '__main__':
config = Configurator()
config.add_view(hello_world)
app = config.make_wsgi_app()
simple_server.make_server('', 8080, app).serve_forever()

• A new class now exists: repoze.bfg.configuration.Configurator. This class forms


the basis for sharing machinery between ”imperatively” configured applications and traditional
declaratively-configured applications.
• The repoze.bfg.testing.setUp function now accepts three extra optional keyword argu-
ments: registry, request and hook_zca.
If the registry argument is not None, the argument will be treated as the registry
that is set as the ”current registry” (it will be returned by repoze.bfg.threadlocal.
get_current_registry) for the duration of the test. If the registry argument is None
(the default), a new registry is created and used for the duration of the test.
The value of the request argument is used as the ”current request” (it will be returned by
repoze.bfg.threadlocal.get_current_request) for the duration of the test; it de-
faults to None.
If hook_zca is True (the default), the zope.component.getSiteManager func-
tion will be hooked with a function that returns the value of registry (or the default-
created registry if registry is None) instead of the registry returned by zope.
component.getGlobalSiteManager, causing the Zope Component Architecture API
(getSiteManager, getAdapter, getUtility, and so on) to use the testing registry instead
of the global ZCA registry.
• The repoze.bfg.testing.tearDown function now accepts an unhook_zca argument. If
this argument is True (the default), zope.component.getSiteManager.reset() will
be called. This will cause the result of the zope.component.getSiteManager function to
be the global ZCA registry (the result of zope.component.getGlobalSiteManager) once
again.
• The run.py module in various repoze.bfg paster templates now use a repoze.bfg.
configuration.Configurator class instead of the (now-legacy) repoze.bfg.router.
make_app function to produce a WSGI application.

1140 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• The documentation now uses the ”request-only” view calling convention in most examples (as
opposed to the context, request convention). This is a documentation-only change; the
context, request convention is also supported and documented, and will be ”forever”.
• repoze.bfg.configuration API documentation has been added.
• A narrative documentation chapter entitled ”Creating Your First repoze.bfg Application”
has been added. This chapter details usage of the new repoze.bfg.configuration.
Configurator class, and demonstrates a simplified ”imperative-mode” configuration; doing
repoze.bfg application configuration imperatively was previously much more difficult.
• A narrative documentation chapter entitled ”Configuration, Decorations and Code Scanning” ex-
plaining ZCML- vs. imperative- vs. decorator-based configuration equivalence.
• The ”ZCML Hooks” chapter has been renamed to ”Hooks”; it documents how to override hooks
now via imperative configuration and ZCML.
• The explanation about how to supply an alternate ”response factory” has been removed from the
”Hooks” chapter. This feature may be removed in a later release (it still works now, it’s just not
documented).
• Add a section entitled ”Test Set Up and Tear Down” to the unittesting chapter.

Bug Fixes

• The ACL authorization policy debugging output when debug_authorization console debug-
ging output was turned on wasn’t as clear as it could have been when a view execution was denied
due to an authorization failure resulting from the set of principals passed never having matched any
ACE in any ACL in the lineage. Now in this case, we report <default deny> as the ACE value
and either the root ACL or <No ACL found on any object in model lineage> if no
ACL was found.
• When two views were registered with the same accept argument, but were otherwise registered
with the same arguments, if a request entered the application which had an Accept header that
accepted either of the media types defined by the set of views registered with predicates that oth-
erwise matched, a more or less ”random” one view would ”win”. Now, we try harder to use the
view callable associated with the view configuration that has the most specific accept argument.
Thanks to Alberto Valverde for an initial patch.

0.6. Change History 1141


The Pyramid Web Framework, Version 2.0.2

Internals

• The routes mapper is no longer a root factory wrapper. It is now consulted directly by the router.
• The repoze.bfg.registry.make_registry callable has been removed.
• The repoze.bfg.view.map_view callable has been removed.
• The repoze.bfg.view.owrap_view callable has been removed.
• The repoze.bfg.view.predicate_wrap callable has been removed.
• The repoze.bfg.view.secure_view callable has been removed.
• The repoze.bfg.view.authdebug_view callable has been removed.
• The repoze.bfg.view.renderer_from_name callable has been removed. Use repoze.
bfg.configuration.Configurator.renderer_from_name instead (still not an API,
however).
• The repoze.bfg.view.derive_view callable has been removed. Use repoze.bfg.
configuration.Configurator.derive_view instead (still not an API, however).
• The repoze.bfg.settings.get_options callable has been removed. Its job has been sub-
sumed by the repoze.bfg.settings.Settings class constructor.
• The repoze.bfg.view.requestonly function has been moved to repoze.bfg.
configuration.requestonly.
• The repoze.bfg.view.rendered_response function has been moved to repoze.bfg.
configuration.rendered_response.
• The repoze.bfg.view.decorate_view function has been moved to repoze.bfg.
configuration.decorate_view.
• The repoze.bfg.view.MultiView class has been moved to repoze.bfg.
configuration.MultiView.
• The repoze.bfg.zcml.Uncacheable class has been removed.
• The repoze.bfg.resource.resource_spec function has been removed.
• All ZCML directives which deal with attributes which are paths now use the path method of the
ZCML context to resolve a relative name to an absolute one (imperative configuration requirement).
• The repoze.bfg.scripting.get_root API now uses a ’real’ WebOb request rather than a
FakeRequest when it sets up the request as a threadlocal.
• The repoze.bfg.traversal.traverse API now uses a ’real’ WebOb request rather than a
FakeRequest when it calls the traverser.
• The repoze.bfg.request.FakeRequest class has been removed.

1142 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Most uses of the ZCA threadlocal API (the getSiteManager, getUtility, getAdapter,
getMultiAdapter threadlocal API) have been removed from the core. Instead, when a threadlo-
cal is necessary, the core uses the repoze.bfg.threadlocal.get_current_registry
API to obtain the registry.
• The internal ILogger utility named repoze.bfg.debug is now just an IDebugLogger unnamed
utility. A named utility with the old name is registered for b/w compat.
• The repoze.bfg.interfaces.ITemplateRendererFactory interface was removed; it
has become unused.
• Instead of depending on the martian package to do code scanning, we now just use our own
scanning routines.
• We now no longer have a dependency on repoze.zcml package; instead, the repoze.bfg
package includes implementations of the adapter, subscriber and utility directives.
• Relating to the following functions:
repoze.bfg.view.render_view
repoze.bfg.view.render_view_to_iterable
repoze.bfg.view.render_view_to_response
repoze.bfg.view.append_slash_notfound_view
repoze.bfg.view.default_notfound_view
repoze.bfg.view.default_forbidden_view
repoze.bfg.configuration.rendered_response
repoze.bfg.security.has_permission
repoze.bfg.security.authenticated_userid
repoze.bfg.security.effective_principals
repoze.bfg.security.view_execution_permitted
repoze.bfg.security.remember
repoze.bfg.security.forget
repoze.bfg.url.route_url
repoze.bfg.url.model_url
repoze.bfg.url.static_url
repoze.bfg.traversal.virtual_root

0.6. Change History 1143


The Pyramid Web Framework, Version 2.0.2

Each of these functions now expects to be called with a request object that has a registry attribute
which represents the current repoze.bfg registry. They fall back to obtaining the registry from
the threadlocal API.

Backwards Incompatibilities

• Unit tests which use zope.testing.cleanup.cleanUp for the purpose of isolating tests from
one another may now begin to fail due to lack of isolation between tests.
Here’s why: In repoze.bfg 1.1 and prior, the registry returned by repoze.bfg.threadlocal.
get_current_registry when no other registry had been pushed on to the threadlo-
cal stack was the zope.component.globalregistry.base global registry (aka the re-
sult of zope.component.getGlobalSiteManager()). In repoze.bfg 1.2+, however,
the registry returned in this situation is the new module-scope repoze.bfg.registry.
global_registry object. The zope.testing.cleanup.cleanUp function clears the
zope.component.globalregistry.base global registry unconditionally. However, it
does not know about the repoze.bfg.registry.global_registry object, so it does not
clear it.
If you use the zope.testing.cleanup.cleanUp function in the setUp of test cases in your
unit test suite instead of using the (more correct as of 1.1) repoze.bfg.testing.setUp, you
will need to replace all calls to zope.testing.cleanup.cleanUp with a call to repoze.
bfg.testing.setUp.
If replacing all calls to zope.testing.cleanup.cleanUp with a call to repoze.bfg.
testing.setUp is infeasible, you can put this bit of code somewhere that is executed exactly
once (not for each test in a test suite; in the “ __init__.py“ of your package or your package’s tests
subpackage would be a reasonable place):

import zope.testing.cleanup
from repoze.bfg.testing import setUp
zope.testing.cleanup.addCleanUp(setUp)

• When there is no ”current registry” in the repoze.bfg.threadlocal.manager threadlocal


data structure (this is the case when there is no ”current request” or we’re not in the midst of a r.
b.testing.setUp-bounded unit test), the .get method of the manager returns a data structure
containing a global registry. In previous releases, this function returned the global Zope ”base” reg-
istry: the result of zope.component.getGlobalSiteManager, which is an instance of the
zope.component.registry.Component class. In this release, however, the global registry
returns a globally importable instance of the repoze.bfg.registry.Registry class. This
registry instance can always be imported as repoze.bfg.registry.global_registry.
Effectively, this means that when you call repoze.bfg.threadlocal.
get_current_registry when no request or setUp bounded unit test is in effect, you will

1144 CONTENTS
The Pyramid Web Framework, Version 2.0.2

always get back the global registry that lives in repoze.bfg.registry.global_registry.


It also means that repoze.bfg APIs that call get_current_registry will use this registry.
This change was made because repoze.bfg now expects the registry it uses to have a slightly
different API than a bare instance of zope.component.registry.Components.
• View registration no longer registers a repoze.bfg.interfaces.IViewPermission
adapter (it is no longer checked by the framework; since 1.1, views have been responsible for pro-
viding their own security).
• The repoze.bfg.router.make_app callable no longer accepts the authentica-
tion_policy nor the authorization_policy arguments. This feature was deprecated in
version 1.0 and has been removed.
• Obscure: the machinery which configured views with a request_type and a route_name
would ignore the request interface implied by route_name registering a view only for the interface
implied by request_type. In the unlikely event that you were trying to use these two features
together, the symptom would have been that views that named a request_type but which were
also associated with routes were not found when the route matched. Now if a view is configured
with both a request_type and a route_name, an error is raised.
• The route ZCML directive now no longer accepts the request_type or
view_request_type attributes. These attributes didn’t actually work in any useful way
(see entry above this one).
• Because the repoze.bfg package now includes implementations of the adapter, sub-
scriber and utility ZCML directives, it is now an error to have <include
package="repoze.zcml" file="meta.zcml"/> in the ZCML of a repoze.bfg ap-
plication. A ZCML conflict error will be raised if your ZCML does so. This shouldn’t be an issue
for ”normal” installations; it has always been the responsibility of the repoze.bfg.includes
ZCML to include this file in the past; it now just doesn’t.
• The repoze.bfg.testing.zcml_configure API was removed. Use the
Configurator.load_zcml API instead.

Deprecations

• The repoze.bfg.router.make_app function is now nominally deprecated. Its import and


usage does not throw a warning, nor will it probably ever disappear. However, using a repoze.
bfg.configuration.Configurator class is now the preferred way to generate a WSGI
application.
Note that make_app calls zope.component.getSiteManager.sethook( repoze.
bfg.threadlocal.get_current_registry) on the caller’s behalf, hooking ZCA global
API lookups, for backwards compatibility purposes. If you disuse make_app, your calling

0.6. Change History 1145


The Pyramid Web Framework, Version 2.0.2

code will need to perform this call itself, at least if your application uses the ZCA global API
(getSiteManager, getAdapter, etc).

Dependencies

• A dependency on the martian package has been removed (its functionality is replaced internally).
• A dependency on the repoze.zcml package has been removed (its functionality is replaced in-
ternally).

1.1.1 (2009-11-21)

Bug Fixes

• ”Hybrid mode” applications (applications which explicitly used traversal after url dispatch via
<route> paths containing the *traverse element) were broken in 1.1-final and all 1.1 alpha
and beta releases. Views registered without a route_name route shadowed views registered with
a route_name inappropriately.

1.1 (2009-11-15)

Internals

• Remove dead IRouteRequirement interface from repoze.bfg.zcml module.

Documentation

• Improve the ”Extending an Existing Application” narrative chapter.


• Add more sections to the ”Defending Design” chapter.

1146 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.1b4 (2009-11-12)

Bug Fixes

• Use alsoProvides in the urldispatch module to attach an interface to the request rather than
directlyProvides to avoid disturbing interfaces set in a NewRequest event handler.

Documentation

• Move 1.0.1 and previous changelog to HISTORY.txt.


• Add examples to repoze.bfg.url.model_url docstring.
• Add ”Defending BFG Design” chapter to frontpage docs.

Templates

• Remove ez_setup.py and its import from all paster templates, samples, and tutorials for dis-
tribute compatibility. The documentation already explains how to install virtualenv (which will
include some setuptools package), so these files, imports and usages were superfluous.

Deprecations

• The options kw arg to the repoze.bfg.router.make_app function is deprecated. In its


place is the keyword argument settings. The options keyword continues to work, and a depre-
cation warning is not emitted when it is detected. However, the paster templates, code samples, and
documentation now make reference to settings rather than options. This change/deprecation
was mainly made for purposes of clarity and symmetry with the get_settings() API and dis-
cussions of ”settings” in various places in the docs: we want to use the same name to refer to the
same thing everywhere.

1.1b3 (2009-11-06)

Features

• repoze.bfg.testing.registerRoutesMapper testing facility added. This testing func-


tion registers a routes ”mapper” object in the registry, for tests which require its presence. This
function is documented in the repoze.bfg.testing API documentation.

0.6. Change History 1147


The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• Compound statements that used an assignment entered into in an interactive IPython session invoked
via paster bfgshell no longer fail to mutate the shell namespace correctly. For example, this
set of statements used to fail:

In [2]: def bar(x): return x


...:
In [3]: list(bar(x) for x in 'abc')
Out[3]: NameError: 'bar'

In this release, the bar function is found and the correct output is now sent to the console. Thanks
to Daniel Holth for the patch.
• The bfgshell command did not function properly; it was still expecting to be able to call the root
factory with a bare environ rather than a request object.

Backwards Incompatibilities

• The repoze.bfg.scripting.get_root function now expects a request object as its sec-


ond argument rather than an environ.

1.1b2 (2009-11-02)

Bug Fixes

• Prevent PyPI installation failure due to easy_install trying way too hard to guess the best ver-
sion of Paste. When easy_install pulls from PyPI it reads links off various pages to determine
”more up to date” versions. It incorrectly picks up a link for an ancient version of a package named
”Paste-Deploy-0.1” (note the dash) when trying to find the ”Paste” distribution and somehow be-
lieves it’s the latest version of ”Paste”. It also somehow ”helpfully” decides to check out a version of
this package from SVN. We pin the Paste dependency version to a version greater than 1.7 to work
around this easy_install bug.

1148 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• Fix ”Hybrid” narrative chapter: stop claiming that <view> statements that mention a route_name
need to come afer (in XML order) the <route> statement which creates the route. This hasn’t been
true since 1.1a1.
• ”What’s New in repoze.bfg 1.1” document added to narrative documentation.

Features

• Add a new event type: repoze.bfg.events.AfterTraversal. Events of this type will


be sent after traversal is completed, but before any view code is invoked. Like repoze.bfg.
events.NewRequest, This event will have a single attribute: request representing the cur-
rent request. Unlike the request attribute of repoze.bfg.events.NewRequest however, dur-
ing an AfterTraversal event, the request object will possess attributes set by the traverser, most no-
tably context, which will be the context used when a view is found and invoked. The interface
repoze.bfg.events.IAfterTraversal can be used to subscribe to the event. For exam-
ple:

<subscriber for="repoze.bfg.interfaces.IAfterTraversal"
handler="my.app.handle_after_traverse"/>

Like any framework event, a subscriber function should expect one parameter: event.

Dependencies

• Rather than depending on chameleon.core and chameleon.zpt distributions individually,


depend on Malthe’s repackaged Chameleon distribution (which includes both chameleon.
core and chameleon.zpt).

1.1b1 (2009-11-01)

Bug Fixes

• The routes root factory called route factories and the default route factory with an environ rather
than a request. One of the symptoms of this bug: applications generated using the bfg_zodb
paster template in 1.1a9 did not work properly.

0.6. Change History 1149


The Pyramid Web Framework, Version 2.0.2

• Reinstate renderer alias for view_renderer in the <route> ZCML directive (in-the-wild
1.1a bw compat).
• bfg_routesalchemy paster template: change <route> declarations: rename renderer at-
tribute to view_renderer.
• Header values returned by the authtktauthenticationpolicy remember and forget
methods would be of type unicode. This violated the WSGI spec, causing a TypeError to be
raised when these headers were used under mod_wsgi.
• If a BFG app that had a route matching the root URL was mounted under a path in modwsgi,
ala WSGIScriptAlias /myapp /Users/chrism/projects/modwsgi/env/bfg.
wsgi, the home route (a route with the path of '/' or '') would not match when the path /myapp
was visited (only when the path /myapp/ was visited). This is now fixed: if the urldispatch root
factory notes that the PATH_INFO is empty, it converts it to a single slash before trying to do
matching.

Documentation

• In <route> declarations in tutorial ZCML, rename renderer attribute to view_renderer


(fwd compat).
• Fix various tutorials broken by 1.1a9 <route> directive changes.

Internal

• Deal with a potential circref in the traversal module.

1.1a9 (2009-10-31)

Bug Fixes

• An incorrect ZCML conflict would be encountered when the request_param predicate attribute
was used on the ZCML view directive if any two otherwise same-predicated views had the combi-
nation of a predicate value with an = sign and one without (e.g. a vs. a=123).

1150 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Features

• In previous versions of BFG, the ”root factory” (the get_root callable passed to make_app or
a function pointed to by the factory attribute of a route) was called with a ”bare” WSGI envi-
ronment. In this version, and going forward, it will be called with a request object. The request
object passed to the factory implements dictionary-like methods in such a way that existing root
factory code which expects to be passed an environ will continue to work.
• The __call__ of a plugin ”traverser” implementation (registered as an adapter for ITraverser
or ITraverserFactory) will now receive a request as the single argument to its __call__
method. In previous versions it was passed a WSGI environ object. The request object passed
to the factory implements dictionary-like methods in such a way that existing traverser code which
expects to be passed an environ will continue to work.
• The ZCML route directive’s attributes xhr, request_method, path_info, re-
quest_param, header and accept are now route predicates rather than view predicates. If
one or more of these predicates is specified in the route configuration, all of the predicates must
return true for the route to match a request. If one or more of the route predicates associated with a
route returns False when checked during a request, the route match fails, and the next match in the
routelist is tried. This differs from the previous behavior, where no route predicates existed and all
predicates were considered view predicates, because in that scenario, the next route was not tried.

Documentation

• Various changes were made to narrative and API documentation supporting the change from passing
a request rather than an environ to root factories and traversers.

Internal

• The request implements dictionary-like methods that mutate and query the WSGI environ. This
is only for the purpose of backwards compatibility with root factories which expect an environ
rather than a request.
• The repoze.bfg.request.create_route_request_factory function, which
returned a request factory was removed in favor of a repoze.bfg.request.
route_request_interface function, which returns an interface.

0.6. Change History 1151


The Pyramid Web Framework, Version 2.0.2

• The repoze.bfg.request.Request class, which is a subclass of webob.Request now


defines its own __setattr__, __getattr__ and __delattr__ methods, which override
the default WebOb behavior. The default WebOb behavior stores attributes of the request in
self.environ['webob.adhoc_attrs'], and retrieves them from that dictionary during
a __getattr__. This behavior was undesirable for speed and ”expectation” reasons. Now at-
tributes of the request are stored in request.__dict__ (as you otherwise might expect from
an object that did not override these methods).
• The router no longer calls repoze.bfg.traversal._traverse and does its work ”inline”
(speed).
• Reverse the order in which the router calls the request factory and the root factory. The request
factory is now called first; the resulting request is passed to the root factory.
• The repoze.bfg.request.request_factory function has been removed. Its functional-
ity is no longer required.
• The ”routes root factory” that wraps the default root factory when there are routes men-
tioned in the configuration now attaches an interface to the request via zope.interface.
directlyProvides. This replaces logic in the (now-gone) repoze.bfg.request.
request_factory function.
• The route and view ZCML directives now register an interface as a named utility (re-
trieved from repoze.bfg.request.route_request_interface) rather than a re-
quest factory (the previous return value of the now-missing repoze.bfg.request.
create_route_request_factory.
• The repoze.bfg.functional module was renamed to repoze.bfg.compat.

Backwards Incompatibilities

• Explicitly revert the feature introduced in 1.1a8: where the name root is available as an attribute
of the request before a NewRequest event is emitted. This makes some potential future features
impossible, or at least awkward (such as grouping traversal and view lookup into a single adapter
lookup).
• The containment, attr and renderer attributes of the route ZCML directive were re-
moved.

1152 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.1a8 (2009-10-27)

Features

• Add path_info view configuration predicate.


• paster bfgshell now supports IPython if it’s available for import. Thanks to Daniel Holth for
the initial patch.
• Add repoze.bfg.testing.registerSettings API, which is documented in the ”re-
poze.bfg.testing” API chapter. This allows for registration of ”settings” values obtained via
repoze.bfg.settings.get_settings() for use in unit tests.
• The name root is available as an attribute of the request slightly earlier now (before a NewRequest
event is emitted). root is the result of the application ”root factory”.
• Added max_age parameter to authtktauthenticationpolicy ZCML directive. If this
value is set, it must be an integer representing the number of seconds which the auth tkt cookie will
survive. Mainly, its existence allows the auth_tkt cookie to survive across browser sessions.

Bug Fixes

• Fix bug encountered during ”scan” (when <scan ..> directive is used in ZCML) introduced in
1.1a7. Symptom: AttributeError: object has no attribute __provides__
raised at startup time.
• The reissue_time argument to the authtktauthenticationpolicy ZCML directive
now actually works. When it is set to an integer value, an authticket set-cookie header is appended to
the response whenever a request requires authentication and ’now’ minus the authticket’s timestamp
is greater than reissue_time seconds.

Documentation

• Add a chapter titled ”Request and Response” to the narrative documentation, content cribbed from
the WebOb documentation.
• Call out predicate attributes of ZCML directive within ”Views” chapter.
• Fix route_url documentation (_query argument documented as query and _anchor argument
documented as anchor).

0.6. Change History 1153


The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• The authtkt authentication policy remember method now no longer honors token or user-
data keyword arguments.

Internal

• Change how bfg_view decorator works when used as a class method decorator. In 1.1a7,
the“scan“directive actually tried to grope every class in scanned package at startup time, calling
dir against each found class, and subsequently invoking getattr against each thing found by
dir to see if it was a method. This led to some strange symptoms (e.g. AttributeError:
object has no attribute __provides__), and was generally just a bad idea. Now,
instead of groping classes for methods at startup time, we just cause the bfg_view decorator it-
self to populate the method’s class’ __dict__ when it is used as a method decorator. This also
requires a nasty _getframe thing but it’s slightly less nasty than the startup time groping behavior.
This is essentially a reversion back to 1.1a6 ”grokking” behavior plus some special magic for using
the bfg_view decorator as method decorator inside the bfg_view class itself.
• The router now checks for a global_response_headers attribute of the request object before
returning a response. If this value exists, it is presumed to be a sequence of two-tuples, representing
a set of headers to append to the ’normal’ response headers. This feature is internal, rather than
exposed externally, because it’s unclear whether it will stay around in the long term. It was added
to support the reissue_time feature of the authtkt authentication policy.
• The interface ITraverserFactory is now just an alias for ITraverser.

1.1a7 (2009-10-18)

Features

• More than one @bfg_view decorator may now be stacked on top of any number of others. Each
invocation of the decorator registers a single view configuration. For instance, the following combi-
nation of decorators and a function will register two view configurations for the same view callable:

from repoze.bfg.view import bfg_view

@bfg_view(name='edit')
@bfg_view(name='change')
def edit(context, request):
pass

1154 CONTENTS
The Pyramid Web Framework, Version 2.0.2

This makes it possible to associate more than one view configuration with a single callable without
requiring any ZCML.
• The @bfg_view decorator can now be used against a class method:

from webob import Response


from repoze.bfg.view import bfg_view

class MyView(object):
def __init__(self, context, request):
self.context = context
self.request = request

@bfg_view(name='hello')
def amethod(self):
return Response('hello from %s!' % self.context)

When the bfg_view decorator is used against a class method, a view is registered for the class (it’s
a ”class view” where the ”attr” happens to be the name of the method it is attached to), so the class
it’s defined within must have a suitable constructor: one that accepts context, request or just
request.

Documentation

• Added Changing the Traverser and Changing How :mod:`repoze.bfg.url.


model_url` Generates a URL to the ”Hooks” narrative chapter of the docs.

Internal

• Remove ez_setup.py and imports of it within setup.py. In the new world, and as per vir-
tualenv setup instructions, people will already have either setuptools or distribute.

1.1a6 (2009-10-15)

Features

• Add xhr, accept, and header view configuration predicates to ZCML view declaration, ZCML
route declaration, and bfg_view decorator. See the Views narrative documentation chapter for
more information about these predicates.

0.6. Change History 1155


The Pyramid Web Framework, Version 2.0.2

• Add setUp and tearDown functions to the repoze.bfg.testing module. Using setUp in
a test setup and tearDown in a test teardown is now the recommended way to do component registry
setup and teardown. Previously, it was recommended that a single function named repoze.bfg.
testing.cleanUp be called in both the test setup and tear down. repoze.bfg.testing.
cleanUp still exists (and will exist ”forever” due to its widespread use); it is now just an alias for
repoze.bfg.testing.setUp and is nominally deprecated.
• The BFG component registry is now available in view and event subscriber code as an attribute of
the request ie. request.registry. This fact is currently undocumented except for this note,
because BFG developers never need to interact with the registry directly anywhere else.
• The BFG component registry now inherits from dict, meaning that it can optionally be used as
a simple dictionary. Component registrations performed against it via e.g. registerUtility,
registerAdapter, and similar API methods are kept in a completely separate namespace than
its dict members, so using the its component API methods won’t effect the keys and values in the
dictionary namespace. Likewise, though the component registry ”happens to be” a dictionary, use
of mutating dictionary methods such as __setitem__ will have no influence on any component
registrations made against it. In other words, the registry object you obtain via e.g. repoze.bfg.
threadlocal.get_current_registry or request.registry happens to be both a
component registry and a dictionary, but using its component-registry API won’t impact data added
to it via its dictionary API and vice versa. This is a forward compatibility move based on the goals
of ”marco”.
• Expose and document repoze.bfg.testing.zcml_configure API. This function popu-
lates a component registry from a ZCML file for testing purposes. It is documented in the ”Unit and
Integration Testing” chapter.

Documentation

• Virtual hosting narrative docs chapter updated with info about mod_wsgi.
• Point all index URLs at the literal 1.1 index (this alpha cycle may go on a while).
• Various tutorial test modules updated to use repoze.bfg.testing.setUp and repoze.
bfg.testing.tearDown methods in order to encourage this as best practice going forward.
• Added ”Creating Integration Tests” section to unit testing narrative documentation chapter. As a
result, the name of the unittesting chapter is now ”Unit and Integration Testing”.

1156 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• Importing getSiteManager and get_registry from repoze.bfg.registry is no


longer supported. These imports were deprecated in repoze.bfg 1.0. Import of getSiteM-
anager should be done as from zope.component import getSiteManager. Im-
port of get_registry should be done as from repoze.bfg.threadlocal import
get_current_registry. This was done to prevent a circular import dependency.
• Code bases which alternately invoke both zope.testing.cleanup.cleanUp and repoze.
bfg.testing.cleanUp (treating them equivalently, using them interchangeably) in the
setUp/tearDown of unit tests will begin to experience test failures due to lack of test isola-
tion. The ”right” mechanism is repoze.bfg.testing.cleanUp (or the combination of
repoze.bfg.testing.setUp and repoze.bfg.testing.tearDown). but a good
number of legacy codebases will use zope.testing.cleanup.cleanUp instead. We support
zope.testing.cleanup.cleanUp but not in combination with repoze.bfg.testing.
cleanUp in the same codebase. You should use one or the other test cleanup function in a single
codebase, but not both.

Internal

• Created new repoze.bfg.configuration module which assumes responsibilities previously


held by the repoze.bfg.registry and repoze.bfg.router modules (avoid a circular
import dependency).
• The result of the zope.component.getSiteManager function in unit tests set up
with repoze.bfg.testing.cleanUp or repoze.bfg.testing.setUp will be an in-
stance of repoze.bfg.registry.Registry instead of the global zope.component.
globalregistry.base registry. This also means that the threadlocal ZCA API functions such
as getAdapter and getUtility as well as internal BFG machinery (such as model_url and
route_url) will consult this registry within unit tests. This is a forward compatibility move based
on the goals of ”marco”.
• Removed repoze.bfg.testing.addCleanUp function and associated module-scope glob-
als. This was never an API.

1.1a5 (2009-10-10)

Documentation

• Change ”Traversal + ZODB” and ”URL Dispatch + SQLAlchemy” Wiki tutorials to make use of
the new-to-1.1 ”renderer” feature (return dictionaries from all views).

0.6. Change History 1157


The Pyramid Web Framework, Version 2.0.2

• Add tests to the ”URL Dispatch + SQLAlchemy” tutorial after the ”view” step.
• Added a diagram of model graph traversal to the ”Traversal” narrative chapter of the documentation.
• An exceptions API chapter was added, documenting the new repoze.bfg.exceptions
module.
• Describe ”request-only” view calling conventions inside the urldispatch narrative chapter, where it’s
most helpful.
• Add a diagram which explains the operation of the BFG router to the ”Router” narrative chapter.

Features

• Add a new repoze.bfg.testing API: registerRoute, for registering routes to satisfy calls
to e.g. repoze.bfg.url.route_url in unit tests.
• The notfound and forbidden ZCML directives now accept the following additional attributes:
attr, renderer, and wrapper. These have the same meaning as they do in the context of a
ZCML view directive.
• For behavior like Django’s APPEND_SLASH=True, use the repoze.bfg.view.
append_slash_notfound_view view as the Not Found view in your application. When this
view is the Not Found view (indicating that no view was found), and any routes have been defined
in the configuration of your application, if the value of PATH_INFO does not already end in a
slash, and if the value of PATH_INFO plus a slash matches any route’s path, do an HTTP redirect
to the slash-appended PATH_INFO. Note that this will lose POST data information (turning it into
a GET), so you shouldn’t rely on this to redirect POST requests.
• Speed up repoze.bfg.location.lineage slightly.
• Speed up repoze.bfg.encode.urlencode (nee’ repoze.bfg.url.urlencode)
slightly.
• Speed up repoze.bfg.traversal.model_path.
• Speed up repoze.bfg.traversal.model_path_tuple slightly.
• Speed up repoze.bfg.traversal.traverse slightly.
• Speed up repoze.bfg.url.model_url slightly.
• Speed up repoze.bfg.url.route_url slightly.
• Sped up repoze.bfg.traversal.ModelGraphTraverser:__call__ slightly.
• Minor speedup of repoze.bfg.router.Router.__call__.
• New repoze.bfg.exceptions module was created to house exceptions that were previously
sprinkled through various modules.

1158 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Internal

• Move repoze.bfg.traversal._url_quote into repoze.bfg.encode as


url_quote.

Deprecations

• The import of repoze.bfg.view.NotFound is deprecated in favor of repoze.bfg.


exceptions.NotFound. The old location still functions, but emits a deprecation warning.
• The import of repoze.bfg.security.Unauthorized is deprecated in favor of repoze.
bfg.exceptions.Forbidden. The old location still functions but emits a deprecation warn-
ing. The rename from Unauthorized to Forbidden brings parity to the name of the exception
and the system view it invokes when raised.

Backwards Incompatibilities

• We previously had a Unicode-aware wrapper for the urllib.urlencode function named


repoze.bfg.url.urlencode which delegated to the stdlib function, but which marshalled
all unicode values to utf-8 strings before calling the stdlib version. A newer replacement now lives
in repoze.bfg.encode The replacement does not delegate to the stdlib.
The replacement diverges from the stdlib implementation and the previous repoze.bfg.url
url implementation inasmuch as its doseq argument is now a decoy: it always behaves in the
doseq=True way (which is the only sane behavior) for speed purposes.
The old import location (repoze.bfg.url.urlencode) still functions and has not been dep-
recated.
• In 0.8a7, the return value expected from an object implementing ITraverserFactory was
changed from a sequence of values to a dictionary containing the keys context, view_name,
subpath, traversed, virtual_root, virtual_root_path, and root. Until now, old-
style traversers which returned a sequence have continued to work but have generated a deprecation
warning. In this release, traversers which return a sequence instead of a dictionary will no longer
work.

0.6. Change History 1159


The Pyramid Web Framework, Version 2.0.2

1.1a4 (2009-09-23)

Bug Fixes

• On 64-bit Linux systems, views that were members of a multiview (orderings of views with predi-
cates) were not evaluated in the proper order. Symptom: in a configuration that had two views with
the same name but one with a request_method=POST predicate and one without, the one with-
out the predicate would be called unconditionally (even if the request was a POST request). Thanks
much to Sebastien Douche for providing the buildbots that pointed this out.

Documentation

• Added a tutorial which explains how to use repoze.session (ZODB-based sessions) in a


ZODB-based repoze.bfg app.
• Added a tutorial which explains how to add ZEO to a ZODB-based repoze.bfg application.
• Added a tutorial which explains how to run a repoze.bfg application under mod_wsgi. See
”Running a repoze.bfg Application under mod_wsgi” in the tutorials section of the documentation.

Features

• Add a repoze.bfg.url.static_url API which is capable of generating URLs to static re-


sources defined by the <static> ZCML directive. See the ”Views” narrative chapter’s section
titled ”Generating Static Resource URLs” for more information.
• Add a string renderer. This renderer converts a non-Response return value of any view callble
into a string. It is documented in the ”Views” narrative chapter.
• Give the route ZCML directive the view_attr and view_renderer parameters (bring up to
speed with 1.1a3 features). These can also be spelled as attr and renderer.

Backwards Incompatibilities

• An object implementing the IRenderer interface (and ITemplateRenderer`, which is


a subclass of ``IRenderer) must now accept an extra system argument in its __call__
method implementation. Values computed by the system (as opposed to by the view) are passed by
the system in the system parameter, which will always be a dictionary. Keys in the dictionary
include: view (the view object that returned the value), renderer_name (the template name or
simple name of the renderer), context (the context object passed to the view), and request (the
request object passed to the view). Previously only ITemplateRenderers received system arguments
as elements inside the main value dictionary.

1160 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Internal

• The way bfg_view declarations are scanned for has been modified. This should have no external
effects.
• Speed: do not register an ITraverserFactory in configure.zcml; instead rely on queryAdapter and a
manual default to ModelGraphTraverser.
• Speed: do not register an IContextURL in configure.zcml; instead rely on queryAdapter and a man-
ual default to TraversalContextURL.
• General speed microimprovements for helloworld benchmark: replace try/excepts with statements
which use ’in’ keyword.

1.1a3 (2009-09-16)

Documentation

• The ”Views” narrative chapter in the documentation has been updated extensively to discuss ”ren-
derers”.

Features

• A renderer attribute has been added to view configurations, replacing the previous (1.1a2) ver-
sion’s template attribute. A ”renderer” is an object which accepts the return value of a view and
converts it to a string. This includes, but is not limited to, templating systems.
• A new interface named IRenderer was added. The existing interface, ITemplateRenderer
now derives from this new interface. This interface is internal.
• A new interface named IRendererFactory was added. An existing interface named ITem-
plateRendererFactory now derives from this interface. This interface is internal.
• The view attribute of the view ZCML directive is no longer required if the ZCML directive also
has a renderer attribute. This is useful when the renderer is a template renderer and no names
need be passed to the template at render time.
• A new zcml directive renderer has been added. It is documented in the ”Views” narrative chapter
of the documentation.

0.6. Change History 1161


The Pyramid Web Framework, Version 2.0.2

• A ZCML view directive (and the associated bfg_view decorator) can now accept a ”wrapper”
value. If a ”wrapper” value is supplied, it is the value of a separate view’s name attribute. When
a view with a wrapper attribute is rendered, the ”inner” view is first rendered normally. Its body
is then attached to the request as ”wrapped_body”, and then a wrapper view name is looked up
and rendered (using repoze.bfg.render_view_to_response), passed the request and the
context. The wrapper view is assumed to do something sensible with request.wrapped_body,
usually inserting its structure into some other rendered template. This feature makes it possible to
specify (potentially nested) ”owrap” relationships between views using only ZCML or decorators
(as opposed always using ZPT METAL and analogues to wrap view renderings in outer wrappers).

Dependencies

• When used under Python < 2.6, BFG now has an installation time dependency on the simplejson
package.

Deprecations

• The repoze.bfg.testing.registerDummyRenderer API has been deprecated in favor


of repoze.bfg.testing.registerTemplateRenderer. A deprecation warning is not
issued at import time for the former name; it will exist ”forever”; its existence has been removed
from the documentation, however.
• The repoze.bfg.templating.renderer_from_cache function has been moved to
repoze.bfg.renderer.template_renderer_factory. This was never an API, but
code in the wild was spotted that used it. A deprecation warning is issued at import time for the
former.

Backwards Incompatibilities

• The ITemplateRenderer interface has been changed. Previously its __call__ method
accepted **kw. It now accepts a single positional parameter named kw (REVISED: it ac-
cepts two positional parameters as of 1.1a4: value and system). This is mostly an internal
change, but it was exposed in APIs in one place: if you’ve used the repoze.bfg.testing.
registerDummyRenderer API in your tests with a custom ”renderer” argument with your own
renderer implementation, you will need to change that renderer implementation to accept kw instead
of **kw in its __call__ method (REVISED: make it accept value and system positional ar-
guments as of 1.1a4).

1162 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• The ITemplateRendererFactory interface has been changed. Previously its __call__


method accepted an auto_reload keyword parameter. Now its __call__ method accepts no
keyword parameters. Renderers are now themselves responsible for determining details of auto-
reload. This is purely an internal change. This interface was never external.
• The template_renderer ZCML directive introduced in 1.1a2 has been removed. It has been
replaced by the renderer directive.
• The previous release (1.1a2) added a view configuration attribute named template. In this release,
the attribute has been renamed to renderer. This signifies that the attribute is more generic: it
can now be not just a template name but any renderer name (ala json).
• In the previous release (1.1a2), the Chameleon text template renderer was used if the system didn’t
associate the template view configuration value with a filename with a ”known” extension. In
this release, you must use a renderer attribute which is a path that ends with a .txt extension
(e.g. templates/foo.txt) to use the Chameleon text renderer.

1.1a2 (2009-09-14)

Features

• A ZCML view directive (and the associated bfg_view decorator) can now accept an ”attr” value.
If an ”attr” value is supplied, it is considered a method named of the view object to be called when
the response is required. This is typically only good for views that are classes or instances (not so
useful for functions, as functions typically have no methods other than __call__).
• A ZCML view directive (and the associated bfg_view decorator) can now accept a ”template”
value. If a ”template” value is supplied, and the view callable returns a dictionary, the associated
template is rendered with the dictionary as keyword arguments. See the section named ”Views That
Have a template” in the ”Views” narrative documentation chapter for more information.

1.1a1 (2009-09-06)

Bug Fixes

• ”tests” module removed from the bfg_alchemy paster template; these tests didn’t work.
• Bugfix: the discriminator for the ZCML ”route” directive was incorrect. It was possible to reg-
ister two routes that collided without the system spitting out a ConfigurationConflictError at startup
time.

0.6. Change History 1163


The Pyramid Web Framework, Version 2.0.2

Features

• Feature addition: view predicates. These are exposed as the request_method, re-
quest_param, and containment attributes of a ZCML view declaration, or the respec-
tive arguments to a @bfg_view decorator. View predicates can be used to register a view for
a more precise set of environment parameters than was previously possible. For example, you
can register two views with the same name with different request_param attributes. If the
request.params dict contains ’foo’ (request_param=”foo”), one view might be called; if it con-
tains ’bar’ (request_param=”bar”), another view might be called. request_param can also name
a key/value pair ala foo=123. This will match only when the foo key is in the request.params dict
and it has the value ’123’. This particular example makes it possible to write separate view functions
for different form submissions. The other predicates, containment and request_method
work similarly. containment is a view predicate that will match only when the context’s graph
lineage has an object possessing a particular class or interface, for example. request_method
is a view predicate that will match when the HTTP REQUEST_METHOD equals some string (eg.
’POST’).
• The @bfg_view decorator now accepts three additional arguments: request_method, re-
quest_param, and containment. request_method is used when you’d like the view
to match only a request with a particular HTTP REQUEST_METHOD; a string naming the RE-
QUEST_METHOD can also be supplied as request_type for backwards compatibility. re-
quest_param is used when you’d like a view to match only a request that contains a particular
request.params key (with or without a value). containment is used when you’d like to
match a request that has a context that has some class or interface in its graph lineage. These are
collectively known as ”view predicates”.
• The route ZCML directive now honors view_request_method, view_request_param
and view_containment attributes, which pass along these values to the associated view
if any is provided. Additionally, the request_type attribute can now be spelled as
view_request_type, and permission can be spelled as view_permission. Any at-
tribute which starts with view_ can now be spelled without the view_ prefix, so view_for can
be spelled as for now, etc. Both forms are documented in the urldispatch narrative documentation
chapter.
• The request_param ZCML view directive attribute (and its bfg_view decorator cousin) can
now specify both a key and a value. For example, request_param="foo=123" means that the
foo key must have a value of 123 for the view to ”match”.
• Allow repoze.bfg.traversal.find_interface API to use a class object as the
argument to compare against the model passed in. This means you can now do
find_interface(model, SomeClass) and the first object which is found in the lineage
which has SomeClass as its class (or the first object found which has SomeClass as any of its
superclasses) will be returned.

1164 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Added static ZCML directive which registers a route for a view that serves up files in a direc-
tory. See the ”Views” narrative documentation chapter’s ”Serving Static Resources Using a ZCML
Directive” section for more information.
• The repoze.bfg.view.static class now accepts a string as its first argument (”root_dir”)
that represents a package-relative name e.g. somepackage:foo/bar/static. This is now the
preferred mechanism for spelling package-relative static paths using this class. A package_name
keyword argument has been left around for backwards compatibility. If it is supplied, it will be
honored.
• The API repoze.bfg.testing.registerView now takes a permission argument. Use
this instead of using repoze.bfg.testing.registerViewPermission.
• The ordering of route declarations vs. the ordering of view declarations that use a ”route_name” in
ZCML no longer matters. Previously it had been impossible to use a route_name from a route that
had not yet been defined in ZCML (order-wise) within a ”view” declaration.
• The repoze.bfg router now catches both repoze.bfg.security.Unauthorized and
repoze.bfg.view.NotFound exceptions while rendering a view. When the router catches an
Unauthorized, it returns the registered forbidden view. When the router catches a NotFound,
it returns the registered notfound view.

Internal

• Change urldispatch internals: Route object is now constructed using a path, a name, and a factory
instead of a name, a matcher, a generator, and a factory.
• Move (non-API) default_view, default_forbidden_view, and default_notfound_view functions into
the repoze.bfg.view module (moved from repoze.bfg.router).
• Removed ViewPermissionFactory from repoze.bfg.security. View permission checking is
now done by registering and looking up an ISecuredView.
• The static ZCML directive now uses a custom root factory when constructing a route.
• The interface IRequestFactories was removed from the repoze.bfg.interfaces module. This
interface was never an API.
• The function named named_request_factories and the data structure named DE-
FAULT_REQUEST_FACTORIES have been removed from the repoze.bfg.request module.
These were never APIs.
• The IViewPermissionFactory interface has been removed. This was never an API.

0.6. Change History 1165


The Pyramid Web Framework, Version 2.0.2

Documentation

• Request-only-convention examples in the ”Views” narrative documentation were broken.


• Fixed documentation bugs related to forget and remember in security API docs.
• Fixed documentation for repoze.bfg.view.static (in narrative Views chapter).

Deprecations

• The API repoze.bfg.testing.registerViewPermission has been deprecated.

Backwards Incompatibilities

• The interfaces IPOSTRequest, IGETRequest, IPUTRequest, IDELETERequest, and


IHEADRequest have been removed from the repoze.bfg.interfaces module. These were
not documented as APIs post-1.0. Instead of using one of these, use a request_method ZCML
attribute or request_method bfg_view decorator parameter containing an HTTP method name
(one of GET, POST, HEAD, PUT, DELETE) instead of one of these interfaces if you were using one
explicitly. Passing a string in the set (GET, HEAD, PUT, POST, DELETE) as a request_type
argument will work too. Rationale: instead of relying on interfaces attached to the request object,
BFG now uses a ”view predicate” to determine the request type.
• Views registered without the help of the ZCML view directive are now responsible for performing
their own authorization checking.
• The registry_manager backwards compatibility alias importable from ”repoze.bfg.registry”,
deprecated since repoze.bfg 0.9 has been removed. If you are tring to use the registry manager
within a debug script of your own, use a combination of the ”repoze.bfg.paster.get_app” and ”re-
poze.bfg.scripting.get_root” APIs instead.
• The INotFoundAppFactory interface has been removed; it has been deprecated since re-
poze.bfg 0.9. If you have something like the following in your configure.zcml:

<utility provides="repoze.bfg.interfaces.INotFoundAppFactory"
component="helloworld.factories.notfound_app_factory"/>

Replace it with something like:

1166 CONTENTS
The Pyramid Web Framework, Version 2.0.2

<notfound
view="helloworld.views.notfound_view"/>

See ”Changing the Not Found View” in the ”Hooks” chapter of the documentation for more infor-
mation.
• The IUnauthorizedAppFactory interface has been removed; it has been deprecated since
repoze.bfg 0.9. If you have something like the following in your configure.zcml:

<utility provides="repoze.bfg.interfaces.IUnauthorizedAppFactory"
component="helloworld.factories.unauthorized_app_factory"/>

Replace it with something like:

<forbidden
view="helloworld.views.forbidden_view"/>

See ”Changing the Forbidden View” in the ”Hooks” chapter of the documentation for more infor-
mation.
• ISecurityPolicy-based security policies, deprecated since repoze.bfg 0.9, have been removed.
If you have something like this in your configure.zcml, it will no longer work:

<utility
provides="repoze.bfg.interfaces.ISecurityPolicy"
factory="repoze.bfg.security.RemoteUserInheritingACLSecurityPolicy"
/>

If ZCML like the above exists in your application, you will receive an error at startup time. Instead
of the above, you’ll need something like:

<remoteuserauthenticationpolicy/>
<aclauthorizationpolicy/>

This is just an example. See the ”Security” chapter of the repoze.bfg documentation for more infor-
mation about configuring security policies.
• Custom ZCML directives which register an authentication or authorization policy (ala ”authtktau-
thenticationpolicy” or ”aclauthorizationpolicy”) should register the policy ”eagerly” in the ZCML
directive instead of from within a ZCML action. If an authentication or authorization policy is not
found in the component registry by the view machinery during deferred ZCML processing, view
security will not work as expected.

0.6. Change History 1167


The Pyramid Web Framework, Version 2.0.2

1.0.1 (2009-07-22)

• Added support for has_resource, resource_isdir, and resource_listdir to the re-


source ”OverrideProvider”; this fixes a bug with a symptom that a file could not be overridden in a
resource directory unless a file with the same name existed in the original directory being overridden.
• Fixed documentation bug showing invalid test for values from the matchdict: they are stored as
attributes of the Article, rather than subitems.
• Fixed documentation bug showing wrong environment key for the matchdict produced by the
matching route.
• Added a workaround for a bug in Python 2.6, 2.6.1, and 2.6.2 having to do with a recursion er-
ror in the mimetypes module when trying to serve static files from Paste’s FileApp: https://bugs.
python.org/issue5853. Symptom: File ”/usr/lib/python2.6/mimetypes.py”, line 244, in guess_type
return guess_type(url, strict) RuntimeError: maximum recursion depth exceeded. Thanks to Armin
Ronacher for identifying the symptom and pointing out a fix.
• Minor edits to tutorials for accuracy based on feedback.
• Declared Paste and PasteDeploy dependencies.

1.0 (2009-07-05)

• Retested and added some content to GAE tutorial.


• Edited ”Extending” narrative docs chapter.
• Added ”Deleting the Database” section to the ”Defining Models” chapter of the traversal wiki tuto-
rial.
• Spell checking of narratives and tutorials.

1.0b2 (2009-07-03)

• remoteuserauthenticationpolicy ZCML directive didn’t work without an envi-


ron_key directive (didn’t match docs).
• Fix configure_zcml filespec check on Windows. Previously if an absolute filesystem path in-
cluding a drive letter was passed as filename (or as configure_zcml in the options dict) to
repoze.bfg.router.make_app, it would be treated as a package:resource_name specifica-
tion.
• Fix inaccuracies and import errors in bfgwiki (traversal+ZODB) and bfgwiki2 (urldispatch+SA)
tutorials.

1168 CONTENTS
The Pyramid Web Framework, Version 2.0.2

• Use bfgsite index for all tutorial setup.cfg files.


• Full documentation grammar/style/spelling audit.

1.0b1 (2009-07-02)

Features

• Allow a Paste config file (configure_zcml) value or an environment variable


(BFG_CONFIGURE_ZCML) to name a ZCML file (optionally package-relative) that will be
used to bootstrap the application. Previously, the integrator could not influence which ZCML file
was used to do the boostrapping (only the original application developer could do so).

Documentation

• Added a ”Resources” chapter to the narrative documentation which explains how to override re-
sources within one package from another package.
• Added an ”Extending” chapter to the narrative documentation which explains how to extend or
modify an existing BFG application using another Python package and ZCML.

1.0a9 (2009-07-01)

Features

• Make it possible to pass strings in the form ”package_name:relative/path” to APIs like ren-
der_template, render_template_to_response, and get_template. Sometimes
the package in which a caller lives is a direct namespace package, so the module which is returned
is semi-useless for navigating from. In this way, the caller can control the horizontal and vertical of
where things get looked up from.

0.6. Change History 1169


The Pyramid Web Framework, Version 2.0.2

1.0a8 (2009-07-01)

Deprecations

• Deprecate the authentication_policy and authorization_policy arguments to


repoze.bfg.router.make_app. Instead, developers should use the various authentication
policy ZCML directives (repozewho1authenticationpolicy, remoteuserauthen-
ticationpolicy and authtktauthenticationpolicy) and the aclauthorizationpolicy‘
authorization policy directive as described in the changes to the ”Security” narrative documentation
chapter and the wiki tutorials.

Features

• Add three new ZCML directives which configure authentication policies:


– repozewho1authenticationpolicy
– remoteuserauthenticationpolicy
– authtktauthenticationpolicy
• Add a new ZCML directive which configures an ACL authorization policy named aclautho-
rizationpolicy.

Bug Fixes

• Bug fix: when a repoze.bfg.resource.PackageOverrides class was instantiated, and


the package it was overriding already had a __loader__ attribute, it would fail at startup
time, even if the __loader__ attribute was another PackageOverrides instance. We now
replace any __loader__ that is also a PackageOverrides instance. Symptom: Config-
urationExecutionError: <type 'exceptions.TypeError'>: Package
<module 'karl.views' from '/Users/chrism/projects/osi/bfgenv/src/
karl/karl/views/__init__.pyc'> already has a __loader__ (probably
a module in a zipped egg).

1170 CONTENTS
The Pyramid Web Framework, Version 2.0.2

1.0a7 (2009-06-30)

Features

• Add a reload_resources configuration file setting (aka the BFG_RELOAD_RESOURCES en-


vironment variable). When this is set to true, the server never needs to be restarted when moving
files between directory resource overrides (esp. for templates currently).
• Add a reload_all configuration file setting (aka the BFG_RELOAD_ALL environment variable)
that implies both reload_resources and reload_templates.
• The static helper view class now uses a PackageURLParser in order to allow for the over-
riding of static resources (CSS / logo files, etc) using the resource ZCML directive. The Pack-
ageURLParser class was added to a (new) static module in BFG; it is a subclass of the
StaticURLParser class in paste.urlparser.
• The repoze.bfg.templating.renderer_from_cache function now checks for the
reload_resources setting; if it’s true, it does not register a template renderer (it won’t use
the registry as a template renderer cache).

Documentation

• Add pkg_resources to the glossary.


• Update the ”Environment” docs to note the existence of reload_resources and reload_all.
• Updated the bfg_alchemy paster template to include two views: the view on the root shows a list
of links to records; the view on a record shows the details for that object.

Internal

• Use a colon instead of a tab as the separator between package name and relpath to form the ”spec”
when register a ITemplateRenderer.
• Register a repoze.bfg.resource.OverrideProvider as a pkg_resources provider only
for modules which are known to have overrides, instead of globally, when a <resource> directive is
used (performance).

0.6. Change History 1171


The Pyramid Web Framework, Version 2.0.2

1.0a6 (2009-06-29)

Bug Fixes

• Use caller_package function instead of caller_module function within templating to


avoid needing to name the caller module in resource overrides (actually match docs).
• Make it possible to override templates stored directly in a module with templates in a subdirectory
of the same module, stored directly within another module, or stored in a subdirectory of another
module (actually match docs).

1.0a5 (2009-06-28)

Features

• A new ZCML directive exists named ”resource”. This ZCML directive allows you to override
Chameleon templates within a package (both directories full of templates and individual template
files) with other templates in the same package or within another package. This allows you to ”fake
out” a view’s use of a template, causing it to retrieve a different template than the one actually
named by a relative path to a call like render_template_to_response('templates/
mytemplate.pt'). For example, you can override a template file by doing:

<resource
to_override="some.package:templates/mytemplate.pt"
override_with="another.package:othertemplates/anothertemplate.pt"
/>

The string passed to ”to_override” and ”override_with” is named a ”specification”. The colon sep-
arator in a specification separates the package name from a package-relative directory name. The
colon and the following relative path are optional. If they are not specified, the override attempts to
resolve every lookup into a package from the directory of another package. For example:

<resource
to_override="some.package"
override_with="another.package"
/>

Individual subdirectories within a package can also be overridden:

1172 CONTENTS
The Pyramid Web Framework, Version 2.0.2

<resource
to_override="some.package:templates/"
override_with="another.package:othertemplates/"
/>

If you wish to override a directory with another directory, you must make sure to attach the slash
to the end of both the to_override specification and the override_with specification. If
you fail to attach a slash to the end of a specification that points a directory, you will get unexpected
results. You cannot override a directory specification with a file specification, and vice versa (a
startup error will occur if you try).
You cannot override a resource with itself (a startup error will occur if you try).
Only individual package resources may be overridden. Overrides will not traverse through sub-
packages within an overridden package. This means that if you want to override resources for both
some.package:templates, and some.package.views:templates, you will need to
register two overrides.
The package name in a specification may start with a dot, meaning that the package is relative to the
package in which the ZCML file resides. For example:

<resource
to_override=".subpackage:templates/"
override_with="another.package:templates/"
/>

Overrides for the same to_overrides specification can be named multiple times within ZCML.
Each override_with path will be consulted in the order defined within ZCML, forming an
override search path.
Resource overrides can actually override resources other than templates. Any software
which uses the pkg_resources get_resource_filename, get_resource_stream or
get_resource_string APIs will obtain an overridden file when an override is used. However,
the only built-in facility which uses the pkg_resources API within BFG is the templating stuff,
so we only call out template overrides here.
• Use the pkg_resources API to locate template filenames instead of dead-reckoning using the
os.path module.
• The repoze.bfg.templating module now uses pkg_resources to locate and register
template files instead of using an absolute path name.

0.6. Change History 1173


The Pyramid Web Framework, Version 2.0.2

1.0a4 (2009-06-25)

Features

• Cause :segment matches in route paths to put a Unicode-decoded and URL-dequoted value in the
matchdict for the value matched. Previously a non-decoded non-URL-dequoted string was placed
in the matchdict as the value.
• Cause *remainder matches in route paths to put a tuple in the matchdict dictionary in order to
be able to present Unicode-decoded and URL-dequoted values for the traversal path. Previously a
non-decoded non-URL-dequoted string was placed in the matchdict as the value.
• Add optional max_age keyword value to the remember method of repoze.bfg.
authentication.AuthTktAuthenticationPolicy; if this value is passed to remem-
ber, the generated cookie will have a corresponding Max-Age value.

Documentation

• Add information to the URL Dispatch narrative documentation about path pattern matching syntax.

Bug Fixes

• Make route_url URL-quote segment replacements during generation. Remainder segments are
not quoted.

1.0a3 (2009-06-24)

Implementation Changes

• repoze.bfg no longer relies on the Routes package to interpret URL paths. All known existing
path patterns will continue to work with the reimplemented logic, which lives in repoze.bfg.
urldispatch. <route> ZCML directives which use certain attributes (uncommon ones) may
not work (see ”Backwards Incompatibilities” below).

1174 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• model_url when passed a request that was generated as a result of a route match would fail in a
call to route.generate.
• BFG-on-GAE didn’t work due to a corner case bug in the fallback Python implementation of
threading.local (symptom: ”Initialization arguments are not supported”). Thanks to Michael
Bernstein for the bug report.

Documentation

• Added a ”corner case” explanation to the ”Hybrid Apps” chapter explaining what to do when ”the
wrong” view is matched.
• Use repoze.bfg.url.route_url API in tutorials rather than Routes url_for API.

Features

• Added the repoze.bfg.url.route_url API. This API allows you to generate URLs based
on <route> declarations. See the URL Dispatch narrative chapter and the ”repoze.bfg.url” module
API documentation for more information.

Backwards Incompatibilities

• As a result of disusing Routes, using the Routes url_for API inside a BFG application (as was
suggested by previous iterations of tutorials) will no longer work. Use the repoze.bfg.url.
route_url method instead.
• The following attributes on the <route> ZCML directive no longer work: encoding, static,
filter, condition_method, condition_subdomain, condition_function, ex-
plicit, or subdomains. These were all Routes features.
• The <route> ZCML directive no longer supports the <requirement> subdirective. This was
a Routes feature.

0.6. Change History 1175


The Pyramid Web Framework, Version 2.0.2

1.0a2 (2009-06-23)

Bug Fixes

• The bfg_routesalchemy paster template app tests failed due to a mismatch between test and
view signatures.

Features

• Add a view_for attribute to the route ZCML directive. This attribute should refer to an interface
or a class (ala the for attribute of the view ZCML directive).

Documentation

• Conditional documentation in installation section (”how to install a Python interpreter”).

Backwards Incompatibilities

• The callback argument of the repoze.bfg.authentication authentication poli-


cies named RepozeWho1AuthenticationPolicy, RemoteUserAuthentication-
Policy, and AuthTktAuthenticationPolicy now must accept two positional arguments:
the original argument accepted by each (userid or identity) plus a second argument, which will be
the current request. Apologies, this is required to service finding groups when there is no ”global”
database connection.

1.0a1 (2009-06-22)

Features

• A new ZCML directive was added named notfound. This ZCML directive can be used to name
a view that should be invoked when the request can’t otherwise be resolved to a view callable. For
example:

1176 CONTENTS
The Pyramid Web Framework, Version 2.0.2

<notfound
view="helloworld.views.notfound_view"/>

• A new ZCML directive was added named forbidden. This ZCML directive can be used to name
a view that should be invoked when a view callable for a request is found, but cannot be invoked due
to an authorization failure. For example:

<forbidden
view="helloworld.views.forbidden_view"/>

• Allow views to be optionally defined as callables that accept only a request object, instead of both
a context and a request (which still works, and always will). The following types work as views in
this style:
– functions that accept a single argument request, e.g.:

def aview(request):
pass

– new and old-style classes that have an __init__ method that accepts self, request,
e.g.:

def View(object):
__init__(self, request):
pass

– Arbitrary callables that have a __call__ method that accepts self, request, e.g.:

def AView(object):
def __call__(self, request):
pass
view = AView()

This likely should have been the calling convention all along, as the request has context as an
attribute already, and with views called as a result of URL dispatch, having the context in the argu-
ments is not very useful. C’est la vie.
• Cache the absolute path in the caller’s package globals within repoze.bfg.path to get rid of
repeated (expensive) calls to os.path.abspath.
• Add reissue_time and timeout parameters to repoze.bfg.authentication.
AuthTktAuthenticationPolicy constructor. If these are passed, cookies will be reset every
so often (cadged from the same change to repoze.who lately).

0.6. Change History 1177


The Pyramid Web Framework, Version 2.0.2

• The matchdict related to the matching of a Routes route is available on the request as the match-
dict attribute: request.matchdict. If no route matched, this attribute will be None.
• Make 404 responses slightly cheaper by showing environ["PATH_INFO"] on the notfound
result page rather than the fullly computed URL.
• Move LRU cache implementation into a separate package (repoze.lru).
• The concepts of traversal and URL dispatch have been unified. It is now possible to use the same
sort of factory as both a traversal ”root factory” and what used to be referred to as a urldispatch
”context factory”.
• When the root factory argument (as a first argument) passed to repoze.bfg.router.
make_app is None, a default root factory is used. This is in support of using routes as ”root
finders”; it supplants the idea that there is a default IRoutesContextFactory.
• The view‘ ZCML statement and the repoze.bfg.view.bfg_view decorator now accept an
extra argument: route_name. If a route_name is specified, it must match the name of a previ-
ously defined route statement. When it is specified, the view will only be called when that route
matches during a request.
• It is now possible to perform traversal after a route has matched. Use the pattern *traverse in a
<route> path attribute within ZCML, and the path remainder which it matches will be used as
a traversal path.
• When any route defined matches, the WSGI environment will now contain a key bfg.routes.
route (the Route object which matched), and a key bfg.routes.matchdict (the result of
calling route.match).

Deprecations

• Utility registrations against repoze.bfg.interfaces.INotFoundView and repoze.


bfg.interfaces.IForbiddenView are now deprecated. Use the notfound and for-
bidden ZCML directives instead (see the ”Hooks” chapter for more information). Such registra-
tions will continue to work, but the notfound and forbidden directives do ”extra work” to ensure
that the callable named by the directive can be called by the router even if it’s a class or request-
argument-only view.

1178 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Removals

• The IRoutesContext, IRoutesContextFactory, and IContextNotFound interfaces


were removed from repoze.bfg.interfaces. These were never APIs.
• The repoze.bfg.urldispatch.RoutesContextNotFound, repoze.bfg.
urldispatch.RoutesModelTraverser and repoze.bfg.urldispatch.
RoutesContextURL classes were removed. These were also never APIs.

Backwards Incompatibilities

• Moved the repoze.bfg.push module, which implemented the pushpage decorator, into a
separate distribution, repoze.bfg.pushpage. Applications which used this decorator should
continue to work after adding that distribution to their installation requirements.
• Changing the default request factory via an IRequestFactory utility registration (as used to be doc-
umented in the ”Hooks” chapter’s ”Changing the request factory” section) is no longer supported.
The dance to manufacture a request is complicated as a result of unifying traversal and url dispatch,
making it highly unlikely for anyone to be able to override it properly. For those who just want
to decorate or modify a request, use a NewRequestEvent subscriber (see the Events chapter in the
documentation).
• The repoze.bfg.IRequestFactory interface was removed. See the bullet above for why.
• Routes ”context factories” (spelled as the factory argument to a route statement in ZCML) must now
expect the WSGI environ as a single argument rather than a set of keyword arguments. They can
obtain the match dictionary by asking for environ[’bfg.routes.matchdict’]. This is the same set of
keywords that used to be passed to urldispatch ”context factories” in BFG 0.9 and below.
• Using the @zope.component.adapter decorator on a bfg view function no longer works. Use
the @repoze.bfg.view.bfg_view decorator instead to mark a function (or a class) as a view.
• The name under which the matching route object is found in the environ was changed from bfg.
route to bfg.routes.route.
• Finding the root is now done before manufacturing a request object (and sending a new request event)
within the router (it used to be performed afterwards).
• Adding *path_info to a route no longer changes the PATH_INFO for a request that matches
using URL dispatch. This feature was only there to service the repoze.bfg.wsgi.wsgiapp2
decorator and it did it wrong; use *subpath instead now.
• The values of subpath, traversed, and virtual_root_path attached to the request object
are always now tuples instead of lists (performance).

0.6. Change History 1179


The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• The bfg_alchemy Paster template named ”repoze.tm” in its pipeline rather than ”repoze.tm2”,
causing the startup to fail.
• Move BBB logic for registering an IAuthenticationPolicy/IForbiddenView/INotFoundView
based on older concepts from the router module’s make_app function into the repoze.
bfg.zcml.zcml_configure callable, to service compatibility with scripts that use
”zope.configuration.xmlconfig” (replace with repoze.bfg.zml.zcml_configure as nec-
essary to get BBB logic)

Documentation

• Add interface docs related to how to create authentication policies and authorization policies to the
”Security” narrative chapter.
• Added a (fairly sad) ”Combining Traversal and URL Dispatch” chapter to the narrative documenta-
tion. This explains the usage of *traverse and *subpath in routes URL patters.
• A ”router” chapter explaining the request/response lifecycle at a high level was added.
• Replaced all mentions and explanations of a routes ”context factory” with equivalent explanations
of a ”root factory” (context factories have been disused).
• Updated Routes bfgwiki2 tutorial to reflect the fact that context factories are now no longer used.

0.9.1 (2009-06-02)

Features

• Add API named repoze.bfg.settings.get_settings which retrieves a derivation of val-


ues passed as the options value of repoze.bfg.router.make_app. This API should be
preferred instead of using getUtility(ISettings). I added a new repoze.bfg.settings API
document as well.

Bug Fixes

• Restored missing entry point declaration for bfg_alchemy paster template, which was accidentally
removed in 0.9.

1180 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• Fix a reference to wsgiapp in the wsgiapp2 API documentation within the repoze.bfg.
wsgi module.

API Removals

• The repoze.bfg.location.locate API was removed: it didn’t do enough to be very helpful


and had a misleading name.

0.9 (2009-06-01)

Bug Fixes

• It was not possible to register a custom IRoutesContextFactory for use as a default context
factory as documented in the ”Hooks” chapter.

Features

• The request_type argument of ZCML view declarations and bfg_view decorators can now
be one of the strings GET, POST, PUT, DELETE, or HEAD instead of a reference to the respective
interface type imported from repoze.bfg.interfaces.
• The route ZCML directive now accepts request_type as an alias for its condi-
tion_method argument for symmetry with the view directive.
• The bfg_routesalchemy paster template now provides a unit test and actually uses the database
during a view rendering.

Removals

• Remove repoze.bfg.threadlocal.setManager. It was only used in unit tests.


• Remove repoze.bfg.wsgi.HTTPException, repoze.bfg.wsgi.NotFound, and
repoze.bfg.wsgi.Unauthorized. These classes were disused with the introduction of the
IUnauthorizedView and INotFoundView machinery.

0.6. Change History 1181


The Pyramid Web Framework, Version 2.0.2

Documentation

• Add description to narrative templating chapter about how to use Chameleon text templates.
• Changed Views narrative chapter to use method strings rather than interface types, and moved ad-
vanced interface type usage to Events narrative chapter.
• Added a Routes+SQLAlchemy wiki tutorial.

0.9a8 (2009-05-31)

Features

• It is now possible to register a custom repoze.bfg.interfaces.INotFoundView


for a given application. This feature replaces the repoze.bfg.interfaces.
INotFoundAppFactory feature previously described in the Hooks chapter. The INot-
FoundView will be called when the framework detects that a view lookup done as a result of a
request fails; it should accept a context object and a request object; it should return an IResponse
object (a webob response, basically). See the Hooks narrative chapter of the BFG docs for more
info.
• The error presented when a view invoked by the router returns a non-response object now includes
the view’s name for troubleshooting purposes.

Bug Fixes

• A ”new response” event is emitted for forbidden and notfound views.

Deprecations

• The repoze.bfg.interfaces.INotFoundAppFactory interface has been deprecated in


favor of using the new repoze.bfg.interfaces.INotFoundView mechanism.

Renames

• Renamed repoze.bfg.interfaces.IForbiddenResponseFactory to repoze.


bfg.interfaces.IForbiddenView.

1182 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.9a7 (2009-05-30)

Features

• Remove ”context” argument from effective_principals and authenticated_userid


function APIs in repoze.bfg.security, effectively a doing reversion to 0.8 and before behav-
ior. Both functions now again accept only the request parameter.

0.9a6 (2009-05-29)

Documentation

• Changed ”BFG Wiki” tutorial to use AuthTktAuthenticationPolicy rather than repoze.who.

Features

• Add an AuthTktAuthenticationPolicy. This policy retrieves credentials from an auth_tkt cookie


managed by the application itself (instead of relying on an upstream data source for authentication
data). See the Security API chapter of the documentation for more info.
• Allow RemoteUserAuthenticationPolicy and RepozeWho1AuthenticationPolicy to accept various
constructor arguments. See the Security API chapter of the documentation for more info.

0.9a5 (2009-05-28)

Features

• Add a get_app API functions to the paster module. This obtains a WSGI application from a
config file given a config file name and a section name. See the repoze.bfg.paster API docs
for more information.
• Add a new module named scripting. It contains a get_root API function, which, provided a
Router instance, returns a traversal root object and a ”closer”. See the repoze.bfg.scripting
API docs for more info.

0.6. Change History 1183


The Pyramid Web Framework, Version 2.0.2

0.9a4 (2009-05-27)

Bug Fixes

• Try checking for an ”old style” security policy after we parse ZCML (thinko).

0.9a3 (2009-05-27)

Features

• Allow IAuthenticationPolicy and IAuthorizationPolicy to be overridden via ZCML registrations (do


ZCML parsing after registering these in router.py).

Documentation

• Added ”BFG Wiki” tutorial to documentation; it describes step-by-step how to create a traversal-
based ZODB application with authentication.

Deprecations

• Added deprecations for imports of ACLSecurityPolicy, InheritingACLSecurity-


Policy, RemoteUserACLSecurityPolicy, RemoteUserInheritingACLSecuri-
tyPolicy, WhoACLSecurityPolicy, and WhoInheritingACLSecurityPolicy from
the repoze.bfg.security module; for the meantime (for backwards compatibility purposes)
these live in the repoze.bfg.secpols module. Note however, that the entire concept of a ”se-
curity policy” is deprecated in BFG in favor of separate authentication and authorization policies,
so any use of a security policy will generate additional deprecation warnings even if you do start
using repoze.bfg.secpols. repoze.bfg.secpols will disappear in a future release of
repoze.bfg.

1184 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Deprecated Import Alias Removals

• Remove repoze.bfg.template module. All imports from this package have been dep-
recated since 0.3.8. Instead, import get_template, render_template, and ren-
der_template_to_response from the repoze.bfg.chameleon_zpt module.
• Remove backwards compatibility import alias for repoze.bfg.traversal.split_path
(deprecated since 0.6.5). This must now be imported as repoze.bfg.traversal.
traversal_path).
• Remove backwards compatibility import alias for repoze.bfg.urldispatch.
RoutesContext (deprecated since 0.6.5). This must now be imported as repoze.bfg.
urldispatch.DefaultRoutesContext.
• Removed backwards compatibility import aliases for repoze.bfg.router.get_options
and repoze.bfg.router.Settings (deprecated since 0.6.2). These both must now be im-
ported from repoze.bfg.settings.
• Removed backwards compatibility import alias for repoze.bfg.interfaces.
IRootPolicy (deprecated since 0.6.2). It must be imported as repoze.bfg.interfaces.
IRootFactory now.
• Removed backwards compatibility import alias for repoze.bfg.interfaces.
ITemplate (deprecated since 0.4.4). It must be imported as repoze.bfg.interfaces.
ITemplateRenderer now.
• Removed backwards compatibility import alias for repoze.bfg.interfaces.
ITemplateFactory (deprecated since 0.4.4). It must be imported as repoze.bfg.
interfaces.ITemplateRendererFactory now.
• Removed backwards compatibility import alias for repoze.bfg.chameleon_zpt.
ZPTTemplateFactory (deprecated since 0.4.4). This must be imported as repoze.
bfg.ZPTTemplateRenderer now.

0.9a2 (2009-05-27)

Features

• A paster command has been added named ”bfgshell”. This command can be used to get an interactive
prompt with your BFG root object in the global namespace. E.g.:

bin/paster bfgshell /path/to/myapp.ini myapp

See the Project chapter in the BFG documentation for more information.

0.6. Change History 1185


The Pyramid Web Framework, Version 2.0.2

Deprecations

• The name repoze.bfg.registry.registry_manager was never an API, but scripts in the


wild were using it to set up an environment for use under a debug shell. A backwards compatibility
shim has been added for this purpose, but the feature is deprecated.

0.9a1 (2009-5-27)

Features

• New API functions named forget and remember are available in the security module. The
forget function returns headers which will cause the currently authenticated user to be logged out
when set in a response. The remember function (when passed the proper arguments) will return
headers which will cause a principal to be ”logged in” when set in a response. See the Security API
chapter of the docs for more info.
• New keyword arguments to the repoze.bfg.router.make_app call have been added:
authentication_policy and authorization_policy. These should, respec-
tively, be an implementation of an authentication policy (an object implementing the
repoze.bfg.interfaces.IAuthenticationPolicy interface) and an implementa-
tion of an authorization policy (an object implementing repoze.bfg.interfaces.
IAuthorizationPolicy). Concrete implementations of authentication policies exist in
repoze.bfg.authentication. Concrete implementations of authorization policies exist in
repoze.bfg.authorization.
Both authentication_policy and authorization_policy default to None.
If authentication_policy is None, but authorization_policy is not None, then
authorization_policy is ignored (the ability to do authorization depends on authentication).
If the authentication_policy argument is not None, and the authorization_policy
argument is None, the authorization policy defaults to an authorization implementation that uses
ACLs (repoze.bfg.authorization.ACLAuthorizationPolicy).
We no longer encourage configuration of ”security policies” using ZCML, as previously we did for
ISecurityPolicy. This is because it’s not uncommon to need to configure settings for concrete
authorization or authentication policies using paste .ini parameters; the app entry point for your
application is the natural place to do this.
• Two new abstractions have been added in the way of adapters used by the system: an IAutho-
rizationPolicy and an IAuthenticationPolicy. A combination of these (as registered
by the securitypolicy ZCML directive) take the place of the ISecurityPolicy abstrac-
tion in previous releases of repoze.who. The API functions in repoze.who.security (such

1186 CONTENTS
The Pyramid Web Framework, Version 2.0.2

as authentication_userid, effective_principals, has_permission, and so on)


have been changed to try to make use of these new adapters. If you’re using an older ISecuri-
tyPolicy adapter, the system will still work, but it will print deprecation warnings when such a
policy is used.
• The way the (internal) IViewPermission utilities registered via ZCML are invoked has changed. They
are purely adapters now, returning a boolean result, rather than returning a callable. You shouldn’t
have been using these anyway. ;-)
• New concrete implementations of IAuthenticationPolicy have been added to the repoze.bfg.
authentication module: RepozeWho1AuthenticationPolicy which uses repoze.
who identity to retrieve authentication data from and RemoteUserAuthenticationPolicy,
which uses the REMOTE_USER value in the WSGI environment to retrieve authentication data.
• A new concrete implementation of IAuthorizationPolicy has been added to the repoze.bfg.
authorization module: ACLAuthorizationPolicy which uses ACL inheritance to do
authorization.
• It is now possible to register a custom repoze.bfg.interfaces.
IForbiddenResponseFactory for a given application. This feature replaces the repoze.
bfg.interfaces.IUnauthorizedAppFactory feature previously described in the
Hooks chapter. The IForbiddenResponseFactory will be called when the framework detects an
authorization failure; it should accept a context object and a request object; it should return an
IResponse object (a webob response, basically). Read the below point for more info and see the
Hooks narrative chapter of the BFG docs for more info.

Backwards Incompatibilities

• Custom NotFound and Forbidden (nee’ Unauthorized) WSGI applications (registered as a utility
for INotFoundAppFactory and IUnauthorizedAppFactory) could rely on an environment key named
message describing the circumstance of the response. This key has been renamed to repoze.
bfg.message (as per the WSGI spec, which requires environment extensions to contain dots).

Deprecations

• The repoze.bfg.interfaces.IUnauthorizedAppFactory interface


has been deprecated in favor of using the new repoze.bfg.interfaces.
IForbiddenResponseFactory mechanism.
• The view_execution_permitted API should now be imported from the repoze.bfg.
security module instead of the repoze.bfg.view module.

0.6. Change History 1187


The Pyramid Web Framework, Version 2.0.2

• The authenticated_userid and effective_principals APIs in repoze.bfg.


security used to only take a single argument (request). They now accept two arguments
(context and request). Calling them with a single argument is still supported but issues a
deprecation warning. (NOTE: this change was reverted in 0.9a7; meaning the 0.9 versions of these
functions again accept request only, just like 0.8 and before).
• Use of ”old-style” security policies (those base on ISecurityPolicy) is now deprecated. See the
”Security” chapter of the docs for info about activating an authorization policy and an authentication
poicy.

0.8.1 (2009-05-21)

Features

• Class objects may now be used as view callables (both via ZCML and via use of the bfg_view
decorator in Python 2.6 as a class decorator). The calling semantics when using a class as a view
callable is similar to that of using a class as a Zope ”browser view”: the class’ __init__ must
accept two positional parameters (conventionally named context, and request). The resulting
instance must be callable (it must have a __call__ method). When called, the instance should
return a response. For example:

from webob import Response

class MyView(object):
def __init__(self, context, request):
self.context = context
self.request = request

def __call__(self):
return Response('hello from %s!' % self.context)

See the "Views" chapter in the documentation and the


``repoze.bfg.view`` API documentation for more information.

• Removed the pickling of ZCML actions (the code that wrote configure.zcml.cache next to
configure.zcml files in projects). The code which managed writing and reading of the cache
file was a source of subtle bugs when users switched between imperative (e.g. @bfg_view) reg-
istrations and declarative registrations (e.g. the view directive in ZCML) on the same project. On
a moderately-sized project (535 ZCML actions and 15 ZCML files), executing actions read from
the pickle was saving us only about 200ms (2.5 sec vs 2.7 sec average). On very small projects (1
ZCML file and 4 actions), startup time was comparable, and sometimes even slower when reading
from the pickle, and both ways were so fast that it really just didn’t matter anyway.

1188 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.8 (2009-05-18)

Features

• Added a traverse function to the repoze.bfg.traversal module. This function may be


used to retrieve certain values computed during path resolution. See the Traversal API chapter of
the documentation for more information about this function.

Deprecations

• Internal: ITraverser callables should now return a dictionary rather than a tuple. Up until 0.7.0,
all ITraversers were assumed to return a 3-tuple. In 0.7.1, ITraversers were assumed to return a
6-tuple. As (by evidence) it’s likely we’ll need to add further information to the return value of an
ITraverser callable, 0.8 assumes that an ITraverser return a dictionary with certain elements in it.
See the repoze.bfg.interfaces.ITraverser interface for the list of keys that should be
present in the dictionary. ITraversers which return tuples will still work, although a deprecation
warning will be issued.

Backwards Incompatibilities

• If your code used the ITraverser interface directly (not via an API function such as find_model)
via an adapter lookup, you’ll need to change your code to expect a dictionary rather than a 3- or
6-tuple if your code ever gets return values from the default ModelGraphTraverser or RoutesMod-
elTraverser adapters.

0.8a7 (2009-05-16)

Backwards Incompatibilities

• The RoutesMapper class in repoze.bfg.urldispatch has been removed, as well as its


documentation. It had been deprecated since 0.6.3. Code in repoze.bfg.urldispatch.
RoutesModelTraverser which catered to it has also been removed.

0.6. Change History 1189


The Pyramid Web Framework, Version 2.0.2

• The semantics of the route ZCML directive have been simplified. Previously, it was assumed that
to use a route, you wanted to map a route to an externally registered view. The new route directive
instead has a view attribute which is required, specifying the dotted path to a view callable. When
a route directive is processed, a view is registered using the name attribute of the route directive as
its name and the callable as its value. The view_name and provides attributes of the route
directive are therefore no longer used. Effectively, if you were previously using the route directive,
it means you must change a pair of ZCML directives that look like this:

<route
name="home"
path=""
view_name="login"
factory=".models.root.Root"
/>

<view
for=".models.root.Root"
name="login"
view=".views.login_view"
/>

To a ZCML directive that looks like this:

<route
name="home"
path=""
view=".views.login_view"
factory=".models.root.Root"
/>

In other words, to make old code work, remove the view directives that were only there to serve
the purpose of backing route directives, and move their view= attribute into the route directive
itself.
This change also necessitated that the name attribute of the route directive is now required. If
you were previously using route directives without a name attribute, you’ll need to add one (the
name is arbitrary, but must be unique among all route and view statements).
The provides attribute of the route directive has also been removed. This directive specified a
sequence of interface types that the generated context would be decorated with. Since route views
are always generated now for a single interface (repoze.bfg.IRoutesContext) as opposed
to being looked up arbitrarily, there is no need to decorate any context to ensure a view is found.

1190 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Documentation

• Added API docs for the repoze.bfg.testing methods registerAdapter, regis-


terUtiity, registerSubscriber, and cleanUp.
• Added glossary entry for ”root factory”.
• Noted existence of repoze.bfg.pagetemplate template bindings in ”Available Add On Tem-
plate System Bindings” in Templates chapter in narrative docs.
• Update ”Templates” narrative chapter in docs (expand to show a sample template and correct macro
example).

Features

• Courtesty Carlos de la Guardia, added an alchemy Paster template. This paster template sets up
a BFG project that uses SQAlchemy (with SQLite) and uses traversal to resolve URLs. (no Routes
areused). This template can be used via paster create -t bfg_alchemy.
• The Routes Route object used to resolve the match is now put into the environment as bfg.route
when URL dispatch is used.
• You can now change the default Routes ”context factory” globally. See the ”ZCML Hooks” chapter
of the documentation (in the ”Changing the Default Routes Context Factory” section).

0.8a6 (2009-05-11)

Features

• Added a routesalchemy Paster template. This paster template sets up a BFG project that uses
SQAlchemy (with SQLite) and uses Routes exclusively to resolve URLs (no traversal root factory is
used). This template can be used via paster create -t bfg_routesalchemy.

Documentation

• Added documentation to the URL Dispatch chapter about how to catch the root URL using a ZCML
route directive.
• Added documentation to the URL Dispatch chapter about how to perform a cleanup function at the
end of a request (e.g. close the SQL connection).

0.6. Change History 1191


The Pyramid Web Framework, Version 2.0.2

Bug Fixes

• In version 0.6.3, passing a get_root callback (a ”root factory”) to repoze.bfg.router.


make_app became optional if any route declaration was made in ZCML. The intent was to make
it possible to disuse traversal entirely, instead relying entirely on URL dispatch (Routes) to resolve
all contexts. However a compound set of bugs prevented usage of a Routes-based root view (a view
which responds to ”/”). One bug existed in repoze.bfg.urldispatch‘, another existed in Routes itself.
To resolve this issue, the urldispatch module was fixed, and a fork of the Routes trunk was put into
the ”dev” index named Routes-1.11dev-chrism-home. The source for the fork exists at
http://bitbucket.org/chrism/routes-home/ (broken link); its contents have been
merged into the Routes trunk (what will be Routes 1.11).

0.8a5 (2009-05-08)

Features

• Two new security policies were added: RemoteUserInheritingACLSecurityPolicy and WhoInher-


itingACLSecurityPolicy. These are security policies which take into account all ACLs defined in
the lineage of a context rather than stopping at the first ACL found in a lineage. See the ”Security”
chapter of the API documentation for more information.
• The API and narrative documentation dealing with security was changed to introduce the new ”in-
heriting” security policy variants.
• Added glossary entry for ”lineage”.

Deprecations

• The security policy previously named RepozeWhoIdentityACLSecurityPolicy now has


the slightly saner name of WhoACLSecurityPolicy. A deprecation warning is emitted when
this policy is imported under the ”old” name; usually this is due to its use in ZCML within your
application. If you’re getting this deprecation warning, change your ZCML to use the new name,
e.g. change:

<utility
provides="repoze.bfg.interfaces.ISecurityPolicy"
factory="repoze.bfg.security.RepozeWhoIdentityACLSecurityPolicy"
/>

To:

1192 CONTENTS
The Pyramid Web Framework, Version 2.0.2

<utility
provides="repoze.bfg.interfaces.ISecurityPolicy"
factory="repoze.bfg.security.WhoACLSecurityPolicy"
/>

0.8a4 (2009-05-04)

Features

• zope.testing is no longer a direct dependency, although our dependencies (such as zope.


interface, repoze.zcml, etc) still depend on it.
• Tested on Google App Engine. Added a tutorial to the documentation explaining how to deploy a
BFG app to GAE.

Backwards Incompatibilities

• Applications which rely on zope.testing.cleanup.cleanUp in unit tests can still use that
function indefinitely. However, for maximum forward compatibility, they should import cleanUp
from repoze.bfg.testing instead of from zope.testing.cleanup. The BFG paster
templates and docs have been changed to use this function instead of the zope.testing.
cleanup version.

0.8a3 (2009-05-03)

Features

• Don’t require a successful import of zope.testing at BFG application runtime. This allows us
to get rid of zope.testing on platforms like GAE which have file limits.

0.6. Change History 1193


The Pyramid Web Framework, Version 2.0.2

0.8a2 (2009-05-02)

Features

• We no longer include the configure.zcml of the chameleon.zpt package within the


configure.zcml of the ”repoze.bfg.includes” package. This has been a no-op for some time
now.
• The repoze.bfg.chameleon_zpt package no longer imports from chameleon.zpt at
module scope, deferring the import until later within a method call. The chameleon.zpt package
can’t be imported on platforms like GAE.

0.8a1 (2009-05-02)

Deprecation Warning and Import Alias Removals

• Since version 0.6.1, a deprecation warning has been emitted when the name model_url is im-
ported from the repoze.bfg.traversal module. This import alias (and the deprecation warn-
ing) has been removed. Any import of the model_url function will now need to be done from
repoze.bfg.url; any import of the name model_url from repoze.bfg.traversal
will now fail. This was done to remove a dependency on zope.deferredimport.
• Since version 0.6.5, a deprecation warning has been emitted when the name RoutesModelTra-
verser is imported from the repoze.bfg.traversal module. This import alias (and the
deprecation warning) has been removed. Any import of the RoutesModelTraverser class will
now need to be done from repoze.bfg.urldispatch; any import of the name Routes-
ModelTraverser from repoze.bfg.traversal will now fail. This was done to remove a
dependency on zope.deferredimport.

Features

• This release of repoze.bfg is ”C-free”. This means it has no hard dependencies on any software
that must be compiled from C source at installation time. In particular, repoze.bfg no longer
depends on the lxml package.
This change has introduced some backwards incompatibilities, described in the ”Backwards Incom-
patibilities” section below.
• This release was tested on Windows XP. It appears to work fine and all the tests pass.

1194 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

Incompatibilities related to making repoze.bfg ”C-free”:


• Removed the repoze.bfg.chameleon_genshi module, and thus support for Genshi-style
chameleon templates. Genshi-style Chameleon templates depend upon lxml, which is implemented
in C (as opposed to pure Python) and the repoze.bfg core is ”C-free” as of this release. You may
get Genshi-style Chameleon support back by installing the repoze.bfg.chameleon_genshi
package availalable from https://pypi.org/project/repoze.bfg.chameleon_genshi/. All existing code
that depended on the chameleon_genshi module prior to this release of repoze.bfg should
work without change after this addon is installed.
• Removed the repoze.bfg.xslt module and thus support for XSL templates. The repoze.
bfg.xslt module depended upon lxml, which is implemented in C, and the repoze.bfg
core is ”C-free” as of this release. You bay get XSL templating back by installing the repoze.
bfg.xslt package available from http://svn.repoze.org/repoze.bfg.xslt/ (bro-
ken link) (also available in the index at http://dist.repoze.org/bfg/0.8/simple)
(broken link). All existing code that depended upon the xslt module prior to this release of
repoze.bfg should work without modification after this addon is installed.
• Removed the repoze.bfg.interfaces.INodeTemplateRenderer interface and the an
old b/w compat aliases from that interface to repoze.bfg.interfaces.INodeTemplate.
This interface must now be imported from the repoze.bfg.xslt.interfaces package af-
ter installation of the repoze.bfg.xslt addon package described above as repoze.bfg.
interfaces.INodeTemplateRenderer. This interface was never part of any public API.
Other backwards incompatibilities:
• The render_template function in repoze.bfg.chameleon_zpt returns Unicode in-
stead of a string. Likewise, the individual values returned by the iterable created by the ren-
der_template_to_iterable function are also each Unicode. This is actually a backwards
incompatibility inherited from our new use of the combination of chameleon.core 1.0b32 (the
non-lxml-depending version) and chameleon.zpt 1.0b16+ ; the chameleon.zpt PageTem-
plateFile implementation used to return a string, but now returns Unicode.

0.7.1 (2009-05-01)

Index-Related

• The canonical package index location for repoze.bfg has changed. The ”old” index (http:/
/dist.repoze.org/lemonade/dev/simple) (broken link) has been superseded by a new
index location http://dist.repoze.org/bfg/current/simple (broken link). The in-
stallation documentation has been updated as well as the setup.cfg file in this package. The
”lemonade” index still exists, but it is not guaranteed to have the latest BFG software in it, nor will
it be maintained in the future.

0.6. Change History 1195


The Pyramid Web Framework, Version 2.0.2

Features

• The ”paster create” templates have been modified to use links to the new ”bfg.repoze.org” and
”docs.repoze.org” websites.
• Added better documentation for virtual hosting at a URL prefix within the virtual hosting docs
chapter.
• The interface for repoze.bfg.interfaces.ITraverser and the built-in implementa-
tions that implement the interface (repoze.bfg.traversal.ModelGraphTraverser,
and repoze.bfg.urldispatch.RoutesModelTraverser) now expect the __call__
method of an ITraverser to return 3 additional arguments: traversed, virtual_root, and
virtual_root_path (the old contract was that the __call__ method of an ITraverser re-
turned; three arguments, the contract new is that it returns six). traversed will be a sequence of
Unicode names that were traversed (including the virtual root path, if any) or None if no traversal
was performed, virtual_root will be a model object representing the virtual root (or the physical
root if traversal was not performed), and virtual_root_path will be a sequence representing
the virtual root path (a sequence of Unicode names) or None if traversal was not performed.
Six arguments are now returned from BFG ITraversers. They are returned in this order: context,
view_name, subpath, traversed, virtual_root, and virtual_root_path.
Places in the BFG code which called an ITraverser continue to accept a 3-argument return value,
although BFG will generate and log a warning when one is encountered.
• The request object now has the following attributes: traversed (the sequence of names traversed
or None if traversal was not performed), virtual_root (the model object representing the virtual
root, including the virtual root path if any), and virtual_root_path (the seuquence of names
representing the virtual root path or None if traversal was not performed).
• A new decorator named wsgiapp2 was added to the repoze.bfg.wsgi module. This dec-
orator performs the same function as repoze.bfg.wsgi.wsgiapp except it fixes up the
SCRIPT_NAME, and PATH_INFO environment values before invoking the WSGI subapplication.
• The repoze.bfg.testing.DummyRequest object now has default attributes for tra-
versed, virtual_root, and virtual_root_path.
• The RoutesModelTraverser now behaves more like the Routes ”RoutesMiddleware” object when
an element in the match dict is named path_info (usually when there’s a pattern like http:/
/foo/*path_info). When this is the case, the PATH_INFO environment variable is set to
the value in the match dict, and the SCRIPT_NAME is appended to with the prefix of the original
PATH_INFO not including the value of the new variable.
• The notfound debug now shows the traversed path, the virtual root, and the virtual root path too.
• Speed up / clarify ’traversal’ module’s ’model_path’, ’model_path_tuple’, and ’_model_path_list’
functions.

1196 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• In previous releases, the repoze.bfg.url.model_url, repoze.bfg.traversal.


model_path and repoze.bfg.traversal.model_path_tuple functions always ig-
nored the __name__ argument of the root object in a model graph ( effectively replacing it with a
leading / in the returned value) when a path or URL was generated. The code required to perform
this operation was not efficient. As of this release, the root object in a model graph must have a
__name__ attribute that is either None or the empty string ('') for URLs and paths to be gener-
ated properly from these APIs. If your root model object has a __name__ argument that is not one
of these values, you will need to change your code for URLs and paths to be generated properly. If
your model graph has a root node with a string __name__ that is not null, the value of __name__
will be prepended to every path and URL generated.
• The repoze.bfg.location.LocationProxy class and the repoze.bfg.location.
ClassAndInstanceDescr class have both been removed in order to be able to eventually shed
a dependency on zope.proxy. Neither of these classes was ever an API.
• In all previous releases, the repoze.bfg.location.locate function worked like so: if a
model did not explicitly provide the repoze.bfg.interfaces.ILocation interface, lo-
cate returned a LocationProxy object representing model with its __parent__ attribute
assigned to parent and a __name__ attribute assigned to __name__. In this release, the
repoze.bfg.location.locate function simply jams the __name__ and __parent__
attributes on to the supplied model unconditionally, no matter if the object implements ILocation
or not, and it never returns a proxy. This was done because the LocationProxy behavior has now
moved into an add-on package (repoze.bfg.traversalwrapper), in order to eventually be
able to shed a dependency on zope.proxy.
• In all previous releases, by default, if traversal was used (as opposed to URL-dispatch), and the
root object supplied the“repoze.bfg.interfaces.ILocation“ interface, but the children returned via its
__getitem__ returned an object that did not implement the same interface, repoze.bfg pro-
vided some implicit help during traversal. This traversal feature wrapped subobjects from the root
(and thereafter) that did not implement ILocation in proxies which automatically provided them
with a __name__ and __parent__ attribute based on the name being traversed and the previ-
ous object traversed. This feature has now been removed from the base repoze.bfg package for
purposes of eventually shedding a dependency on zope.proxy.
In order to re-enable the wrapper behavior for older applications which cannot be changed, regis-
ter the ”traversalwrapper” ModelGraphTraverser as the traversal policy, rather than the de-
fault ModelGraphTraverser. To use this feature, you will need to install the repoze.bfg.
traversalwrapper package (an add-on package, available at https://pypi.org/project/repoze.
bfg.traversalwrapper/) Then change your application’s configure.zcml to include the follow-
ing stanza:
<adapter
factory=”repoze.bfg.traversalwrapper.ModelGraphTraverser” pro-
vides=”repoze.bfg.interfaces.ITraverserFactory” for=”*” />

0.6. Change History 1197


The Pyramid Web Framework, Version 2.0.2

When this ITraverserFactory is used instead of the default, no object in the graph (even
the root object) must supply a __name__ or __parent__ attribute. Even if sub-
objects returned from the root do implement the ILocation interface, these will still
be wrapped in proxies that override the object’s ”real” __parent__ and __name__
attributes.
See also changes to the ”Models” chapter of the documentation (in the ”Location-Aware
Model Instances”) section.

0.7.0 (2009-04-11)

Bug Fixes

• Fix a bug in repoze.bfg.wsgi.HTTPException: the content length was returned as an int


rather than as a string.
• Add explicit dependencies on zope.deferredimport, zope.deprecation, and zope.
proxy for forward compatibility reasons (zope.component will stop relying on zope.
deferredimport soon and although we use it directly, it’s only a transitive dependency, and
”zope.deprecation“ and zope.proxy are used directly even though they’re only transitive depen-
dencies as well).
• Using model_url or model_path against a broken model graph (one with models that had a
non-root model with a __name__ of None) caused an inscrutable error to be thrown: ( if not
_must_quote[cachekey].search(s): TypeError: expected string or
buffer). Now URLs and paths generated against graphs that have None names in intermediate
nodes will replace the None with the empty string, and, as a result, the error won’t be raised. Of
course the URL or path will still be bogus.

Features

• Make it possible to have testing.DummyTemplateRenderer return some nondefault string


representation.
• Added a new anchor keyword argument to model_url. If anchor is present, its string rep-
resentation will be used as a named anchor in the generated URL (e.g. if anchor is passed as
foo and the model URL is http://example.com/model/url, the generated URL will be
http://example.com/model/url#foo).

1198 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Backwards Incompatibilities

• The default request charset encoding is now utf-8. As a result, the request machinery will at-
tempt to decode values from the utf-8 encoding to Unicode automatically when they are obtained
via request.params, request.GET, and request.POST. The previous behavior of BFG
was to return a bytestring when a value was accessed in this manner. This change will break form
handling code in apps that rely on values from those APIs being considered bytestrings. If you are
manually decoding values from form submissions in your application, you’ll either need to change
the code that does that to expect Unicode values from request.params, request.GET and
request.POST, or you’ll need to explicitly reenable the previous behavior. To reenable the pre-
vious behavior, add the following to your application’s configure.zcml:

<subscriber for="repoze.bfg.interfaces.INewRequest"
handler="repoze.bfg.request.make_request_ascii"/>

See also the documentation in the ”Views” chapter of the BFG docs entitled ”Using Views to Handle
Form Submissions (Unicode and Character Set Issues)”.

Documentation

• Add a section to the narrative Views chapter entitled ”Using Views to Handle Form Submissions
(Unicode and Character Set Issues)” explaining implicit decoding of form data values.

0.6.9 (2009-02-16)

Bug Fixes

• lru cache was unstable under concurrency (big surprise!) when it tried to redelete a key in the cache
that had already been deleted. Symptom: line 64 in put:del data[oldkey]:KeyError: ’/some/path’.
Now we just ignore the key error if we can’t delete the key (it has already been deleted).
• Empty location names in model paths when generating a URL using repoze.bfg.model_url
based on a model obtained via traversal are no longer ignored in the generated URL. This means
that if a non-root model object has a __name__ of '', the URL will reflect it (e.g. model_url
will generate http://foo/bar//baz if an object with the __name__ of '' is a child of bar
and the parent of baz). URLs generated with empty path segments are, however, still irresolveable
by the model graph traverser on request ingress (the traverser strips empty path segment names).

0.6. Change History 1199


The Pyramid Web Framework, Version 2.0.2

Features

• Microspeedups of repoze.bfg.traversal.model_path, repoze.bfg.traversal.


model_path_tuple, repoze.bfg.traversal.quote_path_segment, and
repoze.bfg.url.urlencode.
• add zip_safe = false to setup.cfg.

Documentation

• Add a note to the repoze.bfg.traversal.quote_path_segment API docs about


caching of computed values.

Implementation Changes

• Simplification of repoze.bfg.traversal.TraversalContextURL.__call__ (it now


uses repoze.bfg.traversal.model_path instead of rolling its own path-generation).

0.6.8 (2009-02-05)

Backwards Incompatibilities

• The repoze.bfg.traversal.model_path API now returns a quoted string rather than a


string represented by series of unquoted elements joined via / characters. Previously it returned a
string or unicode object representing the model path, with each segment name in the path joined
together via / characters, e.g. /foo /bar. Now it returns a string, where each segment is a
UTF-8 encoded and URL-quoted element e.g. /foo%20/bar. This change was (as discussed
briefly on the repoze-dev maillist) necessary to accommodate model objects which themselves have
__name__ attributes that contain the / character.
For people that have no models that have high-order Unicode __name__ attributes or __name__
attributes with values that require URL-quoting with in their model graphs, this won’t cause any
issue. However, if you have code that currently expects model_path to return an unquoted string,
or you have an existing application with data generated via the old method, and you’re too lazy to
change anything, you may wish replace the BFG-imported model_path in your code with this
function (this is the code of the ”old” model_path implementation):

1200 CONTENTS
The Pyramid Web Framework, Version 2.0.2

from repoze.bfg.location import lineage

def i_am_too_lazy_to_move_to_the_new_model_path(model, *elements):


rpath = []
for location in lineage(model):
if location.__name__:
rpath.append(location.__name__)
path = '/' + '/'.join(reversed(rpath))
if elements:
suffix = '/'.join(elements)
path = '/'.join([path, suffix])
return path

• The repoze.bfg.traversal.find_model API no longer implicitly converts unicode rep-


resentations of a full path passed to it as a Unicode object into a UTF-8 string. Callers should
either use prequoted path strings returned by repoze.bfg.traversal.model_path, or tu-
ple values returned by the result of repoze.bfg.traversal.model_path_tuple or they
should use the guidelines about passing a string path argument described in the find_model
API documentation.

Bugfixes

• Each argument contained in elements passed to repoze.bfg.traversal.model_path


will now have any / characters contained within quoted to %2F in the returned string. Previously, /
characters in elements were left unquoted (a bug).

Features

• A repoze.bfg.traversal.model_path_tuple API was added. This API is an alterna-


tive to model_path (which returns a string); model_path_tuple returns a model path as a
tuple (much like Zope’s getPhysicalPath).
• A repoze.bfg.traversal.quote_path_segment API was added. This API will quote
an individual path segment (string or unicode object). See the repoze.bfg.traversal API
documentation for more information.
• The repoze.bfg.traversal.find_model API now accepts ”path tuples” (see the above
note regarding model_path_tuple) as well as string path representations (from repoze.bfg.
traversal.model_path) as a path argument.
• Add ‘ renderer‘ argument (defaulting to None) to repoze.bfg.testing.
registerDummyRenderer. This makes it possible, for instance, to register a custom
renderer that raises an exception in a unit test.

0.6. Change History 1201


The Pyramid Web Framework, Version 2.0.2

Implementation Changes

• Moved _url_quote function back to repoze.bfg.traversal from repoze.bfg.url. This


is not an API.

0.6.7 (2009-01-27)

Features

• The repoze.bfg.url.model_url API now works against contexts derived from Routes URL
dispatch (Routes.util.url_for is called under the hood).
• ”Virtual root” support for traversal-based applications has been added. Virtual root support is useful
when you’d like to host some model in a repoze.bfg model graph as an application under a URL
pathname that does not include the model path itself. For more information, see the (new) ”Virtual
Hosting” chapter in the documentation.
• A repoze.bfg.traversal.virtual_root API has been added. When called, it returns
the virtual root object (or the physical root object if no virtual root has been specified).

Implementation Changes

• repoze.bfg.traversal.RoutesModelTraverser has been moved to repoze.bfg.


urldispatch.
• model_url URL generation is now performed via an adapter lookup based on the context and the
request.
• ZCML which registers two adapters for the IContextURL interface has been added to the config-
ure.zcml in repoze.bfg.includes.

0.6.6 (2009-01-26)

Implementation Changes

• There is an indirection in repoze.bfg.url.model_url now that consults a utility to generate


the base model url (without extra elements or a query string). Eventually this will service virtual
hosting; for now it’s undocumented and should not be hooked.

1202 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.6.5 (2009-01-26)

Features

• You can now override the NotFound and Unauthorized responses that repoze.bfg generates when
a view cannot be found or cannot be invoked due to lack of permission. See the ”ZCML Hooks”
chapter in the docs for more information.
• Added Routes ZCML directive attribute explanations in documentation.
• Added a traversal_path API to the traversal module; see the ”traversal” API chapter in the
docs. This was a function previously known as split_path that was not an API but people were
using it anyway. Unlike split_path, it now returns a tuple instead of a list (as its values are
cached).

Behavior Changes

• The repoze.bfg.view.render_view_to_response API will no longer raise a ValueEr-


ror if an object returned by a view function it calls does not possess certain attributes (headerlist,
app_iter, status). This API used to attempt to perform a check using the is_response
function in repoze.bfg.view, and raised a ValueError if the is_response check failed.
The responsibility is now the caller’s to ensure that the return value from a view function is a ”real”
response.
• WSGI environ dicts passed to repoze.bfg ’s Router must now contain a REQUEST_METHOD
key/value; if they do not, a KeyError will be raised (speed).
• It is no longer permissible to pass a ”nested” list of principals to repoze.bfg.
ACLAuthorizer.permits (e.g. ['fred', ['larry', 'bob']]). The principals list
must be fully expanded. This feature was never documented, and was never an API, so it’s not a
backwards incompatibility.
• It is no longer permissible for a security ACE to contain a ”nested” list of permissions (e.g. (Allow,
Everyone, ['read', ['view', ['write', 'manage']]])`)`. The list must
instead be fully expanded (e.g. ``(Allow, Everyone, ['read', 'view',
'write', 'manage])). This feature was never documented, and was never an API, so it’s not
a backwards incompatibility.
• The repoze.bfg.urldispatch.RoutesRootFactory now injects the wsgiorg.
routing_args environment variable into the environ when a route matches. This is a tuple
of ((), routing_args) where routing_args is the value that comes back from the routes mapper match
(the ”match dict”).
• The repoze.bfg.traversal.RoutesModelTraverser class now wants to obtain the
view_name and subpath from the wsgiorgs.routing_args environment variable. It falls
back to obtaining these from the context for backwards compatibility.

0.6. Change History 1203


The Pyramid Web Framework, Version 2.0.2

Implementation Changes

• Get rid of repoze.bfg.security.ACLAuthorizer: the ACLSecurityPolicy now


does what it did inline.
• Get rid of repoze.bfg.interfaces.NoAuthorizationInformation exception: it
was used only by ACLAuthorizer.
• Use a homegrown NotFound error instead of webob.exc.HTTPNotFound (the latter is slow).
• Use a homegrown Unauthorized error instead of webob.exc.Unauthorized (the latter is
slow).
• the repoze.bfg.lru.lru_cached decorator now uses functools.wraps in order to make doc-
umentation of LRU-cached functions possible.
• Various speed micro-tweaks.

Bug Fixes

• repoze.bfg.testing.DummyModel did not have a get method; it now does.

0.6.4 (2009-01-23)

Backwards Incompatibilities

• The unicode_path_segments configuration variable and the


BFG_UNICODE_PATH_SEGMENTS configuration variable have been removed. Path seg-
ments are now always passed to model __getitem__ methods as unicode. ”True” has been the
default for this setting since 0.5.4, but changing this configuration setting to false allowed you to go
back to passing raw path element strings to model __getitem__ methods. Removal of this knob
services a speed goal (we get about +80 req/s by removing the check), and it’s clearer just to always
expect unicode path segments in model __getitem__ methods.

1204 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Implementation Changes

• repoze.bfg.traversal.split_path now also handles decoding path segments to unicode


(for speed, because its results are cached).
• repoze.bfg.traversal.step was made a method of the
ModelGraphTraverser.
• Use ”precooked” Request subclasses (e.g. repoze.bfg.request.GETRequest) that corre-
spond to HTTP request methods within router.py when constructing a request object rather than
using alsoProvides to attach the proper interface to an unsubclassed webob.Request. This
pattern is purely an optimization (e.g. preventing calls to alsoProvides means the difference
between 590 r/s and 690 r/s on a MacBook 2GHz).
• Tease out an extra 4% performance boost by changing the Router; instead of using imported ZCA
APIs, use the same APIs directly against the registry that is an attribute of the Router.
• The registry used by BFG is now a subclass of zope.component.registry.Components
(defined as repoze.bfg.registry.Registry); it has a notify method, a register-
SubscriptionAdapter and a registerHandler method. If no subscribers are registered
via registerHandler or registerSubscriptionAdapter, notify is a noop for speed.
• The Allowed and Denied classes in repoze.bfg.security now are lazier about
constructing the representation of a reason message for speed; repoze.bfg.
view_execution_permitted takes advantage of this.
• The is_response check was sped up by about half at the expense of making its code slightly
uglier.

New Modules

• repoze.bfg.lru implements an LRU cache class and a decorator for internal use.

0.6.3 (2009-01-19)

Bug Fixes

• Readd root_policy attribute on Router object (as a property which returns the IRootFactory
utility). It was inadvertently removed in 0.6.2. Code in the wild depended upon its presence (esp.
scripts and ”debug” helpers).

0.6. Change History 1205


The Pyramid Web Framework, Version 2.0.2

Features

• URL-dispatch has been overhauled: it is no longer necessary to manually create a RoutesMap-


per in your application’s entry point callable in order to use URL-dispatch (aka Routes). A new
route directive has been added to the available list of ZCML directives. Each route directive in-
serted into your application’s configure.zcml establishes a Routes mapper connection. If any
route declarations are made via ZCML within a particular application, the get_root callable
passed in to repoze.bfg.router.make_app will automatically be wrapped in the equivalent
of a RoutesMapper. Additionally, the new route directive allows the specification of a con-
text_interfaces attribute for a route, this will be used to tag the manufactured routes context
with specific interfaces when a route specifying a context_interfaces attribute is matched.
• A new interface repoze.bfg.interfaces.IContextNotFound was added. This inter-
face is attached to a ”dummy” context generated when Routes cannot find a match and there is no
”fallback” get_root callable that uses traversal.
• The bfg_starter and bfg_zodb ”paster create” templates now contain images and CSS which
are displayed when the default page is displayed after initial project generation.
• Allow the repoze.bfg.view.static helper to be passed a relative root_path name; it will
be considered relative to the file in which it was called.
• The functionality of repoze.bfg.convention has been merged into the core. Applications
which make use of repoze.bfg.convention will continue to work indefinitely, but it is rec-
ommended that apps stop depending upon it. To do so, substitute imports of repoze.bfg.
convention.bfg_view with imports of repoze.bfg.view.bfg_view, and change the
stanza in ZCML from <convention package="."> to <scan package=".">. As a result
of the merge, bfg has grown a new dependency: martian.
• View functions which use the pushpage decorator are now pickleable (meaning their use won’t pre-
vent a configure.zcml.cache file from being written to disk).
• Instead of invariably using webob.Request as the ”request factory” (e.g. in the
Router class) and webob.Response and the ”response factory” (e.g. in ren-
der_template_to_response), allow both to be overridden via a ZCML utility hook. See
the ”Using ZCML Hooks” chapter of the documentation for more information.

Deprecations

• The class repoze.bfg.urldispatch.RoutesContext has been renamed to repoze.


bfg.urldispatch.DefaultRoutesContext. The class should be imported by the new
name as necessary (although in reality it probably shouldn’t be imported from anywhere except
internally within BFG, as it’s not part of the API).

1206 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Implementation Changes

• The repoze.bfg.wsgi.wsgiapp decorator now uses webob.Request.get_response


to do its work rather than relying on homegrown WSGI code.
• The repoze.bfg.view.static helper now uses webob.Request.get_response to do
its work rather than relying on homegrown WSGI code.
• The repoze.bfg.urldispatch.RoutesModelTraverser class has been moved to
repoze.bfg.traversal.RoutesModelTraverser.
• The repoze.bfg.registry.makeRegistry function was renamed to repoze.bfg.
registry.populateRegistry and now accepts a registry argument (which should be
an instance of zope.component.registry.Components).

Documentation Additions

• Updated narrative urldispatch chapter with changes required by <route..> ZCML directive.
• Add a section on ”Using BFG Security With URL Dispatch” into the urldispatch chapter of the
documentation.
• Better documentation of security policy implementations that ship with repoze.bfg.
• Added a ”Using ZPT Macros in repoze.bfg” section to the narrative templating chapter.

0.6.2 (2009-01-13)

Features

• Tests can be run with coverage output if you’ve got nose installed in the interpreter which you use
to run tests. Using an interpreter with nose installed, do python setup.py nosetests
within a checkout of the repoze.bfg package to see test coverage output.
• Added a post argument to the repoze.bfg.testing:DummyRequest constructor.
• Added __len__ and __nonzero__ to repoze.bfg.testing:DummyModel.
• The repoze.bfg.registry.get_options callable (now renamed to repoze.bfg.
setings.get_options) used to return only framework-specific keys and values in the dic-
tionary it returned. It now returns all the keys and values in the dictionary it is passed plus
any framework-specific settings culled from the environment. As a side effect, all PasteDeploy
application-specific config file settings are made available as attributes of the ISettings utility
from within BFG.

0.6. Change History 1207


The Pyramid Web Framework, Version 2.0.2

• Renamed the existing BFG paster template to bfg_starter. Added another template
(bfg_zodb) showing default ZODB setup using repoze.zodbconn.
• Add a method named assert_ to the DummyTemplateRenderer. This method accepts keyword
arguments. Each key/value pair in the keyword arguments causes an assertion to be made that the
renderer received this key with a value equal to the asserted value.
• Projects generated by the paster templates now use the DummyTemplateRenderer.assert_
method in their view tests.
• Make the (internal) thread local registry manager maintain a stack of registries in order to make it
possible to call one BFG application from inside another.
• An interface specific to the HTTP verb (GET/PUT/POST/DELETE/HEAD) is attached to each
request object on ingress. The HTTP-verb-related interfaces are defined in repoze.bfg.
interfaces and are IGETRequest, IPOSTRequest, IPUTRequest, IDELETERequest
and IHEADRequest. These interfaces can be specified as the request_type attribute of a bfg
view declaration. A view naming a specific HTTP-verb-matching interface will be found only if the
view is defined with a request_type that matches the HTTP verb in the incoming request. The more
general IRequest interface can be used as the request_type to catch all requests (and this is indeed
the default). All requests implement IRequest. The HTTP-verb-matching idea was pioneered by
repoze.bfg.restrequest . That package is no longer required, but still functions fine.

Bug Fixes

• Fix a bug where the Paste configuration’s unicode_path_segments (and os.environ’s


BFG_UNICODE_PATH_SEGMENTS) may have been defaulting to false in some circumstances.
It now always defaults to true, matching the documentation and intent.
• The repoze.bfg.traversal.find_model API did not work properly when passed
a path argument which was unicode and contained high-order bytes when the uni-
code_path_segments or BFG_UNICODE_PATH_SEGMENTS configuration variables were
”true”.
• A new module was added: repoze.bfg.settings. This contains deployment-settings-related
code.

Implementation Changes

• The make_app callable within repoze.bfg.router now registers the root_policy ar-
gument as a utility (unnamed, using the new repoze.bfg.interfaces.IRootFactory as
a provides interface) rather than passing it as the first argument to the repoze.bfg.router.
Router class. As a result, the repoze.bfg.router.Router router class only accepts a single

1208 CONTENTS
The Pyramid Web Framework, Version 2.0.2

argument: registry. The repoze.bfg.router.Router class retrieves the root policy via
a utility lookup now. The repoze.bfg.router.make_app API also now performs some im-
portant application registrations that were previously handled inside repoze.bfg.registry.
makeRegistry.

New Modules

• A repoze.bfg.settings module was added. It contains code related to deployment settings.


Most of the code it contains was moved to it from the repoze.bfg.registry module.

Behavior Changes

• The repoze.bfg.settings.Settings class (an instance of which is registered as a util-


ity providing repoze.bfg.interfaces.ISettings when any application is started) now
automatically calls repoze.bfg.settings.get_options on the options passed to its con-
structor. This means that usage of get_options within an application’s make_app function is
no longer required (the ”raw” options dict or None may be passed).
• Remove old cold which attempts to recover from trying to unpickle a z3c.pt template; Chameleon
has been the templating engine for a good long time now. Running repoze.bfg against a sandbox that
has pickled z3c.pt templates it will now just fail with an unpickling error, but can be fixed by
deleting the template cache files.

Deprecations

• Moved the repoze.bfg.registry.Settings class. This has been moved to repoze.


bfg.settings.Settings. A deprecation warning is issued when it is imported from the older
location.
• Moved the repoze.bfg.registry.get_options function This has been moved to
repoze.bfg.settings.get_options. A deprecation warning is issued when it is imported
from the older location.
• The repoze.bfg.interfaces.IRootPolicy interface was renamed within the interfaces
package. It has been renamed to IRootFactory. A deprecation warning is issued when it is
imported from the older location.

0.6. Change History 1209


The Pyramid Web Framework, Version 2.0.2

0.6.1 (2009-01-06)

New Modules

• A new module repoze.bfg.url has been added. It contains the model_url API (moved from
repoze.bfg.traversal) and an implementation of urlencode (like Python’s urllib.
urlencode) which can handle Unicode keys and values in parameters to the query argument.

Deprecations

• The model_url function has been moved from repoze.bfg.traversal into repoze.
bfg.url. It can still be imported from repoze.bfg.traversal but an import from
repoze.bfg.traversal will emit a DeprecationWarning.

Features

• A static helper class was added to the repoze.bfg.views module. Instances of this class
are willing to act as BFG views which return static resources using files on disk. See the repoze.
bfg.view docs for more info.
• The repoze.bfg.url.model_url API (nee’ repoze.bfg.traversal.model_url)
now accepts and honors a keyword argument named query. The value of this argument will be used
to compose a query string, which will be attached to the generated URL before it is returned. See
the API docs (in the docs directory or on the web http://static.repoze.org/bfgdocs)
(broken URL) for more information.

0.6 (2008-12-26)

Backwards Incompatibilities

• Rather than prepare the ”stock” implementations of the ZCML directives from the zope.
configuration package for use under repoze.bfg, repoze.bfg now makes available
the implementations of directives from the repoze.zcml package (see https://pypi.org/project/
repoze.zcml/). As a result, the repoze.bfg package now depends on the repoze.zcml
package, and no longer depends directly on the zope.component, zope.configuration,
zope.interface, or zope.proxy packages.

1210 CONTENTS
The Pyramid Web Framework, Version 2.0.2

The primary reason for this change is to enable us to eventually reduce the number of inappropri-
ate repoze.bfg Zope package dependencies, as well as to shed features of dependent package
directives that don’t make sense for repoze.bfg.
Note that currently the set of requirements necessary to use bfg has not changed. This is due to
inappropriate Zope package requirements in chameleon.zpt, which will hopefully be remedied
soon. NOTE: in lemonade index a 1.0b8-repozezcml0 package exists which does away with these
requirements.
• BFG applications written prior to this release which expect the ”stock” zope.component ZCML
directive implementations (e.g. adapter, subscriber, or utility) to function now must
either 1) include the meta.zcml file from zope.component manually (e.g. <include
package="zope.component" file="meta.zcml">) and include the zope.security
package as an install_requires dependency or 2) change the ZCML in their applications to
use the declarations from repoze.zcml instead of the stock declarations. repoze.zcml only makes
available the adapter, subscriber and utility directives.
In short, if you’ve got an existing BFG application, after this update, if your application won’t start
due to an import error for ”zope.security”, the fastest way to get it working again is to add zope.
security to the ”install_requires” of your BFG application’s setup.py, then add the following
ZCML anywhere in your application’s configure.zcml:

<include package="zope.component" file="meta.zcml">

Then re-setup.py develop or reinstall your application.


• The http://namespaces.repoze.org/bfg XML namespace is now the default XML
namespace in ZCML for paster-generated applications. The docs have been updated to reflect this.
• The copies of BFG’s meta.zcml and configure.zcml were removed from the root of the
repoze.bfg package. In 0.3.6, a new package named repoze.bfg.includes was added,
which contains the ”correct” copies of these ZCML files; the ones that were removed were for
backwards compatibility purposes.
• The BFG view ZCML directive no longer calls zope.component.interface.
provideInterface for the for interface. We don’t support provideInterface in
BFG because it mutates the global registry.

0.6. Change History 1211


The Pyramid Web Framework, Version 2.0.2

Other

• The minimum requirement for chameleon.core is now 1.0b13. The minimum requirement for
chameleon.zpt is now 1.0b8. The minimum requirement for chameleon.genshi is now
1.0b2.
• Updated paster template ”ez_setup.py” to one that requires setuptools 0.6c9.
• Turn view_execution_permitted from the repoze.bfg.view module into a docu-
mented API.
• Doc cleanups.
• Documented how to create a view capable of serving static resources.

0.5.6 (2008-12-18)

• Speed up traversal.model_url execution by using a custom url quoting function instead of


Python’s urllib.quote, by caching URL path segment quoting and encoding results, by disus-
ing Python’s urlparse.urljoin in favor of a simple string concatenation, and by using ob.
__class__ is unicode rather than isinstance(ob, unicode) in one strategic place.

0.5.5 (2008-12-17)

Backwards Incompatibilities

• In the past, during traversal, the ModelGraphTraverser (the default traverser) always passed each
URL path segment to any __getitem__ method of a model object as a byte string (a str ob-
ject). Now, by default the ModelGraphTraverser attempts to decode the path segment to Unicode
(a unicode object) using the UTF-8 encoding before passing it to the __getitem__ method of
a model object. This makes it possible for model objects to be dumber in __getitem__ when
trying to resolve a subobject, as model objects themselves no longer need to try to divine whether or
not to try to decode the path segment passed by the traverser.
Note that since 0.5.4, URLs generated by repoze.bfg’s model_url API will contain UTF-8 en-
coded path segments as necessary, so any URL generated by BFG itself will be decodeable by the
traverser. If another application generates URLs to a BFG application, to be resolved successfully,
it should generate the URL with UTF-8 encoded path segments to be successfully resolved. The
decoder is not at all magical: if a non-UTF-8-decodeable path segment (e.g. one encoded using
UTF-16 or some other insanity) is passed in the URL, BFG will raise a TypeError with a mes-
sage indicating it could not decode the path segment.

1212 CONTENTS
The Pyramid Web Framework, Version 2.0.2

To turn on the older behavior, where path segments were not decoded to Unicode before being
passed to model object __getitem__ by the traverser, and were passed as a raw byte string, set
the unicode_path_segments configuration setting to a false value in your BFG application’s
section of the paste .ini file, for example:

unicode_path_segments = False

Or start the application using the BFG_UNICODE_PATH_SEGMENT envvar set to a false value:

BFG_UNICODE_PATH_SEGMENTS=0

0.5.4 (2008-12-13)

Backwards Incompatibilities

• URL-quote ”extra” element names passed in as **elements to the traversal.model_url


API. If any of these names is a Unicode string, encode it to UTF-8 before URL-quoting. This is a
slight backwards incompatibility that will impact you if you were already UTF-8 encoding or URL-
quoting the values you passed in as elements to this API.

Bugfixes

• UTF-8 encode each segment in the model path used to generate a URL before url-quoting it within
the traversal.model_url API. This is a bugfix, as Unicode cannot always be successfully
URL-quoted.

Features

• Make it possible to run unit tests using a buildout-generated Python ”interpreter”.


• Add request.root to router.Router in order to have easy access to the application root.

0.6. Change History 1213


The Pyramid Web Framework, Version 2.0.2

0.5.3 (2008-12-07)

• Remove the ITestingTemplateRenderer interface. When testing.


registerDummyRenderer is used, it instead registers a dummy implementation using
ITemplateRenderer interface, which is checked for when the built-in templating facilities do
rendering. This change also allows developers to make explicit named utility registrations in the
ZCML registry against ITemplateRenderer; these will be found before any on-disk template
is looked up.

0.5.2 (2008-12-05)

• The component registration handler for views (functions or class instances) now observes component
adaptation annotations (see zope.component.adaptedBy) and uses them before the fallback
values for for_ and request_type. This change does not affect existing code insomuch as
the code does not rely on these defaults when an annotation is set on the view (unlikely). This
means that for a new-style class you can do zope.component.adapts(ISomeContext,
ISomeRequest) at class scope or at module scope as a decorator to a bfg view function you can
do @zope.component.adapter(ISomeContext, ISomeRequest). This differs from
r.bfg.convention inasmuch as you still need to put something in ZCML for the registrations to get
done; it’s only the defaults that will change if these declarations exist.
• Strip all slashes from end and beginning of path in clean_path within traversal machinery.

0.5.1 (2008-11-25)

• Add keys, items, and values methods to testing.DummyModel.


• Add __delitem__ method to testing.DummyModel.

0.5.0 (2008-11-18)

• Fix ModelGraphTraverser; don’t try to change the __name__ or __parent__ of an object that
claims it implements ILocation during traversal even if the __name__ or __parent__ of the
object traversed does not match the name used in the traversal step or the or the traversal parent .
Rationale: it was insane to do so. This bug was only found due to a misconfiguration in an application
that mistakenly had intermediate persistent non-ILocation objects; traversal was causing a persistent
write on every request under this setup.
• repoze.bfg.location.locate now unconditionally sets __name__ and __parent__
on objects which provide ILocation (it previously only set them conditionally if they didn’t match
attributes already present on the object via equality).

1214 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.4.9 (2008-11-17)

• Add chameleon text template API (chameleon ${name} renderings where the template does not need
to be wrapped in any containing XML).
• Change docs to explain install in terms of a virtualenv (unconditionally).
• Make pushpage decorator compatible with repoze.bfg.convention’s bfg_view decorator when
they’re stacked.
• Add content_length attribute to testing.DummyRequest.
• Change paster template tests.py to include a true unit test. Retain old test as an integration test.
Update documentation.
• Document view registrations against classes and repoze.bfg.convention in context.
• Change the default paster template to register its single view against a class rather than an interface.
• Document adding a request type interface to the request via a subscriber function in the events
narrative documentation.

0.4.8 (2008-11-12)

Backwards Incompatibilities

• repoze.bfg.traversal.model_url now always appends a slash to all generated URLs


unless further elements are passed in as the third and following arguments. Rationale: views often
use model_url without the third-and-following arguments in order to generate a URL for a model
in order to point at the default view of a model. The URL that points to the default view of the root
model is technically http://mysite/ as opposed to http://mysite (browsers happen to ask
for ’/’ implicitly in the GET request). Because URLs are never automatically generated for anything
except models by model_url, and because the root model is not really special, we continue this
pattern. The impact of this change is minimal (at most you will have too many slashes in your URL,
which BFG deals with gracefully anyway).

0.4.7 (2008-11-11)

Features

• Allow testing.registerEventListener to be used with Zope 3 style ”object events” (sub-


scribers accept more than a single event argument). We extend the list with the arguments, rather
than append.

0.6. Change History 1215


The Pyramid Web Framework, Version 2.0.2

0.4.6 (2008-11-10)

Bug Fixes

• The model_path and model_url traversal APIs returned the wrong value for the root object
(e.g. model_path returned '' for the root object, while it should have been returning '/').

0.4.5 (2008-11-09)

Features

• Added a clone method and a __contains__ method to the DummyModel testing object.
• Allow DummyModel objects to receive extra keyword arguments, which will be attached as at-
tributes.
• The DummyTemplateRenderer now returns self as its implementation.

0.4.4 (2008-11-08)

Features

• Added a repoze.bfg.testing module to attempt to make it slightly easier to write unittest-


based automated tests of BFG applications. Information about this module is in the documentation.
• The default template renderer now supports testing better by looking for ITestingTem-
plateRenderer using a relative pathname. This is exposed indirectly through the API named
registerTemplateRenderer in repoze.bfg.testing.

1216 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Deprecations

• The names repoze.bfg.interfaces.ITemplate , repoze.bfg.interfaces.


ITemplateFactory and repoze.bfg.interfaces.INodeTemplate have been depre-
cated. These should now be imported as repoze.bfg.interfaces.ITemplateRenderer
and repoze.bfg.interfaces.ITemplateRendererFactory, and INodeTem-
plateRenderer respectively.
• The name repoze.bfg.chameleon_zpt.ZPTTemplateFactory is deprecated. Use
repoze.bfg.chameleon_zpt.ZPTTemplateRenderer.
• The name repoze.bfg.chameleon_genshi.GenshiTemplateFactory is deprecated.
Use repoze.bfg.chameleon_genshi.GenshiTemplateRenderer.
• The name repoze.bfg.xslt.XSLTemplateFactory is deprecated. Use repoze.bfg.
xslt.XSLTemplateRenderer.

0.4.3 (2008-11-02)

Bug Fixes

• Not passing the result of ”get_options” as the second argument of make_app could cause attribute
errors when attempting to look up settings against the ISettings object (internal). Fixed by giving the
Settings objects defaults for debug_authorization and debug_notfound.
• Return an instance of Allowed (rather than True) from has_permission when no security
policy is in use.
• Fix bug where default deny in authorization check would throw a TypeError (use ACLDenied
instead of Denied).

0.4.2 (2008-11-02)

Features

• Expose a single ILogger named ”repoze.bfg.debug” as a utility; this logger is registered uncondi-
tionally and is used by the authorization debug machinery. Applications may also make use of it as
necessary rather than inventing their own logger, for convenience.

0.6. Change History 1217


The Pyramid Web Framework, Version 2.0.2

• The BFG_DEBUG_AUTHORIZATION envvar and the debug_authorization config file


value now only imply debugging of view-invoked security checks. Previously, information was
printed for every call to has_permission as well, which made output confusing. To debug
has_permission checks and other manual permission checks, use the debugger and print state-
ments in your own code.
• Authorization debugging info is now only present in the HTTP response body oif de-
bug_authorization is true.
• The format of authorization debug messages was improved.
• A new BFG_DEBUG_NOTFOUND envvar was added and a symmetric debug_notfound config
file value was added. When either is true, and a NotFound response is returned by the BFG router
(because a view could not be found), debugging information is printed to stderr. When this value is
set true, the body of HTTPNotFound responses will also contain the same debugging information.
• Allowed and Denied responses from the security machinery are now specialized into two
types: ACL types, and non-ACL types. The ACL-related responses are instances of repoze.
bfg.security.ACLAllowed and repoze.bfg.security.ACLDenied. The non-ACL-
related responses are repoze.bfg.security.Allowed and repoze.bfg.security.
Denied. The allowed-type responses continue to evaluate equal to things that themselves evaluate
equal to the True boolean, while the denied-type responses continue to evaluate equal to things that
themselves evaluate equal to the False boolean. The only difference between the two types is the
information attached to them for debugging purposes.
• Added a new BFG_DEBUG_ALL envvar and a symmetric debug_all config file value. When
either is true, all other debug-related flags are set true unconditionally (e.g. debug_notfound
and debug_authorization).

Documentation

• Added info about debug flag changes.


• Added a section to the security chapter named ”Debugging Imperative Authorization Failures” (for
e.g. has_permssion).

Bug Fixes

• Change default paster template generator to use Paste#http server rather than Paste-
Script#cherrpy server. The cherrypy server has a security risk in it when REMOTE_USER
is trusted by the downstream application.

1218 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.4.1 (2008-10-28)

Bug Fixes

• If the render_view_to_response function was called, if the view was found and called, but
it returned something that did not implement IResponse, the error would pass by unflagged. This
was noticed when I created a view function that essentially returned None, but received a NotFound
error rather than a ValueError when the view was rendered. This was fixed.

0.4.0 (2008-10-03)

Docs

• An ”Environment and Configuration” chapter was added to the narrative portion of the documenta-
tion.

Features

• Ensure bfg doesn’t generate warnings when running under Python 2.6.
• The environment variable BFG_RELOAD_TEMPLATES is now available (serves the same purpose
as reload_templates in the config file).
• A new configuration file option debug_authorization was added. This turns on printing of
security authorization debug statements to sys.stderr. The BFG_DEBUG_AUTHORIZATION
environment variable was also added; this performs the same duty.

Bug Fixes

• The environment variable BFG_SECURITY_DEBUG did not always work. It has been renamed to
BFG_DEBUG_AUTHORIZATION and fixed.

Deprecations

• A deprecation warning is now issued when old API names from the repoze.bfg.templates
module are imported.

0.6. Change History 1219


The Pyramid Web Framework, Version 2.0.2

Backwards incompatibilities

• The BFG_SECURITY_DEBUG environment variable was renamed to


BFG_DEBUG_AUTHORIZATION.

0.3.9 (2008-08-27)

Features

• A repoze.bfg.location API module was added.

Backwards incompatibilities

• Applications must now use the repoze.bfg.interfaces.ILocation interface rather than


zope.location.interfaces.ILocation to represent that a model object is ”location-
aware”. We’ve removed a dependency on zope.location for cleanliness purposes: as new ver-
sions of zope libraries are released which have improved dependency information, getting rid of our
dependence on zope.location will prevent a newly installed repoze.bfg application from re-
quiring the zope.security, egg, which not truly used at all in a ”stock” repoze.bfg setup. These
dependencies are still required by the stack at this time; this is purely a futureproofing move.
The security and model documentation for previous versions of repoze.bfg recommended using
the zope.location.interfaces.ILocation interface to represent that a model object is
”location-aware”. This documentation has been changed to reflect that this interface should now be
imported from repoze.bfg.interfaces.ILocation instead.

0.3.8 (2008-08-26)

Docs

• Documented URL dispatch better in narrative form.

Bug fixes

• Routes URL dispatch did not have access to the WSGI environment, so conditions such as
method=GET did not work.

1220 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Features

• Add principals_allowed_by_permission API to security module.


• Replace z3c.pt support with support for chameleon.zpt. Chameleon is the new name for the
package that used to be named z3c.pt. NOTE: If you update a repoze.bfg SVN checkout that
you’re using for development, you will need to run ”setup.py install” or ”setup.py develop” again in
order to obtain the proper Chameleon packages. z3c.pt is no longer supported by repoze.bfg.
All API functions that used to render z3c.pt templates will work fine with the new packages, and
your templates should render almost identically.
• Add a repoze.bfg.chameleon_zpt module. This module provides Chameleon ZPT support.
• Add a repoze.bfg.xslt module. This module provides XSLT support.
• Add a repoze.bfg.chameleon_genshi module. This provides direct Genshi support, which
did not exist previously.

Deprecations

• Importing API functions directly from repoze.bfg.template is now deprecated. The


get_template, render_template, render_template_to_response functions
should now be imported from repoze.chameleon_zpt. The render_transform, and
render_transform_to_response functions should now be imported from repoze.
bfg.xslt. The repoze.bfg.template module will remain around ”forever” to support
backwards compatibility.

0.3.7 (2008-09-09)

Features

• Add compatibility with z3c.pt 1.0a7+ (z3c.pt became a namespace package).

Bug fixes

• repoze.bfg.traversal.find_model function did not function properly.

0.6. Change History 1221


The Pyramid Web Framework, Version 2.0.2

0.3.6 (2008-09-04)

Features

• Add startup process docs.


• Allow configuration cache to be bypassed by actions which include special ”uncacheable” discrim-
inators (for actions that have variable results).

Bug Fixes

• Move core repoze.bfg ZCML into a repoze.bfg.includes package so we can use repoze.bfg
better as a namespace package. Adjust the code generator to use it. We’ve left around the
configure.zcml in the repoze.bfg package directly so as not to break older apps.
• When a zcml application registry cache was unpickled, and it contained a reference to an object that
no longer existed (such as a view), bfg would not start properly.

0.3.5 (2008-09-01)

Features

• Event notification is issued after application is created and configured


(IWSGIApplicationCreatedEvent).
• New API module: repoze.bfg.view. This module contains the functions named
render_view_to_response, render_view_to_iterable, render_view and
is_response, which are documented in the API docs. These features aid programmatic
(non-server-driven) view execution.

0.3.4 (2008-08-28)

Backwards incompatibilities

• Make repoze.bfg a namespace package so we can allow folks to create subpackages (e.g.
repoze.bfg.otherthing) within separate eggs. This is a backwards incompatible change
which makes it impossible to import ”make_app” and ”get_options” from the repoze.bfg mod-
ule directly. This change will break all existing apps generated by the paster code generator. Instead,
you need to import these functions as repoze.bfg.router:make_app and repoze.bfg.
registry:get_options, respectively. Sorry folks, it has to be done now or never, and defi-
nitely better now.

1222 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Features

• Add model_path API function to traversal module.

Bugfixes

• Normalize path returned by repoze.bfg.caller_path.

0.3.3 (2008-08-23)

• Fix generated test.py module to use project name rather than package name.

0.3.2 (2008-08-23)

• Remove sampleapp sample application from bfg package itself.


• Remove dependency on FormEncode (only needed by sampleapp).
• Fix paster template generation so that case-sensitivity is preserved for project vs. package name.
• Depend on z3c.pt version 1.0a1 (which requires the [lxml] extra currently).
• Read and write a pickled ZCML actions list, stored as configure.zcml.cache next to the
applications’s ”normal” configuration file. A given bfg app will usually start faster if it’s able to read
the pickle data. It fails gracefully to reading the real ZCML file if it cannot read the pickle.

0.3.1 (2008-08-20)

• Generated application differences: make_app entry point renamed to app in order to have a dif-
ferent name than the bfg function of the same name, to prevent confusion.
• Add ”options” processing to bfg’s make_app to support runtime options. A new API func-
tion named get_options was added to the registry module. This function is typically used in
an application’s app entry point. The Paste config file section for the app can now supply the
reload_templates option, which, if true, will prevent the need to restart the appserver in order
for z3c.pt or XSLT template changes to be detected.
• Use only the module name in generated project’s ”test_suite” (run all tests found in the package).
• Default port for generated apps changed from 5432 to 6543 (Postgres default port is 6543).

0.6. Change History 1223


The Pyramid Web Framework, Version 2.0.2

0.3.0 (2008-08-16)

• Add get_template API to template module.

0.2.9 (2008-08-11)

• 0.2.8 was ”brown bag” release. It didn’t work at all. Symptom: ComponentLookupError when
trying to render a page.

0.2.8 (2008-08-11)

• Add find_model and find_root traversal APIs. In the process, make ITraverser a uni-adapter
(on context) rather than a multiadapter (on context and request).

0.2.7 (2008-08-05)

• Add a request_type attribute to the available attributes of a bfg:view configure.zcml ele-


ment. This attribute will have a value which is a dotted Python path, pointing at an interface. If the
request object implements this interface when the view lookup is performed, the appropriate view
will be called. This is meant to allow for simple ”skinning” of sites based on request type. An event
subscriber should attach the interface to the request on ingress to support skins.
• Remove ”template only” views. These were just confusing and were never documented.
• Small url dispatch overhaul: the connect method of the urldispatch.RoutesMapper ob-
ject now accepts a keyword parameter named context_factory. If this parameter is supplied,
it must be a callable which returns an instance. This instance is used as the context for the request
when a route is matched.
• The registration of a RoutesModelTraverser no longer needs to be performed by the application; it’s
in the bfg ZCML now.

0.2.6 (2008-07-31)

• Add event sends for INewRequest and INewResponse. See the events.rst chapter in the documenta-
tion’s api directory.

1224 CONTENTS
The Pyramid Web Framework, Version 2.0.2

0.2.5 (2008-07-28)

• Add model_url API.

0.2.4 (2008-07-27)

• Added url-based dispatch.

0.2.3 (2008-07-20)

• Add API functions for authenticated_userid and effective_principals.

0.2.2 (2008-07-20)

• Add authenticated_userid and effective_principals API to security policy.

0.2.1 (2008-07-20)

• Add find_interface API.

0.2 (2008-07-19)

• Add wsgiapp decorator.


• The concept of ”view factories” was removed in favor of always calling a view, which is a callable
that returns a response directly (as opposed to returning a view). As a result, the factory attribute
in the bfg:view ZCML statement has been renamed to view. Various interface names were changed
also.
• render_template and render_transform no longer return a Response ob-
ject. Instead, these return strings. The old behavior can be obtained by using ren-
der_template_to_response and render_transform_to_response.
• Added ’repoze.bfg.push:pushpage’ decorator, which creates BFG views from callables which take
(context, request) and return a mapping of top-level names.
• Added ACL-based security.
• Support for XSLT templates via a render_transform method

0.6. Change History 1225


The Pyramid Web Framework, Version 2.0.2

0.1 (2008-07-08)

• Initial release.

0.7 Glossary and Index

0.7.1 Glossary

ACE
An access control entry. An access control entry is one element in an ACL. An access control entry
is a three-tuple that describes three things: an action (one of either Allow or Deny), a principal
(a string describing a user or group), and a permission. For example the ACE, (Allow, 'bob',
'read') is a member of an ACL that indicates that the principal bob is allowed the permission
read against the resource the ACL is attached to.
ACL
An access control list. An ACL is a sequence of ACE tuples. An ACL is attached to a resource
instance. An example of an ACL is [ (Allow, 'bob', 'read'), (Deny, 'fred',
'write')]. If an ACL is attached to a resource instance, and that resource is findable via the
context resource, it will be consulted any active security policy to determine whether a particular
request can be fulfilled given the authentication information in the request.
action
Represents a pending configuration statement generated by a call to a configuration directive. The
set of pending configuration actions are processed when pyramid.config.Configurator.
commit() is called.
add-on
A Python distribution that uses Pyramid’s extensibility to plug into a Pyramid application and pro-
vide extra, configurable services.
Agendaless Consulting
A consulting organization formed by Paul Everitt, Tres Seaver, and Chris McDonough.
See also:
See also Agendaless Consulting.
Akhet
Akhet is a Pyramid library and demo application with a Pylons-like feel. It’s most known for its
former application scaffold, which helped users transition from Pylons and those preferring a more
Pylons-like API. The scaffold has been retired but the demo plays a similar role.

1226 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Alembic
Alembic is a lightweight database migration tool for usage with the SQLAlchemy Database Toolkit
for Python.
application registry
A registry of configuration information consulted by Pyramid while servicing an application. An
application registry maps resource types to views, as well as housing other application-specific com-
ponent registrations. Every Pyramid application has one (and only one) application registry.
asset
Any file contained within a Python package which is not a Python source code file.
asset descriptor
An instance representing an asset specification provided by the pyramid.path.
AssetResolver.resolve() method. It supports the methods and attributes documented in
pyramid.interfaces.IAssetDescriptor.
asset specification
A colon-delimited identifier for an asset. The colon separates a Python package name from a package
subpath. For example, the asset specification my.package:static/baz.css identifies the
file named baz.css in the static subdirectory of the my.package Python package. See
Understanding Asset Specifications for more info.
authentication
The act of determining that the credentials a user presents during a particular request are ”good”.
Authentication in Pyramid is performed via an authentication policy.
authentication policy
An authentication policy in Pyramid terms is a bit of code which has an API which determines the
current principal (or principals) associated with a request.
Deprecated since version 2.0: Authentication policies have been deprecated in favor of a security
policy.
authorization
The act of determining whether a user can perform a specific action. In pyramid terms, this means
determining whether, for a given resource, any principal (or principals) associated with the request
have the requisite permission to allow the request to continue. Authorization in Pyramid is performed
via its authorization policy.
authorization policy
An authorization policy in Pyramid terms is a bit of code which has an API which determines
whether or not the principals associated with the request can perform an action associated with a
permission, based on the information found on the context resource.
Deprecated since version 2.0: Authorization policies have been deprecated in favor of a security
policy.

0.7. Glossary and Index 1227


The Pyramid Web Framework, Version 2.0.2

Babel
A collection of tools for internationalizing Python applications. Pyramid does not depend on Ba-
bel to operate, but if Babel is installed, additional locale functionality becomes available to your
application.
cache busting
A technique used when serving a cacheable static asset in order to force a client to query the new
version of the asset. See Cache Busting for more information.
Chameleon
chameleon is an attribute language template compiler which supports the ZPT templating specifica-
tion. It is written and maintained by Malthe Borch. It has several extensions, such as the ability to
use bracketed (Mako-style) ${name} syntax. It is also much faster than the reference implemen-
tation of ZPT. Pyramid offers Chameleon templating out of the box in ZPT and text flavors.
commit
An operation applied to a configurator. A commit checks for conflicts in configuration declara-
tions, and if none are found applies all pending actions. It is possible, although not necessarily
recommended, to invoke commits using pyramid.config.Configurator.commit() to
manually resolve configuration conflicts.
configuration declaration
An individual method call made to a configuration directive, such as registering a view configuration
(via the add_view() method of the configurator) or route configuration (via the add_route()
method of the configurator). A set of configuration declarations is also implied by the configuration
decoration detected by a scan of code in a package.
configuration decoration
Metadata implying one or more configuration declaration invocations. Often set by configuration
Python decorator attributes, such as pyramid.view.view_config, aka @view_config.
configuration directive
A method of the Configurator which causes a configuration action to occur. The method pyramid.
config.Configurator.add_view() is a configuration directive, and application devel-
opers can add their own directives as necessary (see Adding Methods to the Configurator via
add_directive).
configurator
An object used to do configuration declaration within an application. The most common configu-
rator is an instance of the pyramid.config.Configurator class.
conflict resolution
Pyramid attempts to resolve ambiguous configuration statements made by application developers
via automatic conflict resolution. Automatic conflict resolution is described in Automatic Conflict
Resolution. If Pyramid cannot resolve ambiguous configuration statements, it is possible to manually
resolve them as described in Manually Resolving Conflicts.

1228 CONTENTS
The Pyramid Web Framework, Version 2.0.2

console script
A script written to the bin (on Unix, or Scripts on Windows) directory of a Python installation
or virtual environment as the result of running pip install or pip install -e ..
constructor
A function returning a Pyramid WSGI application. Every Pyramid application has a single construc-
tor function named main. It returns a Pyramid router generated by a configurator, and is written
by you. The Pyramid constructor is the application’s entry point.
context
A resource in the resource tree that is found during traversal or URL dispatch based on URL data;
if it’s found via traversal, it’s usually a resource object that is part of a resource tree; if it’s found
via URL dispatch, it’s an object manufactured on behalf of the route’s ”factory”. A context resource
becomes the subject of a view, and often has security information attached to it. See the Traversal
chapter and the URL Dispatch chapter for more information about how a URL is resolved to a context
resource.
context manager
A context manager is an object that defines the runtime context to be established when
executing a with statement in Python. The context manager handles the entry into, and
the exit from, the desired runtime context for the execution of the block of code. Con-
text managers are normally invoked using the with statement, but can also be used by di-
rectly invoking their methods. Pyramid adds context managers for pyramid.config.
Configurator, pyramid.interfaces.IRouter.request_context(), pyramid.
paster.bootstrap(), pyramid.scripting.prepare(), and pyramid.testing.
testConfig(). See also the Python documentation for With Statement Context Managers and
PEP 343.
cookiecutter
A command-line utility that creates projects from cookiecutters (project templates), e.g., creating a
Python package project from a Python package project template.
New in version 1.8: Added cookiecutter support.
Changed in version 1.10: Merged features from pyramid-cookiecutter-alchemy
and pyramid-cookiecutter-zodb into the single cookiecutter to rule them all,
pyramid-cookiecutter-starter.
Deprecated since version 1.10: pyramid-cookiecutter-alchemy
and pyramid-cookiecutter-zodb are no longer supported. Use
pyramid-cookiecutter-starter going forward.
coverage
A measurement of code coverage, usually expressed as a percentage of which lines of code have
been executed over which lines are executable, typically run during test execution.
CPython
The C implementation of the Python language. This is the reference implementation that most

0.7. Glossary and Index 1229


The Pyramid Web Framework, Version 2.0.2

people refer to as simply ”Python”; Jython, Google’s App Engine, and PyPy are examples of non-C
based Python implementations.
CSRF storage policy
A utility that implements pyramid.interfaces.ICSRFStoragePolicy which is respon-
sible for allocating CSRF tokens to a user and verifying that a provided token is acceptable.
declarative configuration
The configuration mode in which you use the combination of configuration decoration and a scan
to configure your Pyramid application.
decorator
A wrapper around a Python function or class which accepts the function or class as its first argument
and which returns an arbitrary object. Pyramid provides several decorators, used for configuration
and return value modification purposes.
See also:
See also PEP 318.
Default Locale Name
The locale name used by an application when no explicit locale name is set. See Localization-
Related Deployment Settings.
default permission
A permission which is registered as the default for an entire application. When a default permission
is in effect, every view configuration registered with the system will be effectively amended with a
permission argument that will require that the executing user possess the default permission in
order to successfully execute the associated view callable.
See also:
See also Setting a Default Permission.
default root factory
If an application does not register a root factory at Pyramid configuration time, a default root factory
is used to created the default root object. Use of the default root object is useful in application
which use URL dispatch for all URL-to-view code mappings, and does not (knowingly) use traversal
otherwise.
Default view
The default view of a resource is the view invoked when the view name is the empty string ('').
This is the case when traversal exhausts the path elements in the PATH_INFO of a request before it
returns a context resource.
Deployment settings
Deployment settings are settings passed to the Configurator as a settings argument. These
are later accessible via a request.registry.settings dictionary in views or as config.

1230 CONTENTS
The Pyramid Web Framework, Version 2.0.2

registry.settings in configuration code. Deployment settings can be used as global appli-


cation values.
discriminator
The unique identifier of an action.
distribution
Setuptools / Python packaging terminology. A file representing an installable library or application.
Distributions are usually archives that have the suffix of .whl, .tar.gz, or .zip. Distributions
are the target of packaging-related commands such as pip install.
distutils
The standard system for packaging and distributing Python packages. See https://docs.python.org/
2/distutils/index.html for more information. Setuptools is actually an extension of the Distutils.
Django
A full-featured Python web framework.
domain model
Persistent data related to your application. For example, data stored in a relational database. In some
applications, the resource tree acts as the domain model.
dotted Python name
A reference to a Python object by name using a string, in the form path.to.
modulename:attributename. Often used in Pyramid and Setuptools configurations.
A variant is used in dotted names within configurator method arguments that name objects (such as
the ”add_view” method’s ”view” and ”context” attributes): the colon (:) is not used; in its place is
a dot.
entry point
A Setuptools indirection, defined within a Setuptools distribution (usually in setup.py or
setup.cfg). It is usually a name which refers to a function somewhere in a package which is
held by the distribution.
event
An object broadcast to zero or more subscriber callables during normal Pyramid system operations
during the lifetime of an application. Application code can subscribe to these events by using the
subscriber functionality described in Using Events.
exception response
A response that is generated as the result of a raised exception being caught by an exception view.
Exception view
An exception view is a view callable which may be invoked by Pyramid when an exception is raised
during request processing. See Custom Exception Views for more information.
execution policy
A policy which wraps the router by creating the request object and sending it through the request
pipeline. See pyramid.config.Configurator.set_execution_policy.

0.7. Glossary and Index 1231


The Pyramid Web Framework, Version 2.0.2

falsey string
A string represeting a value of False. Acceptable values are f, false, n, no, off and 0.
finished callback
A user-defined callback executed by the router unconditionally at the very end of request processing
. See Using Finished Callbacks.
Forbidden view
An exception view invoked by Pyramid when the developer explicitly raises a pyramid.
httpexceptions.HTTPForbidden exception from within view code or root factory code,
or when the view configuration and authorization policy found for a request disallows a particular
view invocation. Pyramid provides a default implementation of a forbidden view; it can be overrid-
den. See Changing the Forbidden View.
Genshi
An XML templating language by Christopher Lenz.
Gettext
The GNU gettext library, used by the Pyramid translation machinery.
global state
A set of values that are available to the entirety of a program.
Google App Engine
Google App Engine (aka ”GAE”) is a Python application hosting service offered by Google. Pyramid
runs on GAE.
Grok
A web framework based on Zope 3.
gunicorn
Aka gunicorn, a fast WSGI server that runs on Unix under Python 2.6+ or Python 3.4+. See
https://gunicorn.org/ for detailed information.
HTTP Exception
The set of exception classes defined in pyramid.httpexceptions. These can be used to gen-
erate responses with various status codes when raised or returned from a view callable.
See also:
See also HTTP Exceptions.
identity
An identity is an object identifying the user associated with the current request. The object can be
of any shape, such as a simple ID string or an ORM object.
immutable
In Python, a value is immutable if it cannot be changed. The Python str, int, and tuple data
types are all immutable.

1232 CONTENTS
The Pyramid Web Framework, Version 2.0.2

imperative configuration
The configuration mode in which you use Python to call methods on a Configurator in order to add
each configuration declaration required by your application.
import time
In Python, the moment when a module is referred to in an import statement. At this moment, all
statements in that module at the module scope (at the left margin) are executed. It is a bad design
decision to put statements in a Python module that have side effects at import time.
interface
A Zope interface object. In Pyramid, an interface may be attached to a resource object or a request
object in order to identify that the object is ”of a type”. Interfaces are used internally by Pyra-
mid to perform view lookups and other policy lookups. The ability to make use of an interface
is exposed to an application programmers during view configuration via the context argument,
the request_type argument and the containment argument. Interfaces are also exposed to
application developers when they make use of the event system. Fundamentally, Pyramid program-
mers can think of an interface as something that they can attach to an object that stamps it with a
”type” unrelated to its underlying Python type. Interfaces can also be used to describe the behavior
of an object (its methods and attributes), but unless they choose to, Pyramid programmers do not
need to understand or use this feature of interfaces.
Internationalization
The act of creating software with a user interface that can potentially be displayed in more than one
language or cultural context. Often shortened to ”i18n” (because the word ”internationalization” is
I, 18 letters, then N).
See also:
See also Localization.
introspectable
An object which implements the attributes and methods described in pyramid.interfaces.
IIntrospectable. Introspectables are used by the introspector to display configuration infor-
mation about a running Pyramid application. An introspectable is associated with a action by virtue
of the pyramid.config.Configurator.action() method.
introspector
An object with the methods described by pyramid.interfaces.IIntrospector that is
available in both configuration code (for registration) and at runtime (for querying) that allows a
developer to introspect configuration statements and relationships between those statements.
Jinja2
A text templating language by Armin Ronacher.
jQuery
A popular Javascript library.

0.7. Glossary and Index 1233


The Pyramid Web Framework, Version 2.0.2

JSON
JavaScript Object Notation is a data serialization format.
Jython
A Python implementation written for the Java Virtual Machine.
lineage
An ordered sequence of objects based on a ”location -aware” resource. The lineage of any given
resource is composed of itself, its parent, its parent’s parent, and so on. The order of the sequence
is resource-first, then the parent of the resource, then its parent’s parent, and so on. The parent of a
resource in a lineage is available as its __parent__ attribute.
Lingua
A package by Wichert Akkerman which provides the pot-create command to extract translate-
able messages from Python sources and Chameleon ZPT template files.
Locale Name
A string like en, en_US, de, or de_AT which uniquely identifies a particular locale.
Locale Negotiator
An object supplying a policy determining which locale name best represents a given re-
quest. It is used by the pyramid.i18n.get_locale_name(), and pyramid.
i18n.negotiate_locale_name() functions, and indirectly by pyramid.i18n.
get_localizer(). The pyramid.i18n.default_locale_negotiator() function
is an example of a locale negotiator.
Localization
The process of displaying the user interface of an internationalized application in a particular lan-
guage or cultural context. Often shortened to ”l10n” (because the word ”localization” is L, 10 letters,
then N).
See also:
See also Internationalization.
Localizer
An instance of the class pyramid.i18n.Localizer which provides translation and plural-
ization services to an application. It is retrieved via the pyramid.i18n.get_localizer()
function.
location
The path to an object in a resource tree. See Location-Aware Resources for more information about
how to make a resource object location-aware.
Mako
Mako is a template language which refines the familiar ideas of componentized layout and inheri-
tance using Python with Python scoping and calling semantics.

1234 CONTENTS
The Pyramid Web Framework, Version 2.0.2

matchdict
The dictionary attached to the request object as request.matchdict when a URL dispatch
route has been matched. Its keys are names as identified within the route pattern; its values are the
values matched by each pattern name.
media type
A label representing the type of some content. A media type is a nested structure containing a top-
level type and a subtype. Optionally, a media type can also contain parameters specific to the type.
See RFC 6838 for more information about media types.
Message Catalog
A gettext .mo file containing translations.
Message Identifier
A string used as a translation lookup key during localization. The msgid argument to a translation
string is a message identifier. Message identifiers are also present in a message catalog.
METAL
Macro Expansion for TAL, a part of ZPT which makes it possible to share common look and feel
between templates.
middleware
Middleware is a WSGI concept. It is a WSGI component that acts both as a server and an applica-
tion. Interesting uses for middleware exist, such as caching, content-transport encoding, and other
functions. See WSGI documentation or PyPI to find middleware for your application.
mod_wsgi
mod_wsgi is an Apache module developed by Graham Dumpleton. It allows WSGI applications
(such as applications developed using Pyramid) to be served using the Apache web server.
module
A Python source file; a file on the filesystem that typically ends with the extension .py or .pyc.
Modules often live in a package.
multidict
An ordered dictionary that can have multiple values for each key. Adds the methods getall,
getone, mixed, add and dict_of_lists to the normal dictionary interface. See Multidict
and pyramid.interfaces.IMultiDict.
mutable
In Python, a value is mutable if it can be changed in place. The Python list and dict types
are mutable. When a value is added to or removed from an instance of either, the original object
remains. The opposite of mutable is immutable.
Not Found View
An exception view invoked by Pyramid when the developer explicitly raises a pyramid.
httpexceptions.HTTPNotFound exception from within view code or root factory code, or

0.7. Glossary and Index 1235


The Pyramid Web Framework, Version 2.0.2

when the current request doesn’t match any view configuration. Pyramid provides a default imple-
mentation of a Not Found View; it can be overridden. See Changing the Not Found View.
package
A directory on disk which contains an __init__.py file, making it recognizable to Python as a
location which can be import -ed. A package exists to contain module files.
PasteDeploy
PasteDeploy is a library used by Pyramid which makes it possible to configure WSGI components
together declaratively within an .ini file. It was developed by Ian Bicking.
permission
A string that represents an action being taken against a context resource. A permission is associated
with a view name and a resource type by the developer. Resources are decorated with security decla-
rations (e.g. an ACL), which reference these tokens also. Permissions are used by the active security
policy to match the view permission against the resources’s statements about which permissions are
granted to which principal in a context in order to answer the question ”is this user allowed to do
this”. Examples of permissions: read, or view_blog_entries.
physical path
The path required by a traversal which resolve a resource starting from the physical root. For exam-
ple, the physical path of the abc subobject of the physical root object is /abc. Physical paths can
also be specified as tuples where the first element is the empty string (representing the root), and
every other element is a Unicode string, e.g. ('', 'abc'). Physical paths are also sometimes
called ”traversal paths”.
physical root
The object returned by the application root factory. Unlike the virtual root of a request, it is not
impacted by Virtual Hosting: it will always be the actual object returned by the root factory, never a
subobject.
pip
The Python Packaging Authority’s recommended tool for installing Python packages.
pipeline
The PasteDeploy term for a single configuration of a WSGI server, a WSGI application, with a set
of middleware in-between.
pkg_resources
A module which ships with Setuptools that provides an API for addressing ”asset files” within a
Python package. Asset files are static files, template files, etc; basically anything non-Python-source
that lives in a Python package can be considered a asset file.
See also:
See also Package Discovery and Resource Access using pkg_resources.
plaster
plaster is a library used by Pyramid which acts as an abstraction between command-line scripts and

1236 CONTENTS
The Pyramid Web Framework, Version 2.0.2

the file format used to load the WSGI components and application settings. By default Pyramid
ships with the plaster_pastedeploy library installed which provides integrated support for
loading a PasteDeploy INI file.
predicate
A test which returns True or False. Two different types of predicates exist in Pyramid: a view
predicate and a route predicate. View predicates are attached to view configuration and route pred-
icates are attached to route configuration.
predicate factory
A callable which is used by a third party during the registration of a route, view, or subscriber
predicates to extend the configuration system. See Adding a Custom View, Route, or Subscriber
Predicate for more information.
pregenerator
A pregenerator is a function associated by a developer with a route. It is called by route_url()
in order to adjust the set of arguments passed to it by the user for special purposes. It will influence
the URL returned by route_url(). See pyramid.interfaces.IRoutePregenerator
for more information.
principal
A principal is a string representing an entity, typically a user or group. Principals are provided by
an authentication policy. For example, if a user has the userid bob, and is a member of two groups
named group foo and group bar, then the request might have information attached to it indicating
that Bob was represented by three principals: bob, group foo and group bar.
project
Setuptools / Python packaging terminology. A directory on disk which contains a setup.py and
/ or pyproject.toml file and one or more Python packages. The project files contain metadata
that allow the package(s) to be installed, distributed, and tested.
Pylons
A lightweight Python web framework and a predecessor of Pyramid.
PyPI
The Python Package Index, a collection of software available for Python.
PyPy
PyPy is an ”alternative implementation of the Python language”: http://pypy.org/
Pyramid Community Cookbook
Additional, community-based documentation for Pyramid which presents topical, practical uses of
Pyramid: Pyramid Community Cookbook
pyramid_debugtoolbar
A Pyramid add-on which displays a helpful debug toolbar ”on top of” HTML pages rendered by your
application, displaying request, routing, and database information. pyramid_debugtoolbar is

0.7. Glossary and Index 1237


The Pyramid Web Framework, Version 2.0.2

configured into the development.ini of all applications which use a Pyramid cookiecutter. For
more information, see https://docs.pylonsproject.org/projects/pyramid_debugtoolbar/en/latest/.
pyramid_exclog
A package which logs Pyramid application exception (error) information to a standard Python log-
ger. This add-on is most useful when used in production applications, because the logger can be
configured to log to a file, to Unix syslog, to the Windows Event Log, or even to email. See its
documentation.
pyramid_handlers
An add-on package which allows Pyramid users to create classes that are analogues of Pylons 1
”controllers”. See https://docs.pylonsproject.org/projects/pyramid_handlers/en/latest/.
pyramid_jinja2
Jinja2 templating system bindings for Pyramid, documented at https://docs.pylonsproject.
org/projects/pyramid_jinja2/en/latest/. This package also includes a scaffold named pyra-
mid_jinja2_starter, which creates an application package based on the Jinja2 templating
system.
pyramid_redis_sessions
A package by Eric Rasmussen which allows you to store Pyramid session data in a Redis database.
See https://pypi.org/project/pyramid_redis_sessions/ for more information.
pyramid_zcml
An add-on package to Pyramid which allows applications to be configured via ZCML. It is available
on PyPI. If you use pyramid_zcml, you can use ZCML as an alternative to imperative configu-
ration or configuration decoration.
Python
The programming language in which Pyramid is written.
Python Packaging Authority
The Python Packaging Authority (PyPA) is a working group that maintains many of the relevant
projects in Python packaging.
renderer
A serializer which converts non-Response return values from a view into a string, and ultimately
into a response, usually through view configuration. Using a renderer can make writing views that
require templating or other serialization, like JSON, less tedious. See Writing View Callables Which
Use a Renderer for more information.
renderer factory
A factory which creates a renderer. See Adding and Changing Renderers for more information.
renderer globals
Values injected as names into a renderer by a pyramid.event.BeforeRender event.
Repoze
”Repoze” is essentially a ”brand” of software developed by Agendaless Consulting and a set of

1238 CONTENTS
The Pyramid Web Framework, Version 2.0.2

contributors. The term has no special intrinsic meaning. The project’s website has more information.
The software developed ”under the brand” is available in a Subversion repository. Pyramid was
originally known as repoze.bfg.
repoze.catalog
An indexing and search facility (fielded and full-text) based on zope.index. See the documentation
for more information.
repoze.lemonade
Zope2 CMF-like data structures and helper facilities for CA-and-ZODB-based applications useful
within Pyramid applications.
repoze.who
Authentication middleware for WSGI applications. It can be used by Pyramid to provide authenti-
cation information.
repoze.workflow
Barebones workflow for Python apps . It can be used by Pyramid to form a workflow system.
request
An object that represents an HTTP request, usually an instance of the pyramid.request.
Request class. See Request and Response Objects (narrative) and pyramid.request (API docu-
mentation) for information about request objects.
request factory
An object which, provided a WSGI environment as a single positional argument, returns a Pyramid-
compatible request.
request type
An attribute of a request that allows for specialization of view invocation based on arbitrary cat-
egorization. The every request object that Pyramid generates and manipulates has one or more
interface objects attached to it. The default interface attached to a request object is pyramid.
interfaces.IRequest.
resource
An object representing a node in the resource tree of an application. If traversal is used, a resource is
an element in the resource tree traversed by the system. When traversal is used, a resource becomes
the context of a view. If URL dispatch is used, a single resource is generated for each request and is
used as the context resource of a view.
Resource Location
The act of locating a context resource given a request. Traversal and URL dispatch are the resource
location subsystems used by Pyramid.
resource tree
A nested set of dictionary-like objects, each of which is a resource. The act of traversal uses the
resource tree to find a context resource.

0.7. Glossary and Index 1239


The Pyramid Web Framework, Version 2.0.2

response
An object returned by a view callable that represents response data returned to the requesting user
agent. It must implement the pyramid.interfaces.IResponse interface. A response ob-
ject is typically an instance of the pyramid.response.Response class or a subclass such as
pyramid.httpexceptions.HTTPFound. See Request and Response Objects for informa-
tion about response objects.
response adapter
A callable which accepts an arbitrary object and ”converts” it to a pyramid.response.
Response object. See Changing How Pyramid Treats View Responses for more information.
response callback
A user-defined callback executed by the router at a point after a response object is successfully
created.
See also:
See also Using Response Callbacks.
response factory
An object which, provided a request as a single positional argument, returns a Pyramid-compatible
response. See pyramid.interfaces.IResponseFactory.
reStructuredText
A plain text markup format that is the defacto standard for documenting Python projects. The Pyra-
mid documentation is written in reStructuredText.
root
The object at which traversal begins when Pyramid searches for a context resource (for URL Dis-
patch, the root is always the context resource unless the traverse= argument is used in route
configuration).
root factory
The ”root factory” of a Pyramid application is called on every request sent to the application. The
root factory returns the traversal root of an application. It is conventionally named get_root. An
application may supply a root factory to Pyramid during the construction of a Configurator. If a root
factory is not supplied, the application creates a default root object using the default root factory.
route
A single pattern matched by the URL dispatch subsystem, which generally resolves to a root factory
(and then ultimately a view).
See also:
See also URL dispatch.
route configuration
Route configuration is the act of associating request parameters with a particular route using pat-

1240 CONTENTS
The Pyramid Web Framework, Version 2.0.2

tern matching and route predicate statements. See URL Dispatch for more information about route
configuration.
route predicate
An argument to a route configuration which implies a value that evaluates to True or False for
a given request. All predicates attached to a route configuration must evaluate to True for the
associated route to ”match” the current request. If a route does not match the current request, the
next route (in definition order) is attempted.
route prefix
A route prefix is a path prefix that is prepended to any routes that are configured while it is active.
A route prefix can be set via pyramid.config.Configurator.include() or pyramid.
config.Configurator.route_prefix_context().
router
The WSGI application created when you start a Pyramid application. The router intercepts requests,
invokes traversal and/or URL dispatch, calls view functions, and returns responses to the WSGI
server on behalf of your Pyramid application.
Routes
A system by Ben Bangert which parses URLs and compares them against a number of user defined
mappings. The URL pattern matching syntax in Pyramid is inspired by the Routes syntax (which
was inspired by Ruby On Rails pattern syntax).
routes mapper
An object which compares path information from a request to an ordered set of route patterns. See
URL Dispatch.
scan
The term used by Pyramid to define the process of importing and examining all code in a Python
package or module for configuration decoration.
security policy
A security policy in Pyramid terms is an object implementing the pyramid.interfaces.
ISecurityPolicy API which identifies the user associated with the current request (perhaps
via a cookie or Authorization header) and determines whether or not that user is permitted to
access the requested resource.
session
A namespace that is valid for some period of continual activity that can be used to represent a user’s
interaction with a web application.
session factory
A callable, which, when called with a single argument named request (a request object), returns
a session object. See Using the Default Session Factory, Using Alternate Session Factories and
pyramid.config.Configurator.set_session_factory() for more information.
settings

0.7. Glossary and Index 1241


The Pyramid Web Framework, Version 2.0.2

Settings control the runtime behavior of a Pyramid application. They are the aggregation of con-
figuration file declarations, process environment values, other additions generated by Pyramid or its
add-ons and tweens, and values produced by your own code. Settings are collected at application
startup. They can affect all the components which make up the the application. Pyramid itself, any
tweens or Pyramid add-ons used, and your own code may reference and act on settings.
Setuptools
Setuptools builds on Python’s distutils to provide easier building, distribution, and installation
of libraries and applications.
side effect
A statement or function has a side effect when it changes a value outside its own scope. Put another
way, if one can observe the change made by a function from outside that function, it has a side effect.
singleton
A singleton is a class which will only ever have one instance. As there is only one, it is shared by all
other code. This makes it an example of global state.
Using a singleton is considered a poor design choice. As mutable global state, it can be changed by
any other code, and so the values it represents cannot be reasoned about or tested properly.
SQLAlchemy
SQLAlchemy is an object relational mapper used in tutorials within this documentation.
subpath
A list of element ”left over” after the router has performed a successful traversal to a view. The
subpath is a sequence of strings, e.g. ['left', 'over', 'names']. Within Pyramid appli-
cations that use URL dispatch rather than traversal, you can use *subpath in the route pattern to
influence the subpath. See Using *subpath in a Route Pattern for more information.
subscriber
A callable which receives an event. A callable becomes a subscriber via imperative configuration
or via configuration decoration. See Using Events for more information.
template
A file with replaceable parts that is capable of representing some text, XML, or HTML when ren-
dered.
thread local
A thread-local variable is one which is essentially a global variable in terms of how it is accessed
and treated, however, each thread used by the application may have a different value for this same
”global” variable. Pyramid uses a small number of thread local variables, as described in Thread
Locals.
See also:
See also the stdlib documentation for more information.

1242 CONTENTS
The Pyramid Web Framework, Version 2.0.2

Translation Context
A string representing the ”context” in which a translation was made within a given translation do-
main. See the gettext documentation, 11.2.5 Using contexts for solving ambiguities for more infor-
mation.
Translation Directory
A translation directory is a gettext translation directory. It contains language folders, which them-
selves contain LC_MESSAGES folders, which contain .mo files. Each .mo file represents a set
of translations for a language in a translation domain. The name of the .mo file (minus the .mo
extension) is the translation domain name.
Translation Domain
A string representing the ”context” in which a translation was made. For example the word ”java”
might be translated differently if the translation domain is ”programming-languages” than would be
if the translation domain was ”coffee”. A translation domain is represented by a collection of .mo
files within one or more translation directory directories.
Translation String
An instance of pyramid.i18n.TranslationString, which is a class that behaves like a
string, but has several extra attributes such as domain, msgid, and mapping for use during trans-
lation. Translation strings are usually created by hand within software, but are sometimes created
on the behalf of the system for automatic template translation. For more information, see Interna-
tionalization and Localization.
Translator
A callable which receives a translation string and returns a translated string for the purposes of
internationalization. A localizer supplies a translator to a Pyramid application accessible via its
translate method.
traversal
The act of descending ”up” a tree of resource objects from a root resource in order to find a context
resource. The Pyramid router performs traversal of resource objects when a root factory is specified.
See the Traversal chapter for more information. Traversal can be performed instead of URL dispatch
or can be combined with URL dispatch. See Combining Traversal and URL Dispatch for more
information about combining traversal and URL dispatch (advanced).
truthy string
A string represeting a value of True. Acceptable values are t, true, y, yes, on and 1.
tween
A bit of code that sits between the Pyramid router’s main request handling function and the upstream
WSGI component that uses Pyramid as its ’app’. The word ”tween” is a contraction of ”between”.
A tween may be used by Pyramid framework extensions, to provide, for example, Pyramid-specific
view timing support, bookkeeping code that examines exceptions before they are returned to the up-
stream WSGI application, or a variety of other features. Tweens behave a bit like WSGI middleware
but they have the benefit of running in a context in which they have access to the Pyramid application
registry as well as the Pyramid rendering machinery. See Registering Tweens.

0.7. Glossary and Index 1243


The Pyramid Web Framework, Version 2.0.2

URL dispatch
An alternative to traversal as a mechanism for locating a context resource for a view. When you use
a route in your Pyramid application via a route configuration, you are using URL dispatch. See the
URL Dispatch for more information.
userid
A userid is the string representation of an identity. Just like the identity, it should identify the user
associated with the current request. Oftentimes this is the ID of the user object in a database.
Venusian
Venusian is a library which allows framework authors to defer decorator actions. Instead of taking
actions when a function (or class) decorator is executed at import time, the action usually taken by
the decorator is deferred until a separate ”scan” phase. Pyramid relies on Venusian to provide a basis
for its scan feature.
venv
The Python Packaging Authority’s recommended tool for creating virtual environments on Python
3.3 and greater.
Note: whenever you encounter commands prefixed with $VENV (Unix) or %VENV (Windows), know
that that is the environment variable whose value is the root of the virtual environment in question.
view
Common vernacular for a view callable.
view callable
A ”view callable” is a callable Python object which is associated with a view configuration; it returns
a response object . A view callable accepts a single argument: request, which will be an instance
of a request object. An alternate calling convention allows a view to be defined as a callable which
accepts a pair of arguments: context and request: this calling convention is useful for traversal-
based applications in which a context is always very important. A view callable is the primary
mechanism by which a developer writes user interface code within Pyramid. See Views for more
information about Pyramid view callables.
view configuration
View configuration is the act of associating a view callable with configuration information. This
configuration information helps map a given request to a particular view callable and it can influence
the response of a view callable. Pyramid views can be configured via imperative configuration, or
by a special @view_config decorator coupled with a scan. See View Configuration for more
information about view configuration.
view deriver
A view deriver is a composable component of the view pipeline which is used to create
a view callable. A view deriver is a callable implementing the pyramid.interfaces.
IViewDeriver interface. Examples of built-in derivers including view mapper, the permission
checker, and applying a renderer to a dictionary returned from the view.

1244 CONTENTS
The Pyramid Web Framework, Version 2.0.2

View handler
A view handler ties together pyramid.config.Configurator.add_route() and
pyramid.config.Configurator.add_view() to make it more convenient to register a
collection of views as a single class when using URL dispatch. View handlers ship as part of the
pyramid_handlers add-on package.
View Lookup
The act of finding and invoking the ”best” view callable, given a request and a context resource.
view mapper
A view mapper is a class which implements the pyramid.interfaces.
IViewMapperFactory interface, which performs view argument and return value mapping.
This is a plug point for extension builders, not normally used by ”civilians”.
view name
The ”URL name” of a view, e.g index.html. If a view is configured without a name, its name is
considered to be the empty string (which implies the default view).
view predicate
An argument to a view configuration which evaluates to True or False for a given request. All
predicates attached to a view configuration must evaluate to true for the associated view to be con-
sidered as a possible callable for a given request.
virtual environment
An isolated Python environment that allows packages to be installed for use by a particular applica-
tion, rather than being installed system wide.
virtual root
A resource object representing the ”virtual” root of a request; this is typically the physical root object
unless Virtual Hosting is in use.
virtualenv
The virtualenv tool that allows one to create virtual environments. In Python 3.3 and greater, venv
is the preferred tool.
Note: whenever you encounter commands prefixed with $VENV (Unix) or %VENV (Windows), know
that that is the environment variable whose value is the root of the virtual environment in question.
Waitress
A WSGI server that runs on Unix and Windows under Python 2.7+ and Python 3.3+. Projects
generated via Pyramid cookiecutters use Waitress as a WGSI server. See https://docs.pylonsproject.
org/projects/waitress/en/latest/ for detailed information.
WebOb
WebOb is a WSGI request/response library created by Ian Bicking.
WebTest
WebTest is a package which can help you write functional tests for your WSGI application.

0.7. Glossary and Index 1245


The Pyramid Web Framework, Version 2.0.2

WSGI
Web Server Gateway Interface. This is a Python standard for connecting web applications to web
servers, similar to the concept of Java Servlets. Pyramid requires that your application be served as
a WSGI application.
ZCML
Zope Configuration Markup Language, an XML dialect used by Zope and pyramid_zcml for con-
figuration tasks.
ZODB
Zope Object Database, a persistent Python object store.
Zope
The Z Object Publishing Framework, a full-featured Python web framework.
Zope Component Architecture
The Zope Component Architecture (aka ZCA) is a system which allows for application pluggability
and complex dispatching based on objects which implement an interface. Pyramid uses the ZCA
”under the hood” to perform view dispatching and other application configuration tasks.
ZPT
The Zope Page Template templating language.

1246 CONTENTS
INDEX

Symbols __init__.py, 377


*subpath __iter__() (IDict method), 819
hybrid applications, 628 __new__() (ACLAllowed static method), 735,
*traverse route pattern 884
hybrid applications, 624 __new__() (ACLDenied static method), 735, 883
.ini __new__() (Allowed static method), 883
logging, 516 __new__() (Denied static method), 882
middleware, 521 __setitem__() (IDict method), 819
settings, 385 __str__() (IActionInfo method), 828
$VENV/bin/pip vs. source --app-name
bin/activate, 346 prequest command line option, 910
__call__() (ICacheBuster method), 829 pserve command line option, 912
__call__() (IPredicateFactory method), 830 --browser
__call__() (IRenderer method), 817 pserve command line option, 912
__call__() (IRendererFactory method), 817 --display-headers
__call__() (IRequestFactory method), 817 prequest command line option, 910
__call__() (IResponse method), 821 --format
__call__() (IResponseFactory method), 817 proutes command line option, 911
__call__() (IRoutePredicate method), 831 --glob
__call__() (IRoutePregenerator method), 814 proutes command line option, 911
__call__() (ISessionFactory method), 816 --header
__call__() (ISubscriberPredicate method), 831 prequest command line option, 910
__call__() (IViewDeriver method), 830 --help
__call__() (IViewMapper method), 818 pdistreport command line option,
__call__() (IViewMapperFactory method), 909
818 prequest command line option, 910
__call__() (IViewPredicate method), 832 proutes command line option, 911
__contains__() (IDict method), 819 pserve command line option, 912
__delitem__() (IDict method), 819 pshell command line option, 913
__getitem__() (IDict method), 819 ptweens command line option, 914
__hash__() (IIntrospectable method), 825 pviews command line option, 915
--list-shells

1247
The Pyramid Web Framework, Version 2.0.2

pshell command line option, 913 -n


--login prequest command line option, 910
prequest command line option, 911 pserve command line option, 912
--method -p
prequest command line option, 911 pshell command line option, 913
--python-shell -q
pshell command line option, 913 pserve command line option, 912
--quiet -s
pserve command line option, 912 pserve command line option, 912
--reload -v
pserve command line option, 912 pserve command line option, 912
--reload-interval
pserve command line option, 912 A
--server absolute_asset_spec() (Configurator
pserve command line option, 912 method), 779
--server-name abspath() (IAssetDescriptor method), 828
pserve command line option, 912 absspec() (IAssetDescriptor method), 828
--setup Accept, 468
pshell command line option, 913 accept (Request property), 861
--verbose Accept content negotiation, 468
pserve command line option, 912 accept_charset (Request property), 861
-b accept_encoding (Request property), 861
pserve command line option, 912 accept_language (Request property), 861
-d accept_ranges (IResponse attribute), 821
prequest command line option, 910 accept_ranges (Response property), 871
-f access control entry, 612
proutes command line option, 911 access control list, 610
-g ACE, 612, 1226
proutes command line option, 911 ACE (special), 615
-h ACL, 610, 1226
pdistreport command line option, resource, 610
909 ACL inheritance, 615
prequest command line option, 910 ACLAllowed (class in pyramid.authorization),
proutes command line option, 911 735
pserve command line option, 912 ACLAllowed (class in pyramid.security), 884
pshell command line option, 913 ACLAuthorizationPolicy (class in pyra-
ptweens command line option, 914 mid.authorization), 733
pviews command line option, 915 ACLDenied (class in pyramid.authorization), 735
-l ACLDenied (class in pyramid.security), 883
prequest command line option, 911 ACLHelper (class in pyramid.authorization), 733
pshell command line option, 913 action, 1226
-m action() (Configurator method), 776
prequest command line option, 911 action_info (IIntrospectable attribute), 825

1248 Index
The Pyramid Web Framework, Version 2.0.2

activating add_traverser() (Configurator method), 770


translation, 561 add_tween() (Configurator method), 771
add() (IIntrospector method), 826 add_view, 463
add() (IMultiDict method), 820 add_view() (Configurator method), 750
add_accept_view_order() (Configurator add_view_deriver() (Configurator method),
method), 768 774
add_adapter() (JSON method), 841 add_view_predicate() (Configurator
add_adapter() (JSONP method), 843 method), 773
add_directive, 696 add-on, 1226
add_directive() (Configurator method), 777 adding
add_exception_view() (Configurator renderer, 438
method), 761 translation directory, 562
add_finished_callback() (Request adding directives
method), 849 configurator, 696
add_forbidden_view() (Configurator adding renderer globals, 644
method), 760 advanced
add_notfound_view() (Configurator configuration, 688
method), 759 age (IResponse attribute), 821
add_permission() (Configurator method), age (Response property), 871
765 Agendaless Consulting, 323, 1226
add_renderer() (Configurator method), 769 Akhet, 1226
add_request_method() (Configurator Akkerman, Wichert, 11
method), 765 Alembic, 1227
add_resource_url_adapter() (Configura- ALL_PERMISSIONS (in module pyra-
tor method), 769 mid.authorization), 734
add_response_adapter() (Configurator ALL_PERMISSIONS (in module pyra-
method), 770 mid.security), 882
add_response_callback() (Request Allow (in module pyramid.security), 882
method), 849 allow (IResponse attribute), 821
add_route, 395 allow (Response property), 871
add_route() (Configurator method), 743 Allowed (class in pyramid.security), 883
add_route_predicate() (Configurator app (IApplicationCreated attribute), 809
method), 773 app_iter (IResponse attribute), 821
add_settings() (Configurator method), 767 app_iter (Response property), 871
add_static_view, 473 app_iter_range() (IResponse method), 821
add_static_view() (Configurator method), app_iter_range() (Response method), 871
748 application configuration, 352
add_subscriber() (Configurator method), application registry, 712, 1227
761 application_url (Request property), 861
add_subscriber_predicate() (Configura- ApplicationCreated (class in pyra-
tor method), 773 mid.events), 788
add_translation_dirs() (Configurator apply_request_extensions() (in module
method), 766 pyramid.request), 869

Index 1249
The Pyramid Web Framework, Version 2.0.2

as_bytes() (Request method), 862 authorization policy, 1227


asbool() (in module pyramid.settings), 888 AuthTktAuthenticationPolicy (class in
aslist() (in module pyramid.settings), 888 pyramid.authentication), 722
assert_() (DummyTemplateRenderer method), AuthTktCookieHelper (class in pyra-
894 mid.authentication), 717
asset, 1227 AuthTktCookieHelper.AuthTicket
asset descriptor, 1227 (class in pyramid.authentication), 720
asset specification, 1227 AuthTktCookieHelper.BadTicket, 720
asset specifications, 472 automatic reloading of templates,
AssetResolver (class in pyramid.path), 836 448
assets, 471
generating urls, 475 B
overriding, 484, 687 Babel, 558, 1228
serving, 473 BadCSRFOrigin, 792
Authenticated (in module pyra- BadCSRFToken, 792
mid.authorization), 734 Bangert, Ben, 11
Authenticated (in module pyramid.security), BaseCookieSessionFactory() (in module
881 pyramid.session), 886
authenticated_userid (IResponse at- BasicAuthAuthenticationPolicy (class
tribute), 821 in pyramid.authentication), 729
authenticated_userid (Request attribute), Beelby, Chris, 11
846 before render event, 644
authenticated_userid() (AuthTktAuthen- BeforeRender (class in pyramid.events), 790
ticationPolicy method), 725 BeforeTraversal (class in pyramid.events),
authenticated_userid() (BasicAuthAu- 789
thenticationPolicy method), 730 begin() (Configurator method), 739
authenticated_userid() (IAuthentication- Bicking, Ian, 11, 487
Policy method), 812 blank() (IRequestFactory method), 817
authenticated_userid() (ISecurityPolicy blank() (Request class method), 862
method), 811 body (IResponse attribute), 821
authenticated_userid() (RemoteUser- body (Request property), 862
AuthenticationPolicy method), 726 body (Response property), 871
authenticated_userid() (Repoze- body_file (IResponse attribute), 821
Who1AuthenticationPolicy method), body_file (Request property), 862
731 body_file (Response property), 871
authenticated_userid() (SessionAuthenti- body_file_raw (Request property), 862
cationHelper method), 717 body_file_seekable (Request property), 862
authenticated_userid() (SessionAuthenti- book audience, 9
cationPolicy method), 728 book content overview, 9
authentication, 1227 bootstrap() (in module pyramid.paster), 832
authentication policy, 1227 Borch, Malthe, 11
authorization, 1227 Brandl, Georg, 11
authorization (Request property), 862 built-in renderers, 432

1250 Index
The Pyramid Web Framework, Version 2.0.2

C compiling
Cache Busting, 477 message catalog, 555
cache busting, 1228 conditional_response_app() (IResponse
cache_control (IResponse attribute), 821 method), 822
cache_control (Request property), 862 conditional_response_app() (Response
cache_control (Response property), 871 method), 871
cache_expires (IResponse attribute), 821 config_uri
call_application() (Request method), 862 prequest command line option, 910
CALLER_PACKAGE (in module pyramid.path), proutes command line option, 911
834 pserve command line option, 912
categories() (IIntrospector method), 826 pshell command line option, 913
categorized() (IIntrospector method), 826 ptweens command line option, 914
category_name (IIntrospectable attribute), 825 pviews command line option, 915
Chameleon, 449, 1228 config_vars
translation strings, 559 prequest command line option, 910
changed() (ISession method), 815 proutes command line option, 911
changing pserve command line option, 912
renderer, 440 pshell command line option, 913
charset (IResponse attribute), 821 ptweens command line option, 914
charset (Response property), 871 pviews command line option, 915
check_csrf_origin() (in module pyra- configuration
mid.csrf ), 785 advanced, 688
check_csrf_token() (CookieCSRFStorage- conflict detection, 688
Policy method), 784 including from external sources,
check_csrf_token() (ICSRFStoragePolicy 694
method), 814 logging, 516
check_csrf_token() (in module pyra- middleware, 521
mid.csrf ), 785 PasteDeploy, 387
check_csrf_token() (LegacySessionCSRFS- configuration declaration, 1228
toragePolicy method), 784 configuration decoration, 353, 1228
check_csrf_token() (SessionCSRFStorage- configuration decorator, 653
Policy method), 784 configuration directive, 1228
cleaning up after request, 492 ConfigurationError, 793
cleanUp() (in module pyramid.testing), 893 Configurator, 349
clear() (BeforeRender method), 791 configurator, 1228
clear() (IDict method), 819 adding directives, 696
clear() (RequestLocalCache method), 870 Configurator (class in pyramid.config), 736
client_addr (Request property), 863 Configurator testing API, 570
clone() (DummyResource method), 893 conflict detection
clone() (IRendererInfo method), 816 configuration, 688
code scanning, 353 conflict resolution, 1228
commit, 1228 console script, 544, 1229
commit() (Configurator method), 739 constructor, 1229

Index 1251
The Pyramid Web Framework, Version 2.0.2

container resources, 575 creating a project, 356


content_disposition (IResponse attribute), cross-site request forgery attacks,
822 prevention, 617
content_disposition (Response property), CSRF storage policy, 1230
872 csrf.get_csrf_token, 618
content_encoding (IResponse attribute), 822 csrf.new_csrf_token, 619
content_encoding (Response property), 872 current_route_path() (in module pyra-
content_language (IResponse attribute), 822 mid.url), 901
content_language (Response property), 872 current_route_path() (Request method),
content_length (IResponse attribute), 822 853
content_length (Request property), 863 current_route_url() (in module pyra-
content_length (Response property), 872 mid.url), 901
content_location (IResponse attribute), 822 current_route_url() (Request method), 853
content_location (Response property), 872 custom settings, 389
content_md5 (IResponse attribute), 822
content_md5 (Response property), 872 D
content_range (IResponse attribute), 822 date (IResponse attribute), 823
content_range (Response property), 872 date (Request property), 864
content_type (IResponse attribute), 822 date (Response property), 873
content_type (Request property), 863 date and currency formatting (i18n),
content_type (Response property), 872 558
content_type_params (IResponse attribute), de la Guardia, Carlos, 11
822 debug settings, 505
content_type_params (Response property), debug toolbar, 364
872 debug_all, 505
context, 598, 1229 debug_authorization, 505
context (Request attribute), 844 debug_notfound, 505
context manager, 1229 debug_routematch, 505
ContextFound (class in pyramid.events), 789 debugging
CookieCSRFStoragePolicy (class in pyra- route matching, 411
mid.csrf ), 784 templates, 447
cookiecutter, 356, 704, 1229 view configuration, 471
cookiecutters, 355 debugging authorization failures,
cookies (Request property), 863 616
copy() (BeforeRender method), 791 debugging not found errors, 467
copy() (IResponse method), 823 declarative configuration, 1230
copy() (Request method), 863 decorator, 1230
copy() (Response method), 873 default
copy_body() (Request method), 863 permission, 610
copy_get() (Request method), 863 default accept ordering, 469
coverage, 1229 Default Locale Name, 1230
CPython, 1229 default permission, 1230
created (ISession attribute), 815 default root factory, 1230

1252 Index
The Pyramid Web Framework, Version 2.0.2

Default view, 1230 E


default view, 598 effective_principals (Request attribute),
default_locale_name, 505, 560 846
default_locale_negotiator() (in mod- effective_principals() (AuthTktAuthen-
ule pyramid.i18n), 809 ticationPolicy method), 725
Deferred (class in pyramid.registry), 838 effective_principals() (BasicAuthAu-
delete_cookie() (IResponse method), 823 thenticationPolicy method), 730
delete_cookie() (Response method), 873 effective_principals() (IAuthentication-
Denied (class in pyramid.security), 882 Policy method), 812
Deny (in module pyramid.security), 882 effective_principals() (RemoteUser-
DENY_ALL (in module pyramid.authorization), AuthenticationPolicy method), 727
734 effective_principals() (Repoze-
DENY_ALL (in module pyramid.security), 882 Who1AuthenticationPolicy method),
deployment 732
settings, 389 effective_principals() (SessionAuthenti-
Deployment settings, 1230 cationPolicy method), 728
derive_view() (Configurator method), 777 encode_content() (IResponse method), 823
detecting languages, 560 encode_content() (Response method), 873
development install, 358 end() (Configurator method), 739
dict_of_lists() (IMultiDict method), 820 entry point, 1231
discriminator, 1231 environ (IResponse attribute), 823
discriminator (IIntrospectable attribute), 825 environment variables, 505
discriminator_hash (IIntrospectable at- etag (IResponse attribute), 823
tribute), 825 etag (Response property), 873
distribution, 1231 event, 501, 1231
distributions, showing installed, Everitt, Paul, 11
540 Everyone (in module pyramid.authorization),
distutils, 1231 734
Django, 323, 342, 1231 Everyone (in module pyramid.security), 881
domain exc_info (Request attribute), 845
translation, 549 exception (Request attribute), 845
domain (Request property), 864 exception response, 1231
domain model, 1231 exception responses, 495
dotted Python name, 1231 Exception view, 1231
DottedNameResolver (class in pyramid.path), exception view
834 subrequest, 636
DummyRequest (class in pyramid.testing), 893 exception views, 424
DummyResource (class in pyramid.testing), 893 exception_only (IViewDeriverInfo attribute),
DummyTemplateRenderer (class in pyra- 830
mid.testing), 894 exception_response() (in module pyra-
Duncan, Casey, 11 mid.httpexceptions), 796
exception_view_config (class in pyra-
mid.view), 907

Index 1253
The Pyramid Web Framework, Version 2.0.2

EXCVIEW (in module pyramid.tweens), 900 resource, 581


excview_tween_factory() (in module finding root
pyramid.tweens), 900 resource, 583
execution policy, 1231 finished callback, 646, 1232
exists() (IAssetDescriptor method), 828 flash messages, 499
exists() (ManifestCacheBuster static method), flash(), 500
890 flash() (ISession method), 815
expires (IResponse attribute), 823 Forbidden (in module pyramid.exceptions), 792
expires (Response property), 873 Forbidden view, 1232
explicitly calling forbidden view, 616, 639
renderer, 331 forbidden_view_config (class in pyra-
view renderer, 331 mid.view), 906
extend() (IMultiDict method), 820 forget() (AuthTktAuthenticationPolicy
extending method), 726
pshell, 532 forget() (AuthTktCookieHelper method), 720
extending an existing application, forget() (BasicAuthAuthenticationPolicy
685 method), 731
extending configuration, 696 forget() (IAuthenticationPolicy method), 812
extensible application, 684 forget() (in module pyramid.security), 880
extract_http_basic_credentials() forget() (ISecurityPolicy method), 811
(in module pyramid.authentication), 721 forget() (RemoteUserAuthenticationPolicy
extracting method), 727
messages, 554 forget() (RepozeWho1AuthenticationPolicy
method), 732
F forget() (SessionAuthenticationHelper
factory (IRoute attribute), 813 method), 717
falsey string, 1232 forget() (SessionAuthenticationPolicy method),
file (IActionInfo attribute), 828 729
FileIter (class in pyramid.response), 877 forms, views, and unicode, 426
FileResponse (class in pyramid.response), 877 framework, 323
find_best_match() (static_view method), frameworks vs. libraries, 323
890 from_bytes() (Request class method), 864
find_interface() (in module from_file() (Request class method), 864
pyra-
mid.traversal), 895 from_file() (Response class method), 873
find_resource() (in module fromkeys() (BeforeRender method), 791
pyra-
mid.traversal), 895 Fulton, Jim, 11
find_resource_path() functional testing, 567
(static_view
method), 890 functional tests, 572
find_root() (in module pyramid.traversal),
896 G
finding by interface or class generate() (IRoute method), 813
resource, 586 generating
finding by path hybrid URLs, 629

1254 Index
The Pyramid Web Framework, Version 2.0.2

resource url, 578 get_response() (Request method), 864


generating route URLs, 406 get_root() (in module pyramid.scripting), 879
generating static asset urls, 475 get_settings() (Configurator method), 768
generating urls getall() (IMultiDict method), 820
assets, 475 getGlobalSiteManager, 716
Genshi, 1232 getmtime() (ManifestCacheBuster static
GET (Request property), 860 method), 891
get() (BeforeRender method), 791 getone() (IMultiDict method), 820
get() (IDict method), 819 getSiteManager, 712, 713
get() (IIntrospector method), 827 Gettext, 553, 1232
get() (RequestLocalCache method), 870 gettext, 552
get_app() (in module pyramid.paster), 833 getUtility, 712, 713
get_appsettings() (in module pyra- global state, 1232
mid.paster), 834 global views
get_category() (IIntrospector method), 827 hybrid applications, 628
get_csrf_token() (CookieCSRFStoragePol- global_registries (in module pyra-
icy method), 785 mid.config), 782
get_csrf_token() (ICSRFStoragePolicy Google App Engine, 1232
method), 814 Grok, 1232
get_csrf_token() (in module pyramid.csrf ), gunicorn, 1232
785
get_csrf_token() (LegacySessionCSRFStor- H
agePolicy method), 784 Hardwick, Nat, 11
get_csrf_token() (SessionCSRFStoragePol- has_body (Response property), 873
icy method), 784 has_permission() (Request method), 848
get_current_registry, 710, 713, 716 Hathaway, Shane, 11
get_current_registry() (in module pyra- headerlist (IResponse attribute), 823
mid.threadlocal), 894 headerlist (Response property), 873
get_current_request, 710 headers (IResponse attribute), 823
get_current_request() (in module pyra- headers (Request property), 864
mid.threadlocal), 894 headers (Response property), 873
get_locale_name() (in module pyra- hello world program, 347
mid.i18n), 808 helloworld (imperative), 349
get_localizer() (in module pyramid.i18n), Holth, Daniel, 11
808 hook_zca (configurator method), 714
get_or_create() (RequestLocalCache hook_zca() (Configurator method), 779
method), 870 host (Request property), 865
get_possible_files() (static_view host_port (Request property), 865
method), 890 host_url (Request property), 865
get_renderer() (in module pyra- hosting an app under a prefix, 564
mid.renderers), 839 HTTP caching, 470
get_resource_name() (static_view method), HTTP Exception, 1232
890 HTTP exceptions, 422

Index 1255
The Pyramid Web Framework, Version 2.0.2

http redirect (from a view), 426 HTTPRequestURITooLong, 803


http_version (Request property), 865 HTTPResetContent, 798
HTTPAccepted, 797 HTTPSeeOther, 799
HTTPBadGateway, 805 HTTPServerError, 797
HTTPBadRequest, 800 HTTPServiceUnavailable, 805
HTTPBasicCredentials (class in pyra- HTTPTemporaryRedirect, 800
mid.authentication), 721 HTTPUnauthorized, 800
HTTPClientError, 797 HTTPUnprocessableEntity, 804
HTTPConflict, 802 HTTPUnsupportedMediaType, 803
HTTPCreated, 797 HTTPUseProxy, 799
HTTPError, 797 HTTPVersionNotSupported, 805
HTTPException, 796 hybrid applications, 622
HTTPExpectationFailed, 804 *subpath, 628
HTTPFailedDependency, 804 *traverse route pattern, 624
HTTPForbidden, 800 global views, 628
HTTPFound, 799 hybrid URLs
HTTPGatewayTimeout, 805 generating, 629
HTTPGone, 802
HTTPInsufficientStorage, 806 I
HTTPInternalServerError, 804 i18n, 549
HTTPLengthRequired, 802 IActionInfo (interface in pyramid.interfaces),
HTTPLocked, 804 828
HTTPMethodNotAllowed, 801 IApplicationCreated (interface in pyra-
HTTPMovedPermanently, 799 mid.interfaces), 809
HTTPMultipleChoices, 798 IAssetDescriptor (interface in pyra-
HTTPNoContent, 798 mid.interfaces), 828
HTTPNonAuthoritativeInformation, IAuthenticationPolicy (interface in pyra-
798 mid.interfaces), 812
HTTPNotAcceptable, 801 IAuthorizationPolicy (interface in pyra-
HTTPNotFound, 801 mid.interfaces), 812
HTTPNotImplemented, 805 IBeforeRender (interface in pyra-
HTTPNotModified, 799 mid.interfaces), 810
HTTPOk, 796 IBeforeTraversal (interface in pyra-
HTTPPartialContent, 798 mid.interfaces), 810
HTTPPaymentRequired, 800 ICacheBuster (interface in pyramid.interfaces),
HTTPPermanentRedirect, 800 829
HTTPPreconditionFailed, 803 IContextFound (interface in pyra-
HTTPProxyAuthenticationRequired, mid.interfaces), 810
802 ICSRFStoragePolicy (interface in pyra-
HTTPRedirection, 797 mid.interfaces), 814
HTTPRequestEntityTooLarge, 803 identify() (AuthTktCookieHelper method),
HTTPRequestRangeNotSatisfiable, 803 720
HTTPRequestTimeout, 802 identity, 1232

1256 Index
The Pyramid Web Framework, Version 2.0.2

identity (IResponse attribute), 823 installing on Windows, 346


identity (Request property), 865 integration testing, 567
identity() (ISecurityPolicy method), 811 integration tests, 572
IDict (interface in pyramid.interfaces), 819 interactive shell, 530
IExceptionResponse (interface in pyra- interface, 1233
mid.interfaces), 813 Internationalization, 1233
if_match (Request property), 865 internationalization, 549
if_modified_since (Request property), 865 introspectable, 1233
if_none_match (Request property), 865 Introspectable (class in pyramid.registry),
if_range (Request property), 865 838
if_unmodified_since (Request property), introspectable (Configurator attribute), 782
865 introspection, 669
IIntrospectable (interface in pyra- introspector, 669, 1233
mid.interfaces), 825 introspector (Configurator attribute), 782
IIntrospector (interface in pyra- introspector (Registry attribute), 838
mid.interfaces), 826 invalidate() (ISession method), 816
immutable, 1232 invoke_exception_view() (Request
imperative configuration, 349, 352, method), 848
1233 invoke_request() (IRouter method), 817
import time, 1233 invoke_subrequest() (Request method), 847
IMultiDict (interface in pyramid.interfaces), invoking a request, 539
820 IPredicate (interface in pyramid.interfaces),
include() (Configurator method), 740 831
including from external sources IPredicateFactory (interface in pyra-
configuration, 694 mid.interfaces), 830
INewRequest, 501 IPredicateInfo (interface in pyra-
INewRequest (interface in pyramid.interfaces), mid.interfaces), 830
810 IRenderer (interface in pyramid.interfaces), 817
INewResponse, 501 IRendererFactory (interface in pyra-
INewResponse (interface in pyramid.interfaces), mid.interfaces), 817
810 IRendererInfo (interface in pyra-
INGRESS (in module pyramid.tweens), 900 mid.interfaces), 816
INGRESS (in module pyramid.viewderivers), 907 IRequestFactory (interface in pyra-
ini file, 371, 387 mid.interfaces), 817
ini file settings, 505 IResourceURL (interface in pyramid.interfaces),
initializing 828
message catalog, 554 IResponse, 649
inside() (in module pyramid.location), 832 IResponse (interface in pyramid.interfaces), 820
install IResponseFactory (interface in pyra-
Python (from package, Windows), 344 mid.interfaces), 817
install preparation, 342 IRoute (interface in pyramid.interfaces), 813
installing on macOS, 345 IRoutePredicate (interface in pyra-
installing on Unix, 345 mid.interfaces), 831

Index 1257
The Pyramid Web Framework, Version 2.0.2

IRoutePregenerator (interface in pyra- json_body (Response property), 874


mid.interfaces), 814 JSONP
IRouter (interface in pyramid.interfaces), 817 renderer, 435
is_authenticated (IResponse attribute), 823 JSONP (class in pyramid.renderers), 842
is_authenticated (Request property), 865 JSONSerializer (class in pyramid.session),
is_body_readable (Request property), 865 888
is_body_seekable (Request property), 866 Jython, 1234
is_response() (Request method), 866
is_xhr (Request property), 866 K
isdir() (IAssetDescriptor method), 828 keys() (BeforeRender method), 791
ISecurityPolicy (interface in pyra- keys() (DummyResource method), 893
mid.interfaces), 811 keys() (IDict method), 819
ISession (interface in pyramid.interfaces), 815 Koym, Todd, 11
ISessionFactory (interface in pyra-
mid.interfaces), 816 L
ISubscriberPredicate (interface in pyra- l10n, 549
mid.interfaces), 831 Laflamme, Blaise, 11
items() (BeforeRender method), 791 Laflamme, Hugues, 11
items() (DummyResource method), 893 last_modified (IResponse attribute), 823
items() (IDict method), 819 last_modified (Response property), 874
IViewDeriver (interface in pyramid.interfaces), leaf resources, 575
829 LegacySessionCSRFStoragePolicy
IViewDeriverInfo (interface in pyra- (class in pyramid.csrf ), 784
mid.interfaces), 830 line (IActionInfo attribute), 828
IViewMapper (interface in pyramid.interfaces), lineage, 1234
818 resource, 582
IViewMapperFactory (interface in pyra- lineage() (in module pyramid.location), 832
mid.interfaces), 818 Lingua, 553, 1234
IViewPredicate (interface in pyra- listdir() (IAssetDescriptor method), 828
mid.interfaces), 831 locale
negotiator, 561
J setting, 562
Jinja2, 449, 1233 Locale Name, 1234
Jinja2 i18n, 560 locale name, 557
jQuery, 1233 Locale Negotiator, 1234
JSON, 1234 locale negotiator, 563
renderer, 433 locale_name (Localizer attribute), 807
JSON (class in pyramid.renderers), 840 locale_name (Request attribute), 860
json (Request property), 866 Localization, 1234
json (Response property), 873 localization, 549
json_body localization deployment settings,
request, 491 560
json_body (Request property), 866 Localizer, 1234

1258 Index
The Pyramid Web Framework, Version 2.0.2

localizer, 555 max_forwards (Request property), 866


Localizer (class in pyramid.i18n), 807 maybe_dotted() (Configurator method), 779
localizer (Request attribute), 860 maybe_dotted() (IPredicateInfo method), 830
location, 1234 maybe_resolve() (DottedNameResolver
location (IResponse attribute), 823 method), 835
location (Response property), 874 md5_etag() (IResponse method), 824
location-aware md5_etag() (Response method), 874
resource, 576 media type, 1235
security, 615 merge_cookies() (IResponse method), 824
logging merge_cookies() (Response method), 874
.ini, 516 Merickel, Michael, 11
configuration, 516 Message Catalog, 1235
settings, 516 message catalog
startup, 386, 516 compiling, 555
initializing, 554
M updating, 555
MAIN (in module pyramid.tweens), 900 Message Identifier, 1235
make_body_seekable() (Request method), message identifier, 549
866 messages
make_localizer() (in module pyramid.i18n), extracting, 554
809 METAL, 1235
make_tempfile() (Request method), 866 method (Request property), 866
make_wsgi_app, 351 middleware, 1235
make_wsgi_app() (Configurator method), 741 .ini, 521
Mako, 449, 1234 configuration, 521
Mako i18n, 559 TransLogger, 521
manifest (ManifestCacheBuster property), 891 mixed() (IMultiDict method), 820
MANIFEST.in, 374 mod_wsgi, 1235
ManifestCacheBuster (class in pyra- modifying
mid.static), 890 package structure, 382
mapping to view callable module, 1235
resource, 449 pyramid.authentication, 717
URL pattern, 449 pyramid.authorization, 733
match() (IRoute method), 813 pyramid.config, 736
matchdict, 402, 1235 pyramid.csrf, 784
matchdict (Request attribute), 846 pyramid.decorator, 786
matched_route, 402 pyramid.events, 787
matched_route (Request attribute), 846 pyramid.exceptions, 792
matching pyramid.httpexceptions, 793
root URL, 406 pyramid.i18n, 806
matching the root URL, 406 pyramid.interfaces, 809
matching views pyramid.location, 832
printing, 529 pyramid.paster, 832

Index 1259
The Pyramid Web Framework, Version 2.0.2

pyramid.path, 834 new_csrf_token() (ICSRFStoragePolicy


pyramid.registry, 837 method), 815
pyramid.renderers, 839 new_csrf_token() (in module pyramid.csrf ),
pyramid.request, 844 785
pyramid.response, 871 new_csrf_token() (LegacySessionCSRFStor-
pyramid.scripting, 879 agePolicy method), 784
pyramid.security, 880 new_csrf_token() (SessionCSRFStoragePol-
pyramid.session, 884 icy method), 784
pyramid.settings, 888 NewRequest, 501
pyramid.static, 889 NewRequest (class in pyramid.events), 789
pyramid.testing, 891 NewResponse, 501
pyramid.threadlocal, 894 NewResponse (class in pyramid.events), 789
pyramid.traversal, 895 NO_PERMISSION_REQUIRED (in module pyra-
pyramid.tweens, 900 mid.security), 881
pyramid.url, 901 not found error (debugging), 467
pyramid.view, 902 Not Found View, 1235
pyramid.viewderivers, 907 not found view, 637
pyramid.wsgi, 908 not_ (class in pyramid.config), 783
Moroz, Tom, 11 NotFound (in module pyramid.exceptions), 793
msg (ACLAllowed property), 735, 884 notfound_view_config (class in pyra-
msg (ACLDenied property), 735, 884 mid.view), 905
msg (Allowed property), 883 notify() (Registry method), 838
msg (Denied property), 883 null_renderer (in module pyramid.renderers),
msgid 843
translation, 549
multidict, 1235 O
multidict (WebOb), 491 object tree, 575, 596
mutable, 1235 options (IViewDeriver attribute), 830
MVC, 342 options (IViewDeriverInfo attribute), 830
Oram, Simon, 11
N order (IIntrospectable attribute), 825
name original_view (IViewDeriverInfo attribute),
p-script running, 528 830
name (IRendererInfo attribute), 816 Orr, Mike, 11
name (IRoute attribute), 814 override_asset, 485
negotiate_locale_name, 557 override_asset() (Configurator method),
negotiate_locale_name() (in module 767
pyramid.i18n), 808 overriding
negotiator assets, 484, 687
locale, 561 resource URL generation, 579
new (ISession attribute), 816 routes, 687
new_csrf_token() (CookieCSRFStoragePol- views, 686
icy method), 785 overriding at runtime

1260 Index
The Pyramid Web Framework, Version 2.0.2

renderer, 440 -h, 909


peek_flash(), 501
P peek_flash() (ISession method), 816
p-script permission, 1236
running name, 528 default, 610
running Python, 528 permission names, 614
p-scripts permissions, 608
running, 528 permits() (ACLHelper method), 733
package, 377, 1236 permits() (IAuthorizationPolicy method), 813
package (IPredicateInfo attribute), 831 permits() (ISecurityPolicy method), 811
package (IRendererInfo attribute), 816 Peters, Tim, 11
package (IViewDeriverInfo attribute), 830 PHASE0_CONFIG (in module pyramid.config),
package structure 783
modifying, 382 PHASE1_CONFIG (in module pyramid.config),
package_name (Registry attribute), 838 783
Paez, Patricio, 11 PHASE2_CONFIG (in module pyramid.config),
par: settings 783
adding custom, 514 PHASE3_CONFIG (in module pyramid.config),
params (Request property), 866 783
parse_manifest() (ManifestCacheBuster phash() (IPredicate method), 831
method), 891 physical path, 1236
parse_ticket() (AuthTktCookieHelper static physical root, 1236
method), 720 physical_path (IResourceURL attribute), 828
Passing in configuration variables, physical_path_tuple (IResourceURL
429 attribute), 829
password (HTTPBasicCredentials attribute), PickleSerializer (class in pyramid.session),
721 888
PasteDeploy, 371, 1236 pip, 1236
configuration, 387 pipeline, 1236
PasteDeploy settings, 505 pkg_resources, 1236
path (Request property), 866 plaster, 1236
path_info pluralization, 555
prequest command line option, 910 pluralize() (Localizer method), 807
path_info (Request property), 867 pluralizing (i18n), 556
path_info_peek() (Request method), 867 pop() (BeforeRender method), 791
path_info_pop() (Request method), 867 pop() (IDict method), 819
path_qs (Request property), 867 pop_flash(), 500
path_url (Request property), 867 pop_flash() (ISession method), 816
pattern (IRoute attribute), 814 popitem() (BeforeRender method), 792
pdistreport, 540 popitem() (IDict method), 819
--help, 909 POST (Request property), 861
pdistreport command line option pragma (IResponse attribute), 824
--help, 909 pragma (Request property), 867

Index 1261
The Pyramid Web Framework, Version 2.0.2

pragma (Response property), 874 tweens, 537


pre-compressed assets, 474 production.ini, 373
predicate, 1237 project, 356, 1237
predicate factory, 1237 project structure, 366
PredicateMismatch, 792 protecting views, 608
predicates (IRoute attribute), 814 proutes, 535
predicates (IViewDeriverInfo attribute), 830 --help, 911
predvalseq (class in pyramid.registry), 839 proutes command line option
pregenerator, 1237 --format, 911
pregenerator (IRoute attribute), 814 --glob, 911
prepare() (IExceptionResponse method), 813 --help, 911
prepare() (in module pyramid.scripting), 879 -f, 911
prequest, 539 -g, 911
--help, 909 -h, 911
prequest command line option config_uri, 911
--app-name, 910 config_vars, 911
--display-headers, 910 pserve, 360
--header, 910 --help, 911
--help, 910 pserve command line option
--login, 911 --app-name, 912
--method, 911 --browser, 912
-d, 910 --help, 912
-h, 910 --quiet, 912
-l, 911 --reload, 912
-m, 911 --reload-interval, 912
-n, 910 --server, 912
config_uri, 910 --server-name, 912
config_vars, 910 --verbose, 912
path_info, 910 -b, 912
prevent_http_cache, 505 -h, 912
preventing cross-site request -n, 912
forgery attacks, 617 -q, 912
principal, 614, 1237 -s, 912
principal names, 614 -v, 912
principals_allowed_by_permission() config_uri, 912
(ACLHelper method), 733 config_vars, 912
principals_allowed_by_permission() pshell, 530
(IAuthorizationPolicy method), 813 --help, 912
principals_allowed_by_permission() extending, 532
(in module pyramid.security), 881 pshell command line option
printing --help, 913
matching views, 529 --list-shells, 913
routes, 535 --python-shell, 913

1262 Index
The Pyramid Web Framework, Version 2.0.2

--setup, 913 module, 792


-h, 913 pyramid.httpexceptions
-l, 913 module, 793
-p, 913 pyramid.i18n
config_uri, 913 module, 806
config_vars, 913 pyramid.interfaces
ptweens, 537 module, 809
--help, 913 pyramid.location
ptweens command line option module, 832
--help, 914 pyramid.paster
-h, 914 module, 832
config_uri, 914 pyramid.path
config_vars, 914 module, 834
pviews, 529 pyramid.registry
--help, 914 module, 837
pviews command line option pyramid.renderers
--help, 915 module, 839
-h, 915 pyramid.request
config_uri, 915 module, 844
config_vars, 915 pyramid.response
url, 915 module, 871
Pylons, 323, 342, 1237 pyramid.scripting
Pylons Project, 341 module, 879
Pylons-style controller dispatch, pyramid.security
429 module, 880
PyPI, 1237 pyramid.session
PyPy, 1237 module, 884
pyramid and other frameworks, 342 pyramid.settings
Pyramid Community Cookbook, 1237 module, 888
pyramid genesis, 10 pyramid.static
pyramid.authentication module, 889
module, 717 pyramid.testing, 570
pyramid.authorization module, 891
module, 733 pyramid.threadlocal
pyramid.config module, 894
module, 736 pyramid.traversal
pyramid.csrf module, 895
module, 784 pyramid.tweens
pyramid.decorator module, 900
module, 786 pyramid.url
pyramid.events module, 901
module, 787 pyramid.view
pyramid.exceptions module, 902

Index 1263
The Pyramid Web Framework, Version 2.0.2

pyramid.viewderivers relate() (IIntrospectable method), 826


module, 907 relate() (IIntrospector method), 827
pyramid.wsgi related() (IIntrospector method), 827
module, 908 relative_url() (Request method), 867
pyramid_debugtoolbar, 1237 reload, 360, 505
pyramid_exclog, 1238 reload settings, 505
pyramid_handlers, 1238 reload_all, 505
pyramid_jinja2, 1238 reload_assets, 505, 514
pyramid_redis_sessions, 498, 1238 reload_templates, 514
pyramid_zcml, 1238 remember() (AuthTktAuthenticationPolicy
pyramid-cookiecutter-starter, 355 method), 726
Python, 1238 remember() (AuthTktCookieHelper method),
p-script running, 528 721
Python (from package, Windows) remember() (BasicAuthAuthenticationPolicy
install, 344 method), 731
Python Enhancement Proposals remember() (IAuthenticationPolicy method),
PEP 343, 1229 812
Python Packaging Authority, 1238 remember() (in module pyramid.security), 880
remember() (ISecurityPolicy method), 811
Q remember() (RemoteUserAuthenticationPolicy
query_string (Request property), 867 method), 727
QueryStringCacheBuster (class in pyra- remember() (RepozeWho1AuthenticationPolicy
mid.static), 891 method), 732
QueryStringConstantCacheBuster remember() (SessionAuthenticationHelper
(class in pyramid.static), 891 method), 717
quote_path_segment() (in module pyra- remember() (SessionAuthenticationPolicy
mid.traversal), 897 method), 729
remote_addr (Request property), 867
R remote_host (Request property), 867
range (Request property), 867 remote_user (Request property), 868
redirecting to slash-appended RemoteUserAuthenticationPolicy
routes, 409 (class in pyramid.authentication), 726
referer (Request property), 867 remove() (IIntrospector method), 827
referrer (Request property), 867 remove_conditional_headers() (Request
register() (IIntrospectable method), 825 method), 868
Registry (class in pyramid.registry), 837 render() (in module pyramid.renderers), 839
registry (Configurator attribute), 782 render_to_response() (in module pyra-
registry (IPredicateInfo attribute), 831 mid.renderers), 840
registry (IRendererInfo attribute), 816 render_view() (in module pyramid.view), 903
registry (IRouter attribute), 818 render_view_to_iterable() (in module
registry (IViewDeriverInfo attribute), 830 pyramid.view), 903
registry (Request attribute), 844 render_view_to_response() (in module
reify() (in module pyramid.decorator), 786 pyramid.view), 902

1264 Index
The Pyramid Web Framework, Version 2.0.2

renderer, 430, 1238 request URLs, 489


adding, 438 request.registry, 714
changing, 440 request_context() (IRouter method), 818
explicitly calling, 331 request_iface (DummyRequest attribute), 894
JSON, 433 request_iface (Request attribute), 868
JSONP, 435 RequestClass (IResponse attribute), 821
overriding at runtime, 440 RequestLocalCache (class in pyra-
string, 432 mid.request), 869
system values, 445 requirements for installing pack-
templates, 446 ages, 345
renderer (template), 445 resolve() (AssetResolver method), 836
renderer factory, 1238 resolve() (DottedNameResolver method), 835
renderer globals, 1238 resource, 591, 1239
renderer response headers, 436 ACL, 610
renderers (built-in), 432 finding by interface or class,
rendering_val (IBeforeRender attribute), 811 586
Repoze, 1238 finding by path, 581
repoze.bfg genesis, 10 finding root, 583
repoze.catalog, 1239 lineage, 582
repoze.lemonade, 1239 location-aware, 576
repoze.who, 1239 mapping to view callable, 449
repoze.workflow, 1239 resource API functions, 586
repoze.zope2, 10 resource interfaces, 583, 603
RepozeWho1AuthenticationPolicy Resource Location, 1239
(class in pyramid.authentication), 731 resource path generation, 580
request, 389, 1239 resource tree, 575, 596, 1239
json_body, 491 resource url
request (and text/unicode), 490 generating, 578
Request (class in pyramid.request), 844 resource URL generation
request (IBeforeTraversal attribute), 810 overriding, 579
request (IContextFound attribute), 810 resource_path() (in module pyra-
request (INewRequest attribute), 810 mid.traversal), 896
request (INewResponse attribute), 810 resource_path() (Request method), 859
request (IResponse attribute), 824 resource_path_tuple() (in module pyra-
request attributes, 488 mid.traversal), 896
request attributes (special), 489 resource_url, 578
request factory, 641, 1239 resource_url() (in module pyramid.url), 901
request lifecycle, 389 resource_url() (Request method), 855
request method, 641 response, 421, 1240
request methods, 490 Response (class in pyramid.response), 871
request object, 488 response (creating), 495
request processing, 389 response (INewResponse attribute), 810
request type, 1239 response (Request attribute), 845

Index 1265
The Pyramid Web Framework, Version 2.0.2

response adapter, 1240 route URLs, 406


response callback, 645, 1240 route_path() (in module pyramid.url), 901
response factory, 643, 1240 route_path() (Request method), 852
response headers, 494 route_prefix_context() (Configurator
response headers (from a renderer), 436 method), 742
response object, 493 route_url() (in module pyramid.url), 901
response_adapter() (in module pyra- route_url() (Request method), 850
mid.response), 877 router, 389, 1241
ResponseClass (Request attribute), 861 Routes, 1241
reStructuredText, 1240 routes
retry_after (IResponse attribute), 824 overriding, 687
retry_after (Response property), 874 printing, 535
RFC routes mapper, 1241
RFC 2068, 793 routes.py, 378
RFC 2616, 820 running
RFC 3986#section-3.5, 851 name, p-script, 528
RFC 6838, 1235 p-scripts, 528
RFC 7231#section-5.3.2, 469, 769, Python, p-script, 528
861 running an application, 360
RFC 7231#section-5.3.3, 861 running p-script by name, 528
RFC 7231#section-5.3.4, 861 running p-scripts, 528
RFC 7231#section-5.3.5, 861 running p-scripts via Python, 528
RFC 7538, 793 running tests, 359
root, 1240
root (Request attribute), 844 S
root factory, 598, 1240 Sawyers, Andrew, 11
root URL scan, 1241
matching, 406 scan() (Configurator method), 742
root url (matching), 406 scheme (Request property), 868
Rossi, Chris, 11 script_name (Request property), 868
route, 1240 Seaver, Tres, 11
view callable lookup details, 419 security, 605
route configuration, 395, 1240 location-aware, 615
route configuration arguments, 401 URL dispatch, 418
route factory, 417 view, 467
route matching, 401 security policy, 605, 1241
debugging, 411 send() (Request method), 868
route ordering, 401 server (IResponse attribute), 824
route path pattern syntax, 396 server (Response property), 874
route predicate, 1241 server_name (Request property), 868
route predicates (custom), 414 server_port (Request property), 868
route prefix, 1241 serving
route subpath, 628 assets, 473

1266 Index
The Pyramid Web Framework, Version 2.0.2

session, 496, 1241 775


session (Request attribute), 846 setdefault() (BeforeRender method), 792
session factory, 1241 setdefault() (IDict method), 819
session factory (alternates), 498 setting
session factory (custom), 499 locale, 562
session factory (default), 496 settings, 505, 1241
session object, 497 .ini, 385
session.flash, 499 deployment, 389
session.peek_flash, 501 logging, 516
session.pop_flash, 500 middleware, 521
SessionAuthenticationHelper (class in settings (IPredicateInfo attribute), 831
pyramid.authentication), 717 settings (IRendererInfo attribute), 817
SessionAuthenticationPolicy (class in settings (IViewDeriverInfo attribute), 830
pyramid.authentication), 727 settings (Registry attribute), 837
SessionCSRFStoragePolicy (class in pyra- setUp() (in module pyramid.testing), 891
mid.csrf ), 784 setup.py, 375
set() (RequestLocalCache method), 871 setup.py develop, 358
set_authentication_policy() (Configu- setup_logging() (in module pyramid.paster),
rator method), 762 834
set_authorization_policy() (Configura- setup_registry() (Configurator method),
tor method), 762 780
set_cookie() (IResponse method), 824 Setuptools, 1242
set_cookie() (Response method), 874 Shipman, John, 11
set_csrf_storage_policy() (Configura- showing installed distributions, 540
tor method), 764 side effect, 1242
set_default_csrf_options() (Configura- SignedCookieSessionFactory() (in mod-
tor method), 763 ule pyramid.session), 884
set_default_permission() (Configurator singleton, 1242
method), 764 special ACE, 615
set_execution_policy() (Configurator special permission names, 614
method), 774 special view responses, 649
set_locale_negotiator() (Configurator SQLAlchemy, 1242
method), 767 starting, 360
set_property() (Request method), 859 startup
set_request_factory() (Configurator logging, 386, 516
method), 775 startup process, 385
set_root_factory() (Configurator method), static asset urls, 475
775 static assets view, 481
set_security_policy() (Configurator static asssets, 471
method), 762 static directory, 381
set_session_factory() (Configurator static routes, 408
method), 775 static_path() (in module pyramid.url), 902
set_view_mapper() (Configurator method), static_path() (Request method), 855

Index 1267
The Pyramid Web Framework, Version 2.0.2

static_url() (in module pyramid.url), 901 testing_resources() (Configurator


static_url() (Request method), 854 method), 781
static_view (class in pyramid.static), 889 testing_securitypolicy() (Configurator
status (IResponse attribute), 824 method), 781
status (Response property), 876 tests, 367
status_code (Response property), 876 tests (running), 359
status_int (IResponse attribute), 824 text (Request property), 868
status_int (Response property), 876 text (Response property), 876
status_map (in module pyramid.httpexceptions),text() (IPredicate method), 831
796 thread local, 1242
stream() (IAssetDescriptor method), 828 thread locals, 710
string title (IIntrospectable attribute), 826
renderer, 432 translate() (Localizer method), 808
subpath, 598, 1242 translating (i18n), 556
subpath (Request attribute), 844 translation, 555
subpath (route), 628 activating, 561
subrequest, 631 domain, 549
exception view, 636 msgid, 549
use_tweens, 633 Translation Context, 1243
subscriber, 501, 1242 translation directories, 552
subscriber() (in module pyramid.events), 787 Translation Directory, 1243
system values translation directory, 561
renderer, 445 adding, 562
Translation Domain, 1243
T Translation String, 1243
tearDown() (in module pyramid.testing), 892 translation string, 549
template, 1242 translation string factory, 551
template automatic reload, 448 translation strings
template renderers, 445 Chameleon, 559
template system bindings, 449 TranslationStringFactory() (in module
templates pyramid.i18n), 807
debugging, 447 Translator, 1243
renderer, 446 TransLogger, 521
templates used as renderers, 445 traversal, 590, 1243
templates used directly, 442 traversal algorithm, 597
test setup, 567 traversal details, 595
test tear down, 567 traversal examples, 600
testConfig() (in module pyramid.testing), 893 traversal quick example, 587
testing.ini, 374 traversal tree, 575, 596
testing_add_renderer() (Configurator traversal_path() (in module pyra-
method), 780 mid.traversal), 900
testing_add_subscriber() (Configurator traverse() (in module pyramid.traversal), 898
method), 781 traversed (Request attribute), 844

1268 Index
The Pyramid Web Framework, Version 2.0.2

traverser, 647 url (Request property), 868


truthy string, 1243 URL dispatch, 395, 589, 1244
tween, 1243 security, 418
tweens url generation (traversal), 586
printing, 537 URL generator, 648
type (IRendererInfo attribute), 817 URL pattern
type_name (IIntrospectable attribute), 826 mapping to view callable, 449
url_encoding (Request property), 868
U urlargs (Request property), 869
ubody (Response property), 876 URLDecodeError, 793
unauthenticated_userid (Request at- urlencode() (in module pyramid.url), 902
tribute), 846 urlvars (Request property), 869
unauthenticated_userid() (AuthTktAu- uscript_name (Request property), 869
thenticationPolicy method), 726 use_tweens
unauthenticated_userid() (BasicAuthAu- subrequest, 633
thenticationPolicy method), 731 user_agent (Request property), 869
unauthenticated_userid() (IAuthentica- userid, 1244
tionPolicy method), 812 username (HTTPBasicCredentials attribute),
unauthenticated_userid() (RemoteUser- 721
AuthenticationPolicy method), 727
unauthenticated_userid() (Repoze- V
Who1AuthenticationPolicy method), values() (BeforeRender method), 792
732 values() (DummyResource method), 893
undefer() (in module pyramid.registry), 839 values() (IDict method), 820
unhook_zca() (Configurator method), 779 van Rossum, Guido, 11
unicode and text (and the request), 490 vary (IResponse attribute), 824
unicode, views, and forms, 426 vary (Response property), 876
unicode_body (IResponse attribute), 824 Venusian, 1244
unicode_body (Response property), 876 venv, 1244
unit testing, 567 view, 1244
unittest, 567 security, 467
unrelate() (IIntrospectable method), 826 VIEW (in module pyramid.viewderivers), 907
unrelate() (IIntrospector method), 827 view callable, 1244
unset_cookie() (IResponse method), 824 view callable lookup details
unset_cookie() (Response method), 876 route, 419
upath_info (Request property), 868 view callables, 420
update() (BeforeRender method), 791 view calling convention, 420, 421, 428
update() (IDict method), 820 view class, 421
updating view configuration, 1244
message catalog, 555 debugging, 471
upgrading pyramid, 705 view configuration parameters, 450
url view deriver, 1244
pviews command line option, 915 view derivers, 665

Index 1269
The Pyramid Web Framework, Version 2.0.2

view exceptions, 422 with_package() (Configurator method), 777


view function, 420 WSGI, 363, 1246
View handler, 1245 WSGI application, 351
view http redirect, 426 wsgiapp() (in module pyramid.wsgi), 908
View Lookup, 1245 wsgiapp2() (in module pyramid.wsgi), 908
view lookup, 449, 592, 597 www_authenticate (IResponse attribute), 825
view mapper, 651, 1245 www_authenticate (Response property), 876
view name, 598, 1245
view predicate, 1245 Z
view renderer, 430 ZCA, 712
explicitly calling, 331 ZCA global API, 713
view response, 421 ZCA global registry, 716
view security, 467 ZCML, 1246
view_config, 353 ZODB, 1246
view_config (class in pyramid.view), 903 Zope, 323, 342, 1246
view_config decorator, 459 Zope 2, 10
view_config placement, 461 Zope 3, 10
view_defaults class decorator, 463 Zope Component Architecture, 712, 1246
view_defaults() (in module pyramid.view), zope.component, 712
905 ZPT, 1246
view_execution_permitted() (in module
pyramid.security), 881
view_name (Request attribute), 844
views
overriding, 686
views, forms, and unicode, 426
views.py, 379
virtual environment, 1245
virtual hosting, 564
virtual root, 565, 1245
virtual_path (IResourceURL attribute), 829
virtual_path_tuple (IResourceURL at-
tribute), 829
virtual_root (Request attribute), 845
virtual_root() (in module pyra-
mid.traversal), 897
virtual_root_path (Request attribute), 845
virtualenv, 1245

W
Waitress, 1245
WebOb, 487, 1245
WebTest, 1245

1270 Index

You might also like