From fbbb20c7953370c86f999e865b1a9d682690eb70 Mon Sep 17 00:00:00 2001 From: Brian Sutherland Date: Sat, 16 Jun 2012 12:57:46 +0200 Subject: A context manager for test setup --- docs/narr/testing.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'docs/narr') diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst index 5ce2c8a66..89bc1a089 100644 --- a/docs/narr/testing.rst +++ b/docs/narr/testing.rst @@ -157,6 +157,30 @@ We use a "dummy" request implementation supplied by :class:`pyramid.testing.DummyRequest` because it's easier to construct than a "real" :app:`Pyramid` request object. +Test setup using a context manager +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An alternative style of setting up a test configuration is to use the +`with` statement and :func:`pyramid.testing.testConfig` to create a +context manager. The context manager will call +:func:`pyramid.testing.setUp` before the code under test and +:func:`pyramid.testing.tearDown` afterwards. + +This style is useful for small self-contained tests. For example: + +.. code-block:: python + :linenos: + + import unittest + + class MyTest(unittest.TestCase): + + def test_my_function(self): + from pyramid import testing + with testing.testConfig() as config: + config.add_route('bar', '/bar/{id}') + my_function_which_needs_route_bar() + What? ~~~~~ -- cgit v1.2.3 From cabcd3788beceb9a41eca2414068ab32aaf3340e Mon Sep 17 00:00:00 2001 From: David Gay Date: Sun, 29 Jul 2012 19:05:07 -0400 Subject: prettify CSS stored in docs tutorials --- docs/narr/MyProject/myproject/static/pylons.css | 435 ++++++++++++++++++++---- 1 file changed, 371 insertions(+), 64 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/MyProject/myproject/static/pylons.css b/docs/narr/MyProject/myproject/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/narr/MyProject/myproject/static/pylons.css +++ b/docs/narr/MyProject/myproject/static/pylons.css @@ -1,65 +1,372 @@ -html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */ -vertical-align:baseline;background:transparent;} -body{line-height:1;} -ol,ul{list-style:none;} -blockquote,q{quotes:none;} -blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;} -:focus{outline:0;} -ins{text-decoration:none;} -del{text-decoration:line-through;} -table{border-collapse:collapse;border-spacing:0;} -sub{vertical-align:sub;font-size:smaller;line-height:normal;} -sup{vertical-align:super;font-size:smaller;line-height:normal;} -ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;} -ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;} -li{display:list-item;} -ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;} -ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;} -ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;} -.hidden{display:none;} -p{line-height:1.5em;} -h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;} -h2{font-size:1.5em;line-height:1.7em;font-family:helvetica,verdana;} -h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} -h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} -html,body{width:100%;height:100%;} -body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} -a{color:#1b61d6;text-decoration:none;} -a:hover{color:#e88f00;text-decoration:underline;} -body h1, -body h2, -body h3, -body h4, -body h5, -body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} -#wrap{min-height:100%;} -#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} -#header{background:#000000;top:0;font-size:14px;} -#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;} -.header,.footer{width:750px;margin-right:auto;margin-left:auto;} -.wrapper{width:100%} -#top,#top-small,#bottom{width:100%;} -#top{color:#000000;height:230px;background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;} -#top-small{color:#000000;height:60px;background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;} -#bottom{color:#222;background-color:#ffffff;} -.top,.top-small,.middle,.bottom{width:750px;margin-right:auto;margin-left:auto;} -.top{padding-top:40px;} -.top-small{padding-top:10px;} -#middle{width:100%;height:100px;background:url(middlebg.png) repeat-x;border-top:2px solid #ffffff;border-bottom:2px solid #b2b2b2;} -.app-welcome{margin-top:25px;} -.app-name{color:#000000;font-weight:bold;} -.bottom{padding-top:50px;} -#left{width:350px;float:left;padding-right:25px;} -#right{width:350px;float:right;padding-left:25px;} -.align-left{text-align:left;} -.align-right{text-align:right;} -.align-center{text-align:center;} -ul.links{margin:0;padding:0;} -ul.links li{list-style-type:none;font-size:14px;} -form{border-style:none;} -fieldset{border-style:none;} -input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;} -input[type=text],input[type=password]{width:205px;} -input[type=submit]{background-color:#ddd;font-weight:bold;} +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td +{ + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: 100%; /* 16px */ + vertical-align: baseline; + background: transparent; +} + +body +{ + line-height: 1; +} + +ol, ul +{ + list-style: none; +} + +blockquote, q +{ + quotes: none; +} + +blockquote:before, blockquote:after, q:before, q:after +{ + content: ''; + content: none; +} + +:focus +{ + outline: 0; +} + +ins +{ + text-decoration: none; +} + +del +{ + text-decoration: line-through; +} + +table +{ + border-collapse: collapse; + border-spacing: 0; +} + +sub +{ + vertical-align: sub; + font-size: smaller; + line-height: normal; +} + +sup +{ + vertical-align: super; + font-size: smaller; + line-height: normal; +} + +ul, menu, dir +{ + display: block; + list-style-type: disc; + margin: 1em 0; + padding-left: 40px; +} + +ol +{ + display: block; + list-style-type: decimal-leading-zero; + margin: 1em 0; + padding-left: 40px; +} + +li +{ + display: list-item; +} + +ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl +{ + margin-top: 0; + margin-bottom: 0; +} + +ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir +{ + list-style-type: circle; +} + +ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir +{ + list-style-type: square; +} + +.hidden +{ + display: none; +} + +p +{ + line-height: 1.5em; +} + +h1 +{ + font-size: 1.75em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h2 +{ + font-size: 1.5em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h3 +{ + font-size: 1.25em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h4 +{ + font-size: 1em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +html, body +{ + width: 100%; + height: 100%; +} + +body +{ + margin: 0; + padding: 0; + background-color: #fff; + position: relative; + font: 16px/24px NobileRegular, "Lucida Grande", Lucida, Verdana, sans-serif; +} + +a +{ + color: #1b61d6; + text-decoration: none; +} + +a:hover +{ + color: #e88f00; + text-decoration: underline; +} + +body h1, body h2, body h3, body h4, body h5, body h6 +{ + font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif; + font-weight: 400; + color: #373839; + font-style: normal; +} + +#wrap +{ + min-height: 100%; +} + +#header, #footer +{ + width: 100%; + color: #fff; + height: 40px; + position: absolute; + text-align: center; + line-height: 40px; + overflow: hidden; + font-size: 12px; + vertical-align: middle; +} + +#header +{ + background: #000; + top: 0; + font-size: 14px; +} + +#footer +{ + bottom: 0; + background: #000 url(footerbg.png) repeat-x 0 top; + position: relative; + margin-top: -40px; + clear: both; +} + +.header, .footer +{ + width: 750px; + margin-right: auto; + margin-left: auto; +} + +.wrapper +{ + width: 100%; +} + +#top, #top-small, #bottom +{ + width: 100%; +} + +#top +{ + color: #000; + height: 230px; + background: #fff url(headerbg.png) repeat-x 0 top; + position: relative; +} + +#top-small +{ + color: #000; + height: 60px; + background: #fff url(headerbg.png) repeat-x 0 top; + position: relative; +} + +#bottom +{ + color: #222; + background-color: #fff; +} + +.top, .top-small, .middle, .bottom +{ + width: 750px; + margin-right: auto; + margin-left: auto; +} + +.top +{ + padding-top: 40px; +} + +.top-small +{ + padding-top: 10px; +} + +#middle +{ + width: 100%; + height: 100px; + background: url(middlebg.png) repeat-x; + border-top: 2px solid #fff; + border-bottom: 2px solid #b2b2b2; +} + +.app-welcome +{ + margin-top: 25px; +} + +.app-name +{ + color: #000; + font-weight: 700; +} + +.bottom +{ + padding-top: 50px; +} + +#left +{ + width: 350px; + float: left; + padding-right: 25px; +} + +#right +{ + width: 350px; + float: right; + padding-left: 25px; +} + +.align-left +{ + text-align: left; +} + +.align-right +{ + text-align: right; +} + +.align-center +{ + text-align: center; +} + +ul.links +{ + margin: 0; + padding: 0; +} + +ul.links li +{ + list-style-type: none; + font-size: 14px; +} + +form +{ + border-style: none; +} + +fieldset +{ + border-style: none; +} + +input +{ + color: #222; + border: 1px solid #ccc; + font-family: sans-serif; + font-size: 12px; + line-height: 16px; +} + +input[type=text], input[type=password] +{ + width: 205px; +} + +input[type=submit] +{ + background-color: #ddd; + font-weight: 700; +} + /*Opera Fix*/ -body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;} +body:before +{ + content: ""; + height: 100%; + float: left; + width: 0; + margin-top: -32767px; +} -- cgit v1.2.3 From d501b7cb23a26b85882d01deb1c8381acd75447e Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 15 Sep 2012 04:17:12 -0400 Subject: point at cookbook --- docs/narr/advconfig.rst | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'docs/narr') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index 165cf7474..ad22a82c9 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -414,3 +414,10 @@ constraints: the routes they imply require relative ordering. Such ordering constraints are not absolved by two-phase configuration. Routes are still added in configuration execution order. +More Information +---------------- + +For more information, see the article entitled `"A Whirlwind Rour of Advanced +Configuration Tactics" +`_ +in the Pyramid Cookbook. -- cgit v1.2.3 From 54d3e3ecf8929f90373669b9682b9db3b4ce3290 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 15 Sep 2012 23:24:48 -0400 Subject: add a whatsnew-1.4 document --- docs/narr/upgrading.rst | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs/narr') diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst index 92f125c0a..839f59c35 100644 --- a/docs/narr/upgrading.rst +++ b/docs/narr/upgrading.rst @@ -1,3 +1,5 @@ +.. _upgrading_chapter: + Upgrading Pyramid ================= -- cgit v1.2.3 From 37d2c224b804dfebe9ee217c7a536364eacdee15 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 03:25:17 -0400 Subject: docs and test --- docs/narr/subrequest.rst | 143 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 docs/narr/subrequest.rst (limited to 'docs/narr') diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst new file mode 100644 index 000000000..6ed679579 --- /dev/null +++ b/docs/narr/subrequest.rst @@ -0,0 +1,143 @@ +.. index:: + single: subrequest + +.. _subrequest_chapter: + +Invoking a Subrequest +===================== + +.. warning:: + + This feature was added in Pyramid 1.4a1. + +:app:`Pyramid` allows you to invoke a subrequest at any point during the +processing of a request. Invoking a subrequest allows you to obtain a +:term:`response` object from a view callable within your :app:`Pyramid` +application while you're executing a different view callable within the same +application. + +Here's an example application which uses a subrequest: + +.. code-block:: python + + from wsgiref.simple_server import make_server + from pyramid.config import Configurator + from pyramid.request import Request + + def view_one(request): + subreq = Request.blank('/view_two') + response = request.subrequest(subreq) + return response + + def view_two(request): + request.response.body = 'This came from view_two' + return request.response + + if __name__ == '__main__': + config = Configurator() + config.add_route('one', '/view_one') + config.add_route('two', '/view_two') + config.add_view(view_one, route_name='one') + config.add_view(view_two, route_name='two') + app = config.make_wsgi_app() + server = make_server('0.0.0.0', 8080, app) + server.serve_forever() + +When ``/view_one`` is visted in a browser, the text printed in the browser +pane will be ``This came from view_two``. The ``view_one`` view used the +:meth:`pyramid.request.Request.subrequest` API to obtain a response from +another view (``view_two``) within the same application when it executed. It +did so by constructing a new request that had a URL that it knew would match +the ``view_two`` view registration, and passed that new request along to +:meth:`pyramid.request.Request.subrequest`. The ``view_two`` view callable +was invoked, and it returned a response. The ``view_one`` view callable then +simply returned the response it obtained from the ``view_two`` view callable. + +Note that it doesn't matter if the view callable invoked via a subrequest +actually returns a literal Response object. Any view callable that uses a +renderer or which returns an object that can be interpreted by a response +adapter will work too: + +.. code-block:: python + + from wsgiref.simple_server import make_server + from pyramid.config import Configurator + from pyramid.request import Request + + def view_one(request): + subreq = Request.blank('/view_two') + response = request.subrequest(subreq) + return response + + def view_two(request): + return 'This came from view_two' + + if __name__ == '__main__': + config = Configurator() + config.add_route('one', '/view_one') + config.add_route('two', '/view_two') + config.add_view(view_one, route_name='one') + config.add_view(view_two, route_name='two', renderer='string') + app = config.make_wsgi_app() + server = make_server('0.0.0.0', 8080, app) + server.serve_forever() + +Being able to unconditionally obtain a response object by invoking a view +callable indirectly is the main advantage to using +:meth:`pyramid.request.Request.subrequest` instead of simply importing it and +executing it directly. Note that there's not much advantage to invoking a +view using a subrequest if you *can* invoke a view callable directly. It's +much slower to use a subrequest. + +The :meth:`pyramid.request.Request.subrequest` API accepts two arguments: a +positional argument ``request`` that must be provided, and and ``use_tweens`` +keyword argument that is optional; it defaults to ``False``. + +The ``request`` object passed to the API must be an object that implements +the Pyramid request interface (such as a :class:`pyramid.request.Request` +instance). If ``use_tweens`` is ``True``, the request will be sent to the +:term:`tween` in the tween stack closest to the request ingress. If +``use_tweens`` is ``False``, the request will be sent to the main router +handler, and no tweens will be invoked. It's usually best to not invoke any +tweens when executing a subrequest, because the original request will invoke +any tween logic as necessary. The :meth:`pyramid.request.Request.subrequest` +function also: + +- manages the threadlocal stack so that + :func:`~pyramid.threadlocal.get_current_request` and + :func:`~pyramid.threadlocal.get_current_registry` work during a request + (they will return the subrequest instead of the original request) + +- Adds a ``registry`` attribute and a ``subrequest`` attribute to the request + object it's handed. + +- sets request extensions (such as those added via + :meth:`~pyramid.config.Configurator.add_request_method` or + :meth:`~pyramid.config.Configurator.set_request_property`) on the subrequest + object passed as ``request`` + +- causes a :class:`~pyramid.event.NewRequest` event to be sent at the + beginning of request processing. + +- causes a :class:`~pyramid.event.ContextFound` event to be sent when a + context resource is found. + +- causes a :class:`~pyramid.event.NewResponse` event to be sent when the + Pyramid application returns a response. + +- Calls any :term:`response callback` functions defined within the subrequest's + lifetime if a response is obtained from the Pyramid application. + +- Calls any :term:`finished callback` functions defined within the subrequest's + lifetime. + +It's a poor idea to use the original ``request`` object as an argument to +:meth:`~pyramid.request.Request.subrequest`. You should construct a new +request instead as demonstrated in the above example, using +:meth:`pyramid.request.Request.blank`. Once you've constructed a request +object, you'll need to massage the it to match the view callable you'd like +to be executed during the subrequest. This can be done by adjusting the +subrequest's URL, its headers, its request method, and other attributes. See +the documentation for :class:`pyramid.request.Request` to understand how to +massage your new request object into something that will match the view you'd +like to call via a subrequest. -- cgit v1.2.3 From 3f3917f9c70ddc83263e440a8bc781bacb33bb6e Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 03:27:00 -0400 Subject: moar --- docs/narr/subrequest.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst index 6ed679579..5067fa890 100644 --- a/docs/narr/subrequest.rst +++ b/docs/narr/subrequest.rst @@ -84,10 +84,10 @@ adapter will work too: Being able to unconditionally obtain a response object by invoking a view callable indirectly is the main advantage to using -:meth:`pyramid.request.Request.subrequest` instead of simply importing it and -executing it directly. Note that there's not much advantage to invoking a -view using a subrequest if you *can* invoke a view callable directly. It's -much slower to use a subrequest. +:meth:`pyramid.request.Request.subrequest` instead of simply importing the +view callable and executing it directly. Note that there's not much +advantage to invoking a view using a subrequest if you *can* invoke a view +callable directly. It's much slower to use a subrequest. The :meth:`pyramid.request.Request.subrequest` API accepts two arguments: a positional argument ``request`` that must be provided, and and ``use_tweens`` @@ -141,3 +141,7 @@ subrequest's URL, its headers, its request method, and other attributes. See the documentation for :class:`pyramid.request.Request` to understand how to massage your new request object into something that will match the view you'd like to call via a subrequest. + +We've demonstrated use of a subrequest from within a view callable, but you +can use the :meth:`~pyramid.request.Request.subrequest` API from within a +tween or an event handler as well. -- cgit v1.2.3 From ab84e1038b9004c978ea49829c2d1b7a2d48d3d4 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 03:30:28 -0400 Subject: explain --- docs/narr/subrequest.rst | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'docs/narr') diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst index 5067fa890..045cec279 100644 --- a/docs/narr/subrequest.rst +++ b/docs/narr/subrequest.rst @@ -82,6 +82,11 @@ adapter will work too: server = make_server('0.0.0.0', 8080, app) server.serve_forever() +Even though the ``view_two`` view callable returned a string, it was invoked +in such a way that the ``string`` renderer associated with the view +registration that was found turned it into a "real" response object for +consumption by ``view_one``. + Being able to unconditionally obtain a response object by invoking a view callable indirectly is the main advantage to using :meth:`pyramid.request.Request.subrequest` instead of simply importing the -- cgit v1.2.3 From fef69b67c5d07f7b7294fe9b52f70fb9de22d17f Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 03:31:40 -0400 Subject: explain --- docs/narr/subrequest.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'docs/narr') diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst index 045cec279..8429fe7fe 100644 --- a/docs/narr/subrequest.rst +++ b/docs/narr/subrequest.rst @@ -92,7 +92,9 @@ callable indirectly is the main advantage to using :meth:`pyramid.request.Request.subrequest` instead of simply importing the view callable and executing it directly. Note that there's not much advantage to invoking a view using a subrequest if you *can* invoke a view -callable directly. It's much slower to use a subrequest. +callable directly. Subrequests are slower and are less convenient if you +actually do want just the literal information returned by a function that +happens to be a view callable. The :meth:`pyramid.request.Request.subrequest` API accepts two arguments: a positional argument ``request`` that must be provided, and and ``use_tweens`` -- cgit v1.2.3 From 1e59ef41026d9754ac9dc21522dd68edfcaf18d7 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 03:37:37 -0400 Subject: garden todo, add docs about exception handling --- docs/narr/subrequest.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'docs/narr') diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst index 8429fe7fe..39f985520 100644 --- a/docs/narr/subrequest.rst +++ b/docs/narr/subrequest.rst @@ -96,6 +96,36 @@ callable directly. Subrequests are slower and are less convenient if you actually do want just the literal information returned by a function that happens to be a view callable. +Note that if a view callable invoked by a subrequest raises an exception, the +exception will usually bubble up to the invoking code: + +.. code-block:: python + + from wsgiref.simple_server import make_server + from pyramid.config import Configurator + from pyramid.request import Request + + def view_one(request): + subreq = Request.blank('/view_two') + response = request.subrequest(subreq) + return response + + def view_two(request): + raise ValueError('foo') + + if __name__ == '__main__': + config = Configurator() + config.add_route('one', '/view_one') + config.add_route('two', '/view_two') + config.add_view(view_one, route_name='one') + config.add_view(view_two, route_name='two', renderer='string') + app = config.make_wsgi_app() + server = make_server('0.0.0.0', 8080, app) + server.serve_forever() + +In the above application, the call to ``request.subrequest(subreq)`` will +raise a :exc:`ValueError` exception instead of obtaining a "500" response. + The :meth:`pyramid.request.Request.subrequest` API accepts two arguments: a positional argument ``request`` that must be provided, and and ``use_tweens`` keyword argument that is optional; it defaults to ``False``. -- cgit v1.2.3 From b895defdcecbf9d758ad92b1bbf6a49f21620c8a Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 03:39:26 -0400 Subject: wording --- docs/narr/subrequest.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'docs/narr') diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst index 39f985520..4f132f72f 100644 --- a/docs/narr/subrequest.rst +++ b/docs/narr/subrequest.rst @@ -124,7 +124,8 @@ exception will usually bubble up to the invoking code: server.serve_forever() In the above application, the call to ``request.subrequest(subreq)`` will -raise a :exc:`ValueError` exception instead of obtaining a "500" response. +actually raise a :exc:`ValueError` exception instead of retrieving a "500" +response from the attempted invocation of ``view_two``. The :meth:`pyramid.request.Request.subrequest` API accepts two arguments: a positional argument ``request`` that must be provided, and and ``use_tweens`` -- cgit v1.2.3 From 64452edb014423054d1bbc0bb3ed8a3e47b6f611 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 03:54:08 -0400 Subject: rename subrequest to invoke_subrequest --- docs/narr/subrequest.rst | 53 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst index 4f132f72f..bd50b6053 100644 --- a/docs/narr/subrequest.rst +++ b/docs/narr/subrequest.rst @@ -26,7 +26,7 @@ Here's an example application which uses a subrequest: def view_one(request): subreq = Request.blank('/view_two') - response = request.subrequest(subreq) + response = request.invoke_subrequest(subreq) return response def view_two(request): @@ -45,13 +45,14 @@ Here's an example application which uses a subrequest: When ``/view_one`` is visted in a browser, the text printed in the browser pane will be ``This came from view_two``. The ``view_one`` view used the -:meth:`pyramid.request.Request.subrequest` API to obtain a response from -another view (``view_two``) within the same application when it executed. It -did so by constructing a new request that had a URL that it knew would match -the ``view_two`` view registration, and passed that new request along to -:meth:`pyramid.request.Request.subrequest`. The ``view_two`` view callable -was invoked, and it returned a response. The ``view_one`` view callable then -simply returned the response it obtained from the ``view_two`` view callable. +:meth:`pyramid.request.Request.invoke_subrequest` API to obtain a response +from another view (``view_two``) within the same application when it +executed. It did so by constructing a new request that had a URL that it +knew would match the ``view_two`` view registration, and passed that new +request along to :meth:`pyramid.request.Request.invoke_subrequest`. The +``view_two`` view callable was invoked, and it returned a response. The +``view_one`` view callable then simply returned the response it obtained from +the ``view_two`` view callable. Note that it doesn't matter if the view callable invoked via a subrequest actually returns a literal Response object. Any view callable that uses a @@ -66,7 +67,7 @@ adapter will work too: def view_one(request): subreq = Request.blank('/view_two') - response = request.subrequest(subreq) + response = request.invoke_subrequest(subreq) return response def view_two(request): @@ -89,8 +90,8 @@ consumption by ``view_one``. Being able to unconditionally obtain a response object by invoking a view callable indirectly is the main advantage to using -:meth:`pyramid.request.Request.subrequest` instead of simply importing the -view callable and executing it directly. Note that there's not much +:meth:`pyramid.request.Request.invoke_subrequest` instead of simply importing +the view callable and executing it directly. Note that there's not much advantage to invoking a view using a subrequest if you *can* invoke a view callable directly. Subrequests are slower and are less convenient if you actually do want just the literal information returned by a function that @@ -107,7 +108,7 @@ exception will usually bubble up to the invoking code: def view_one(request): subreq = Request.blank('/view_two') - response = request.subrequest(subreq) + response = request.invoke_subrequest(subreq) return response def view_two(request): @@ -123,13 +124,13 @@ exception will usually bubble up to the invoking code: server = make_server('0.0.0.0', 8080, app) server.serve_forever() -In the above application, the call to ``request.subrequest(subreq)`` will -actually raise a :exc:`ValueError` exception instead of retrieving a "500" -response from the attempted invocation of ``view_two``. +In the above application, the call to ``request.invoke_subrequest(subreq)`` +will actually raise a :exc:`ValueError` exception instead of retrieving a +"500" response from the attempted invocation of ``view_two``. -The :meth:`pyramid.request.Request.subrequest` API accepts two arguments: a -positional argument ``request`` that must be provided, and and ``use_tweens`` -keyword argument that is optional; it defaults to ``False``. +The :meth:`pyramid.request.Request.invoke_subrequest` API accepts two +arguments: a positional argument ``request`` that must be provided, and and +``use_tweens`` keyword argument that is optional; it defaults to ``False``. The ``request`` object passed to the API must be an object that implements the Pyramid request interface (such as a :class:`pyramid.request.Request` @@ -138,16 +139,16 @@ instance). If ``use_tweens`` is ``True``, the request will be sent to the ``use_tweens`` is ``False``, the request will be sent to the main router handler, and no tweens will be invoked. It's usually best to not invoke any tweens when executing a subrequest, because the original request will invoke -any tween logic as necessary. The :meth:`pyramid.request.Request.subrequest` -function also: +any tween logic as necessary. The +:meth:`pyramid.request.Request.invoke_subrequest` function also: - manages the threadlocal stack so that :func:`~pyramid.threadlocal.get_current_request` and :func:`~pyramid.threadlocal.get_current_registry` work during a request (they will return the subrequest instead of the original request) -- Adds a ``registry`` attribute and a ``subrequest`` attribute to the request - object it's handed. +- Adds a ``registry`` attribute and a ``invoke_subrequest`` attribute (a + callable) to the request object it's handed. - sets request extensions (such as those added via :meth:`~pyramid.config.Configurator.add_request_method` or @@ -170,8 +171,8 @@ function also: lifetime. It's a poor idea to use the original ``request`` object as an argument to -:meth:`~pyramid.request.Request.subrequest`. You should construct a new -request instead as demonstrated in the above example, using +:meth:`~pyramid.request.Request.invoke_subrequest`. You should construct a +new request instead as demonstrated in the above example, using :meth:`pyramid.request.Request.blank`. Once you've constructed a request object, you'll need to massage the it to match the view callable you'd like to be executed during the subrequest. This can be done by adjusting the @@ -181,5 +182,5 @@ massage your new request object into something that will match the view you'd like to call via a subrequest. We've demonstrated use of a subrequest from within a view callable, but you -can use the :meth:`~pyramid.request.Request.subrequest` API from within a -tween or an event handler as well. +can use the :meth:`~pyramid.request.Request.invoke_subrequest` API from +within a tween or an event handler as well. -- cgit v1.2.3 From 7259e7e9f3d8f8eb70bcf782f622f8613f99a51d Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 13:04:14 -0400 Subject: make use_tweens=True the default, add some more tests --- docs/narr/subrequest.rst | 83 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 15 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst index bd50b6053..1c26da73a 100644 --- a/docs/narr/subrequest.rst +++ b/docs/narr/subrequest.rst @@ -91,14 +91,14 @@ consumption by ``view_one``. Being able to unconditionally obtain a response object by invoking a view callable indirectly is the main advantage to using :meth:`pyramid.request.Request.invoke_subrequest` instead of simply importing -the view callable and executing it directly. Note that there's not much +a view callable and executing it directly. Note that there's not much advantage to invoking a view using a subrequest if you *can* invoke a view callable directly. Subrequests are slower and are less convenient if you actually do want just the literal information returned by a function that happens to be a view callable. Note that if a view callable invoked by a subrequest raises an exception, the -exception will usually bubble up to the invoking code: +exception will usually be converted to a response: .. code-block:: python @@ -124,23 +124,69 @@ exception will usually bubble up to the invoking code: server = make_server('0.0.0.0', 8080, app) server.serve_forever() -In the above application, the call to ``request.invoke_subrequest(subreq)`` -will actually raise a :exc:`ValueError` exception instead of retrieving a -"500" response from the attempted invocation of ``view_two``. +Because the exception view handling tween is generally in the tween list, if +we run the above code, the default :term:`exception view` will generate a +"500" error response, which will be returned to us within ``view_one``: a +Python exception will not be raised. The :meth:`pyramid.request.Request.invoke_subrequest` API accepts two arguments: a positional argument ``request`` that must be provided, and and -``use_tweens`` keyword argument that is optional; it defaults to ``False``. +``use_tweens`` keyword argument that is optional; it defaults to ``True``. The ``request`` object passed to the API must be an object that implements the Pyramid request interface (such as a :class:`pyramid.request.Request` instance). If ``use_tweens`` is ``True``, the request will be sent to the :term:`tween` in the tween stack closest to the request ingress. If ``use_tweens`` is ``False``, the request will be sent to the main router -handler, and no tweens will be invoked. It's usually best to not invoke any -tweens when executing a subrequest, because the original request will invoke -any tween logic as necessary. The -:meth:`pyramid.request.Request.invoke_subrequest` function also: +handler, and no tweens will be invoked. + +In the example above, the call to +:meth:`~pyramid.request.Request.invoke_subrequest` will generally always +return a Response object, even when the view it invokes raises an exception, +because it uses the default ``use_tweens=True``. + +We can cause the subrequest to not be run through the tween stack by passing +``use_tweens=False`` to the call to +:meth:`~pyramid.request.Request.invoke_subrequest`, like this: + +.. code-block:: python + + from wsgiref.simple_server import make_server + from pyramid.config import Configurator + from pyramid.request import Request + + def view_one(request): + subreq = Request.blank('/view_two') + response = request.invoke_subrequest(subreq, use_tweens=False) + return response + + def view_two(request): + raise ValueError('foo') + + if __name__ == '__main__': + config = Configurator() + config.add_route('one', '/view_one') + config.add_route('two', '/view_two') + config.add_view(view_one, route_name='one') + config.add_view(view_two, route_name='two', renderer='string') + app = config.make_wsgi_app() + server = make_server('0.0.0.0', 8080, app) + server.serve_forever() + +In the above case, the call to ``request.invoke_subrequest(subreq)`` will +actually raise a :exc:`ValueError` exception instead of retrieving a "500" +response from the attempted invocation of ``view_two``, because the tween +which invokes an exception view to generate a response is never run. + +This is one of the major differences between specifying the +``use_tweens=True`` and ``use_tweens=False`` arguments to +:meth:`~pyramid.request.Request.invoke_subrequest`. ``use_tweens=True`` may +also imply invoking transaction commit/abort for the logic executed in the +subrequest if you've got ``pyramid_tm`` in the tween list, injecting debug +HTML if you've got ``pyramid_debugtoolbar`` in the tween list, and other +tween-related side effects as defined by your particular tween list. + +The :meth:`~pyramid.request.Request.invoke_subrequest` function also: - manages the threadlocal stack so that :func:`~pyramid.threadlocal.get_current_request` and @@ -176,11 +222,18 @@ new request instead as demonstrated in the above example, using :meth:`pyramid.request.Request.blank`. Once you've constructed a request object, you'll need to massage the it to match the view callable you'd like to be executed during the subrequest. This can be done by adjusting the -subrequest's URL, its headers, its request method, and other attributes. See -the documentation for :class:`pyramid.request.Request` to understand how to -massage your new request object into something that will match the view you'd -like to call via a subrequest. +subrequest's URL, its headers, its request method, and other attributes. The +documentation for :class:`pyramid.request.Request` exposes the methods you +should call and attributes you should set on the request you create to +massage it into something that will actually match the view you'd like to +call via a subrequest. We've demonstrated use of a subrequest from within a view callable, but you can use the :meth:`~pyramid.request.Request.invoke_subrequest` API from -within a tween or an event handler as well. +within a tween or an event handler as well. It's usually a poor idea to +invoke :meth:`~pyramid.request.Request.invoke_subrequest` from within a +tween, because tweens already by definition have access to a function that +will cause a subrequest (they are passed a ``handle`` function), but you can +do it. It's fine to invoke +:meth:`~pyramid.request.Request.invoke_subrequest` from within an event +handler, however. -- cgit v1.2.3 From 0966cfb8bd7ac43f8ce3b6dd903b03ae3bab8ac6 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 13:08:42 -0400 Subject: explain how this works with the exception view --- docs/narr/subrequest.rst | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst index 1c26da73a..43876b45a 100644 --- a/docs/narr/subrequest.rst +++ b/docs/narr/subrequest.rst @@ -98,7 +98,8 @@ actually do want just the literal information returned by a function that happens to be a view callable. Note that if a view callable invoked by a subrequest raises an exception, the -exception will usually be converted to a response: +exception will usually be converted to a response if you have a +:term:`exception view` configured: .. code-block:: python @@ -114,20 +115,26 @@ exception will usually be converted to a response: def view_two(request): raise ValueError('foo') + def excview(request): + request.response.body = b'An exception was raised' + request.response.status_int = 500 + return request.response + if __name__ == '__main__': config = Configurator() config.add_route('one', '/view_one') config.add_route('two', '/view_two') config.add_view(view_one, route_name='one') config.add_view(view_two, route_name='two', renderer='string') + config.add_view(excview, context=Exception) app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever() Because the exception view handling tween is generally in the tween list, if -we run the above code, the default :term:`exception view` will generate a +we run the above code, the ``excview`` :term:`exception view` will generate a "500" error response, which will be returned to us within ``view_one``: a -Python exception will not be raised. +Python exception will not be raised. The :meth:`pyramid.request.Request.invoke_subrequest` API accepts two arguments: a positional argument ``request`` that must be provided, and and @@ -143,7 +150,8 @@ handler, and no tweens will be invoked. In the example above, the call to :meth:`~pyramid.request.Request.invoke_subrequest` will generally always return a Response object, even when the view it invokes raises an exception, -because it uses the default ``use_tweens=True``. +because it uses the default ``use_tweens=True`` and a :term:`exception view` +is configured. We can cause the subrequest to not be run through the tween stack by passing ``use_tweens=False`` to the call to @@ -163,12 +171,18 @@ We can cause the subrequest to not be run through the tween stack by passing def view_two(request): raise ValueError('foo') + def excview(request): + request.response.body = b'An exception was raised' + request.response.status_int = 500 + return request.response + if __name__ == '__main__': config = Configurator() config.add_route('one', '/view_one') config.add_route('two', '/view_two') config.add_view(view_one, route_name='one') config.add_view(view_two, route_name='two', renderer='string') + config.add_view(excview, context=Exception) app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever() @@ -176,7 +190,8 @@ We can cause the subrequest to not be run through the tween stack by passing In the above case, the call to ``request.invoke_subrequest(subreq)`` will actually raise a :exc:`ValueError` exception instead of retrieving a "500" response from the attempted invocation of ``view_two``, because the tween -which invokes an exception view to generate a response is never run. +which invokes an exception view to generate a response is never run, and +therefore ``excview`` is never executed. This is one of the major differences between specifying the ``use_tweens=True`` and ``use_tweens=False`` arguments to -- cgit v1.2.3 From eab66f3e3f5c6ddbe88c5e632d78263a5c3d7cd4 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 14:36:44 -0400 Subject: update docs to recommend 2.7, add distribute-related instructions for python 3, add windows instructions for python 3, closes #653 --- docs/narr/install.rst | 213 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 156 insertions(+), 57 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/install.rst b/docs/narr/install.rst index 172cfd6d3..e8482a289 100644 --- a/docs/narr/install.rst +++ b/docs/narr/install.rst @@ -14,13 +14,13 @@ run :app:`Pyramid`. .. sidebar:: Python Versions - As of this writing, :app:`Pyramid` has been tested under Python 2.6.6, - Python 2.7.2, and Python 3.2. :app:`Pyramid` does not run under any - version of Python before 2.6. + As of this writing, :app:`Pyramid` has been tested under Python 2.6.8, + Python 2.7.3, Python 3.2.3, and Python 3.3b1. :app:`Pyramid` does not + run under any version of Python before 2.6. :app:`Pyramid` is known to run on all popular UNIX-like systems such as Linux, MacOS X, and FreeBSD as well as on Windows platforms. It is also -known to run on :term:`PyPy` (1.6+). +known to run on :term:`PyPy` (1.9+). :app:`Pyramid` installation does not require the compilation of any C code, so you need only a Python interpreter that meets the @@ -45,15 +45,15 @@ system's package manager is slightly different, but the "flavor" of them is usually the same. For example, on an Ubuntu Linux system, to use the system package -manager to install a Python 2.6 interpreter, use the following +manager to install a Python 2.7 interpreter, use the following command: .. code-block:: text - $ sudo apt-get install python2.6-dev + $ sudo apt-get install python2.7-dev Once these steps are performed, the Python interpreter will usually be -invokable via ``python2.6`` from a shell prompt. +invokable via ``python2.7`` from a shell prompt. .. index:: pair: install; Python (from source, UNIX) @@ -80,7 +80,7 @@ On Mac OS X, installing `XCode `_ has much the same effect. Once you've got development tools installed on your system, you can -install a Python 2.6 interpreter from *source*, on the same system, +install a Python 2.7 interpreter from *source*, on the same system, using the following commands: .. code-block:: text @@ -90,15 +90,15 @@ using the following commands: [chrism@vitaminf ~]$ mkdir opt [chrism@vitaminf ~]$ cd tmp [chrism@vitaminf tmp]$ wget \ - http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tgz - [chrism@vitaminf tmp]$ tar xvzf Python-2.6.4.tgz - [chrism@vitaminf tmp]$ cd Python-2.6.4 - [chrism@vitaminf Python-2.6.4]$ ./configure \ - --prefix=$HOME/opt/Python-2.6.4 - [chrism@vitaminf Python-2.6.4]$ make; make install + http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz + [chrism@vitaminf tmp]$ tar xvzf Python-2.7.3.tgz + [chrism@vitaminf tmp]$ cd Python-2.7.3 + [chrism@vitaminf Python-2.7.3]$ ./configure \ + --prefix=$HOME/opt/Python-2.7.3 + [chrism@vitaminf Python-2.7.3]$ make; make install Once these steps are performed, the Python interpreter will be -invokable via ``$HOME/opt/Python-2.6.4/bin/python`` from a shell +invokable via ``$HOME/opt/Python-2.7.3/bin/python`` from a shell prompt. .. index:: @@ -108,7 +108,7 @@ If You Don't Yet Have A Python Interpreter (Windows) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If your Windows system doesn't have a Python interpreter, you'll need -to install it by downloading a Python 2.6-series interpreter +to install it by downloading a Python 2.7-series interpreter executable from `python.org's download section `_ (the files labeled "Windows Installer"). Once you've downloaded it, double click on the @@ -119,7 +119,7 @@ extensions `_. .. warning:: After you install Python on Windows, you may need to add the - ``C:\Python26`` directory to your environment's ``Path`` in order + ``C:\Python27`` directory to your environment's ``Path`` in order to make it possible to invoke Python from a command prompt by typing ``python``. To do so, right click ``My Computer``, select ``Properties`` --> ``Advanced Tab`` --> ``Environment Variables`` @@ -141,39 +141,62 @@ done by using the :term:`virtualenv` package. Using a virtualenv will also prevent :app:`Pyramid` from globally installing versions of packages that are not compatible with your system Python. -To set up a virtualenv in which to install :app:`Pyramid`, first -ensure that :term:`setuptools` is installed. Invoke ``import -setuptools`` within the Python interpreter you'd like to run -:app:`Pyramid` under: +To set up a virtualenv in which to install :app:`Pyramid`, first ensure that +:term:`setuptools` or :term:`distribute` is installed. To do so, invoke +``import setuptools`` within the Python interpreter you'd like to run +:app:`Pyramid` under. + +Here's the output you'll expect if setuptools or distribute is already +installed: .. code-block:: text - [chrism@vitaminf pyramid]$ python - Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32) - [GCC 4.4.3] on linux2 + [chrism@thinko docs]$ python2.7 + Python 2.7.3 (default, Aug 1 2012, 05:14:39) + [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import setuptools + >>> -If running ``import setuptools`` does not raise an ``ImportError``, it -means that setuptools is already installed into your Python -interpreter. If ``import setuptools`` fails, you will need to install -setuptools manually. Note that above we're using a Python 2.6-series -interpreter on Mac OS X; your output may differ if you're using a -later Python version or a different platform. - -If you are using a "system" Python (one installed by your OS -distributor or a 3rd-party packager such as Fink or MacPorts), you can -usually install the setuptools package by using your system's package -manager. If you cannot do this, or if you're using a self-installed -version of Python, you will need to install setuptools "by hand". -Installing setuptools "by hand" is always a reasonable thing to do, -even if your package manager already has a pre-chewed version of -setuptools for installation. - -To install setuptools by hand, first download `ez_setup.py -`_ then invoke it -using the Python interpreter into which you want to install -setuptools. +Here's the output you can expect if setuptools or distribute is not already +installed: + +.. code-block:: text + + [chrism@thinko docs]$ python2.7 + Python 2.7.3 (default, Aug 1 2012, 05:14:39) + [GCC 4.6.3] on linux2 + Type "help", "copyright", "credits" or "license" for more information. + >>> import setutptools + Traceback (most recent call last): + File "", line 1, in + ImportError: No module named setutptools + >>> + +If ``import setuptools`` raises an :exc:`ImportError` as it does above, you +will need to install setuptools or distribute manually. Note that above +we're using a Python 2.7-series interpreter on Mac OS X; your output may +differ if you're using a later Python version or a different platform. + +If you are using a "system" Python (one installed by your OS distributor or a +3rd-party packager such as Fink or MacPorts), you can usually install the +setuptools or distribute package by using your system's package manager. If +you cannot do this, or if you're using a self-installed version of Python, +you will need to install setuptools or distribute "by hand". Installing +setuptools or distribute "by hand" is always a reasonable thing to do, even +if your package manager already has a pre-chewed version of setuptools for +installation. + +If you're using Python 2, you'll want to install ``setuptools``. If you're +using Python 3, you'll want to install ``distribute``. Below we tell you how +to do both. + +Installing Setuptools On Python 2 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To install setuptools by hand under Python 2, first download `ez_setup.py +`_ then invoke it using the +Python interpreter into which you want to install setuptools. .. code-block:: text @@ -188,16 +211,37 @@ the script. To remediate this, you may need to do: $ sudo python ez_setup.py +Installing Distribute On Python 3 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``setuptools`` doesn't work under Python 3. Instead, you can use +``distribute``, which is a fork of setuptools that does work on Python 3. To +install it, first download `distribute_setup.py +`_ then invoke it using the +Python interpreter into which you want to install setuptools. + +.. code-block:: text + + $ python3 distribute_setup.py + +Once this command is invoked, distribute should be installed on your system. +If the command fails due to permission errors, you may need to be the +administrative user on your system to successfully invoke the script. To +remediate this, you may need to do: + +.. code-block:: text + + $ sudo python3 distribute_setup.py + .. index:: pair: install; virtualenv Installing the ``virtualenv`` Package ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Once you've got setuptools installed, you should install the -:term:`virtualenv` package. To install the :term:`virtualenv` package -into your setuptools-enabled Python interpreter, use the -``easy_install`` command. +Once you've got setuptools or distribute installed, you should install the +:term:`virtualenv` package. To install the :term:`virtualenv` package into +your setuptools-enabled Python interpreter, use the ``easy_install`` command. .. code-block:: text @@ -269,35 +313,90 @@ complete, as it downloads and installs a number of dependencies. Installing :app:`Pyramid` on a Windows System ------------------------------------------------- -#. Install, or find `Python 2.6 - `_ for your system. +You can use Pyramid on Windows under Python 2 or under Python 3. Directions +for both versions are included below. + +Windows Using Python 2 +~~~~~~~~~~~~~~~~~~~~~~ + +#. Install, or find `Python 2.7 + `_ for your system. #. Install the `Python for Windows extensions `_. Make sure to - pick the right download for Python 2.6 and install it using the + pick the right download for Python 2.7 and install it using the same Python installation from the previous step. #. Install latest :term:`setuptools` distribution into the Python you obtained/installed/found in the step above: download `ez_setup.py `_ and run it using - the ``python`` interpreter of your Python 2.6 installation using a + the ``python`` interpreter of your Python 2.7 installation using a command prompt: .. code-block:: text - c:\> c:\Python26\python ez_setup.py + c:\> c:\Python27\python ez_setup.py + +#. Use that Python's `bin/easy_install` to install `virtualenv`: + + .. code-block:: text + + c:\> c:\Python27\Scripts\easy_install virtualenv + +#. Use that Python's virtualenv to make a workspace: + + .. code-block:: text + + c:\> c:\Python27\Scripts\virtualenv --no-site-packages env + +#. Switch to the ``env`` directory: + + .. code-block:: text + + c:\> cd env + +#. (Optional) Consider using ``Scripts\activate.bat`` to make your shell + environment wired to use the virtualenv. + +#. Use ``easy_install`` to get :app:`Pyramid` and its direct dependencies + installed: + + .. code-block:: text + + c:\env> Scripts\easy_install pyramid + +Windows Using Python 3 +~~~~~~~~~~~~~~~~~~~~~~ + +#. Install, or find `Python 3.2 + `_ for your system. + +#. Install the `Python for Windows extensions + `_. Make sure to + pick the right download for Python 3.2 and install it using the + same Python installation from the previous step. + +#. Install latest :term:`distribute` distribution into the Python you + obtained/installed/found in the step above: download `distribute_setup.py + `_ and run it using the + ``python`` interpreter of your Python 3.2 installation using a command + prompt: + + .. code-block:: text + + c:\> c:\Python32\python distribute_setup.py #. Use that Python's `bin/easy_install` to install `virtualenv`: .. code-block:: text - c:\> c:\Python26\Scripts\easy_install virtualenv + c:\> c:\Python32\Scripts\easy_install virtualenv #. Use that Python's virtualenv to make a workspace: .. code-block:: text - c:\> c:\Python26\Scripts\virtualenv --no-site-packages env + c:\> c:\Python32\Scripts\virtualenv --no-site-packages env #. Switch to the ``env`` directory: @@ -308,8 +407,8 @@ Installing :app:`Pyramid` on a Windows System #. (Optional) Consider using ``Scripts\activate.bat`` to make your shell environment wired to use the virtualenv. -#. Use ``easy_install`` pointed at the "current" index to get - :app:`Pyramid` and its direct dependencies installed: +#. Use ``easy_install`` to get :app:`Pyramid` and its direct dependencies + installed: .. code-block:: text -- cgit v1.2.3 From dace59817bea583145f6ecf0910712b527ef2d0b Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 21:42:25 -0400 Subject: describe how to restrict access to 127.0.0.1, closes #489 --- docs/narr/project.rst | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 1e2c225d2..b08948e43 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -286,11 +286,39 @@ Here's sample output from a run of ``pserve`` on UNIX: $ ../bin/pserve development.ini Starting server in PID 16601. - serving on 0.0.0.0:6543 view at http://127.0.0.1:6543 + serving on http://0.0.0.0:6543 -By default, :app:`Pyramid` applications generated from a scaffold -will listen on TCP port 6543. You can shut down a server started this way by -pressing ``Ctrl-C``. +When you use ``pserve`` to start the application implied by the default +rendering of a scaffold, it will respond to requests on *all* IP addresses +possessed by your system, not just requests to ``localhost``. This is what +the ``0.0.0.0`` in ``serving on http://0.0.0.0:6543`` means. The server will +respond to requests made to ``127.0.0.1`` and on any external IP address. +For example, your system might be configured to have an external IP address +``192.168.1.50``. If that's the case, if you use a browser running on the +same system as Pyramid, it will be able to access the application via +``http://127.0.0.1:6543/`` as well as via +``http://129.168.1.50:6543/``. However, *other people* on other computers on +the same network will also be able to visit your Pyramid application in their +browser by visiting ``http://192.168.1.50:6543/``. + +If you want to restrict access such that only a browser running on the same +machine as Pyramid will be able to access your Pyramid application, edit the +``development.ini`` file, and replace the ``host`` value in the +``[server:main]`` section. Change it from ``0.0.0.0`` to ``127.0.0.1``. For +example:: + + [server:main] + use = egg:waitress#main + host = 127.0.0.1 + port = 6543 + +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 +``port = 6543`` line in the ``development.ini`` file's ``[server:main]`` +section to ``port = 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``. The default server used to run your Pyramid application when a project is created from a scaffold is named :term:`Waitress`. This server is what @@ -309,11 +337,6 @@ under the default server, it will almost certainly work under any other server in production if you eventually choose to use a different one. Don't worry about it right now. -You can change the port on which the server runs on by changing the -``development.ini`` file. For example, you can change the ``port = 6543`` -line in the ``development.ini`` file's ``[server:main]`` section to ``port = -8080`` to run the server on port 8080 instead of port 6543. - For more detailed information about the startup process, see :ref:`startup_chapter`. For more information about environment variables and configuration file settings that influence startup and runtime behavior, see -- cgit v1.2.3 From db2a03786ec76f2c6b7eaebb6f1b7c8b844d8c82 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 22:32:26 -0400 Subject: make use_tweens=False the default --- docs/narr/subrequest.rst | 63 ++++++++++++++++++++++++++++++------------------ docs/narr/views.rst | 10 ++++++++ 2 files changed, 50 insertions(+), 23 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst index 43876b45a..89551ab35 100644 --- a/docs/narr/subrequest.rst +++ b/docs/narr/subrequest.rst @@ -55,9 +55,11 @@ request along to :meth:`pyramid.request.Request.invoke_subrequest`. The the ``view_two`` view callable. Note that it doesn't matter if the view callable invoked via a subrequest -actually returns a literal Response object. Any view callable that uses a +actually returns a *literal* Response object. Any view callable that uses a renderer or which returns an object that can be interpreted by a response -adapter will work too: +adapter when found and invoked via +:meth:`pyramid.request.Request.invoke_subrequest` will return a Response +object: .. code-block:: python @@ -97,8 +99,9 @@ callable directly. Subrequests are slower and are less convenient if you actually do want just the literal information returned by a function that happens to be a view callable. -Note that if a view callable invoked by a subrequest raises an exception, the -exception will usually be converted to a response if you have a +Note that, by default, if a view callable invoked by a subrequest raises an +exception, the exception will be raised to the caller of +:meth:`~pyramid.request.Request.invoke_subrequest` even if you have a :term:`exception view` configured: .. code-block:: python @@ -131,14 +134,16 @@ exception will usually be converted to a response if you have a server = make_server('0.0.0.0', 8080, app) server.serve_forever() -Because the exception view handling tween is generally in the tween list, if -we run the above code, the ``excview`` :term:`exception view` will generate a -"500" error response, which will be returned to us within ``view_one``: a -Python exception will not be raised. +When we run the above code and visit ``/view_one`` in a browser, the +``excview`` :term:`exception view` will *not* be executed. Instead, the call +to :meth:`~pyramid.request.Request.invoke_subrequest` will cause a +:exc:`ValueError` exception to be raised and a response will never be +generated. We can change this behavior; how to do so is described below in +our discussion of the ``use_tweens`` argument. The :meth:`pyramid.request.Request.invoke_subrequest` API accepts two arguments: a positional argument ``request`` that must be provided, and and -``use_tweens`` keyword argument that is optional; it defaults to ``True``. +``use_tweens`` keyword argument that is optional; it defaults to ``False``. The ``request`` object passed to the API must be an object that implements the Pyramid request interface (such as a :class:`pyramid.request.Request` @@ -148,13 +153,16 @@ instance). If ``use_tweens`` is ``True``, the request will be sent to the handler, and no tweens will be invoked. In the example above, the call to -:meth:`~pyramid.request.Request.invoke_subrequest` will generally always -return a Response object, even when the view it invokes raises an exception, -because it uses the default ``use_tweens=True`` and a :term:`exception view` -is configured. - -We can cause the subrequest to not be run through the tween stack by passing -``use_tweens=False`` to the call to +:meth:`~pyramid.request.Request.invoke_subrequest` will always raise an +exception. This is because it's using the default value for ``use_tweens``, +which is ``False``. You can pass ``use_tweens=True`` instead to ensure that +it will convert an exception to a Response if an :term:`exception view` is +configured instead of raising the exception. This because exception views +are called by the exception view :term:`tween` as described in +:ref:`exception_views` when any view raises an exception. + +We can cause the subrequest to be run through the tween stack by passing +``use_tweens=True`` to the call to :meth:`~pyramid.request.Request.invoke_subrequest`, like this: .. code-block:: python @@ -165,7 +173,7 @@ We can cause the subrequest to not be run through the tween stack by passing def view_one(request): subreq = Request.blank('/view_two') - response = request.invoke_subrequest(subreq, use_tweens=False) + response = request.invoke_subrequest(subreq, use_tweens=True) return response def view_two(request): @@ -187,11 +195,11 @@ We can cause the subrequest to not be run through the tween stack by passing server = make_server('0.0.0.0', 8080, app) server.serve_forever() -In the above case, the call to ``request.invoke_subrequest(subreq)`` will -actually raise a :exc:`ValueError` exception instead of retrieving a "500" -response from the attempted invocation of ``view_two``, because the tween -which invokes an exception view to generate a response is never run, and -therefore ``excview`` is never executed. +In the above case, the call to ``request.invoke_subrequest(subreq)`` will not +raise an exception. Instead, it will retrieve a "500" response from the +attempted invocation of ``view_two``, because the tween which invokes an +exception view to generate a response is run, and therefore ``excview`` is +executed. This is one of the major differences between specifying the ``use_tweens=True`` and ``use_tweens=False`` arguments to @@ -201,7 +209,8 @@ subrequest if you've got ``pyramid_tm`` in the tween list, injecting debug HTML if you've got ``pyramid_debugtoolbar`` in the tween list, and other tween-related side effects as defined by your particular tween list. -The :meth:`~pyramid.request.Request.invoke_subrequest` function also: +The :meth:`~pyramid.request.Request.invoke_subrequest` function also +unconditionally: - manages the threadlocal stack so that :func:`~pyramid.threadlocal.get_current_request` and @@ -222,6 +231,9 @@ The :meth:`~pyramid.request.Request.invoke_subrequest` function also: - causes a :class:`~pyramid.event.ContextFound` event to be sent when a context resource is found. +- Ensures that the user implied by the request passed has the necessary + authorization to invoke view callable before calling it. + - causes a :class:`~pyramid.event.NewResponse` event to be sent when the Pyramid application returns a response. @@ -231,6 +243,11 @@ The :meth:`~pyramid.request.Request.invoke_subrequest` function also: - Calls any :term:`finished callback` functions defined within the subrequest's lifetime. +The invocation of a subrequest has more or less exactly the same effect as +the invocation of a request received by the Pyramid router from a web client +when ``use_tweens=True``. When ``use_tweens=False``, the tweens are skipped +but all the other steps take place. + It's a poor idea to use the original ``request`` object as an argument to :meth:`~pyramid.request.Request.invoke_subrequest`. You should construct a new request instead as demonstrated in the above example, using diff --git a/docs/narr/views.rst b/docs/narr/views.rst index 9e41464a6..07d018127 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -338,6 +338,16 @@ exception views which have a name will be ignored. Exception views can be configured with any view registration mechanism: ``@view_config`` decorator or imperative ``add_view`` styles. +.. note:: + + Pyramid's :term:`exception view` handling logic is implemented as a tween + factory function: :func:`pyramid.tweens.excview_tween_factory`. If + Pyramid exception view handling is desired, and tween factories are + specified via the ``pyramid.tweens`` configuration setting, the + :func:`pyramid.tweens.excview_tween_factory` function must be added to the + ``pyramid.tweens`` configuration setting list explicitly. If it is not + present, Pyramid will not perform exception view handling. + .. index:: single: view http redirect single: http redirect (from a view) -- cgit v1.2.3 From 643a83473a6faabd0ff08547a0cbca09e9cdda1c Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 19 Sep 2012 04:46:01 -0400 Subject: A ``check_csrf`` view predicate was added. For example, you can now do ``config.add_view(someview, check_csrf=True)``. When the predicate is checked, if the ``csrf_token`` value in ``request.params`` matches the csrf token in the request's session, the view will be permitted to execute. Otherwise, it will not be permitted to execute. --- docs/narr/introspector.rst | 4 ++++ docs/narr/viewconfig.rst | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'docs/narr') diff --git a/docs/narr/introspector.rst b/docs/narr/introspector.rst index 6bfaf11c0..b88f3f0c8 100644 --- a/docs/narr/introspector.rst +++ b/docs/narr/introspector.rst @@ -393,6 +393,10 @@ introspectables in categories not described here. The ``match_param`` argument passed to ``add_view``. + ``csrf_token`` + + The ``csrf_token`` argument passed to ``add_view``. + ``callable`` The (resolved) ``view`` argument passed to ``add_view``. Represents the diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index 23b4fde68..f65435cc6 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -394,6 +394,28 @@ configured view. consideration when deciding whether or not to invoke the associated view callable. +``check_csrf`` + If specified, this value should be one of ``None``, ``True``, ``False``, or + a string representing the 'check name'. If the value is ``True`` or a + string, CSRF checking will be performed. If the value is ``False`` or + ``None``, CSRF checking will not be performed. + + If the value provided is a string, that string will be used as the 'check + name'. If the value provided is ``True``, ``csrf_token`` will be used as + the check name. + + If CSRF checking is performed, the checked value will be the value of + ``request.params[check_name]``. This value will be compared against the + value of ``request.session.get_csrf_token()``, and the check will pass if + these two values are the same. If the check passes, the associated view + will be permitted to execute. If the check fails, the associated view + will not be permitted to execute. + + Note that using this feature requires a :term:`session factory` to have + been configured. + + .. versionadded:: 1.4a2 + ``custom_predicates`` If ``custom_predicates`` is specified, it must be a sequence of references to custom predicate callables. Use custom predicates when no set of @@ -407,6 +429,15 @@ configured view. If ``custom_predicates`` is not specified, no custom predicates are used. +``predicates`` + Pass a key/value pair here to use a third-party predicate registered via + :meth:`pyramid.config.Configurator.add_view_predicate`. More than one + key/value pair can be used at the same time. See + :ref:`view_and_route_predicates` for more information about third-party + predicates. + + .. versionadded:: 1.4a1 + .. index:: single: view_config decorator -- cgit v1.2.3 From 5f0e510c7de2735f8cb84479be07a94a9617b8b8 Mon Sep 17 00:00:00 2001 From: Carlos de la Guardia Date: Fri, 28 Sep 2012 01:14:27 -0500 Subject: Remove duplicate word --- docs/narr/introduction.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr') diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 7c0f9223f..b35c61720 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -315,7 +315,7 @@ Rendered views can return dictionaries If you use a :term:`renderer`, you don't have to return a special kind of "webby" ``Response`` object from a view. Instead, you can return a -dictionary instead, and Pyramid will take care of converting that dictionary +dictionary, and Pyramid will take care of converting that dictionary to a Response using a template on your behalf. This makes the view easier to test, because you don't have to parse HTML in your tests; just make an assertion instead that the view returns "the right stuff" in the dictionary -- cgit v1.2.3