diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 3d574f99de..8eadbeecf2 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -246,3 +246,5 @@ Contributors - David Glick, 2015/02/12 - Donald Stufft, 2015/03/15 + +- Karen Dalton, 2015/06/01 diff --git a/docs/api/request.rst b/docs/api/request.rst index b325ad0766..105ffb5a7e 100644 --- a/docs/api/request.rst +++ b/docs/api/request.rst @@ -11,7 +11,7 @@ :exclude-members: add_response_callback, add_finished_callback, route_url, route_path, current_route_url, current_route_path, static_url, static_path, - model_url, resource_url, set_property, + model_url, resource_url, resource_path, set_property, effective_principals, authenticated_userid, unauthenticated_userid, has_permission diff --git a/docs/conventions.rst b/docs/conventions.rst index 21b506623f..0492ab4fd8 100644 --- a/docs/conventions.rst +++ b/docs/conventions.rst @@ -1,19 +1,19 @@ Typographical Conventions ========================= -Literals, filenames and function arguments are presented using the +Literals, filenames, and function arguments are presented using the following style: ``argument1`` -Warnings, which represent limitations and need-to-know information +Warnings which represent limitations and need-to-know information related to a topic or concept are presented in the following style: .. warning:: This is a warning. -Notes, which represent additional information related to a topic or +Notes which represent additional information related to a topic or concept are presented in the following style: .. note:: @@ -105,7 +105,7 @@ It may look unusual, but it has advantages: * It allows one to swap out the higher-level package ``foo`` for something else that provides the similar API. An example would be swapping out - one Database for another (e.g. graduating from SQLite to PostgreSQL). + one Database for another (e.g., graduating from SQLite to PostgreSQL). * Looks more neat in cases where a large number of objects get imported from that package. diff --git a/docs/copyright.rst b/docs/copyright.rst index 9803358271..3beaee7f7a 100644 --- a/docs/copyright.rst +++ b/docs/copyright.rst @@ -39,7 +39,7 @@ 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 as "as-is" basis. The author and 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 @@ -89,14 +89,14 @@ 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 maillist +technical queries to the `Pylons-devel mailing list `_. HTML Version and Source Code ---------------------------- An HTML version of this book is freely available via -http://docs.pylonsproject.org +http://docs.pylonsproject.org/projects/pyramid/en/latest/ The source code for the examples used in this book are available within the :app:`Pyramid` software distribution, always available diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index a37d74c9b5..2d3cd23e9a 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -65,11 +65,11 @@ Openness .. _what_makes_pyramid_unique: -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 +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? @@ -78,13 +78,13 @@ 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 +"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 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 +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 @@ -95,15 +95,15 @@ 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 +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 +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 a la carte without +them in one place, documented appropriately, and useful *à la carte* without necessarily paying for the entire banquet. These are detailed below. Single-file applications @@ -143,14 +143,14 @@ decorators to localize the configuration. For example: return Response('fred') However, unlike some other systems, using decorators for Pyramid -configuration does not make your application difficult to extend, test or +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 +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 +Pyramid decorators are inert instead of eager. You detect and activate them with a :term:`scan`. Example: :ref:`mapping_views_using_a_decorator_section`. @@ -171,24 +171,24 @@ 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. +``/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 +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 +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 +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 @@ -201,16 +201,16 @@ 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 +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 +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: +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 +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`. @@ -224,8 +224,8 @@ 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 - +Examples: +http://docs.pylonsproject.org/en/latest/docs/pyramid.html#pyramid-add-on-documentation Class-based and function-based views ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -233,13 +233,13 @@ 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 +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. +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: @@ -283,10 +283,10 @@ 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 +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 +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 @@ -325,10 +325,9 @@ 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; just make an -assertion instead that the view returns "the right stuff" in the dictionary -it returns. You can write "real" unit tests instead of functionally testing -all of your views. +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:: pair: renderer; explicitly calling @@ -394,7 +393,7 @@ 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 catalog via the use +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. @@ -445,7 +444,7 @@ 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/ +Example: http://blog.curiasolutions.com/pages/the-great-web-framework-shootout.html Exception views ~~~~~~~~~~~~~~~ @@ -469,11 +468,11 @@ 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 +exactly zero "singleton" data structures. Or put another way, Pyramid doesn't require you to construct any "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 +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 @@ -494,7 +493,7 @@ 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 +individual views clean. They won't need much conditional logic, so they'll be easier to test. Example: :ref:`view_configuration_parameters`. @@ -505,10 +504,10 @@ 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 +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 +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. @@ -521,8 +520,8 @@ 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. -Also, Pyramid's transaction management system allows you to synchronize -commits between multiple databases, and allows you to do things like +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 @@ -534,13 +533,14 @@ 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, -and if you accidentally add two that are identical, or Pyramid can't make + +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 +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 +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`. @@ -552,15 +552,15 @@ 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, +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 a URL prefix. It's not a big deal, and requires +``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: @@ -603,8 +603,8 @@ 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 +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 @@ -635,7 +635,7 @@ 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 +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 @@ -826,7 +826,7 @@ within a function called when another user uses the See also :ref:`add_directive`. -Programmatic Introspection +Programmatic introspection ~~~~~~~~~~~~~~~~~~~~~~~~~~ If you're building a large system that other users may plug code into, it's @@ -856,7 +856,7 @@ callable: See also :ref:`using_introspection`. -Python 3 Compatibility +Python 3 compatibility ~~~~~~~~~~~~~~~~~~~~~~ Pyramid and most of its add-ons are Python 3 compatible. If you develop a @@ -871,11 +871,11 @@ 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.6, Python 2.7, Python 3.2 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've noticed we find a lot more of them while working on other projects -that don't have a good testing regime. +Jenkins tool on Python 2.6, Python 2.7, Python 3.2, Python 3.3, Python 3.4, +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. Example: http://jenkins.pylonsproject.org/ @@ -883,15 +883,15 @@ 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 reasonably prompt response. We don't tolerate "support +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/ . +http://groups.google.com/group/pylons-discuss/. Documentation ~~~~~~~~~~~~~ @@ -900,12 +900,12 @@ 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 +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 and the cookbook at -http://docs.pylonsproject.org/projects/pyramid_cookbook/dev/ . +Example: The Pyramid Cookbook at +http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/. .. index:: single: Pylons Project @@ -934,25 +934,26 @@ in July of 2008. At the end of 2010, we changed the name of 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 +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 easily extended: -if you obey certain constraints, the application you produce can be reused, +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. +: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 @@ -967,15 +968,15 @@ 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 unlike other "full-stack" frameworks such +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; it allows you to use a -relational database but doesn't encourage or discourage the decision. +: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 @@ -987,7 +988,7 @@ frameworks, :app:`Pyramid` also generally fits into this class. 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 + 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 diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 5c103405a5..916c6c1f62 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -56,7 +56,7 @@ by using the :meth:`pyramid.config.Configurator.set_session_factory` method. config = Configurator() config.set_session_factory(my_session_factory) -.. warning:: +.. warning:: By default the :func:`~pyramid.session.SignedCookieSessionFactory` implementation is *unencrypted*. You should not use it @@ -112,7 +112,7 @@ Extra attributes: 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 + A boolean. If ``new`` is True, this session is new. Otherwise, it has been constituted from data that was already serialized. Extra methods: @@ -225,7 +225,7 @@ method: request.session.flash('mymessage') The ``flash()`` method appends a message to a flash queue, creating the queue -if necessary. +if necessary. ``flash()`` accepts three arguments: @@ -406,7 +406,7 @@ Checking CSRF Tokens With A View Predicate A convenient way to require a valid CSRF Token for a particular view is to include ``check_csrf=True`` as a view predicate. -See :meth:`pyramid.config.Configurator.add_route`. +See :meth:`pyramid.config.Configurator.add_view`. .. code-block:: python @@ -414,6 +414,12 @@ See :meth:`pyramid.config.Configurator.add_route`. def myview(request): ... +.. note:: + A mismatch of CSRF token is treated like any other predicate miss, and the + predicate system, when it doesn't find a view, raises ``HTTPNotFound`` + instead of ``HTTPBadRequest``, so ``check_csrf=True`` behavior is different + from calling :func:`pyramid.session.check_csrf_token`. + Using the ``session.new_csrf_token`` Method ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index d5203c6bab..fc5ae6dc6e 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -234,6 +234,21 @@ Non-Predicate Arguments def myview(request): ... + All view callables in the decorator chain must return a response object + implementing :class:`pyramid.interfaces.IResponse` or raise an exception: + + .. code-block:: python + + 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 :term:`dotted Python name` which refers to a :term:`view mapper`, or ``None``. By default it is ``None``, which indicates that the diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst index 1b8c82b0a3..0fc3a7ab8a 100644 --- a/docs/quick_tour.rst +++ b/docs/quick_tour.rst @@ -39,12 +39,12 @@ For Windows: Of course Pyramid runs fine on Python 2.6+, as do the examples in this *Quick Tour*. We're just showing Python 3 a little love (Pyramid had -production support in October 2011.) +production support for Python 3 in October 2011). .. note:: Why ``easy_install`` and not ``pip``? Pyramid encourages use of namespace - packages which, until recently, ``pip`` didn't permit. Also, Pyramid has + packages which, until recently, ``pip`` didn't permit. Also Pyramid has some optional C extensions for performance. With ``easy_install``, Windows users can get these extensions without needing a C compiler. @@ -69,8 +69,8 @@ This simple example is easy to run. Save this as ``app.py`` and run it: $ python ./app.py -Next, open `http://localhost:6543/ `_ in a -browser and you will see the ``Hello World!`` message. +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: @@ -96,7 +96,7 @@ one that we will revisit regurlarly in this *Quick Tour*. :ref:`firstapp_chapter`, and :ref:`Single File Tasks tutorial ` -Handling Web Requests and Responses +Handling web requests and responses =================================== Developing for the web means processing web requests. As this is a @@ -104,21 +104,20 @@ 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, scaffolding, -first to embrace Python 3, etc.) For request handling, Pyramid turned -to the well-regarded :term:`WebOb` Python library for request and -response handling. In our example -above, Pyramid hands ``hello_world`` a ``request`` that is -:ref:`based on WebOb `. +development (virtual environments, packaging, scaffolding, one of the first to +embrace Python 3, etc.). Pyramid turned to the well-regarded :term:`WebOb` +Python library for request and response handling. In our example above, +Pyramid hands ``hello_world`` a ``request`` that is :ref:`based on WebOb +`. Let's see some features of requests and responses in action: .. literalinclude:: quick_tour/requests/app.py :pyobject: hello_world -In this Pyramid view, we get the URL being visited from ``request.url``. -Also, if you visited ``http://localhost:6543/?name=alice``, -the name is included in the body of the response:: +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 @@ -142,13 +141,15 @@ So far our examples place everything in one file: - its registration with the configurator -- the route to map it to a URL +- 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``: +the views. + +First, our revised ``app.py``: .. literalinclude:: quick_tour/views/app.py :linenos: @@ -163,8 +164,8 @@ and responses: .. literalinclude:: quick_tour/views/views.py :linenos: -We have 4 views, each leading to the other. If you start at -``http://localhost:6543/``, you get a response with a link to the next +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 ``redirect_view``, which issues a redirect to the final view. @@ -175,7 +176,7 @@ section introduces ``@view_config``. Pyramid's configuration supports the previous example. You can also use :term:`declarative configuration`, in which a Python :term:`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. +configuration, thus usually it is simply a matter of taste. .. seealso:: See also: :ref:`Quick Tutorial Views `, @@ -195,7 +196,7 @@ 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 +- Elsewhere a view is configured to be called for that route name .. note:: @@ -282,12 +283,12 @@ we can use ``name`` as a variable in our template via :ref:`debugging_templates`, and :ref:`available_template_system_bindings` -Templating With ``jinja2`` +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, -modelled after Django's templates. Let's add ``pyramid_jinja2``, +modeled after Django's templates. Let's add ``pyramid_jinja2``, a Pyramid :term:`add-on` which enables Jinja2 as a :term:`renderer` in our Pyramid applications: @@ -324,12 +325,12 @@ renderer. `Jinja2 homepage `_, and :ref:`pyramid_jinja2 Overview ` -Static Assets +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. First, another call to the +Pyramid will serve some static assets. First another call to the :term:`configurator`: .. literalinclude:: quick_tour/static_assets/app.py @@ -337,10 +338,10 @@ Pyramid will serve some static assets. First, another call to the :end-before: End Static 1 This tells our WSGI application to map requests under -``http://localhost:6543/static/`` to files and directories inside a +http://localhost:6543/static/ to files and directories inside a ``static`` directory alongside our Python module. -Next, make a directory ``static`` and place ``app.css`` inside: +Next make a directory named ``static``, and place ``app.css`` inside: .. literalinclude:: quick_tour/static_assets/static/app.css :language: css @@ -394,14 +395,13 @@ into JSON and set the appropriate HTTP headers. :ref:`json_renderer`, and :ref:`adding_and_overriding_renderers` -View Classes +View classes ============ So far our views have been 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 -:ref:`view class ` makes sense: +data, or a REST API that handles multiple operations. Grouping these +together as a :ref:`view class ` makes sense. - Group views @@ -425,14 +425,14 @@ Specifically: - The second view is returned when the form data contains a field with ``form.edit``, such as clicking on - ````. This rule + ````. This rule is specified in the ``@view_config`` for that view. - The third view is returned when clicking on a button such - as ````. + as ````. -Only one route needed, stated in one place atop the view class. Also, -the assignment of the ``name`` is done in the ``__init__``. Our +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, @@ -450,7 +450,7 @@ have much more to offer: :ref:`Quick Tutorial More View Classes `, and :ref:`class_as_view` -Quick Project Startup with Scaffolds +Quick project startup with scaffolds ==================================== So far we have done all of our *Quick Tour* as a single Python file. @@ -501,7 +501,7 @@ Let's look at ``pserve`` and configuration in more depth. :ref:`project_narr`, and :doc:`../narr/scaffolding` -Application Running with ``pserve`` +Application running with ``pserve`` =================================== Prior to scaffolds, our project mixed a number of operational details @@ -530,19 +530,19 @@ take a look at this configuration file. .. seealso:: See also: :ref:`what_is_this_pserve_thing` -Configuration with ``.ini`` Files +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 scaffold has moved this decision, and more, into the +code. Our scaffold has moved this decision and more into the ``development.ini`` file: .. literalinclude:: quick_tour/package/development.ini :language: ini -Let's take a quick high-level look. First, the ``.ini`` file is divided +Let's take a quick high-level look. First the ``.ini`` file is divided into sections: - ``[app:hello_world]`` configures our WSGI app @@ -555,23 +555,21 @@ into sections: We have a few decisions made for us in this configuration: -#. *Choice of web server*. The ``use = egg:pyramid#wsgiref`` tells - ``pserve`` to use the ``wsgiref`` server that is wrapped in the Pyramid - package. +#. *Choice of web server:* ``use = egg:pyramid#wsgiref`` tells ``pserve`` to + use the ``wsgiref`` server that is wrapped in the Pyramid package. -#. *Port number*. ``port = 6543`` tells ``wsgiref`` to listen on port - 6543. +#. *Port number:* ``port = 6543`` tells ``wsgiref`` to listen on port 6543. -#. *WSGI app*. What package has our WSGI application in it? +#. *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. -#. *Easier development by automatic template reloading*. In development - mode, you shouldn't have to restart the server when editing a Jinja2 - template. ``reload_templates = true`` sets this policy, - which might be different in production. +#. *Easier development by automatic template reloading:* In development mode, + you shouldn't have to restart the server when editing a Jinja2 template. + ``reload_templates = true`` sets this policy, which might be different in + production. -Additionally, the ``development.ini`` generated by this scaffold wired +Additionally the ``development.ini`` generated by this scaffold 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. @@ -581,7 +579,7 @@ a log on every request that comes in, as well as traceback information. :doc:`../narr/paste` -Easier Development with ``debugtoolbar`` +Easier development with ``debugtoolbar`` ======================================== As we introduce the basics, we also want to show how to be productive in @@ -592,21 +590,21 @@ reloading and earlier we showed ``--reload`` for application reloading. several tools available in your browser. Adding it to your project illustrates several points about configuration. -First, change your ``setup.py`` to say: +First change your ``setup.py`` to say: .. literalinclude:: quick_tour/package/setup.py :start-after: Start Requires :end-before: End Requires -...and re-run your setup: +...and rerun your setup: .. code-block:: bash $ python ./setup.py develop -The Python package was now installed into our environment. The package -is a Pyramid add-on, which means we need to include its configuration -into our web application. We could do this with imperative +The Python package ``pyramid_debugtoolbar`` is now installed into our +environment. The package is a Pyramid add-on, which means we need to include +its configuration into our web application. We could do this with imperative configuration, as we did above for the ``pyramid_jinja2`` add-on: .. literalinclude:: quick_tour/package/hello_world/__init__.py @@ -635,12 +633,12 @@ configuration file. pyramid_debugtoolbar ` and :ref:`pyramid_debugtoolbar ` -Unit Tests and ``nose`` +Unit tests and ``nose`` ======================= -Yikes! We got this far and we haven't yet discussed tests. Particularly -egregious, as Pyramid has had a deep commitment to full test coverage -since before it was released. +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_jinja2_starter`` scaffold generated a ``tests.py`` module with one unit test in it. To run it, let's install the handy ``nose`` @@ -656,7 +654,7 @@ the ``coverage`` tool which yells at us for code that isn't tested: } ) -We changed ``setup.py`` which means we need to re-run +We changed ``setup.py`` which means we need to rerun ``python ./setup.py develop``. We can now run all our tests: .. code-block:: bash @@ -694,7 +692,7 @@ 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, +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*. @@ -716,7 +714,7 @@ You can now, in your code, log messages: :start-after: Start Logging 2 :end-before: End Logging 2 -This will log ``Some Message`` at a ``debug`` log level, +This will log ``Some Message`` at a ``debug`` log level to the application-configured logger in your ``development.ini``. What controls that? These sections in the configuration file: @@ -727,7 +725,7 @@ controls that? These sections in the configuration file: 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:: +visit http://localhost:6543, your console will now show:: 2013-08-09 10:42:42,968 DEBUG [hello_world.views][MainThread] Some Message @@ -886,8 +884,8 @@ widgets, schemas, and validation. Recent versions of Deform also include a :ref:`retail mode ` for gaining Deform features on custom forms. -Also, the ``deform_bootstrap`` Pyramid add-on restyles the stock Deform -widgets using attractive CSS from Bootstrap and more powerful widgets +Also the ``deform_bootstrap`` Pyramid add-on restyles the stock Deform +widgets using attractive CSS from Twitter Bootstrap and more powerful widgets from Chosen. .. seealso:: See also: diff --git a/docs/quick_tutorial/authentication.rst b/docs/quick_tutorial/authentication.rst index 4b4eb1ba31..a4ab83c452 100644 --- a/docs/quick_tutorial/authentication.rst +++ b/docs/quick_tutorial/authentication.rst @@ -93,7 +93,7 @@ Steps Analysis ======== -Unlike many web frameworks, Pyramid includes a built-in (but optional) +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 diff --git a/docs/quick_tutorial/authentication/tutorial/home.pt b/docs/quick_tutorial/authentication/tutorial/home.pt index 6ecd0081b0..ed911b6739 100644 --- a/docs/quick_tutorial/authentication/tutorial/home.pt +++ b/docs/quick_tutorial/authentication/tutorial/home.pt @@ -1,7 +1,7 @@ - Quick Tour: ${name} + Quick Tutorial: ${name} @@ -15,4 +15,4 @@

Hi ${name}

Visit hello

- \ No newline at end of file + diff --git a/docs/quick_tutorial/authentication/tutorial/login.pt b/docs/quick_tutorial/authentication/tutorial/login.pt index 4451fc4f84..9e5bfe2ad6 100644 --- a/docs/quick_tutorial/authentication/tutorial/login.pt +++ b/docs/quick_tutorial/authentication/tutorial/login.pt @@ -1,7 +1,7 @@ - Quick Tour: ${name} + Quick Tutorial: ${name}

Login

@@ -22,4 +22,4 @@ value="Log In"/> - \ No newline at end of file + diff --git a/docs/quick_tutorial/authorization.rst b/docs/quick_tutorial/authorization.rst index dc159234cd..08df15a287 100644 --- a/docs/quick_tutorial/authorization.rst +++ b/docs/quick_tutorial/authorization.rst @@ -11,7 +11,7 @@ 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 +``editor`` and password of ``editor``). We will allow the other views to continue working without a password. Objectives @@ -101,7 +101,7 @@ by decorating the view with ``@forbidden_view_config``. Extra Credit ============ -#. Perhaps you would like experience of not having enough permissions +#. Perhaps you would like the experience of not having enough permissions (forbidden) to be richer. How could you change this? #. Perhaps we want to store security statements in a database and diff --git a/docs/quick_tutorial/authorization/tutorial/home.pt b/docs/quick_tutorial/authorization/tutorial/home.pt index 6ecd0081b0..ed911b6739 100644 --- a/docs/quick_tutorial/authorization/tutorial/home.pt +++ b/docs/quick_tutorial/authorization/tutorial/home.pt @@ -1,7 +1,7 @@ - Quick Tour: ${name} + Quick Tutorial: ${name} @@ -15,4 +15,4 @@

Hi ${name}

Visit hello

- \ No newline at end of file + diff --git a/docs/quick_tutorial/authorization/tutorial/login.pt b/docs/quick_tutorial/authorization/tutorial/login.pt index 4451fc4f84..9e5bfe2ad6 100644 --- a/docs/quick_tutorial/authorization/tutorial/login.pt +++ b/docs/quick_tutorial/authorization/tutorial/login.pt @@ -1,7 +1,7 @@ - Quick Tour: ${name} + Quick Tutorial: ${name}

Login

@@ -22,4 +22,4 @@ value="Log In"/> - \ No newline at end of file + diff --git a/docs/quick_tutorial/databases.rst b/docs/quick_tutorial/databases.rst index 7c019dbfc7..19dfd066df 100644 --- a/docs/quick_tutorial/databases.rst +++ b/docs/quick_tutorial/databases.rst @@ -53,8 +53,8 @@ Steps .. note:: - We aren't yet doing ``python3.3 setup.py develop`` as we - are changing it later. + We aren't yet doing ``$VENV/bin/python setup.py develop`` as we + will change it later. #. Our configuration file at ``databases/development.ini`` wires together some new pieces: @@ -72,6 +72,7 @@ Steps to initialize the database: .. literalinclude:: databases/tutorial/initialize_db.py + :linenos: #. Since ``setup.py`` changed, we now run it: @@ -89,21 +90,34 @@ Steps .. code-block:: bash $ $VENV/bin/initialize_tutorial_db development.ini - 2013-09-06 15:54:08,050 INFO [sqlalchemy.engine.base.Engine][MainThread] PRAGMA table_info("wikipages") - 2013-09-06 15:54:08,050 INFO [sqlalchemy.engine.base.Engine][MainThread] () - 2013-09-06 15:54:08,051 INFO [sqlalchemy.engine.base.Engine][MainThread] + 2015-06-01 11:22:52,650 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 + 2015-06-01 11:22:52,650 INFO [sqlalchemy.engine.base.Engine][MainThread] () + 2015-06-01 11:22:52,651 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 + 2015-06-01 11:22:52,651 INFO [sqlalchemy.engine.base.Engine][MainThread] () + 2015-06-01 11:22:52,652 INFO [sqlalchemy.engine.base.Engine][MainThread] PRAGMA table_info("wikipages") + 2015-06-01 11:22:52,652 INFO [sqlalchemy.engine.base.Engine][MainThread] () + 2015-06-01 11:22:52,653 INFO [sqlalchemy.engine.base.Engine][MainThread] CREATE TABLE wikipages ( - uid INTEGER NOT NULL, - title TEXT, - body TEXT, - PRIMARY KEY (uid), - UNIQUE (title) + uid INTEGER NOT NULL, + title TEXT, + body TEXT, + PRIMARY KEY (uid), + UNIQUE (title) ) + + 2015-06-01 11:22:52,653 INFO [sqlalchemy.engine.base.Engine][MainThread] () + 2015-06-01 11:22:52,655 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT + 2015-06-01 11:22:52,658 INFO [sqlalchemy.engine.base.Engine][MainThread] BEGIN (implicit) + 2015-06-01 11:22:52,659 INFO [sqlalchemy.engine.base.Engine][MainThread] INSERT INTO wikipages (title, body) VALUES (?, ?) + 2015-06-01 11:22:52,659 INFO [sqlalchemy.engine.base.Engine][MainThread] ('Root', '

Root

') + 2015-06-01 11:22:52,659 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT + #. With our data now driven by SQLAlchemy queries, we need to update our ``databases/tutorial/views.py``: .. literalinclude:: databases/tutorial/views.py + :linenos: #. Our tests in ``databases/tutorial/tests.py`` changed to include SQLAlchemy bootstrapping: @@ -138,8 +152,8 @@ Let's start with the dependencies. We made the decision to use ``pyramid_tm`` and ``zope.sqlalchemy``. Why? Pyramid has a strong orientation towards support for ``transactions``. -Specifically, you can install a transaction manager into your app -application, either as middleware or a Pyramid "tween". Then, +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. @@ -149,7 +163,7 @@ 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`` configuration file. That installs it. We then need -a package that makes SQLAlchemy and thus the RDBMS transaction manager +a package that makes SQLAlchemy, and thus the RDBMS transaction manager, integrate with the Pyramid transaction manager. That's what ``zope.sqlalchemy`` does. @@ -167,8 +181,8 @@ 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.) +transaction, as we aren't inside a web request where this is done +automatically. The ``models.py`` does a little bit extra work to hook up SQLAlchemy into the Pyramid transaction manager. It then declares the model for a diff --git a/docs/quick_tutorial/databases/development.ini b/docs/quick_tutorial/databases/development.ini index 04c249a62d..5da87d602f 100644 --- a/docs/quick_tutorial/databases/development.ini +++ b/docs/quick_tutorial/databases/development.ini @@ -11,3 +11,39 @@ sqlalchemy.url = sqlite:///%(here)s/sqltutorial.sqlite use = egg:pyramid#wsgiref host = 0.0.0.0 port = 6543 + +# Begin logging configuration + +[loggers] +keys = root, tutorial, sqlalchemy.engine.base.Engine + +[logger_tutorial] +level = DEBUG +handlers = +qualname = tutorial + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[logger_sqlalchemy.engine.base.Engine] +level = INFO +handlers = +qualname = sqlalchemy.engine.base.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 diff --git a/docs/quick_tutorial/databases/tutorial/tests.py b/docs/quick_tutorial/databases/tutorial/tests.py index e18e70c8c9..11e747d152 100644 --- a/docs/quick_tutorial/databases/tutorial/tests.py +++ b/docs/quick_tutorial/databases/tutorial/tests.py @@ -40,16 +40,14 @@ def test_wiki_view(self): class WikiFunctionalTests(unittest.TestCase): def setUp(self): - self.session = _initTestingDB() - self.config = testing.setUp() from pyramid.paster import get_app app = get_app('development.ini') from webtest import TestApp self.testapp = TestApp(app) def tearDown(self): - self.session.remove() - testing.tearDown() + from .models import DBSession + DBSession.remove() def test_it(self): res = self.testapp.get('/', status=200) diff --git a/docs/quick_tutorial/databases/tutorial/wikipage_addedit.pt b/docs/quick_tutorial/databases/tutorial/wikipage_addedit.pt index d1fea0d7f9..01955ef72f 100644 --- a/docs/quick_tutorial/databases/tutorial/wikipage_addedit.pt +++ b/docs/quick_tutorial/databases/tutorial/wikipage_addedit.pt @@ -4,10 +4,12 @@ WikiPage: Add/Edit + href="${request.static_url(reqt)}"> + - diff --git a/docs/quick_tutorial/forms.rst b/docs/quick_tutorial/forms.rst index b08167edc0..f81b88fc24 100644 --- a/docs/quick_tutorial/forms.rst +++ b/docs/quick_tutorial/forms.rst @@ -12,13 +12,13 @@ Background Modern web applications deal extensively with forms. Developers, though, have a wide range of philosophies 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 +one particular form library. Instead there are a variety of form libraries that are easy to use in Pyramid. :ref:`Deform ` is one such library. In this step, we introduce Deform for our -forms and validation. This also gives us the -:ref:`Colander ` for schemas and validation. +forms and validation. This also gives us :ref:`Colander ` +for schemas and validation. Deform is getting a facelift, with styling from Twitter Bootstrap and advanced widgets from popular JavaScript projects. The work began in diff --git a/docs/quick_tutorial/forms/tutorial/wikipage_addedit.pt b/docs/quick_tutorial/forms/tutorial/wikipage_addedit.pt index 3292dfd908..547465018b 100644 --- a/docs/quick_tutorial/forms/tutorial/wikipage_addedit.pt +++ b/docs/quick_tutorial/forms/tutorial/wikipage_addedit.pt @@ -6,6 +6,8 @@ + diff --git a/docs/quick_tutorial/functional_testing.rst b/docs/quick_tutorial/functional_testing.rst index 09b05b0bc2..6f1544e792 100644 --- a/docs/quick_tutorial/functional_testing.rst +++ b/docs/quick_tutorial/functional_testing.rst @@ -10,7 +10,7 @@ Background ========== Unit tests are a common and popular approach to test-driven development -(TDD.) In web applications, though, the templating and entire apparatus +(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. diff --git a/docs/quick_tutorial/jinja2.rst b/docs/quick_tutorial/jinja2.rst index 613542349c..2121803f97 100644 --- a/docs/quick_tutorial/jinja2.rst +++ b/docs/quick_tutorial/jinja2.rst @@ -6,7 +6,7 @@ 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 modelled after Django's templates. Let's add +used in Flask and modeled after Django's templates. Let's add ``pyramid_jinja2``, a Pyramid :term:`add-on` which enables Jinja2 as a :term:`renderer` in our Pyramid applications. diff --git a/docs/quick_tutorial/jinja2/tutorial/home.jinja2 b/docs/quick_tutorial/jinja2/tutorial/home.jinja2 index 9753231693..20d33b7333 100644 --- a/docs/quick_tutorial/jinja2/tutorial/home.jinja2 +++ b/docs/quick_tutorial/jinja2/tutorial/home.jinja2 @@ -1,9 +1,9 @@ - Quick Tour: {{ name }} + Quick Tutorial: {{ name }}

Hi {{ name }}

- \ No newline at end of file + diff --git a/docs/quick_tutorial/json/tutorial/home.pt b/docs/quick_tutorial/json/tutorial/home.pt index a0cc08e7ae..fd4ef8764d 100644 --- a/docs/quick_tutorial/json/tutorial/home.pt +++ b/docs/quick_tutorial/json/tutorial/home.pt @@ -1,9 +1,9 @@ - Quick Tour: ${name} + Quick Tutorial: ${name}

Hi ${name}

- \ No newline at end of file + diff --git a/docs/quick_tutorial/logging.rst b/docs/quick_tutorial/logging.rst index 82cfbe3c3e..5d29cd1961 100644 --- a/docs/quick_tutorial/logging.rst +++ b/docs/quick_tutorial/logging.rst @@ -16,9 +16,9 @@ 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 -scaffold generated, in your ``development.ini``, has a number of lines that +scaffold generated in your ``development.ini`` 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.) +messages sent by Pyramid, for example, when a new request comes in. Objectives ========== diff --git a/docs/quick_tutorial/logging/tutorial/home.pt b/docs/quick_tutorial/logging/tutorial/home.pt index a0cc08e7ae..fd4ef8764d 100644 --- a/docs/quick_tutorial/logging/tutorial/home.pt +++ b/docs/quick_tutorial/logging/tutorial/home.pt @@ -1,9 +1,9 @@ - Quick Tour: ${name} + Quick Tutorial: ${name}

Hi ${name}

- \ No newline at end of file + diff --git a/docs/quick_tutorial/more_view_classes.rst b/docs/quick_tutorial/more_view_classes.rst index 9cc4cc5202..c06fb0f15c 100644 --- a/docs/quick_tutorial/more_view_classes.rst +++ b/docs/quick_tutorial/more_view_classes.rst @@ -95,6 +95,23 @@ Steps .. literalinclude:: more_view_classes/tutorial/delete.pt :language: html +#. Our tests in ``more_view_classes/tutorial/tests.py`` fail, so let's modify + them: + + .. literalinclude:: more_view_classes/tutorial/tests.py + :linenos: + +#. Now run the tests: + + .. code-block:: bash + + $ $VENV/bin/nosetests tutorial + . + ---------------------------------------------------------------------- + Ran 2 tests in 0.248s + + OK + #. Run your Pyramid application with: .. code-block:: bash @@ -125,7 +142,7 @@ Specifically: - The fourth view is returned when clicking on a button such as ````. -In this step we show using the following information as criteria to +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.) diff --git a/docs/quick_tutorial/more_view_classes/tutorial/delete.pt b/docs/quick_tutorial/more_view_classes/tutorial/delete.pt index 67cc8bf098..7bd4d3b0d2 100644 --- a/docs/quick_tutorial/more_view_classes/tutorial/delete.pt +++ b/docs/quick_tutorial/more_view_classes/tutorial/delete.pt @@ -1,9 +1,9 @@ - Quick Tour: ${page_title} + Quick Tutorial: ${page_title}

${view.view_name} - ${page_title}

- \ No newline at end of file + diff --git a/docs/quick_tutorial/more_view_classes/tutorial/edit.pt b/docs/quick_tutorial/more_view_classes/tutorial/edit.pt index 1bd2040653..523a4ce5de 100644 --- a/docs/quick_tutorial/more_view_classes/tutorial/edit.pt +++ b/docs/quick_tutorial/more_view_classes/tutorial/edit.pt @@ -1,10 +1,10 @@ - Quick Tour: ${view.view_name} - ${page_title} + Quick Tutorial: ${view.view_name} - ${page_title}

${view.view_name} - ${page_title}

You submitted ${new_name}

- \ No newline at end of file + diff --git a/docs/quick_tutorial/more_view_classes/tutorial/hello.pt b/docs/quick_tutorial/more_view_classes/tutorial/hello.pt index 8a39aed09d..40b00bfe46 100644 --- a/docs/quick_tutorial/more_view_classes/tutorial/hello.pt +++ b/docs/quick_tutorial/more_view_classes/tutorial/hello.pt @@ -1,7 +1,7 @@ - Quick Tour: ${view.view_name} - ${page_title} + Quick Tutorial: ${view.view_name} - ${page_title}

${view.view_name} - ${page_title}

@@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/docs/quick_tutorial/more_view_classes/tutorial/home.pt b/docs/quick_tutorial/more_view_classes/tutorial/home.pt index fa90167051..fa0436f7e7 100644 --- a/docs/quick_tutorial/more_view_classes/tutorial/home.pt +++ b/docs/quick_tutorial/more_view_classes/tutorial/home.pt @@ -1,7 +1,7 @@ - Quick Tour: ${view.view_name} - ${page_title} + Quick Tutorial: ${view.view_name} - ${page_title}

${view.view_name} - ${page_title}

@@ -9,4 +9,4 @@

Go to the form.

- \ No newline at end of file + diff --git a/docs/quick_tutorial/request_response.rst b/docs/quick_tutorial/request_response.rst index 504803804e..4f8de02213 100644 --- a/docs/quick_tutorial/request_response.rst +++ b/docs/quick_tutorial/request_response.rst @@ -46,14 +46,17 @@ Steps #. Simplify the routes in ``request_response/tutorial/__init__.py``: .. literalinclude:: request_response/tutorial/__init__.py + :linenos: #. We only need one view in ``request_response/tutorial/views.py``: .. literalinclude:: request_response/tutorial/views.py + :linenos: #. Update the tests in ``request_response/tutorial/tests.py``: .. literalinclude:: request_response/tutorial/tests.py + :linenos: #. Now run the tests: diff --git a/docs/quick_tutorial/routing.rst b/docs/quick_tutorial/routing.rst index 54dff5c392..1b79a58898 100644 --- a/docs/quick_tutorial/routing.rst +++ b/docs/quick_tutorial/routing.rst @@ -14,7 +14,7 @@ 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 +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 diff --git a/docs/quick_tutorial/routing/tutorial/home.pt b/docs/quick_tutorial/routing/tutorial/home.pt index f2b9910599..b68e963387 100644 --- a/docs/quick_tutorial/routing/tutorial/home.pt +++ b/docs/quick_tutorial/routing/tutorial/home.pt @@ -1,10 +1,10 @@ - Quick Tour: ${name} + Quick Tutorial: ${name}

${name}

First: ${first}, Last: ${last}

- \ No newline at end of file + diff --git a/docs/quick_tutorial/sessions.rst b/docs/quick_tutorial/sessions.rst index b4887beb89..f97405500d 100644 --- a/docs/quick_tutorial/sessions.rst +++ b/docs/quick_tutorial/sessions.rst @@ -89,7 +89,7 @@ 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 requests. +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 removed when they finally get displayed. diff --git a/docs/quick_tutorial/sessions/tutorial/home.pt b/docs/quick_tutorial/sessions/tutorial/home.pt index 0b27ba1d8d..50342e52ff 100644 --- a/docs/quick_tutorial/sessions/tutorial/home.pt +++ b/docs/quick_tutorial/sessions/tutorial/home.pt @@ -1,10 +1,10 @@ - Quick Tour: ${name} + Quick Tutorial: ${name}

Hi ${name}

Count: ${view.counter}

- \ No newline at end of file + diff --git a/docs/quick_tutorial/static_assets/tutorial/home.pt b/docs/quick_tutorial/static_assets/tutorial/home.pt index 5d347f0570..57867a1ff5 100644 --- a/docs/quick_tutorial/static_assets/tutorial/home.pt +++ b/docs/quick_tutorial/static_assets/tutorial/home.pt @@ -1,11 +1,11 @@ - Quick Tour: ${name} + Quick Tutorial: ${name}

Hi ${name}

- \ No newline at end of file + diff --git a/docs/quick_tutorial/templating.rst b/docs/quick_tutorial/templating.rst index d73067f484..cf56d2a969 100644 --- a/docs/quick_tutorial/templating.rst +++ b/docs/quick_tutorial/templating.rst @@ -112,7 +112,7 @@ Analysis Ahh, that looks better. We have a view that is focused on Python code. Our ``@view_config`` decorator specifies a :term:`renderer` that points -our template file. Our view then simply returns data which is then +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. diff --git a/docs/quick_tutorial/templating/tutorial/home.pt b/docs/quick_tutorial/templating/tutorial/home.pt index a0cc08e7ae..fd4ef8764d 100644 --- a/docs/quick_tutorial/templating/tutorial/home.pt +++ b/docs/quick_tutorial/templating/tutorial/home.pt @@ -1,9 +1,9 @@ - Quick Tour: ${name} + Quick Tutorial: ${name}

Hi ${name}

- \ No newline at end of file + diff --git a/docs/quick_tutorial/unit_testing.rst b/docs/quick_tutorial/unit_testing.rst index f8a33b39d0..4cb7ef7148 100644 --- a/docs/quick_tutorial/unit_testing.rst +++ b/docs/quick_tutorial/unit_testing.rst @@ -24,7 +24,7 @@ and functionality. The Pyramid developers use ``nose``, which we'll thus 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, +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. diff --git a/docs/quick_tutorial/view_classes.rst b/docs/quick_tutorial/view_classes.rst index 58ab43e407..50a7ee0af3 100644 --- a/docs/quick_tutorial/view_classes.rst +++ b/docs/quick_tutorial/view_classes.rst @@ -51,7 +51,7 @@ Steps :linenos: #. Our unit tests in ``view_classes/tutorial/tests.py`` don't run, - so let's modify the to import the view class and make an instance + so let's modify them to import the view class and make an instance before getting a response: .. literalinclude:: view_classes/tutorial/tests.py @@ -88,7 +88,7 @@ view class, then updated the tests. In our ``TutorialViews`` view class you can see that our two view classes are logically grouped together as methods on a common class. Since the two views shared the same template, we could move that to a -``@view_defaults`` decorator on at the class level. +``@view_defaults`` decorator at the class level. 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 diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index 6c98b6f3ad..b0a8c155d3 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -1,19 +1,20 @@ +.. _wiki_adding_authorization: + ==================== -Adding Authorization +Adding authorization ==================== :app:`Pyramid` provides facilities for :term:`authentication` and -:term:`authorization`. We'll 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'll change that -to allow only people who are members of a *group* named ``group:editors`` -to add and edit wiki pages but we'll continue allowing -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 a permission, instead of -a default "403 Forbidden" page. +::term:`authorization`. We'll 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'll change that to +:allow only people who are members of a *group* named ``group:editors`` to add +:and edit wiki pages but we'll continue allowing 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: @@ -28,12 +29,13 @@ Then we will add the login and logout feature: * 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``). +* 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 +Access control -------------- Add users and groups @@ -49,11 +51,9 @@ following content: The ``groupfinder`` function accepts a userid and a request and returns one of these values: -- If the userid exists in the system, it will return a - sequence of group identifiers (or an empty sequence if the user - isn't a member of any groups). -- If the userid *does not* exist in the system, it will - return ``None``. +- If the userid exists in the system, it will return a sequence of group + identifiers (or an empty sequence if the user isn't a member of any groups). +- If the userid *does not* exist in the system, it will return ``None``. For example, ``groupfinder('editor', request )`` returns ``['group:editor']``, ``groupfinder('viewer', request)`` returns ``[]``, and ``groupfinder('admin', @@ -61,9 +61,8 @@ request)`` returns ``None``. We will use ``groupfinder()`` as an :term:`authentication policy` "callback" that will provide the :term:`principal` or principals for a user. -In a production system, user and group -data will most often come from a database, but here we use "dummy" -data to represent user and groups sources. +In a production system, user and group data will most often come from a +database, but here we use "dummy" data to represent user and groups sources. Add an ACL ~~~~~~~~~~ @@ -81,44 +80,42 @@ Add the following lines to the ``Wiki`` class: .. literalinclude:: src/authorization/tutorial/models.py :lines: 9-13 :linenos: + :lineno-start: 9 :emphasize-lines: 4-5 :language: python -We import :data:`~pyramid.security.Allow`, an action that -means that permission is allowed, and -:data:`~pyramid.security.Everyone`, a special :term:`principal` -that is associated to all requests. Both are used in the +We import :data:`~pyramid.security.Allow`, an action that means that +permission is allowed, and :data:`~pyramid.security.Everyone`, a special +:term:`principal` that is associated to all requests. Both are used in the :term:`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 :term:`ACL` with two -:term:`ACE` entries: the first entry allows any user the `view` -permission, and the second entry allows the ``group:editors`` -principal the `edit` permission. +The ACL is a list that needs to be named `__acl__` and be an attribute of a +class. We define an :term:`ACL` with two :term:`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 :term:`resource` -constructor for the :term:`root` resource, which is -a ``Wiki`` instance. The ACL is -provided to each view in the :term:`context` of the request, as -the ``context`` attribute. +The ``Wiki`` class that contains the ACL is the :term:`resource` constructor +for the :term:`root` resource, which is a ``Wiki`` instance. The ACL is +provided to each view in the :term:`context` of the request as the ``context`` +attribute. It's only happenstance that we're assigning 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 :app:`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 -:ref:`assigning_acls` for more information about what an -:term:`ACL` represents. +simple, so this feature is not demonstrated. See :ref:`assigning_acls` for +more information about what an :term:`ACL` represents. -Add Authentication and Authorization Policies +Add authentication and authorization policies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Open ``tutorial/__init__.py`` and -add these import statements: +Open ``tutorial/tutorial/__init__.py`` and add the highlighted import +statements: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 4-5,8 + :lines: 1-8 :linenos: + :emphasize-lines: 4-5,8 :language: python Now add those policies to the configuration: @@ -126,15 +123,16 @@ Now add those policies to the configuration: .. literalinclude:: src/authorization/tutorial/__init__.py :lines: 18-23 :linenos: + :lineno-start: 18 :emphasize-lines: 1-3,5-6 :language: python -(Only the highlighted lines need to be added.) +Only the highlighted lines need to be added. -We are enabling an ``AuthTktAuthenticationPolicy``, it is based in an -auth ticket that may be included in the request, and an -``ACLAuthorizationPolicy`` that uses an ACL to determine the allow or deny -outcome for a view. +We are enabling an ``AuthTktAuthenticationPolicy``, which is based in an auth +ticket that may be included in the request. We are also enabling an +``ACLAuthorizationPolicy``, which uses an ACL to determine the *allow* or +*deny* outcome for a view. Note that the :class:`pyramid.authentication.AuthTktAuthenticationPolicy` constructor accepts two arguments: ``secret`` and ``callback``. ``secret`` is @@ -144,235 +142,231 @@ machinery represented by this policy: it is required. The ``callback`` is the Add permission declarations ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Open ``tutorial/tutorial/views.py``. Add a ``permission='edit'`` parameter -to the ``@view_config`` decorator for ``add_page()`` and -``edit_page()``, for example: +Open ``tutorial/tutorial/views.py`` and add a ``permission='edit'`` parameter +to the ``@view_config`` decorators for ``add_page()`` and ``edit_page()``: -.. code-block:: python - :linenos: - :emphasize-lines: 3 +.. literalinclude:: src/authorization/tutorial/views.py + :lines: 50-52 + :emphasize-lines: 2-3 + :language: python - @view_config(name='add_page', context='.models.Wiki', - renderer='templates/edit.pt', - permission='edit') +.. literalinclude:: src/authorization/tutorial/views.py + :lines: 70-72 + :emphasize-lines: 2-3 + :language: python -(Only the highlighted line, along with its preceding comma, -needs to be added.) +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. +The result is that only users who possess the ``edit`` permission at the time +of the request may invoke those two views. -Add a ``permission='view'`` parameter to the ``@view_config`` -decorator for ``view_wiki()`` and ``view_page()``, like this: +Add a ``permission='view'`` parameter to the ``@view_config`` decorator for +``view_wiki()`` and ``view_page()`` as follows: -.. code-block:: python - :linenos: - :emphasize-lines: 2 +.. literalinclude:: src/authorization/tutorial/views.py + :lines: 23-24 + :emphasize-lines: 1-2 + :language: python - @view_config(context='.models.Page', renderer='templates/view.pt', - permission='view') +.. literalinclude:: src/authorization/tutorial/views.py + :lines: 28-29 + :emphasize-lines: 1-2 + :language: python -(Only the highlighted line, along with its preceding comma, -needs to be added.) +Only the highlighted lines, along with their preceding commas, need to be +edited and added. This allows anyone to invoke these two views. -We are done with the changes needed to control access. The -changes that follow will add the login and logout feature. +We are done with the changes needed to control access. The changes that +follow will add the login and logout feature. -Login, Logout +Login, logout ------------- -Add Login and Logout Views +Add login and logout views ~~~~~~~~~~~~~~~~~~~~~~~~~~ -We'll add a ``login`` view which renders a login form and processes -the post from the login form, checking credentials. +We'll add a ``login`` view which renders a login form and processes the post +from the login form, checking credentials. -We'll 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. +We'll 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 the following import statements to the -head of ``tutorial/tutorial/views.py``: +Add the following import statements to the head of +``tutorial/tutorial/views.py``: .. literalinclude:: src/authorization/tutorial/views.py :lines: 6-17 - :linenos: - :emphasize-lines: 3,6-11 + :emphasize-lines: 1-12 :language: python -(Only the highlighted lines, with other necessary modifications, -need to be added.) +All the highlighted lines need to be added or edited. -:meth:`~pyramid.view.forbidden_view_config` will be used -to customize the default 403 Forbidden page. -:meth:`~pyramid.security.remember` and -:meth:`~pyramid.security.forget` help to create and -expire an auth ticket cookie. +:meth:`~pyramid.view.forbidden_view_config` will be used to customize the +default 403 Forbidden page. :meth:`~pyramid.security.remember` and +:meth:`~pyramid.security.forget` help to create and expire an auth ticket +cookie. -Now add the ``login`` and ``logout`` views: +Now add the ``login`` and ``logout`` views at the end of the file: .. literalinclude:: src/authorization/tutorial/views.py - :lines: 82-120 + :lines: 82-116 :linenos: + :lineno-start: 82 :language: python ``login()`` has two decorators: -- a ``@view_config`` decorator which associates it with the - ``login`` route and makes it visible when we visit ``/login``, -- a ``@forbidden_view_config`` decorator which turns it into - a :term:`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, they will be shown the - login form before being allowed to continue. +- a ``@view_config`` decorator which associates it with the ``login`` route + and makes it visible when we visit ``/login``, +- a ``@forbidden_view_config`` decorator which turns it into a + :term:`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, they will be + shown the login form before being allowed to continue. -The order of these two :term:`view configuration` decorators -is unimportant. +The order of these two :term:`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``. +``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/tutorial/templates/login.pt`` with the following -content: +Create ``tutorial/tutorial/templates/login.pt`` with the following content: .. literalinclude:: src/authorization/tutorial/templates/login.pt - :language: xml + :language: html -The above template is referred in the login view that we just added -in ``views.py``. +The above template is referenced in the login view that we just added in +``views.py``. -Return a logged_in flag to the renderer -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Return a ``logged_in`` flag to the renderer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Add a ``logged_in`` parameter to the return value of -``view_page()``, ``edit_page()`` and ``add_page()``, -like this: +Open ``tutorial/tutorial/views.py`` again. Add a ``logged_in`` parameter to +the return value of ``view_page()``, ``edit_page()``, and ``add_page()`` as +follows: -.. code-block:: python - :linenos: - :emphasize-lines: 4 +.. literalinclude:: src/authorization/tutorial/views.py + :lines: 47-48 + :emphasize-lines: 1-2 + :language: python - return dict(page = page, - content = content, - edit_url = edit_url, - logged_in = request.authenticated_userid) +.. literalinclude:: src/authorization/tutorial/views.py + :lines: 67-68 + :emphasize-lines: 1-2 + :language: python -(Only the highlighted line and a trailing comma on the preceding -line need to be added.) +.. literalinclude:: src/authorization/tutorial/views.py + :lines: 75-77 + :emphasize-lines: 2-3 + :language: python + +Only the highlighted lines need to be added or edited. The :meth:`pyramid.request.Request.authenticated_userid` will be ``None`` if -the user is not authenticated, or a user id if the user is authenticated. +the user is not authenticated, or a userid if the user is authenticated. Add a "Logout" link when logged in ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Open ``tutorial/tutorial/templates/edit.pt`` and -``tutorial/tutorial/templates/view.pt`` and add this within the -`` - -
-
-
- Editing Page Name Goes - Here
- You can return to the - FrontPage.
+
+
- -
-
-
-
-
- +
+
+ +
+ +
+
- - -
-
-
- Editing Page Name - Goes Here
- You can return to the - FrontPage.
-
-
-
-
-
- +
+
+ +
+ +
+
- - -
-
-
- Editing Page Name - Goes Here
- You can return to the - FrontPage.
-
-
-
-
-
- +
+
+ +
+ +
+
- - -
-
-
- Editing Page Name Goes - Here
- You can return to the - FrontPage.
+
+
- -
-
-
-
-
-