diff options
Diffstat (limited to 'docs/narr/introduction.rst')
| -rw-r--r-- | docs/narr/introduction.rst | 1046 |
1 files changed, 932 insertions, 114 deletions
diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index a0b682e25..24c9f6b93 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -7,83 +7,903 @@ single: framework :app:`Pyramid` Introduction -============================== +=========================== :app:`Pyramid` is a general, open source, Python web application development -*framework*. Its primary goal is to make it easier for a developer to create -web applications. The type of application being created could be a -spreadsheet, a corporate intranet, or a social networking platform; Pyramid's -generality enables it to be used to build an unconstrained variety of web -applications. +*framework*. Its primary goal is to make it easier for a Python developer to +create web applications. .. sidebar:: Frameworks vs. Libraries - A *framework* differs from a *library* in one very important way: - library code is always *called* by code that you write, while a - framework always *calls* code that you write. Using a set of - libraries to create an application is usually easier than using a - framework initially, because you can choose to cede control to - library code you have not authored very selectively. But when you - use a framework, you are required to cede a greater portion of - control to code you have not authored: code that resides in the - framework itself. You needn't use a framework at all to create a - web application using Python. A rich set of libraries already - exists for the platform. In practice, however, using a framework - to create an application is often more practical than rolling your - own via a set of libraries if the framework provides a set of - facilities that fits your application requirements. + A *framework* differs from a *library* in one very important way: library + code is always *called* by code that you write, while a framework always + *calls* code that you write. Using a set of libraries to create an + application is usually easier than using a framework initially, because you + can choose to cede control to library code you have not authored very + selectively. But when you use a framework, you are required to cede a + greater portion of control to code you have not authored: code that resides + in the framework itself. You needn't use a framework at all to create a web + application using Python. A rich set of libraries already exists for the + platform. In practice, however, using a framework to create an application + is often more practical than rolling your own via a set of libraries if the + framework provides a set of facilities that fits your application + requirements. -The first release of Pyramid's predecessor (named :mod:`repoze.bfg`) was made -in July of 2008. We have worked hard to ensure that Pyramid continues to -follow the design and engineering principles that we consider to be the core -characteristics of a successful framework: +Pyramid attempts to follow these design and engineering principles: Simplicity - :app:`Pyramid` takes a *"pay only for what you eat"* approach. This means - that you can get results even if you have only a partial understanding of - :app:`Pyramid`. It doesn’t force you to use any particular technology to - produce an application, and we try to keep the core set of concepts that - you need to understand to a minimum. + :app:`Pyramid` takes a *"pay only for what you eat"* approach. You can get + results even if you have only a partial understanding of :app:`Pyramid`. It + doesn't force you to use any particular technology to produce an application, + and we try to keep the core set of concepts that you need to understand to a + minimum. Minimalism - :app:`Pyramid` concentrates on providing fast, high-quality solutions to - the fundamental problems of creating a web application: the mapping of URLs - to code, templating, security and serving static assets. We consider these - to be the core activities that are common to nearly all web applications. + :app:`Pyramid` tries to solve only the fundamental problems of creating a web + application: the mapping of URLs to code, templating, security, and serving + static assets. We consider these to be the core activities that are common to + nearly all web applications. Documentation - Pyramid's minimalism means that it is relatively easy for us to maintain - extensive and up-to-date documentation. It is our goal that no aspect of - Pyramid remains undocumented. + Pyramid's minimalism means that it is easier for us to maintain complete and + up-to-date documentation. It is our goal that no aspect of Pyramid is + undocumented. Speed :app:`Pyramid` is designed to provide noticeably fast execution for common - tasks such as templating and simple response generation. Although the - “hardware is cheap” mantra may appear to offer a ready solution to speed - problems, the limits of this approach become painfully evident when one - finds him or herself responsible for managing a great many machines. + tasks such as templating and simple response generation. 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. + Pyramid source code is concerned, 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 <http://repoze.org/license.html>`_. + As with Python, the Pyramid software is distributed under a `permissive open + source license <http://repoze.org/license.html>`_. + +.. _what_makes_pyramid_unique: + +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 one +of the many 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 to what size every application will eventually grow. 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 frameworks +for small and large applications is just false. A well-designed framework +should be able to be good at both. Pyramid strives to be that kind of +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 *à la 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. + +.. literalinclude:: helloworld.py + +.. seealso:: + + See also :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: + +.. code-block:: python + + from pyramid.view import view_config + from pyramid.response import Response + + @view_config(route_name='fred') + def fred_view(request): + return Response('fred') + +However, unlike some other systems, using decorators for Pyramid configuration +does not make your application difficult to extend, test, or reuse. The +:class:`~pyramid.view.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 :term:`scan`. + +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 optionally place your files on an external web server +and ask Pyramid to help you generate URLs to those files. This let's you use +Pyramid's internal file serving while doing development, and a faster static +file server in production, without changing any code. + +Example: :ref:`static_assets_section`. + +Fully interactive development +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When developing a Pyramid application, several interactive features are +available. Pyramid can automatically utilize changed templates when rendering +pages and automatically restart the application to incorporate changed Python +code. Plain old ``print()`` calls used for debugging can display to a console. + +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 commands that you can invoke within a Pyramid +environment that allow you to introspect the configuration of your system. +``proutes`` shows all configured routes for an application in the order they'll +be evaluated for matching. ``pviews`` shows all configured views for any given +URL. These are also WTF-crushers in some circumstances. + +Examples: :ref:`debug_authorization_section` and :ref:`command_line_chapter`. + +Add-ons +~~~~~~~ + +Pyramid has an extensive set of add-ons held to the same quality standards as +the Pyramid core itself. Add-ons are packages which provide functionality that +the Pyramid core doesn't. Add-on packages already exist which let you easily +send email, let you use the Jinja2 templating system, let you use XML-RPC or +JSON-RPC, let you integrate with jQuery Mobile, etc. + +Examples: +http://docs.pylonsproject.org/en/latest/docs/pyramid.html#pyramid-add-on-documentation + +Class-based and function-based views +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Pyramid has a structured, unified concept of a :term:`view callable`. View +callables can be functions, methods of classes, or even instances. When you +add a new view callable, 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. + +Here's a view callable defined as a function: + +.. code-block:: python + :linenos: + + from pyramid.response import Response + from pyramid.view import view_config + + @view_config(route_name='aview') + def aview(request): + return Response('one') + +Here's a few views defined as methods of a class instead: + +.. code-block:: python + :linenos: + + from pyramid.response import Response + from pyramid.view import view_config + + class AView(object): + def __init__(self, request): + self.request = request + + @view_config(route_name='view_one') + def view_one(self): + return Response('one') + + @view_config(route_name='view_two') + def view_two(self): + return Response('two') + +.. seealso:: + + See also :ref:`view_config_placement`. + +.. _intro_asset_specs: + +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. An asset specification can refer to +a template, a translation directory, or any other package-bound static +resource. 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. + +Examples: :ref:`asset_specifications` and :ref:`overriding_assets_section`. + +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 +favorite templating system. You'll then be able to use that templating system +from within Pyramid just as you'd use one of the "built-in" templating systems. + +Pyramid does not make you use a single templating system exclusively. You can +use multiple templating systems, even in the same project. + +Example: :ref:`templates_used_directly`. + +Rendered views can return dictionaries +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you use a :term:`renderer`, you don't have to return a special kind of +"webby" ``Response`` object from a view. Instead you can return a dictionary, +and Pyramid will take care of converting that dictionary to a Response using a +template on your behalf. This makes the view easier to test, because you don't +have to parse HTML in your tests. Instead just make an assertion that the view +returns "the right stuff" in the dictionary. You can write "real" unit tests +instead of functionally testing all of your views. .. index:: - single: Pylons - single: Agendaless Consulting - single: repoze namespace package + pair: renderer; explicitly calling + pair: view renderer; explictly calling + +.. _example_render_to_response_call: + +For example, instead of returning a ``Response`` object from a +``render_to_response`` call: + +.. code-block:: python + :linenos: + + from pyramid.renderers import render_to_response + + def myview(request): + return render_to_response('myapp:templates/mytemplate.pt', {'a':1}, + request=request) + +You can return a Python dictionary: + +.. code-block:: python + :linenos: + + from pyramid.view import view_config + + @view_config(renderer='myapp:templates/mytemplate.pt') + def myview(request): + return {'a':1} + +When this view callable is called by Pyramid, the ``{'a':1}`` dictionary will +be rendered to a response on your behalf. The string passed as ``renderer=`` +above is an :term:`asset specification`. It is in the form +``packagename:directoryname/filename.ext``. In this case, it refers to the +``mytemplate.pt`` file in the ``templates`` directory within the ``myapp`` +Python package. Asset specifications are omnipresent in Pyramid. See +:ref:`intro_asset_specs` for more information. + +Example: :ref:`renderers_chapter`. + +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`. + +Built-in internationalization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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: :ref:`i18n_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` method's ``http_cache`` +documentation for more information. + +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 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: :ref:`sessions_chapter`. + +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. 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 statistics 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/pages/the-great-web-framework-shootout.html + +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 an :term:`exception view`. 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 +:exc:`Exception` exception, 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 specific kinds of application-specific exceptions, such +as an exception that happens when a file is not found, or an exception that +happens when an 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`. + +No singletons +~~~~~~~~~~~~~ + +Pyramid is written in such a way that it requires your application to have +exactly zero "singleton" data structures. Or put another way, Pyramid doesn't +require you to construct any "mutable globals". Or put even another 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 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`. + +Transaction management +~~~~~~~~~~~~~~~~~~~~~~ + +Pyramid's :term:`scaffold` system renders projects that include a *transaction +management* system, 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? Having a centralized place +for transaction management is a great thing. If, instead of managing your +transactions in a centralized place, you sprinkle ``session.commit`` calls in +your application logic itself, you can wind up in a bad place. Wherever you +manually commit data to your database, it's likely that some of your other code +is going to run *after* your commit. If that code goes on to do other important +things after that commit, and an error happens in the later code, you can +easily wind up with inconsistent data if you're not extremely careful. 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; +it's great for lazy people who also care about data integrity. Either the +request completes successfully, and all changes are committed, or it does not, +and all changes are aborted. + +Pyramid's transaction management system allows you to synchronize commits +between multiple databases. It also 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 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. 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 :meth:`~pyramid.config.Configurator.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 (see +:meth:`~pyramid.config.Configurator.include`) that allows you to combine +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, overriding or adding new views and routes to it. This has the +potential to allow you to create 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 an +URL prefix. It's not a big deal, and requires little up-front engineering +effort. + +For example: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + + if __name__ == '__main__': + config = Configurator() + config.include('pyramid_jinja2') + config.include('pyramid_exclog') + config.include('some.other.guys.package', route_prefix='/someotherguy') + +.. seealso:: + + See also :ref:`including_configuration` and + :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`. + +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. If +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 content +management 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"). + +Examples: :ref:`hello_traversal_chapter` and +:ref:`much_ado_about_traversal_chapter`. + +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 +:term:`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`. + +View response adapters +~~~~~~~~~~~~~~~~~~~~~~ + +A lot is made of the aesthetics of what *kinds* of objects you're allowed to +return from view callables in various frameworks. In a previous section in +this document, we showed you that, if you use a :term:`renderer`, you can +usually return a dictionary from a view callable instead of a full-on +:term:`Response` object. But some frameworks allow you to return strings or +tuples from view callables. When frameworks allow for this, code looks +slightly prettier, because fewer imports need to be done, and there is less +code. For example, compare this: + +.. code-block:: python + :linenos: + + def aview(request): + return "Hello world!" + +To this: + +.. code-block:: python + :linenos: + + from pyramid.response import Response + + def aview(request): + return Response("Hello world!") + +The former is "prettier", right? + +Out of the box, if you define the former view callable (the one that simply +returns a string) in Pyramid, when it is executed, Pyramid will raise an +exception. This is because "explicit is better than implicit", in most cases, +and by default Pyramid wants you to return a :term:`Response` object from a +view callable. This is because there's usually a heck of a lot more to a +response object than just its body. But if you're the kind of person who +values such aesthetics, we have an easy way to allow for this sort of thing: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + from pyramid.response import Response + + def string_response_adapter(s): + response = Response(s) + response.content_type = 'text/html' + return response + + if __name__ == '__main__': + config = Configurator() + config.add_response_adapter(string_response_adapter, basestring) + +Do that once in your Pyramid application at startup. Now you can return +strings from any of your view callables, e.g.: + +.. code-block:: python + :linenos: + + def helloview(request): + return "Hello world!" + + def goodbyeview(request): + return "Goodbye world!" + +Oh noes! What if you want to indicate a custom content type? And a custom +status code? No fear: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + + def tuple_response_adapter(val): + status_int, content_type, body = val + response = Response(body) + response.content_type = content_type + response.status_int = status_int + return response + + def string_response_adapter(body): + response = Response(body) + response.content_type = 'text/html' + response.status_int = 200 + return response + + if __name__ == '__main__': + config = Configurator() + config.add_response_adapter(string_response_adapter, basestring) + config.add_response_adapter(tuple_response_adapter, tuple) + +Once this is done, both of these view callables will work: + +.. code-block:: python + :linenos: + + def aview(request): + return "Hello world!" + + def anotherview(request): + return (403, 'text/plain', "Forbidden") + +Pyramid defaults to explicit behavior, because it's the most generally useful, +but provides hooks that allow you to adapt the framework to localized aesthetic +desires. + +.. seealso:: + + See also :ref:`using_iresponse`. + +"Global" response object +~~~~~~~~~~~~~~~~~~~~~~~~ + +"Constructing these response objects in my view callables is such a chore! And +I'm way too lazy to register a response adapter, as per the prior section," you +say. Fine. Be that way: + +.. code-block:: python + :linenos: + + def aview(request): + response = request.response + response.body = 'Hello world!' + response.content_type = 'text/plain' + return response + +.. seealso:: + + See also :ref:`request_response_attr`. + +Automating repetitive configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Does Pyramid's configurator allow you to do something, but you're a little +adventurous and just want it a little less verbose? Or you'd like to offer up +some handy configuration feature to other Pyramid users without requiring that +we change Pyramid? You can extend Pyramid's :term:`Configurator` with your own +directives. For example, let's say you find yourself calling +:meth:`pyramid.config.Configurator.add_view` repetitively. Usually you can +take the boring away by using existing shortcuts, but let's say that this is a +case where there is no such shortcut: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + + config = Configurator() + config.add_route('xhr_route', '/xhr/{id}') + config.add_view('my.package.GET_view', route_name='xhr_route', + xhr=True, permission='view', request_method='GET') + config.add_view('my.package.POST_view', route_name='xhr_route', + xhr=True, permission='view', request_method='POST') + config.add_view('my.package.HEAD_view', route_name='xhr_route', + xhr=True, permission='view', request_method='HEAD') + +Pretty tedious right? You can add a directive to the Pyramid configurator to +automate some of the tedium away: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + + def add_protected_xhr_views(config, module): + module = config.maybe_dotted(module) + for method in ('GET', 'POST', 'HEAD'): + view = getattr(module, 'xhr_%s_view' % method, None) + if view is not None: + config.add_view(view, route_name='xhr_route', xhr=True, + permission='view', request_method=method) + + config = Configurator() + 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: + +.. code-block:: python + :linenos: + + config.add_route('xhr_route', '/xhr/{id}') + config.add_protected_xhr_views('my.package') + +Your previously repetitive configuration lines have now morphed into one line. + +You can share your configuration code with others this way, too, by packaging +it up and calling :meth:`~pyramid.config.Configurator.add_directive` from +within a function called when another user uses the +:meth:`~pyramid.config.Configurator.include` method against your code. + +.. seealso:: + + See also :ref:`add_directive`. + +Programmatic introspection +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you're building a large system that other users may plug code into, it's +useful to be able to get an enumeration of what code they plugged in *at +application runtime*. For example, you might want to show them a set of tabs +at the top of the screen based on an enumeration of views they registered. + +This is possible using Pyramid's :term:`introspector`. + +Here's an example of using Pyramid's introspector from within a view callable: + +.. code-block:: python + :linenos: + + from pyramid.view import view_config + from pyramid.response import Response + + @view_config(route_name='bar') + def show_current_route_pattern(request): + introspector = request.registry.introspector + route_name = request.matched_route.name + route_intr = introspector.get('routes', route_name) + return Response(str(route_intr['pattern'])) + +.. seealso:: + + See also :ref:`using_introspection`. + +Python 3 compatibility +~~~~~~~~~~~~~~~~~~~~~~ + +Pyramid and most of its add-ons are Python 3 compatible. If you develop a +Pyramid application today, you won't need to worry that five years from now +you'll be backwatered because there are language features you'd like to use but +your framework doesn't support newer Python versions. + +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 Travis, +and Jenkins on Python 2.7, Python 3.3, Python 3.4, Python 3.5, PyPy, and PyPy3 +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've noticed we find a lot more of them while working on other +projects that don't have a good testing regime. + +Travis: https://travis-ci.org/Pylons/pyramid +Jenkins: http://jenkins.pylonsproject.org/job/pyramid/ + +Support +~~~~~~~ + +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. We don't tolerate "support +trolls" or other people who seem to get their rocks off by berating fellow +users in our various official 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 :ref:`Pyramid Community Cookbook <cookbook:pyramid-cookbook>`. + +.. index:: + single: Pylons Project What Is The Pylons Project? --------------------------- :app:`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 <http://docs.pylonsproject.org>`_ +contributors. The `Pylons Project website <http://pylonsproject.org>`_ includes details about how :app:`Pyramid` relates to the Pylons Project. .. index:: @@ -96,72 +916,70 @@ includes details about how :app:`Pyramid` relates to the Pylons Project. :app:`Pyramid` and Other Web Frameworks ------------------------------------------ -Until the end of 2010, :app:`Pyramid` was known as :mod:`repoze.bfg`; it was -merged into the Pylons project as :app:`Pyramid` in November of that year. +The first release of Pyramid's predecessor (named :mod:`repoze.bfg`) was made +in July of 2008. At the end of 2010, we changed the name of :mod:`repoze.bfg` +to :app:`Pyramid`. It was merged into the Pylons project as :app:`Pyramid` in +November of that year. -:app:`Pyramid` was inspired by :term:`Zope`, :term:`Pylons` (version -1.0) and :term:`Django`. As a result, :app:`Pyramid` borrows several -concepts and features from each, combining them into a unique web -framework. +:app:`Pyramid` was inspired by :term:`Zope`, :term:`Pylons` (version 1.0), and +:term:`Django`. As a result, :app:`Pyramid` borrows several concepts and +features from each, combining them into a unique web framework. -Many features of :app:`Pyramid` trace their origins back to -:term:`Zope`. Like Zope applications, :app:`Pyramid` applications -can be configured via a set of declarative configuration files. Like -Zope applications, :app:`Pyramid` applications can be easily -extended: if you obey certain constraints, the application you produce -can be reused, modified, re-integrated, or extended by third-party -developers without forking the original application. The concepts of -:term:`traversal` and declarative security in :app:`Pyramid` were -pioneered first in Zope. +Many features of :app:`Pyramid` trace their origins back to :term:`Zope`. Like +Zope applications, :app:`Pyramid` applications can be easily extended. If you +obey certain constraints, the application you produce can be reused, modified, +re-integrated, or extended by third-party developers without forking the +original application. The concepts of :term:`traversal` and declarative +security in :app:`Pyramid` were pioneered first in Zope. The :app:`Pyramid` concept of :term:`URL dispatch` is inspired by the -:term:`Routes` system used by :term:`Pylons` version 1.0. Like Pylons -version 1.0, :app:`Pyramid` is mostly policy-free. It makes no -assertions about which database you should use, and its built-in -templating facilities are included only for convenience. In essence, -it only supplies a mechanism to map URLs to :term:`view` code, along -with a set of conventions for calling those views. You are free to -use third-party components that fit your needs in your applications. - -The concept of :term:`view` is used by :app:`Pyramid` mostly as it would be -by Django. :app:`Pyramid` has a documentation culture more like Django's -than like Zope's. - -Like :term:`Pylons` version 1.0, but unlike :term:`Zope`, a -:app:`Pyramid` application developer may use completely imperative -code to perform common framework configuration tasks such as adding a -view or a route. In Zope, :term:`ZCML` is typically required for -similar purposes. In :term:`Grok`, a Zope-based web framework, -:term:`decorator` objects and class-level declarations are used for -this purpose. :app:`Pyramid` supports :term:`ZCML` and -decorator-based configuration, but does not require either. See -:ref:`configuration_narr` for more information. - -Also unlike :term:`Zope` and unlike other "full-stack" frameworks such -as :term:`Django`, :app:`Pyramid` makes no assumptions about which -persistence mechanisms you should use to build an application. Zope -applications are typically reliant on :term:`ZODB`; :app:`Pyramid` -allows you to build :term:`ZODB` applications, but it has no reliance -on the ZODB software. Likewise, :term:`Django` tends to assume that -you want to store your application's data in a relational database. -:app:`Pyramid` makes no such assumption; it allows you to use a -relational database but doesn't encourage or discourage the decision. - -Other Python web frameworks advertise themselves as members of a class -of web frameworks named `model-view-controller -<http://en.wikipedia.org/wiki/Model–view–controller>`_ frameworks. -Insofar as this term has been claimed to represent a class of web -frameworks, :app:`Pyramid` also generally fits into this class. - -.. sidebar:: You Say :app:`Pyramid` is MVC, But Where's The Controller? - - The :app:`Pyramid` authors believe that the MVC pattern just doesn't - really fit the web very well. In a :app:`Pyramid` application, there is a - resource tree, which represents the site structure, and views, which tend - to present the data stored in the resource tree and a user-defined "domain - model". However, no facility provided *by the framework* actually - necessarily maps to the concept of a "controller" or "model". So if you - had to give it some acronym, I guess you'd say :app:`Pyramid` is actually - an "RV" framework rather than an "MVC" framework. "MVC", however, is - close enough as a general classification moniker for purposes of - comparison with other web frameworks. +:term:`Routes` system used by :term:`Pylons` version 1.0. Like Pylons version +1.0, :app:`Pyramid` is mostly policy-free. It makes no assertions about which +database you should use. Pyramid no longer has built-in templating facilities +as of version 1.5a2, but instead officially supports bindings for templating +languages, including Chameleon, Jinja2, and Mako. In essence, it only supplies +a mechanism to map URLs to :term:`view` code, along with a set of conventions +for calling those views. You are free to use third-party components that fit +your needs in your applications. + +The concept of :term:`view` is used by :app:`Pyramid` mostly as it would be by +Django. :app:`Pyramid` has a documentation culture more like Django's than +like Zope's. + +Like :term:`Pylons` version 1.0, but unlike :term:`Zope`, a :app:`Pyramid` +application developer may use completely imperative code to perform common +framework configuration tasks such as adding a view or a route. In Zope, +:term:`ZCML` is typically required for similar purposes. In :term:`Grok`, a +Zope-based web framework, :term:`decorator` objects and class-level +declarations are used for this purpose. Out of the box, Pyramid supports +imperative and decorator-based configuration. :term:`ZCML` may be used via an +add-on package named ``pyramid_zcml``. + +Also unlike :term:`Zope` and other "full-stack" frameworks such as +:term:`Django`, :app:`Pyramid` makes no assumptions about which persistence +mechanisms you should use to build an application. Zope applications are +typically reliant on :term:`ZODB`. :app:`Pyramid` allows you to build +:term:`ZODB` applications, but it has no reliance on the ZODB software. +Likewise, :term:`Django` tends to assume that you want to store your +application's data in a relational database. :app:`Pyramid` makes no such +assumption, allowing you to use a relational database, and neither encouraging +nor discouraging the decision. + +Other Python web frameworks advertise themselves as members of a class of web +frameworks named `model-view-controller +<http://en.wikipedia.org/wiki/Model–view–controller>`_ frameworks. Insofar as +this term has been claimed to represent a class of web frameworks, +:app:`Pyramid` also generally fits into this class. + +.. sidebar:: You Say :app:`Pyramid` is MVC, but Where's the Controller? + + The :app:`Pyramid` authors believe that the MVC pattern just doesn't really + fit the web very well. In a :app:`Pyramid` application, there is a resource + tree which represents the site structure, and views which tend to present + the data stored in the resource tree and a user-defined "domain model". + However, no facility provided *by the framework* actually necessarily maps + to the concept of a "controller" or "model". So if you had to give it some + acronym, I guess you'd say :app:`Pyramid` is actually an "RV" framework + rather than an "MVC" framework. "MVC", however, is close enough as a + general classification moniker for purposes of comparison with other web + frameworks. |
