From 335200ed8f2b3fbd37fe8816749a9c2303082a53 Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 2 Jun 2016 17:16:29 -0700 Subject: be assertive in claims --- docs/narr/introduction.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index de6ac408b..a387594d2 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -9,9 +9,8 @@ :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 Python developer to -create web applications. +:app:`Pyramid` is a Python web application *framework*. It is designed to make +creating web applications easier. It is open source. .. sidebar:: Frameworks vs. Libraries @@ -29,7 +28,7 @@ create web applications. framework provides a set of facilities that fits your application requirements. -Pyramid attempts to follow these design and engineering principles: +Pyramid follows these design and engineering principles: Simplicity :app:`Pyramid` takes a *"pay only for what you eat"* approach. You can get -- cgit v1.2.3 From 66b71518d01b2005c8070e58e7a7f37f2391fb0e Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 14:00:38 -0700 Subject: clarify the framework sidebar --- docs/narr/introduction.rst | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index a387594d2..e6658d953 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -12,21 +12,20 @@ :app:`Pyramid` is a Python web application *framework*. It is designed to make creating web applications easier. It is open source. -.. 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. +.. sidebar:: What Is a Framework? + + A *framework* provides capabilities that developers can enhance or extend. A + web application framework provides many of the common needs of building web + applications allowing developers to concentrate only on the parts that are + specific to their application. + + Every framework makes choices about how a particular problem should be + solved. When developers choose to use a framework, they cede control over + the portions of their application that are provided by the framework. It is + possible to write a complete web application without any framework, by using + Python libraries. In practice, however, it is often more practical to use a + framework, so long as your chosen framework fits the requirements of your + application. Pyramid follows these design and engineering principles: -- cgit v1.2.3 From 9f2b004cd31fb4d949fb4e18f62bec7b82af58e6 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 15:06:42 -0700 Subject: simplify the statement of principles --- docs/narr/introduction.rst | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index e6658d953..ac87f9ed4 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -30,31 +30,26 @@ creating web applications easier. It is open source. Pyramid follows these design and engineering principles: Simplicity - :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. + :app:`Pyramid` is designed to be easy to use. You can get started even if you + don't understand it all. And when you're ready to do more, :app:`Pyramid` + will be there for you. Minimalism - :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. + Out of the box, :app:`Pyramid` provides only the core tools needed for nearly + all web applications: mapping URLs to code, security, and serving static + assets (files like JavaScript and CSS). Additional tools provide templating, + database integration and more. But with :app:`Pyramid` you can *"pay only for + what you eat"*. Documentation - 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. + :app:`Pyramid` is committed to comprehensive and up-to-date documentation. Speed - :app:`Pyramid` is designed to provide noticeably fast execution for common - tasks such as templating and simple response generation. + :app:`Pyramid` is designed to be noticeably fast. 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". + :app:`Pyramid` is developed conservatively and tested exhaustively. Our motto + is: "If it ain't tested, it's broke". Openness As with Python, the Pyramid software is distributed under a `permissive open -- cgit v1.2.3 From f920852b93dd4d81dfe1dca12b72ac92140bf37c Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 15:42:22 -0700 Subject: rewrite what makes pyramid unique --- docs/narr/introduction.rst | 54 +++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index ac87f9ed4..6e025f5f7 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -60,42 +60,28 @@ Openness 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. +There are many tools available for web development. What would make someone +want to use Pyramid instead? What makes Pyramid unique? + +With Pyramid you can write very small applications without needing to know a +lot. And by learning a bit more, you can write very large applications too. Pyramid will allow you to become productive quickly, and will grow with you. It won't hold you back when your application is small, and it won't get in your -way when your application becomes large. "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. +way when your application becomes large. Other application frameworks seem to +fall into two non-overlapping categories: those that support "small apps" and +those designed for "big apps". + +We don't believe you should have to make this choice. You can't really know how +large your application will become. You certainly shouldn't have to rewrite a +small application in another framework when it gets "too big". A well-designed +framework should be able to be good at both. Pyramid is that kind of framework. + +Pyramid provides a set of features that are unique among Python web frameworks. +Others may provide some, but only Pyramid provides them all, in one place, +fully documented, and useful *à la carte* without needing to pay for the whole +banquet. + +With Pyramid you get: Single-file applications ~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From 02c5ba3a2cc09948ff49fd9f7c1bcba65050893a Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 15:59:53 -0700 Subject: make title an action --- docs/narr/introduction.rst | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 6e025f5f7..bbe7df537 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -81,19 +81,15 @@ Others may provide some, but only Pyramid provides them all, in one place, fully documented, and useful *à la carte* without needing to pay for the whole banquet. -With Pyramid you get: -Single-file applications -~~~~~~~~~~~~~~~~~~~~~~~~ +Build 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. +You can write a Pyramid application that lives entirely in one Python file. +Such an application is easy to understand since everything is in one place. It +is easy to deploy because you don't need to know much about Python packaging. +Pyramid allows you to do almost everything that so-called *microframeworks* can +in very similar ways. .. literalinclude:: helloworld.py -- cgit v1.2.3 From 6fcca68c34057200e7d7bebbdae678e4c0216dd6 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 16:18:34 -0700 Subject: fix decorator configuration section --- docs/narr/introduction.rst | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index bbe7df537..41bc7ead3 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -97,13 +97,11 @@ in very similar ways. See also :ref:`firstapp_chapter`. -Decorator-based configuration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Configure applications with decorators +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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: +Pyramid allows you to keep your configuration right next to your code. That way +you don't have to switch files to see your configuration. For example: .. code-block:: python @@ -114,15 +112,11 @@ decorators to localize the configuration. For example: 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`. +However, using Pyramid configuration decorators does not change your code. It +remains easy to extend, test or reuse. You can test your code as if the +decorators were not there. You can instruct the framework to ignore some +decorators. You can even use an imperative style to write your configuration, +skipping decorators entirely. Example: :ref:`mapping_views_using_a_decorator_section`. -- cgit v1.2.3 From dc7c27bdfbec0b22b650b9daf3e92f3b6000b4db Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 16:20:21 -0700 Subject: fix generated urls section --- docs/narr/introduction.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 41bc7ead3..f13397edc 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -120,13 +120,13 @@ skipping decorators entirely. Example: :ref:`mapping_views_using_a_decorator_section`. -URL generation -~~~~~~~~~~~~~~ +Generate application URLs +~~~~~~~~~~~~~~~~~~~~~~~~~ -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. +Dynamic web applications produce URLs that can change depending on what you are +viewing. Pyramid provides flexible, consistent, easy to use tools for generating +URLs. When you use these tools to write your application, you can change your +configuration without fear of breaking links in your web pages. Example: :ref:`generating_route_urls`. -- cgit v1.2.3 From 8c12559d800cde22d28a3cbc2ad5897c49768cb3 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 16:21:37 -0700 Subject: fix static assets section --- docs/narr/introduction.rst | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index f13397edc..6a27cb715 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -130,16 +130,15 @@ configuration without fear of breaking links in your web pages. Example: :ref:`generating_route_urls`. -Static file serving +Serve static assets ~~~~~~~~~~~~~~~~~~~ -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. +Web applications often require JavaScript, CSS, images and other so-called +*static assets*. Pyramid provides flexible tools for serving these kinds of +files. You can serve them directly from Pyramid, or host them on an external +server or CDN (content delivery network). Either way, Pyramid can help you to +generate URLs so you can change where your files come from without changing any +code. Example: :ref:`static_assets_section`. -- cgit v1.2.3 From 0c4065080b6078c9d7495e28402718591f8e294b Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 17:00:59 -0700 Subject: update the dynamic development section --- docs/narr/introduction.rst | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 6a27cb715..471b7a2ec 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -142,21 +142,19 @@ code. Example: :ref:`static_assets_section`. -Fully interactive development -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Develop interactively +~~~~~~~~~~~~~~~~~~~~~ + +Pyramid can automatically detect changes you make to template files and code, +so your changes are immediately available in your browser. You can debug using +plain old ``print()`` calls, which will display to your console. + +Pyramid has a debug toolbar that allows you to see information about how your +application is working right in your browser. See configuration, installed +packages, SQL queries, logging statements and more. -When 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. +When your application has an error, an interactive debugger allows you to poke +around from your browser to find out what happened. Example: :ref:`debug_toolbar`. -- cgit v1.2.3 From 0027f5d5b2219aa483139390e31f23e63327fc55 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 17:01:45 -0700 Subject: update the debugging sections --- docs/narr/introduction.rst | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 471b7a2ec..114d013f2 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -158,22 +158,19 @@ around from your browser to find out what happened. 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. +Debug with power +~~~~~~~~~~~~~~~~ + +When things go wrong, Pyramid gives you powerful ways to fix the problem. + +You can configure Pyramid to print helpful information to the console. The +``debug_notfound`` setting shows information about URLs that aren't matched. +The ``debug_authorization`` setting provides helpful messages about why you +aren't allowed to do what you just tried. + +Pyramid also has command line tools to help you verify your configuration. You +can use ``proutes`` and ``pviews`` to inspect how URLs are connected to your +application code. Examples: :ref:`debug_authorization_section` and :ref:`command_line_chapter`. -- cgit v1.2.3 From f9822db7231bc4e52cadc467d60ea328def08d5b Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 17:21:16 -0700 Subject: updated extensions section --- docs/narr/introduction.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 114d013f2..2782267ae 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -174,14 +174,15 @@ application code. Examples: :ref:`debug_authorization_section` and :ref:`command_line_chapter`. -Add-ons -~~~~~~~ +Extend your application +~~~~~~~~~~~~~~~~~~~~~~~ + +Pyramid add-ons extend the core of the framework with useful abilities. There +are add-ons available for your favorite template language, SQL and NoSQL +databases, authentication services and much much more. -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. +Supported Pyramid add-ons are held to the same demanding standards as the +framework itself. You will find them to be fully tested and well documented. Examples: https://trypyramid.com/resources-extending-pyramid.html -- cgit v1.2.3 From 42089ef5acc065dbb1fe826855936a415162b42b Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 17:43:39 -0700 Subject: re-write the views section --- docs/narr/introduction.rst | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 2782267ae..2ede8328d 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -187,19 +187,15 @@ framework itself. You will find them to be fully tested and well documented. Examples: https://trypyramid.com/resources-extending-pyramid.html -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. +Write your views +~~~~~~~~~~~~~~~~ + +A fundamental task for any framework is to map URLs to code. In Pyramid, that +code is called a :term:`view callable`. View callables can be functions, class +methods or even callable class instances. You are free to choose the approach +that best fits your use case. Regardless of your choice, Pyramid treats them +the same. You can change your mind at any time without any penalty. There are +no artificial distinctions between the various approaches. Here's a view callable defined as a function: -- cgit v1.2.3 From 86ed4c13d31cae497cd7459798e57c1fa03e2548 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 17:44:22 -0700 Subject: emphasize that the views are yours --- docs/narr/introduction.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 2ede8328d..3f04327cc 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -187,8 +187,8 @@ framework itself. You will find them to be fully tested and well documented. Examples: https://trypyramid.com/resources-extending-pyramid.html -Write your views -~~~~~~~~~~~~~~~~ +Write *your* views +~~~~~~~~~~~~~~~~~~ A fundamental task for any framework is to map URLs to code. In Pyramid, that code is called a :term:`view callable`. View callables can be functions, class -- cgit v1.2.3 From 0967f59a084b5d0eee1de18a85cb0f2ed486e0b5 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 3 Jun 2016 17:51:42 -0700 Subject: improve section title a bit more --- docs/narr/introduction.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 3f04327cc..c1f17dcfd 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -187,8 +187,8 @@ framework itself. You will find them to be fully tested and well documented. Examples: https://trypyramid.com/resources-extending-pyramid.html -Write *your* views -~~~~~~~~~~~~~~~~~~ +Write *your* views, *your* way +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A fundamental task for any framework is to map URLs to code. In Pyramid, that code is called a :term:`view callable`. View callables can be functions, class -- cgit v1.2.3 From ff14e5d4406a5fe9a4cc346be22cb36f45b6d844 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 7 Jun 2016 10:39:23 -0700 Subject: fix up headline a bit --- docs/narr/introduction.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index c1f17dcfd..41d7d384e 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -187,8 +187,8 @@ framework itself. You will find them to be fully tested and well documented. Examples: https://trypyramid.com/resources-extending-pyramid.html -Write *your* views, *your* way -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Write your views, *your* way +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A fundamental task for any framework is to map URLs to code. In Pyramid, that code is called a :term:`view callable`. View callables can be functions, class -- cgit v1.2.3 From 9b942a4bceb3efe98fbf5799d5e7aace33f9770c Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 7 Jun 2016 10:42:10 -0700 Subject: update asset specification section --- docs/narr/introduction.rst | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 41d7d384e..b9771c5f3 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -235,25 +235,26 @@ Here's a few views defined as methods of a class instead: .. _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. +Find *your* static assets +~~~~~~~~~~~~~~~~~~~~~~~~~ + +In many web frameworks, the static assets required by an application are kept +in a globally shared location, "the *static* directory". Others use a lookup +scheme, like an ordered set of template directories. Both of these approaches +have problems when it comes to customization. + +Pyramid takes a different approach. Static assets are located using *asset +specifications*, strings that contain reference both to a Python package name +and a file or directory name, e.g. ``MyPackage:static/index.html``. These +specifications are used for templates, JavaScript and CSS, translation files, +and any other package-bound static resource. By using asset specifications, +Pyramid makes it easy to extend your application with other packages without +worrying about conflicts. + +What happens if another Pyramid package you are using provides an asset you +need to customize? Maybe that page template needs better HTML, or you want to +update some CSS. With asset specifications you can override the assets from +other packages using simple wrappers. Examples: :ref:`asset_specifications` and :ref:`overriding_assets_section`. -- cgit v1.2.3 From 5404f9cef8eacefa37a221327de6a7f66c5798eb Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 7 Jun 2016 11:01:36 -0700 Subject: update information about extensible templating --- docs/narr/introduction.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index b9771c5f3..53f68a2ef 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -258,19 +258,19 @@ other packages using simple wrappers. 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. +Use *your* templates +~~~~~~~~~~~~~~~~~~~~ + +In Pyramid, the job of creating a ``Response`` belongs to a :term:`renderer`. +Any templating system--Mako, Genshi, Chameleon, Jinja2--can be a renderer. In +fact, packages exist for all of these systems. But if you'd rather use another, +a structured API exists allowing you to create a renderer using your favorite +templating system. You can use the templating system *you* understand, not one +required by the framework. + +What's more, Pyramid does not make you use a single templating system +exclusively. You can use multiple templating systems, even in the same +project. Example: :ref:`templates_used_directly`. -- cgit v1.2.3 From 1610c8fd3605f2ed481c37da27a1ce059419888a Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 7 Jun 2016 11:02:21 -0700 Subject: update section on returning dictionaries from views --- docs/narr/introduction.rst | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 53f68a2ef..112754b6a 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -274,16 +274,16 @@ project. Example: :ref:`templates_used_directly`. -Rendered views can return dictionaries -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Write testable views +~~~~~~~~~~~~~~~~~~~~ -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. +When you use a :term:`renderer` with your view callable, you are freed from +needing to return a "webby" ``Response`` object. Instead, your views can return +a simple Python dictionary. Pyramid will take care of rendering the information +in that dictionary to a ``Response`` on your behalf. As a result, your views +are more easily tested, since you don't need to parse HTML to evaluate the +results. Pyramid makes it a snap to write unit tests for your views, instead of +requiring you to use functional tests. .. index:: pair: renderer; explicitly calling @@ -291,7 +291,7 @@ instead of functionally testing all of your views. .. _example_render_to_response_call: -For example, instead of returning a ``Response`` object from a +For example, a typical web framework might return a ``Response`` object from a ``render_to_response`` call: .. code-block:: python @@ -303,7 +303,7 @@ For example, instead of returning a ``Response`` object from a return render_to_response('myapp:templates/mytemplate.pt', {'a':1}, request=request) -You can return a Python dictionary: +While you *can* do this in Pyramid, you can also return a Python dictionary: .. code-block:: python :linenos: @@ -314,13 +314,13 @@ You can return a Python dictionary: 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. +By configuring your view to use a renderer, you tell Pyramid to use the +``{'a':1}`` dictionary and the specified template to render a response on your +behalf. + +The string passed as ``renderer=`` above is an :term:`asset specification`. +Asset specifications are omnipresent in Pyramid. They allow for more reliable +customization. See :ref:`intro_asset_specs` for more information. Example: :ref:`renderers_chapter`. -- cgit v1.2.3 From 6d120e5f740f3b9a3f9ffd52da5c748b2f06cbca Mon Sep 17 00:00:00 2001 From: Aleph Melo Date: Sun, 16 Apr 2017 16:50:45 -0300 Subject: Fix #2927 - Change to listen = localhost:6543. --- docs/narr/myproject/development.ini | 2 +- docs/narr/startup.rst | 2 +- docs/quick_tour.rst | 2 +- docs/quick_tour/logging/development.ini | 2 +- docs/quick_tour/package/development.ini | 2 +- docs/quick_tour/sessions/development.ini | 2 +- docs/quick_tour/sqla_demo/development.ini | 2 +- docs/quick_tutorial/cookiecutters/development.ini | 2 +- docs/tutorials/wiki/src/authorization/development.ini | 2 +- docs/tutorials/wiki/src/basiclayout/development.ini | 2 +- docs/tutorials/wiki/src/installation/development.ini | 2 +- docs/tutorials/wiki/src/models/development.ini | 2 +- docs/tutorials/wiki/src/tests/development.ini | 2 +- docs/tutorials/wiki/src/views/development.ini | 2 +- docs/tutorials/wiki2/src/authentication/development.ini | 2 +- docs/tutorials/wiki2/src/authorization/development.ini | 2 +- docs/tutorials/wiki2/src/basiclayout/development.ini | 2 +- docs/tutorials/wiki2/src/installation/development.ini | 2 +- docs/tutorials/wiki2/src/models/development.ini | 2 +- docs/tutorials/wiki2/src/tests/development.ini | 2 +- docs/tutorials/wiki2/src/views/development.ini | 2 +- pyramid/scaffolds/alchemy/development.ini_tmpl | 2 +- pyramid/scaffolds/starter/development.ini_tmpl | 2 +- pyramid/scaffolds/zodb/development.ini_tmpl | 2 +- 24 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/narr/myproject/development.ini b/docs/narr/myproject/development.ini index 5d110805a..20a8a4868 100644 --- a/docs/narr/myproject/development.ini +++ b/docs/narr/myproject/development.ini @@ -24,7 +24,7 @@ pyramid.includes = [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst index cf4612602..08747fa89 100644 --- a/docs/narr/startup.rst +++ b/docs/narr/startup.rst @@ -132,7 +132,7 @@ Here's a high-level time-ordered overview of what happens when you press #. ``pserve`` starts the WSGI *server* defined within the ``[server:main]`` section. In our case, this is the Waitress server (``use = egg:waitress#main``), and it will listen on all interfaces on port 6543 - for both IPv4 and IPv6 (``listen = 127.0.0.1:6543 [::1]:6543``). The server + for both IPv4 and IPv6 (``listen = localhost:6543``). The server code itself is what prints ``serving on http://127.0.0.1:6543``. The server serves the application, and the application is running, waiting to receive requests. diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst index 02c3ff811..cd1598a1c 100644 --- a/docs/quick_tour.rst +++ b/docs/quick_tour.rst @@ -618,7 +618,7 @@ We have a few decisions made for us in this configuration: #. *Choice of web server:* ``use = egg:waitress#main`` tells ``pserve`` to use the ``waitress`` server. -#. *Interfaces:* ``listen = 127.0.0.1:6543 [::1]:6543`` tells ``waitress`` to listen on all interfaces on port 6543 for both IPv4 and IPv6. +#. *Interfaces:* ``listen = localhost:6543`` tells ``waitress`` to listen on all interfaces on port 6543 for both IPv4 and IPv6. Additionally the ``development.ini`` generated by this cookiecutter wired up Python's standard logging. We'll now see in the console, for example, a log on diff --git a/docs/quick_tour/logging/development.ini b/docs/quick_tour/logging/development.ini index 1f19e373d..b0210cbad 100644 --- a/docs/quick_tour/logging/development.ini +++ b/docs/quick_tour/logging/development.ini @@ -24,7 +24,7 @@ pyramid.includes = [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/quick_tour/package/development.ini b/docs/quick_tour/package/development.ini index 1f19e373d..b0210cbad 100644 --- a/docs/quick_tour/package/development.ini +++ b/docs/quick_tour/package/development.ini @@ -24,7 +24,7 @@ pyramid.includes = [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/quick_tour/sessions/development.ini b/docs/quick_tour/sessions/development.ini index 1f19e373d..b0210cbad 100644 --- a/docs/quick_tour/sessions/development.ini +++ b/docs/quick_tour/sessions/development.ini @@ -24,7 +24,7 @@ pyramid.includes = [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/quick_tour/sqla_demo/development.ini b/docs/quick_tour/sqla_demo/development.ini index 17b57fd0d..8d45a0975 100644 --- a/docs/quick_tour/sqla_demo/development.ini +++ b/docs/quick_tour/sqla_demo/development.ini @@ -26,7 +26,7 @@ sqlalchemy.url = sqlite:///%(here)s/sqla_demo.sqlite [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/quick_tutorial/cookiecutters/development.ini b/docs/quick_tutorial/cookiecutters/development.ini index 86b54b51d..a5093fb52 100644 --- a/docs/quick_tutorial/cookiecutters/development.ini +++ b/docs/quick_tutorial/cookiecutters/development.ini @@ -24,7 +24,7 @@ pyramid.includes = [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki/src/authorization/development.ini b/docs/tutorials/wiki/src/authorization/development.ini index 82c8cf3a1..74e7457d6 100644 --- a/docs/tutorials/wiki/src/authorization/development.ini +++ b/docs/tutorials/wiki/src/authorization/development.ini @@ -26,7 +26,7 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki/src/basiclayout/development.ini b/docs/tutorials/wiki/src/basiclayout/development.ini index 82c8cf3a1..74e7457d6 100644 --- a/docs/tutorials/wiki/src/basiclayout/development.ini +++ b/docs/tutorials/wiki/src/basiclayout/development.ini @@ -26,7 +26,7 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki/src/installation/development.ini b/docs/tutorials/wiki/src/installation/development.ini index 82c8cf3a1..74e7457d6 100644 --- a/docs/tutorials/wiki/src/installation/development.ini +++ b/docs/tutorials/wiki/src/installation/development.ini @@ -26,7 +26,7 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki/src/models/development.ini b/docs/tutorials/wiki/src/models/development.ini index 82c8cf3a1..74e7457d6 100644 --- a/docs/tutorials/wiki/src/models/development.ini +++ b/docs/tutorials/wiki/src/models/development.ini @@ -26,7 +26,7 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki/src/tests/development.ini b/docs/tutorials/wiki/src/tests/development.ini index 82c8cf3a1..74e7457d6 100644 --- a/docs/tutorials/wiki/src/tests/development.ini +++ b/docs/tutorials/wiki/src/tests/development.ini @@ -26,7 +26,7 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki/src/views/development.ini b/docs/tutorials/wiki/src/views/development.ini index 82c8cf3a1..74e7457d6 100644 --- a/docs/tutorials/wiki/src/views/development.ini +++ b/docs/tutorials/wiki/src/views/development.ini @@ -26,7 +26,7 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki2/src/authentication/development.ini b/docs/tutorials/wiki2/src/authentication/development.ini index 1e08d1bce..0786c1f66 100644 --- a/docs/tutorials/wiki2/src/authentication/development.ini +++ b/docs/tutorials/wiki2/src/authentication/development.ini @@ -28,7 +28,7 @@ auth.secret = seekrit [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki2/src/authorization/development.ini b/docs/tutorials/wiki2/src/authorization/development.ini index 1e08d1bce..0786c1f66 100644 --- a/docs/tutorials/wiki2/src/authorization/development.ini +++ b/docs/tutorials/wiki2/src/authorization/development.ini @@ -28,7 +28,7 @@ auth.secret = seekrit [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki2/src/basiclayout/development.ini b/docs/tutorials/wiki2/src/basiclayout/development.ini index e9f6d8d3f..be80882a5 100644 --- a/docs/tutorials/wiki2/src/basiclayout/development.ini +++ b/docs/tutorials/wiki2/src/basiclayout/development.ini @@ -26,7 +26,7 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki2/src/installation/development.ini b/docs/tutorials/wiki2/src/installation/development.ini index e9f6d8d3f..be80882a5 100644 --- a/docs/tutorials/wiki2/src/installation/development.ini +++ b/docs/tutorials/wiki2/src/installation/development.ini @@ -26,7 +26,7 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki2/src/models/development.ini b/docs/tutorials/wiki2/src/models/development.ini index e9f6d8d3f..be80882a5 100644 --- a/docs/tutorials/wiki2/src/models/development.ini +++ b/docs/tutorials/wiki2/src/models/development.ini @@ -26,7 +26,7 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki2/src/tests/development.ini b/docs/tutorials/wiki2/src/tests/development.ini index 1e08d1bce..0786c1f66 100644 --- a/docs/tutorials/wiki2/src/tests/development.ini +++ b/docs/tutorials/wiki2/src/tests/development.ini @@ -28,7 +28,7 @@ auth.secret = seekrit [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/docs/tutorials/wiki2/src/views/development.ini b/docs/tutorials/wiki2/src/views/development.ini index e9f6d8d3f..be80882a5 100644 --- a/docs/tutorials/wiki2/src/views/development.ini +++ b/docs/tutorials/wiki2/src/views/development.ini @@ -26,7 +26,7 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/pyramid/scaffolds/alchemy/development.ini_tmpl b/pyramid/scaffolds/alchemy/development.ini_tmpl index 64ac5ab6c..6efde1d82 100644 --- a/pyramid/scaffolds/alchemy/development.ini_tmpl +++ b/pyramid/scaffolds/alchemy/development.ini_tmpl @@ -26,7 +26,7 @@ sqlalchemy.url = sqlite:///%(here)s/{{project}}.sqlite [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/pyramid/scaffolds/starter/development.ini_tmpl b/pyramid/scaffolds/starter/development.ini_tmpl index de58ea63e..79302bd0a 100644 --- a/pyramid/scaffolds/starter/development.ini_tmpl +++ b/pyramid/scaffolds/starter/development.ini_tmpl @@ -24,7 +24,7 @@ pyramid.includes = [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration diff --git a/pyramid/scaffolds/zodb/development.ini_tmpl b/pyramid/scaffolds/zodb/development.ini_tmpl index a155590f8..453b87e49 100644 --- a/pyramid/scaffolds/zodb/development.ini_tmpl +++ b/pyramid/scaffolds/zodb/development.ini_tmpl @@ -29,7 +29,7 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 [server:main] use = egg:waitress#main -listen = 127.0.0.1:6543 [::1]:6543 +listen = localhost:6543 ### # logging configuration -- cgit v1.2.3 From 6dbdeb344579522829007c64cfbe535d2f2ece1b Mon Sep 17 00:00:00 2001 From: Aleph Melo Date: Sun, 16 Apr 2017 17:00:06 -0300 Subject: Add a new contributor. --- CONTRIBUTORS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 566e91195..1a6fc24ac 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -294,3 +294,5 @@ Contributors - Martin Frlin, 2016/12/7 - Kirill Kuzminykh, 2017/03/01 + +- Aleph Melo, 2017/04/16 \ No newline at end of file -- cgit v1.2.3 From d1745247edae01ef934acf5bb206d29952a99dbf Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 4 May 2017 00:27:18 -0500 Subject: line length --- docs/whatsnew-1.9.rst | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/docs/whatsnew-1.9.rst b/docs/whatsnew-1.9.rst index f49258662..0ba29625c 100644 --- a/docs/whatsnew-1.9.rst +++ b/docs/whatsnew-1.9.rst @@ -49,25 +49,11 @@ Deprecations Backward Incompatibilities -------------------------- -- ``request.exception`` and ``request.exc_info`` will only be set if the - response was generated by the EXCVIEW tween. This is to avoid any confusion - where a response was generated elsewhere in the pipeline and not in - direct relation to the original exception. If anyone upstream wants to - catch and render responses for exceptions they should set - ``request.exception`` and ``request.exc_info`` themselves to indicate - the exception that was squashed when generating the response. - - Similar behavior occurs with - :meth:`pyramid.request.Request.invoke_exception_view` in which - the exception properties are set to reflect the exception if a response - is successfully generated by the method. - - This is a very minor incompatibility. Most tweens right now would give - priority to the raised exception and ignore ``request.exception``. This - change just improves and clarifies that bookkeeping by trying to be - more clear about the relationship between the response and its squashed - exception. See https://github.com/Pylons/pyramid/pull/3029 and - https://github.com/Pylons/pyramid/pull/3031 +- ``request.exception`` and ``request.exc_info`` will only be set if the response was generated by the EXCVIEW tween. This is to avoid any confusion where a response was generated elsewhere in the pipeline and not in direct relation to the original exception. If anyone upstream wants to catch and render responses for exceptions they should set ``request.exception`` and ``request.exc_info`` themselves to indicate the exception that was squashed when generating the response. + + Similar behavior occurs with :meth:`pyramid.request.Request.invoke_exception_view` in which the exception properties are set to reflect the exception if a response is successfully generated by the method. + + This is a very minor incompatibility. Most tweens right now would give priority to the raised exception and ignore ``request.exception``. This change just improves and clarifies that bookkeeping by trying to be more clear about the relationship between the response and its squashed exception. See https://github.com/Pylons/pyramid/pull/3029 and https://github.com/Pylons/pyramid/pull/3031 Documentation Enhancements -------------------------- -- cgit v1.2.3 From 1fc7eefc4ac9f5ea3d22d7a108cd3da1e73cbcfa Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 9 May 2017 01:41:12 -0500 Subject: fix changelog, added #3031 and #3029 to the wrong release version --- CHANGES.txt | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 80b5003c1..51a1e457d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,28 @@ +1.9a2 (2017-05-09) +================== + +Backward Incompatibilities +-------------------------- + +- ``request.exception`` and ``request.exc_info`` will only be set if the + response was generated by the EXCVIEW tween. This is to avoid any confusion + where a response was generated elsewhere in the pipeline and not in + direct relation to the original exception. If anyone upstream wants to + catch and render responses for exceptions they should set + ``request.exception`` and ``request.exc_info`` themselves to indicate + the exception that was squashed when generating the response. + + Similar behavior occurs with ``request.invoke_exception_view`` in which + the exception properties are set to reflect the exception if a response + is successfully generated by the method. + + This is a very minor incompatibility. Most tweens right now would give + priority to the raised exception and ignore ``request.exception``. This + change just improves and clarifies that bookkeeping by trying to be + more clear about the relationship between the response and its squashed + exception. See https://github.com/Pylons/pyramid/pull/3029 and + https://github.com/Pylons/pyramid/pull/3031 + 1.9a1 (2017-05-01) ================== @@ -114,28 +139,6 @@ Deprecations See https://github.com/Pylons/pyramid/pull/2854 and https://github.com/Pylons/pyramid/pull/3019 -Backward Incompatibilities --------------------------- - -- ``request.exception`` and ``request.exc_info`` will only be set if the - response was generated by the EXCVIEW tween. This is to avoid any confusion - where a response was generated elsewhere in the pipeline and not in - direct relation to the original exception. If anyone upstream wants to - catch and render responses for exceptions they should set - ``request.exception`` and ``request.exc_info`` themselves to indicate - the exception that was squashed when generating the response. - - Similar behavior occurs with ``request.invoke_exception_view`` in which - the exception properties are set to reflect the exception if a response - is successfully generated by the method. - - This is a very minor incompatibility. Most tweens right now would give - priority to the raised exception and ignore ``request.exception``. This - change just improves and clarifies that bookkeeping by trying to be - more clear about the relationship between the response and its squashed - exception. See https://github.com/Pylons/pyramid/pull/3029 and - https://github.com/Pylons/pyramid/pull/3031 - Documentation Changes --------------------- -- cgit v1.2.3 From 607367ace939488f787d918c60275a90d5505dbd Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 9 May 2017 01:42:09 -0500 Subject: prep 1.9a2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6aac12ff8..03416efe7 100644 --- a/setup.py +++ b/setup.py @@ -61,7 +61,7 @@ testing_extras = tests_require + [ ] setup(name='pyramid', - version='1.9a1', + version='1.9a2', description='The Pyramid Web Framework, a Pylons project', long_description=README + '\n\n' + CHANGES, classifiers=[ -- cgit v1.2.3 From a7402ad57c6bf4803286b61fd9560d8b192826b6 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Tue, 9 May 2017 14:15:01 -0400 Subject: Pytest changed their URL structure --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index f09ae325b..0fdfa7c9a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -70,7 +70,7 @@ intersphinx_mapping = { 'plaster': ('http://docs.pylonsproject.org/projects/plaster/en/latest/', None), 'pylonswebframework': ('http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/', None), 'python': ('https://docs.python.org/3', None), - 'pytest': ('http://pytest.org/latest/', None), + 'pytest': ('http://pytest.org/en/latest/', None), 'sphinx': ('http://www.sphinx-doc.org/en/latest', None), 'sqla': ('http://docs.sqlalchemy.org/en/latest', None), 'tm': ('http://docs.pylonsproject.org/projects/pyramid-tm/en/latest/', None), -- cgit v1.2.3 From 0b92dfed800117595ef00fb2847c5db9970f4cac Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 9 May 2017 12:00:33 -0700 Subject: use new TLD for pytest-cov --- docs/quick_tutorial/unit_testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quick_tutorial/unit_testing.rst b/docs/quick_tutorial/unit_testing.rst index 7c85d5289..002c62fde 100644 --- a/docs/quick_tutorial/unit_testing.rst +++ b/docs/quick_tutorial/unit_testing.rst @@ -29,7 +29,7 @@ broken the code. As you're writing your code, you might find this more convenient than changing to your browser constantly and clicking reload. We'll also leave discussion of `pytest-cov -`_ for another section. +`_ for another section. Objectives -- cgit v1.2.3 From f46c7944b70e2204529216655bfdfac1b72e646b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 12 May 2017 01:18:17 -0700 Subject: use https --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 0fdfa7c9a..e63019c63 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -70,7 +70,7 @@ intersphinx_mapping = { 'plaster': ('http://docs.pylonsproject.org/projects/plaster/en/latest/', None), 'pylonswebframework': ('http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/', None), 'python': ('https://docs.python.org/3', None), - 'pytest': ('http://pytest.org/en/latest/', None), + 'pytest': ('https://pytest.org/en/latest/', None), 'sphinx': ('http://www.sphinx-doc.org/en/latest', None), 'sqla': ('http://docs.sqlalchemy.org/en/latest', None), 'tm': ('http://docs.pylonsproject.org/projects/pyramid-tm/en/latest/', None), -- cgit v1.2.3 From b57460e673b4837f9bb587ecb9b6deb1761dcfe6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 12 May 2017 21:06:08 -0700 Subject: update narrative docs to align with source code - per https://github.com/Pylons/pyramid/pull/3000#issuecomment-294565854 --- docs/narr/project.rst | 6 +++--- docs/narr/startup.rst | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/narr/project.rst b/docs/narr/project.rst index ce7e90793..ad27290f3 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -332,7 +332,7 @@ Access is restricted such that only a browser running on the same machine as Pyramid will be able to access your Pyramid application. However, if you want to open access to other machines on the same network, then edit the ``development.ini`` file, and replace the ``listen`` value in the -``[server:main]`` section, changing it from ``127.0.0.1:6543 [::1]:6543`` to ``*:6543`` +``[server:main]`` section, changing it from ``localhost:6543`` to ``*:6543`` (this is equivalent to ``0.0.0.0:6543 [::]:6543``). For example: .. code-block:: ini @@ -356,8 +356,8 @@ IPv6. ``[::]`` means the same as ``0.0.0.0`` but for IPv6 protocol. You can change the port on which the server runs on by changing the same portion of the ``development.ini`` file. For example, you can change the -``listen = 127.0.0.1:6543 [::1]:6543`` line in the ``development.ini`` file's ``[server:main]`` -section to ``listen = 127:0.0.1:8080 [::1]:8080`` to run the server on port 8080 instead of port 6543. +``listen = localhost:6543`` line in the ``development.ini`` file's ``[server:main]`` +section to ``listen = localhost:8080`` to run the server on port 8080 instead of port 6543. You can shut down a server started this way by pressing ``Ctrl-C`` (or ``Ctrl-Break`` on Windows). diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst index 08747fa89..27a2f1919 100644 --- a/docs/narr/startup.rst +++ b/docs/narr/startup.rst @@ -10,12 +10,12 @@ you'll see something much like this show up on the console: $ $VENV/bin/pserve development.ini Starting server in PID 16305. - Serving on http://127.0.0.1:6543 - Serving on http://[::1]:6543 + Serving on http://localhost:6543 + Serving on http://localhost:6543 This chapter explains what happens between the time you press the "Return" key -on your keyboard after typing ``pserve development.ini`` and the time the line -``serving on http://127.0.0.1:6543`` is output to your console. +on your keyboard after typing ``pserve development.ini`` and the time the lines +``Serving on http://localhost:6543`` are output to your console. .. index:: single: startup process @@ -133,7 +133,7 @@ Here's a high-level time-ordered overview of what happens when you press section. In our case, this is the Waitress server (``use = egg:waitress#main``), and it will listen on all interfaces on port 6543 for both IPv4 and IPv6 (``listen = localhost:6543``). The server - code itself is what prints ``serving on http://127.0.0.1:6543``. The server + code itself is what prints ``Serving on http://localhost:6543``. The server serves the application, and the application is running, waiting to receive requests. .. seealso:: -- cgit v1.2.3 From b5444950d84c507f26764a16021db6e01d0461e3 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 12 May 2017 21:22:39 -0700 Subject: resolve conflicts --- CONTRIBUTORS.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 1a6fc24ac..542b85f8e 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -295,4 +295,6 @@ Contributors - Kirill Kuzminykh, 2017/03/01 -- Aleph Melo, 2017/04/16 \ No newline at end of file +- Aleph Melo, 2017/04/16 + +- Jeremy(Ching-Rui) Chen, 2017/04/19 -- cgit v1.2.3 From b730ae3a4706df6e5cf39a91b23ec67225fc63db Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 17 May 2017 04:01:27 -0700 Subject: remove bad path from python executable - Closes #3044 --- docs/quick_tour.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst index de896939a..1265012ab 100644 --- a/docs/quick_tour.rst +++ b/docs/quick_tour.rst @@ -46,7 +46,7 @@ For Windows: # set an environment variable to where you want your virtual environment c:\\> set VENV=c:\\env # create the virtual environment - c:\\> %VENV%\\Scripts\\python -m venv %VENV% + c:\\> python -m venv %VENV% # install pyramid c:\\> %VENV%\\Scripts\\pip install pyramid # or for a specific released version -- cgit v1.2.3 From ad6b57f351799c44eb539cf622ed197ea85f9dbd Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 17 May 2017 04:24:44 -0700 Subject: adjust emphasize-lines range --- docs/tutorials/wiki/authorization.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index d580e7816..0ba734f83 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -233,7 +233,7 @@ Add the following import statements to the head of .. literalinclude:: src/authorization/tutorial/views.py :lines: 6-17 - :emphasize-lines: 1-14 + :emphasize-lines: 1-12 :language: python All the highlighted lines need to be added or edited. -- cgit v1.2.3 From 7c680930d09d20bfa05249e01553e6488e61f1ca Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 22 May 2017 10:56:05 -0700 Subject: updates to narrative docs introduction, fixing for clarity and concision --- docs/narr/introduction.rst | 665 +++++++++++---------------------------------- 1 file changed, 159 insertions(+), 506 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 40d9c14a8..adf955a97 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -55,6 +55,63 @@ Openness As with Python, the Pyramid software is distributed under a `permissive open source license `_. +.. _why_pyramid: + +Why Pyramid? +------------ + +In a world filled with web frameworks, why should you choose Pyramid? + +Modern +~~~~~~ + +Pyramid is fully compatible with Python 3. If you develop a Pyramid application +today, you can rest assured that you'll be able to use the most modern features +of your favorite language. And in the years to come, you'll continue to be +working on a framework that is up-to-date and forward-looking. + +Tested +~~~~~~ + +Untested code is broken by design. The Pyramid community has a strong testing +culture and our framework reflects that. Every release of Pyramid has 100% +statement coverage [#]_ and 95% decision/condition coverage. [#]_ It is +automatically tested using `Travis `_ and +`Jenkins `_ on Python 2.7, +Python 3.4, Python 3.5, 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, but we've noticed we find a lot fewer of them +while working on projects with a solid testing regime. + +.. [#] as measured by `coverage `_ +.. [#] as measured by `instrumental `_ + +Documented +~~~~~~~~~~ + +The Pyramid documentation is comprehensive. We strive to keep our narrative +documentation both complete and friendly to newcomers. We also maintain a +:ref:`cookbook ` of recipes, demonstrations of +common scenarios you might face. And contributions in the form of improvements +to our documentation are always appreciated. + +Supported +~~~~~~~~~ + +You can get help quickly with Pyramid. It's our goal that no Pyramid question +go unanswered. Whether you ask a question on IRC, on the Pylons-discuss mailing +list, or on StackOverflow, you're likely to get a reasonably prompt response. + +Pyramid is also a welcoming, friendly space for newcomers. We don't tolerate +"support trolls" or those who enjoy berating fellow users in our support +channels. We try to keep it well-lit and new-user-friendly. + +Example: Visit irc\://freenode.net#pyramid (the ``#pyramid`` channel on +irc.freenode.net in an IRC client) or the pylons-discuss maillist at +https://groups.google.com/forum/#!forum/pylons-discuss. + .. _what_makes_pyramid_unique: What makes Pyramid unique @@ -324,537 +381,131 @@ customization. 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 +Use events to coordinate +~~~~~~~~~~~~~~~~~~~~~~~~ - if __name__ == '__main__': - config = Configurator() - config.add_response_adapter(string_response_adapter, basestring) - config.add_response_adapter(tuple_response_adapter, tuple) +When writing web applications, it is often important to have your code run at a +specific point in the lifecycle of a request. In Pyramid, you can accomplish +this using *subscribers* and *events*. -Once this is done, both of these view callables will work: +For example, you might have a job that needs to be done each time your +application handles a new request. Pyramid emits a ``NewRequest`` event at this +point in the request handling lifecycle. You can register your code as a +subscriber to this event using a clear, declarative style: .. code-block:: python - :linenos: - def aview(request): - return "Hello world!" - - def anotherview(request): - return (403, 'text/plain', "Forbidden") + from pyramid.events import NewRequest + from pyramid.events import subscriber -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. + @subscriber(NewRequest) + def my_job(event): + do_something(event.request) -.. seealso:: +Pyramid's event system can be extended as well. If you need, you can create +events of your own and send them using Pyramid's event system. Then anyone +working with your application can subscribe to your events and coordinate their +code with yours. - 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`. +Example: :ref:`events_chapter` and :ref:`event_types`. -Automating repetitive configuration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Build international applications +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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: +Pyramid ships with features that allow you to write applications for +international audiences. You can mark text in your source files and templates +and build catalogs of messages to be translated. You can translate these +catalogs into other languages. Users may then indicate their preference, and +see your application in their language. -.. code-block:: python - :linenos: +Many systems which offer internationalization suffer from a common problem. A +message in your code may have the same text as one in some other package. +Messages can conflict with each-other, leading to translation errors. Pyramid +solves this problem by using translation *domains*. Each application can have +its own translation domain. Messages in one domain cannot conflict with +messages in another. Problem solved. - from pyramid.config import Configurator +Example: :ref:`i18n_chapter`. - 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') +Build efficient applications +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Pretty tedious right? You can add a directive to the Pyramid configurator to -automate some of the tedium away: +Views in dynamic web applications can be expensive or slow to build. Pyramid +allows you to save the results of such a view by *caching* the rendered +response. Indicate in configuration that you want a view to be cached:: -.. code-block:: python - :linenos: + @view_config(http_cache=3600) # 60 minutes + def myview(request): ... - from pyramid.config import Configurator +Pyramid will automatically add the appropriate ``Cache-Control`` and +``Expires`` headers to the response it creates. - 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) +See the :meth:`~pyramid.config.Configurator.add_view` method's ``http_cache`` +documentation for more information. - config = Configurator() - config.add_directive('add_protected_xhr_views', add_protected_xhr_views) +Build fast applications +~~~~~~~~~~~~~~~~~~~~~~~ -Once that's done, you can call the directive you've just added as a method of -the Configurator object: +The Pyramid core is fast. It has been engineered from the ground up for speed. +It only does as much work as absolutely necessary when you ask it to get a job +done. If you need speed from your application, Pyramid is the right choice for +you. -.. code-block:: python - :linenos: +Example: http://blog.curiasolutions.com/pages/the-great-web-framework-shootout.html - config.add_route('xhr_route', '/xhr/{id}') - config.add_protected_xhr_views('my.package') +Store session data +~~~~~~~~~~~~~~~~~~ -Your previously repetitive configuration lines have now morphed into one line. +HTTP is a *stateless* protocol. No request can have knowledge of any other +request. But it is often desireable to associate data with a particular user. +Think of a shopping cart that remembers the items you have added to it even as +you move through the shopping site finding other items to add. -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. +Pyramid allows you to use *sessions* to solve this problem. Many other +frameworks also support sessions. But Pyramid allows you to plug in your own +custom sessioning system. So long as your system conforms to a documented +interface, you can drop it in in place of the provided system. -.. seealso:: +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. - See also :ref:`add_directive`. +Example: :ref:`sessions_chapter`. -Programmatic introspection +Handle problems with grace ~~~~~~~~~~~~~~~~~~~~~~~~~~ -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. +Mistakes happen. Problems crop up. No-one writes bug-free code. Pyramid +provides a way to handle the exceptions your code encounters. An +:term:`exception view` is a special kind of view which is automatically called +when an particular exception type "bubbles up" without being handled by your +application. -This is possible using Pyramid's :term:`introspector`. +For example, you might register an exception view for the :exc:`Exception` +exception type, which will catch *all* exceptions, and present a pretty "well, +this is embarrassing" page. Or you might choose to register an exception view +for only certain application-specific exceptions. You can make a one for when a +file is not found, or when the user doesn't have permission to do something. In +the former case, you can show a pretty "Not Found" page; in the latter case you +might show a login form. -Here's an example of using Pyramid's introspector from within a view callable: +Example: :ref:`exception_views`. -.. code-block:: python - :linenos: +And much, much more... +~~~~~~~~~~~~~~~~~~~~~~ - from pyramid.view import view_config - from pyramid.response import Response +Pyramid has been built with a number of other sophisticated design features +that make it adaptable. Read more about them below. - @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'])) +.. toctree:: + :maxdepth: 2 -.. seealso:: + advfeatures - 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.4, Python 3.5, 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. - -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 -https://groups.google.com/forum/#!forum/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 `. .. index:: single: Pylons Project @@ -907,6 +558,21 @@ 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. + +.. 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. + + 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, @@ -931,16 +597,3 @@ frameworks named `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. -- cgit v1.2.3 From 26c90db176cb109bbb5b1fb094827be2df273dae Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 22 May 2017 12:10:51 -0700 Subject: move more esoteric framework features into a separate file to remove complexity from the intro doc. --- docs/narr/advfeatures.rst | 393 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 docs/narr/advfeatures.rst diff --git a/docs/narr/advfeatures.rst b/docs/narr/advfeatures.rst new file mode 100644 index 000000000..4365b1855 --- /dev/null +++ b/docs/narr/advfeatures.rst @@ -0,0 +1,393 @@ +Advanced :app:`Pyramid` Design Features +======================================= + +Pyramid has been built from the ground up to avoid the problems that other +frameworks can suffer. + + +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.package', route_prefix='/somethingelse') + +.. 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`. \ No newline at end of file -- cgit v1.2.3 From f47d226dc4c390a476f2b1fabe8e56d458c971ae Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 22 May 2017 14:02:08 -0700 Subject: simplify the section comparing pyramid with other web frameworks also remove the sidebar about MVC, in favor of a simpler statement of belief in the MVC paragraph. --- docs/narr/introduction.rst | 76 ++++++++++++---------------------------------- 1 file changed, 19 insertions(+), 57 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 5eda0fcf4..63bc164fb 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -517,7 +517,7 @@ includes details about how :app:`Pyramid` relates to the Pylons Project. single: MVC :app:`Pyramid` and Other Web Frameworks ------------------------------------------- +--------------------------------------- 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` @@ -528,63 +528,25 @@ November of that year. :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, 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. 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. - - -.. 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. - - -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. +Similar to :term:`Zope`, :app:`Pyramid` applications may easily be extended. If +you work within the constraints of the framework, you can produce applications +that can be reused, modified or extended without needing to modify the original +application code. :app:`Pyramid` also inherits the concepts of :term:`traversal` +and declarative security from Zope. + +Similar to :term:`Pylons` version 1.0, :app:`Pyramid` is largely free of +policy. It makes no assertions about which database or template system you +should use. You are free to use whatever third-party components fit the needs +of your specific application. :app:`Pyramid` also inherits its approach to +:term:`URL dispatch` from Pylons. + +Similar to :term:`Django`, :app:`Pyramid` values extensive documentation. In +addition, the concept of a :term:`view` is used by :app:`Pyramid` much as it +would be by Django. Other Python web frameworks advertise themselves as members of a class of web frameworks named `model-view-controller `_ -frameworks. Insofar as this term has been claimed to represent a class of web -frameworks, :app:`Pyramid` also generally fits into this class. +frameworks. The authors of :app:`Pyramid` do not believe that the MVC pattern +fits the web particularly well. However, if this abstraction works for you, +:app:`Pyramid` also generally fits into this class. -- cgit v1.2.3 From aafaf73655c11ca1d6645d85e1754be6996540dd Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Mon, 22 May 2017 14:38:53 -0700 Subject: Add test for closest predicate error message --- pyramid/tests/test_config/test_util.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pyramid/tests/test_config/test_util.py b/pyramid/tests/test_config/test_util.py index 398b6fba8..bb86a1f56 100644 --- a/pyramid/tests/test_config/test_util.py +++ b/pyramid/tests/test_config/test_util.py @@ -365,6 +365,16 @@ class TestPredicateList(unittest.TestCase): from pyramid.exceptions import ConfigurationError self.assertRaises(ConfigurationError, self._callFUT, unknown=1) + def test_predicate_close_matches(self): + from pyramid.exceptions import ConfigurationError + with self.assertRaises(ConfigurationError) as context: + self._callFUT(method='GET') + expected_msg = ( + "Unknown predicate values: {'method': 'GET'} " + "(did you mean request_method)" + ) + self.assertEqual(context.exception.args[0], expected_msg) + def test_notted(self): from pyramid.config import not_ from pyramid.testing import DummyRequest -- cgit v1.2.3 From 08422ee6340cbcd225dcfc26c7c0aa3165449a58 Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Mon, 22 May 2017 14:40:44 -0700 Subject: Fix #1603, add closest predicate name in error message --- pyramid/config/util.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/pyramid/config/util.py b/pyramid/config/util.py index 67bba9593..d09d37d94 100644 --- a/pyramid/config/util.py +++ b/pyramid/config/util.py @@ -1,3 +1,4 @@ +from difflib import get_close_matches from hashlib import md5 import inspect @@ -36,7 +37,7 @@ class not_(object): config.add_view( 'mypackage.views.my_view', - route_name='ok', + route_name='ok', request_method=not_('POST') ) @@ -69,7 +70,7 @@ class Notted(object): # if the underlying predicate doesnt return a value, it's not really # a predicate, it's just something pretending to be a predicate, # so dont update the hash - if val: + if val: val = '!' + val return val @@ -90,7 +91,7 @@ class Notted(object): # over = before class PredicateList(object): - + def __init__(self): self.sorter = TopologicalSorter() self.last_added = None @@ -152,7 +153,15 @@ class PredicateList(object): weights.append(1 << n + 1) preds.append(pred) if kw: - raise ConfigurationError('Unknown predicate values: %r' % (kw,)) + closest = [] + names = [ name for name, _ in ordered ] + for name in kw: + closest.extend(get_close_matches(name, names, 3)) + + raise ConfigurationError( + 'Unknown predicate values: %r (did you mean %s)' + % (kw, ','.join(closest)) + ) # A "order" is computed for the predicate list. An order is # a scoring. # -- cgit v1.2.3 From 96dd805d55c5576778580ff52e978ff8aebc3a04 Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Mon, 22 May 2017 14:54:46 -0700 Subject: =?UTF-8?q?Load=20difflib=20on-demand=20so=20that=20it=20won?= =?UTF-8?q?=E2=80=99t=20take=20message=20proactively?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyramid/config/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyramid/config/util.py b/pyramid/config/util.py index d09d37d94..63f06ff9b 100644 --- a/pyramid/config/util.py +++ b/pyramid/config/util.py @@ -1,4 +1,3 @@ -from difflib import get_close_matches from hashlib import md5 import inspect @@ -153,6 +152,7 @@ class PredicateList(object): weights.append(1 << n + 1) preds.append(pred) if kw: + from difflib import get_close_matches closest = [] names = [ name for name, _ in ordered ] for name in kw: -- cgit v1.2.3 From 37d887705400e0c7631ec26afb972ebe9bfe35d5 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 22 May 2017 15:13:18 -0700 Subject: add changelog for #3054 --- CHANGES.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 51a1e457d..1a7cfaf0b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,10 @@ +unreleased +========== + +- Add an informative error message when unknown predicates are supplied. The + new message suggests alternatives based on the list of known predicates. + See https://github.com/Pylons/pyramid/pull/3054 + 1.9a2 (2017-05-09) ================== -- cgit v1.2.3 From 3b340c9922f9bc1ea42e729c086c946b4cdfaf83 Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Mon, 22 May 2017 16:11:48 -0700 Subject: Fix #2548, add SRI has for script tags --- docs/narr/myproject/myproject/templates/layout.jinja2 | 8 ++++---- pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl | 8 ++++---- pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl | 8 ++++---- pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/narr/myproject/myproject/templates/layout.jinja2 b/docs/narr/myproject/myproject/templates/layout.jinja2 index bfac9e64e..820758fea 100644 --- a/docs/narr/myproject/myproject/templates/layout.jinja2 +++ b/docs/narr/myproject/myproject/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl b/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl index b5cfdc94d..6f6946ba2 100644 --- a/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl +++ b/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl @@ -18,8 +18,8 @@ @@ -60,7 +60,7 @@ - - + + diff --git a/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl b/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl index a784c741b..f3c27e3f0 100644 --- a/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl +++ b/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl @@ -18,8 +18,8 @@ @@ -60,7 +60,7 @@ - - + + diff --git a/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl b/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl index 72b480249..4b24ee2df 100644 --- a/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl +++ b/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl @@ -18,8 +18,8 @@ @@ -61,7 +61,7 @@ - - + + -- cgit v1.2.3 From 52ff50f75d265a4c7d04db538c26b61ab05677c6 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 22 May 2017 16:38:53 -0700 Subject: Updating wording in the advanced features doc to make it more accessible --- docs/narr/advfeatures.rst | 352 +++++++++++++++++++++++----------------------- 1 file changed, 179 insertions(+), 173 deletions(-) diff --git a/docs/narr/advfeatures.rst b/docs/narr/advfeatures.rst index 4365b1855..5c45cf61a 100644 --- a/docs/narr/advfeatures.rst +++ b/docs/narr/advfeatures.rst @@ -5,104 +5,123 @@ Pyramid has been built from the ground up to avoid the problems that other frameworks can suffer. -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 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +You Don't Need Singletons +------------------------- + +Have you ever struggled with parametrizing Django's ``settings.py`` file for +multiple installations of the same Django application? Have you ever needed to +monkey-patch a framework fixture to get it to behave properly for your +use-case? Have you ever tried to deploy your application using an asynchronous +server and failed? + +All these problems are symptoms of "mutable global state", also known as +"import-time side effects" and arise from the use of "singleton" data structures. + +:app:`Pyramid` is written so that you don't run into these types of problems. +It is even possible to run multiple copies of the *same* :app:`Pyramid` +application configured differently within a single Python process. This makes +running Pyramid in shared hosting environments a snap. + +Simplify your View Code with Predicates +--------------------------------------- + +How many times have you found yourself beginning the logic of your view code +with something like this:: + + if request.user.is_authenticated: + # do one thing + else: + # do something else 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. +with a single route. For example, you can create a route with the pattern +``/items`` and when the route is matched, you can send the request to one view +if the request method is GET, another view if the request method is POST, and +so on. + +:app:`Pyramid` uses a system of "view predicates" to allow this. Matching the +request method is one basic thing you can do with a view predicate. You can +also associate views with other request parameters, such as elements in the +query string, the Accept header, whether the request is an XHR request or not, +and lots of other things. + +For our example above, you can do this instead:: + + @view_config(route_name="items", effective_principals=pyramid.security.Authenticated) + def auth_view(request): + # do one thing + + @view_config(route_name="items") + def anon_view(request): + # do something else + +This approach allows you to develop view code that is simpler, more easily +understandable, and more directly testable. Example: :ref:`view_configuration_parameters`. -Transaction management -~~~~~~~~~~~~~~~~~~~~~~ +Stop Worrying About Transactions +-------------------------------- 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. +management* system. When you use this system, you can stop worrying about when +to commit your changes, :app:`Pyramid` handles it for you. The system will +commit at the end of a request or aborts if there was an exception. + +Why is that a good thing? Imagine a situation where you manually commit a +change to your persistence layer. It's very likely that other framework code +will run *after* your changes are done. If an error happens in that other code, +you can easily wind up with inconsistent data if you're not extremely careful. + +Using transaction management saves you from needing to think about this. Either +a request completes successfully, and all changes are committed, or it does +not, and all changes are aborted. + +Pyramid's transaction management is extendable, so you can synchronize commits +between multiple databases, or databases of different kinds. It also allows you +to do things like conditionally send email if a transaction commits, but +otherwise keep quiet. Example: :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements anywhere in application code). -Configuration conflict detection -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Stop Worrying About Configuration +--------------------------------- 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. +as systems grow large, configuration grows more complex. Your app may grow to +have hundreds or even thousands of configuration statements. -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 +Pyramid's configuration system keeps track of your configuration. 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. +complain loudly at startup time. + +Pyramid's configuration system is not dumb though. If you use the confugration +:meth:`~pyramid.config.Configurator.include` system, it can automatically +resolve conflicts on its own. "More local" statements are preferred over "less +local" ones. So you can 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: +Compose Powerful Apps From Simple Parts +---------------------------------------- + +Speaking of the :app:`Pyramid` structured "include" mechanism (see +:meth:`~pyramid.config.Configurator.include`), it allows you to compose complex +applications from multiple, simple Python packages. All the configuration +statements that can be performed in your "main" Pyramid application can also be +used in included packages. You can add views, routes, and subscribers, and even +set authentication and authorization policies. + +If you need, you can extend or override the configuration of an existing +application by including its configuration in your own and then modifying it. + + +For example, if you want to reuse an existing application that already has a +bunch of routes, you can just use the ``include`` statement with a +``route_prefix``. All the routes of that application will be availabe, prefixed +as you requested: .. code-block:: python :linenos: @@ -120,91 +139,79 @@ For example: See also :ref:`including_configuration` and :ref:`building_an_extensible_app`. -Flexible authentication and authorization -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Authenticate Users Your Way +--------------------------- + +:app:`Pyramid` ships with prebuilt well-tested authentication and authorization +schemes out of the box. Using a scheme is a matter of configuration. So if you +need to change approaches later, you need only update your configuration. -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. +In addition, the system that handles authentication an authorization is +flexible and pluggable. If you want to use another security add-on, or define +your own, you can. And again, you need only update your application +configuration to make the change. 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"). +Build Trees of Resources +------------------------ + +:app:`Pyramid` supports :term:`Traversal`, a way of mapping URLs to a concrete +tree of resources. If your application naturally consists of an arbitrary +heirarchy of different types of content (like a CMS or a Document Management +System), traversal is for you. If you have a requirement for a highly granular +security model ("Jane can edit documents in *this* folder, but not *that* +one"), traversal can be a powerful approach. Examples: :ref:`hello_traversal_chapter` and :ref:`much_ado_about_traversal_chapter`. -Tweens -~~~~~~ +Take Action on Each Request with Tweens +--------------------------------------- + +Pyramid has a system for applying arbitrary actions to each request or response +called *tweens*. The system is similar in concept to WSGI :term:`middleware`, +but can be more useful since they run in the Pyramid context, and have access +to templates, request objects, and other niceties. -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. +The Pyramid debug toolbar is a "tween", as is the ``pyramid_tm`` transaction +manager. Example: :ref:`registering_tweens`. -View response adapters -~~~~~~~~~~~~~~~~~~~~~~ +Return What You Want From Your Views +------------------------------------ -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: +We have shown before (in the :doc:`introduction`) how using a :term:`renderer` +allows you to return simple Python dictionaries from your view code. But some +frameworks allow you to return strings or tuples from view callables. +When frameworks allow for this, code looks slightly prettier, because there are +fewer imports, and less code. For example, compare this: .. code-block:: python :linenos: + from pyramid.response import Response + def aview(request): - return "Hello world!" + return Response("Hello world!") To this: .. code-block:: python :linenos: - from pyramid.response import Response - def aview(request): - return Response("Hello world!") + return "Hello world!" -The former is "prettier", right? +Nicer to look at, 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: +Out of the box, Pyramid will raise an exception if you try to run the second +example above. After all, a view should return a response, and "explicit is +better than implicit". + +But if you're a developer who likes the aesthetics of simplicity, Pyramid +provides an way to support this sort of thing, the *response adapter*: .. code-block:: python :linenos: @@ -217,12 +224,13 @@ values such aesthetics, we have an easy way to allow for this sort of thing: response.content_type = 'text/html' return response +A new response adapter is registered in configuration: + 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.: +With that, you may return strings from any of your view callables, e.g.: .. code-block:: python :linenos: @@ -233,8 +241,8 @@ strings from any of your view callables, e.g.: 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: +You can even use a response adapter to allow for custom content types and +return codes: .. code-block:: python :linenos: @@ -259,7 +267,7 @@ status code? No fear: 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: +With this, both of these views will work as expected: .. code-block:: python :linenos: @@ -270,20 +278,17 @@ Once this is done, both of these view callables will work: 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 -~~~~~~~~~~~~~~~~~~~~~~~~ +Use Global Response Objects +--------------------------- -"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: +Views have to return responses. But constructing them in view code is a chore. +And perhaps registering a response adapter as shown above is just too much +work. :app:`Pyramid` provides a global response object as well. You can just +use it directly, if you prefer: .. code-block:: python :linenos: @@ -298,17 +303,18 @@ say. Fine. Be that way: See also :ref:`request_response_attr`. -Automating repetitive configuration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Extend Configuration +-------------------- + +Perhaps the :app:`Pyramid` configurator's syntax feels a bit verbose to you. Or +possibly you would like to add a feature to configuration without asking the +core developers to change Pyramid itself? -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: +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 get +rid of the boring with existing shortcuts, but let's say that this is a case +where there is no such shortcut: .. code-block:: python :linenos: @@ -352,26 +358,26 @@ the Configurator object: 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. +Much better! -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 +You can share your configuration code with others, too. Package it up and call +: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 -~~~~~~~~~~~~~~~~~~~~~~~~~~ +Introspect Your Application +--------------------------- -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. +If you're building a large, pluggalbe system, it's useful to be able to get a +list of what has been plugged in *at application runtime*. For example, you +might want to show users a set of tabs at the top of the screen based on a list +of the views they registered. -This is possible using Pyramid's :term:`introspector`. +:app:`Pyramid` provides an :term:`introspector` for just this purpose. Here's an example of using Pyramid's introspector from within a view callable: -- cgit v1.2.3 From c5538ea907990a19994c9d9acda92e602a8769c4 Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Mon, 22 May 2017 16:54:17 -0700 Subject: Also replace script tags appear everywhere --- docs/quick_tour/logging/hello_world/templates/layout.jinja2 | 8 ++++---- docs/quick_tour/package/hello_world/templates/layout.jinja2 | 8 ++++---- docs/quick_tour/sessions/hello_world/templates/layout.jinja2 | 8 ++++---- docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 | 8 ++++---- .../cookiecutters/cc_starter/templates/layout.jinja2 | 8 ++++---- docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt | 8 ++++---- docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt | 8 ++++---- docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt | 8 ++++---- .../wiki/src/basiclayout/tutorial/templates/mytemplate.pt | 8 ++++---- .../wiki/src/installation/tutorial/templates/mytemplate.pt | 8 ++++---- docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt | 8 ++++---- docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt | 8 ++++---- docs/tutorials/wiki/src/tests/tutorial/templates/login.pt | 8 ++++---- docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt | 8 ++++---- docs/tutorials/wiki/src/tests/tutorial/templates/view.pt | 8 ++++---- docs/tutorials/wiki/src/views/tutorial/templates/edit.pt | 8 ++++---- docs/tutorials/wiki/src/views/tutorial/templates/view.pt | 8 ++++---- .../wiki2/src/authentication/tutorial/templates/layout.jinja2 | 8 ++++---- .../wiki2/src/authorization/tutorial/templates/layout.jinja2 | 8 ++++---- .../wiki2/src/basiclayout/tutorial/templates/layout.jinja2 | 8 ++++---- .../wiki2/src/installation/tutorial/templates/layout.jinja2 | 8 ++++---- docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 | 8 ++++---- docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 | 8 ++++---- docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 | 8 ++++---- 24 files changed, 96 insertions(+), 96 deletions(-) diff --git a/docs/quick_tour/logging/hello_world/templates/layout.jinja2 b/docs/quick_tour/logging/hello_world/templates/layout.jinja2 index 916127267..c82cac915 100644 --- a/docs/quick_tour/logging/hello_world/templates/layout.jinja2 +++ b/docs/quick_tour/logging/hello_world/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/quick_tour/package/hello_world/templates/layout.jinja2 b/docs/quick_tour/package/hello_world/templates/layout.jinja2 index 916127267..c82cac915 100644 --- a/docs/quick_tour/package/hello_world/templates/layout.jinja2 +++ b/docs/quick_tour/package/hello_world/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 b/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 index 916127267..c82cac915 100644 --- a/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 +++ b/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 b/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 index 4607eb11f..b84b3ec0e 100644 --- a/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 +++ b/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 b/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 index 20da74879..3aed0a123 100644 --- a/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 +++ b/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt index 19adc5932..6073c706c 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt @@ -19,8 +19,8 @@ @@ -67,7 +67,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt index 02f7038fe..66b8cf685 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt @@ -19,8 +19,8 @@ @@ -69,7 +69,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt index 17a715b50..f6a234d8f 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt @@ -19,8 +19,8 @@ @@ -67,7 +67,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt index 3ac122711..4ffc0eb22 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt @@ -18,8 +18,8 @@ @@ -59,7 +59,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt index 3ac122711..4ffc0eb22 100644 --- a/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt @@ -18,8 +18,8 @@ @@ -59,7 +59,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt index 3ac122711..4ffc0eb22 100644 --- a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt @@ -18,8 +18,8 @@ @@ -59,7 +59,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt index 19adc5932..6073c706c 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt @@ -19,8 +19,8 @@ @@ -67,7 +67,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt index 02f7038fe..66b8cf685 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt @@ -19,8 +19,8 @@ @@ -69,7 +69,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt index f8cbe2e2c..6c3809250 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt @@ -18,8 +18,8 @@ @@ -61,7 +61,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt index 17a715b50..f6a234d8f 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt @@ -19,8 +19,8 @@ @@ -67,7 +67,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt index b23f45d56..71a15d48c 100644 --- a/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt @@ -19,8 +19,8 @@ @@ -63,7 +63,7 @@ - - + + diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/view.pt b/docs/tutorials/wiki/src/views/tutorial/templates/view.pt index 5caaef4af..e91f0b8d5 100644 --- a/docs/tutorials/wiki/src/views/tutorial/templates/view.pt +++ b/docs/tutorials/wiki/src/views/tutorial/templates/view.pt @@ -19,8 +19,8 @@ @@ -64,7 +64,7 @@ - - + + diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/authentication/tutorial/templates/layout.jinja2 index 44d14304e..bd5185800 100644 --- a/docs/tutorials/wiki2/src/authentication/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/authentication/tutorial/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 index 44d14304e..bd5185800 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 index 1f658c834..e29413cf9 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 index 1f658c834..e29413cf9 100644 --- a/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 index 1f658c834..e29413cf9 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 index 44d14304e..bd5185800 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -58,7 +58,7 @@ - - + + diff --git a/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 index 7575de8a7..f2c4b50f2 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 @@ -18,8 +18,8 @@ @@ -49,7 +49,7 @@ - - + + -- cgit v1.2.3 From 50d216a549bc848f411769690d722d367c91fdb4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 22 May 2017 17:49:58 -0700 Subject: add change note --- CHANGES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 1a7cfaf0b..c21508a70 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -5,6 +5,10 @@ unreleased new message suggests alternatives based on the list of known predicates. See https://github.com/Pylons/pyramid/pull/3054 +- Added integrity attributes for JavaScripts in cookiecutters, scaffolds, and + resulting source files in tutorials. + See https://github.com/Pylons/pyramid/issues/2548 + 1.9a2 (2017-05-09) ================== -- cgit v1.2.3 From ed7bad6862f5b495e3c6b55007822813d021248b Mon Sep 17 00:00:00 2001 From: Chris Morales Date: Tue, 23 May 2017 11:57:47 -0700 Subject: pyramid_tm.explicit_manager set in the configuration. --- pyramid/scaffolds/alchemy/+package+/models/__init__.py_tmpl | 1 + pyramid/scaffolds/zodb/+package+/__init__.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/pyramid/scaffolds/alchemy/+package+/models/__init__.py_tmpl b/pyramid/scaffolds/alchemy/+package+/models/__init__.py_tmpl index f626d1ef0..521816ce7 100644 --- a/pyramid/scaffolds/alchemy/+package+/models/__init__.py_tmpl +++ b/pyramid/scaffolds/alchemy/+package+/models/__init__.py_tmpl @@ -57,6 +57,7 @@ def includeme(config): """ settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') diff --git a/pyramid/scaffolds/zodb/+package+/__init__.py b/pyramid/scaffolds/zodb/+package+/__init__.py index f2a86df47..a956d0faf 100644 --- a/pyramid/scaffolds/zodb/+package+/__init__.py +++ b/pyramid/scaffolds/zodb/+package+/__init__.py @@ -12,6 +12,8 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(root_factory=root_factory, settings=settings) + settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_chameleon') config.add_static_view('static', 'static', cache_max_age=3600) config.scan() -- cgit v1.2.3 From 07e0e15fdafb28843a92cd03681a07aa652008a9 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 23 May 2017 12:50:58 -0700 Subject: allow the execution policy to perform a last-ditch effort to render an exception view --- pyramid/router.py | 14 ++++++++++++-- pyramid/tests/test_router.py | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/pyramid/router.py b/pyramid/router.py index 8b7b7b6bc..7f3f9fbea 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -1,3 +1,4 @@ +import sys from zope.interface import ( implementer, providedBy, @@ -24,6 +25,7 @@ from pyramid.events import ( BeforeTraversal, ) +from pyramid.compat import reraise from pyramid.httpexceptions import HTTPNotFound from pyramid.request import Request from pyramid.view import _call_view @@ -252,7 +254,15 @@ class Router(object): response = self.execution_policy(environ, self) return response(environ, start_response) - def default_execution_policy(environ, router): request = router.make_request(environ) - return router.invoke_request(request) + try: + return router.invoke_request(request) + except Exception: + exc_info = sys.exc_info() + try: + return request.invoke_exception_view(exc_info) + except HTTPNotFound: + reraise(*exc_info) + finally: + del exc_info # avoid local ref cycle diff --git a/pyramid/tests/test_router.py b/pyramid/tests/test_router.py index a5da5c627..bd023824c 100644 --- a/pyramid/tests/test_router.py +++ b/pyramid/tests/test_router.py @@ -1284,6 +1284,33 @@ class TestRouter(unittest.TestCase): self.assertEqual(resp.status_code, 200) self.assertEqual(resp.body, b'foo') + def test_execution_policy_handles_exception(self): + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IExceptionViewClassifier + from pyramid.interfaces import IRequest + class Exception1(Exception): + pass + class Exception2(Exception): + pass + req_iface = self._registerRouteRequest('foo') + self._connectRoute('foo', 'archives/:action/:article', None) + view = DummyView(DummyResponse(), raise_exception=Exception1) + self._registerView(view, '', IViewClassifier, req_iface, None) + exception_view1 = DummyView(DummyResponse(), + raise_exception=Exception2) + self._registerView(exception_view1, '', IExceptionViewClassifier, + IRequest, Exception1) + response = DummyResponse() + response.app_iter = ["Hello, world"] + exception_view2 = DummyView(response) + self._registerView(exception_view2, '', IExceptionViewClassifier, + IRequest, Exception2) + environ = self._makeEnviron(PATH_INFO='/archives/action1/article1') + start_response = DummyStartResponse() + router = self._makeOne() + result = router(environ, start_response) + self.assertEqual(result, ["Hello, world"]) + class DummyPredicate(object): def __call__(self, info, request): return True -- cgit v1.2.3 From dda9fa85a8132ae3a18ff0b09e902ee6057430d1 Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Tue, 23 May 2017 13:53:10 -0700 Subject: When invoking an exception view, push the new threadlocals This way when calling the threadlocal get_current_request() you get the same request object as the one that was passed to the view. --- pyramid/tests/test_view.py | 22 ++++++++++++++++++++++ pyramid/threadlocal.py | 2 +- pyramid/view.py | 40 ++++++++++++++++++++++++++++------------ 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py index 2061515b3..9f02b1352 100644 --- a/pyramid/tests/test_view.py +++ b/pyramid/tests/test_view.py @@ -790,6 +790,8 @@ class TestViewMethodsMixin(unittest.TestCase): def test_it_supports_alternate_requests(self): def exc_view(exc, request): self.assertTrue(request is other_req) + from pyramid.threadlocal import get_current_request + self.assertTrue(get_current_request() is other_req) return DummyResponse(b'foo') self.config.add_view(exc_view, context=RuntimeError) request = self._makeOne() @@ -816,6 +818,26 @@ class TestViewMethodsMixin(unittest.TestCase): else: # pragma: no cover self.fail() + def test_it_raises_if_no_registry(self): + def exc_view(exc, request): + return DummyResponse(b'foo') + self.config.add_view(exc_view, context=RuntimeError) + request = self._makeOne() + del request.registry + from pyramid.threadlocal import manager + manager.push({'registry': None, 'request': request}) + try: + raise RuntimeError + except RuntimeError: + try: + request.invoke_exception_view() + except RuntimeError as e: + self.assertEqual(e.args[0], "Unable to retrieve registry") + else: # pragma: no cover + self.fail() + finally: + manager.pop() + def test_it_supports_alternate_exc_info(self): def exc_view(exc, request): self.assertTrue(request.exc_info is exc_info) diff --git a/pyramid/threadlocal.py b/pyramid/threadlocal.py index 638f7b7b0..9429fe953 100644 --- a/pyramid/threadlocal.py +++ b/pyramid/threadlocal.py @@ -31,7 +31,7 @@ class ThreadLocalManager(threading.local): self.stack[:] = [] def defaults(): - return {'request':None, 'registry':global_registry} + return {'request': None, 'registry': global_registry} manager = ThreadLocalManager(default=defaults) diff --git a/pyramid/view.py b/pyramid/view.py index 0c1b8cd97..14c8c029e 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -28,7 +28,11 @@ from pyramid.httpexceptions import ( default_exceptionresponse_view, ) -from pyramid.threadlocal import get_current_registry +from pyramid.threadlocal import ( + get_current_registry, + manager, + ) + from pyramid.util import hide_attrs _marker = object() @@ -675,8 +679,13 @@ class ViewMethodsMixin(object): registry = getattr(request, 'registry', None) if registry is None: registry = get_current_registry() + + if registry is None: + raise RuntimeError("Unable to retrieve registry") + if exc_info is None: exc_info = sys.exc_info() + exc = exc_info[1] attrs = request.__dict__ context_iface = providedBy(exc) @@ -690,17 +699,24 @@ class ViewMethodsMixin(object): # we use .get instead of .__getitem__ below due to # https://github.com/Pylons/pyramid/issues/700 request_iface = attrs.get('request_iface', IRequest) - response = _call_view( - registry, - request, - exc, - context_iface, - '', - view_types=None, - view_classifier=IExceptionViewClassifier, - secure=secure, - request_iface=request_iface.combined, - ) + + try: + if request is not self: + manager.push({'request': request, 'registry': registry}) + + response = _call_view( + registry, + request, + exc, + context_iface, + '', + view_types=None, + view_classifier=IExceptionViewClassifier, + secure=secure, + request_iface=request_iface.combined, + ) + finally: + manager.pop() if response is None: raise HTTPNotFound -- cgit v1.2.3 From 3bb3c6e18bc94856b8c08907dfea5d1ce8217754 Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Tue, 23 May 2017 13:59:55 -0700 Subject: Make coverage happy again --- pyramid/tests/test_view.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py index 9f02b1352..a9ce2234d 100644 --- a/pyramid/tests/test_view.py +++ b/pyramid/tests/test_view.py @@ -819,9 +819,6 @@ class TestViewMethodsMixin(unittest.TestCase): self.fail() def test_it_raises_if_no_registry(self): - def exc_view(exc, request): - return DummyResponse(b'foo') - self.config.add_view(exc_view, context=RuntimeError) request = self._makeOne() del request.registry from pyramid.threadlocal import manager -- cgit v1.2.3 From d8388838022aa5bafe78c8ba6949bc52c2968799 Mon Sep 17 00:00:00 2001 From: Chris Morales Date: Tue, 23 May 2017 15:01:16 -0700 Subject: updated references for the models that have references for the config.settings --- docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py | 2 +- docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py | 1 + docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py | 1 + docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py | 1 + docs/tutorials/wiki2/src/models/tutorial/models/__init__.py | 1 + docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py | 1 + docs/tutorials/wiki2/src/views/tutorial/models/__init__.py | 1 + 7 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py b/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py index 339326758..e6eb98fbd 100644 --- a/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py +++ b/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py @@ -57,7 +57,7 @@ def includeme(config): """ settings = config.get_settings() - + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py index 8147052ad..cd8347ccd 100644 --- a/docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py @@ -58,6 +58,7 @@ def includeme(config): """ settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py index 5ca037787..ae575691c 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py @@ -57,6 +57,7 @@ def includeme(config): """ settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') diff --git a/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py index 5ca037787..ae575691c 100644 --- a/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py @@ -57,6 +57,7 @@ def includeme(config): """ settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') diff --git a/docs/tutorials/wiki2/src/models/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/models/__init__.py index 8147052ad..cd8347ccd 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/models/tutorial/models/__init__.py @@ -58,6 +58,7 @@ def includeme(config): """ settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py index 8147052ad..cd8347ccd 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py @@ -58,6 +58,7 @@ def includeme(config): """ settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') diff --git a/docs/tutorials/wiki2/src/views/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/models/__init__.py index 8147052ad..cd8347ccd 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/views/tutorial/models/__init__.py @@ -58,6 +58,7 @@ def includeme(config): """ settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') -- cgit v1.2.3 From 81fa04cc4e59ce01bb0abbabfefb8c25cf43eb78 Mon Sep 17 00:00:00 2001 From: Chris Morales Date: Tue, 23 May 2017 17:53:09 -0700 Subject: updated the emphasis in the tutorial docs for the definingmodels.rst --- docs/tutorials/wiki2/definingmodels.rst | 2 +- docs/tutorials/wiki2/src/models/tutorial/__init__.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst index 5cebb943c..801b56eb4 100644 --- a/docs/tutorials/wiki2/definingmodels.rst +++ b/docs/tutorials/wiki2/definingmodels.rst @@ -153,7 +153,7 @@ the following: .. literalinclude:: src/models/tutorial/models/__init__.py :linenos: :language: py - :emphasize-lines: 8,9 + :emphasize-lines: 10,11 Here we align our imports with the names of the models, ``Page`` and ``User``. diff --git a/docs/tutorials/wiki2/src/models/tutorial/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/__init__.py index 4dab44823..7654fc808 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/models/tutorial/__init__.py @@ -5,6 +5,8 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(settings=settings) + settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_jinja2') config.include('.models') config.include('.routes') -- cgit v1.2.3 From f20a018167a19d17527d40c027e6f9045749f065 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 23 May 2017 20:21:07 -0700 Subject: fixes per code review, Thanks @stevepiercy. --- docs/glossary.rst | 33 +++- docs/narr/advanced-features.rst | 418 ++++++++++++++++++++++++++++++++++++++++ docs/narr/advfeatures.rst | 399 -------------------------------------- docs/narr/introduction.rst | 2 +- 4 files changed, 451 insertions(+), 401 deletions(-) create mode 100644 docs/narr/advanced-features.rst delete mode 100644 docs/narr/advfeatures.rst diff --git a/docs/glossary.rst b/docs/glossary.rst index 2e5276554..9031ede04 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -751,7 +751,7 @@ Glossary :ref:`Venusian` is a library which allows framework authors to defer decorator actions. Instead of taking actions when a function (or class) decorator is executed - at import time, the action usually taken by the decorator is + at :term:`import time`, the action usually taken by the decorator is deferred until a separate "scan" phase. :app:`Pyramid` relies on Venusian to provide a basis for its :term:`scan` feature. @@ -1172,3 +1172,34 @@ Glossary A policy which wraps the :term:`router` by creating the request object and sending it through the request pipeline. See :class:`pyramid.config.Configurator.set_execution_policy`. + + singleton + A singleton is a class which will only ever have one instance. + As there is only one, it is shared by all other code. + This makes it an example of :term:`global state`. + + Using a singleton is `considered a poor design choice. `_ + As :term:`mutable` global state, it can be changed by any other code, + and so the values it represents cannot be reasoned about or tested properly. + + global state + A set of values that are available to the entirety of a program. + + mutable + In Python, a value is mutable if it can be changed *in place*. + The Python ``list`` and ``dict`` types are mutable. + When a value is added to or removed from an instance of either, the original object remains. + The opposite of mutable is :term:`immutable`. + + immutable + In Python, a value is immutable if it cannot be changed. + The Python ``str``, ``int``, and ``tuple`` data types are all ``immutable``. + + import time + In Python, the moment when a module is referred to in an ``import`` statement. + At this moment, all statements in that module at the module scope (at the left margin) are executed. + It is a bad design decision to put statements in a Python module that have :term:`side effect`\ s at import time. + + side effect + A statement or function has a side effect when it changes a value outside its own scope. + Put another way, if one can observe the change made by a function from outside that function, it has a side effect. diff --git a/docs/narr/advanced-features.rst b/docs/narr/advanced-features.rst new file mode 100644 index 000000000..a97d4f3b1 --- /dev/null +++ b/docs/narr/advanced-features.rst @@ -0,0 +1,418 @@ +Advanced :app:`Pyramid` Design Features +======================================= + +Pyramid has been built from the ground up to avoid the problems that other +frameworks can suffer. + + +You Don't Need Singletons +------------------------- + +Have you ever struggled with parameterizing Django's ``settings.py`` file for +multiple installations of the same Django application? Have you ever needed to +monkey-patch a framework fixture to get it to behave properly for your +use case? Have you ever tried to deploy your application using an asynchronous +server and failed? + +All these problems are symptoms of :term:`mutable` :term:`global state`, also +known as :term:`import time` :term:`side effect`\ s and arise from the use of +:term:`singleton` data structures. + +:app:`Pyramid` is written so that you don't run into these types of problems. +It is even possible to run multiple copies of the *same* :app:`Pyramid` +application configured differently within a single Python process. This makes +running :app:`Pyramid` in shared hosting environments a snap. + +Simplify your View Code with Predicates +--------------------------------------- + +How many times have you found yourself beginning the logic of your view code +with something like this: + +.. code-block:: python + + if request.user.is_authenticated: + # do one thing + else: + # do something else + +Unlike many other systems, :app:`Pyramid` allows you to associate more than one view +with a single route. For example, you can create a route with the pattern +``/items`` and when the route is matched, you can send the request to one view +if the request method is GET, another view if the request method is POST, and +so on. + +:app:`Pyramid` uses a system of :term:`view predicate`\ s to allow this. +Matching the request method is one basic thing you can do with a +:term:`view predicate`. You can also associate views with other request +parameters, such as elements in the query string, the Accept header, whether +the request is an AJAX (XHR) request or not, and lots of other things. + +For our example above, you can do this instead: + +.. code-block:: python + + @view_config(route_name="items", effective_principals=pyramid.security.Authenticated) + def auth_view(request): + # do one thing + + @view_config(route_name="items") + def anon_view(request): + # do something else + +This approach allows you to develop view code that is simpler, more easily +understandable, and more directly testable. + +.. seealso:: + + See also :ref:`view_configuration_parameters`. + +Stop Worrying About Transactions +-------------------------------- + +:app:`Pyramid`\ 's :term:`cookiecutter`\ s render projects that include a *transaction +management* system. When you use this system, you can stop worrying about when +to commit your changes, :app:`Pyramid` handles it for you. The system will +commit at the end of a request or abort if there was an exception. + +Why is that a good thing? Imagine a situation where you manually commit a +change to your persistence layer. It's very likely that other framework code +will run *after* your changes are done. If an error happens in that other code, +you can easily wind up with inconsistent data if you're not extremely careful. + +Using transaction management saves you from needing to think about this. Either +a request completes successfully and all changes are committed, or it does +not and all changes are aborted. + +Pyramid's transaction management is extendable, so you can synchronize commits +between multiple databases or databases of different kinds. It also allows you +to do things like conditionally send email if a transaction is committed, but +otherwise keep quiet. + +.. seealso:: + + See also :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements + anywhere in application code). + +Stop Worrying About Configuration +--------------------------------- + +When a system is small, it's reasonably easy to keep it all in your head. But +as systems grow large, configuration grows more complex. Your app may grow to +have hundreds or even thousands of configuration statements. + +:app:`Pyramid`\ 's configuration system keeps track of each of your statements. If you +accidentally add two that are identical, or :app:`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. + +:app:`Pyramid`\ 's configuration system is not dumb though. If you use the +:meth:`~pyramid.config.Configurator.include` system, it can automatically +resolve conflicts on its own. More local statements are preferred over less +local ones. So you can intelligently factor large systems into smaller ones. + +.. seealso:: + + See also :ref:`conflict_detection`. + +Compose Powerful Apps From Simple Parts +---------------------------------------- + +Speaking of the :app:`Pyramid` structured "include" mechanism (see +:meth:`~pyramid.config.Configurator.include`), it allows you to compose complex +applications from multiple, simple Python packages. All the configuration +statements that can be performed in your main :app:`Pyramid` application can also be +used in included packages. You can add views, routes, and subscribers, and even +set authentication and authorization policies. + +If you need, you can extend or override the configuration of an existing +application by including its configuration in your own and then modifying it. + + +For example, if you want to reuse an existing application that already has a +bunch of routes, you can just use the ``include`` statement with a +``route_prefix``. All the routes of that application will be availabe, prefixed +as you requested: + +.. 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.package', route_prefix='/somethingelse') + +.. seealso:: + + See also :ref:`including_configuration` and + :ref:`building_an_extensible_app`. + +Authenticate Users Your Way +--------------------------- + +:app:`Pyramid` ships with prebuilt, well-tested authentication and authorization +schemes out of the box. Using a scheme is a matter of configuration. So if you +need to change approaches later, you need only update your configuration. + +In addition, the system that handles authentication and authorization is +flexible and pluggable. If you want to use another security add-on, or define +your own, you can. And again, you need only update your application +configuration to make the change. + +.. seealso:: + + See also :ref:`enabling_authorization_policy`. + +Build Trees of Resources +------------------------ + +:app:`Pyramid` supports :term:`traversal`, a way of mapping URLs to a concrete +:term:`resource tree`. If your application naturally consists of an arbitrary +heirarchy of different types of content (like a CMS or a Document Management +System), traversal is for you. If you have a requirement for a highly granular +security model ("Jane can edit documents in *this* folder, but not *that* +one"), traversal can be a powerful approach. + +.. seealso:: + + See also :ref:`hello_traversal_chapter` and + :ref:`much_ado_about_traversal_chapter`. + +Take Action on Each Request with Tweens +--------------------------------------- + +:app:`Pyramid` has a system for applying an arbitrary action to each request or +response called a :term:`tween`. The system is similar in concept to WSGI +:term:`middleware`, but can be more useful since :term:`tween`\ s run in the +:app:`Pyramid` context, and have access to templates, request objects, and +other niceties. + +The :app:`Pyramid` debug toolbar is a :term:`tween`, as is the ``pyramid_tm`` +transaction manager. + +.. seealso:: + + See also :ref:`registering_tweens`. + +Return What You Want From Your Views +------------------------------------ + +We have shown elsewhere (in the :doc:`introduction`) how using a :term:`renderer` +allows you to return simple Python dictionaries from your view code. But some +frameworks allow you to return strings or tuples from view callables. +When frameworks allow for this, code looks slightly prettier because there are +fewer imports and less code. For example, compare this: + +.. code-block:: python + :linenos: + + from pyramid.response import Response + + def aview(request): + return Response("Hello world!") + +To this: + +.. code-block:: python + :linenos: + + def aview(request): + return "Hello world!" + +Nicer to look at, right? + +Out of the box, :app:`Pyramid` will raise an exception if you try to run the +second example above. After all, a view should return a response, and "explicit +is better than implicit". + +But if you're a developer who likes the aesthetics of simplicity, +:app:`Pyramid` provides an way to support this sort of thing, the +:term:`response adapter`\ : + +.. 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 + +A new response adapter is registered in configuration: + + if __name__ == '__main__': + config = Configurator() + config.add_response_adapter(string_response_adapter, basestring) + +With that, you may 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!" + +You can even use a :term:`response adapter` to allow for custom content types +and return codes: + +.. 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) + +With this, both of these views will work as expected: + +.. code-block:: python + :linenos: + + def aview(request): + return "Hello world!" + + def anotherview(request): + return (403, 'text/plain', "Forbidden") + +.. seealso:: + + See also :ref:`using_iresponse`. + +Use Global Response Objects +--------------------------- + +Views have to return responses. But constructing them in view code is a chore. +And perhaps registering a :term:`response adapter` as shown above is just too +much work. :app:`Pyramid` provides a global response object as well. You can +use it directly, if you prefer: + +.. 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`. + +Extend Configuration +-------------------- + +Perhaps the :app:`Pyramid` configurator's syntax feels a bit verbose to you. Or +possibly you would like to add a feature to configuration without asking the +core developers to change :app:`Pyramid` itself? + +You can extend :app:`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 get +rid of the boring with 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 :app:`Pyramid` +:term:`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 :term:`configurator` object: + +.. code-block:: python + :linenos: + + config.add_route('xhr_route', '/xhr/{id}') + config.add_protected_xhr_views('my.package') + +Much better! + +You can share your configuration code with others, too. Package it up and call +: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`. + +Introspect Your Application +--------------------------- + +If you're building a large, pluggalbe system, it's useful to be able to get a +list of what has been plugged in *at application runtime*. For example, you +might want to show users a set of tabs at the top of the screen based on a list +of the views they registered. + +:app:`Pyramid` provides an :term:`introspector` for just this purpose. + +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`. \ No newline at end of file diff --git a/docs/narr/advfeatures.rst b/docs/narr/advfeatures.rst deleted file mode 100644 index 5c45cf61a..000000000 --- a/docs/narr/advfeatures.rst +++ /dev/null @@ -1,399 +0,0 @@ -Advanced :app:`Pyramid` Design Features -======================================= - -Pyramid has been built from the ground up to avoid the problems that other -frameworks can suffer. - - -You Don't Need Singletons -------------------------- - -Have you ever struggled with parametrizing Django's ``settings.py`` file for -multiple installations of the same Django application? Have you ever needed to -monkey-patch a framework fixture to get it to behave properly for your -use-case? Have you ever tried to deploy your application using an asynchronous -server and failed? - -All these problems are symptoms of "mutable global state", also known as -"import-time side effects" and arise from the use of "singleton" data structures. - -:app:`Pyramid` is written so that you don't run into these types of problems. -It is even possible to run multiple copies of the *same* :app:`Pyramid` -application configured differently within a single Python process. This makes -running Pyramid in shared hosting environments a snap. - -Simplify your View Code with Predicates ---------------------------------------- - -How many times have you found yourself beginning the logic of your view code -with something like this:: - - if request.user.is_authenticated: - # do one thing - else: - # do something else - -Unlike many other systems, Pyramid allows you to associate more than one view -with a single route. For example, you can create a route with the pattern -``/items`` and when the route is matched, you can send the request to one view -if the request method is GET, another view if the request method is POST, and -so on. - -:app:`Pyramid` uses a system of "view predicates" to allow this. Matching the -request method is one basic thing you can do with a view predicate. You can -also associate views with other request parameters, such as elements in the -query string, the Accept header, whether the request is an XHR request or not, -and lots of other things. - -For our example above, you can do this instead:: - - @view_config(route_name="items", effective_principals=pyramid.security.Authenticated) - def auth_view(request): - # do one thing - - @view_config(route_name="items") - def anon_view(request): - # do something else - -This approach allows you to develop view code that is simpler, more easily -understandable, and more directly testable. - -Example: :ref:`view_configuration_parameters`. - -Stop Worrying About Transactions --------------------------------- - -Pyramid's :term:`scaffold` system renders projects that include a *transaction -management* system. When you use this system, you can stop worrying about when -to commit your changes, :app:`Pyramid` handles it for you. The system will -commit at the end of a request or aborts if there was an exception. - -Why is that a good thing? Imagine a situation where you manually commit a -change to your persistence layer. It's very likely that other framework code -will run *after* your changes are done. If an error happens in that other code, -you can easily wind up with inconsistent data if you're not extremely careful. - -Using transaction management saves you from needing to think about this. Either -a request completes successfully, and all changes are committed, or it does -not, and all changes are aborted. - -Pyramid's transaction management is extendable, so you can synchronize commits -between multiple databases, or databases of different kinds. It also allows you -to do things like conditionally send email if a transaction commits, but -otherwise keep quiet. - -Example: :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements -anywhere in application code). - -Stop Worrying About Configuration ---------------------------------- - -When a system is small, it's reasonably easy to keep it all in your head. But -as systems grow large, configuration grows more complex. Your app may grow to -have hundreds or even thousands of configuration statements. - -Pyramid's configuration system keeps track of your configuration. If you -accidentally add two that are identical, or Pyramid can't make sense out of -what it would mean to have both statements active at the same time, it will -complain loudly at startup time. - -Pyramid's configuration system is not dumb though. If you use the confugration -:meth:`~pyramid.config.Configurator.include` system, it can automatically -resolve conflicts on its own. "More local" statements are preferred over "less -local" ones. So you can intelligently factor large systems into smaller ones. - -Example: :ref:`conflict_detection`. - -Compose Powerful Apps From Simple Parts ----------------------------------------- - -Speaking of the :app:`Pyramid` structured "include" mechanism (see -:meth:`~pyramid.config.Configurator.include`), it allows you to compose complex -applications from multiple, simple Python packages. All the configuration -statements that can be performed in your "main" Pyramid application can also be -used in included packages. You can add views, routes, and subscribers, and even -set authentication and authorization policies. - -If you need, you can extend or override the configuration of an existing -application by including its configuration in your own and then modifying it. - - -For example, if you want to reuse an existing application that already has a -bunch of routes, you can just use the ``include`` statement with a -``route_prefix``. All the routes of that application will be availabe, prefixed -as you requested: - -.. 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.package', route_prefix='/somethingelse') - -.. seealso:: - - See also :ref:`including_configuration` and - :ref:`building_an_extensible_app`. - -Authenticate Users Your Way ---------------------------- - -:app:`Pyramid` ships with prebuilt well-tested authentication and authorization -schemes out of the box. Using a scheme is a matter of configuration. So if you -need to change approaches later, you need only update your configuration. - -In addition, the system that handles authentication an authorization is -flexible and pluggable. If you want to use another security add-on, or define -your own, you can. And again, you need only update your application -configuration to make the change. - -Example: :ref:`enabling_authorization_policy`. - -Build Trees of Resources ------------------------- - -:app:`Pyramid` supports :term:`Traversal`, a way of mapping URLs to a concrete -tree of resources. If your application naturally consists of an arbitrary -heirarchy of different types of content (like a CMS or a Document Management -System), traversal is for you. If you have a requirement for a highly granular -security model ("Jane can edit documents in *this* folder, but not *that* -one"), traversal can be a powerful approach. - -Examples: :ref:`hello_traversal_chapter` and -:ref:`much_ado_about_traversal_chapter`. - -Take Action on Each Request with Tweens ---------------------------------------- - -Pyramid has a system for applying arbitrary actions to each request or response -called *tweens*. The system is similar in concept to WSGI :term:`middleware`, -but can be more useful since they run in the Pyramid context, and have access -to templates, request objects, and other niceties. - -The Pyramid debug toolbar is a "tween", as is the ``pyramid_tm`` transaction -manager. - -Example: :ref:`registering_tweens`. - -Return What You Want From Your Views ------------------------------------- - -We have shown before (in the :doc:`introduction`) how using a :term:`renderer` -allows you to return simple Python dictionaries from your view code. But some -frameworks allow you to return strings or tuples from view callables. -When frameworks allow for this, code looks slightly prettier, because there are -fewer imports, and less code. For example, compare this: - -.. code-block:: python - :linenos: - - from pyramid.response import Response - - def aview(request): - return Response("Hello world!") - -To this: - -.. code-block:: python - :linenos: - - def aview(request): - return "Hello world!" - -Nicer to look at, right? - -Out of the box, Pyramid will raise an exception if you try to run the second -example above. After all, a view should return a response, and "explicit is -better than implicit". - -But if you're a developer who likes the aesthetics of simplicity, Pyramid -provides an way to support this sort of thing, the *response adapter*: - -.. 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 - -A new response adapter is registered in configuration: - - if __name__ == '__main__': - config = Configurator() - config.add_response_adapter(string_response_adapter, basestring) - -With that, you may 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!" - -You can even use a response adapter to allow for custom content types and -return codes: - -.. 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) - -With this, both of these views will work as expected: - -.. code-block:: python - :linenos: - - def aview(request): - return "Hello world!" - - def anotherview(request): - return (403, 'text/plain', "Forbidden") - -.. seealso:: - - See also :ref:`using_iresponse`. - -Use Global Response Objects ---------------------------- - -Views have to return responses. But constructing them in view code is a chore. -And perhaps registering a response adapter as shown above is just too much -work. :app:`Pyramid` provides a global response object as well. You can just -use it directly, if you prefer: - -.. 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`. - -Extend Configuration --------------------- - -Perhaps the :app:`Pyramid` configurator's syntax feels a bit verbose to you. Or -possibly you would like to add a feature to configuration without asking the -core developers to change Pyramid itself? - -You can extend Pyramid's :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 get -rid of the boring with 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') - -Much better! - -You can share your configuration code with others, too. Package it up and call -: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`. - -Introspect Your Application ---------------------------- - -If you're building a large, pluggalbe system, it's useful to be able to get a -list of what has been plugged in *at application runtime*. For example, you -might want to show users a set of tabs at the top of the screen based on a list -of the views they registered. - -:app:`Pyramid` provides an :term:`introspector` for just this purpose. - -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`. \ No newline at end of file diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 63bc164fb..a8d417250 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -492,7 +492,7 @@ that make it adaptable. Read more about them below. .. toctree:: :maxdepth: 2 - advfeatures + advanced-features -- cgit v1.2.3 From 44c621a5b8320848933024280dc491dec844c184 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 23 May 2017 21:07:42 -0700 Subject: finish polishing the advanced configuration doc per code review --- docs/narr/advanced-features.rst | 44 +++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/docs/narr/advanced-features.rst b/docs/narr/advanced-features.rst index a97d4f3b1..35841631f 100644 --- a/docs/narr/advanced-features.rst +++ b/docs/narr/advanced-features.rst @@ -245,6 +245,8 @@ But if you're a developer who likes the aesthetics of simplicity, A new response adapter is registered in configuration: +.. code-block:: python + if __name__ == '__main__': config = Configurator() config.add_response_adapter(string_response_adapter, basestring) @@ -325,15 +327,14 @@ use it directly, if you prefer: Extend Configuration -------------------- -Perhaps the :app:`Pyramid` configurator's syntax feels a bit verbose to you. Or -possibly you would like to add a feature to configuration without asking the -core developers to change :app:`Pyramid` itself? +Perhaps the :app:`Pyramid` configurator's syntax feels a bit verbose to you. +Or possibly you would like to add a feature to configuration +without asking the core developers to change :app:`Pyramid` itself? -You can extend :app:`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 get -rid of the boring with existing shortcuts, but let's say that this is a case -where there is no such shortcut: +You can extend :app:`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 get rid of the boring with existing shortcuts, +but let's say that this is a case where there is no such shortcut: .. code-block:: python :linenos: @@ -349,8 +350,8 @@ where there is no such shortcut: 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 :app:`Pyramid` -:term:`configurator` to automate some of the tedium away: +Pretty tedious right? +You can add a directive to the :app:`Pyramid` :term:`configurator` to automate some of the tedium away: .. code-block:: python :linenos: @@ -368,8 +369,8 @@ Pretty tedious right? You can add a directive to the :app:`Pyramid` 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 :term:`configurator` object: +Once that's done, +you can call the directive you've just added as a method of the :term:`configurator` object: .. code-block:: python :linenos: @@ -379,10 +380,11 @@ the :term:`configurator` object: Much better! -You can share your configuration code with others, too. Package it up and call -: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. +You can share your configuration code with others, too. +Add your code to a Python package. +Put the call to :meth:`~pyramid.config.Configurator.add_directive` in a function. +When other programmers install your package, +they'll be able to use your configuration by passing your function to a call to :meth:`~pyramid.config.Configurator.include`. .. seealso:: @@ -391,14 +393,14 @@ called when another user uses the Introspect Your Application --------------------------- -If you're building a large, pluggalbe system, it's useful to be able to get a -list of what has been plugged in *at application runtime*. For example, you -might want to show users a set of tabs at the top of the screen based on a list -of the views they registered. +If you're building a large, pluggable system, +it's useful to be able to get a list of what has been plugged in *at application runtime*. +For example, you might want to show users a set of tabs at the top of the screen +based on a list of the views they registered. :app:`Pyramid` provides an :term:`introspector` for just this purpose. -Here's an example of using Pyramid's introspector from within a view callable: +Here's an example of using :app:`Pyramid`\ 's :term:`introspector` from within a view: .. code-block:: python :linenos: -- cgit v1.2.3 From 5c6e8dfc9e9d91468b2a570eb763d146b8272d76 Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Wed, 24 May 2017 01:24:35 -0700 Subject: Add myself in the contributors list --- CONTRIBUTORS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 2e49a193a..cbee08d0d 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -300,3 +300,5 @@ Contributors - Aleph Melo, 2017/04/16 - Jeremy(Ching-Rui) Chen, 2017/04/19 + +- Fang-Pen Lin, 2017/05/22 -- cgit v1.2.3 From 7c20d8ca305c8cdcc72fd721054b9ed2b783f02d Mon Sep 17 00:00:00 2001 From: Chris Morales Date: Wed, 24 May 2017 14:51:25 -0700 Subject: updated documentation showing the pyramid_tm.explicit_manager being set --- docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py index 8147052ad..cd8347ccd 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py @@ -58,6 +58,7 @@ def includeme(config): """ settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') -- cgit v1.2.3 From e20ed7d9271d4e824a08d23be1ed942db0756a86 Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 25 May 2017 09:05:35 -0700 Subject: fix code indentation and unify style for all code blocks, per CR --- docs/narr/advanced-features.rst | 165 ++++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 81 deletions(-) diff --git a/docs/narr/advanced-features.rst b/docs/narr/advanced-features.rst index 35841631f..ae28ba41b 100644 --- a/docs/narr/advanced-features.rst +++ b/docs/narr/advanced-features.rst @@ -30,6 +30,7 @@ How many times have you found yourself beginning the logic of your view code with something like this: .. code-block:: python + :linenos: if request.user.is_authenticated: # do one thing @@ -51,6 +52,7 @@ the request is an AJAX (XHR) request or not, and lots of other things. For our example above, you can do this instead: .. code-block:: python + :linenos: @view_config(route_name="items", effective_principals=pyramid.security.Authenticated) def auth_view(request): @@ -135,15 +137,15 @@ bunch of routes, you can just use the ``include`` statement with a as you requested: .. code-block:: python - :linenos: + :linenos: - from pyramid.config import Configurator + from pyramid.config import Configurator - if __name__ == '__main__': - config = Configurator() - config.include('pyramid_jinja2') - config.include('pyramid_exclog') - config.include('some.other.package', route_prefix='/somethingelse') + if __name__ == '__main__': + config = Configurator() + config.include('pyramid_jinja2') + config.include('pyramid_exclog') + config.include('some.other.package', route_prefix='/somethingelse') .. seealso:: @@ -207,20 +209,20 @@ When frameworks allow for this, code looks slightly prettier because there are fewer imports and less code. For example, compare this: .. code-block:: python - :linenos: + :linenos: - from pyramid.response import Response + from pyramid.response import Response - def aview(request): - return Response("Hello world!") + def aview(request): + return Response("Hello world!") To this: .. code-block:: python - :linenos: + :linenos: - def aview(request): - return "Hello world!" + def aview(request): + return "Hello world!" Nicer to look at, right? @@ -233,71 +235,72 @@ But if you're a developer who likes the aesthetics of simplicity, :term:`response adapter`\ : .. code-block:: python - :linenos: + :linenos: - from pyramid.config import Configurator - from pyramid.response import Response + 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 + def string_response_adapter(s): + response = Response(s) + response.content_type = 'text/html' + return response A new response adapter is registered in configuration: .. code-block:: python + :linenos: - if __name__ == '__main__': - config = Configurator() - config.add_response_adapter(string_response_adapter, basestring) + if __name__ == '__main__': + config = Configurator() + config.add_response_adapter(string_response_adapter, basestring) With that, you may return strings from any of your view callables, e.g.: .. code-block:: python - :linenos: + :linenos: - def helloview(request): - return "Hello world!" + def helloview(request): + return "Hello world!" - def goodbyeview(request): - return "Goodbye world!" + def goodbyeview(request): + return "Goodbye world!" You can even use a :term:`response adapter` to allow for custom content types and return codes: .. code-block:: python - :linenos: + :linenos: - from pyramid.config import Configurator + 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 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 + 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) + if __name__ == '__main__': + config = Configurator() + config.add_response_adapter(string_response_adapter, basestring) + config.add_response_adapter(tuple_response_adapter, tuple) With this, both of these views will work as expected: .. code-block:: python - :linenos: + :linenos: - def aview(request): - return "Hello world!" + def aview(request): + return "Hello world!" - def anotherview(request): - return (403, 'text/plain', "Forbidden") + def anotherview(request): + return (403, 'text/plain', "Forbidden") .. seealso:: @@ -312,13 +315,13 @@ much work. :app:`Pyramid` provides a global response object as well. You can use it directly, if you prefer: .. code-block:: python - :linenos: + :linenos: - def aview(request): - response = request.response - response.body = 'Hello world!' - response.content_type = 'text/plain' - return response + def aview(request): + response = request.response + response.body = 'Hello world!' + response.content_type = 'text/plain' + return response .. seealso:: @@ -337,46 +340,46 @@ Usually you can get rid of the boring with existing shortcuts, but let's say that this is a case where there is no such shortcut: .. code-block:: python - :linenos: + :linenos: - from pyramid.config import Configurator + 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') + 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 :app:`Pyramid` :term:`configurator` to automate some of the tedium away: .. code-block:: python - :linenos: + :linenos: - from pyramid.config import Configurator + 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) + 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) + 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 :term:`configurator` object: .. code-block:: python - :linenos: + :linenos: - config.add_route('xhr_route', '/xhr/{id}') - config.add_protected_xhr_views('my.package') + config.add_route('xhr_route', '/xhr/{id}') + config.add_protected_xhr_views('my.package') Much better! -- cgit v1.2.3 From 981a9df80716ca622324d653117b9c7c3ada70c2 Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 25 May 2017 09:05:55 -0700 Subject: fix more style issues per CR --- docs/narr/introduction.rst | 82 +++++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index a8d417250..19b8fcdb8 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -73,44 +73,47 @@ working on a framework that is up-to-date and forward-looking. Tested ~~~~~~ -Untested code is broken by design. The Pyramid community has a strong testing -culture and our framework reflects that. Every release of Pyramid has 100% -statement coverage [#]_ and 95% decision/condition coverage. [#]_ It is -automatically tested using `Travis `_ and -`Jenkins `_ on Python 2.7, -Python 3.4, Python 3.5, and PyPy after each commit to its GitHub repository. +Untested code is broken by design. +The Pyramid community has a strong testing culture and our framework reflects that. +Every release of Pyramid has 100% statement coverage (as measured by `coverage `_) +and 95% decision/condition coverage. (as measured by `instrumental `_) +It is automatically tested using `Travis `_ +and `Jenkins `_ +on supported versions of Python after each commit to its GitHub repository. `Official Pyramid add-ons `_ are held to a similar testing standard. We still find bugs in Pyramid, but we've noticed we find a lot fewer of them while working on projects with a solid testing regime. -.. [#] as measured by `coverage `_ -.. [#] as measured by `instrumental `_ - Documented ~~~~~~~~~~ -The Pyramid documentation is comprehensive. We strive to keep our narrative -documentation both complete and friendly to newcomers. We also maintain a -:ref:`cookbook ` of recipes, demonstrations of -common scenarios you might face. And contributions in the form of improvements -to our documentation are always appreciated. +The Pyramid documentation is comprehensive. +We strive to keep our narrative documentation both complete and friendly to newcomers. +We also maintain a :ref:`cookbook ` of recipes, +demonstrations of common scenarios you might face. +Contributions in the form of improvements to our documentation are always appreciated. +And we always welcome improvements to our `official tutorials `_ +as well as new contributions to our `community maintained tutorials `_. Supported ~~~~~~~~~ -You can get help quickly with Pyramid. It's our goal that no Pyramid question -go unanswered. Whether you ask a question on IRC, on the Pylons-discuss mailing -list, or on StackOverflow, you're likely to get a reasonably prompt response. +You can get help quickly with :app:`Pyramid`. +It's our goal that no :app:`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. + +:app:`Pyramid` is also a welcoming, friendly space for newcomers. +We don't tolerate "support trolls" or those who enjoy berating fellow users in our support channels. +We try to keep it well-lit and new-user-friendly. -Pyramid is also a welcoming, friendly space for newcomers. We don't tolerate -"support trolls" or those who enjoy berating fellow users in our support -channels. We try to keep it well-lit and new-user-friendly. +.. seealso:: -Example: Visit irc\://freenode.net#pyramid (the ``#pyramid`` channel on -irc.freenode.net in an IRC client) or the pylons-discuss maillist at -https://groups.google.com/forum/#!forum/pylons-discuss. + See also our `#pyramid IRC channel `_, + our `pylons-discuss mailing list `_, + and :ref:`support-and-development`. .. _what_makes_pyramid_unique: @@ -135,8 +138,7 @@ framework should be able to be good at both. Pyramid is that kind of framework. Pyramid provides a set of features that are unique among Python web frameworks. Others may provide some, but only Pyramid provides them all, in one place, -fully documented, and useful *à la carte* without needing to pay for the whole -banquet. +fully documented, and *à la carte* without needing to pay for the whole banquet. Build single-file applications @@ -170,12 +172,14 @@ you don't have to switch files to see your configuration. For example: return Response('fred') However, using Pyramid configuration decorators does not change your code. It -remains easy to extend, test or reuse. You can test your code as if the +remains easy to extend, test, or reuse. You can test your code as if the decorators were not there. You can instruct the framework to ignore some decorators. You can even use an imperative style to write your configuration, skipping decorators entirely. -Example: :ref:`mapping_views_using_a_decorator_section`. +.. seealso:: + + See also :ref:`mapping_views_using_a_decorator_section`. Generate application URLs ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -185,7 +189,9 @@ viewing. Pyramid provides flexible, consistent, easy to use tools for generating URLs. When you use these tools to write your application, you can change your configuration without fear of breaking links in your web pages. -Example: :ref:`generating_route_urls`. +.. seealso:: + + See also :ref:`generating_route_urls`. Serve static assets ~~~~~~~~~~~~~~~~~~~ @@ -197,7 +203,9 @@ server or CDN (content delivery network). Either way, Pyramid can help you to generate URLs so you can change where your files come from without changing any code. -Example: :ref:`static_assets_section`. +.. seealso:: + + See also :ref:`static_assets_section`. Develop interactively ~~~~~~~~~~~~~~~~~~~~~ @@ -216,7 +224,9 @@ around from your browser to find out what happened. To use the Pyramid debug toolbar, build your project with a Pyramid :term:`cookiecutter`. -Example: :ref:`debug_toolbar`. +.. seealso:: + + See also :ref:`debug_toolbar`. Debug with power ~~~~~~~~~~~~~~~~ @@ -232,20 +242,24 @@ Pyramid also has command line tools to help you verify your configuration. You can use ``proutes`` and ``pviews`` to inspect how URLs are connected to your application code. -Examples: :ref:`debug_authorization_section` and :ref:`command_line_chapter`. +.. seealso:: + + See also :ref:`debug_authorization_section`, :ref:`command_line_chapter`, + and :doc:`../pscripts/index` Extend your application ~~~~~~~~~~~~~~~~~~~~~~~ Pyramid add-ons extend the core of the framework with useful abilities. There are add-ons available for your favorite template language, SQL and NoSQL -databases, authentication services and much much more. +databases, authentication services and more. Supported Pyramid add-ons are held to the same demanding standards as the framework itself. You will find them to be fully tested and well documented. -Examples: -https://trypyramid.com/resources-extending-pyramid.html +.. seealso:: + + See also https://trypyramid.com/resources-extending-pyramid.html Write your views, *your* way ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From 7dbc4a7a4b480365461ce882670070c932b3fcd9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 1 Jun 2017 11:41:41 -0700 Subject: clarify badges for releasing --- README.rst | 12 ++++-------- RELEASING.txt | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 5f42115df..4125dac01 100644 --- a/README.rst +++ b/README.rst @@ -1,17 +1,13 @@ Pyramid ======= -.. image:: https://travis-ci.org/Pylons/pyramid.png?branch=1.9-branch +.. image:: https://travis-ci.org/Pylons/pyramid.png?branch=master :target: https://travis-ci.org/Pylons/pyramid :alt: master Travis CI Status -.. image:: https://readthedocs.org/projects/pyramid/badge/?version=1.9-branch - :target: http://docs.pylonsproject.org/projects/pyramid/en/1.9-branch/ - :alt: Master Documentation Status - -.. image:: https://readthedocs.org/projects/pyramid/badge/?version=1.9-branch - :target: http://docs.pylonsproject.org/projects/pyramid/en/1.9-branch/ - :alt: Latest Documentation Status +.. image:: https://readthedocs.org/projects/pyramid/badge/?version=master + :target: http://docs.pylonsproject.org/projects/pyramid/en/master/ + :alt: master Documentation Status .. image:: https://img.shields.io/badge/irc-freenode-blue.svg :target: https://webchat.freenode.net/?channels=pyramid diff --git a/RELEASING.txt b/RELEASING.txt index 58ebb2fb3..24bbb3e77 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -48,8 +48,8 @@ Prepare new release branch include a link under "Bug Fix Releases" to the minor feature changes in CHANGES.txt. -- Update README.rst to use correct versions of badges and URLs according to - each branch and context, i.e., RTD "latest" == GitHub/Travis "1.x-branch". +- Update README.rst to use correct versions of badges, URLs, and ALT option + according to each branch and context. - Update whatsnew-X.X.rst in docs to point at change log entries for individual releases if applicable. -- cgit v1.2.3 From 93c94e102f5b6d732fb06ca8d18383154e2c9636 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 1 Jun 2017 12:11:58 -0700 Subject: use the version for the mid-release cycle - update releasing.txt accordingly --- README.rst | 10 +++++----- RELEASING.txt | 5 ++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 4125dac01..0429c36b5 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,13 @@ Pyramid ======= -.. image:: https://travis-ci.org/Pylons/pyramid.png?branch=master +.. image:: https://travis-ci.org/Pylons/pyramid.png?branch=1.9-branch :target: https://travis-ci.org/Pylons/pyramid - :alt: master Travis CI Status + :alt: 1.9-branch Travis CI Status -.. image:: https://readthedocs.org/projects/pyramid/badge/?version=master - :target: http://docs.pylonsproject.org/projects/pyramid/en/master/ - :alt: master Documentation Status +.. image:: https://readthedocs.org/projects/pyramid/badge/?version=1.9-branch + :target: http://docs.pylonsproject.org/projects/pyramid/en/1.9-branch/ + :alt: 1.9-branch Documentation Status .. image:: https://img.shields.io/badge/irc-freenode-blue.svg :target: https://webchat.freenode.net/?channels=pyramid diff --git a/RELEASING.txt b/RELEASING.txt index 24bbb3e77..f780a607b 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -49,7 +49,7 @@ Prepare new release branch changes in CHANGES.txt. - Update README.rst to use correct versions of badges, URLs, and ALT option - according to each branch and context. + according to the new release branch name. - Update whatsnew-X.X.rst in docs to point at change log entries for individual releases if applicable. @@ -96,6 +96,9 @@ Prepare master for further development (major releases only) - Change setup.py version to the next version number. +- Update README.rst to use correct versions of badges, URLs, and ALT option + for "master" instead of the major release version. + Update previous version (final releases only) --------------------------------------------- -- cgit v1.2.3 From d179ce929d800fb5a8a43e9fece625cdd2eba25f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 1 Jun 2017 18:10:25 -0700 Subject: use shortcut for github URL; update RELEASING.txt - refs: #3042 --- CHANGES.txt | 4 ++++ RELEASING.txt | 8 ++++++++ docs/narr/project.rst | 2 +- docs/quick_tour.rst | 4 ++-- docs/quick_tutorial/cookiecutters.rst | 2 +- docs/tutorials/modwsgi/index.rst | 2 +- docs/tutorials/wiki/installation.rst | 4 ++-- docs/tutorials/wiki2/installation.rst | 4 ++-- 8 files changed, 21 insertions(+), 9 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index c21508a70..fc1d5ae25 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,6 +9,10 @@ unreleased resulting source files in tutorials. See https://github.com/Pylons/pyramid/issues/2548 +- Update RELEASING.txt for updating cookiecutters. Change cookiecutter URLs to + use shortcut. + See: https://github.com/Pylons/pyramid/issues/3042 + 1.9a2 (2017-05-09) ================== diff --git a/RELEASING.txt b/RELEASING.txt index f780a607b..cb619dc8d 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -38,6 +38,9 @@ Prepare new release branch $ ./scaffoldtests.sh +- For each ``pyramid-cookiecutter-*``, make a new branch off "master" with the + same name to align with the new Pyramid release branch name. + - Ensure all features of the release are documented (audit CHANGES.txt or communicate with contributors). @@ -102,6 +105,11 @@ Prepare master for further development (major releases only) Update previous version (final releases only) --------------------------------------------- +- In the docs, update the ``cookiecutter`` command by appending the previous + branch name for checkout, for example, ``cookiecutter + gh:Pylons/pyramid-cookiecutter-starter --checkout 1.8-branch``. A search for + ``cookiecutter gh:Pylons/pyramid-cookiecutter-`` should return all instances. + - In docs/conf.py, update values under html_theme_options for in_progress and outdated. Uncomment the sections to enable pylons_sphinx_latesturl. diff --git a/docs/narr/project.rst b/docs/narr/project.rst index a150afc6b..924f0b696 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -85,7 +85,7 @@ On all platforms, generate a project using cookiecutter. .. code-block:: bash - $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-starter + $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst index 1265012ab..d6ecd20c9 100644 --- a/docs/quick_tour.rst +++ b/docs/quick_tour.rst @@ -510,7 +510,7 @@ Let's use the cookiecutter ``pyramid-cookiecutter-starter`` to create a starter .. code-block:: bash - $ $VENV/bin/cookiecutter https://github.com/Pylons/pyramid-cookiecutter-starter + $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter If prompted for the first item, accept the default ``yes`` by hitting return. @@ -866,7 +866,7 @@ Pyramid and SQLAlchemy are great friends. That friendship includes a cookiecutte .. code-block:: bash $ cd ~ - $ env/bin/cookiecutter https://github.com/Pylons/pyramid-cookiecutter-alchemy + $ env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/quick_tutorial/cookiecutters.rst b/docs/quick_tutorial/cookiecutters.rst index 337a5c535..36ec700f0 100644 --- a/docs/quick_tutorial/cookiecutters.rst +++ b/docs/quick_tutorial/cookiecutters.rst @@ -28,7 +28,7 @@ Steps .. code-block:: bash - $ $VENV/bin/cookiecutter https://github.com/Pylons/pyramid-cookiecutter-starter + $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst index 170f2ebc8..10cf8a478 100644 --- a/docs/tutorials/modwsgi/index.rst +++ b/docs/tutorials/modwsgi/index.rst @@ -39,7 +39,7 @@ specific path information for commands and files. .. code-block:: bash $ cd ~ - $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-starter + $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index de057b1cc..570ba7f6c 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -31,7 +31,7 @@ On UNIX .. code-block:: bash $ cd ~ - $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-zodb + $ cookiecutter gh:Pylons/pyramid-cookiecutter-zodb On Windows ^^^^^^^^^^ @@ -39,7 +39,7 @@ On Windows .. code-block:: doscon c:\> cd \ - c:\> cookiecutter https://github.com/Pylons/pyramid-cookiecutter-zodb + c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-zodb On all operating systems ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index c61d4360d..3cd04a940 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -43,7 +43,7 @@ On UNIX .. code-block:: bash $ cd ~ - $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-alchemy + $ cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy On Windows ^^^^^^^^^^ @@ -51,7 +51,7 @@ On Windows .. code-block:: doscon c:\> cd \ - c:\> cookiecutter https://github.com/Pylons/pyramid-cookiecutter-alchemy + c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy On all operating systems ^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit v1.2.3 From 64cf0e5f9e4f4f56a377bd33202c2232c14e2eaf Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 2 Jun 2017 12:54:32 -0700 Subject: Move docs update to Prepare new release branch --- RELEASING.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/RELEASING.txt b/RELEASING.txt index cb619dc8d..29d999522 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -41,6 +41,11 @@ Prepare new release branch - For each ``pyramid-cookiecutter-*``, make a new branch off "master" with the same name to align with the new Pyramid release branch name. +- In the docs, update the ``cookiecutter`` command with the new branch name, + for example, ``cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout + x.y-branch``. A search for ``cookiecutter gh:Pylons/pyramid-cookiecutter-`` + should return all instances to be updated. + - Ensure all features of the release are documented (audit CHANGES.txt or communicate with contributors). @@ -105,11 +110,6 @@ Prepare master for further development (major releases only) Update previous version (final releases only) --------------------------------------------- -- In the docs, update the ``cookiecutter`` command by appending the previous - branch name for checkout, for example, ``cookiecutter - gh:Pylons/pyramid-cookiecutter-starter --checkout 1.8-branch``. A search for - ``cookiecutter gh:Pylons/pyramid-cookiecutter-`` should return all instances. - - In docs/conf.py, update values under html_theme_options for in_progress and outdated. Uncomment the sections to enable pylons_sphinx_latesturl. -- cgit v1.2.3 From c3bb231f4bb36fd30cdf740607c3faeb5b4a1ee5 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 2 Jun 2017 12:56:14 -0700 Subject: append ` --checkout master` to cookie cutter command --- docs/narr/project.rst | 2 +- docs/quick_tour.rst | 4 ++-- docs/quick_tutorial/cookiecutters.rst | 2 +- docs/tutorials/modwsgi/index.rst | 2 +- docs/tutorials/wiki/installation.rst | 4 ++-- docs/tutorials/wiki2/installation.rst | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 924f0b696..5863926c9 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -85,7 +85,7 @@ On all platforms, generate a project using cookiecutter. .. code-block:: bash - $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter + $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst index d6ecd20c9..2ada97ac3 100644 --- a/docs/quick_tour.rst +++ b/docs/quick_tour.rst @@ -510,7 +510,7 @@ Let's use the cookiecutter ``pyramid-cookiecutter-starter`` to create a starter .. code-block:: bash - $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter + $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master If prompted for the first item, accept the default ``yes`` by hitting return. @@ -866,7 +866,7 @@ Pyramid and SQLAlchemy are great friends. That friendship includes a cookiecutte .. code-block:: bash $ cd ~ - $ env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy + $ env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/quick_tutorial/cookiecutters.rst b/docs/quick_tutorial/cookiecutters.rst index 36ec700f0..f8568206d 100644 --- a/docs/quick_tutorial/cookiecutters.rst +++ b/docs/quick_tutorial/cookiecutters.rst @@ -28,7 +28,7 @@ Steps .. code-block:: bash - $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter + $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst index 10cf8a478..a409284cc 100644 --- a/docs/tutorials/modwsgi/index.rst +++ b/docs/tutorials/modwsgi/index.rst @@ -39,7 +39,7 @@ specific path information for commands and files. .. code-block:: bash $ cd ~ - $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter + $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index 570ba7f6c..668fee098 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -31,7 +31,7 @@ On UNIX .. code-block:: bash $ cd ~ - $ cookiecutter gh:Pylons/pyramid-cookiecutter-zodb + $ cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout master On Windows ^^^^^^^^^^ @@ -39,7 +39,7 @@ On Windows .. code-block:: doscon c:\> cd \ - c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-zodb + c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout master On all operating systems ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index 3cd04a940..6c6c5d786 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -43,7 +43,7 @@ On UNIX .. code-block:: bash $ cd ~ - $ cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy + $ cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master On Windows ^^^^^^^^^^ @@ -51,7 +51,7 @@ On Windows .. code-block:: doscon c:\> cd \ - c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy + c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master On all operating systems ^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit v1.2.3 From 1aa283fac740cf5ca7e6c9a02c6cc1366e328fe8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 2 Jun 2017 13:05:39 -0700 Subject: mid-release cycle will be the death of me --- docs/narr/project.rst | 2 +- docs/quick_tour.rst | 4 ++-- docs/quick_tutorial/cookiecutters.rst | 2 +- docs/tutorials/modwsgi/index.rst | 2 +- docs/tutorials/wiki/installation.rst | 4 ++-- docs/tutorials/wiki2/installation.rst | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 5863926c9..f542eae86 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -85,7 +85,7 @@ On all platforms, generate a project using cookiecutter. .. code-block:: bash - $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master + $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 1.9-branch If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst index 2ada97ac3..f3a0a27b8 100644 --- a/docs/quick_tour.rst +++ b/docs/quick_tour.rst @@ -510,7 +510,7 @@ Let's use the cookiecutter ``pyramid-cookiecutter-starter`` to create a starter .. code-block:: bash - $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master + $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 1.9-branch If prompted for the first item, accept the default ``yes`` by hitting return. @@ -866,7 +866,7 @@ Pyramid and SQLAlchemy are great friends. That friendship includes a cookiecutte .. code-block:: bash $ cd ~ - $ env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master + $ env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout 1.9-branch If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/quick_tutorial/cookiecutters.rst b/docs/quick_tutorial/cookiecutters.rst index f8568206d..0f2a24816 100644 --- a/docs/quick_tutorial/cookiecutters.rst +++ b/docs/quick_tutorial/cookiecutters.rst @@ -28,7 +28,7 @@ Steps .. code-block:: bash - $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master + $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 1.9-branch If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst index a409284cc..8df432434 100644 --- a/docs/tutorials/modwsgi/index.rst +++ b/docs/tutorials/modwsgi/index.rst @@ -39,7 +39,7 @@ specific path information for commands and files. .. code-block:: bash $ cd ~ - $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master + $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 1.9-branch If prompted for the first item, accept the default ``yes`` by hitting return. diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index 668fee098..3e7434bd7 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -31,7 +31,7 @@ On UNIX .. code-block:: bash $ cd ~ - $ cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout master + $ cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout 1.9-branch On Windows ^^^^^^^^^^ @@ -39,7 +39,7 @@ On Windows .. code-block:: doscon c:\> cd \ - c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout master + c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout 1.9-branch On all operating systems ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index 6c6c5d786..56197900c 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -43,7 +43,7 @@ On UNIX .. code-block:: bash $ cd ~ - $ cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master + $ cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout 1.9-branch On Windows ^^^^^^^^^^ @@ -51,7 +51,7 @@ On Windows .. code-block:: doscon c:\> cd \ - c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master + c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout 1.9-branch On all operating systems ^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit v1.2.3 From cb3b05f43fd297fc8e3556cb8c9d59017229e519 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 2 Jun 2017 13:15:57 -0700 Subject: Add cookiecutter step for master branch upon release of new branch --- RELEASING.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RELEASING.txt b/RELEASING.txt index 29d999522..9f7db457e 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -107,6 +107,11 @@ Prepare master for further development (major releases only) - Update README.rst to use correct versions of badges, URLs, and ALT option for "master" instead of the major release version. +- In the docs, update the ``cookiecutter`` command with ``master``, + for example, ``cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout + master``. A search for ``cookiecutter gh:Pylons/pyramid-cookiecutter-`` + should return all instances to be updated. + Update previous version (final releases only) --------------------------------------------- -- cgit v1.2.3 From f42ab136cd5d2c98c34b101d458750f638380d08 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 3 Jun 2017 16:06:38 -0700 Subject: use str in deference to Py3 style over Py2 --- docs/narr/advanced-features.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/narr/advanced-features.rst b/docs/narr/advanced-features.rst index ae28ba41b..9ed0cc712 100644 --- a/docs/narr/advanced-features.rst +++ b/docs/narr/advanced-features.rst @@ -252,7 +252,7 @@ A new response adapter is registered in configuration: if __name__ == '__main__': config = Configurator() - config.add_response_adapter(string_response_adapter, basestring) + config.add_response_adapter(string_response_adapter, str) With that, you may return strings from any of your view callables, e.g.: @@ -288,7 +288,7 @@ and return codes: if __name__ == '__main__': config = Configurator() - config.add_response_adapter(string_response_adapter, basestring) + config.add_response_adapter(string_response_adapter, str) config.add_response_adapter(tuple_response_adapter, tuple) With this, both of these views will work as expected: -- cgit v1.2.3 From a419bcd2b1fabf2fcf551edd714236a990d89b36 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 3 Jun 2017 16:08:00 -0700 Subject: more fixes for CR --- docs/narr/introduction.rst | 75 +++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 19b8fcdb8..4f9574ec6 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -73,15 +73,17 @@ working on a framework that is up-to-date and forward-looking. Tested ~~~~~~ -Untested code is broken by design. -The Pyramid community has a strong testing culture and our framework reflects that. -Every release of Pyramid has 100% statement coverage (as measured by `coverage `_) -and 95% decision/condition coverage. (as measured by `instrumental `_) -It is automatically tested using `Travis `_ -and `Jenkins `_ -on supported versions of Python after each commit to its GitHub repository. -`Official Pyramid add-ons `_ -are held to a similar testing standard. +Untested code is broken by design. The Pyramid community has a strong testing +culture and our framework reflects that. Every release of Pyramid has 100% +statement coverage (as measured by `coverage +`_) and 95% decision/condition coverage. (as +measured by `instrumental +`_) It is +automatically tested using `Travis `_ and +`Jenkins `_ on supported +versions of Python after each commit to its GitHub repository. `Official +Pyramid add-ons `_ are +held to a similar testing standard. We still find bugs in Pyramid, but we've noticed we find a lot fewer of them while working on projects with a solid testing regime. @@ -89,25 +91,27 @@ while working on projects with a solid testing regime. Documented ~~~~~~~~~~ -The Pyramid documentation is comprehensive. -We strive to keep our narrative documentation both complete and friendly to newcomers. -We also maintain a :ref:`cookbook ` of recipes, -demonstrations of common scenarios you might face. -Contributions in the form of improvements to our documentation are always appreciated. -And we always welcome improvements to our `official tutorials `_ -as well as new contributions to our `community maintained tutorials `_. +The Pyramid documentation is comprehensive. We strive to keep our narrative +documentation both complete and friendly to newcomers. We also maintain a +:ref:`cookbook ` of recipes, demonstrations of +common scenarios you might face. Contributions in the form of improvements to +our documentation are always appreciated. And we always welcome improvements to +our `official tutorials +`_ as well +as new contributions to our `community maintained tutorials +`_. Supported ~~~~~~~~~ -You can get help quickly with :app:`Pyramid`. -It's our goal that no :app:`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. +You can get help quickly with :app:`Pyramid`. It's our goal that no +:app:`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. -:app:`Pyramid` is also a welcoming, friendly space for newcomers. -We don't tolerate "support trolls" or those who enjoy berating fellow users in our support channels. -We try to keep it well-lit and new-user-friendly. +:app:`Pyramid` is also a welcoming, friendly space for newcomers. We don't +tolerate "support trolls" or those who enjoy berating fellow users in our +support channels. We try to keep it well-lit and new-user-friendly. .. seealso:: @@ -336,9 +340,9 @@ Use *your* templates ~~~~~~~~~~~~~~~~~~~~ In Pyramid, the job of creating a ``Response`` belongs to a :term:`renderer`. -Any templating system--Mako, Genshi, Chameleon, Jinja2--can be a renderer. In -fact, packages exist for all of these systems. But if you'd rather use another, -a structured API exists allowing you to create a renderer using your favorite +Any templating system—Mako, Chameleon, Jinja2—can be a renderer. In fact, +packages exist for all of these systems. But if you'd rather use another, a +structured API exists allowing you to create a renderer using your favorite templating system. You can use the templating system *you* understand, not one required by the framework. @@ -352,7 +356,7 @@ Write testable views ~~~~~~~~~~~~~~~~~~~~ When you use a :term:`renderer` with your view callable, you are freed from -needing to return a "webby" ``Response`` object. Instead, your views can return +needing to return a "webby" ``Response`` object. Instead your views can return a simple Python dictionary. Pyramid will take care of rendering the information in that dictionary to a ``Response`` on your behalf. As a result, your views are more easily tested, since you don't need to parse HTML to evaluate the @@ -398,8 +402,8 @@ customization. See :ref:`intro_asset_specs` for more information. Example: :ref:`renderers_chapter`. -Use events to coordinate -~~~~~~~~~~~~~~~~~~~~~~~~ +Use events to coordinate actions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When writing web applications, it is often important to have your code run at a specific point in the lifecycle of a request. In Pyramid, you can accomplish @@ -441,10 +445,13 @@ Build efficient applications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pyramid provides an easy way to *cache* the results of slow or expensive views. -You can indicate in view configuration that you want a view to be cached:: +You can indicate in view configuration that you want a view to be cached: + +.. code-block:: python @view_config(http_cache=3600) # 60 minutes - def myview(request): ... + def myview(request): + # ... Pyramid will automatically add the appropriate ``Cache-Control`` and ``Expires`` headers to the response it creates. @@ -544,9 +551,9 @@ features from each, combining them into a unique web framework. Similar to :term:`Zope`, :app:`Pyramid` applications may easily be extended. If you work within the constraints of the framework, you can produce applications -that can be reused, modified or extended without needing to modify the original -application code. :app:`Pyramid` also inherits the concepts of :term:`traversal` -and declarative security from Zope. +that can be reused, modified, or extended without needing to modify the +original application code. :app:`Pyramid` also inherits the concepts of +:term:`traversal` and declarative security from Zope. Similar to :term:`Pylons` version 1.0, :app:`Pyramid` is largely free of policy. It makes no assertions about which database or template system you -- cgit v1.2.3 From 794fd355156224b9ce93651837a311dbf6ac7040 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 3 Jun 2017 16:29:01 -0700 Subject: finish all app references for Pyramid and refold line lengths --- docs/narr/advanced-features.rst | 96 +++++++------- docs/narr/introduction.rst | 277 ++++++++++++++++++++-------------------- 2 files changed, 192 insertions(+), 181 deletions(-) diff --git a/docs/narr/advanced-features.rst b/docs/narr/advanced-features.rst index 9ed0cc712..63bc5d3e7 100644 --- a/docs/narr/advanced-features.rst +++ b/docs/narr/advanced-features.rst @@ -1,9 +1,8 @@ Advanced :app:`Pyramid` Design Features ======================================= -Pyramid has been built from the ground up to avoid the problems that other -frameworks can suffer. - +:app:`Pyramid` has been built from the ground up to avoid the problems +that other frameworks can suffer. You Don't Need Singletons ------------------------- @@ -37,8 +36,8 @@ with something like this: else: # do something else -Unlike many other systems, :app:`Pyramid` allows you to associate more than one view -with a single route. For example, you can create a route with the pattern +Unlike many other systems, :app:`Pyramid` allows you to associate more than one +view with a single route. For example, you can create a route with the pattern ``/items`` and when the route is matched, you can send the request to one view if the request method is GET, another view if the request method is POST, and so on. @@ -72,10 +71,11 @@ understandable, and more directly testable. Stop Worrying About Transactions -------------------------------- -:app:`Pyramid`\ 's :term:`cookiecutter`\ s render projects that include a *transaction -management* system. When you use this system, you can stop worrying about when -to commit your changes, :app:`Pyramid` handles it for you. The system will -commit at the end of a request or abort if there was an exception. +:app:`Pyramid`\ 's :term:`cookiecutter`\ s render projects that include a +*transaction management* system. When you use this system, you can stop +worrying about when to commit your changes, :app:`Pyramid` handles it for you. +The system will commit at the end of a request or abort if there was an +exception. Why is that a good thing? Imagine a situation where you manually commit a change to your persistence layer. It's very likely that other framework code @@ -86,10 +86,10 @@ Using transaction management saves you from needing to think about this. Either a request completes successfully and all changes are committed, or it does not and all changes are aborted. -Pyramid's transaction management is extendable, so you can synchronize commits -between multiple databases or databases of different kinds. It also allows you -to do things like conditionally send email if a transaction is committed, but -otherwise keep quiet. +:app:`Pyramid`\ 's transaction management is extendable, so you can synchronize +commits between multiple databases or databases of different kinds. It also +allows you to do things like conditionally send email if a transaction is +committed, but otherwise keep quiet. .. seealso:: @@ -103,10 +103,10 @@ When a system is small, it's reasonably easy to keep it all in your head. But as systems grow large, configuration grows more complex. Your app may grow to have hundreds or even thousands of configuration statements. -:app:`Pyramid`\ 's configuration system keeps track of each of your statements. If you -accidentally add two that are identical, or :app:`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. +:app:`Pyramid`\ 's configuration system keeps track of each of your statements. +If you accidentally add two that are identical, or :app:`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. :app:`Pyramid`\ 's configuration system is not dumb though. If you use the :meth:`~pyramid.config.Configurator.include` system, it can automatically @@ -123,9 +123,9 @@ Compose Powerful Apps From Simple Parts Speaking of the :app:`Pyramid` structured "include" mechanism (see :meth:`~pyramid.config.Configurator.include`), it allows you to compose complex applications from multiple, simple Python packages. All the configuration -statements that can be performed in your main :app:`Pyramid` application can also be -used in included packages. You can add views, routes, and subscribers, and even -set authentication and authorization policies. +statements that can be performed in your main :app:`Pyramid` application can +also be used in included packages. You can add views, routes, and subscribers, +and even set authentication and authorization policies. If you need, you can extend or override the configuration of an existing application by including its configuration in your own and then modifying it. @@ -155,9 +155,10 @@ as you requested: Authenticate Users Your Way --------------------------- -:app:`Pyramid` ships with prebuilt, well-tested authentication and authorization -schemes out of the box. Using a scheme is a matter of configuration. So if you -need to change approaches later, you need only update your configuration. +:app:`Pyramid` ships with prebuilt, well-tested authentication and +authorization schemes out of the box. Using a scheme is a matter of +configuration. So if you need to change approaches later, you need only update +your configuration. In addition, the system that handles authentication and authorization is flexible and pluggable. If you want to use another security add-on, or define @@ -202,11 +203,11 @@ transaction manager. Return What You Want From Your Views ------------------------------------ -We have shown elsewhere (in the :doc:`introduction`) how using a :term:`renderer` -allows you to return simple Python dictionaries from your view code. But some -frameworks allow you to return strings or tuples from view callables. -When frameworks allow for this, code looks slightly prettier because there are -fewer imports and less code. For example, compare this: +We have shown elsewhere (in the :doc:`introduction`) how using a +:term:`renderer` allows you to return simple Python dictionaries from your view +code. But some frameworks allow you to return strings or tuples from view +callables. When frameworks allow for this, code looks slightly prettier because +there are fewer imports and less code. For example, compare this: .. code-block:: python :linenos: @@ -334,10 +335,11 @@ Perhaps the :app:`Pyramid` configurator's syntax feels a bit verbose to you. Or possibly you would like to add a feature to configuration without asking the core developers to change :app:`Pyramid` itself? -You can extend :app:`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 get rid of the boring with existing shortcuts, -but let's say that this is a case where there is no such shortcut: +You can extend :app:`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 get +rid of the boring with existing shortcuts, but let's say that this is a case +where there is no such shortcut: .. code-block:: python :linenos: @@ -353,8 +355,8 @@ but let's say that this is a case where there is no such shortcut: 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 :app:`Pyramid` :term:`configurator` to automate some of the tedium away: +Pretty tedious right? You can add a directive to the :app:`Pyramid` +:term:`configurator` to automate some of the tedium away: .. code-block:: python :linenos: @@ -372,8 +374,8 @@ You can add a directive to the :app:`Pyramid` :term:`configurator` to automate s 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 :term:`configurator` object: +Once that's done, you can call the directive you've just added as a method of +the :term:`configurator` object: .. code-block:: python :linenos: @@ -383,11 +385,12 @@ you can call the directive you've just added as a method of the :term:`configura Much better! -You can share your configuration code with others, too. -Add your code to a Python package. -Put the call to :meth:`~pyramid.config.Configurator.add_directive` in a function. -When other programmers install your package, -they'll be able to use your configuration by passing your function to a call to :meth:`~pyramid.config.Configurator.include`. +You can share your configuration code with others, too. Add your code to a +Python package. Put the call to +:meth:`~pyramid.config.Configurator.add_directive` in a function. When other +programmers install your package, they'll be able to use your configuration by +passing your function to a call to +:meth:`~pyramid.config.Configurator.include`. .. seealso:: @@ -396,14 +399,15 @@ they'll be able to use your configuration by passing your function to a call to Introspect Your Application --------------------------- -If you're building a large, pluggable system, -it's useful to be able to get a list of what has been plugged in *at application runtime*. -For example, you might want to show users a set of tabs at the top of the screen -based on a list of the views they registered. +If you're building a large, pluggable system, it's useful to be able to get a +list of what has been plugged in *at application runtime*. For example, you +might want to show users a set of tabs at the top of the screen based on a list +of the views they registered. :app:`Pyramid` provides an :term:`introspector` for just this purpose. -Here's an example of using :app:`Pyramid`\ 's :term:`introspector` from within a view: +Here's an example of using :app:`Pyramid`\ 's :term:`introspector` from within +a view: .. code-block:: python :linenos: diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 4f9574ec6..b53ecd6bd 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -27,19 +27,19 @@ creating web applications easier. It is open source. framework, so long as your chosen framework fits the requirements of your application. -Pyramid follows these design and engineering principles: +:app:`Pyramid` follows these design and engineering principles: Simplicity - :app:`Pyramid` is designed to be easy to use. You can get started even if you - don't understand it all. And when you're ready to do more, :app:`Pyramid` - will be there for you. + :app:`Pyramid` is designed to be easy to use. You can get started even if + you don't understand it all. And when you're ready to do more, + :app:`Pyramid` will be there for you. Minimalism - Out of the box, :app:`Pyramid` provides only the core tools needed for nearly - all web applications: mapping URLs to code, security, and serving static - assets (files like JavaScript and CSS). Additional tools provide templating, - database integration and more. But with :app:`Pyramid` you can *"pay only for - what you eat"*. + Out of the box, :app:`Pyramid` provides only the core tools needed for + nearly all web applications: mapping URLs to code, security, and serving + static assets (files like JavaScript and CSS). Additional tools provide + templating, database integration and more. But with :app:`Pyramid` you can + *"pay only for what you eat"*. Documentation :app:`Pyramid` is committed to comprehensive and up-to-date documentation. @@ -52,30 +52,31 @@ Reliability is: "If it ain't tested, it's broke". Openness - As with Python, the Pyramid software is distributed under a `permissive open - source license `_. + As with Python, the :app:`Pyramid` software is distributed under a + `permissive open source license `_. .. _why_pyramid: Why Pyramid? ------------ -In a world filled with web frameworks, why should you choose Pyramid? +In a world filled with web frameworks, why should you choose :app:`Pyramid`\ ? Modern ~~~~~~ -Pyramid is fully compatible with Python 3. If you develop a Pyramid application -today, you can rest assured that you'll be able to use the most modern features -of your favorite language. And in the years to come, you'll continue to be -working on a framework that is up-to-date and forward-looking. +:app:`Pyramid` is fully compatible with Python 3. If you develop a +:app:`Pyramid` application today, you can rest assured that you'll be able +to use the most modern features of your favorite language. And in the years +to come, you'll continue to bed working on a framework that is up-to-date +and forward-looking. Tested ~~~~~~ -Untested code is broken by design. The Pyramid community has a strong testing -culture and our framework reflects that. Every release of Pyramid has 100% -statement coverage (as measured by `coverage +Untested code is broken by design. The :app:`Pyramid` community has a strong +testing culture and our framework reflects that. Every release of +:app:`Pyramid` has 100% statement coverage (as measured by `coverage `_) and 95% decision/condition coverage. (as measured by `instrumental `_) It is @@ -85,18 +86,18 @@ versions of Python after each commit to its GitHub repository. `Official Pyramid add-ons `_ are held to a similar testing standard. -We still find bugs in Pyramid, but we've noticed we find a lot fewer of them -while working on projects with a solid testing regime. +We still find bugs in :app:`Pyramid`, but we've noticed we find a lot fewer of +them while working on projects with a solid testing regime. Documented ~~~~~~~~~~ -The Pyramid documentation is comprehensive. We strive to keep our narrative -documentation both complete and friendly to newcomers. We also maintain a -:ref:`cookbook ` of recipes, demonstrations of -common scenarios you might face. Contributions in the form of improvements to -our documentation are always appreciated. And we always welcome improvements to -our `official tutorials +The :app:`Pyramid` documentation is comprehensive. We strive to keep our +narrative documentation both complete and friendly to newcomers. We also +maintain a :ref:`cookbook ` of recipes, +demonstrations of common scenarios you might face. Contributions in the form of +improvements to our documentation are always appreciated. And we always welcome +improvements to our `official tutorials `_ as well as new contributions to our `community maintained tutorials `_. @@ -125,34 +126,36 @@ What makes Pyramid unique ------------------------- There are many tools available for web development. What would make someone -want to use Pyramid instead? What makes Pyramid unique? +want to use :app:`Pyramid` instead? What makes :app:`Pyramid` unique? -With Pyramid you can write very small applications without needing to know a -lot. And by learning a bit more, you can write very large applications too. -Pyramid will allow you to become productive quickly, and will grow with you. It -won't hold you back when your application is small, and it won't get in your -way when your application becomes large. Other application frameworks seem to -fall into two non-overlapping categories: those that support "small apps" and -those designed for "big apps". +With :app:`Pyramid` you can write very small applications without needing to +know a lot. And by learning a bit more, you can write very large applications +too. :app:`Pyramid` will allow you to become productive quickly, and will grow +with you. It won't hold you back when your application is small, and it won't +get in your way when your application becomes large. Other application +frameworks seem to fall into two non-overlapping categories: those that support +"small apps" and those designed for "big apps". We don't believe you should have to make this choice. You can't really know how large your application will become. You certainly shouldn't have to rewrite a small application in another framework when it gets "too big". A well-designed -framework should be able to be good at both. Pyramid is that kind of framework. +framework should be able to be good at both. :app:`Pyramid` is that kind of +framework. -Pyramid provides a set of features that are unique among Python web frameworks. -Others may provide some, but only Pyramid provides them all, in one place, -fully documented, and *à la carte* without needing to pay for the whole banquet. +:app:`Pyramid` provides a set of features that are unique among Python web +frameworks. Others may provide some, but only :app:`Pyramid` provides them all, +in one place, fully documented, and *à la carte* without needing to pay for the +whole banquet. Build single-file applications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can write a Pyramid application that lives entirely in one Python file. -Such an application is easy to understand since everything is in one place. It -is easy to deploy because you don't need to know much about Python packaging. -Pyramid allows you to do almost everything that so-called *microframeworks* can -in very similar ways. +You can write a :app:`Pyramid` application that lives entirely in one Python +file. Such an application is easy to understand since everything is in one +place. It is easy to deploy because you don't need to know much about Python +packaging. :app:`Pyramid` allows you to do almost everything that so-called +*microframeworks* can in very similar ways. .. literalinclude:: helloworld.py @@ -163,8 +166,8 @@ in very similar ways. Configure applications with decorators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Pyramid allows you to keep your configuration right next to your code. That way -you don't have to switch files to see your configuration. For example: +:app:`Pyramid` allows you to keep your configuration right next to your code. +That way you don't have to switch files to see your configuration. For example: .. code-block:: python @@ -175,9 +178,9 @@ you don't have to switch files to see your configuration. For example: def fred_view(request): return Response('fred') -However, using Pyramid configuration decorators does not change your code. It -remains easy to extend, test, or reuse. You can test your code as if the -decorators were not there. You can instruct the framework to ignore some +However, using :app:`Pyramid` configuration decorators does not change your +code. It remains easy to extend, test, or reuse. You can test your code as if +the decorators were not there. You can instruct the framework to ignore some decorators. You can even use an imperative style to write your configuration, skipping decorators entirely. @@ -189,9 +192,9 @@ Generate application URLs ~~~~~~~~~~~~~~~~~~~~~~~~~ Dynamic web applications produce URLs that can change depending on what you are -viewing. Pyramid provides flexible, consistent, easy to use tools for generating -URLs. When you use these tools to write your application, you can change your -configuration without fear of breaking links in your web pages. +viewing. :app:`Pyramid` provides flexible, consistent, easy to use tools for +generating URLs. When you use these tools to write your application, you can +change your configuration without fear of breaking links in your web pages. .. seealso:: @@ -201,11 +204,11 @@ Serve static assets ~~~~~~~~~~~~~~~~~~~ Web applications often require JavaScript, CSS, images and other so-called -*static assets*. Pyramid provides flexible tools for serving these kinds of -files. You can serve them directly from Pyramid, or host them on an external -server or CDN (content delivery network). Either way, Pyramid can help you to -generate URLs so you can change where your files come from without changing any -code. +*static assets*. :app:`Pyramid` provides flexible tools for serving these kinds +of files. You can serve them directly from :app:`Pyramid`, or host them on an +external server or CDN (content delivery network). Either way, :app:`Pyramid` +can help you to generate URLs so you can change where your files come from +without changing any code. .. seealso:: @@ -214,19 +217,19 @@ code. Develop interactively ~~~~~~~~~~~~~~~~~~~~~ -Pyramid can automatically detect changes you make to template files and code, -so your changes are immediately available in your browser. You can debug using -plain old ``print()`` calls, which will display to your console. +:app:`Pyramid` can automatically detect changes you make to template files and +code, so your changes are immediately available in your browser. You can debug +using plain old ``print()`` calls, which will display to your console. -Pyramid has a debug toolbar that allows you to see information about how your -application is working right in your browser. See configuration, installed +:app:`Pyramid` has a debug toolbar that allows you to see information about how +your application is working right in your browser. See configuration, installed packages, SQL queries, logging statements and more. When your application has an error, an interactive debugger allows you to poke around from your browser to find out what happened. -To use the Pyramid debug toolbar, build your project with a Pyramid -:term:`cookiecutter`. +To use the :app:`Pyramid` debug toolbar, build your project with a +:app:`Pyramid` :term:`cookiecutter`. .. seealso:: @@ -235,16 +238,16 @@ To use the Pyramid debug toolbar, build your project with a Pyramid Debug with power ~~~~~~~~~~~~~~~~ -When things go wrong, Pyramid gives you powerful ways to fix the problem. +When things go wrong, :app:`Pyramid` gives you powerful ways to fix the problem. -You can configure Pyramid to print helpful information to the console. The -``debug_notfound`` setting shows information about URLs that aren't matched. -The ``debug_authorization`` setting provides helpful messages about why you -aren't allowed to do what you just tried. +You can configure :app:`Pyramid` to print helpful information to the console. +The ``debug_notfound`` setting shows information about URLs that aren't +matched. The ``debug_authorization`` setting provides helpful messages about +why you aren't allowed to do what you just tried. -Pyramid also has command line tools to help you verify your configuration. You -can use ``proutes`` and ``pviews`` to inspect how URLs are connected to your -application code. +:app:`Pyramid` also has command line tools to help you verify your +configuration. You can use ``proutes`` and ``pviews`` to inspect how URLs are +connected to your application code. .. seealso:: @@ -254,12 +257,13 @@ application code. Extend your application ~~~~~~~~~~~~~~~~~~~~~~~ -Pyramid add-ons extend the core of the framework with useful abilities. There -are add-ons available for your favorite template language, SQL and NoSQL +:app:`Pyramid` add-ons extend the core of the framework with useful abilities. +There are add-ons available for your favorite template language, SQL and NoSQL databases, authentication services and more. -Supported Pyramid add-ons are held to the same demanding standards as the -framework itself. You will find them to be fully tested and well documented. +Supported :app:`Pyramid` add-ons are held to the same demanding standards as +the framework itself. You will find them to be fully tested and well +documented. .. seealso:: @@ -268,12 +272,13 @@ framework itself. You will find them to be fully tested and well documented. Write your views, *your* way ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A fundamental task for any framework is to map URLs to code. In Pyramid, that -code is called a :term:`view callable`. View callables can be functions, class -methods or even callable class instances. You are free to choose the approach -that best fits your use case. Regardless of your choice, Pyramid treats them -the same. You can change your mind at any time without any penalty. There are -no artificial distinctions between the various approaches. +A fundamental task for any framework is to map URLs to code. In :app:`Pyramid`, +that code is called a :term:`view callable`. View callables can be functions, +class methods or even callable class instances. You are free to choose the +approach that best fits your use case. Regardless of your choice, +:app:`Pyramid` treats them the same. You can change your mind at any time +without any penalty. There are no artificial distinctions between the various +approaches. Here's a view callable defined as a function: @@ -321,17 +326,17 @@ in a globally shared location, "the *static* directory". Others use a lookup scheme, like an ordered set of template directories. Both of these approaches have problems when it comes to customization. -Pyramid takes a different approach. Static assets are located using *asset +:app:`Pyramid` takes a different approach. Static assets are located using *asset specifications*, strings that contain reference both to a Python package name and a file or directory name, e.g. ``MyPackage:static/index.html``. These specifications are used for templates, JavaScript and CSS, translation files, and any other package-bound static resource. By using asset specifications, -Pyramid makes it easy to extend your application with other packages without +:app:`Pyramid` makes it easy to extend your application with other packages without worrying about conflicts. -What happens if another Pyramid package you are using provides an asset you -need to customize? Maybe that page template needs better HTML, or you want to -update some CSS. With asset specifications you can override the assets from +What happens if another :app:`Pyramid` package you are using provides an asset +you need to customize? Maybe that page template needs better HTML, or you want +to update some CSS. With asset specifications you can override the assets from other packages using simple wrappers. Examples: :ref:`asset_specifications` and :ref:`overriding_assets_section`. @@ -339,14 +344,14 @@ Examples: :ref:`asset_specifications` and :ref:`overriding_assets_section`. Use *your* templates ~~~~~~~~~~~~~~~~~~~~ -In Pyramid, the job of creating a ``Response`` belongs to a :term:`renderer`. -Any templating system—Mako, Chameleon, Jinja2—can be a renderer. In fact, -packages exist for all of these systems. But if you'd rather use another, a -structured API exists allowing you to create a renderer using your favorite -templating system. You can use the templating system *you* understand, not one -required by the framework. +In :app:`Pyramid`, the job of creating a ``Response`` belongs to a +:term:`renderer`. Any templating system—Mako, Chameleon, Jinja2—can be a +renderer. In fact, packages exist for all of these systems. But if you'd rather +use another, a structured API exists allowing you to create a renderer using +your favorite templating system. You can use the templating system *you* +understand, not one required by the framework. -What's more, Pyramid does not make you use a single templating system +What's more, :app:`Pyramid` does not make you use a single templating system exclusively. You can use multiple templating systems, even in the same project. @@ -357,11 +362,11 @@ Write testable views When you use a :term:`renderer` with your view callable, you are freed from needing to return a "webby" ``Response`` object. Instead your views can return -a simple Python dictionary. Pyramid will take care of rendering the information -in that dictionary to a ``Response`` on your behalf. As a result, your views -are more easily tested, since you don't need to parse HTML to evaluate the -results. Pyramid makes it a snap to write unit tests for your views, instead of -requiring you to use functional tests. +a simple Python dictionary. :app:`Pyramid` will take care of rendering the +information in that dictionary to a ``Response`` on your behalf. As a result, +your views are more easily tested, since you don't need to parse HTML to +evaluate the results. :app:`Pyramid` makes it a snap to write unit tests for +your views, instead of requiring you to use functional tests. .. index:: pair: renderer; explicitly calling @@ -381,7 +386,8 @@ For example, a typical web framework might return a ``Response`` object from a return render_to_response('myapp:templates/mytemplate.pt', {'a':1}, request=request) -While you *can* do this in Pyramid, you can also return a Python dictionary: +While you *can* do this in :app:`Pyramid`, you can also return a Python +dictionary: .. code-block:: python :linenos: @@ -392,13 +398,13 @@ While you *can* do this in Pyramid, you can also return a Python dictionary: def myview(request): return {'a':1} -By configuring your view to use a renderer, you tell Pyramid to use the +By configuring your view to use a renderer, you tell :app:`Pyramid` to use the ``{'a':1}`` dictionary and the specified template to render a response on your behalf. The string passed as ``renderer=`` above is an :term:`asset specification`. -Asset specifications are widely used in Pyramid. They allow for more reliable -customization. See :ref:`intro_asset_specs` for more information. +Asset specifications are widely used in :app:`Pyramid`. They allow for more +reliable customization. See :ref:`intro_asset_specs` for more information. Example: :ref:`renderers_chapter`. @@ -406,13 +412,13 @@ Use events to coordinate actions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When writing web applications, it is often important to have your code run at a -specific point in the lifecycle of a request. In Pyramid, you can accomplish -this using *subscribers* and *events*. +specific point in the lifecycle of a request. In :app:`Pyramid`, you can +accomplish this using *subscribers* and *events*. For example, you might have a job that needs to be done each time your -application handles a new request. Pyramid emits a ``NewRequest`` event at this -point in the request handling lifecycle. You can register your code as a -subscriber to this event using a clear, declarative style: +application handles a new request. :app:`Pyramid` emits a ``NewRequest`` event +at this point in the request handling lifecycle. You can register your code as +a subscriber to this event using a clear, declarative style: .. code-block:: python @@ -423,29 +429,30 @@ subscriber to this event using a clear, declarative style: def my_job(event): do_something(event.request) -Pyramid's event system can be extended as well. If you need, you can create -events of your own and send them using Pyramid's event system. Then anyone -working with your application can subscribe to your events and coordinate their -code with yours. +:app:`Pyramid`\ 's event system can be extended as well. If you need, you can +create events of your own and send them using :app:`Pyramid`\ 's event system. +Then anyone working with your application can subscribe to your events and +coordinate their code with yours. Example: :ref:`events_chapter` and :ref:`event_types`. Build international applications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Pyramid ships with internationalization-related features in its core: +:app:`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. +and templates. :app:`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`. Build efficient applications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Pyramid provides an easy way to *cache* the results of slow or expensive views. -You can indicate in view configuration that you want a view to be cached: +:app:`Pyramid` provides an easy way to *cache* the results of slow or expensive +views. You can indicate in view configuration that you want a view to be +cached: .. code-block:: python @@ -453,7 +460,7 @@ You can indicate in view configuration that you want a view to be cached: def myview(request): # ... -Pyramid will automatically add the appropriate ``Cache-Control`` and +:app:`Pyramid` will automatically add the appropriate ``Cache-Control`` and ``Expires`` headers to the response it creates. See the :meth:`~pyramid.config.Configurator.add_view` method's ``http_cache`` @@ -462,21 +469,21 @@ documentation for more information. Build fast applications ~~~~~~~~~~~~~~~~~~~~~~~ -The Pyramid core is fast. It has been engineered from the ground up for speed. -It only does as much work as absolutely necessary when you ask it to get a job -done. If you need speed from your application, Pyramid is the right choice for -you. +The :app:`Pyramid` core is fast. It has been engineered from the ground up for +speed. It only does as much work as absolutely necessary when you ask it to get +a job done. If you need speed from your application, :app:`Pyramid` is the +right choice for you. Example: http://blog.curiasolutions.com/pages/the-great-web-framework-shootout.html Store session data ~~~~~~~~~~~~~~~~~~ -Pyramid has built-in support for HTTP sessions, so you can associate data with -specific users between requests. Lots of other frameworks also support -sessions. But Pyramid allows you to plug in your own custom sessioning system. -So long as your system conforms to a documented interface, you can drop it in -in place of the provided system. +:app:`Pyramid` has built-in support for HTTP sessions, so you can associate +data with specific users between requests. Lots of other frameworks also +support sessions. But :app:`Pyramid` allows you to plug in your own custom +sessioning system. So long as your system conforms to a documented interface, +you can drop it in in place of the provided system. Currently there is a binding package for the third-party Redis sessioning system that does exactly this. But if you have a specialized need (perhaps you @@ -488,7 +495,7 @@ Example: :ref:`sessions_chapter`. Handle problems with grace ~~~~~~~~~~~~~~~~~~~~~~~~~~ -Mistakes happen. Problems crop up. No-one writes bug-free code. Pyramid +Mistakes happen. Problems crop up. No-one writes bug-free code. :app:`Pyramid` provides a way to handle the exceptions your code encounters. An :term:`exception view` is a special kind of view which is automatically called when an particular exception type "bubbles up" without being handled by your @@ -507,8 +514,8 @@ Example: :ref:`exception_views`. And much, much more... ~~~~~~~~~~~~~~~~~~~~~~ -Pyramid has been built with a number of other sophisticated design features -that make it adaptable. Read more about them below. +:app:`Pyramid` has been built with a number of other sophisticated design +features that make it adaptable. Read more about them below. .. toctree:: :maxdepth: 2 @@ -540,10 +547,10 @@ includes details about how :app:`Pyramid` relates to the Pylons Project. :app:`Pyramid` and Other Web Frameworks --------------------------------------- -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. +The first release of :app:`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 -- cgit v1.2.3 From be4b64f19c1dfde34d95e492c0554f13d8b8f797 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 5 Jun 2017 08:49:30 -0700 Subject: fix more comments and refold lines, one per paragraph as specified in stylesheet. --- docs/narr/advanced-features.rst | 173 +++++++++------------------------------- 1 file changed, 38 insertions(+), 135 deletions(-) diff --git a/docs/narr/advanced-features.rst b/docs/narr/advanced-features.rst index 63bc5d3e7..82e20963d 100644 --- a/docs/narr/advanced-features.rst +++ b/docs/narr/advanced-features.rst @@ -1,32 +1,21 @@ Advanced :app:`Pyramid` Design Features ======================================= -:app:`Pyramid` has been built from the ground up to avoid the problems -that other frameworks can suffer. +:app:`Pyramid` has been built from the ground up to avoid the problems that other frameworks can suffer. You Don't Need Singletons ------------------------- -Have you ever struggled with parameterizing Django's ``settings.py`` file for -multiple installations of the same Django application? Have you ever needed to -monkey-patch a framework fixture to get it to behave properly for your -use case? Have you ever tried to deploy your application using an asynchronous -server and failed? +Have you ever struggled with parameterizing Django's ``settings.py`` file for multiple installations of the same Django application? Have you ever needed to monkey-patch a framework fixture to get it to behave properly for your use case? Have you ever tried to deploy your application using an asynchronous server and failed? -All these problems are symptoms of :term:`mutable` :term:`global state`, also -known as :term:`import time` :term:`side effect`\ s and arise from the use of -:term:`singleton` data structures. +All these problems are symptoms of :term:`mutable` :term:`global state`, also known as :term:`import time` :term:`side effect`\ s and arise from the use of :term:`singleton` data structures. -:app:`Pyramid` is written so that you don't run into these types of problems. -It is even possible to run multiple copies of the *same* :app:`Pyramid` -application configured differently within a single Python process. This makes -running :app:`Pyramid` in shared hosting environments a snap. +:app:`Pyramid` is written so that you don't run into these types of problems. It is even possible to run multiple copies of the *same* :app:`Pyramid` application configured differently within a single Python process. This makes running :app:`Pyramid` in shared hosting environments a snap. Simplify your View Code with Predicates --------------------------------------- -How many times have you found yourself beginning the logic of your view code -with something like this: +How many times have you found yourself beginning the logic of your view code with something like this: .. code-block:: python :linenos: @@ -36,17 +25,9 @@ with something like this: else: # do something else -Unlike many other systems, :app:`Pyramid` allows you to associate more than one -view with a single route. For example, you can create a route with the pattern -``/items`` and when the route is matched, you can send the request to one view -if the request method is GET, another view if the request method is POST, and -so on. +Unlike many other systems, :app:`Pyramid` allows you to associate more than one view with a single route. For example, you can create a route with the pattern ``/items`` and when the route is matched, you can send the request to one view if the request method is GET, another view if the request method is POST, and so on. -:app:`Pyramid` uses a system of :term:`view predicate`\ s to allow this. -Matching the request method is one basic thing you can do with a -:term:`view predicate`. You can also associate views with other request -parameters, such as elements in the query string, the Accept header, whether -the request is an AJAX (XHR) request or not, and lots of other things. +:app:`Pyramid` uses a system of :term:`view predicate`\ s to allow this. Matching the request method is one basic thing you can do with a :term:`view predicate`. You can also associate views with other request parameters, such as elements in the query string, the Accept header, whether the request is an AJAX (XHR) request or not, and lots of other things. For our example above, you can do this instead: @@ -61,8 +42,7 @@ For our example above, you can do this instead: def anon_view(request): # do something else -This approach allows you to develop view code that is simpler, more easily -understandable, and more directly testable. +This approach allows you to develop view code that is simpler, more easily understandable, and more directly testable. .. seealso:: @@ -71,47 +51,26 @@ understandable, and more directly testable. Stop Worrying About Transactions -------------------------------- -:app:`Pyramid`\ 's :term:`cookiecutter`\ s render projects that include a -*transaction management* system. When you use this system, you can stop -worrying about when to commit your changes, :app:`Pyramid` handles it for you. -The system will commit at the end of a request or abort if there was an -exception. +:app:`Pyramid`\ 's :term:`cookiecutter`\ s render projects that include a *transaction management* system. When you use this system, you can stop worrying about when to commit your changes, :app:`Pyramid` handles it for you. The system will commit at the end of a request or abort if there was an exception. -Why is that a good thing? Imagine a situation where you manually commit a -change to your persistence layer. It's very likely that other framework code -will run *after* your changes are done. If an error happens in that other code, -you can easily wind up with inconsistent data if you're not extremely careful. +Why is that a good thing? Imagine a situation where you manually commit a change to your persistence layer. It's very likely that other framework code will run *after* your changes are done. If an error happens in that other code, you can easily wind up with inconsistent data if you're not extremely careful. -Using transaction management saves you from needing to think about this. Either -a request completes successfully and all changes are committed, or it does -not and all changes are aborted. +Using transaction management saves you from needing to think about this. Either a request completes successfully and all changes are committed, or it does not and all changes are aborted. -:app:`Pyramid`\ 's transaction management is extendable, so you can synchronize -commits between multiple databases or databases of different kinds. It also -allows you to do things like conditionally send email if a transaction is -committed, but otherwise keep quiet. +:app:`Pyramid`\ 's transaction management is extendable, so you can synchronize commits between multiple databases or databases of different kinds. It also allows you to do things like conditionally send email if a transaction is committed, but otherwise keep quiet. .. seealso:: - See also :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements - anywhere in application code). + See also :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements anywhere in application code). Stop Worrying About Configuration --------------------------------- -When a system is small, it's reasonably easy to keep it all in your head. But -as systems grow large, configuration grows more complex. Your app may grow to -have hundreds or even thousands of configuration statements. +When a system is small, it's reasonably easy to keep it all in your head. But as systems grow large, configuration grows more complex. Your app may grow to have hundreds or even thousands of configuration statements. -:app:`Pyramid`\ 's configuration system keeps track of each of your statements. -If you accidentally add two that are identical, or :app:`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. +:app:`Pyramid`\ 's configuration system keeps track of each of your statements. If you accidentally add two that are identical, or :app:`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. -:app:`Pyramid`\ 's configuration system is not dumb though. If you use the -:meth:`~pyramid.config.Configurator.include` system, it can automatically -resolve conflicts on its own. More local statements are preferred over less -local ones. So you can intelligently factor large systems into smaller ones. +:app:`Pyramid`\ 's configuration system is not dumb though. If you use the :meth:`~pyramid.config.Configurator.include` system, it can automatically resolve conflicts on its own. More local statements are preferred over less local ones. So you can intelligently factor large systems into smaller ones. .. seealso:: @@ -120,21 +79,12 @@ local ones. So you can intelligently factor large systems into smaller ones. Compose Powerful Apps From Simple Parts ---------------------------------------- -Speaking of the :app:`Pyramid` structured "include" mechanism (see -:meth:`~pyramid.config.Configurator.include`), it allows you to compose complex -applications from multiple, simple Python packages. All the configuration -statements that can be performed in your main :app:`Pyramid` application can -also be used in included packages. You can add views, routes, and subscribers, -and even set authentication and authorization policies. +Speaking of the :app:`Pyramid` structured :meth:`~pyramid.config.Configurator.include` mechanism, it allows you to compose complex applications from multiple, simple Python packages. All the configuration statements that can be performed in your main :app:`Pyramid` application can also be used in included packages. You can add views, routes, and subscribers, and even set authentication and authorization policies. -If you need, you can extend or override the configuration of an existing -application by including its configuration in your own and then modifying it. +If you need, you can extend or override the configuration of an existing application by including its configuration in your own and then modifying it. -For example, if you want to reuse an existing application that already has a -bunch of routes, you can just use the ``include`` statement with a -``route_prefix``. All the routes of that application will be availabe, prefixed -as you requested: +For example, if you want to reuse an existing application that already has a bunch of routes, you can just use the ``include`` statement with a ``route_prefix``. All the routes of that application will be availabe, prefixed as you requested: .. code-block:: python :linenos: @@ -149,21 +99,14 @@ as you requested: .. seealso:: - See also :ref:`including_configuration` and - :ref:`building_an_extensible_app`. + See also :ref:`including_configuration` and :ref:`building_an_extensible_app`. Authenticate Users Your Way --------------------------- -:app:`Pyramid` ships with prebuilt, well-tested authentication and -authorization schemes out of the box. Using a scheme is a matter of -configuration. So if you need to change approaches later, you need only update -your configuration. +:app:`Pyramid` ships with prebuilt, well-tested authentication and authorization schemes out of the box. Using a scheme is a matter of configuration. So if you need to change approaches later, you need only update your configuration. -In addition, the system that handles authentication and authorization is -flexible and pluggable. If you want to use another security add-on, or define -your own, you can. And again, you need only update your application -configuration to make the change. +In addition, the system that handles authentication and authorization is flexible and pluggable. If you want to use another security add-on, or define your own, you can. And again, you need only update your application configuration to make the change. .. seealso:: @@ -172,29 +115,18 @@ configuration to make the change. Build Trees of Resources ------------------------ -:app:`Pyramid` supports :term:`traversal`, a way of mapping URLs to a concrete -:term:`resource tree`. If your application naturally consists of an arbitrary -heirarchy of different types of content (like a CMS or a Document Management -System), traversal is for you. If you have a requirement for a highly granular -security model ("Jane can edit documents in *this* folder, but not *that* -one"), traversal can be a powerful approach. +:app:`Pyramid` supports :term:`traversal`, a way of mapping URLs to a concrete :term:`resource tree`. If your application naturally consists of an arbitrary heirarchy of different types of content (like a CMS or a Document Management System), traversal is for you. If you have a requirement for a highly granular security model ("Jane can edit documents in *this* folder, but not *that* one"), traversal can be a powerful approach. .. seealso:: - See also :ref:`hello_traversal_chapter` and - :ref:`much_ado_about_traversal_chapter`. + See also :ref:`hello_traversal_chapter` and :ref:`much_ado_about_traversal_chapter`. Take Action on Each Request with Tweens --------------------------------------- -:app:`Pyramid` has a system for applying an arbitrary action to each request or -response called a :term:`tween`. The system is similar in concept to WSGI -:term:`middleware`, but can be more useful since :term:`tween`\ s run in the -:app:`Pyramid` context, and have access to templates, request objects, and -other niceties. +:app:`Pyramid` has a system for applying an arbitrary action to each request or response called a :term:`tween`. The system is similar in concept to WSGI :term:`middleware`, but can be more useful since :term:`tween`\ s run in the :app:`Pyramid` context, and have access to templates, request objects, and other niceties. -The :app:`Pyramid` debug toolbar is a :term:`tween`, as is the ``pyramid_tm`` -transaction manager. +The :app:`Pyramid` debug toolbar is a :term:`tween`, as is the ``pyramid_tm`` transaction manager. .. seealso:: @@ -203,11 +135,7 @@ transaction manager. Return What You Want From Your Views ------------------------------------ -We have shown elsewhere (in the :doc:`introduction`) how using a -:term:`renderer` allows you to return simple Python dictionaries from your view -code. But some frameworks allow you to return strings or tuples from view -callables. When frameworks allow for this, code looks slightly prettier because -there are fewer imports and less code. For example, compare this: +We have shown elsewhere (in the :doc:`introduction`) how using a :term:`renderer` allows you to return simple Python dictionaries from your view code. But some frameworks allow you to return strings or tuples from view callables. When frameworks allow for this, code looks slightly prettier because there are fewer imports and less code. For example, compare this: .. code-block:: python :linenos: @@ -227,13 +155,9 @@ To this: Nicer to look at, right? -Out of the box, :app:`Pyramid` will raise an exception if you try to run the -second example above. After all, a view should return a response, and "explicit -is better than implicit". +Out of the box, :app:`Pyramid` will raise an exception if you try to run the second example above. After all, a view should return a response, and "explicit is better than implicit". -But if you're a developer who likes the aesthetics of simplicity, -:app:`Pyramid` provides an way to support this sort of thing, the -:term:`response adapter`\ : +But if you're a developer who likes the aesthetics of simplicity, :app:`Pyramid` provides a way to support this sort of thing, the :term:`response adapter`\ : .. code-block:: python :linenos: @@ -266,8 +190,7 @@ With that, you may return strings from any of your view callables, e.g.: def goodbyeview(request): return "Goodbye world!" -You can even use a :term:`response adapter` to allow for custom content types -and return codes: +You can even use a :term:`response adapter` to allow for custom content types and return codes: .. code-block:: python :linenos: @@ -310,10 +233,7 @@ With this, both of these views will work as expected: Use Global Response Objects --------------------------- -Views have to return responses. But constructing them in view code is a chore. -And perhaps registering a :term:`response adapter` as shown above is just too -much work. :app:`Pyramid` provides a global response object as well. You can -use it directly, if you prefer: +Views have to return responses. But constructing them in view code is a chore. And perhaps registering a :term:`response adapter` as shown above is just too much work. :app:`Pyramid` provides a global response object as well. You can use it directly, if you prefer: .. code-block:: python :linenos: @@ -331,15 +251,9 @@ use it directly, if you prefer: Extend Configuration -------------------- -Perhaps the :app:`Pyramid` configurator's syntax feels a bit verbose to you. -Or possibly you would like to add a feature to configuration -without asking the core developers to change :app:`Pyramid` itself? +Perhaps the :app:`Pyramid` configurator's syntax feels a bit verbose to you. Or possibly you would like to add a feature to configuration without asking the core developers to change :app:`Pyramid` itself? -You can extend :app:`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 get -rid of the boring with existing shortcuts, but let's say that this is a case -where there is no such shortcut: +You can extend :app:`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 get rid of the boring with existing shortcuts, but let's say that this is a case where there is no such shortcut: .. code-block:: python :linenos: @@ -355,8 +269,7 @@ where there is no such shortcut: 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 :app:`Pyramid` -:term:`configurator` to automate some of the tedium away: +Pretty tedious right? You can add a directive to the :app:`Pyramid` :term:`configurator` to automate some of the tedium away: .. code-block:: python :linenos: @@ -374,8 +287,7 @@ Pretty tedious right? You can add a directive to the :app:`Pyramid` 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 :term:`configurator` object: +Once that's done, you can call the directive you've just added as a method of the :term:`configurator` object: .. code-block:: python :linenos: @@ -385,12 +297,7 @@ the :term:`configurator` object: Much better! -You can share your configuration code with others, too. Add your code to a -Python package. Put the call to -:meth:`~pyramid.config.Configurator.add_directive` in a function. When other -programmers install your package, they'll be able to use your configuration by -passing your function to a call to -:meth:`~pyramid.config.Configurator.include`. +You can share your configuration code with others, too. Add your code to a Python package. Put the call to :meth:`~pyramid.config.Configurator.add_directive` in a function. When other programmers install your package, they'll be able to use your configuration by passing your function to a call to :meth:`~pyramid.config.Configurator.include`. .. seealso:: @@ -399,15 +306,11 @@ passing your function to a call to Introspect Your Application --------------------------- -If you're building a large, pluggable system, it's useful to be able to get a -list of what has been plugged in *at application runtime*. For example, you -might want to show users a set of tabs at the top of the screen based on a list -of the views they registered. +If you're building a large, pluggable system, it's useful to be able to get a list of what has been plugged in *at application runtime*. For example, you might want to show users a set of tabs at the top of the screen based on a list of the views they registered. :app:`Pyramid` provides an :term:`introspector` for just this purpose. -Here's an example of using :app:`Pyramid`\ 's :term:`introspector` from within -a view: +Here's an example of using :app:`Pyramid`\ 's :term:`introspector` from within a view: .. code-block:: python :linenos: -- cgit v1.2.3 From 719ab350b5c2bb6772e8f376adf7bd10be412f52 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 5 Jun 2017 09:17:03 -0700 Subject: fix a few more comments, and reflow introduction document to one line per paragraph --- docs/narr/introduction.rst | 327 ++++++++++----------------------------------- 1 file changed, 68 insertions(+), 259 deletions(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index b53ecd6bd..2f58a78e7 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -9,37 +9,21 @@ :app:`Pyramid` Introduction =========================== -:app:`Pyramid` is a Python web application *framework*. It is designed to make -creating web applications easier. It is open source. +:app:`Pyramid` is a Python web application *framework*. It is designed to make creating web applications easier. It is open source. .. sidebar:: What Is a Framework? - A *framework* provides capabilities that developers can enhance or extend. A - web application framework provides many of the common needs of building web - applications allowing developers to concentrate only on the parts that are - specific to their application. + A *framework* provides capabilities that developers can enhance or extend. A web application framework provides many of the common needs of building web applications allowing developers to concentrate only on the parts that are specific to their application. - Every framework makes choices about how a particular problem should be - solved. When developers choose to use a framework, they cede control over - the portions of their application that are provided by the framework. It is - possible to write a complete web application without any framework, by using - Python libraries. In practice, however, it is often more practical to use a - framework, so long as your chosen framework fits the requirements of your - application. + Every framework makes choices about how a particular problem should be solved. When developers choose to use a framework, they cede control over the portions of their application that are provided by the framework. It is possible to write a complete web application without any framework, by using Python libraries. In practice, however, it is often more practical to use a framework, so long as your chosen framework fits the requirements of your application. :app:`Pyramid` follows these design and engineering principles: Simplicity - :app:`Pyramid` is designed to be easy to use. You can get started even if - you don't understand it all. And when you're ready to do more, - :app:`Pyramid` will be there for you. + :app:`Pyramid` is designed to be easy to use. You can get started even if you don't understand it all. And when you're ready to do more, :app:`Pyramid` will be there for you. Minimalism - Out of the box, :app:`Pyramid` provides only the core tools needed for - nearly all web applications: mapping URLs to code, security, and serving - static assets (files like JavaScript and CSS). Additional tools provide - templating, database integration and more. But with :app:`Pyramid` you can - *"pay only for what you eat"*. + Out of the box, :app:`Pyramid` provides only the core tools needed for nearly all web applications: mapping URLs to code, security, and serving static assets (files like JavaScript and CSS). Additional tools provide templating, database integration and more. But with :app:`Pyramid` you can *"pay only for what you eat"*. Documentation :app:`Pyramid` is committed to comprehensive and up-to-date documentation. @@ -48,12 +32,10 @@ Speed :app:`Pyramid` is designed to be noticeably fast. Reliability - :app:`Pyramid` is developed conservatively and tested exhaustively. Our motto - is: "If it ain't tested, it's broke". + :app:`Pyramid` is developed conservatively and tested exhaustively. Our motto is: "If it ain't tested, it's broke". Openness - As with Python, the :app:`Pyramid` software is distributed under a - `permissive open source license `_. + As with Python, the :app:`Pyramid` software is distributed under a `permissive open source license `_. .. _why_pyramid: @@ -65,97 +47,49 @@ In a world filled with web frameworks, why should you choose :app:`Pyramid`\ ? Modern ~~~~~~ -:app:`Pyramid` is fully compatible with Python 3. If you develop a -:app:`Pyramid` application today, you can rest assured that you'll be able -to use the most modern features of your favorite language. And in the years -to come, you'll continue to bed working on a framework that is up-to-date -and forward-looking. +:app:`Pyramid` is fully compatible with Python 3. If you develop a :app:`Pyramid` application today, you can rest assured that you'll be able to use the most modern features of your favorite language. And in the years to come, you'll continue to bed working on a framework that is up-to-dateand forward-looking. Tested ~~~~~~ -Untested code is broken by design. The :app:`Pyramid` community has a strong -testing culture and our framework reflects that. Every release of -:app:`Pyramid` has 100% statement coverage (as measured by `coverage -`_) and 95% decision/condition coverage. (as -measured by `instrumental -`_) It is -automatically tested using `Travis `_ and -`Jenkins `_ on supported -versions of Python after each commit to its GitHub repository. `Official -Pyramid add-ons `_ are -held to a similar testing standard. - -We still find bugs in :app:`Pyramid`, but we've noticed we find a lot fewer of -them while working on projects with a solid testing regime. +Untested code is broken by design. The :app:`Pyramid` community has a strong testing culture and our framework reflects that. Every release of :app:`Pyramid` has 100% statement coverage (as measured by `coverage `_) and 95% decision/condition coverage. (as measured by `instrumental `_) It is automatically tested using `Travis `_ and `Jenkins `_ on supported versions of Python after each commit to its GitHub repository. `Official Pyramid add-ons `_ are held to a similar testing standard. + +We still find bugs in :app:`Pyramid`, but we've noticed we find a lot fewer of them while working on projects with a solid testing regime. Documented ~~~~~~~~~~ -The :app:`Pyramid` documentation is comprehensive. We strive to keep our -narrative documentation both complete and friendly to newcomers. We also -maintain a :ref:`cookbook ` of recipes, -demonstrations of common scenarios you might face. Contributions in the form of -improvements to our documentation are always appreciated. And we always welcome -improvements to our `official tutorials -`_ as well -as new contributions to our `community maintained tutorials -`_. +The :app:`Pyramid` documentation is comprehensive. We strive to keep our narrative documentation both complete and friendly to newcomers. We also maintain the :ref:`Pyramid Community Cookbook ` of ecipes demonstrating common scenarios you might face. Contributions in the form of improvements to our documentation are always appreciated. And we always welcome improvements to our `official tutorials `_ as well as new contributions to our `community maintained tutorials `_. Supported ~~~~~~~~~ -You can get help quickly with :app:`Pyramid`. It's our goal that no -:app:`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. +You can get help quickly with :app:`Pyramid`. It's our goal that no :app:`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. -:app:`Pyramid` is also a welcoming, friendly space for newcomers. We don't -tolerate "support trolls" or those who enjoy berating fellow users in our -support channels. We try to keep it well-lit and new-user-friendly. +:app:`Pyramid` is also a welcoming, friendly space for newcomers. We don't tolerate "support trolls" or those who enjoy berating fellow users in our support channels. We try to keep it well-lit and new-user-friendly. .. seealso:: - See also our `#pyramid IRC channel `_, - our `pylons-discuss mailing list `_, - and :ref:`support-and-development`. + See also our `#pyramid IRC channel `_, our `pylons-discuss mailing list `_, and :ref:`support-and-development`. .. _what_makes_pyramid_unique: What makes Pyramid unique ------------------------- -There are many tools available for web development. What would make someone -want to use :app:`Pyramid` instead? What makes :app:`Pyramid` unique? +There are many tools available for web development. What would make someone want to use :app:`Pyramid` instead? What makes :app:`Pyramid` unique? -With :app:`Pyramid` you can write very small applications without needing to -know a lot. And by learning a bit more, you can write very large applications -too. :app:`Pyramid` will allow you to become productive quickly, and will grow -with you. It won't hold you back when your application is small, and it won't -get in your way when your application becomes large. Other application -frameworks seem to fall into two non-overlapping categories: those that support -"small apps" and those designed for "big apps". +With :app:`Pyramid` you can write very small applications without needing to know a lot. And by learning a bit more, you can write very large applications too. :app:`Pyramid` will allow you to become productive quickly, and will grow with you. It won't hold you back when your application is small, and it won't get in your way when your application becomes large. Other application frameworks seem to fall into two non-overlapping categories: those that support "small apps" and those designed for "big apps". -We don't believe you should have to make this choice. You can't really know how -large your application will become. You certainly shouldn't have to rewrite a -small application in another framework when it gets "too big". A well-designed -framework should be able to be good at both. :app:`Pyramid` is that kind of -framework. +We don't believe you should have to make this choice. You can't really know how large your application will become. You certainly shouldn't have to rewrite a small application in another framework when it gets "too big". A well-designed framework should be able to be good at both. :app:`Pyramid` is that kind of framework. -:app:`Pyramid` provides a set of features that are unique among Python web -frameworks. Others may provide some, but only :app:`Pyramid` provides them all, -in one place, fully documented, and *à la carte* without needing to pay for the -whole banquet. +:app:`Pyramid` provides a set of features that are unique among Python web frameworks. Others may provide some, but only :app:`Pyramid` provides them all, in one place, fully documented, and *à la carte* without needing to pay for the whole banquet. Build single-file applications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can write a :app:`Pyramid` application that lives entirely in one Python -file. Such an application is easy to understand since everything is in one -place. It is easy to deploy because you don't need to know much about Python -packaging. :app:`Pyramid` allows you to do almost everything that so-called -*microframeworks* can in very similar ways. +You can write a :app:`Pyramid` application that lives entirely in one Python file. Such an application is easy to understand since everything is in one place. It is easy to deploy because you don't need to know much about Python packaging. :app:`Pyramid` allows you to do almost everything that so-called *microframeworks* can in very similar ways. .. literalinclude:: helloworld.py @@ -166,8 +100,7 @@ packaging. :app:`Pyramid` allows you to do almost everything that so-called Configure applications with decorators ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -:app:`Pyramid` allows you to keep your configuration right next to your code. -That way you don't have to switch files to see your configuration. For example: +:app:`Pyramid` allows you to keep your configuration right next to your code. That way you don't have to switch files to see your configuration. For example: .. code-block:: python @@ -178,11 +111,7 @@ That way you don't have to switch files to see your configuration. For example: def fred_view(request): return Response('fred') -However, using :app:`Pyramid` configuration decorators does not change your -code. It remains easy to extend, test, or reuse. You can test your code as if -the decorators were not there. You can instruct the framework to ignore some -decorators. You can even use an imperative style to write your configuration, -skipping decorators entirely. +However, using :app:`Pyramid` configuration decorators does not change your code. It remains easy to extend, test, or reuse. You can test your code as if the decorators were not there. You can instruct the framework to ignore some decorators. You can even use an imperative style to write your configuration, skipping decorators entirely. .. seealso:: @@ -191,10 +120,7 @@ skipping decorators entirely. Generate application URLs ~~~~~~~~~~~~~~~~~~~~~~~~~ -Dynamic web applications produce URLs that can change depending on what you are -viewing. :app:`Pyramid` provides flexible, consistent, easy to use tools for -generating URLs. When you use these tools to write your application, you can -change your configuration without fear of breaking links in your web pages. +Dynamic web applications produce URLs that can change depending on what you are viewing. :app:`Pyramid` provides flexible, consistent, easy to use tools for generating URLs. When you use these tools to write your application, you can change your configuration without fear of breaking links in your web pages. .. seealso:: @@ -203,12 +129,7 @@ change your configuration without fear of breaking links in your web pages. Serve static assets ~~~~~~~~~~~~~~~~~~~ -Web applications often require JavaScript, CSS, images and other so-called -*static assets*. :app:`Pyramid` provides flexible tools for serving these kinds -of files. You can serve them directly from :app:`Pyramid`, or host them on an -external server or CDN (content delivery network). Either way, :app:`Pyramid` -can help you to generate URLs so you can change where your files come from -without changing any code. +Web applications often require JavaScript, CSS, images and other so-called *static assets*. :app:`Pyramid` provides flexible tools for serving these kinds of files. You can serve them directly from :app:`Pyramid`, or host them on an external server or CDN (content delivery network). Either way, :app:`Pyramid` can help you to generate URLs so you can change where your files come from without changing any code. .. seealso:: @@ -217,19 +138,13 @@ without changing any code. Develop interactively ~~~~~~~~~~~~~~~~~~~~~ -:app:`Pyramid` can automatically detect changes you make to template files and -code, so your changes are immediately available in your browser. You can debug -using plain old ``print()`` calls, which will display to your console. +:app:`Pyramid` can automatically detect changes you make to template files and code, so your changes are immediately available in your browser. You can debug using plain old ``print()`` calls, which will display to your console. -:app:`Pyramid` has a debug toolbar that allows you to see information about how -your application is working right in your browser. See configuration, installed -packages, SQL queries, logging statements and more. +:app:`Pyramid` has a debug toolbar that allows you to see information about how your application is working right in your browser. See configuration, installed packages, SQL queries, logging statements and more. -When your application has an error, an interactive debugger allows you to poke -around from your browser to find out what happened. +When your application has an error, an interactive debugger allows you to poke around from your browser to find out what happened. -To use the :app:`Pyramid` debug toolbar, build your project with a -:app:`Pyramid` :term:`cookiecutter`. +To use the :app:`Pyramid` debug toolbar, build your project with a :app:`Pyramid` :term:`cookiecutter`. .. seealso:: @@ -240,14 +155,9 @@ Debug with power When things go wrong, :app:`Pyramid` gives you powerful ways to fix the problem. -You can configure :app:`Pyramid` to print helpful information to the console. -The ``debug_notfound`` setting shows information about URLs that aren't -matched. The ``debug_authorization`` setting provides helpful messages about -why you aren't allowed to do what you just tried. +You can configure :app:`Pyramid` to print helpful information to the console. The ``debug_notfound`` setting shows information about URLs that aren't matched. The ``debug_authorization`` setting provides helpful messages about why you aren't allowed to do what you just tried. -:app:`Pyramid` also has command line tools to help you verify your -configuration. You can use ``proutes`` and ``pviews`` to inspect how URLs are -connected to your application code. +:app:`Pyramid` also has command line tools to help you verify your configuration. You can use ``proutes`` and ``pviews`` to inspect how URLs are connected to your application code. .. seealso:: @@ -257,13 +167,9 @@ connected to your application code. Extend your application ~~~~~~~~~~~~~~~~~~~~~~~ -:app:`Pyramid` add-ons extend the core of the framework with useful abilities. -There are add-ons available for your favorite template language, SQL and NoSQL -databases, authentication services and more. +:app:`Pyramid` add-ons extend the core of the framework with useful abilities. There are add-ons available for your favorite template language, SQL and NoSQL databases, authentication services and more. -Supported :app:`Pyramid` add-ons are held to the same demanding standards as -the framework itself. You will find them to be fully tested and well -documented. +Supported :app:`Pyramid` add-ons are held to the same demanding standards as the framework itself. You will find them to be fully tested and well documented. .. seealso:: @@ -272,13 +178,7 @@ documented. Write your views, *your* way ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A fundamental task for any framework is to map URLs to code. In :app:`Pyramid`, -that code is called a :term:`view callable`. View callables can be functions, -class methods or even callable class instances. You are free to choose the -approach that best fits your use case. Regardless of your choice, -:app:`Pyramid` treats them the same. You can change your mind at any time -without any penalty. There are no artificial distinctions between the various -approaches. +A fundamental task for any framework is to map URLs to code. In :app:`Pyramid`, that code is called a :term:`view callable`. View callables can be functions, class methods or even callable class instances. You are free to choose the approach that best fits your use case. Regardless of your choice, :app:`Pyramid` treats them the same. You can change your mind at any time without any penalty. There are no artificial distinctions between the various approaches. Here's a view callable defined as a function: @@ -321,52 +221,27 @@ Here's a few views defined as methods of a class instead: Find *your* static assets ~~~~~~~~~~~~~~~~~~~~~~~~~ -In many web frameworks, the static assets required by an application are kept -in a globally shared location, "the *static* directory". Others use a lookup -scheme, like an ordered set of template directories. Both of these approaches -have problems when it comes to customization. +In many web frameworks, the static assets required by an application are kept in a globally shared location, "the *static* directory". Others use a lookup scheme, like an ordered set of template directories. Both of these approaches have problems when it comes to customization. -:app:`Pyramid` takes a different approach. Static assets are located using *asset -specifications*, strings that contain reference both to a Python package name -and a file or directory name, e.g. ``MyPackage:static/index.html``. These -specifications are used for templates, JavaScript and CSS, translation files, -and any other package-bound static resource. By using asset specifications, -:app:`Pyramid` makes it easy to extend your application with other packages without -worrying about conflicts. +:app:`Pyramid` takes a different approach. Static assets are located using *asset specifications*, strings that contain reference both to a Python package name and a file or directory name, e.g. ``MyPackage:static/index.html``. These specifications are used for templates, JavaScript and CSS, translation files, and any other package-bound static resource. By using asset specifications, :app:`Pyramid` makes it easy to extend your application with other packages without worrying about conflicts. -What happens if another :app:`Pyramid` package you are using provides an asset -you need to customize? Maybe that page template needs better HTML, or you want -to update some CSS. With asset specifications you can override the assets from -other packages using simple wrappers. +What happens if another :app:`Pyramid` package you are using provides an asset you need to customize? Maybe that page template needs better HTML, or you want to update some CSS. With asset specifications you can override the assets from other packages using simple wrappers. Examples: :ref:`asset_specifications` and :ref:`overriding_assets_section`. Use *your* templates ~~~~~~~~~~~~~~~~~~~~ -In :app:`Pyramid`, the job of creating a ``Response`` belongs to a -:term:`renderer`. Any templating system—Mako, Chameleon, Jinja2—can be a -renderer. In fact, packages exist for all of these systems. But if you'd rather -use another, a structured API exists allowing you to create a renderer using -your favorite templating system. You can use the templating system *you* -understand, not one required by the framework. +In :app:`Pyramid`, the job of creating a ``Response`` belongs to a :term:`renderer`. Any templating system—Mako, Chameleon, Jinja2—can be a renderer. In fact, packages exist for all of these systems. But if you'd rather use another, a structured API exists allowing you to create a renderer using your favorite templating system. You can use the templating system *you* understand, not one required by the framework. -What's more, :app:`Pyramid` does not make you use a single templating system -exclusively. You can use multiple templating systems, even in the same -project. +What's more, :app:`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`. Write testable views ~~~~~~~~~~~~~~~~~~~~ -When you use a :term:`renderer` with your view callable, you are freed from -needing to return a "webby" ``Response`` object. Instead your views can return -a simple Python dictionary. :app:`Pyramid` will take care of rendering the -information in that dictionary to a ``Response`` on your behalf. As a result, -your views are more easily tested, since you don't need to parse HTML to -evaluate the results. :app:`Pyramid` makes it a snap to write unit tests for -your views, instead of requiring you to use functional tests. +When you use a :term:`renderer` with your view callable, you are freed from needing to return a "webby" ``Response`` object. Instead your views can return a simple Python dictionary. :app:`Pyramid` will take care of rendering the information in that dictionary to a ``Response`` on your behalf. As a result, your views are more easily tested, since you don't need to parse HTML to evaluate the results. :app:`Pyramid` makes it a snap to write unit tests for your views, instead of requiring you to use functional tests. .. index:: pair: renderer; explicitly calling @@ -374,8 +249,7 @@ your views, instead of requiring you to use functional tests. .. _example_render_to_response_call: -For example, a typical web framework might return a ``Response`` object from a -``render_to_response`` call: +For example, a typical web framework might return a ``Response`` object from a ``render_to_response`` call: .. code-block:: python :linenos: @@ -386,8 +260,7 @@ For example, a typical web framework might return a ``Response`` object from a return render_to_response('myapp:templates/mytemplate.pt', {'a':1}, request=request) -While you *can* do this in :app:`Pyramid`, you can also return a Python -dictionary: +While you *can* do this in :app:`Pyramid`, you can also return a Python dictionary: .. code-block:: python :linenos: @@ -398,27 +271,18 @@ dictionary: def myview(request): return {'a':1} -By configuring your view to use a renderer, you tell :app:`Pyramid` to use the -``{'a':1}`` dictionary and the specified template to render a response on your -behalf. +By configuring your view to use a renderer, you tell :app:`Pyramid` to use the ``{'a':1}`` dictionary and the specified template to render a response on your behalf. -The string passed as ``renderer=`` above is an :term:`asset specification`. -Asset specifications are widely used in :app:`Pyramid`. They allow for more -reliable customization. See :ref:`intro_asset_specs` for more information. +The string passed as ``renderer=`` above is an :term:`asset specification`. Asset specifications are widely used in :app:`Pyramid`. They allow for more reliable customization. See :ref:`intro_asset_specs` for more information. Example: :ref:`renderers_chapter`. Use events to coordinate actions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When writing web applications, it is often important to have your code run at a -specific point in the lifecycle of a request. In :app:`Pyramid`, you can -accomplish this using *subscribers* and *events*. +When writing web applications, it is often important to have your code run at a specific point in the lifecycle of a request. In :app:`Pyramid`, you can accomplish this using *subscribers* and *events*. -For example, you might have a job that needs to be done each time your -application handles a new request. :app:`Pyramid` emits a ``NewRequest`` event -at this point in the request handling lifecycle. You can register your code as -a subscriber to this event using a clear, declarative style: +For example, you might have a job that needs to be done each time your application handles a new request. :app:`Pyramid` emits a ``NewRequest`` event at this point in the request handling lifecycle. You can register your code as a subscriber to this event using a clear, declarative style: .. code-block:: python @@ -429,30 +293,21 @@ a subscriber to this event using a clear, declarative style: def my_job(event): do_something(event.request) -:app:`Pyramid`\ 's event system can be extended as well. If you need, you can -create events of your own and send them using :app:`Pyramid`\ 's event system. -Then anyone working with your application can subscribe to your events and -coordinate their code with yours. +:app:`Pyramid`\ 's event system can be extended as well. If you need, you can create events of your own and send them using :app:`Pyramid`\ 's event system. Then anyone working with your application can subscribe to your events and coordinate their code with yours. Example: :ref:`events_chapter` and :ref:`event_types`. Build international applications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -:app:`Pyramid` ships with internationalization-related features in its core: -localization, pluralization, and creating message catalogs from source files -and templates. :app:`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. +:app:`Pyramid` ships with internationalization-related features in its core: localization, pluralization, and creating message catalogs from source files and templates. :app:`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`. Build efficient applications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -:app:`Pyramid` provides an easy way to *cache* the results of slow or expensive -views. You can indicate in view configuration that you want a view to be -cached: +:app:`Pyramid` provides an easy way to *cache* the results of slow or expensive views. You can indicate in view configuration that you want a view to be cached: .. code-block:: python @@ -460,62 +315,39 @@ cached: def myview(request): # ... -:app:`Pyramid` will automatically add the appropriate ``Cache-Control`` and -``Expires`` headers to the response it creates. +:app:`Pyramid` will automatically add the appropriate ``Cache-Control`` and ``Expires`` headers to the response it creates. -See the :meth:`~pyramid.config.Configurator.add_view` method's ``http_cache`` -documentation for more information. +See the :meth:`~pyramid.config.Configurator.add_view` method's ``http_cache`` documentation for more information. Build fast applications ~~~~~~~~~~~~~~~~~~~~~~~ -The :app:`Pyramid` core is fast. It has been engineered from the ground up for -speed. It only does as much work as absolutely necessary when you ask it to get -a job done. If you need speed from your application, :app:`Pyramid` is the -right choice for you. +The :app:`Pyramid` core is fast. It has been engineered from the ground up for speed. It only does as much work as absolutely necessary when you ask it to get a job done. If you need speed from your application, :app:`Pyramid` is the right choice for you. Example: http://blog.curiasolutions.com/pages/the-great-web-framework-shootout.html Store session data ~~~~~~~~~~~~~~~~~~ -:app:`Pyramid` has built-in support for HTTP sessions, so you can associate -data with specific users between requests. Lots of other frameworks also -support sessions. But :app:`Pyramid` allows you to plug in your own custom -sessioning system. So long as your system conforms to a documented interface, -you can drop it in in place of the provided system. +:app:`Pyramid` has built-in support for HTTP sessions, so you can associate data with specific users between requests. Lots of other frameworks also support sessions. But :app:`Pyramid` allows you to plug in your own custom sessioning system. So long as your system conforms to a documented interface, you can drop it in in place of the provided system. -Currently there is a binding package for the third-party Redis sessioning -system that does exactly this. But if you have a specialized need (perhaps you -want to store your session data in MongoDB), you can. You can even switch -between implementations without changing your application code. +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`. Handle problems with grace ~~~~~~~~~~~~~~~~~~~~~~~~~~ -Mistakes happen. Problems crop up. No-one writes bug-free code. :app:`Pyramid` -provides a way to handle the exceptions your code encounters. An -:term:`exception view` is a special kind of view which is automatically called -when an particular exception type "bubbles up" without being handled by your -application. +Mistakes happen. Problems crop up. No one writes bug-free code. :app:`Pyramid`provides a way to handle the exceptions your code encounters. An :term:`exception view` is a special kind of view which is automatically called when a particular exception type arises without being handled by your application. -For example, you might register an exception view for the :exc:`Exception` -exception type, which will catch *all* exceptions, and present a pretty "well, -this is embarrassing" page. Or you might choose to register an exception view -for only certain application-specific exceptions. You can make a one for when a -file is not found, or when the user doesn't have permission to do something. In -the former case, you can show a pretty "Not Found" page; in the latter case you -might show a login form. +For example, you might register an exception view for the :exc:`Exception` exception type, which will catch *all* exceptions, and present a pretty "well, this is embarrassing" page. Or you might choose to register an exception view for only certain application-specific exceptions. You can make one for when a file is not found, or when the user doesn't have permission to do something. In the former case, you can show a pretty "Not Found" page; in the latter case you might show a login form. Example: :ref:`exception_views`. And much, much more... ~~~~~~~~~~~~~~~~~~~~~~ -:app:`Pyramid` has been built with a number of other sophisticated design -features that make it adaptable. Read more about them below. +:app:`Pyramid` has been built with a number of other sophisticated design features that make it adaptable. Read more about them below. .. toctree:: :maxdepth: 2 @@ -532,10 +364,7 @@ features that make it adaptable. Read more about them below. 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 `_ -includes details about how :app:`Pyramid` relates to 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 `_ includes details about how :app:`Pyramid` relates to the Pylons Project. .. index:: single: pyramid and other frameworks @@ -547,34 +376,14 @@ includes details about how :app:`Pyramid` relates to the Pylons Project. :app:`Pyramid` and Other Web Frameworks --------------------------------------- -The first release of :app:`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. - -Similar to :term:`Zope`, :app:`Pyramid` applications may easily be extended. If -you work within the constraints of the framework, you can produce applications -that can be reused, modified, or extended without needing to modify the -original application code. :app:`Pyramid` also inherits the concepts of -:term:`traversal` and declarative security from Zope. - -Similar to :term:`Pylons` version 1.0, :app:`Pyramid` is largely free of -policy. It makes no assertions about which database or template system you -should use. You are free to use whatever third-party components fit the needs -of your specific application. :app:`Pyramid` also inherits its approach to -:term:`URL dispatch` from Pylons. - -Similar to :term:`Django`, :app:`Pyramid` values extensive documentation. In -addition, the concept of a :term:`view` is used by :app:`Pyramid` much as it -would be by Django. - -Other Python web frameworks advertise themselves as members of a class of web -frameworks named `model-view-controller -`_ -frameworks. The authors of :app:`Pyramid` do not believe that the MVC pattern -fits the web particularly well. However, if this abstraction works for you, -:app:`Pyramid` also generally fits into this class. +The first release of :app:`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. + +Similar to :term:`Zope`, :app:`Pyramid` applications may easily be extended. If you work within the constraints of the framework, you can produce applications that can be reused, modified, or extended without needing to modify the original application code. :app:`Pyramid` also inherits the concepts of :term:`traversal` and declarative security from Zope. + +Similar to :term:`Pylons` version 1.0, :app:`Pyramid` is largely free of policy. It makes no assertions about which database or template system you should use. You are free to use whatever third-party components fit the needs of your specific application. :app:`Pyramid` also inherits its approach to :term:`URL dispatch` from Pylons. + +Similar to :term:`Django`, :app:`Pyramid` values extensive documentation. In addition, the concept of a :term:`view` is used by :app:`Pyramid` much as it would be by Django. + +Other Python web frameworks advertise themselves as members of a class of web frameworks named `model-view-controller `_ frameworks. The authors of :app:`Pyramid` do not believe that the MVC pattern fits the web particularly well. However, if this abstraction works for you, :app:`Pyramid` also generally fits into this class. -- cgit v1.2.3 From 4f66355fb5d7e6fe319742cb50f263425a88c57f Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Tue, 23 May 2017 14:35:48 -0700 Subject: Always push the threadlocals --- pyramid/view.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyramid/view.py b/pyramid/view.py index 14c8c029e..47b756ad8 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -700,10 +700,9 @@ class ViewMethodsMixin(object): # https://github.com/Pylons/pyramid/issues/700 request_iface = attrs.get('request_iface', IRequest) - try: - if request is not self: - manager.push({'request': request, 'registry': registry}) + manager.push({'request': request, 'registry': registry}) + try: response = _call_view( registry, request, -- cgit v1.2.3 From cc8ce57839d26e82466df9f74c79281450bf18a5 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 5 Jun 2017 11:51:52 -0500 Subject: add changelog for #3060 --- CHANGES.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index fc1d5ae25..06bb71c1e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -11,7 +11,11 @@ unreleased - Update RELEASING.txt for updating cookiecutters. Change cookiecutter URLs to use shortcut. - See: https://github.com/Pylons/pyramid/issues/3042 + See https://github.com/Pylons/pyramid/issues/3042 + +- Ensure the correct threadlocals are pushed during view execution when + invoked from ``request.invoke_exception_view``. + See https://github.com/Pylons/pyramid/pull/3060 1.9a2 (2017-05-09) ================== -- cgit v1.2.3 From 1814cda1f5ec85c24651bfd29645e4057ae5200e Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Mon, 5 Jun 2017 17:14:32 -0400 Subject: Ensure that instances of 'AllPermissionsList' are iterable. Closes #3073. --- pyramid/security.py | 5 ++++- pyramid/tests/test_security.py | 24 ++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/pyramid/security.py b/pyramid/security.py index 82e6b73a9..035f09f77 100644 --- a/pyramid/security.py +++ b/pyramid/security.py @@ -21,10 +21,13 @@ _marker = object() class AllPermissionsList(object): """ Stand in 'permission list' to represent all permissions """ + def __iter__(self): - return () + return iter(()) + def __contains__(self, other): return True + def __eq__(self, other): return isinstance(other, self.__class__) diff --git a/pyramid/tests/test_security.py b/pyramid/tests/test_security.py index 6d75ac8e3..5561a05d7 100644 --- a/pyramid/tests/test_security.py +++ b/pyramid/tests/test_security.py @@ -16,12 +16,32 @@ class TestAllPermissionsList(unittest.TestCase): def _makeOne(self): return self._getTargetClass()() - def test_it(self): + def test_equality_w_self(self): thing = self._makeOne() self.assertTrue(thing.__eq__(thing)) - self.assertEqual(thing.__iter__(), ()) + + def test_equality_w_other_instances_of_class(self): + thing = self._makeOne() + other = self._makeOne() + self.assertTrue(thing.__eq__(other)) + + def test_equality_miss(self): + thing = self._makeOne() + other = object() + self.assertFalse(thing.__eq__(other)) + + def test_contains_w_string(self): + thing = self._makeOne() self.assertTrue('anything' in thing) + def test_contains_w_object(self): + thing = self._makeOne() + self.assertTrue(object() in thing) + + def test_iterable(self): + thing = self._makeOne() + self.assertEqual(list(thing), []) + def test_singleton(self): from pyramid.security import ALL_PERMISSIONS self.assertEqual(ALL_PERMISSIONS.__class__, self._getTargetClass()) -- cgit v1.2.3 From 381fe100f37e5bbe4d8e032760f244c2a9f92667 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 6 Jun 2017 08:33:52 -0700 Subject: restore the r. it's important --- docs/narr/introduction.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 2f58a78e7..3dd0cc464 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -59,7 +59,7 @@ We still find bugs in :app:`Pyramid`, but we've noticed we find a lot fewer of t Documented ~~~~~~~~~~ -The :app:`Pyramid` documentation is comprehensive. We strive to keep our narrative documentation both complete and friendly to newcomers. We also maintain the :ref:`Pyramid Community Cookbook ` of ecipes demonstrating common scenarios you might face. Contributions in the form of improvements to our documentation are always appreciated. And we always welcome improvements to our `official tutorials `_ as well as new contributions to our `community maintained tutorials `_. +The :app:`Pyramid` documentation is comprehensive. We strive to keep our narrative documentation both complete and friendly to newcomers. We also maintain the :ref:`Pyramid Community Cookbook ` of recipes demonstrating common scenarios you might face. Contributions in the form of improvements to our documentation are always appreciated. And we always welcome improvements to our `official tutorials `_ as well as new contributions to our `community maintained tutorials `_. Supported ~~~~~~~~~ -- cgit v1.2.3 From 57ce7b0c251d34e29a2eb5375c70e751c9b83f4e Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 7 Jun 2017 00:02:15 -0500 Subject: explain why we prefer to avoid activate fixes #3064 --- docs/narr/install.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/narr/install.rst b/docs/narr/install.rst index 2a25ad84d..c2bd00bff 100644 --- a/docs/narr/install.rst +++ b/docs/narr/install.rst @@ -206,9 +206,7 @@ After installing Python as described previously in :ref:`for-mac-os-x-users` or ``$VENV/bin/pip`` clearly specifies that ``pip`` is run from within the virtual environment and not at the system level. - ``activate`` drops turds into the user's shell environment, leaving them - vulnerable to executing commands in the wrong context. ``deactivate`` might - not correctly restore previous shell environment variables. + ``activate`` makes changes to the user's shell environment which can often be convenient. However, in the context of long-form documentation, environment configuration can easily be forgotten. By keeping each snippet explicit we can reduce copy / paste errors by users in which commands are executed against the wrong Python environment. Also, ``deactivate`` might not correctly restore previous shell environment variables. Avoiding ``activate`` keeps the environment more reproducible. Although using ``source bin/activate``, then ``pip``, requires fewer key strokes to issue commands once invoked, there are other things to consider. -- cgit v1.2.3 From daf06d8f8dbfa3245ea4de28defc0249219b6b0e Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 7 Jun 2017 01:05:32 -0500 Subject: add versionadded directive for invoke_exception_view --- pyramid/view.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyramid/view.py b/pyramid/view.py index 47b756ad8..14d11825e 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -668,6 +668,8 @@ class ViewMethodsMixin(object): response. Otherwise the previous values for ``request.exception`` and ``request.exc_info`` will be restored. + .. versionadded:: 1.7 + .. versionchanged:: 1.9 The ``request.exception`` and ``request.exc_info`` properties will reflect the exception used to render the response where previously -- cgit v1.2.3 From 7b3249dff86b4359508897c77dea6aa75421b052 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Fri, 9 Jun 2017 00:04:35 -0500 Subject: add changelog for #3074 --- CHANGES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 06bb71c1e..1402045d4 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -17,6 +17,10 @@ unreleased invoked from ``request.invoke_exception_view``. See https://github.com/Pylons/pyramid/pull/3060 +- Fix a bug in which ``pyramid.security.ALL_PERMISSIONS`` failed to return + a valid iterator in its ``__iter__`` implementation. + See https://github.com/Pylons/pyramid/pull/3074 + 1.9a2 (2017-05-09) ================== -- cgit v1.2.3 From 5067ffcf19a8659777406b06485fefc75404f2fa Mon Sep 17 00:00:00 2001 From: Volker Diels-Grabsch Date: Fri, 9 Jun 2017 14:48:54 +0200 Subject: Fix forbidden_view for BasicAuthAuthenticationPolicy (#3066) --- CONTRIBUTORS.txt | 2 ++ pyramid/authentication.py | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index cbee08d0d..445536e9e 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -302,3 +302,5 @@ Contributors - Jeremy(Ching-Rui) Chen, 2017/04/19 - Fang-Pen Lin, 2017/05/22 + +- Volker Diels-Grabsch, 2017/06/09 diff --git a/pyramid/authentication.py b/pyramid/authentication.py index 03b204e1a..445d6fcd2 100644 --- a/pyramid/authentication.py +++ b/pyramid/authentication.py @@ -1084,10 +1084,12 @@ class BasicAuthAuthenticationPolicy(CallbackAuthenticationPolicy): from pyramid.view import forbidden_view_config @forbidden_view_config() - def basic_challenge(request): - response = HTTPUnauthorized() - response.headers.update(forget(request)) - return response + def forbidden_view(request): + if request.authenticated_userid is None: + response = HTTPUnauthorized() + response.headers.update(forget(request)) + return response + return HTTPForbidden() """ def __init__(self, check, realm='Realm', debug=False): self.check = check -- cgit v1.2.3 From 85623b13b3790dcfae53697f282e9f8e68736e35 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 10 Jun 2017 21:45:09 -0700 Subject: Update src files for ZODB wiki tutorial - ref #3081 --- docs/tutorials/wiki/src/authorization/development.ini | 2 ++ docs/tutorials/wiki/src/authorization/production.ini | 2 ++ docs/tutorials/wiki/src/authorization/setup.py | 4 +++- docs/tutorials/wiki/src/authorization/tutorial/__init__.py | 3 +++ docs/tutorials/wiki/src/basiclayout/README.txt | 2 +- docs/tutorials/wiki/src/basiclayout/development.ini | 2 ++ docs/tutorials/wiki/src/basiclayout/production.ini | 2 ++ docs/tutorials/wiki/src/basiclayout/setup.py | 4 +++- docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py | 3 +++ docs/tutorials/wiki/src/installation/README.txt | 2 +- docs/tutorials/wiki/src/installation/development.ini | 2 ++ docs/tutorials/wiki/src/installation/production.ini | 2 ++ docs/tutorials/wiki/src/installation/setup.py | 4 +++- docs/tutorials/wiki/src/installation/tutorial/__init__.py | 3 +++ docs/tutorials/wiki/src/models/README.txt | 2 +- docs/tutorials/wiki/src/models/development.ini | 2 ++ docs/tutorials/wiki/src/models/production.ini | 2 ++ docs/tutorials/wiki/src/models/setup.py | 4 +++- docs/tutorials/wiki/src/models/tutorial/__init__.py | 3 +++ docs/tutorials/wiki/src/tests/development.ini | 2 ++ docs/tutorials/wiki/src/tests/production.ini | 2 ++ docs/tutorials/wiki/src/tests/setup.py | 4 +++- docs/tutorials/wiki/src/tests/tutorial/__init__.py | 3 +++ docs/tutorials/wiki/src/views/development.ini | 2 ++ docs/tutorials/wiki/src/views/production.ini | 2 ++ docs/tutorials/wiki/src/views/setup.py | 4 +++- docs/tutorials/wiki/src/views/tutorial/__init__.py | 3 +++ 27 files changed, 63 insertions(+), 9 deletions(-) diff --git a/docs/tutorials/wiki/src/authorization/development.ini b/docs/tutorials/wiki/src/authorization/development.ini index 74e7457d6..9d45c3611 100644 --- a/docs/tutorials/wiki/src/authorization/development.ini +++ b/docs/tutorials/wiki/src/authorization/development.ini @@ -16,6 +16,8 @@ pyramid.includes = zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki/src/authorization/production.ini b/docs/tutorials/wiki/src/authorization/production.ini index 60b6fe253..92a36813f 100644 --- a/docs/tutorials/wiki/src/authorization/production.ini +++ b/docs/tutorials/wiki/src/authorization/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/tutorials/wiki/src/authorization/setup.py b/docs/tutorials/wiki/src/authorization/setup.py index 4a9f041e3..3f0b1317c 100644 --- a/docs/tutorials/wiki/src/authorization/setup.py +++ b/docs/tutorials/wiki/src/authorization/setup.py @@ -9,9 +9,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ - 'pyramid', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', diff --git a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py index 8af2ee5c0..e584eff2b 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py @@ -19,10 +19,13 @@ def main(global_config, **settings): 'sosecret', callback=groupfinder, hashalg='sha512') authz_policy = ACLAuthorizationPolicy() config = Configurator(root_factory=root_factory, settings=settings) + settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) config.include('pyramid_chameleon') config.include('pyramid_tm') + config.include('pyramid_retry') config.include('pyramid_zodbconn') config.add_static_view('static', 'static', cache_max_age=3600) config.scan() diff --git a/docs/tutorials/wiki/src/basiclayout/README.txt b/docs/tutorials/wiki/src/basiclayout/README.txt index 5ec53bf9d..8a56d14af 100644 --- a/docs/tutorials/wiki/src/basiclayout/README.txt +++ b/docs/tutorials/wiki/src/basiclayout/README.txt @@ -14,7 +14,7 @@ Getting Started - Upgrade packaging tools. - env/bin/pip install --upgrade pip setuptools wheel + env/bin/pip install --upgrade pip setuptools - Install the project in editable mode with its testing requirements. diff --git a/docs/tutorials/wiki/src/basiclayout/development.ini b/docs/tutorials/wiki/src/basiclayout/development.ini index 74e7457d6..9d45c3611 100644 --- a/docs/tutorials/wiki/src/basiclayout/development.ini +++ b/docs/tutorials/wiki/src/basiclayout/development.ini @@ -16,6 +16,8 @@ pyramid.includes = zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki/src/basiclayout/production.ini b/docs/tutorials/wiki/src/basiclayout/production.ini index 60b6fe253..92a36813f 100644 --- a/docs/tutorials/wiki/src/basiclayout/production.ini +++ b/docs/tutorials/wiki/src/basiclayout/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/tutorials/wiki/src/basiclayout/setup.py b/docs/tutorials/wiki/src/basiclayout/setup.py index 5d1e9c7b5..d743c984f 100644 --- a/docs/tutorials/wiki/src/basiclayout/setup.py +++ b/docs/tutorials/wiki/src/basiclayout/setup.py @@ -9,9 +9,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ - 'pyramid', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py index 728f7ac02..eb703e086 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py @@ -12,8 +12,11 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(root_factory=root_factory, settings=settings) + settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_chameleon') config.include('pyramid_tm') + config.include('pyramid_retry') config.include('pyramid_zodbconn') config.add_static_view('static', 'static', cache_max_age=3600) config.scan() diff --git a/docs/tutorials/wiki/src/installation/README.txt b/docs/tutorials/wiki/src/installation/README.txt index 5ec53bf9d..8a56d14af 100644 --- a/docs/tutorials/wiki/src/installation/README.txt +++ b/docs/tutorials/wiki/src/installation/README.txt @@ -14,7 +14,7 @@ Getting Started - Upgrade packaging tools. - env/bin/pip install --upgrade pip setuptools wheel + env/bin/pip install --upgrade pip setuptools - Install the project in editable mode with its testing requirements. diff --git a/docs/tutorials/wiki/src/installation/development.ini b/docs/tutorials/wiki/src/installation/development.ini index 74e7457d6..9d45c3611 100644 --- a/docs/tutorials/wiki/src/installation/development.ini +++ b/docs/tutorials/wiki/src/installation/development.ini @@ -16,6 +16,8 @@ pyramid.includes = zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki/src/installation/production.ini b/docs/tutorials/wiki/src/installation/production.ini index 60b6fe253..92a36813f 100644 --- a/docs/tutorials/wiki/src/installation/production.ini +++ b/docs/tutorials/wiki/src/installation/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/tutorials/wiki/src/installation/setup.py b/docs/tutorials/wiki/src/installation/setup.py index 5d1e9c7b5..d743c984f 100644 --- a/docs/tutorials/wiki/src/installation/setup.py +++ b/docs/tutorials/wiki/src/installation/setup.py @@ -9,9 +9,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ - 'pyramid', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', diff --git a/docs/tutorials/wiki/src/installation/tutorial/__init__.py b/docs/tutorials/wiki/src/installation/tutorial/__init__.py index 728f7ac02..eb703e086 100644 --- a/docs/tutorials/wiki/src/installation/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/installation/tutorial/__init__.py @@ -12,8 +12,11 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(root_factory=root_factory, settings=settings) + settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_chameleon') config.include('pyramid_tm') + config.include('pyramid_retry') config.include('pyramid_zodbconn') config.add_static_view('static', 'static', cache_max_age=3600) config.scan() diff --git a/docs/tutorials/wiki/src/models/README.txt b/docs/tutorials/wiki/src/models/README.txt index 5ec53bf9d..8a56d14af 100644 --- a/docs/tutorials/wiki/src/models/README.txt +++ b/docs/tutorials/wiki/src/models/README.txt @@ -14,7 +14,7 @@ Getting Started - Upgrade packaging tools. - env/bin/pip install --upgrade pip setuptools wheel + env/bin/pip install --upgrade pip setuptools - Install the project in editable mode with its testing requirements. diff --git a/docs/tutorials/wiki/src/models/development.ini b/docs/tutorials/wiki/src/models/development.ini index 74e7457d6..9d45c3611 100644 --- a/docs/tutorials/wiki/src/models/development.ini +++ b/docs/tutorials/wiki/src/models/development.ini @@ -16,6 +16,8 @@ pyramid.includes = zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki/src/models/production.ini b/docs/tutorials/wiki/src/models/production.ini index 60b6fe253..92a36813f 100644 --- a/docs/tutorials/wiki/src/models/production.ini +++ b/docs/tutorials/wiki/src/models/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/tutorials/wiki/src/models/setup.py b/docs/tutorials/wiki/src/models/setup.py index 5d1e9c7b5..d743c984f 100644 --- a/docs/tutorials/wiki/src/models/setup.py +++ b/docs/tutorials/wiki/src/models/setup.py @@ -9,9 +9,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ - 'pyramid', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', diff --git a/docs/tutorials/wiki/src/models/tutorial/__init__.py b/docs/tutorials/wiki/src/models/tutorial/__init__.py index 728f7ac02..eb703e086 100644 --- a/docs/tutorials/wiki/src/models/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/models/tutorial/__init__.py @@ -12,8 +12,11 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(root_factory=root_factory, settings=settings) + settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_chameleon') config.include('pyramid_tm') + config.include('pyramid_retry') config.include('pyramid_zodbconn') config.add_static_view('static', 'static', cache_max_age=3600) config.scan() diff --git a/docs/tutorials/wiki/src/tests/development.ini b/docs/tutorials/wiki/src/tests/development.ini index 74e7457d6..9d45c3611 100644 --- a/docs/tutorials/wiki/src/tests/development.ini +++ b/docs/tutorials/wiki/src/tests/development.ini @@ -16,6 +16,8 @@ pyramid.includes = zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki/src/tests/production.ini b/docs/tutorials/wiki/src/tests/production.ini index 60b6fe253..92a36813f 100644 --- a/docs/tutorials/wiki/src/tests/production.ini +++ b/docs/tutorials/wiki/src/tests/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/tutorials/wiki/src/tests/setup.py b/docs/tutorials/wiki/src/tests/setup.py index 4a9f041e3..3f0b1317c 100644 --- a/docs/tutorials/wiki/src/tests/setup.py +++ b/docs/tutorials/wiki/src/tests/setup.py @@ -9,9 +9,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ - 'pyramid', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', diff --git a/docs/tutorials/wiki/src/tests/tutorial/__init__.py b/docs/tutorials/wiki/src/tests/tutorial/__init__.py index 8af2ee5c0..e584eff2b 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/tests/tutorial/__init__.py @@ -19,10 +19,13 @@ def main(global_config, **settings): 'sosecret', callback=groupfinder, hashalg='sha512') authz_policy = ACLAuthorizationPolicy() config = Configurator(root_factory=root_factory, settings=settings) + settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) config.include('pyramid_chameleon') config.include('pyramid_tm') + config.include('pyramid_retry') config.include('pyramid_zodbconn') config.add_static_view('static', 'static', cache_max_age=3600) config.scan() diff --git a/docs/tutorials/wiki/src/views/development.ini b/docs/tutorials/wiki/src/views/development.ini index 74e7457d6..9d45c3611 100644 --- a/docs/tutorials/wiki/src/views/development.ini +++ b/docs/tutorials/wiki/src/views/development.ini @@ -16,6 +16,8 @@ pyramid.includes = zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki/src/views/production.ini b/docs/tutorials/wiki/src/views/production.ini index 60b6fe253..92a36813f 100644 --- a/docs/tutorials/wiki/src/views/production.ini +++ b/docs/tutorials/wiki/src/views/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/tutorials/wiki/src/views/setup.py b/docs/tutorials/wiki/src/views/setup.py index 598ad8146..bd3d15af1 100644 --- a/docs/tutorials/wiki/src/views/setup.py +++ b/docs/tutorials/wiki/src/views/setup.py @@ -9,9 +9,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ - 'pyramid', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', diff --git a/docs/tutorials/wiki/src/views/tutorial/__init__.py b/docs/tutorials/wiki/src/views/tutorial/__init__.py index 728f7ac02..eb703e086 100644 --- a/docs/tutorials/wiki/src/views/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/views/tutorial/__init__.py @@ -12,8 +12,11 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(root_factory=root_factory, settings=settings) + settings = config.get_settings() + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_chameleon') config.include('pyramid_tm') + config.include('pyramid_retry') config.include('pyramid_zodbconn') config.add_static_view('static', 'static', cache_max_age=3600) config.scan() -- cgit v1.2.3 From 909ae055f2f7391036736ff41a0564becb60478f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 10 Jun 2017 22:09:12 -0700 Subject: synch emphasize-lines with src files for zodb wiki tutorial --- docs/tutorials/wiki/authorization.rst | 8 ++++---- docs/tutorials/wiki/basiclayout.rst | 12 ++++++++---- docs/tutorials/wiki/definingviews.rst | 2 +- docs/tutorials/wiki/installation.rst | 4 ++-- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index 0ba734f83..211d69f3a 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -49,7 +49,7 @@ Open ``setup.py`` and edit it to look like the following: .. literalinclude:: src/authorization/setup.py :linenos: - :emphasize-lines: 21 + :emphasize-lines: 23 :language: python Only the highlighted line needs to be added. @@ -155,9 +155,9 @@ statements: Now add those policies to the configuration: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 18-23 + :lines: 18-25 :lineno-match: - :emphasize-lines: 1-3,5-6 + :emphasize-lines: 1-3,7-9 :language: python Only the highlighted lines need to be added. @@ -327,7 +327,7 @@ Our ``tutorial/__init__.py`` will look like this when we're done: .. literalinclude:: src/authorization/tutorial/__init__.py :linenos: - :emphasize-lines: 4-5,8,18-20,22-23 + :emphasize-lines: 4-5,8,18-20,24-25 :language: python Only the highlighted lines need to be added or edited. diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index d00eab956..f713d1057 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -41,14 +41,18 @@ Open ``tutorial/__init__.py``. It should already contain the following: factory and the settings keywords parsed by :term:`PasteDeploy`. The root factory is named ``root_factory``. -#. *Line 15*. Include support for the :term:`Chameleon` template rendering +#. *Lines 15 and 16*. Get the settings and use an explicit transaction transaction manager for apps so that they do not implicitly create new transactions when touching the manager outside of the ``pyramid_tm`` lifecycle. + +#. *Line 17*. Include support for the :term:`Chameleon` template rendering bindings, allowing us to use the ``.pt`` templates. -#. *Line 16*. Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction `_ package. +#. *Line 18*. Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction `_ package. + +#. *Line 19*. Include support for ``pyramid_retry`` to retry a request when transient exceptions occur. -#. *Line 17*. Include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application. +#. *Line 20*. Include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application. -#. *Line 18*. Register a "static view", which answers requests whose URL +#. *Line 21*. Register a "static view", which answers requests whose URL paths start with ``/static``, using the :meth:`pyramid.config.Configurator.add_static_view` method. This statement registers a view that will serve up static assets, such as CSS diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 442d5ed18..f4ca9b8d7 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -47,7 +47,7 @@ Open ``setup.py`` and edit it to look like the following: .. literalinclude:: src/views/setup.py :linenos: - :emphasize-lines: 20 + :emphasize-lines: 22 :language: python Only the highlighted line needs to be added. diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index 3e7434bd7..e9a93f9fe 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -180,12 +180,12 @@ Testing requirements are defined in our project's ``setup.py`` file, in the ``te .. literalinclude:: src/installation/setup.py :language: python :lineno-match: - :lines: 22-26 + :lines: 24-28 .. literalinclude:: src/installation/setup.py :language: python :lineno-match: - :lines: 46-48 + :lines: 48-50 .. _running_tests: -- cgit v1.2.3 From 2c0e3e334955574383fa73eaf932931199e13a8a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 10 Jun 2017 22:57:54 -0700 Subject: update src files and synch emphasize-lines for alchemy wiki tutorial --- docs/tutorials/wiki2/authentication.rst | 4 ++-- docs/tutorials/wiki2/definingmodels.rst | 2 +- docs/tutorials/wiki2/installation.rst | 4 ++-- docs/tutorials/wiki2/src/authentication/README.txt | 2 +- docs/tutorials/wiki2/src/authentication/development.ini | 2 ++ docs/tutorials/wiki2/src/authentication/production.ini | 2 ++ docs/tutorials/wiki2/src/authentication/setup.py | 6 ++++-- docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py | 3 +++ docs/tutorials/wiki2/src/authorization/README.txt | 2 +- docs/tutorials/wiki2/src/authorization/development.ini | 2 ++ docs/tutorials/wiki2/src/authorization/production.ini | 2 ++ docs/tutorials/wiki2/src/authorization/setup.py | 6 ++++-- docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py | 3 +++ docs/tutorials/wiki2/src/basiclayout/README.txt | 2 +- docs/tutorials/wiki2/src/basiclayout/development.ini | 2 ++ docs/tutorials/wiki2/src/basiclayout/production.ini | 2 ++ docs/tutorials/wiki2/src/basiclayout/setup.py | 6 ++++-- docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py | 3 +++ docs/tutorials/wiki2/src/installation/README.txt | 2 +- docs/tutorials/wiki2/src/installation/development.ini | 2 ++ docs/tutorials/wiki2/src/installation/production.ini | 2 ++ docs/tutorials/wiki2/src/installation/setup.py | 6 ++++-- docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py | 3 +++ docs/tutorials/wiki2/src/models/README.txt | 2 +- docs/tutorials/wiki2/src/models/development.ini | 2 ++ docs/tutorials/wiki2/src/models/production.ini | 2 ++ docs/tutorials/wiki2/src/models/setup.py | 6 ++++-- docs/tutorials/wiki2/src/models/tutorial/__init__.py | 2 -- docs/tutorials/wiki2/src/models/tutorial/models/__init__.py | 3 +++ docs/tutorials/wiki2/src/tests/README.txt | 2 +- docs/tutorials/wiki2/src/tests/development.ini | 2 ++ docs/tutorials/wiki2/src/tests/production.ini | 2 ++ docs/tutorials/wiki2/src/tests/setup.py | 6 ++++-- docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py | 3 +++ docs/tutorials/wiki2/src/views/README.txt | 2 +- docs/tutorials/wiki2/src/views/development.ini | 2 ++ docs/tutorials/wiki2/src/views/production.ini | 2 ++ docs/tutorials/wiki2/src/views/setup.py | 6 ++++-- docs/tutorials/wiki2/src/views/tutorial/models/__init__.py | 3 +++ 39 files changed, 89 insertions(+), 28 deletions(-) diff --git a/docs/tutorials/wiki2/authentication.rst b/docs/tutorials/wiki2/authentication.rst index ff59ce70b..85977d1be 100644 --- a/docs/tutorials/wiki2/authentication.rst +++ b/docs/tutorials/wiki2/authentication.rst @@ -92,7 +92,7 @@ Our authentication policy is expecting a new setting, ``auth.secret``. Open the file ``development.ini`` and add the highlighted line below: .. literalinclude:: src/authentication/development.ini - :lines: 17-19 + :lines: 19-21 :emphasize-lines: 3 :lineno-match: :language: ini @@ -101,7 +101,7 @@ Finally, best practices tell us to use a different secret for production, so open ``production.ini`` and add a different secret: .. literalinclude:: src/authentication/production.ini - :lines: 15-17 + :lines: 17-19 :emphasize-lines: 3 :lineno-match: :language: ini diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst index 801b56eb4..5cebb943c 100644 --- a/docs/tutorials/wiki2/definingmodels.rst +++ b/docs/tutorials/wiki2/definingmodels.rst @@ -153,7 +153,7 @@ the following: .. literalinclude:: src/models/tutorial/models/__init__.py :linenos: :language: py - :emphasize-lines: 10,11 + :emphasize-lines: 8,9 Here we align our imports with the names of the models, ``Page`` and ``User``. diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index 56197900c..0d49fc12b 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -190,12 +190,12 @@ Testing requirements are defined in our project's ``setup.py`` file, in the ``te .. literalinclude:: src/installation/setup.py :language: python :lineno-match: - :lines: 22-26 + :lines: 24-28 .. literalinclude:: src/installation/setup.py :language: python :lineno-match: - :lines: 46-48 + :lines: 48-50 .. _sql_running_tests: diff --git a/docs/tutorials/wiki2/src/authentication/README.txt b/docs/tutorials/wiki2/src/authentication/README.txt index 81102a869..7b33da610 100644 --- a/docs/tutorials/wiki2/src/authentication/README.txt +++ b/docs/tutorials/wiki2/src/authentication/README.txt @@ -14,7 +14,7 @@ Getting Started - Upgrade packaging tools. - env/bin/pip install --upgrade pip setuptools wheel + env/bin/pip install --upgrade pip setuptools - Install the project in editable mode with its testing requirements. diff --git a/docs/tutorials/wiki2/src/authentication/development.ini b/docs/tutorials/wiki2/src/authentication/development.ini index 0786c1f66..00d0dd2bf 100644 --- a/docs/tutorials/wiki2/src/authentication/development.ini +++ b/docs/tutorials/wiki2/src/authentication/development.ini @@ -16,6 +16,8 @@ pyramid.includes = sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + auth.secret = seekrit # By default, the toolbar only appears for clients from IP addresses diff --git a/docs/tutorials/wiki2/src/authentication/production.ini b/docs/tutorials/wiki2/src/authentication/production.ini index 05d60feec..e55e9fecc 100644 --- a/docs/tutorials/wiki2/src/authentication/production.ini +++ b/docs/tutorials/wiki2/src/authentication/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + auth.secret = real-seekrit ### diff --git a/docs/tutorials/wiki2/src/authentication/setup.py b/docs/tutorials/wiki2/src/authentication/setup.py index cc1aa421c..abc24876d 100644 --- a/docs/tutorials/wiki2/src/authentication/setup.py +++ b/docs/tutorials/wiki2/src/authentication/setup.py @@ -11,9 +11,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'bcrypt', 'docutils', - 'pyramid', - 'pyramid_jinja2', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_debugtoolbar', + 'pyramid_jinja2', + 'pyramid_retry', 'pyramid_tm', 'SQLAlchemy', 'transaction', diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py index cd8347ccd..3c9ba8e54 100644 --- a/docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py @@ -63,6 +63,9 @@ def includeme(config): # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') + # use pyramid_retry to retry a request when transient exceptions occur + config.include('pyramid_retry') + session_factory = get_session_factory(get_engine(settings)) config.registry['dbsession_factory'] = session_factory diff --git a/docs/tutorials/wiki2/src/authorization/README.txt b/docs/tutorials/wiki2/src/authorization/README.txt index 81102a869..7b33da610 100644 --- a/docs/tutorials/wiki2/src/authorization/README.txt +++ b/docs/tutorials/wiki2/src/authorization/README.txt @@ -14,7 +14,7 @@ Getting Started - Upgrade packaging tools. - env/bin/pip install --upgrade pip setuptools wheel + env/bin/pip install --upgrade pip setuptools - Install the project in editable mode with its testing requirements. diff --git a/docs/tutorials/wiki2/src/authorization/development.ini b/docs/tutorials/wiki2/src/authorization/development.ini index 0786c1f66..00d0dd2bf 100644 --- a/docs/tutorials/wiki2/src/authorization/development.ini +++ b/docs/tutorials/wiki2/src/authorization/development.ini @@ -16,6 +16,8 @@ pyramid.includes = sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + auth.secret = seekrit # By default, the toolbar only appears for clients from IP addresses diff --git a/docs/tutorials/wiki2/src/authorization/production.ini b/docs/tutorials/wiki2/src/authorization/production.ini index 05d60feec..e55e9fecc 100644 --- a/docs/tutorials/wiki2/src/authorization/production.ini +++ b/docs/tutorials/wiki2/src/authorization/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + auth.secret = real-seekrit ### diff --git a/docs/tutorials/wiki2/src/authorization/setup.py b/docs/tutorials/wiki2/src/authorization/setup.py index cc1aa421c..abc24876d 100644 --- a/docs/tutorials/wiki2/src/authorization/setup.py +++ b/docs/tutorials/wiki2/src/authorization/setup.py @@ -11,9 +11,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'bcrypt', 'docutils', - 'pyramid', - 'pyramid_jinja2', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_debugtoolbar', + 'pyramid_jinja2', + 'pyramid_retry', 'pyramid_tm', 'SQLAlchemy', 'transaction', diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py index cd8347ccd..3c9ba8e54 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py @@ -63,6 +63,9 @@ def includeme(config): # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') + # use pyramid_retry to retry a request when transient exceptions occur + config.include('pyramid_retry') + session_factory = get_session_factory(get_engine(settings)) config.registry['dbsession_factory'] = session_factory diff --git a/docs/tutorials/wiki2/src/basiclayout/README.txt b/docs/tutorials/wiki2/src/basiclayout/README.txt index 81102a869..7b33da610 100644 --- a/docs/tutorials/wiki2/src/basiclayout/README.txt +++ b/docs/tutorials/wiki2/src/basiclayout/README.txt @@ -14,7 +14,7 @@ Getting Started - Upgrade packaging tools. - env/bin/pip install --upgrade pip setuptools wheel + env/bin/pip install --upgrade pip setuptools - Install the project in editable mode with its testing requirements. diff --git a/docs/tutorials/wiki2/src/basiclayout/development.ini b/docs/tutorials/wiki2/src/basiclayout/development.ini index be80882a5..73ef3d863 100644 --- a/docs/tutorials/wiki2/src/basiclayout/development.ini +++ b/docs/tutorials/wiki2/src/basiclayout/development.ini @@ -16,6 +16,8 @@ pyramid.includes = sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki2/src/basiclayout/production.ini b/docs/tutorials/wiki2/src/basiclayout/production.ini index c01ad9a7e..8dea38631 100644 --- a/docs/tutorials/wiki2/src/basiclayout/production.ini +++ b/docs/tutorials/wiki2/src/basiclayout/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/tutorials/wiki2/src/basiclayout/setup.py b/docs/tutorials/wiki2/src/basiclayout/setup.py index d3992a8f2..9fc5519a5 100644 --- a/docs/tutorials/wiki2/src/basiclayout/setup.py +++ b/docs/tutorials/wiki2/src/basiclayout/setup.py @@ -9,9 +9,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ - 'pyramid', - 'pyramid_jinja2', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_debugtoolbar', + 'pyramid_jinja2', + 'pyramid_retry', 'pyramid_tm', 'SQLAlchemy', 'transaction', diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py index ae575691c..d8a273e9e 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py @@ -62,6 +62,9 @@ def includeme(config): # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') + # use pyramid_retry to retry a request when transient exceptions occur + config.include('pyramid_retry') + session_factory = get_session_factory(get_engine(settings)) config.registry['dbsession_factory'] = session_factory diff --git a/docs/tutorials/wiki2/src/installation/README.txt b/docs/tutorials/wiki2/src/installation/README.txt index 81102a869..7b33da610 100644 --- a/docs/tutorials/wiki2/src/installation/README.txt +++ b/docs/tutorials/wiki2/src/installation/README.txt @@ -14,7 +14,7 @@ Getting Started - Upgrade packaging tools. - env/bin/pip install --upgrade pip setuptools wheel + env/bin/pip install --upgrade pip setuptools - Install the project in editable mode with its testing requirements. diff --git a/docs/tutorials/wiki2/src/installation/development.ini b/docs/tutorials/wiki2/src/installation/development.ini index be80882a5..73ef3d863 100644 --- a/docs/tutorials/wiki2/src/installation/development.ini +++ b/docs/tutorials/wiki2/src/installation/development.ini @@ -16,6 +16,8 @@ pyramid.includes = sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki2/src/installation/production.ini b/docs/tutorials/wiki2/src/installation/production.ini index c01ad9a7e..8dea38631 100644 --- a/docs/tutorials/wiki2/src/installation/production.ini +++ b/docs/tutorials/wiki2/src/installation/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/tutorials/wiki2/src/installation/setup.py b/docs/tutorials/wiki2/src/installation/setup.py index d3992a8f2..9fc5519a5 100644 --- a/docs/tutorials/wiki2/src/installation/setup.py +++ b/docs/tutorials/wiki2/src/installation/setup.py @@ -9,9 +9,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ - 'pyramid', - 'pyramid_jinja2', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_debugtoolbar', + 'pyramid_jinja2', + 'pyramid_retry', 'pyramid_tm', 'SQLAlchemy', 'transaction', diff --git a/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py index ae575691c..d8a273e9e 100644 --- a/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py @@ -62,6 +62,9 @@ def includeme(config): # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') + # use pyramid_retry to retry a request when transient exceptions occur + config.include('pyramid_retry') + session_factory = get_session_factory(get_engine(settings)) config.registry['dbsession_factory'] = session_factory diff --git a/docs/tutorials/wiki2/src/models/README.txt b/docs/tutorials/wiki2/src/models/README.txt index 81102a869..7b33da610 100644 --- a/docs/tutorials/wiki2/src/models/README.txt +++ b/docs/tutorials/wiki2/src/models/README.txt @@ -14,7 +14,7 @@ Getting Started - Upgrade packaging tools. - env/bin/pip install --upgrade pip setuptools wheel + env/bin/pip install --upgrade pip setuptools - Install the project in editable mode with its testing requirements. diff --git a/docs/tutorials/wiki2/src/models/development.ini b/docs/tutorials/wiki2/src/models/development.ini index be80882a5..73ef3d863 100644 --- a/docs/tutorials/wiki2/src/models/development.ini +++ b/docs/tutorials/wiki2/src/models/development.ini @@ -16,6 +16,8 @@ pyramid.includes = sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki2/src/models/production.ini b/docs/tutorials/wiki2/src/models/production.ini index c01ad9a7e..8dea38631 100644 --- a/docs/tutorials/wiki2/src/models/production.ini +++ b/docs/tutorials/wiki2/src/models/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/tutorials/wiki2/src/models/setup.py b/docs/tutorials/wiki2/src/models/setup.py index faf76aa27..c688c6866 100644 --- a/docs/tutorials/wiki2/src/models/setup.py +++ b/docs/tutorials/wiki2/src/models/setup.py @@ -10,9 +10,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'bcrypt', - 'pyramid', - 'pyramid_jinja2', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_debugtoolbar', + 'pyramid_jinja2', + 'pyramid_retry', 'pyramid_tm', 'SQLAlchemy', 'transaction', diff --git a/docs/tutorials/wiki2/src/models/tutorial/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/__init__.py index 7654fc808..4dab44823 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/models/tutorial/__init__.py @@ -5,8 +5,6 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(settings=settings) - settings = config.get_settings() - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_jinja2') config.include('.models') config.include('.routes') diff --git a/docs/tutorials/wiki2/src/models/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/models/__init__.py index cd8347ccd..3c9ba8e54 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/models/tutorial/models/__init__.py @@ -63,6 +63,9 @@ def includeme(config): # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') + # use pyramid_retry to retry a request when transient exceptions occur + config.include('pyramid_retry') + session_factory = get_session_factory(get_engine(settings)) config.registry['dbsession_factory'] = session_factory diff --git a/docs/tutorials/wiki2/src/tests/README.txt b/docs/tutorials/wiki2/src/tests/README.txt index 81102a869..7b33da610 100644 --- a/docs/tutorials/wiki2/src/tests/README.txt +++ b/docs/tutorials/wiki2/src/tests/README.txt @@ -14,7 +14,7 @@ Getting Started - Upgrade packaging tools. - env/bin/pip install --upgrade pip setuptools wheel + env/bin/pip install --upgrade pip setuptools - Install the project in editable mode with its testing requirements. diff --git a/docs/tutorials/wiki2/src/tests/development.ini b/docs/tutorials/wiki2/src/tests/development.ini index 0786c1f66..00d0dd2bf 100644 --- a/docs/tutorials/wiki2/src/tests/development.ini +++ b/docs/tutorials/wiki2/src/tests/development.ini @@ -16,6 +16,8 @@ pyramid.includes = sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + auth.secret = seekrit # By default, the toolbar only appears for clients from IP addresses diff --git a/docs/tutorials/wiki2/src/tests/production.ini b/docs/tutorials/wiki2/src/tests/production.ini index 05d60feec..e55e9fecc 100644 --- a/docs/tutorials/wiki2/src/tests/production.ini +++ b/docs/tutorials/wiki2/src/tests/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + auth.secret = real-seekrit ### diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py index cc1aa421c..abc24876d 100644 --- a/docs/tutorials/wiki2/src/tests/setup.py +++ b/docs/tutorials/wiki2/src/tests/setup.py @@ -11,9 +11,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'bcrypt', 'docutils', - 'pyramid', - 'pyramid_jinja2', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_debugtoolbar', + 'pyramid_jinja2', + 'pyramid_retry', 'pyramid_tm', 'SQLAlchemy', 'transaction', diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py index cd8347ccd..3c9ba8e54 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py @@ -63,6 +63,9 @@ def includeme(config): # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') + # use pyramid_retry to retry a request when transient exceptions occur + config.include('pyramid_retry') + session_factory = get_session_factory(get_engine(settings)) config.registry['dbsession_factory'] = session_factory diff --git a/docs/tutorials/wiki2/src/views/README.txt b/docs/tutorials/wiki2/src/views/README.txt index 81102a869..7b33da610 100644 --- a/docs/tutorials/wiki2/src/views/README.txt +++ b/docs/tutorials/wiki2/src/views/README.txt @@ -14,7 +14,7 @@ Getting Started - Upgrade packaging tools. - env/bin/pip install --upgrade pip setuptools wheel + env/bin/pip install --upgrade pip setuptools - Install the project in editable mode with its testing requirements. diff --git a/docs/tutorials/wiki2/src/views/development.ini b/docs/tutorials/wiki2/src/views/development.ini index be80882a5..73ef3d863 100644 --- a/docs/tutorials/wiki2/src/views/development.ini +++ b/docs/tutorials/wiki2/src/views/development.ini @@ -16,6 +16,8 @@ pyramid.includes = sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/tutorials/wiki2/src/views/production.ini b/docs/tutorials/wiki2/src/views/production.ini index c01ad9a7e..8dea38631 100644 --- a/docs/tutorials/wiki2/src/views/production.ini +++ b/docs/tutorials/wiki2/src/views/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/tutorials/wiki2/src/views/setup.py b/docs/tutorials/wiki2/src/views/setup.py index cc1aa421c..abc24876d 100644 --- a/docs/tutorials/wiki2/src/views/setup.py +++ b/docs/tutorials/wiki2/src/views/setup.py @@ -11,9 +11,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'bcrypt', 'docutils', - 'pyramid', - 'pyramid_jinja2', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_debugtoolbar', + 'pyramid_jinja2', + 'pyramid_retry', 'pyramid_tm', 'SQLAlchemy', 'transaction', diff --git a/docs/tutorials/wiki2/src/views/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/models/__init__.py index cd8347ccd..3c9ba8e54 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/models/__init__.py +++ b/docs/tutorials/wiki2/src/views/tutorial/models/__init__.py @@ -63,6 +63,9 @@ def includeme(config): # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') + # use pyramid_retry to retry a request when transient exceptions occur + config.include('pyramid_retry') + session_factory = get_session_factory(get_engine(settings)) config.registry['dbsession_factory'] = session_factory -- cgit v1.2.3 From bb079f4094da8e2dce39e4020f6126b9df533728 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 10 Jun 2017 23:20:52 -0700 Subject: update src files and synch emphasize-lines for myproject --- docs/narr/myproject/setup.py | 1 + docs/narr/testing.rst | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/narr/myproject/setup.py b/docs/narr/myproject/setup.py index 00e377349..153a659ba 100644 --- a/docs/narr/myproject/setup.py +++ b/docs/narr/myproject/setup.py @@ -9,6 +9,7 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ + 'plaster_pastedeploy', 'pyramid', 'pyramid_jinja2', 'pyramid_debugtoolbar', diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst index 406383bbd..f124ac562 100644 --- a/docs/narr/testing.rst +++ b/docs/narr/testing.rst @@ -376,18 +376,16 @@ following the ``requires`` block in the file ``myproject/setup.py``. .. literalinclude:: myproject/setup.py :language: python - :linenos: - :lines: 11-22 - :lineno-start: 11 - :emphasize-lines: 8- + :lines: 11-23 + :lineno-match: + :emphasize-lines: 9- Remember to change the dependency. .. literalinclude:: myproject/setup.py :language: python - :linenos: - :lines: 40-44 - :lineno-start: 40 + :lines: 42-46 + :lineno-match: :emphasize-lines: 2-4 As always, whenever you change your dependencies, make sure to run the correct -- cgit v1.2.3 From 65a6d3a79f8fdcdd32a70888c669a8548366f7cb Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 10 Jun 2017 23:45:31 -0700 Subject: update src files and synch emphasize-lines for quick_tour --- docs/quick_tour.rst | 20 ++++++-------------- docs/quick_tour/logging/setup.py | 1 + docs/quick_tour/package/setup.py | 1 + docs/quick_tour/sessions/setup.py | 1 + docs/quick_tour/sqla_demo/development.ini | 2 ++ docs/quick_tour/sqla_demo/production.ini | 2 ++ docs/quick_tour/sqla_demo/setup.py | 6 ++++-- .../sqla_demo/sqla_demo/models/__init__.py | 4 ++++ 8 files changed, 21 insertions(+), 16 deletions(-) diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst index f3a0a27b8..5679b0dc8 100644 --- a/docs/quick_tour.rst +++ b/docs/quick_tour.rst @@ -647,8 +647,8 @@ add-on ``pyramid_debugtoolbar`` in its ``setup.py``: .. literalinclude:: quick_tour/package/setup.py :language: python :lineno-match: - :lines: 11-16 - :emphasize-lines: 4 + :lines: 11-17 + :emphasize-lines: 5 It was installed when you previously ran: @@ -657,14 +657,7 @@ It was installed when you previously ran: $ $VENV/bin/pip install -e ".[testing]" The ``pyramid_debugtoolbar`` package is a Pyramid add-on, which means we need -to include its configuration into our web application. The cookiecutter already took care of this for us in its ``__init__.py``: - -.. literalinclude:: quick_tour/package/hello_world/__init__.py - :language: python - :lineno-match: - :lines: 8 - -And it uses the ``pyramid.includes`` facility in our ``development.ini``: +to include its configuration into our web application. The cookiecutter already took care of this for us in its ``development.ini`` using the ``pyramid.includes`` facility: .. literalinclude:: quick_tour/package/development.ini :language: ini @@ -692,18 +685,17 @@ before its release. Our ``pyramid-cookiecutter-starter`` cookiecutter generated a ``tests.py`` module with one unit test and one functional test in it. It also configured ``setup.py`` with test requirements: ``py.test`` as the test runner, ``WebTest`` for running view tests, and the -``pytest-cov`` tool which yells at us for code that isn't tested. The -highlighted lines show this: +``pytest-cov`` tool which yells at us for code that isn't tested: .. literalinclude:: quick_tour/package/setup.py :language: python :lineno-match: - :lines: 18-22 + :lines: 19-23 .. literalinclude:: quick_tour/package/setup.py :language: python :lineno-match: - :lines: 42-44 + :lines: 43-45 We already installed the test requirements when we ran the command ``$VENV/bin/pip install -e ".[testing]"``. We can now run all our tests: diff --git a/docs/quick_tour/logging/setup.py b/docs/quick_tour/logging/setup.py index e32aecacd..44d90b990 100644 --- a/docs/quick_tour/logging/setup.py +++ b/docs/quick_tour/logging/setup.py @@ -9,6 +9,7 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ + 'plaster_pastedeploy', 'pyramid', 'pyramid_jinja2', 'pyramid_debugtoolbar', diff --git a/docs/quick_tour/package/setup.py b/docs/quick_tour/package/setup.py index e32aecacd..44d90b990 100644 --- a/docs/quick_tour/package/setup.py +++ b/docs/quick_tour/package/setup.py @@ -9,6 +9,7 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ + 'plaster_pastedeploy', 'pyramid', 'pyramid_jinja2', 'pyramid_debugtoolbar', diff --git a/docs/quick_tour/sessions/setup.py b/docs/quick_tour/sessions/setup.py index e32aecacd..44d90b990 100644 --- a/docs/quick_tour/sessions/setup.py +++ b/docs/quick_tour/sessions/setup.py @@ -9,6 +9,7 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ + 'plaster_pastedeploy', 'pyramid', 'pyramid_jinja2', 'pyramid_debugtoolbar', diff --git a/docs/quick_tour/sqla_demo/development.ini b/docs/quick_tour/sqla_demo/development.ini index 8d45a0975..a986c0063 100644 --- a/docs/quick_tour/sqla_demo/development.ini +++ b/docs/quick_tour/sqla_demo/development.ini @@ -16,6 +16,8 @@ pyramid.includes = sqlalchemy.url = sqlite:///%(here)s/sqla_demo.sqlite +retry.attempts = 3 + # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. # debugtoolbar.hosts = 127.0.0.1 ::1 diff --git a/docs/quick_tour/sqla_demo/production.ini b/docs/quick_tour/sqla_demo/production.ini index a85c354d3..9abb54231 100644 --- a/docs/quick_tour/sqla_demo/production.ini +++ b/docs/quick_tour/sqla_demo/production.ini @@ -14,6 +14,8 @@ pyramid.default_locale_name = en sqlalchemy.url = sqlite:///%(here)s/sqla_demo.sqlite +retry.attempts = 3 + ### # wsgi server configuration ### diff --git a/docs/quick_tour/sqla_demo/setup.py b/docs/quick_tour/sqla_demo/setup.py index 75c1403fb..855a15d58 100644 --- a/docs/quick_tour/sqla_demo/setup.py +++ b/docs/quick_tour/sqla_demo/setup.py @@ -9,9 +9,11 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: CHANGES = f.read() requires = [ - 'pyramid', - 'pyramid_jinja2', + 'plaster_pastedeploy', + 'pyramid >= 1.9a', 'pyramid_debugtoolbar', + 'pyramid_jinja2', + 'pyramid_retry', 'pyramid_tm', 'SQLAlchemy', 'transaction', diff --git a/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py b/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py index e6eb98fbd..31aab9d26 100644 --- a/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py +++ b/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py @@ -58,9 +58,13 @@ def includeme(config): """ settings = config.get_settings() settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' + # use pyramid_tm to hook the transaction lifecycle to the request config.include('pyramid_tm') + # use pyramid_retry to retry a request when transient exceptions occur + config.include('pyramid_retry') + session_factory = get_session_factory(get_engine(settings)) config.registry['dbsession_factory'] = session_factory -- cgit v1.2.3 From fa13770dba3947ce78c2a67041cbd02272992104 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 11 Jun 2017 00:06:53 -0700 Subject: fix out of range error --- docs/tutorials/wiki/authorization.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index 211d69f3a..c9ba9feb3 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -157,7 +157,7 @@ Now add those policies to the configuration: .. literalinclude:: src/authorization/tutorial/__init__.py :lines: 18-25 :lineno-match: - :emphasize-lines: 1-3,7-9 + :emphasize-lines: 1-3,7-8 :language: python Only the highlighted lines need to be added. -- cgit v1.2.3 From cdd0a86b46ecf0a16403ccf780c87f2c938b3e0c Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 11 Jun 2017 22:53:10 -0500 Subject: update whatsnew-1.9 --- docs/whatsnew-1.9.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/whatsnew-1.9.rst b/docs/whatsnew-1.9.rst index 0ba29625c..eca159d4c 100644 --- a/docs/whatsnew-1.9.rst +++ b/docs/whatsnew-1.9.rst @@ -35,6 +35,10 @@ Minor Feature Additions - The threadlocals are now available inside any function invoked via :meth:`pyramid.config.Configurator.include`. This means the only config-time code that cannot rely on threadlocals is code executed from non-actions inside the main. This can be alleviated by invoking :meth:`pyramid.config.Configurator.begin` and :meth:`pyramid.config.Configurator.end` appropriately or using the new context manager feature of the configurator. See https://github.com/Pylons/pyramid/pull/2989 +- The threadlocals are now available inside exception views invoked via :meth:`pyramid.request.Request.invoke_exception_view` even when the ``request`` argument is overridden. See https://github.com/Pylons/pyramid/pull/3060 + +- When unsupported predicates are supplied to :meth:`pyramid.config.Configurator.add_view`, :meth:`pyramid.config.Configurator.add_route` and :meth:`pyramid.config.Configurator.add_subscriber` a much more helpful error message is output with a guess as to which predicate was intended. See https://github.com/Pylons/pyramid/pull/3054 + Deprecations ------------ -- cgit v1.2.3 From 72ca1352493ef5b9113090598608da0c0d49389a Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 12 Jun 2017 01:07:57 -0500 Subject: apply request extensions within invoke_subrequest itself --- pyramid/router.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/pyramid/router.py b/pyramid/router.py index 7f3f9fbea..a02ff1715 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -192,13 +192,21 @@ class Router(object): """ request.registry = self.registry request.invoke_subrequest = self.invoke_subrequest - return self.invoke_request( - request, - _use_tweens=use_tweens, - _apply_extensions=True, - ) + extensions = self.request_extensions + if extensions is not None: + apply_request_extensions(request, extensions=extensions) + return self.invoke_request(request, _use_tweens=use_tweens) def make_request(self, environ): + """ + Configure a request object for use by the router. + + The request is created using the configured + :class:`pyramid.interfaces.IRequestFactory` and will have any + configured request methods / properties added that were set by + :meth:`pyramid.config.Configurator.add_request_method`. + + """ request = self.request_factory(environ) request.registry = self.registry request.invoke_subrequest = self.invoke_subrequest @@ -207,8 +215,12 @@ class Router(object): apply_request_extensions(request, extensions=extensions) return request - def invoke_request(self, request, - _use_tweens=True, _apply_extensions=False): + def invoke_request(self, request, _use_tweens=True): + """ + Execute a request through the request processing pipeline and + return the generated response. + + """ registry = self.registry has_listeners = self.registry.has_listeners notify = self.registry.notify @@ -224,9 +236,6 @@ class Router(object): try: try: - extensions = self.request_extensions - if _apply_extensions and extensions is not None: - apply_request_extensions(request, extensions=extensions) response = handle_request(request) if request.response_callbacks: -- cgit v1.2.3 From 2e015c97443d381832554161d090b7608dba1e16 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 12 Jun 2017 01:11:02 -0500 Subject: typo --- pyramid/interfaces.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index ab83813c8..4a069ad65 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -713,7 +713,7 @@ class IExecutionPolicy(Interface): The return value should be a :class:`pyramid.interfaces.IResponse` object or an exception that will be handled by WSGI middleware. - The default execution policy simple creates a request and sends it + The default execution policy simply creates a request and sends it through the pipeline: .. code-block:: python -- cgit v1.2.3 From 21300198ee62eb00b757a77f2792329ff2d882a0 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 14 Jun 2017 23:21:04 -0500 Subject: fix p.security.ACLPermitsResult to subclass p.security.PermitsResult The ``IAuthorizationPolicy`` is expected to return an instance of ``PermitsResult`` and the ``ACLPermitsResult`` now subclasses this to form a consistent class hierarchy. Similarly the ``ACLDenied`` subclasses ``Denied`` and ``ACLAllowed`` subclasses ``Allowed`` for consistency. --- docs/api/security.rst | 22 ++++++--- pyramid/interfaces.py | 6 ++- pyramid/security.py | 109 +++++++++++++++++++++++++---------------- pyramid/tests/test_security.py | 4 ++ 4 files changed, 90 insertions(+), 51 deletions(-) diff --git a/docs/api/security.rst b/docs/api/security.rst index 88086dbbf..116459226 100644 --- a/docs/api/security.rst +++ b/docs/api/security.rst @@ -80,15 +80,23 @@ Return Values 'george', 'read')`` that means deny access. A sequence of ACEs makes up an ACL. It is a string, and its actual value is "Deny". +.. autoclass:: Denied + :members: msg + + .. automethod:: __new__ + +.. autoclass:: Allowed + :members: msg + + .. automethod:: __new__ + .. autoclass:: ACLDenied - :members: + :members: msg -.. autoclass:: ACLAllowed - :members: + .. automethod:: __new__ -.. autoclass:: Denied - :members: +.. autoclass:: ACLAllowed + :members: msg -.. autoclass:: Allowed - :members: + .. automethod:: __new__ diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index 4a069ad65..c6fbe3af8 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -503,8 +503,10 @@ class IAuthenticationPolicy(Interface): class IAuthorizationPolicy(Interface): """ An object representing a Pyramid authorization policy. """ def permits(context, principals, permission): - """ Return ``True`` if any of the ``principals`` is allowed the - ``permission`` in the current ``context``, else return ``False`` + """ Return an instance of :class:`pyramid.security.Allowed` if any + of the ``principals`` is allowed the ``permission`` in the current + ``context``, else return an instance of + :class:`pyramid.security.Denied`. """ def principals_allowed_by_permission(context, permission): diff --git a/pyramid/security.py b/pyramid/security.py index 035f09f77..d12314684 100644 --- a/pyramid/security.py +++ b/pyramid/security.py @@ -245,6 +245,14 @@ def view_execution_permitted(context, request, name=''): class PermitsResult(int): def __new__(cls, s, *args): + """ + Create a new instance. + + :param fmt: A format string explaining the reason for denial. + :param args: Arguments are stored and used with the format string + to generate the ``msg``. + + """ inst = int.__new__(cls, cls.boolval) inst.s = s inst.args = args @@ -252,6 +260,7 @@ class PermitsResult(int): @property def msg(self): + """ A string indicating why the result was generated.""" return self.s % self.args def __str__(self): @@ -263,24 +272,52 @@ class PermitsResult(int): self.msg) class Denied(PermitsResult): - """ An instance of ``Denied`` is returned when a security-related + """ + An instance of ``Denied`` is returned when a security-related API or other :app:`Pyramid` code denies an action unrelated to an ACL check. It evaluates equal to all boolean false types. It has an attribute named ``msg`` describing the circumstances for - the deny.""" + the deny. + + """ boolval = 0 class Allowed(PermitsResult): - """ An instance of ``Allowed`` is returned when a security-related + """ + An instance of ``Allowed`` is returned when a security-related API or other :app:`Pyramid` code allows an action unrelated to an ACL check. It evaluates equal to all boolean true types. It has an attribute named ``msg`` describing the circumstances for - the allow.""" + the allow. + + """ boolval = 1 -class ACLPermitsResult(int): +class ACLPermitsResult(PermitsResult): def __new__(cls, ace, acl, permission, principals, context): - inst = int.__new__(cls, cls.boolval) + """ + Create a new instance. + + :param ace: The :term:`ACE` that matched, triggering the result. + :param acl: The :term:`ACL` containing ``ace``. + :param permission: The required :term:`permission`. + :param principals: The list of :term:`principals ` provided. + :param context: The :term:`context` providing the :term:`lineage` + searched. + + """ + fmt = ('%s permission %r via ACE %r in ACL %r on context %r for ' + 'principals %r') + inst = PermitsResult.__new__( + cls, + fmt, + cls.__name__, + permission, + ace, + acl, + context, + principals, + ) inst.permission = permission inst.ace = ace inst.acl = acl @@ -288,44 +325,31 @@ class ACLPermitsResult(int): inst.context = context return inst - @property - def msg(self): - s = ('%s permission %r via ACE %r in ACL %r on context %r for ' - 'principals %r') - return s % (self.__class__.__name__, - self.permission, - self.ace, - self.acl, - self.context, - self.principals) - - def __str__(self): - return self.msg +class ACLDenied(ACLPermitsResult, Denied): + """ + An instance of ``ACLDenied`` is a specialization of + :class:`pyramid.security.Denied` that represents that a security check + made explicitly against ACL was denied. It evaluates equal to all + boolean false types. It also has the following attributes: ``acl``, + ``ace``, ``permission``, ``principals``, and ``context``. These + attributes indicate the security values involved in the request. Its + ``__str__`` method prints a summary of these attributes for debugging + purposes. The same summary is available as the ``msg`` attribute. - def __repr__(self): - return '<%s instance at %s with msg %r>' % (self.__class__.__name__, - id(self), - self.msg) + """ -class ACLDenied(ACLPermitsResult): - """ An instance of ``ACLDenied`` represents that a security check made - explicitly against ACL was denied. It evaluates equal to all boolean - false types. It also has the following attributes: ``acl``, ``ace``, - ``permission``, ``principals``, and ``context``. These attributes - indicate the security values involved in the request. Its __str__ method - prints a summary of these attributes for debugging purposes. The same - summary is available as the ``msg`` attribute.""" - boolval = 0 +class ACLAllowed(ACLPermitsResult, Allowed): + """ + An instance of ``ACLAllowed`` is a specialization of + :class:`pyramid.security.Allowed` that represents that a security check + made explicitly against ACL was allowed. It evaluates equal to all + boolean true types. It also has the following attributes: ``acl``, + ``ace``, ``permission``, ``principals``, and ``context``. These + attributes indicate the security values involved in the request. Its + ``__str__`` method prints a summary of these attributes for debugging + purposes. The same summary is available as the ``msg`` attribute. -class ACLAllowed(ACLPermitsResult): - """ An instance of ``ACLAllowed`` represents that a security check made - explicitly against ACL was allowed. It evaluates equal to all boolean - true types. It also has the following attributes: ``acl``, ``ace``, - ``permission``, ``principals``, and ``context``. These attributes - indicate the security values involved in the request. Its __str__ method - prints a summary of these attributes for debugging purposes. The same - summary is available as the ``msg`` attribute.""" - boolval = 1 + """ class AuthenticationAPIMixin(object): @@ -395,7 +419,8 @@ class AuthorizationAPIMixin(object): :type permission: unicode, str :param context: A resource object or ``None`` :type context: object - :returns: `pyramid.security.PermitsResult` + :returns: Either :class:`pyramid.security.Allowed` or + :class:`pyramid.security.Denied`. .. versionadded:: 1.5 diff --git a/pyramid/tests/test_security.py b/pyramid/tests/test_security.py index 5561a05d7..1da73ff73 100644 --- a/pyramid/tests/test_security.py +++ b/pyramid/tests/test_security.py @@ -92,9 +92,11 @@ class TestACLAllowed(unittest.TestCase): return klass(*arg, **kw) def test_it(self): + from pyramid.security import Allowed msg = ("ACLAllowed permission 'permission' via ACE 'ace' in ACL 'acl' " "on context 'ctx' for principals 'principals'") allowed = self._makeOne('ace', 'acl', 'permission', 'principals', 'ctx') + self.assertIsInstance(allowed, Allowed) self.assertTrue(msg in allowed.msg) self.assertEqual(allowed, True) self.assertTrue(allowed) @@ -112,9 +114,11 @@ class TestACLDenied(unittest.TestCase): return klass(*arg, **kw) def test_it(self): + from pyramid.security import Denied msg = ("ACLDenied permission 'permission' via ACE 'ace' in ACL 'acl' " "on context 'ctx' for principals 'principals'") denied = self._makeOne('ace', 'acl', 'permission', 'principals', 'ctx') + self.assertIsInstance(denied, Denied) self.assertTrue(msg in denied.msg) self.assertEqual(denied, False) self.assertFalse(denied) -- cgit v1.2.3 From b54a702599e00827ae0389808d07f941cdfb04c5 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 14 Jun 2017 23:56:42 -0500 Subject: add changelog for #3084 --- CHANGES.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 1402045d4..547c00bbc 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -21,6 +21,12 @@ unreleased a valid iterator in its ``__iter__`` implementation. See https://github.com/Pylons/pyramid/pull/3074 +- Normalize the permission results to a proper class hierarchy. + ``pyramid.security.ACLAllowed`` is now a subclass of + ``pyramid.security.Allowed`` and ``pyramid.securit.ACLDenied`` is now a + subclass of ``pyramid.security.Denied``. + See https://github.com/Pylons/pyramid/pull/3084 + 1.9a2 (2017-05-09) ================== -- cgit v1.2.3 From 975b025c7952d148392cc17b48388a4ee5dcbd45 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 15 Jun 2017 00:39:57 -0500 Subject: update whatsnew-1.9 --- CHANGES.txt | 2 +- docs/whatsnew-1.9.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 547c00bbc..fdd9dd884 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -23,7 +23,7 @@ unreleased - Normalize the permission results to a proper class hierarchy. ``pyramid.security.ACLAllowed`` is now a subclass of - ``pyramid.security.Allowed`` and ``pyramid.securit.ACLDenied`` is now a + ``pyramid.security.Allowed`` and ``pyramid.security.ACLDenied`` is now a subclass of ``pyramid.security.Denied``. See https://github.com/Pylons/pyramid/pull/3084 diff --git a/docs/whatsnew-1.9.rst b/docs/whatsnew-1.9.rst index eca159d4c..0c3385a66 100644 --- a/docs/whatsnew-1.9.rst +++ b/docs/whatsnew-1.9.rst @@ -39,6 +39,8 @@ Minor Feature Additions - When unsupported predicates are supplied to :meth:`pyramid.config.Configurator.add_view`, :meth:`pyramid.config.Configurator.add_route` and :meth:`pyramid.config.Configurator.add_subscriber` a much more helpful error message is output with a guess as to which predicate was intended. See https://github.com/Pylons/pyramid/pull/3054 +- Normalize the permission results to a proper class hierarchy. :class:`pyramid.security.ACLAllowed` is now a subclass of :class:`pyramid.security.Allowed` and :class:`pyramid.security.ACLDenied` is now a subclass of :class:`pyramid.security.Denied`. See https://github.com/Pylons/pyramid/pull/3084 + Deprecations ------------ -- cgit v1.2.3 From 6f2f04a4d2d1df1b5fd7d5327c57e96e059279cd Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 15 Jun 2017 01:12:10 -0500 Subject: add a reraise argument to request.invoke_exception_view --- pyramid/tests/test_view.py | 27 +++++++++++++++++++++++++++ pyramid/view.py | 26 +++++++++++++++++--------- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py index a9ce2234d..e03487a70 100644 --- a/pyramid/tests/test_view.py +++ b/pyramid/tests/test_view.py @@ -886,6 +886,18 @@ class TestViewMethodsMixin(unittest.TestCase): else: # pragma: no cover self.fail() + def test_it_reraises_if_not_found(self): + request = self._makeOne() + dummy_exc = RuntimeError() + try: + raise dummy_exc + except RuntimeError: + self.assertRaises( + RuntimeError, + lambda: request.invoke_exception_view(reraise=True)) + else: # pragma: no cover + self.fail() + def test_it_raises_predicate_mismatch(self): from pyramid.exceptions import PredicateMismatch def exc_view(exc, request): pass @@ -900,6 +912,21 @@ class TestViewMethodsMixin(unittest.TestCase): else: # pragma: no cover self.fail() + def test_it_reraises_after_predicate_mismatch(self): + def exc_view(exc, request): pass + self.config.add_view(exc_view, context=Exception, request_method='POST') + request = self._makeOne() + request.method = 'GET' + dummy_exc = RuntimeError() + try: + raise dummy_exc + except RuntimeError: + self.assertRaises( + RuntimeError, + lambda: request.invoke_exception_view(reraise=True)) + else: # pragma: no cover + self.fail() + class ExceptionResponse(Exception): status = '404 Not Found' app_iter = ['Not Found'] diff --git a/pyramid/view.py b/pyramid/view.py index 14d11825e..dc4aae3fa 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -16,6 +16,7 @@ from pyramid.interfaces import ( ) from pyramid.compat import decode_path_info +from pyramid.compat import reraise as reraise_ from pyramid.exceptions import ( ConfigurationError, @@ -630,8 +631,9 @@ class ViewMethodsMixin(object): self, exc_info=None, request=None, - secure=True - ): + secure=True, + reraise=False, + ): """ Executes an exception view related to the request it's called upon. The arguments it takes are these: @@ -654,14 +656,12 @@ class ViewMethodsMixin(object): does not have the appropriate permission, this should be ``True``. Default: ``True``. - If called with no arguments, it uses the global exception information - returned by ``sys.exc_info()`` as ``exc_info``, the request - object that this method is attached to as the ``request``, and - ``True`` for ``secure``. + ``reraise`` - This method returns a :term:`response` object or raises - :class:`pyramid.httpexceptions.HTTPNotFound` if a matching view cannot - be found. + A boolean indicating whether the original error should be reraised + if a :term:`response` object could not be created. If ``False`` + then an :class:`pyramid.httpexceptions.HTTPNotFound`` exception + will be raised. Default: ``False``. If a response is generated then ``request.exception`` and ``request.exc_info`` will be left at the values used to render the @@ -675,6 +675,8 @@ class ViewMethodsMixin(object): reflect the exception used to render the response where previously they were reset to the values prior to invoking the method. + Also added the ``reraise`` argument. + """ if request is None: request = self @@ -716,10 +718,16 @@ class ViewMethodsMixin(object): secure=secure, request_iface=request_iface.combined, ) + except: + if reraise: + reraise_(*exc_info) + raise finally: manager.pop() if response is None: + if reraise: + reraise_(*exc_info) raise HTTPNotFound # successful response, overwrite exception/exc_info -- cgit v1.2.3 From 804232f6ea90a5e537ccd46d87b66a976f736c0c Mon Sep 17 00:00:00 2001 From: drnextgis Date: Thu, 15 Jun 2017 23:08:54 +0700 Subject: quote_via urlencode argument --- CONTRIBUTORS.txt | 2 ++ pyramid/encode.py | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 445536e9e..32c0833b4 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -304,3 +304,5 @@ Contributors - Fang-Pen Lin, 2017/05/22 - Volker Diels-Grabsch, 2017/06/09 + +- Denis Rykov, 2017/06/15 diff --git a/pyramid/encode.py b/pyramid/encode.py index 0be0107b3..62f96938b 100644 --- a/pyramid/encode.py +++ b/pyramid/encode.py @@ -14,7 +14,16 @@ def url_quote(val, safe=''): # bw compat api val = str(val).encode('utf-8') return _url_quote(val, safe=safe) -def urlencode(query, doseq=True): +# bw compat api (dnr) +def quote_plus(val, safe=''): + cls = val.__class__ + if cls is text_type: + val = val.encode('utf-8') + elif cls is not binary_type: + val = str(val).encode('utf-8') + return _quote_plus(val, safe=safe) + +def urlencode(query, doseq=True, quote_via=quote_plus): """ An alternate implementation of Python's stdlib `urllib.urlencode function `_ which @@ -52,28 +61,19 @@ def urlencode(query, doseq=True): prefix = '' for (k, v) in query: - k = quote_plus(k) + k = quote_via(k) if is_nonstr_iter(v): for x in v: - x = quote_plus(x) + x = quote_via(x) result += '%s%s=%s' % (prefix, k, x) prefix = '&' elif v is None: result += '%s%s=' % (prefix, k) else: - v = quote_plus(v) + v = quote_via(v) result += '%s%s=%s' % (prefix, k, v) prefix = '&' return result - -# bw compat api (dnr) -def quote_plus(val, safe=''): - cls = val.__class__ - if cls is text_type: - val = val.encode('utf-8') - elif cls is not binary_type: - val = str(val).encode('utf-8') - return _quote_plus(val, safe=safe) -- cgit v1.2.3 From 4216e1f9204ea3d0d495d6edc84d8d656fc09e1d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 15 Jun 2017 10:12:52 -0700 Subject: Use HTTPS for pylonsproject.org --- README.rst | 2 +- docs/index.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 0429c36b5..70dcc5dda 100644 --- a/README.rst +++ b/README.rst @@ -34,7 +34,7 @@ and deployment more fun, more predictable, and more productive. server = make_server('0.0.0.0', 8080, app) server.serve_forever() -Pyramid is a project of the `Pylons Project `_. +Pyramid is a project of the `Pylons Project `_. Support and Documentation ------------------------- diff --git a/docs/index.rst b/docs/index.rst index 7d3393548..e3d2835b7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,7 +5,7 @@ The Pyramid Web Framework ========================= :app:`Pyramid` is a small, fast, down-to-earth Python web framework. It is -developed as part of the `Pylons Project `_. +developed as part of the `Pylons Project `_. It is licensed under a `BSD-like license `_. Here is one of the simplest :app:`Pyramid` applications you can make: -- cgit v1.2.3 From 2cd6a6dbcdb517788ef3275af63feca703e73658 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 15 Jun 2017 21:59:18 -0700 Subject: Use HTTPS for pylonsproject.org --- contributing.md | 2 +- docs/narr/introduction.rst | 2 +- docs/narr/myproject/myproject/templates/layout.jinja2 | 2 +- docs/quick_tour/logging/hello_world/templates/layout.jinja2 | 2 +- docs/quick_tour/package/hello_world/templates/layout.jinja2 | 2 +- docs/quick_tour/sessions/hello_world/templates/layout.jinja2 | 2 +- docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 | 2 +- docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 | 2 +- docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt | 2 +- docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt | 2 +- docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt | 2 +- docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt | 2 +- docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 | 2 +- docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 | 2 +- docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 | 2 +- pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl | 2 +- pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl | 2 +- pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl | 2 +- .../fixture_scaffold/+package+/templates/mytemplate.pt_tmpl | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/contributing.md b/contributing.md index 82f60e7b8..c0f842e3e 100644 --- a/contributing.md +++ b/contributing.md @@ -3,7 +3,7 @@ Contributing All projects under the Pylons Projects, including this one, follow the guidelines established at [How to -Contribute](http://www.pylonsproject.org/community/how-to-contribute) and +Contribute](https://pylonsproject.org//community/how-to-contribute) and [Coding Style and Standards](http://docs.pylonsproject.org/en/latest/community/codestyle.html). diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 3dd0cc464..45ea712b2 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -364,7 +364,7 @@ And much, much more... 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 `_ includes details about how :app:`Pyramid` relates to 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 `_ includes details about how :app:`Pyramid` relates to the Pylons Project. .. index:: single: pyramid and other frameworks diff --git a/docs/narr/myproject/myproject/templates/layout.jinja2 b/docs/narr/myproject/myproject/templates/layout.jinja2 index 820758fea..2b3c26628 100644 --- a/docs/narr/myproject/myproject/templates/layout.jinja2 +++ b/docs/narr/myproject/myproject/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/docs/quick_tour/logging/hello_world/templates/layout.jinja2 b/docs/quick_tour/logging/hello_world/templates/layout.jinja2 index c82cac915..8473e8b5d 100644 --- a/docs/quick_tour/logging/hello_world/templates/layout.jinja2 +++ b/docs/quick_tour/logging/hello_world/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/docs/quick_tour/package/hello_world/templates/layout.jinja2 b/docs/quick_tour/package/hello_world/templates/layout.jinja2 index c82cac915..8473e8b5d 100644 --- a/docs/quick_tour/package/hello_world/templates/layout.jinja2 +++ b/docs/quick_tour/package/hello_world/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 b/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 index c82cac915..8473e8b5d 100644 --- a/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 +++ b/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 b/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 index b84b3ec0e..69c9941ac 100644 --- a/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 +++ b/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 b/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 index 3aed0a123..175a7b30b 100644 --- a/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 +++ b/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt index 4ffc0eb22..5d3486061 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt @@ -43,7 +43,7 @@ diff --git a/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt index 4ffc0eb22..5d3486061 100644 --- a/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt @@ -43,7 +43,7 @@ diff --git a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt index 4ffc0eb22..5d3486061 100644 --- a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt @@ -43,7 +43,7 @@ diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt index 6c3809250..c5776be23 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt @@ -45,7 +45,7 @@
  • Docs
  • Github Project
  • IRC Channel
  • -
  • Pylons Project
  • +
  • Pylons Project
  • diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 index e29413cf9..d97c73ed2 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 index e29413cf9..d97c73ed2 100644 --- a/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 index e29413cf9..d97c73ed2 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl b/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl index 6f6946ba2..6906ea204 100644 --- a/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl +++ b/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl @@ -44,7 +44,7 @@
  • Docs
  • Github Project
  • IRC Channel
  • -
  • Pylons Project
  • +
  • Pylons Project
  • diff --git a/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl b/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl index f3c27e3f0..a6ec9d00a 100644 --- a/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl +++ b/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl @@ -44,7 +44,7 @@
  • Docs
  • Github Project
  • IRC Channel
  • -
  • Pylons Project
  • +
  • Pylons Project
  • diff --git a/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl b/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl index 4b24ee2df..04f5260e3 100644 --- a/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl +++ b/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl @@ -45,7 +45,7 @@
  • Docs
  • Github Project
  • IRC Channel
  • -
  • Pylons Project
  • +
  • Pylons Project
  • diff --git a/pyramid/tests/test_scaffolds/fixture_scaffold/+package+/templates/mytemplate.pt_tmpl b/pyramid/tests/test_scaffolds/fixture_scaffold/+package+/templates/mytemplate.pt_tmpl index 856bc22e7..f4d98ec29 100644 --- a/pyramid/tests/test_scaffolds/fixture_scaffold/+package+/templates/mytemplate.pt_tmpl +++ b/pyramid/tests/test_scaffolds/fixture_scaffold/+package+/templates/mytemplate.pt_tmpl @@ -41,7 +41,7 @@

    Pyramid links

    diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 index d97c73ed2..36b1fa374 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 index d97c73ed2..36b1fa374 100644 --- a/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 index d97c73ed2..36b1fa374 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 @@ -42,7 +42,7 @@ diff --git a/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl b/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl index 6906ea204..485d6efa4 100644 --- a/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl +++ b/pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl @@ -44,7 +44,7 @@
  • Docs
  • Github Project
  • IRC Channel
  • -
  • Pylons Project
  • +
  • Pylons Project
  • diff --git a/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl b/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl index a6ec9d00a..679ba25ea 100644 --- a/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl +++ b/pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl @@ -44,7 +44,7 @@
  • Docs
  • Github Project
  • IRC Channel
  • -
  • Pylons Project
  • +
  • Pylons Project
  • -- cgit v1.2.3 From d505174d3217025ea87a7b51d0adff73c5e9e199 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 15 Jun 2017 22:05:32 -0700 Subject: fix URL --- contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributing.md b/contributing.md index 83a3f5b6e..5e0ac53bf 100644 --- a/contributing.md +++ b/contributing.md @@ -3,7 +3,7 @@ Contributing All projects under the Pylons Projects, including this one, follow the guidelines established at [How to -Contribute](https://pylonsproject.org/community/how-to-contribute) and +Contribute](https://pylonsproject.org/community-how-to-contribute.html) and [Coding Style and Standards](http://docs.pylonsproject.org/en/latest/community/codestyle.html). -- cgit v1.2.3 From c2161266fa7fdca8b6e7405de9a903c24b49ba69 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 15 Jun 2017 23:20:25 -0700 Subject: update contributing URL --- docs/index.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 6df3023f0..4b739d23f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -95,9 +95,7 @@ the trunk via ``git``, use either command: # Otherwise, HTTPS will work, using your GitHub login: git clone https://github.com/Pylons/pyramid.git -To find out how to become a contributor to :app:`Pyramid`, please see the -`contributor's section of the documentation -`_. +To find out how to become a contributor to :app:`Pyramid`, please see `How to Contribute Source Code and Documentation `_. .. _html_narrative_documentation: -- cgit v1.2.3 From 6f43b617476127cc333efb885970ca87e9de39fa Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 18 Jun 2017 00:03:48 -0500 Subject: document and test p.encode.urlencode(quote_via=...) --- pyramid/encode.py | 19 ++++++++++++------- pyramid/tests/test_encode.py | 11 +++++++++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/pyramid/encode.py b/pyramid/encode.py index 62f96938b..73ff14e62 100644 --- a/pyramid/encode.py +++ b/pyramid/encode.py @@ -25,11 +25,10 @@ def quote_plus(val, safe=''): def urlencode(query, doseq=True, quote_via=quote_plus): """ - An alternate implementation of Python's stdlib `urllib.urlencode - function `_ which - accepts unicode keys and values within the ``query`` - dict/sequence; all Unicode keys and values are first converted to - UTF-8 before being used to compose the query string. + An alternate implementation of Python's stdlib + :func:`urllib.parse.urlencode` function which accepts unicode keys and + values within the ``query`` dict/sequence; all Unicode keys and values are + first converted to UTF-8 before being used to compose the query string. The value of ``query`` must be a sequence of two-tuples representing key/value pairs *or* an object (often a dictionary) @@ -44,12 +43,18 @@ def urlencode(query, doseq=True, quote_via=quote_plus): the ``doseq=True`` mode, no matter what the value of the second argument. - See the Python stdlib documentation for ``urllib.urlencode`` for - more information. + Both the key and value are encoded using the ``quote_via`` function which + by default is using a similar algorithm to :func:`urllib.parse.quote_plus` + which converts spaces into '+' characters and '/' into '%2F'. .. versionchanged:: 1.5 In a key/value pair, if the value is ``None`` then it will be dropped from the resulting output. + + .. versionchanged:: 1.9 + Added the ``quote_via`` argument to allow alternate quoting algorithms + to be used. + """ try: # presumed to be a dictionary diff --git a/pyramid/tests/test_encode.py b/pyramid/tests/test_encode.py index 8fb766d88..d3a9f7095 100644 --- a/pyramid/tests/test_encode.py +++ b/pyramid/tests/test_encode.py @@ -5,9 +5,9 @@ from pyramid.compat import ( ) class UrlEncodeTests(unittest.TestCase): - def _callFUT(self, query, doseq=False): + def _callFUT(self, query, doseq=False, **kw): from pyramid.encode import urlencode - return urlencode(query, doseq) + return urlencode(query, doseq, **kw) def test_ascii_only(self): result = self._callFUT([('a',1), ('b',2)]) @@ -53,6 +53,13 @@ class UrlEncodeTests(unittest.TestCase): result = self._callFUT([('a', '1'), ('b', None), ('c', None)]) self.assertEqual(result, 'a=1&b=&c=') + def test_quote_via(self): + def my_quoter(value): + return 'xxx' + value + result = self._callFUT([('a', '1'), ('b', None), ('c', None)], + quote_via=my_quoter) + self.assertEqual(result, 'xxxa=xxx1&xxxb=&xxxc=') + class URLQuoteTests(unittest.TestCase): def _callFUT(self, val, safe=''): from pyramid.encode import url_quote -- cgit v1.2.3 From 5c437abba0926f6093efbd481e49763de2436665 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 18 Jun 2017 00:18:13 -0500 Subject: add changelog for #3088 --- CHANGES.txt | 4 ++++ docs/whatsnew-1.9.rst | 2 ++ 2 files changed, 6 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index fdd9dd884..939b777ab 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -27,6 +27,10 @@ unreleased subclass of ``pyramid.security.Denied``. See https://github.com/Pylons/pyramid/pull/3084 +- Add a ``quote_via`` argument to ``pyramid.encode.urlencode`` to follow + the stdlib's version and enable custom quoting functions. + See https://github.com/Pylons/pyramid/pull/3088 + 1.9a2 (2017-05-09) ================== diff --git a/docs/whatsnew-1.9.rst b/docs/whatsnew-1.9.rst index 0c3385a66..9e9c1614d 100644 --- a/docs/whatsnew-1.9.rst +++ b/docs/whatsnew-1.9.rst @@ -41,6 +41,8 @@ Minor Feature Additions - Normalize the permission results to a proper class hierarchy. :class:`pyramid.security.ACLAllowed` is now a subclass of :class:`pyramid.security.Allowed` and :class:`pyramid.security.ACLDenied` is now a subclass of :class:`pyramid.security.Denied`. See https://github.com/Pylons/pyramid/pull/3084 +- Add a ``quote_via`` argument to :func:`pyramid.encode.urlencode` to follow the stdlib's version and enable custom quoting functions. See https://github.com/Pylons/pyramid/pull/3088 + Deprecations ------------ -- cgit v1.2.3