Chris McDonough
2011-09-07 bb93cbdf16ac03e354569959663d053a68685fc5
add squishy whats-unique section to introduction
4 files modified
473 ■■■■■ changed files
docs/narr/introduction.rst 467 ●●●●● patch | view | raw | blame | history
docs/narr/security.rst 2 ●●●●● patch | view | raw | blame | history
docs/narr/urldispatch.rst 2 ●●●●● patch | view | raw | blame | history
docs/narr/viewconfig.rst 2 ●●●●● patch | view | raw | blame | history
docs/narr/introduction.rst
@@ -52,20 +52,481 @@
Speed
  :app:`Pyramid` is designed to provide noticeably fast execution for common
  tasks such as templating and simple response generation. Although “hardware
  tasks such as templating and simple response generation. Although "hardware
  is cheap", the limits of this approach become painfully evident when one
  finds him or herself responsible for managing a great many machines.
Reliability
  :app:`Pyramid` is developed conservatively and tested exhaustively. Where
  Pyramid source code is concerned, our motto is: "If it ain’t tested, it’s
  broke". Every release of Pyramid has 100% statement coverage via unit
  tests.
  broke".
Openness
  As with Python, the Pyramid software is distributed under a `permissive
  open source license <http://repoze.org/license.html>`_.
What Makes Pyramid Unique
-------------------------
Understandably, people don't usually want to hear about squishy engineering
principles, they want to hear about concrete stuff that solves their
problems.  With that in mind, what would make someone want to use Pyramid
instead of the dozens-of-odd other web frameworks available today?  What
makes Pyramid unique?
This is a hard question to answer, because there are lots of excellent
choices, and it's actually quite hard to make a wrong choice, particularly in
the Python web framework market.  But one reasonable answer is this: you can
write very small applications in Pyramid without needing to know a lot.
"What?", you say, "that can't possibly be a unique feature, lots of other web
frameworks let you do that!"  Well, you're right.  But unlike many other
systems, you can also write very large applications in Pyramid if you learn a
little more about it.  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.  "Well
that's fine," you say, "lots of other frameworks let me write large apps
too."  Absolutely.  But other Python web frameworks don't seamlessly let you
do both.  They seem to fall into two non-overlapping categories: frameworks
for "small apps" and frameworks for "big apps".  The "small app" frameworks
typically sacrifice "big app" features, and vice versa.
We don't think it's a universally reasonable suggestion to write "small apps"
in a "small framework" and "big apps" in a "big framework".  You can't really
know what size every application will eventually grow to.  We don't really
want to have to rewrite a previously small application in another framework
when it gets "too big".  We believe the current binary distinction between
"small" and "large" frameworks is just false; one framework should be able to
be good at both if it's well-designed.  Pyramid is such a framework.
To this end, Pyramid provides a set of features, that, combined, are unique
amongst Python web frameworks.  Lots of other frameworks contain some
combination of these features; Pyramid of course actually stole many of them
from those other frameworks.  But Pyramid is the only one that has all of
them in one place, documented appropriately, and useful ala-carte without
necessarily paying for the entire banquet.  These are detailed below.
Single-File Applications
~~~~~~~~~~~~~~~~~~~~~~~~
You can write a Pyramid application that lives entirely in one Python file,
not unlike existing Python microframeworks.  This is beneficial for "one off"
prototyping, bug reproduction, and very small applications.  These
applications are easy to understand because all the information about the
application lives in a single place, and you can deploy them without needing
to understand much about Python distributions and packaging.  Pyramid isn't
really marketed as a "microframework", but it allows you to do almost
everything that frameworks that are marketed as "micro" offer in very similar
ways.
Example: :ref:`firstapp_chapter`.
Decorator-Based Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you like the idea of framework configuration statements living next to the
code it configures, so you don't have to constantly switch between files to
refer to framework configuration when adding new code, you can use Pyramid
decorators to localize the configuration.  For example::
   @view_config(route_name='fred')
   def fred_view(request):
       return Response('fred')
However, unlike other systems (various "microframeworks" come to mind), using
decorators for configuration does not make your application difficult,
extend, test or reuse.  The ``view_config`` decorator, for example, does not
actually *change* the input or output of the function it decorates, so
testing it is a "WYSIWYG" operation; you don't need to understand the
framework to test your own code, you just behave as if the decorator is not
there.  You can also instruct Pyramid to ignore some decorators, or use
completely imperative configuration instead of decorators to add views.
Pyramid decorators are inert instead of eager: you detect and activate them
with a ``scan``.  They're basically just markers.
Example: :ref:`mapping_views_using_a_decorator_section`.
URL Generation
~~~~~~~~~~~~~~
Pyramid is capable of generating URLs for resources, routes, and static
assets.  Its URL generation APIs are easy to use and flexible.  If you use
Pyramid's various APIs for generating URLs, you can change your configuration
around arbitrarily without fear of breaking a link on one of your web pages.
Example: :ref:`generating_route_urls`.
Static file serving
~~~~~~~~~~~~~~~~~~~
Pyramid is perfectly willing to serve static files itself.  It won't make you
use some external web server to do that.  You can even serve more than one
set of static files in a single Pyramid web application (e.g. ``/static`` and
``/static2``).  You can also, optionally, place your files on an external web
server and ask Pyramid to help you generate URLs to those files, so you can
use Pyramid's internal fileserving while doing development, and a faster
static file server in production without changing any code.
Example: :ref:`static_assets_section`.
Debug Toolbar
~~~~~~~~~~~~~
Pyramid's debug toolbar comes activated when you use a Pyramid scaffold to
render a project.  This toolbar overlays your application in the browser, and
allows you access to framework data such as the routes configured, the last
renderings performed, the current set of packages installed, SQLAlchemy
queries run, logging data, and various other facts.  When an exception
occurs, you can use its interactive debugger to poke around right in your
browser to try to determine the cause of the exception.  It's handy.
Example: :ref:`debug_toolbar`.
Debugging settings
~~~~~~~~~~~~~~~~~~
Pyramid has debugging settings that allow you to print Pyramid runtime
information to the console when things aren't behaving as you're expecting.
For example, you can turn on "debug_notfound", which prints an informative
message to the console every time a URL does not match any view.  You can
turn on "debug_authorization", which lets you know why a view execution was
allowed or denied by printing a message to the console.  These features are
useful for those WTF moments.
There are also a number of ``paster`` commands that allow you to introspect
the configuration of your system: ``paster proutes`` shows all configured
routes for an application in the order they'll be evaluated for matching;
``paster pviews`` shows all configured views for any given URL.  These are
also WTF-crushers in some circumstances.
Example: :ref:`debug_authorization_section` and :ref:`command_line_chapter`.
Class-Based and Function-Based Views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pyramid has a structured, unified conception of views.  Views can be
functions, methods of classes, or even instances.  When you add a new view,
you can choose to make it a function or a method of a class; in either case,
Pyramid treats it largely the same way.  You can change your mind later, and
move code between methods of classes and functions.  A collection of similar
view callables can be attached to a single class as methods, if that floats
your boat, and they can share initialization code as necessary.  All kinds of
views are easy to understand and use and operate similarly.  There is no
phony distinction between them; they can be used for the same purposes.
Example: :ref:`view_config_placement`.
Event system
~~~~~~~~~~~~
Pyramid emits *events* during its request processing lifecycle.  You can
subscribe any number of listeners to these events.  For example, to be
notified of a new request, you can subscribe to the ``NewRequest`` event.  To
be notified that a template is about to be rendered, you can subscribe to the
``BeforeRender`` event, and so forth.  Using an event publishing system as a
framework notification feature instead of hardcoded hook points tends to make
systems based on that framework less brittle.  You can also use Pyramid's
event system to send your *own* events.  For example, if you'd like to create
a system that is itself a framework, and may want to notify subscribers that
a document has just been indexed, you can create your own event type
(``DocumentIndexed`` perhaps) and send the event via Pyramid.  Users of this
framework can then subscribe to your event like they'd subscribe to the
events that are normally sent by Pyramid itself.
Example: :ref:`events_chapter` and :ref:`event_types`.
Extensible templating
~~~~~~~~~~~~~~~~~~~~~
Pyramid has a structured API that allows for pluggability of "renderers".
Templating systems such as Mako, Genshi, Chameleon, and Jinja2 can be treated
as renderers.  Renderer bindings for all of these templating systems already
exist for use in Pyramid.  But if you'd rather use another, it's not a big
deal.  Just copy the code from an existing renderer package, and plug in your
own.  You'll then be able to use your templating system from within Pyramid
just as you'd use one of the "built-in" templating systems.
Example: :ref:`templates_used_directly`.
Speed
~~~~~
The Pyramid core is, as far as we can tell, at least marginally faster than
any other existing Python web framework.  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.  Extraneous function calls and suboptimal
algorithms in its core codepaths are avoided religiously.  It is feasible to
get, for example, between 3500 and 4000 requests per second from a simple
Pyramid view on commodity dual-core laptop hardware and an appropriate WSGI
server (mod_wsgi or gunicorn).  In any case, performance statstics are
largely useless without requirements and goals, but if you need speed,
Pyramid will almost certainly never be your application's bottleneck; at
least no more than Python will be a bottleneck.
Example: http://blog.curiasolutions.com/the-great-web-framework-shootout/
Sessions
~~~~~~~~
Pyramid has built-in HTTP sessioning.  This allows you to associate data with
otherwise anonymous users between requests.  Lots of systems do this.  But
Pyramid also allows you to plug in your own sessioning system by creating
some code that adheres to a documented interface.  Currently there is a
binding package for the Beaker 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: :ref:`sessions_chapter`.
No singletons
~~~~~~~~~~~~~
Pyramid is written in such a way that it has exactly zero "singleton" data
structures.  Or, put another way, Pyramid constructs no "mutable globals".
Or put even a different way, an import of a Pyramid application needn't have
any "import time side effects".  This is esoteric-sounding, but if you've
ever tried to cope with parameterizing a Django "settings.py" file for
multiple installations of the same application, or if you've ever needed to
monkey-patch some framework fixture so that it behaves properly for your use
case, or if you've ever wanted to deploy your system using an asynchronous
server, you'll end up appreciating this feature.  It just won't be a problem.
You can even run multiple copies of a similar but not identically configured
Pyramid application within the same Python process.  This is good for shared
hosting environments, where RAM is at a premium.
View Predicates and Many Views Per Route
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlike many other systems, Pyramid allows you to associate more than one view
per route.  For example, you can create a route with the pattern ``/items``
and when the route is matched, you can shuffle off the request to one view if
the request method is GET, another view if the request method is POST, etc.
A system known as "view predicates" allows for this.  Request method matching
is the very most basic thing you can do with a view predicate.  You can also
associate views with other request parameters such as the elements in the
query string, the Accept header, whether the request is an XHR request or
not, and lots of other things.  This feature allows you to keep your
individual views "clean"; they won't need much conditional logic, so they'll
be easier to test.
Example: :ref:`view_configuration_parameters`.
Exception views
~~~~~~~~~~~~~~~
Exceptions happen.  Rather than deal with exceptions that might present
themselves to a user in production in an ad-hoc way, Pyramid allows you to
register *exception views*.  Exception views are like regular Pyramid views,
but they're only invoked when an exception "bubbles up" to Pyramid itself.
For example, you might register an exception view for the ``Exception``
exception, which will catch *all* exceptions, and present a pretty "whoops,
this is embarrassing" page.  Or you might choose to register an exception
view for only specific kinds of application-specific exceptions, such as an
exception that happens when a file is not found, or an exception that happens
when action cannot be performed because 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: :ref:`exception_views`.
Asset specifications
~~~~~~~~~~~~~~~~~~~~
Asset specifications are strings that contain both a Python package name and
a file or directory name, e.g. ``MyPackage:static/index.html``.  Use of these
specifications is omnipresent in Pyramid.  You can refer to a template using
an asset specification, a translation directory, and other package-bound
static resources using one.  This makes a system built on Pyramid extensible,
because you don't have to rely on globals ("the static directory") or lookup
schemes ("the ordered set of template directories") to address your files.
You can move files around as necessary, and include other packages that may
not share your system's templates or static files without encountering
conflicts.
Because asset specifications are used heavily in Pyramid, we've also provided
a way to allow users to override assets.  Say you love a system that someone
else has created with Pyramid but you just need to change "that one template"
to make it all better.  No need to fork the application.  Just override the
asset specification for that template with your own inside a wrapper, and
you're good to go.
Example: :ref:`asset_specifications`.
Transaction management
~~~~~~~~~~~~~~~~~~~~~~
Pyramid's :term:`scaffold` system renders projects that include a
*transaction management* system, also stolen from Zope.  When you use this
transaction management system, you cease being responsible for committing
your data anymore.  Instead, Pyramid takes care of committing: it commits at
the end of a request or aborts if there's an exception.  Why is that a good
thing?  Transaction boundaries are awfully hard to get right.  If you add a
``session.commit`` call in your application logic, and your code goes on to
do other important things after that commit, and error happens in the later
code, sometimes, you're kind of screwed.  Some data will have been written to
the database that probably should not have.  Having a centralized commit
point saves you from needing to think about this.  Also, Pyramid's
transaction management system allows you to synchronize commits between
multiple databases, and allows you to do things like conditionally send email
if a transaction commits, but otherwise keep quiet.
Example: :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements
anywhere in application code).
Configuration conflict detection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When a system is small, it's reasonably easy to keep it in all in your head.
But when systems grow large, you may have hundreds or thousands of
configuration statements which add a view, add a route, and so forth.
Pyramid's configuration system keeps track of your configuration statements,
and 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.  It's not dumb though: it will
automatically resolve conflicting configuration statements on its own if you
use the configuration ``include`` system: "more local" statements are
preferred over "less local" ones.  This allows you to intelligently factor
large systems into smaller ones.
Example: :ref:`conflict_detection`.
Configuration extensibility
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlike other systems, Pyramid provides a structured ``include`` mechanism
that allows you compose applications from multiple Python packages.  All the
configuration statements that can be performed in your "main" Pyramid
application can also be performed by included packages (including the
addition of views, routes, subscribers, and even authentication and
authorization policies). You can even extend or override an existing
application by including another application's configuration in your own, and
overriding or adding new views and routes to it.  This has the potential to
allow you to compose a big application out of many other smaller ones.  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``; the new application will live within your application at a
URL prefix.  It's not a big deal, and requires little up-front engineering
effort.
Example: :ref:`building_an_extensible_app`.
Flexible authentication and authorization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pyramid includes a flexible, pluggable authentication and authorization
system.  No matter where your user data is stored, or what scheme you'd like
to use to permit your users to access your data, you can use a predefined
Pyramid plugpoint to plug in your custom authentication and authorization
code.  If you want to change these schemes later, you can just change it in
one place rather than everywhere in your code.  It also ships with prebuilt
well-tested authentication and authorization schemes out of the box.  But
what if you don't want to use Pyramid's built-in system?  You don't have to.
You can just write your own bespoke security code as you would in any other
system.
Example: :ref:`enabling_authorization_policy`.
Built-in Internationalization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pyramid ships with internalization-related features in its core:
localization, pluralization, and creating message catalogs from source files
and templates.  Pyramid allows for a plurality of message catalog 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: :ref:`i18n_chapter`.
Traversal
~~~~~~~~~
:term:`Traversal` is a concept stolen from :term:`Zope`.  It allows you to
create a tree of resources, each of which can be addressed by one or more
URLs.  Each of those resources can have one or more *views* associated with
it. Iif your data isn't naturally treelike (or you're unwilling to create a
treelike representation of your data), you aren't going to find traversal
very useful.  However, traversal is absolutely fantastic for sites that need
to be arbitrarily extensible: it's a lot easier to add a node to a tree than
it is to shoehorn a route into an ordered list of other routes, or to create
another entire instance of an application to service a department and glue
code to allow disparate apps to share data.  It's a great fit for sites that
naturally lend themselves to changing departmental hierarchies, such as CMS
systems and document management systems.  Traversal also lends itself well to
systems that require very granular security ("Bob can edit *this* document"
as opposed to "Bob can edit documents").
Example: :ref:`much_ado_about_traversal_chapter`.
HTTP Caching
~~~~~~~~~~~~
Pyramid provides an easy way to associate views with HTTP caching policies.
You can just tell Pyramid to configure your view with an ``http_cache``
statement, and it will take care of the rest::
   @view_config(http_cache=3600) # 60 minutes
   def myview(request): ....
Pyramid will add appropriate ``Cache-Control`` and ``Expires`` headers to
responses generated when this view is invoked.
See the :meth:`pyramid.config.Configurator.add_view` statement's
``http_cache`` documentation for more information.
Tweens
~~~~~~
Pyramid has a sort of internal WSGI-middleware-ish pipeline that can be
hooked by arbitrary add-ons named "tweens".  The debug toolbar is a "tween",
and the ``pyramid_tm`` transaction manager is also.  Tweens are more useful
than WSGI middleware in some circumstances because they run in the context of
Pyramid itself, meaning you have access to templates and other renderers, a
"real" request object, and other niceties.
Example: :ref:`registering_tweens`.
Testing
~~~~~~~
Every release of Pyramid has 100% statement coverage via unit and integration
tests, as measured by the ``coverage`` tool available on PyPI.  It also has
greater than 95% decision/condition coverage as measured by the
``instrumental`` tool available on PyPI.  It is automatically tested by the
Jenkins tool on Python 2.5, Python 2.6, Python 2.7, Jython and PyPy after
each commit to its GitHub repository.  Official Pyramid add-ons are held to a
similar testing standard.  We still find bugs in Pyramid and its official
add-ons, but we find a lot fewer of them than do the owners of comparable
projects that don't test so exhaustively.
Example: http://jenkins.pylonsproject.org/
Support
~~~~~~~
It's our goal that no Pyramid question go unanswered.  Whether you ask a
question on IRC, on the Pylons-discuss maillist, or on StackOverflow, you're
likely to get a reasonaly prompt response.  We don't tolerate "tech trolls"
or other people who seem to get their rocks off by berating fellow users in
our various offical support channels.  We try to keep it well-lit and
new-user-friendly.
Example: Visit irc://freenode.net#pyramid (the ``#pyramid`` channel on
irc.freenode.net in an IRC client) or the pylons-discuss maillist at
http://groups.google.com/group/pylons-discuss/ .
Documentation
~~~~~~~~~~~~~
It's a constant struggle, but we try to maintain a balance between
completeness and new-user-friendliness in the official narrative Pyramid
documentation (concrete suggestions for improvement are always appreciated,
by the way).  We also maintain a "cookbook" of recipes, which are usually
demonstrations of common integration scenarios, too specific to add to the
official narrative docs.  In any case, the Pyramid documentation is
comprehensive.
Example: The rest of this documentation.
.. index::
   single: Pylons Project
docs/narr/security.rst
@@ -60,6 +60,8 @@
.. index::
   single: authorization policy
.. _enabling_authorization_policy:
Enabling an Authorization Policy
--------------------------------
docs/narr/urldispatch.rst
@@ -590,6 +590,8 @@
   single: generating route URLs
   single: route URLs
.. _generating_route_urls:
Generating Route URLs
---------------------
docs/narr/viewconfig.rst
@@ -504,6 +504,8 @@
.. index::
   single: view_config placement
.. _view_config_placement:
``@view_config`` Placement
++++++++++++++++++++++++++