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/api/testing.rst | 2 ++ docs/narr/testing.rst | 24 +++++++++++++++++++ pyramid/testing.py | 35 +++++++++++++++++++++++++++ pyramid/tests/test_testing.py | 55 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+) diff --git a/docs/api/testing.rst b/docs/api/testing.rst index f388dc263..1366a1795 100644 --- a/docs/api/testing.rst +++ b/docs/api/testing.rst @@ -9,6 +9,8 @@ .. autofunction:: tearDown + .. autofunction:: testConfig(registry=None, request=None, hook_zca=True, autocommit=True, settings=None) + .. autofunction:: cleanUp .. autoclass:: DummyResource 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? ~~~~~ diff --git a/pyramid/testing.py b/pyramid/testing.py index 40e90cda6..5589f6ae2 100644 --- a/pyramid/testing.py +++ b/pyramid/testing.py @@ -1,5 +1,6 @@ import copy import os +from contextlib import contextmanager from zope.deprecation import deprecated @@ -941,3 +942,37 @@ def skip_on(*platforms): # pragma: no cover return wrapper return decorator skip_on.os_name = os.name # for testing + +@contextmanager +def testConfig(registry=None, + request=None, + hook_zca=True, + autocommit=True, + settings=None): + """Returns a context manager for test set up. + + This context manager calls :func:`pyramid.testing.testSetup` when + entering and :func:`pyramid.testing.tearDown` when exiting. + + All arguments are passed directly to :func:`pyramid.testing.testSetup`. + If the ZCA is hooked, it will always be un-hooked in tearDown. + + This context manager allows you to write test code like this: + + .. code-block:: python + :linenos: + + with testConfig() as config: + config.add_route('bar', '/bar/{id}') + req = DummyRequest() + resp = myview(req), + """ + config = setUp(registry=registry, + request=request, + hook_zca=hook_zca, + autocommit=autocommit, + settings=settings) + try: + yield config + finally: + tearDown(unhook_zca=hook_zca) diff --git a/pyramid/tests/test_testing.py b/pyramid/tests/test_testing.py index 5b0073b81..779c66818 100644 --- a/pyramid/tests/test_testing.py +++ b/pyramid/tests/test_testing.py @@ -932,3 +932,58 @@ class DummyRendererInfo(object): def __init__(self, kw): self.__dict__.update(kw) +class Test_testConfig(unittest.TestCase): + + def _setUp(self, **kw): + self._log.append(('setUp', kw)) + return 'fake config' + + def _tearDown(self, **kw): + self._log.append(('tearDown', kw)) + + def setUp(self): + from pyramid import testing + self._log = [] + self._orig_setUp = testing.setUp + testing.setUp = self._setUp + self._orig_tearDown = testing.tearDown + testing.tearDown = self._tearDown + + def tearDown(self): + from pyramid import testing + testing.setUp = self._orig_setUp + testing.tearDown = self._orig_tearDown + + def _callFUT(self, inner, **kw): + from pyramid.testing import testConfig + with testConfig(**kw) as config: + inner(config) + + def test_ok_calls(self): + self.assertEqual(self._log, []) + def inner(config): + self.assertEqual(self._log, + [('setUp', + {'autocommit': True, + 'hook_zca': True, + 'registry': None, + 'request': None, + 'settings': None})]) + self._log.pop() + self._callFUT(inner) + self.assertEqual(self._log, + [('tearDown', {'unhook_zca': True})]) + + def test_teardown_called_on_exception(self): + class TestException(Exception): + pass + def inner(config): + self._log = [] + raise TestException('oops') + self.assertRaises(TestException, self._callFUT, inner) + self.assertEqual(self._log[0][0], 'tearDown') + + def test_ok_get_config(self): + def inner(config): + self.assertEqual(config, 'fake config') + self._callFUT(inner) -- cgit v1.2.3 From d6f0fd56fb93d30d8d7d6b490a57967d940b0135 Mon Sep 17 00:00:00 2001 From: Brian Sutherland Date: Sat, 16 Jun 2012 12:58:58 +0200 Subject: add myself to contributers --- CONTRIBUTORS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 027fc0857..65ff1b2f2 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -174,3 +174,5 @@ Contributors - Marin Rukavina, 2012/05/03 - Marc Abramowitz, 2012/06/13 + +- Brian Sutherland, 2012/06/16 -- cgit v1.2.3 From 8d20bd8e3d14c0de208177032aedac79c5a1328d Mon Sep 17 00:00:00 2001 From: David Gay Date: Sun, 29 Jul 2012 18:53:03 -0400 Subject: add whitespace to scaffolds' CSS --- .../scaffolds/alchemy/+package+/static/pylons.css | 435 ++++++++++++++++++--- .../scaffolds/starter/+package+/static/pylons.css | 435 ++++++++++++++++++--- pyramid/scaffolds/zodb/+package+/static/pylons.css | 435 ++++++++++++++++++--- 3 files changed, 1113 insertions(+), 192 deletions(-) diff --git a/pyramid/scaffolds/alchemy/+package+/static/pylons.css b/pyramid/scaffolds/alchemy/+package+/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/pyramid/scaffolds/alchemy/+package+/static/pylons.css +++ b/pyramid/scaffolds/alchemy/+package+/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; +} diff --git a/pyramid/scaffolds/starter/+package+/static/pylons.css b/pyramid/scaffolds/starter/+package+/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/pyramid/scaffolds/starter/+package+/static/pylons.css +++ b/pyramid/scaffolds/starter/+package+/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; +} diff --git a/pyramid/scaffolds/zodb/+package+/static/pylons.css b/pyramid/scaffolds/zodb/+package+/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/pyramid/scaffolds/zodb/+package+/static/pylons.css +++ b/pyramid/scaffolds/zodb/+package+/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 a07dcd3c63e0ce737335a56290126cdfd62254a8 Mon Sep 17 00:00:00 2001 From: David Gay Date: Sun, 29 Jul 2012 18:59:02 -0400 Subject: correct typo 'snall' to 'small' --- docs/tutorials/wiki/src/models/tutorial/static/pylons.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/wiki/src/models/tutorial/static/pylons.css b/docs/tutorials/wiki/src/models/tutorial/static/pylons.css index 7e6ec739d..c54499ddd 100644 --- a/docs/tutorials/wiki/src/models/tutorial/static/pylons.css +++ b/docs/tutorials/wiki/src/models/tutorial/static/pylons.css @@ -42,7 +42,7 @@ body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;fo #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-snall,.middle,.bottom{width:750px;margin-right:auto;margin-left:auto;} +.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;} -- 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 ++++++++++++++++++--- .../src/authorization/tutorial/static/pylons.css | 435 ++++++++++++++++++--- .../src/basiclayout/tutorial/static/pylons.css | 435 ++++++++++++++++++--- .../wiki/src/models/tutorial/static/pylons.css | 435 ++++++++++++++++++--- .../wiki/src/tests/tutorial/static/pylons.css | 435 ++++++++++++++++++--- .../wiki/src/views/tutorial/static/pylons.css | 435 ++++++++++++++++++--- .../src/authorization/tutorial/static/pylons.css | 435 ++++++++++++++++++--- .../src/basiclayout/tutorial/static/pylons.css | 435 ++++++++++++++++++--- .../wiki2/src/models/tutorial/static/pylons.css | 435 ++++++++++++++++++--- .../wiki2/src/tests/tutorial/static/pylons.css | 435 ++++++++++++++++++--- .../wiki2/src/views/tutorial/static/pylons.css | 435 ++++++++++++++++++--- 11 files changed, 4081 insertions(+), 704 deletions(-) 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; +} diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css b/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css +++ b/docs/tutorials/wiki/src/authorization/tutorial/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; +} diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css b/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/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; +} diff --git a/docs/tutorials/wiki/src/models/tutorial/static/pylons.css b/docs/tutorials/wiki/src/models/tutorial/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/tutorials/wiki/src/models/tutorial/static/pylons.css +++ b/docs/tutorials/wiki/src/models/tutorial/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; +} diff --git a/docs/tutorials/wiki/src/tests/tutorial/static/pylons.css b/docs/tutorials/wiki/src/tests/tutorial/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/static/pylons.css +++ b/docs/tutorials/wiki/src/tests/tutorial/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; +} diff --git a/docs/tutorials/wiki/src/views/tutorial/static/pylons.css b/docs/tutorials/wiki/src/views/tutorial/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/tutorials/wiki/src/views/tutorial/static/pylons.css +++ b/docs/tutorials/wiki/src/views/tutorial/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; +} diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css +++ b/docs/tutorials/wiki2/src/authorization/tutorial/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; +} diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/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; +} diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css +++ b/docs/tutorials/wiki2/src/models/tutorial/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; +} diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css +++ b/docs/tutorials/wiki2/src/tests/tutorial/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; +} diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css index c54499ddd..4b1c017cd 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css +++ b/docs/tutorials/wiki2/src/views/tutorial/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 4c1933f522731e1ae5874275025a8d20b9e63336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Domen=20Ko=C5=BEar?= Date: Tue, 11 Sep 2012 19:38:11 +0200 Subject: remove pypy from travis-ci allow_failures list --- .travis.yml | 6 ------ CONTRIBUTORS.txt | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 490fd2df7..ab9c3ff30 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,12 +6,6 @@ python: - pypy - 3.2 -# Why does travis-ci's PyPy blow up? Pyramid's tests -# run fine under tox. -matrix: - allow_failures: - - python: pypy - script: python setup.py test notifications: diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 264acf048..bb11006f3 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -182,3 +182,5 @@ Contributors - Ian Wilson, 2012/06/17 - Roman Kozlovskyi, 2012/08/11 + +- Domen Kozar, 2012/09/11 -- 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(+) 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 714dd4164d7b2f473c4437f1db0460b819c64680 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 15 Sep 2012 18:09:37 -0400 Subject: remove dead code which supported jython --- pyramid/chameleon_text.py | 13 +------------ pyramid/chameleon_zpt.py | 13 +------------ pyramid/tests/test_chameleon_text.py | 10 ---------- pyramid/tests/test_chameleon_zpt.py | 10 ---------- 4 files changed, 2 insertions(+), 44 deletions(-) diff --git a/pyramid/chameleon_text.py b/pyramid/chameleon_text.py index 3484b7973..21dc85528 100644 --- a/pyramid/chameleon_text.py +++ b/pyramid/chameleon_text.py @@ -2,18 +2,7 @@ import sys from zope.interface import implementer -from pyramid.compat import reraise - -try: - from chameleon.zpt.template import PageTextTemplateFile - # prevent pyflakes complaining about a redefinition below - PageTextTemplateFile -except ImportError: # pragma: no cover - exc_class, exc, tb = sys.exc_info() - # Chameleon doesn't work on non-CPython platforms - class PageTextTemplateFile(object): - def __init__(self, *arg, **kw): - reraise(ImportError, exc, tb) +from chameleon.zpt.template import PageTextTemplateFile from pyramid.interfaces import ITemplateRenderer diff --git a/pyramid/chameleon_zpt.py b/pyramid/chameleon_zpt.py index d9f4337fa..862e996b9 100644 --- a/pyramid/chameleon_zpt.py +++ b/pyramid/chameleon_zpt.py @@ -2,20 +2,9 @@ import sys from zope.interface import implementer -from pyramid.compat import reraise - -try: - from chameleon.zpt.template import PageTemplateFile - PageTemplateFile # prevent pyflakes complaining about a redefinition below -except ImportError: # pragma: no cover - exc_class, exc, tb = sys.exc_info() - # Chameleon doesn't work on non-CPython platforms - class PageTemplateFile(object): - def __init__(self, *arg, **kw): - reraise(ImportError, exc, tb) +from chameleon.zpt.template import PageTemplateFile from pyramid.interfaces import ITemplateRenderer - from pyramid.decorator import reify from pyramid import renderers diff --git a/pyramid/tests/test_chameleon_text.py b/pyramid/tests/test_chameleon_text.py index 297e96554..d9f20f241 100644 --- a/pyramid/tests/test_chameleon_text.py +++ b/pyramid/tests/test_chameleon_text.py @@ -2,7 +2,6 @@ import sys import unittest from pyramid.compat import binary_type -from pyramid.testing import skip_on from pyramid import testing class Base(object): @@ -50,7 +49,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase): from pyramid.interfaces import ITemplateRenderer verifyClass(ITemplateRenderer, self._getTargetClass()) - @skip_on('java') def test_template_reified(self): minimal = self._getTemplatePath('minimal.txt') lookup = DummyLookup() @@ -59,7 +57,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template, instance.__dict__['template']) - @skip_on('java') def test_template_with_ichameleon_translate(self): minimal = self._getTemplatePath('minimal.txt') lookup = DummyLookup() @@ -68,7 +65,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template.translate, lookup.translate) - @skip_on('java') def test_template_with_debug_templates(self): minimal = self._getTemplatePath('minimal.txt') lookup = DummyLookup() @@ -78,7 +74,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template.debug, True) - @skip_on('java') def test_template_with_reload_templates(self): minimal = self._getTemplatePath('minimal.txt') lookup = DummyLookup() @@ -88,7 +83,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template.auto_reload, True) - @skip_on('java') def test_template_without_reload_templates(self): minimal = self._getTemplatePath('minimal.txt') lookup = DummyLookup() @@ -98,7 +92,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template.auto_reload, False) - @skip_on('java') def test_call(self): minimal = self._getTemplatePath('minimal.txt') lookup = DummyLookup() @@ -107,14 +100,12 @@ class TextTemplateRendererTests(Base, unittest.TestCase): self.assertTrue(isinstance(result, binary_type)) self.assertEqual(result, b'Hello.\n') - @skip_on('java') def test_call_with_nondict_value(self): minimal = self._getTemplatePath('minimal.txt') lookup = DummyLookup() instance = self._makeOne(minimal, lookup) self.assertRaises(ValueError, instance, None, {}) - @skip_on('java') def test_call_nonminimal(self): nonminimal = self._getTemplatePath('nonminimal.txt') lookup = DummyLookup() @@ -123,7 +114,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase): self.assertTrue(isinstance(result, binary_type)) self.assertEqual(result, b'Hello, Chris!\n') - @skip_on('java') def test_implementation(self): minimal = self._getTemplatePath('minimal.txt') lookup = DummyLookup() diff --git a/pyramid/tests/test_chameleon_zpt.py b/pyramid/tests/test_chameleon_zpt.py index 5d197dac4..37538e83e 100644 --- a/pyramid/tests/test_chameleon_zpt.py +++ b/pyramid/tests/test_chameleon_zpt.py @@ -1,7 +1,6 @@ import sys import unittest -from pyramid.testing import skip_on from pyramid import testing from pyramid.compat import text_type @@ -50,7 +49,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): from pyramid.interfaces import ITemplateRenderer verifyClass(ITemplateRenderer, self._getTargetClass()) - @skip_on('java') def test_call(self): minimal = self._getTemplatePath('minimal.pt') lookup = DummyLookup() @@ -60,7 +58,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): self.assertEqual(result.rstrip('\n'), '
\n
') - @skip_on('java') def test_template_reified(self): minimal = self._getTemplatePath('minimal.pt') lookup = DummyLookup() @@ -69,7 +66,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template, instance.__dict__['template']) - @skip_on('java') def test_template_with_ichameleon_translate(self): minimal = self._getTemplatePath('minimal.pt') lookup = DummyLookup() @@ -78,7 +74,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template.translate, lookup.translate) - @skip_on('java') def test_template_with_debug_templates(self): minimal = self._getTemplatePath('minimal.pt') lookup = DummyLookup() @@ -88,7 +83,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template.debug, True) - @skip_on('java') def test_template_without_debug_templates(self): minimal = self._getTemplatePath('minimal.pt') lookup = DummyLookup() @@ -98,7 +92,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template.debug, False) - @skip_on('java') def test_template_with_reload_templates(self): minimal = self._getTemplatePath('minimal.pt') lookup = DummyLookup() @@ -108,7 +101,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template.auto_reload, True) - @skip_on('java') def test_template_without_reload_templates(self): minimal = self._getTemplatePath('minimal.pt') lookup = DummyLookup() @@ -118,14 +110,12 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): template = instance.template self.assertEqual(template.auto_reload, False) - @skip_on('java') def test_call_with_nondict_value(self): minimal = self._getTemplatePath('minimal.pt') lookup = DummyLookup() instance = self._makeOne(minimal, lookup) self.assertRaises(ValueError, instance, None, {}) - @skip_on('java') def test_implementation(self): minimal = self._getTemplatePath('minimal.pt') lookup = DummyLookup() -- cgit v1.2.3 From 684fd22755f5ffd98b5629c63bc07a23c2edaf4a Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 15 Sep 2012 18:35:22 -0400 Subject: use with statement to acquire/release thread locks --- pyramid/mako_templating.py | 9 ++++----- pyramid/renderers.py | 18 +++++------------- pyramid/scripts/pserve.py | 8 ++------ 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/pyramid/mako_templating.py b/pyramid/mako_templating.py index 2b09e8d45..5d09cad01 100644 --- a/pyramid/mako_templating.py +++ b/pyramid/mako_templating.py @@ -95,7 +95,9 @@ class MakoRendererFactoryHelper(object): r'(?:\#(?P[\w_]+))?' r'(\.(?P.*))' ) - asset, defname, ext = p.match(info.name).group('asset', 'defname', 'ext') + asset, defname, ext = p.match(info.name).group( + 'asset', 'defname', 'ext' + ) path = '%s.%s' % (asset, ext) registry = info.registry settings = info.settings @@ -154,12 +156,9 @@ class MakoRendererFactoryHelper(object): preprocessor=preprocessor ) - registry_lock.acquire() - try: + with registry_lock: registry.registerUtility(lookup, IMakoLookup, name=settings_prefix) - finally: - registry_lock.release() return MakoLookupTemplateRenderer(path, defname, lookup) diff --git a/pyramid/renderers.py b/pyramid/renderers.py index fe9df33d1..3252c2c93 100644 --- a/pyramid/renderers.py +++ b/pyramid/renderers.py @@ -429,12 +429,9 @@ class ChameleonRendererLookup(object): if renderer is None: renderer = self.impl(spec, self, macro=None) # cache the template - try: - self.lock.acquire() + with self.lock: registry.registerUtility(renderer, ITemplateRenderer, name=spec) - finally: - self.lock.release() else: # spec is a package:relpath asset spec renderer = registry.queryUtility(ITemplateRenderer, name=spec) @@ -445,7 +442,8 @@ class ChameleonRendererLookup(object): r'(\.(?P.*))' ) asset, macro, ext = p.match(spec).group( - 'asset', 'defname', 'ext') + 'asset', 'defname', 'ext' + ) spec = '%s.%s' % (asset, ext) try: package_name, filename = spec.split(':', 1) @@ -463,12 +461,9 @@ class ChameleonRendererLookup(object): settings = info.settings if not settings.get('reload_assets'): # cache the template - self.lock.acquire() - try: + with self.lock: registry.registerUtility(renderer, ITemplateRenderer, name=spec) - finally: - self.lock.release() return renderer @@ -479,11 +474,8 @@ def template_renderer_factory(info, impl, lock=registry_lock): lookup = registry.queryUtility(IChameleonLookup, name=info.type) if lookup is None: lookup = ChameleonRendererLookup(impl, registry) - lock.acquire() - try: + with lock: registry.registerUtility(lookup, IChameleonLookup, name=info.type) - finally: - lock.release() return lookup(info) @implementer(IRendererInfo) diff --git a/pyramid/scripts/pserve.py b/pyramid/scripts/pserve.py index ea2a4ae09..9fbf0729a 100644 --- a/pyramid/scripts/pserve.py +++ b/pyramid/scripts/pserve.py @@ -583,12 +583,8 @@ class LazyWriter(object): def open(self): if self.fileobj is None: - self.lock.acquire() - try: - if self.fileobj is None: - self.fileobj = open(self.filename, self.mode) - finally: - self.lock.release() + with self.lock: + self.fileobj = open(self.filename, self.mode) return self.fileobj def close(self): -- cgit v1.2.3 From 07cb8f0e112642a6a40127232ddc06125a73750e Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 15 Sep 2012 18:58:45 -0400 Subject: add pyramid.decorator.reify as an API. Closes #682 --- CHANGES.txt | 7 ++++++- TODO.txt | 3 ++- docs/api.rst | 1 + docs/api/decorator.rst | 9 +++++++++ pyramid/decorator.py | 28 +++++++++++++++++++++++++--- pyramid/testing.py | 2 +- 6 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 docs/api/decorator.rst diff --git a/CHANGES.txt b/CHANGES.txt index 47f51575c..94c331cef 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -160,6 +160,9 @@ Features - ``request.context`` of environment request during ``bootstrap`` is now the root object if a context isn't already set on a provided request. +- The ``pyramid.decorator.reify`` function is now an API, and was added to + the API documentation. + Deprecations ------------ @@ -250,7 +253,9 @@ Documentation ------------- - Added an "Upgrading Pyramid" chapter to the narrative documentation. It - describes how to cope with deprecations and removals of Pyramid APIs. + describes how to cope with deprecations and removals of Pyramid APIs and + how to show Pyramid-generated deprecation warnings while running tests and + while running a server. Dependencies ------------ diff --git a/TODO.txt b/TODO.txt index a13433f54..202d1afbb 100644 --- a/TODO.txt +++ b/TODO.txt @@ -143,7 +143,8 @@ Future original dict (after ``__getattr__`` deprecation period, it was deprecated in 1.2). -- 1.5: Remove ``pyramid.requests.DeprecatedRequestMethodsMixin``. +- 1.5: Remove ``pyramid.requests.DeprecatedRequestMethodsMixin`` and code in + renderers module that looks for _response_content_type, et. al. - 1.5: Maybe? deprecate set_request_property in favor of pointing people at add_request_method, schedule removal for 1.8? diff --git a/docs/api.rst b/docs/api.rst index e33fd6a74..9e540b49b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -12,6 +12,7 @@ documentation is organized alphabetically by module name. api/authentication api/compat api/config + api/decorator api/events api/exceptions api/httpexceptions diff --git a/docs/api/decorator.rst b/docs/api/decorator.rst new file mode 100644 index 000000000..35d9131df --- /dev/null +++ b/docs/api/decorator.rst @@ -0,0 +1,9 @@ +.. _decorator_module: + +:mod:`pyramid.decorator` +-------------------------- + +.. automodule:: pyramid.decorator + +.. autofunction:: reify + diff --git a/pyramid/decorator.py b/pyramid/decorator.py index 98d7b36b5..82d2b1280 100644 --- a/pyramid/decorator.py +++ b/pyramid/decorator.py @@ -1,9 +1,31 @@ class reify(object): + """ Use as a class method decorator. It operates almost exactly like the + Python ``@property`` decorator, but it puts the result of the method it + decorates into the instance dict after the first call, effectively + replacing the function it decorates with an instance variable. It is, in + Python parlance, a non-data descriptor. An example: - """ Put the result of a method which uses this (non-data) - descriptor decorator in the instance dict after the first call, - effectively replacing the decorator with an instance variable.""" + .. code-block:: python + class Foo(object): + @reify + def jammy(self): + print 'jammy called' + return 1 + + And usage of Foo: + + .. code-block:: text + + >>> f = Foo() + >>> v = f.jammy + 'jammy called' + >>> print v + 1 + >>> f.jammy + 1 + >>> # jammy func not called the second time; it replaced itself with 1 + """ def __init__(self, wrapped): self.wrapped = wrapped try: diff --git a/pyramid/testing.py b/pyramid/testing.py index 750effb83..e091bac4f 100644 --- a/pyramid/testing.py +++ b/pyramid/testing.py @@ -293,7 +293,7 @@ class DummyRequest(DeprecatedRequestMethodsMixin, URLMethodsMixin, request. For example, by default, the DummyRequest ``GET`` and ``POST`` attributes are of type ``dict``, unlike a normal Request's GET and POST, which are of type ``MultiDict``. If your code uses the features of - MultiDict, you should either use a"real" :class:`pyramid.request.Request` + MultiDict, you should either use a real :class:`pyramid.request.Request` or adapt your DummyRequest by replacing the attributes with ``MultiDict`` instances. -- cgit v1.2.3 From d246597b50226456fd350d44be8af0cf6831cd15 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 15 Sep 2012 21:14:54 -0400 Subject: reclassify bug as feature --- CHANGES.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index da2399d9b..851941ff6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -33,11 +33,6 @@ Bug Fixes differ in the case ('text/html' vs. 'text/HTML') will now raise an error. https://github.com/Pylons/pyramid/pull/620 -- Configurator.add_directive now accepts arbitrary callables like partials or - objects implementing ``__call__`` which dont have ``__name__`` and - ``__doc__`` attributes. See https://github.com/Pylons/pyramid/issues/621 - and https://github.com/Pylons/pyramid/pull/647. - - Forward-port from 1.3 branch: when registering multiple views with an ``accept`` predicate in a Pyramid application runing under Python 3, you might have received a ``TypeError: unorderable types: function() < @@ -46,6 +41,11 @@ Bug Fixes Features -------- +- Configurator.add_directive now accepts arbitrary callables like partials or + objects implementing ``__call__`` which dont have ``__name__`` and + ``__doc__`` attributes. See https://github.com/Pylons/pyramid/issues/621 + and https://github.com/Pylons/pyramid/pull/647. + - Third-party custom view, route, and subscriber predicates can now be added for use by view authors via ``pyramid.config.Configurator.add_view_predicate``, -- cgit v1.2.3 From 6f5401a470f51c372eb6f996592487fdd2a4bb03 Mon Sep 17 00:00:00 2001 From: Blaise Laflamme Date: Sun, 16 Sep 2012 00:24:20 -0300 Subject: fixed git submodule update for docs --- docs/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index e4a325022..a66f93d60 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -25,7 +25,7 @@ help: clean: -rm -rf _build/* -html: _themes +html: themes mkdir -p _build/html _build/doctrees $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html @echo @@ -47,7 +47,7 @@ pickle: web: pickle -htmlhelp: _themes +htmlhelp: themes mkdir -p _build/htmlhelp _build/doctrees $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp @echo @@ -85,4 +85,4 @@ epub: @echo "Build finished. The epub file is in _build/epub." _themes: - git submodule update --init + cd ..; git submodule update --init --recursive; cd docs; -- 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 --- CHANGES.txt | 11 ++++------- docs/index.rst | 1 + docs/narr/upgrading.rst | 2 ++ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 851941ff6..6c210600c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -104,13 +104,13 @@ Features and ``HTTPMovedPermanently`` exceptions, so these can be caught by the NotFound view (and other exception views). -- The Mako renderer now accepts a def name in an asset spect. When the def +- The Mako renderer now supports a def name in an asset spec. When the def name is present in the asset spec, the system will render the template def within the template and will return the result. An example asset spec is ``package:path/to/template#defname.mako``. This will render the def named - ``defname`` inside the ``template.pt`` package instead of rendering the - entire template. The old way of returning a tuple from the view is - supported for backward compatibility, ('defname', {}). + ``defname`` inside the ``template.mako`` template instead of rendering the + entire template. The old way of returning a tuple in the form + ``('defname', {})`` from the view is supported for backward compatibility, - The Chameleon ZPT renderer now accepts a macro name in an asset spec. When the macro name is present in the asset spec, the system will render the @@ -150,9 +150,6 @@ Features - Request properties and methods added via ``config.set_request_property`` or ``config.add_request_method`` are now available to tweens. -- Request properties and methods added via ``config.set_request_property`` or - ``config.add_request_method`` are now available to tweens. - - Request properties and methods added via ``config.set_request_property`` or ``config.add_request_method`` are now available in the request object returned from ``pyramid.paster.bootstrap``. diff --git a/docs/index.rst b/docs/index.rst index 321fe1fed..4a9b3951b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -37,6 +37,7 @@ What's New .. toctree:: :maxdepth: 1 + whatsnew-1.4 whatsnew-1.3 whatsnew-1.2 whatsnew-1.1 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 fcd7045e051632c6e43227c44ac540d4d655d1dd Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 15 Sep 2012 23:26:01 -0400 Subject: really add whatsnew-1.4 --- docs/whatsnew-1.4.rst | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 docs/whatsnew-1.4.rst diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst new file mode 100644 index 000000000..58a44202c --- /dev/null +++ b/docs/whatsnew-1.4.rst @@ -0,0 +1,250 @@ +What's New In Pyramid 1.4 +========================= + +This article explains the new features in :app:`Pyramid` version 1.4 as +compared to its predecessor, :app:`Pyramid` 1.3. It also documents backwards +incompatibilities between the two versions and deprecations added to +:app:`Pyramid` 1.4, as well as software dependency changes and notable +documentation additions. + +Major Feature Additions +----------------------- + +The major feature additions in Pyramid 1.4 follow. + +Third-Party Predicates +~~~~~~~~~~~~~~~~~~~~~~~ + +- Third-party custom view, route, and subscriber predicates can now be added + for use by view authors via + :meth:`pyramid.config.Configurator.add_view_predicate`, + :meth:`pyramid.config.Configurator.add_route_predicate` and + :meth:`pyramid.config.Configurator.add_subscriber_predicate`. So, for + example, doing this:: + + config.add_view_predicate('abc', my.package.ABCPredicate) + + Might allow a view author to do this in an application that configured that + predicate:: + + @view_config(abc=1) + + Similar features exist for :meth:`pyramid.config.Configurator.add_route`, + and :meth:`pyramid.config.Configurator.add_subscriber`. See + :ref:`registering_thirdparty_predicates` for more information. + +Easy Custom JSON Serialization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Views can now return custom objects which will be serialized to JSON by a + JSON renderer by defining a ``__json__`` method on the object's class. This + method should return values natively serializable by ``json.dumps`` (such + as ints, lists, dictionaries, strings, and so forth). See + :ref:`json_serializing_custom_objects` for more information. The JSON + renderer now also allows for the definition of custom type adapters to + convert unknown objects to JSON serializations, in case you can't add a + ``__json__`` method to returned objects. + +Partial Mako and Chameleon Template Renderings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- The Mako renderer now supports using a def name in an asset spec. When the + def name is present in the asset spec, the system will render the template + named def within the template instead of rendering the entire template. An + example asset spec which names a def is + ``package:path/to/template#defname.mako``. This will render the def named + ``defname`` inside the ``template.mako`` template instead of rendering the + entire template. The old way of returning a tuple in the form + ``('defname', {})`` from the view is supported for backward compatibility. + +- The Chameleon ZPT renderer now supports using a macro name in an asset + spec. When the macro name is present in the asset spec, the system will + render the macro listed as a ``define-macro`` and return the result instead + of rendering the entire template. An example asset spec: + ``package:path/to/template#macroname.pt``. This will render the macro + defined as ``macroname`` within the ``template.pt`` template instead of the + entire templae. + +Minor Feature Additions +----------------------- + +- :meth:`pyramid.config.Configurator.add_directive` now accepts arbitrary + callables like partials or objects implementing ``__call__`` which dont + have ``__name__`` and ``__doc__`` attributes. See + https://github.com/Pylons/pyramid/issues/621 and + https://github.com/Pylons/pyramid/pull/647. + +- As of this release, the ``request_method`` view/route predicate, when used, + will also imply that ``HEAD`` is implied when you use ``GET``. For + example, using ``@view_config(request_method='GET')`` is equivalent to + using ``@view_config(request_method=('GET', 'HEAD'))``. Using + ``@view_config(request_method=('GET', 'POST')`` is equivalent to using + ``@view_config(request_method=('GET', 'HEAD', 'POST')``. This is because + HEAD is a variant of GET that omits the body, and WebOb has special support + to return an empty body when a HEAD is used. + +- :meth:`pyramid.config.Configurator.add_request_method` has been introduced + to support extending request objects with arbitrary callables. This method + expands on the previous + :meth:`pyramid.config.Configurator.set_request_property` by supporting + methods as well as properties. This method causes less code to be executed + at request construction time than + :meth:`~pyramid.config.Configurator.set_request_property`. + +- The static view machinery now raises rather than returns + :class:`pyramid.httpexceptions.HTTPNotFound` and + :class:`pyramid.httpexceptions.HTTPMovedPermanently` exceptions, so these can + be caught by the notfound view (and other exception views). + +- When there is a predicate mismatch exception (seen when no view matches for + a given request due to predicates not working), the exception now contains + a textual description of the predicate which didn't match. + +- An :meth:`pyramid.config.Configurator.add_permission` directive method was + added to the Configurator. This directive registers a free-standing + permission introspectable into the Pyramid introspection system. + Frameworks built atop Pyramid can thus use the the ``permissions`` + introspectable category data to build a comprehensive list of permissions + supported by a running system. Before this method was added, permissions + were already registered in this introspectable category as a side effect of + naming them in an :meth:`pyramid.config.Configurator.add_view` call, this + method just makes it possible to arrange for a permission to be put into + the ``permissions`` introspectable category without naming it along with an + associated view. Here's an example of usage of ``add_permission``:: + + config = Configurator() + config.add_permission('view') + +- The :func:`pyramid.session.UnencryptedCookieSessionFactoryConfig` function + now accepts ``signed_serialize`` and ``signed_deserialize`` hooks which may + be used to influence how the sessions are marshalled (by default this is + done with HMAC+pickle). + +- :class:`pyramid.testing.DummyRequest` now supports methods supplied by the + ``pyramid.util.InstancePropertyMixin`` class such as ``set_property``. + +- Request properties and methods added via + :meth:`pyramid.config.Configurator.set_request_property` or + :meth:`pyramid.config.Configurator.add_request_method` are now available to + tweens. + +- Request properties and methods added via + :meth:`pyramid.config.Configurator.set_request_property` or + :meth:`pyramid.config.Configurator.add_request_method` are now available + in the request object returned from :func:`pyramid.paster.bootstrap`. + +- ``request.context`` of environment request during + :func:`pyramid.paster.bootstrap` is now the root object if a context isn't + already set on a provided request. + +- :class:`pyramid.decorator.reify` is now an API, and was added to + the API documentation. + +- Added the :func:`pyramid.testing.testConfig` context manager, which can be + used to generate a configurator in a test, e.g. ``with + testing.testConfig(...):``. + +Backwards Incompatibilities +--------------------------- + +- The Pyramid router no longer adds the values ``bfg.routes.route`` or + ``bfg.routes.matchdict`` to the request's WSGI environment dictionary. + These values were docs-deprecated in ``repoze.bfg`` 1.0 (effectively seven + minor releases ago). If your code depended on these values, use + request.matched_route and request.matchdict instead. + +- It is no longer possible to pass an environ dictionary directly to + ``pyramid.traversal.ResourceTreeTraverser.__call__`` (aka + ``ModelGraphTraverser.__call__``). Instead, you must pass a request + object. Passing an environment instead of a request has generated a + deprecation warning since Pyramid 1.1. + +- Pyramid will no longer work properly if you use the + ``webob.request.LegacyRequest`` as a request factory. Instances of the + LegacyRequest class have a ``request.path_info`` which return a string. + This Pyramid release assumes that ``request.path_info`` will + unconditionally be Unicode. + +- The functions from ``pyramid.chameleon_zpt`` and ``pyramid.chameleon_text`` + named ``get_renderer``, ``get_template``, ``render_template``, and + ``render_template_to_response`` have been removed. These have issued a + deprecation warning upon import since Pyramid 1.0. Use + :func:`pyramid.renderers.get_renderer`, + ``pyramid.renderers.get_renderer().implementation()``, + :func:`pyramid.renderers.render` or + :func:`pyramid.renderers.render_to_response` respectively instead of these + functions. + +- The ``pyramid.configuration`` module was removed. It had been deprecated + since Pyramid 1.0 and printed a deprecation warning upon its use. Use + :mod:`pyramid.config` instead. + +- The ``pyramid.paster.PyramidTemplate`` API was removed. It had been + deprecated since Pyramid 1.1 and issued a warning on import. If your code + depended on this, adjust your code to import + :class:`pyramid.scaffolds.PyramidTemplate` instead. + +- The ``pyramid.settings.get_settings()`` API was removed. It had been + printing a deprecation warning since Pyramid 1.0. If your code depended on + this API, use ``pyramid.threadlocal.get_current_registry().settings`` + instead or use the ``settings`` attribute of the registry available from + the request (``request.registry.settings``). + +- These APIs from the ``pyramid.testing`` module were removed. They have + been printing deprecation warnings since Pyramid 1.0: + + * ``registerDummySecurityPolicy``, use + :meth:`pyramid.config.Configurator.testing_securitypolicy` instead. + + * ``registerResources`` (aka ``registerModels``), use + :meth:`pyramid.config.Configurator.testing_resources` instead. + + * ``registerEventListener``, use + :meth:`pyramid.config.Configurator.testing_add_subscriber` instead. + + * ``registerTemplateRenderer`` (aka `registerDummyRenderer``), use + :meth:`pyramid.config.Configurator.testing_add_template` instead. + + * ``registerView``, use :meth:`pyramid.config.Configurator.add_view` instead. + + * ``registerUtility``, use + :meth:`pyramid.config.Configurator.registry.registerUtility` instead. + + * ``registerAdapter``, use + :meth:`pyramid.config.Configurator.registry.registerAdapter` instead. + + * ``registerSubscriber``, use + :meth:`pyramid.config.Configurator.add_subscriber` instead. + + * ``registerRoute``, use + :meth:`pyramid.config.Configurator.add_route` instead. + + * ``registerSettings``, use + :meth:`pyramid.config.Configurator.add_settings` instead. + +Deprecations +------------ + +- The :meth:`pyramid.config.Configurator.set_request_property` directive has + been documentation-deprecated. The method remains usable but the more + featureful :meth:`pyramid.config.Configurator.add_request_method` should be + used in its place (it has all of the same capabilities but can also extend + the request object with methods). + +Documentation Enhancements +-------------------------- + +- Added an :ref:`upgrading_chapter` chapter to the narrative documentation. + It describes how to cope with deprecations and removals of Pyramid APIs and + how to show Pyramid-generated deprecation warnings while running tests and + while running a server. + +- Many cleanups and improvements to narrative and API docs. + +Dependency Changes +------------------ + +- Pyramid now requires WebOb 1.2b3+ (the prior Pyramid release only relied on + 1.2dev+). This is to ensure that we obtain a version of WebOb that returns + ``request.path_info`` as text. + -- cgit v1.2.3 From a9e278e5e0cb4f5fb290c296bed55eee510d0d37 Mon Sep 17 00:00:00 2001 From: Blaise Laflamme Date: Sun, 16 Sep 2012 00:37:26 -0300 Subject: fixed typo --- docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index a66f93d60..c98fdc65e 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -84,5 +84,5 @@ epub: @echo @echo "Build finished. The epub file is in _build/epub." -_themes: +themes: cd ..; git submodule update --init --recursive; cd docs; -- cgit v1.2.3 From dd9859fb7e93875f246059f2bc6b18cb10dbeff9 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 01:48:30 -0400 Subject: sketch out a subrequest API --- pyramid/router.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/pyramid/router.py b/pyramid/router.py index 0cbe00f3a..ffc67eae5 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -53,6 +53,7 @@ class Router(object): tweens = q(ITweens) if tweens is None: tweens = excview_tween_factory + self.orig_handle_request = self.handle_request self.handle_request = tweens(self.handle_request, registry) self.root_policy = self.root_factory # b/w compat self.registry = registry @@ -161,35 +162,35 @@ class Router(object): return response - def __call__(self, environ, start_response): - """ - Accept ``environ`` and ``start_response``; create a - :term:`request` and route the request to a :app:`Pyramid` - view based on introspection of :term:`view configuration` - within the application registry; call ``start_response`` and - return an iterable. - """ + def subrequest(self, request, use_tweens=False): registry = self.registry has_listeners = self.registry.has_listeners notify = self.registry.notify - request = self.request_factory(environ) threadlocals = {'registry':registry, 'request':request} manager = self.threadlocal_manager manager.push(threadlocals) request.registry = registry + request.subrequest = self.subrequest + if use_tweens: + handle_request = self.handle_request + else: + handle_request = self.orig_handle_request try: try: extensions = self.request_extensions if extensions is not None: request._set_extensions(extensions) - response = self.handle_request(request) + response = handle_request(request) has_listeners and notify(NewResponse(request, response)) if request.response_callbacks: request._process_response_callbacks(response) - return response(request.environ, start_response) + # XXX before subrequest factoring, the below line + # actually invoked Response.__call__, passing it + # the start_response + return response finally: if request.finished_callbacks: @@ -197,3 +198,16 @@ class Router(object): finally: manager.pop() + + def __call__(self, environ, start_response): + """ + Accept ``environ`` and ``start_response``; create a + :term:`request` and route the request to a :app:`Pyramid` + view based on introspection of :term:`view configuration` + within the application registry; call ``start_response`` and + return an iterable. + """ + request = self.request_factory(environ) + response = self.subrequest(request, use_tweens=True) + return response(request.environ, start_response) + -- cgit v1.2.3 From 277b2af26871a4d84730b6d3e38fbaa2f4102823 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 02:33:39 -0400 Subject: add docs --- docs/api/request.rst | 43 +++++++++++++++++++++++++++++++++++++++++++ pyramid/router.py | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/docs/api/request.rst b/docs/api/request.rst index 1112ea069..5e52cfd50 100644 --- a/docs/api/request.rst +++ b/docs/api/request.rst @@ -161,6 +161,49 @@ request, the value of this attribute will be ``None``. See :ref:`matched_route`. + .. method:: subrequest(request, use_tweens=False) + + Obtain a response object from the Pyramid application based on + information in the ``request`` object provided. The ``request`` object + 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. This isn't *actually* a method of the Request object; it's + a callable added when the Pyramid router is invoked, or when a + subrequest is invoked. This 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) + + - Adds a ``registry`` attribute (the current Pyramid registry) and a + ``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 + :meth:`~pyramid.config.Configurator.set_request_property`) on the + request it's passed. + + - 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 + request's lifetime if a response is obtained from the Pyramid + application. + + - Calls any :term:`finished callback` functions defined within the + request's lifetime. + .. automethod:: add_response_callback .. automethod:: add_finished_callback diff --git a/pyramid/router.py b/pyramid/router.py index ffc67eae5..380c9fe30 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -163,6 +163,45 @@ class Router(object): return response def subrequest(self, request, use_tweens=False): + """ + Obtain a response object from the Pyramid application based on + information in the ``request`` object provided. The ``request`` + object 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. This 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) + + - 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 + request it's passed. + + - 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 + request's lifetime if a response is obtained from the Pyramid + application. + + - Calls any :term:`finished callback` functions defined within the + request's lifetime. + """ registry = self.registry has_listeners = self.registry.has_listeners notify = self.registry.notify -- 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 --- CHANGES.txt | 6 ++ docs/api/request.rst | 6 ++ docs/index.rst | 1 + docs/latexindex.rst | 1 + docs/narr/subrequest.rst | 143 +++++++++++++++++++++++++++ docs/whatsnew-1.4.rst | 10 ++ pyramid/router.py | 4 +- pyramid/tests/pkgs/subrequestapp/__init__.py | 20 ++++ pyramid/tests/test_integration.py | 55 +++++++---- 9 files changed, 225 insertions(+), 21 deletions(-) create mode 100644 docs/narr/subrequest.rst create mode 100644 pyramid/tests/pkgs/subrequestapp/__init__.py diff --git a/CHANGES.txt b/CHANGES.txt index 6c210600c..6736f6d3e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -163,6 +163,9 @@ Features - Added the ``pyramid.testing.testConfig`` context manager, which can be used to generate a configurator in a test, e.g. ``with testing.testConfig(...):``. +- Users can now invoke a subrequest from within view code using the + ``request.subrequest`` API. + Deprecations ------------ @@ -257,6 +260,9 @@ Documentation how to show Pyramid-generated deprecation warnings while running tests and while running a server. +- Added a "Invoking a Subrequest" chapter to the documentation. It describes + how to use the new ``request.subrequest`` API. + Dependencies ------------ diff --git a/docs/api/request.rst b/docs/api/request.rst index 5e52cfd50..603807abe 100644 --- a/docs/api/request.rst +++ b/docs/api/request.rst @@ -163,6 +163,10 @@ .. method:: subrequest(request, use_tweens=False) + .. warning:: + + This API was added in Pyramid 1.4a1. + Obtain a response object from the Pyramid application based on information in the ``request`` object provided. The ``request`` object must be an object that implements the Pyramid request interface (such @@ -204,6 +208,8 @@ - Calls any :term:`finished callback` functions defined within the request's lifetime. + See also :ref:`subrequest_chapter`. + .. automethod:: add_response_callback .. automethod:: add_finished_callback diff --git a/docs/index.rst b/docs/index.rst index 4a9b3951b..faf8258c1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -83,6 +83,7 @@ Narrative documentation in chapter form explaining how to use narr/traversal narr/security narr/hybrid + narr/subrequest narr/hooks narr/introspector narr/extending diff --git a/docs/latexindex.rst b/docs/latexindex.rst index 604e6e7c6..6bb875f73 100644 --- a/docs/latexindex.rst +++ b/docs/latexindex.rst @@ -54,6 +54,7 @@ Narrative Documentation narr/traversal narr/security narr/hybrid + narr/subrequest narr/hooks narr/introspector narr/extending 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. diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst index 58a44202c..70d5f12a7 100644 --- a/docs/whatsnew-1.4.rst +++ b/docs/whatsnew-1.4.rst @@ -65,6 +65,14 @@ Partial Mako and Chameleon Template Renderings defined as ``macroname`` within the ``template.pt`` template instead of the entire templae. +Subrequest Support +~~~~~~~~~~~~~~~~~~ + +- Developers may invoke a subrequest by using the + :meth:`pyramid.request.Request.subrequest` API. This allows a developer to + obtain a response from one view callable by issuing a subrequest from within + a different view callable. + Minor Feature Additions ----------------------- @@ -239,6 +247,8 @@ Documentation Enhancements how to show Pyramid-generated deprecation warnings while running tests and while running a server. +- Added a :ref:`subrequest_chapter` chapter to the narrative documentation. + - Many cleanups and improvements to narrative and API docs. Dependency Changes diff --git a/pyramid/router.py b/pyramid/router.py index 380c9fe30..75bf70f07 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -201,7 +201,9 @@ class Router(object): - Calls any :term:`finished callback` functions defined within the request's lifetime. - """ + + See also :ref:`subrequest_chapter`. + """ registry = self.registry has_listeners = self.registry.has_listeners notify = self.registry.notify diff --git a/pyramid/tests/pkgs/subrequestapp/__init__.py b/pyramid/tests/pkgs/subrequestapp/__init__.py new file mode 100644 index 000000000..c59993fb7 --- /dev/null +++ b/pyramid/tests/pkgs/subrequestapp/__init__.py @@ -0,0 +1,20 @@ +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 + +def 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') + return config + diff --git a/pyramid/tests/test_integration.py b/pyramid/tests/test_integration.py index 590ba0760..3f26791de 100644 --- a/pyramid/tests/test_integration.py +++ b/pyramid/tests/test_integration.py @@ -578,26 +578,41 @@ class WSGIApp2AppTest(unittest.TestCase): res = self.testapp.get('/hello', status=200) self.assertTrue(b'Hello' in res.body) -if os.name != 'java': # uses chameleon - class RendererScanAppTest(IntegrationBase, unittest.TestCase): - package = 'pyramid.tests.pkgs.rendererscanapp' - def test_root(self): - res = self.testapp.get('/one', status=200) - self.assertTrue(b'One!' in res.body) - - def test_two(self): - res = self.testapp.get('/two', status=200) - self.assertTrue(b'Two!' in res.body) - - def test_rescan(self): - self.config.scan('pyramid.tests.pkgs.rendererscanapp') - app = self.config.make_wsgi_app() - from webtest import TestApp - testapp = TestApp(app) - res = testapp.get('/one', status=200) - self.assertTrue(b'One!' in res.body) - res = testapp.get('/two', status=200) - self.assertTrue(b'Two!' in res.body) +class SubrequestAppTest(unittest.TestCase): + def setUp(self): + from pyramid.tests.pkgs.subrequestapp import main + config = main() + app = config.make_wsgi_app() + from webtest import TestApp + self.testapp = TestApp(app) + self.config = config + + def tearDown(self): + self.config.end() + + def test_it(self): + res = self.testapp.get('/view_one', status=200) + self.assertTrue(b'This came from view_two' in res.body) + +class RendererScanAppTest(IntegrationBase, unittest.TestCase): + package = 'pyramid.tests.pkgs.rendererscanapp' + def test_root(self): + res = self.testapp.get('/one', status=200) + self.assertTrue(b'One!' in res.body) + + def test_two(self): + res = self.testapp.get('/two', status=200) + self.assertTrue(b'Two!' in res.body) + + def test_rescan(self): + self.config.scan('pyramid.tests.pkgs.rendererscanapp') + app = self.config.make_wsgi_app() + from webtest import TestApp + testapp = TestApp(app) + res = testapp.get('/one', status=200) + self.assertTrue(b'One!' in res.body) + res = testapp.get('/two', status=200) + self.assertTrue(b'Two!' in res.body) class DummyContext(object): pass -- 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(-) 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(+) 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(-) 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 --- TODO.txt | 9 --------- docs/narr/subrequest.rst | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/TODO.txt b/TODO.txt index 202d1afbb..1686c27a2 100644 --- a/TODO.txt +++ b/TODO.txt @@ -82,15 +82,6 @@ Nice-to-Have - Deprecate pyramid.security.view_execution_permitted (it only works for traversal). -- Create a function which performs a recursive request. - -- Create a ``render_view`` that works by using config.derive_view against an - existing view callable instead of querying the registry (some sort of API - for rendering a view callable object to a response from within another view - callable). Possible idea: have config.add_view mark up the - function/method/class like @view_config does, then use the attached info to - derive a view callable whenever called via some API. - - Provide a ``has_view`` function. - Update App engine chapter with less creaky directions. 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(-) 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 --- CHANGES.txt | 12 +++++-- docs/api/request.rst | 4 +-- docs/narr/subrequest.rst | 53 ++++++++++++++-------------- docs/whatsnew-1.4.rst | 12 +++++-- pyramid/router.py | 13 +++---- pyramid/tests/pkgs/subrequestapp/__init__.py | 2 +- 6 files changed, 53 insertions(+), 43 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 6736f6d3e..66ac42136 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -163,8 +163,8 @@ Features - Added the ``pyramid.testing.testConfig`` context manager, which can be used to generate a configurator in a test, e.g. ``with testing.testConfig(...):``. -- Users can now invoke a subrequest from within view code using the - ``request.subrequest`` API. +- Users can now invoke a subrequest from within view code using a new + ``request.invoke_subrequest`` API. Deprecations ------------ @@ -252,6 +252,12 @@ Backwards Incompatibilities * ``registerSettings``, use ``pyramid.config.Configurator.add_settings`` instead. +- In Pyramid 1.3 and previous, the ``__call__`` method of a Response object + was invoked before any finished callbacks were executed. As of this + release, the ``__call__`` method of a Response object is invoked *after* + finished callbacks are executed. This is in support of the + ``request.invoke_subrequest`` feature. + Documentation ------------- @@ -261,7 +267,7 @@ Documentation while running a server. - Added a "Invoking a Subrequest" chapter to the documentation. It describes - how to use the new ``request.subrequest`` API. + how to use the new ``request.invoke_subrequest`` API. Dependencies ------------ diff --git a/docs/api/request.rst b/docs/api/request.rst index 603807abe..1718d0743 100644 --- a/docs/api/request.rst +++ b/docs/api/request.rst @@ -161,7 +161,7 @@ request, the value of this attribute will be ``None``. See :ref:`matched_route`. - .. method:: subrequest(request, use_tweens=False) + .. method:: invoke_subrequest(request, use_tweens=False) .. warning:: @@ -184,7 +184,7 @@ request) - Adds a ``registry`` attribute (the current Pyramid registry) and a - ``subrequest`` attribute (a callable) to the request object it's + ``invoke_subrequest`` attribute (a callable) to the request object it's handed. - sets request extensions (such as those added via 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. diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst index 70d5f12a7..8e333bf5d 100644 --- a/docs/whatsnew-1.4.rst +++ b/docs/whatsnew-1.4.rst @@ -69,9 +69,9 @@ Subrequest Support ~~~~~~~~~~~~~~~~~~ - Developers may invoke a subrequest by using the - :meth:`pyramid.request.Request.subrequest` API. This allows a developer to - obtain a response from one view callable by issuing a subrequest from within - a different view callable. + :meth:`pyramid.request.Request.invoke_subrequest` API. This allows a + developer to obtain a response from one view callable by issuing a subrequest + from within a different view callable. Minor Feature Additions ----------------------- @@ -230,6 +230,12 @@ Backwards Incompatibilities * ``registerSettings``, use :meth:`pyramid.config.Configurator.add_settings` instead. +- In Pyramid 1.3 and previous, the ``__call__`` method of a Response object + returned by a view was invoked before any finished callbacks were executed. + As of this release, the ``__call__`` method of a Response object is invoked + *after* finished callbacks are executed. This is in support of the + :meth:`pyramid.request.Request.invoke_subrequest` feature. + Deprecations ------------ diff --git a/pyramid/router.py b/pyramid/router.py index 75bf70f07..18624376c 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -162,7 +162,7 @@ class Router(object): return response - def subrequest(self, request, use_tweens=False): + def invoke_subrequest(self, request, use_tweens=False): """ Obtain a response object from the Pyramid application based on information in the ``request`` object provided. The ``request`` @@ -178,8 +178,8 @@ class Router(object): :func:`~pyramid.threadlocal.get_current_registry` work during a 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 @@ -211,7 +211,7 @@ class Router(object): manager = self.threadlocal_manager manager.push(threadlocals) request.registry = registry - request.subrequest = self.subrequest + request.invoke_subrequest = self.invoke_subrequest if use_tweens: handle_request = self.handle_request else: @@ -228,9 +228,6 @@ class Router(object): if request.response_callbacks: request._process_response_callbacks(response) - # XXX before subrequest factoring, the below line - # actually invoked Response.__call__, passing it - # the start_response return response finally: @@ -249,6 +246,6 @@ class Router(object): return an iterable. """ request = self.request_factory(environ) - response = self.subrequest(request, use_tweens=True) + response = self.invoke_subrequest(request, use_tweens=True) return response(request.environ, start_response) diff --git a/pyramid/tests/pkgs/subrequestapp/__init__.py b/pyramid/tests/pkgs/subrequestapp/__init__.py index c59993fb7..06a4d9d16 100644 --- a/pyramid/tests/pkgs/subrequestapp/__init__.py +++ b/pyramid/tests/pkgs/subrequestapp/__init__.py @@ -3,7 +3,7 @@ from pyramid.request import Request def view_one(request): subreq = Request.blank('/view_two') - response = request.subrequest(subreq) + response = request.invoke_subrequest(subreq) return response def view_two(request): -- cgit v1.2.3 From 355ed0f0063d37cddfc3d315c7a32cb9e9a2987c Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 03:56:42 -0400 Subject: pointer --- docs/whatsnew-1.4.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst index 8e333bf5d..f57178db1 100644 --- a/docs/whatsnew-1.4.rst +++ b/docs/whatsnew-1.4.rst @@ -71,7 +71,8 @@ Subrequest Support - Developers may invoke a subrequest by using the :meth:`pyramid.request.Request.invoke_subrequest` API. This allows a developer to obtain a response from one view callable by issuing a subrequest - from within a different view callable. + from within a different view callable. See :ref:`subrequest_chapter` for + more information. Minor Feature Additions ----------------------- -- cgit v1.2.3 From b60fe723898b6c9d16e69c0ea4bb4ced4bd4f55c Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 04:02:04 -0400 Subject: fix py3 --- pyramid/tests/pkgs/subrequestapp/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyramid/tests/pkgs/subrequestapp/__init__.py b/pyramid/tests/pkgs/subrequestapp/__init__.py index 06a4d9d16..3cc125c50 100644 --- a/pyramid/tests/pkgs/subrequestapp/__init__.py +++ b/pyramid/tests/pkgs/subrequestapp/__init__.py @@ -7,7 +7,7 @@ def view_one(request): return response def view_two(request): - request.response.body = 'This came from view_two' + request.response.body = b'This came from view_two' return request.response def main(): -- cgit v1.2.3 From 5da21f623e0aa71106bd54bf0d199435f003b1d4 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 04:06:37 -0400 Subject: use a string renderer --- pyramid/tests/pkgs/subrequestapp/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyramid/tests/pkgs/subrequestapp/__init__.py b/pyramid/tests/pkgs/subrequestapp/__init__.py index 3cc125c50..92f4bbe68 100644 --- a/pyramid/tests/pkgs/subrequestapp/__init__.py +++ b/pyramid/tests/pkgs/subrequestapp/__init__.py @@ -7,14 +7,13 @@ def view_one(request): return response def view_two(request): - request.response.body = b'This came from view_two' - return request.response + return 'This came from view_two' def 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') + config.add_view(view_two, route_name='two', renderer='string') return config -- 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/api/request.rst | 14 +++-- docs/narr/subrequest.rst | 83 +++++++++++++++++++++++----- pyramid/router.py | 4 +- pyramid/tests/pkgs/subrequestapp/__init__.py | 30 +++++++++- pyramid/tests/test_integration.py | 10 +++- 5 files changed, 118 insertions(+), 23 deletions(-) diff --git a/docs/api/request.rst b/docs/api/request.rst index 1718d0743..8af81cdac 100644 --- a/docs/api/request.rst +++ b/docs/api/request.rst @@ -161,7 +161,7 @@ request, the value of this attribute will be ``None``. See :ref:`matched_route`. - .. method:: invoke_subrequest(request, use_tweens=False) + .. method:: invoke_subrequest(request, use_tweens=True) .. warning:: @@ -174,9 +174,9 @@ ``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. This isn't *actually* a method of the Request object; it's - a callable added when the Pyramid router is invoked, or when a - subrequest is invoked. This function also: + be invoked. + + This function also: - manages the threadlocal stack (so that :func:`~pyramid.threadlocal.get_current_request` and @@ -208,7 +208,11 @@ - Calls any :term:`finished callback` functions defined within the request's lifetime. - See also :ref:`subrequest_chapter`. + ``invoke_subrequest`` isn't *actually* a method of the Request object; + it's a callable added when the Pyramid router is invoked, or when a + subrequest is invoked. This means that it's not available for use on a + request provided by e.g. the ``pshell`` environment. For more + information, see :ref:`subrequest_chapter`. .. automethod:: add_response_callback 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. diff --git a/pyramid/router.py b/pyramid/router.py index 18624376c..8ee826a2c 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -162,7 +162,7 @@ class Router(object): return response - def invoke_subrequest(self, request, use_tweens=False): + def invoke_subrequest(self, request, use_tweens=True): """ Obtain a response object from the Pyramid application based on information in the ``request`` object provided. The ``request`` @@ -212,10 +212,12 @@ class Router(object): manager.push(threadlocals) request.registry = registry request.invoke_subrequest = self.invoke_subrequest + if use_tweens: handle_request = self.handle_request else: handle_request = self.orig_handle_request + try: try: diff --git a/pyramid/tests/pkgs/subrequestapp/__init__.py b/pyramid/tests/pkgs/subrequestapp/__init__.py index 92f4bbe68..dceaa9e45 100644 --- a/pyramid/tests/pkgs/subrequestapp/__init__.py +++ b/pyramid/tests/pkgs/subrequestapp/__init__.py @@ -3,17 +3,45 @@ from pyramid.request import Request def view_one(request): subreq = Request.blank('/view_two') - response = request.invoke_subrequest(subreq) + response = request.invoke_subrequest(subreq, use_tweens=False) return response def view_two(request): return 'This came from view_two' +def view_three(request): + subreq = Request.blank('/view_four') + response = request.invoke_subrequest(subreq, use_tweens=True) + return response + +def view_four(request): + raise ValueError('foo') + +def view_five(request): + subreq = Request.blank('/view_four') + try: + return request.invoke_subrequest(subreq, use_tweens=False) + except ValueError: + request.response.body = b'Value error raised' + return request.response + +def excview(request): + request.response.status_int = 500 + request.response.body = b'Bad stuff happened' + return request.response + def main(): config = Configurator() config.add_route('one', '/view_one') config.add_route('two', '/view_two') + config.add_route('three', '/view_three') + config.add_route('four', '/view_four') + config.add_route('five', '/view_five') + config.add_view(excview, context=Exception) config.add_view(view_one, route_name='one') config.add_view(view_two, route_name='two', renderer='string') + config.add_view(view_three, route_name='three') + config.add_view(view_four, route_name='four') + config.add_view(view_five, route_name='five') return config diff --git a/pyramid/tests/test_integration.py b/pyramid/tests/test_integration.py index 3f26791de..9a8f842aa 100644 --- a/pyramid/tests/test_integration.py +++ b/pyramid/tests/test_integration.py @@ -590,10 +590,18 @@ class SubrequestAppTest(unittest.TestCase): def tearDown(self): self.config.end() - def test_it(self): + def test_one(self): res = self.testapp.get('/view_one', status=200) self.assertTrue(b'This came from view_two' in res.body) + def test_three(self): + res = self.testapp.get('/view_three', status=500) + self.assertTrue(b'Bad stuff happened' in res.body) + + def test_five(self): + res = self.testapp.get('/view_five', status=200) + self.assertTrue(b'Value error raised' in res.body) + class RendererScanAppTest(IntegrationBase, unittest.TestCase): package = 'pyramid.tests.pkgs.rendererscanapp' def test_root(self): -- 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(-) 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 f7462bb5ada798ce38ed9a9f8109ec2564c1d32a Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 13:13:49 -0400 Subject: be very explicit that view_three should indeed obtain a response as the result of invoke_subrequest instead of catching an exception --- pyramid/tests/pkgs/subrequestapp/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pyramid/tests/pkgs/subrequestapp/__init__.py b/pyramid/tests/pkgs/subrequestapp/__init__.py index dceaa9e45..b8f44cd7f 100644 --- a/pyramid/tests/pkgs/subrequestapp/__init__.py +++ b/pyramid/tests/pkgs/subrequestapp/__init__.py @@ -11,8 +11,11 @@ def view_two(request): def view_three(request): subreq = Request.blank('/view_four') - response = request.invoke_subrequest(subreq, use_tweens=True) - return response + try: + return request.invoke_subrequest(subreq, use_tweens=True) + except: # pragma: no cover + request.response.body = b'Value error raised' + return request.response def view_four(request): raise ValueError('foo') -- 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/glossary.rst | 20 +++-- docs/narr/install.rst | 213 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 169 insertions(+), 64 deletions(-) diff --git a/docs/glossary.rst b/docs/glossary.rst index 34cf1b078..2b006da20 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -41,14 +41,20 @@ Glossary setuptools `Setuptools `_ builds on Python's ``distutils`` to provide easier building, - distribution, and installation of libraries and applications. + distribution, and installation of libraries and applications. As of + this writing, setuptools runs under Python 2, but not under Python 3. + You can use :term:`distribute` under Python 3 instead. + + distribute + `Distribute `_ is a fork of + :term:`setuptools` which runs on both Python 2 and Python 3. pkg_resources - A module which ships with :term:`setuptools` that provides an API for - addressing "asset files" within a Python :term:`package`. Asset files - are static files, template files, etc; basically anything - non-Python-source that lives in a Python package can be considered a - asset file. See also `PkgResources + A module which ships with :term:`setuptools` and :term:`distribute` that + provides an API for addressing "asset files" within a Python + :term:`package`. Asset files are static files, template files, etc; + basically anything non-Python-source that lives in a Python package can + be considered a asset file. See also `PkgResources `_ asset @@ -84,7 +90,7 @@ Glossary (Setuptools/distutils terminology). A file representing an installable library or application. Distributions are usually files that have the suffix of ``.egg``, ``.tar.gz``, or ``.zip``. - Distributions are the target of Setuptools commands such as + Distributions are the target of Setuptools-related commands such as ``easy_install``. entry point 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 2208c2cca8f44a9fff547131b3adda8fac8e2829 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 14:45:07 -0400 Subject: add link to forbidden footnote ref issue #671 --- docs/tutorials/wiki2/design.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/tutorials/wiki2/design.rst b/docs/tutorials/wiki2/design.rst index deaf32ef6..6e41e00aa 100644 --- a/docs/tutorials/wiki2/design.rst +++ b/docs/tutorials/wiki2/design.rst @@ -115,7 +115,8 @@ listed in the following table: | | redirect to | | | | | | /PageName | | | | +----------------------+-----------------------+-------------+------------+------------+ -| /login | Display login form. | login | login.pt | | +| /login | Display login form, | login | login.pt | | +| | Forbidden [3]_ | | | | | | | | | | | | If the form was | | | | | | submitted, | | | | -- cgit v1.2.3 From b9595cd2578fa1cbc2b817c9cd9c4bc93c9508b8 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 14:49:09 -0400 Subject: no longer an issue --- docs/designdefense.rst | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/docs/designdefense.rst b/docs/designdefense.rst index d896022e6..b468ddac6 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -390,20 +390,6 @@ completely optional. No ZCML is required at all to use :app:`Pyramid`, nor any other sort of frameworky declarative frontend to application configuration. -.. _model_traversal_confusion: - -Pyramid Uses "Model" To Represent A Node In The Graph of Objects Traversed --------------------------------------------------------------------------- - -The ``repoze.bfg`` documentation used to refer to the graph being traversed -when :term:`traversal` is used as a "model graph". A terminology overlap -confused people who wrote applications that always use ORM packages such as -SQLAlchemy, which has a different notion of the definition of a "model". As -a result, in Pyramid 1.0a7, the tree of objects traversed is now renamed to -:term:`resource tree` and its components are now named :term:`resource` -objects. Associated APIs have been changed. This hopefully alleviates the -terminology confusion caused by overriding the term "model". - Pyramid Does Traversal, And I Don't Like Traversal -------------------------------------------------- -- cgit v1.2.3 From def086c61678a0b17727ab8cba191b286bf0e475 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 18:18:49 -0400 Subject: unused imports --- pyramid/config/factories.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyramid/config/factories.py b/pyramid/config/factories.py index e46519bf5..01b1fb22e 100644 --- a/pyramid/config/factories.py +++ b/pyramid/config/factories.py @@ -1,11 +1,9 @@ from zope.interface import implementer -from pyramid.compat import iteritems_ from pyramid.config.util import action_method from pyramid.interfaces import ( IDefaultRootFactory, - INewRequest, IRequestFactory, IRequestExtensions, IRootFactory, -- 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(-) 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/api/request.rst | 5 +++- docs/narr/subrequest.rst | 63 ++++++++++++++++++++++++++++++------------------ docs/narr/views.rst | 10 ++++++++ pyramid/router.py | 2 +- 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/docs/api/request.rst b/docs/api/request.rst index 8af81cdac..3a1439874 100644 --- a/docs/api/request.rst +++ b/docs/api/request.rst @@ -161,7 +161,7 @@ request, the value of this attribute will be ``None``. See :ref:`matched_route`. - .. method:: invoke_subrequest(request, use_tweens=True) + .. method:: invoke_subrequest(request, use_tweens=False) .. warning:: @@ -198,6 +198,9 @@ - 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. 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) diff --git a/pyramid/router.py b/pyramid/router.py index 8ee826a2c..0c7f61071 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -162,7 +162,7 @@ class Router(object): return response - def invoke_subrequest(self, request, use_tweens=True): + def invoke_subrequest(self, request, use_tweens=False): """ Obtain a response object from the Pyramid application based on information in the ``request`` object provided. The ``request`` -- cgit v1.2.3 From aa9d3bf71765342852e688aca34d04e07707263c Mon Sep 17 00:00:00 2001 From: David Gay Date: Sun, 16 Sep 2012 22:37:50 -0400 Subject: add name to CONTRIBUTORS.txt as per request --- CONTRIBUTORS.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index c3995aaba..bbe32d53b 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -1,4 +1,4 @@ - Pylons Project Contributor Agreement +Pylons Project Contributor Agreement ==================================== The submitter agrees by adding his or her name within the section below named @@ -176,3 +176,5 @@ Contributors - Marc Abramowitz, 2012/06/13 - Jeff Cook, 2012/06/16 + +- David Gay, 2012/09/16 -- cgit v1.2.3 From ce1e86c44e812ae438c2647cd7d5b6a4ce2ab478 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 23:15:45 -0400 Subject: prep for 1.4a1 --- CHANGES.txt | 5 ++--- docs/conf.py | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 66ac42136..592b08448 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,5 @@ -Next release -============ - +1.4a1 (2012-09-16) +================== Bug Fixes --------- diff --git a/docs/conf.py b/docs/conf.py index 80ee0d2e5..65d1cb83b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -81,7 +81,7 @@ copyright = '%s, Agendaless Consulting' % datetime.datetime.now().year # other places throughout the built documents. # # The short X.Y version. -version = '1.4dev' +version = '1.4a1' # The full version, including alpha/beta/rc tags. release = version diff --git a/setup.py b/setup.py index 03ebb4293..bb0bf45a7 100644 --- a/setup.py +++ b/setup.py @@ -68,7 +68,7 @@ testing_extras = tests_require + [ ] setup(name='pyramid', - version='1.4dev', + version='1.4a1', description=('The Pyramid web application development framework, a ' 'Pylons project'), long_description=README + '\n\n' + CHANGES, -- cgit v1.2.3 From 0583963c30caa1e12a9fc9a3a69830f5b50f40e7 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 23:20:59 -0400 Subject: change to kick rtd --- CHANGES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.txt b/CHANGES.txt index 592b08448..a673396ba 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,7 @@ 1.4a1 (2012-09-16) ================== + Bug Fixes --------- -- cgit v1.2.3 From 8c51dfc02a889f0296df6455d0b62a2c805e39ec Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 23:23:04 -0400 Subject: change to kick rtd --- CHANGES.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index a673396ba..592b08448 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,7 +1,6 @@ 1.4a1 (2012-09-16) ================== - Bug Fixes --------- -- cgit v1.2.3 From 2389c332c63d0fedf5b65d45b0db55cb9c601818 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Sep 2012 23:37:14 -0400 Subject: no longer in progress --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 65d1cb83b..7abae7a85 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -160,7 +160,7 @@ html_theme_path = ['_themes'] html_theme = 'pyramid' html_theme_options = dict( github_url='https://github.com/Pylons/pyramid', - in_progress='true', +# in_progress='true', ) # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths -- cgit v1.2.3 From 0436567f2f4bd92e9769890befc77aae54d5ea36 Mon Sep 17 00:00:00 2001 From: Philip Jenvey Date: Tue, 18 Sep 2012 13:54:27 -0700 Subject: mention set_request_property's doc-deprecation up above as well, make add_request_method more prominent --- docs/whatsnew-1.4.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst index f57178db1..ddc602271 100644 --- a/docs/whatsnew-1.4.rst +++ b/docs/whatsnew-1.4.rst @@ -94,10 +94,10 @@ Minor Feature Additions - :meth:`pyramid.config.Configurator.add_request_method` has been introduced to support extending request objects with arbitrary callables. This method - expands on the previous + expands on the now documentation-deprecated :meth:`pyramid.config.Configurator.set_request_property` by supporting - methods as well as properties. This method causes less code to be executed - at request construction time than + methods as well as properties. This method also causes less code to be + executed at request construction time than :meth:`~pyramid.config.Configurator.set_request_property`. - The static view machinery now raises rather than returns @@ -133,13 +133,13 @@ Minor Feature Additions ``pyramid.util.InstancePropertyMixin`` class such as ``set_property``. - Request properties and methods added via - :meth:`pyramid.config.Configurator.set_request_property` or - :meth:`pyramid.config.Configurator.add_request_method` are now available to + :meth:`pyramid.config.Configurator.add_request_method` or + :meth:`pyramid.config.Configurator.set_request_property` are now available to tweens. - Request properties and methods added via - :meth:`pyramid.config.Configurator.set_request_property` or - :meth:`pyramid.config.Configurator.add_request_method` are now available + :meth:`pyramid.config.Configurator.add_request_method` or + :meth:`pyramid.config.Configurator.set_request_property` are now available in the request object returned from :func:`pyramid.paster.bootstrap`. - ``request.context`` of environment request during -- cgit v1.2.3 From 68c00de2f71f95571c1876d024c9ad5d4dfeec2c Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 19 Sep 2012 03:30:18 -0400 Subject: add check_csrf convenience function --- docs/api/session.rst | 2 ++ docs/whatsnew-1.4.rst | 3 +++ pyramid/session.py | 16 ++++++++++++++++ pyramid/tests/test_session.py | 20 ++++++++++++++++++++ 4 files changed, 41 insertions(+) diff --git a/docs/api/session.rst b/docs/api/session.rst index 44b4bd860..31bc196ad 100644 --- a/docs/api/session.rst +++ b/docs/api/session.rst @@ -11,4 +11,6 @@ .. autofunction:: signed_deserialize + .. autofunction:: check_csrf_token + diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst index f57178db1..fc25c415e 100644 --- a/docs/whatsnew-1.4.rst +++ b/docs/whatsnew-1.4.rst @@ -153,6 +153,9 @@ Minor Feature Additions used to generate a configurator in a test, e.g. ``with testing.testConfig(...):``. +- A new :func:`pyramid.session.check_csrf_token` convenience API function was + added. + Backwards Incompatibilities --------------------------- diff --git a/pyramid/session.py b/pyramid/session.py index 40e21ddbc..3f700564d 100644 --- a/pyramid/session.py +++ b/pyramid/session.py @@ -15,6 +15,7 @@ from pyramid.compat import ( native_, ) +from pyramid.httpexceptions import HTTPBadRequest from pyramid.interfaces import ISession from pyramid.util import strings_differ @@ -80,6 +81,21 @@ def signed_deserialize(serialized, secret, hmac=hmac): return pickle.loads(pickled) +def check_csrf_token(request, token='csrf_token'): + """ Check the CSRF token in the request's session against the value in + ``request.params.get(token)``. If ``token`` is not supplied, the string + value ``csrf_token`` will be used as the token value. If the value in + ``request.params.get(token)`` doesn't match the value supplied by + ``request.session.get_csrf_token()``, this function will raise an + :exc:`pyramid.httpexceptions.HTTPBadRequest` exception. If the CSRF + check is successful, this function will return ``True``. + + .. versionadded:: 1.4a2 + """ + if request.params.get(token) != request.session.get_csrf_token(): + raise HTTPBadRequest('incorrect CSRF token') + return True + def UnencryptedCookieSessionFactoryConfig( secret, timeout=1200, diff --git a/pyramid/tests/test_session.py b/pyramid/tests/test_session.py index 5143b7a95..21cf16b12 100644 --- a/pyramid/tests/test_session.py +++ b/pyramid/tests/test_session.py @@ -355,6 +355,26 @@ class Test_signed_deserialize(unittest.TestCase): serialized = 'bad' + serialize('123', 'secret') self.assertRaises(ValueError, self._callFUT, serialized, 'secret') +class Test_check_csrf_token(unittest.TestCase): + def _callFUT(self, request, token): + from ..session import check_csrf_token + return check_csrf_token(request, token) + + def test_success(self): + request = testing.DummyRequest() + request.params['csrf_token'] = request.session.get_csrf_token() + self.assertEqual(self._callFUT(request, 'csrf_token'), True) + + def test_success_default_token(self): + from ..session import check_csrf_token + request = testing.DummyRequest() + request.params['csrf_token'] = request.session.get_csrf_token() + self.assertEqual(check_csrf_token(request), True) + + def test_failure(self): + from pyramid.httpexceptions import HTTPBadRequest + request = testing.DummyRequest() + self.assertRaises(HTTPBadRequest, self._callFUT, request, 'csrf_token') class DummySessionFactory(dict): _dirty = False -- cgit v1.2.3 From 68c25d39f9c0531be2916ad433904c7247c0f5c7 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 19 Sep 2012 03:31:09 -0400 Subject: garden --- CHANGES.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 592b08448..e08a69b84 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,12 @@ +Next release +============ + +Features +-------- + +- A new ``pyramid.session.check_csrf_token`` convenience function was added. + + 1.4a1 (2012-09-16) ================== -- 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/glossary.rst | 9 ++++-- docs/narr/introspector.rst | 4 +++ docs/narr/viewconfig.rst | 31 ++++++++++++++++++++ docs/whatsnew-1.4.rst | 6 ++++ pyramid/config/predicates.py | 23 +++++++++++++++ pyramid/config/views.py | 31 +++++++++++++++++++- pyramid/session.py | 17 +++++++---- pyramid/tests/test_config/test_predicates.py | 43 ++++++++++++++++++++++++++++ pyramid/tests/test_session.py | 11 +++++-- pyramid/view.py | 2 +- 10 files changed, 164 insertions(+), 13 deletions(-) diff --git a/docs/glossary.rst b/docs/glossary.rst index 2b006da20..96dd826d1 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -818,9 +818,12 @@ Glossary application. session factory - A callable, which, when called with a single argument named - ``request`` (a :term:`request` object), returns a - :term:`session` object. + A callable, which, when called with a single argument named ``request`` + (a :term:`request` object), returns a :term:`session` object. See + :ref:`using_the_default_session_factory`, + :ref:`using_alternate_session_factories` and + :meth:`pyramid.config.Configurator.set_session_factory` for more + information. Mako `Mako `_ is a template language language 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 diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst index 76320f6e6..86bfc7c0a 100644 --- a/docs/whatsnew-1.4.rst +++ b/docs/whatsnew-1.4.rst @@ -156,6 +156,12 @@ Minor Feature Additions - A new :func:`pyramid.session.check_csrf_token` convenience API function was added. +- 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. + Backwards Incompatibilities --------------------------- diff --git a/pyramid/config/predicates.py b/pyramid/config/predicates.py index 9e0ee28c1..77b55d9b3 100644 --- a/pyramid/config/predicates.py +++ b/pyramid/config/predicates.py @@ -13,6 +13,8 @@ from pyramid.urldispatch import _compile_route from pyramid.util import object_description +from pyramid.session import check_csrf_token + from .util import as_sorted_tuple class XHRPredicate(object): @@ -226,3 +228,24 @@ class TraversePredicate(object): # injects ``traverse`` into the matchdict. As a result, we just # return True. return True + +class CheckCSRFTokenPredicate(object): + + check_csrf_token = staticmethod(check_csrf_token) # testing + + def __init__(self, val, config): + self.val = val + + def text(self): + return 'check_csrf = %s' % (self.val,) + + phash = text + + def __call__(self, context, request): + val = self.val + if val: + if val is True: + val = 'csrf_token' + return self.check_csrf_token(request, val, raises=False) + return True + diff --git a/pyramid/config/views.py b/pyramid/config/views.py index 36896a17e..9ace96c1d 100644 --- a/pyramid/config/views.py +++ b/pyramid/config/views.py @@ -662,6 +662,7 @@ class ViewsConfiguratorMixin(object): mapper=None, http_cache=None, match_param=None, + check_csrf=None, **predicates): """ Add a :term:`view configuration` to the current configuration state. Arguments to ``add_view`` are broken @@ -989,6 +990,29 @@ class ViewsConfiguratorMixin(object): variable. If the regex matches, this predicate will be ``True``. + 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 This value should be a sequence of references to custom @@ -1007,7 +1031,9 @@ class ViewsConfiguratorMixin(object): :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. This argument is new as of Pyramid 1.4. + third-party predicates. + + .. versionadded: 1.4a1 """ view = self.maybe_dotted(view) @@ -1061,6 +1087,7 @@ class ViewsConfiguratorMixin(object): containment=containment, request_type=request_type, match_param=match_param, + check_csrf=check_csrf, custom=predvalseq(custom_predicates), ) ) @@ -1098,6 +1125,7 @@ class ViewsConfiguratorMixin(object): header=header, path_info=path_info, match_param=match_param, + check_csrf=check_csrf, callable=view, mapper=mapper, decorator=decorator, @@ -1340,6 +1368,7 @@ class ViewsConfiguratorMixin(object): ('containment', p.ContainmentPredicate), ('request_type', p.RequestTypePredicate), ('match_param', p.MatchParamPredicate), + ('check_csrf', p.CheckCSRFTokenPredicate), ('custom', p.CustomPredicate), ): self.add_view_predicate(name, factory) diff --git a/pyramid/session.py b/pyramid/session.py index 3f700564d..3b2834693 100644 --- a/pyramid/session.py +++ b/pyramid/session.py @@ -81,19 +81,26 @@ def signed_deserialize(serialized, secret, hmac=hmac): return pickle.loads(pickled) -def check_csrf_token(request, token='csrf_token'): +def check_csrf_token(request, token='csrf_token', raises=True): """ Check the CSRF token in the request's session against the value in ``request.params.get(token)``. If ``token`` is not supplied, the string value ``csrf_token`` will be used as the token value. If the value in ``request.params.get(token)`` doesn't match the value supplied by - ``request.session.get_csrf_token()``, this function will raise an - :exc:`pyramid.httpexceptions.HTTPBadRequest` exception. If the CSRF - check is successful, this function will return ``True``. + ``request.session.get_csrf_token()``, and ``raises`` is ``True``, this + function will raise an :exc:`pyramid.httpexceptions.HTTPBadRequest` + exception. If the check does succeed and ``raises`` is ``False``, this + function will return ``False``. If the CSRF check is successful, this + function will return ``True`` unconditionally. + + Note that using this function requires that a :term:`session factory` is + configured. .. versionadded:: 1.4a2 """ if request.params.get(token) != request.session.get_csrf_token(): - raise HTTPBadRequest('incorrect CSRF token') + if raises: + raise HTTPBadRequest('incorrect CSRF token') + return False return True def UnencryptedCookieSessionFactoryConfig( diff --git a/pyramid/tests/test_config/test_predicates.py b/pyramid/tests/test_config/test_predicates.py index e33a31458..005b1b27a 100644 --- a/pyramid/tests/test_config/test_predicates.py +++ b/pyramid/tests/test_config/test_predicates.py @@ -256,6 +256,49 @@ class TestTraversePredicate(unittest.TestCase): inst = self._makeOne('/abc') self.assertEqual(inst.phash(), '') +class Test_CheckCSRFTokenPredicate(unittest.TestCase): + def _makeOne(self, val, config): + from pyramid.config.predicates import CheckCSRFTokenPredicate + return CheckCSRFTokenPredicate(val, config) + + def test_text(self): + inst = self._makeOne(True, None) + self.assertEqual(inst.text(), 'check_csrf = True') + + def test_phash(self): + inst = self._makeOne(True, None) + self.assertEqual(inst.phash(), 'check_csrf = True') + + def test_it_call_val_True(self): + inst = self._makeOne(True, None) + request = Dummy() + def check_csrf_token(req, val, raises=True): + self.assertEqual(req, request) + self.assertEqual(val, 'csrf_token') + self.assertEqual(raises, False) + return True + inst.check_csrf_token = check_csrf_token + result = inst(None, request) + self.assertEqual(result, True) + + def test_it_call_val_str(self): + inst = self._makeOne('abc', None) + request = Dummy() + def check_csrf_token(req, val, raises=True): + self.assertEqual(req, request) + self.assertEqual(val, 'abc') + self.assertEqual(raises, False) + return True + inst.check_csrf_token = check_csrf_token + result = inst(None, request) + self.assertEqual(result, True) + + def test_it_call_val_False(self): + inst = self._makeOne(False, None) + request = Dummy() + result = inst(None, request) + self.assertEqual(result, True) + class predicate(object): def __repr__(self): return 'predicate' diff --git a/pyramid/tests/test_session.py b/pyramid/tests/test_session.py index 21cf16b12..b3e0e20c4 100644 --- a/pyramid/tests/test_session.py +++ b/pyramid/tests/test_session.py @@ -356,9 +356,9 @@ class Test_signed_deserialize(unittest.TestCase): self.assertRaises(ValueError, self._callFUT, serialized, 'secret') class Test_check_csrf_token(unittest.TestCase): - def _callFUT(self, request, token): + def _callFUT(self, request, token, raises=True): from ..session import check_csrf_token - return check_csrf_token(request, token) + return check_csrf_token(request, token, raises=raises) def test_success(self): request = testing.DummyRequest() @@ -371,11 +371,16 @@ class Test_check_csrf_token(unittest.TestCase): request.params['csrf_token'] = request.session.get_csrf_token() self.assertEqual(check_csrf_token(request), True) - def test_failure(self): + def test_failure_raises(self): from pyramid.httpexceptions import HTTPBadRequest request = testing.DummyRequest() self.assertRaises(HTTPBadRequest, self._callFUT, request, 'csrf_token') + def test_failure_no_raises(self): + request = testing.DummyRequest() + result = self._callFUT(request, 'csrf_token', raises=False) + self.assertEqual(result, False) + class DummySessionFactory(dict): _dirty = False _cookie_name = 'session' diff --git a/pyramid/view.py b/pyramid/view.py index 12a2efde6..76f466b83 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -170,7 +170,7 @@ class view_config(object): ``request_type``, ``route_name``, ``request_method``, ``request_param``, ``containment``, ``xhr``, ``accept``, ``header``, ``path_info``, ``custom_predicates``, ``decorator``, ``mapper``, ``http_cache``, - ``match_param``, and ``predicates``. + ``match_param``, ``csrf_token``, and ``predicates``. The meanings of these arguments are the same as the arguments passed to :meth:`pyramid.config.Configurator.add_view`. If any argument is left -- cgit v1.2.3 From 80cd0b1ab6b97c99863db045a2dda984e006c3b9 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 19 Sep 2012 04:48:14 -0400 Subject: garden --- CHANGES.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index e08a69b84..58e484a92 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,6 +6,11 @@ Features - A new ``pyramid.session.check_csrf_token`` convenience function was added. +- 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. 1.4a1 (2012-09-16) ================== -- cgit v1.2.3 From 1c7724e5484c65257f18b542662d5e1a1115c9f0 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 19 Sep 2012 05:44:03 -0400 Subject: remove dead code --- pyramid/chameleon_text.py | 5 ----- pyramid/chameleon_zpt.py | 5 ----- pyramid/tests/test_config/test_init.py | 11 ++++++----- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/pyramid/chameleon_text.py b/pyramid/chameleon_text.py index 21dc85528..8cf04bf79 100644 --- a/pyramid/chameleon_text.py +++ b/pyramid/chameleon_text.py @@ -1,5 +1,3 @@ -import sys - from zope.interface import implementer from chameleon.zpt.template import PageTextTemplateFile @@ -22,9 +20,6 @@ class TextTemplateRenderer(object): @reify # avoid looking up reload_templates before manager pushed def template(self): - if sys.platform.startswith('java'): # pragma: no cover - raise RuntimeError( - 'Chameleon templates are not compatible with Jython') return PageTextTemplateFile(self.path, auto_reload=self.lookup.auto_reload, debug=self.lookup.debug, diff --git a/pyramid/chameleon_zpt.py b/pyramid/chameleon_zpt.py index 862e996b9..73203a7cb 100644 --- a/pyramid/chameleon_zpt.py +++ b/pyramid/chameleon_zpt.py @@ -1,5 +1,3 @@ -import sys - from zope.interface import implementer from chameleon.zpt.template import PageTemplateFile @@ -20,9 +18,6 @@ class ZPTTemplateRenderer(object): @reify # avoid looking up reload_templates before manager pushed def template(self): - if sys.platform.startswith('java'): # pragma: no cover - raise RuntimeError( - 'Chameleon templates are not compatible with Jython') tf = PageTemplateFile(self.path, auto_reload=self.lookup.auto_reload, debug=self.lookup.debug, diff --git a/pyramid/tests/test_config/test_init.py b/pyramid/tests/test_config/test_init.py index f39906dd9..2cf9a269a 100644 --- a/pyramid/tests/test_config/test_init.py +++ b/pyramid/tests/test_config/test_init.py @@ -923,12 +923,13 @@ pyramid.tests.test_config.dummy_include2""", result = render_view_to_response(ctx, req, 'another_stacked_class2') self.assertEqual(result, 'another_stacked_class') - if not os.name.startswith('java'): - # on Jython, a class without an __init__ apparently accepts - # any number of arguments without raising a TypeError. + # NB: on Jython, a class without an __init__ apparently accepts + # any number of arguments without raising a TypeError, so the next + # assertion may fail there. We don't support Jython at the moment, + # this is just a note to a future self. - self.assertRaises(TypeError, - render_view_to_response, ctx, req, 'basemethod') + self.assertRaises(TypeError, + render_view_to_response, ctx, req, 'basemethod') result = render_view_to_response(ctx, req, 'method1') self.assertEqual(result, 'method1') -- cgit v1.2.3 From f272f27b106265e9151eabe850ca282f6035a246 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 21 Sep 2012 20:35:12 -0400 Subject: note potential 1.5 removals and remove dead code --- TODO.txt | 4 ++++ pyramid/config/routes.py | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/TODO.txt b/TODO.txt index 1686c27a2..6787b8a55 100644 --- a/TODO.txt +++ b/TODO.txt @@ -140,6 +140,10 @@ Future - 1.5: Maybe? deprecate set_request_property in favor of pointing people at add_request_method, schedule removal for 1.8? +- 1.5: Remove pyramid.config.rendering set_renderer_globals_factory maybe. + +- 1.5: remove pyramid.config.route _add_view_from_route function. + - 1.6: Remove IContextURL and TraversalContextURL. Probably Bad Ideas diff --git a/pyramid/config/routes.py b/pyramid/config/routes.py index 1a7fdfac9..30bebfb98 100644 --- a/pyramid/config/routes.py +++ b/pyramid/config/routes.py @@ -4,7 +4,6 @@ from pyramid.interfaces import ( IRequest, IRouteRequest, IRoutesMapper, - PHASE1_CONFIG, PHASE2_CONFIG, ) -- cgit v1.2.3 From b9f54f3c3b391a5964ba14b8fe6828c9a1ca9c0f Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sat, 22 Sep 2012 03:04:57 -0300 Subject: Filenames like app:foo-bar.mako should be valid. --- pyramid/mako_templating.py | 2 +- pyramid/tests/test_mako_templating.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pyramid/mako_templating.py b/pyramid/mako_templating.py index 5d09cad01..f2627c1fc 100644 --- a/pyramid/mako_templating.py +++ b/pyramid/mako_templating.py @@ -91,7 +91,7 @@ class MakoRendererFactoryHelper(object): def __call__(self, info): p = re.compile( - r'(?P[\w_.:/]+)' + r'(?P[\w_.:/-]+)' r'(?:\#(?P[\w_]+))?' r'(\.(?P.*))' ) diff --git a/pyramid/tests/test_mako_templating.py b/pyramid/tests/test_mako_templating.py index 97b2c679b..37264aa48 100644 --- a/pyramid/tests/test_mako_templating.py +++ b/pyramid/tests/test_mako_templating.py @@ -31,6 +31,20 @@ class Test_renderer_factory(Base, unittest.TestCase): from pyramid.mako_templating import IMakoLookup return self.config.registry.getUtility(IMakoLookup, name=name) + def test_hyphen_filenames(self): + from pyramid.mako_templating import renderer_factory + + info = DummyRendererInfo({ + 'name':'app:moon-and-world.mak', + 'package':None, + 'registry':self.config.registry, + 'settings':{}, + 'type': '' + }) + + result = renderer_factory(info) + self.assertEqual(result.path, 'app:moon-and-world.mak') + def test_no_directories(self): info = DummyRendererInfo({ 'name':'pyramid.tests:fixtures/helloworld.mak', -- cgit v1.2.3 From d27bc7903516b8666ea814c5bb8c10de64a679f5 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 22 Sep 2012 07:59:53 -0400 Subject: garden --- CHANGES.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 58e484a92..104ed1e98 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,12 @@ Next release ============ +Bug Fixes +--------- + +- It is now possible to use asset specifications which contain a hyphen in + Mako asset spec names. See https://github.com/Pylons/pyramid/pull/692 + Features -------- -- cgit v1.2.3 From 4388d317712be00a1d49cc73ac78407fe6906263 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 22 Sep 2012 08:06:52 -0400 Subject: mirror john's change for chameleon, better changelog message --- CHANGES.txt | 5 +++-- pyramid/renderers.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 104ed1e98..4e6feb68c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,8 +4,9 @@ Next release Bug Fixes --------- -- It is now possible to use asset specifications which contain a hyphen in - Mako asset spec names. See https://github.com/Pylons/pyramid/pull/692 +- When trying to determine Mako defnames and Chameleon macro names in asset + specifications, take into account that the filename may have a hyphen in + it. See https://github.com/Pylons/pyramid/pull/692 Features -------- diff --git a/pyramid/renderers.py b/pyramid/renderers.py index 3252c2c93..1368e190e 100644 --- a/pyramid/renderers.py +++ b/pyramid/renderers.py @@ -437,7 +437,7 @@ class ChameleonRendererLookup(object): renderer = registry.queryUtility(ITemplateRenderer, name=spec) if renderer is None: p = re.compile( - r'(?P[\w_.:/]+)' + r'(?P[\w_.:/-]+)' r'(?:\#(?P[\w_]+))?' r'(\.(?P.*))' ) -- cgit v1.2.3 From 098599b497fb6cd7c9372ceb795e9e8a416d573e Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 22 Sep 2012 10:04:14 -0400 Subject: - Add ``Base.metadata.bind = engine`` to alchemy template, so that tables defined imperatively will work. - update wiki2 SQLA tutorial with the changes required after inserting ``Base.metadata.bind = engine`` into the alchemy scaffold. --- CHANGES.txt | 9 +++++++ docs/tutorials/wiki2/authorization.rst | 8 +++---- docs/tutorials/wiki2/basiclayout.rst | 28 +++++++++++++++------- docs/tutorials/wiki2/definingviews.rst | 2 +- .../wiki2/src/authorization/tutorial/__init__.py | 6 ++++- .../wiki2/src/basiclayout/tutorial/__init__.py | 6 ++++- .../wiki2/src/models/tutorial/__init__.py | 6 ++++- .../tutorials/wiki2/src/tests/tutorial/__init__.py | 6 ++++- .../tutorials/wiki2/src/views/tutorial/__init__.py | 6 ++++- pyramid/scaffolds/alchemy/+package+/__init__.py | 6 ++++- 10 files changed, 64 insertions(+), 19 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 4e6feb68c..0b27a74c3 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -19,6 +19,15 @@ Features token in the request's session, the view will be permitted to execute. Otherwise, it will not be permitted to execute. +- Add ``Base.metadata.bind = engine`` to alchemy template, so that tables + defined imperatively will work. + +Documentation +------------- + +- update wiki2 SQLA tutorial with the changes required after inserting + ``Base.metadata.bind = engine`` into the alchemy scaffold. + 1.4a1 (2012-09-16) ================== diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst index d7bd24a53..6b2d44410 100644 --- a/docs/tutorials/wiki2/authorization.rst +++ b/docs/tutorials/wiki2/authorization.rst @@ -112,7 +112,7 @@ parameter to our :term:`Configurator` constructor, that points to the class we created above: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 19-20 + :lines: 23-24 :linenos: :emphasize-lines: 2 :language: python @@ -144,7 +144,7 @@ add these import statements: Now add those policies to the configuration: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 16-22 + :lines: 20-26 :linenos: :emphasize-lines: 1-3,6-7 :language: python @@ -206,7 +206,7 @@ Go back to ``tutorial/tutorial/__init__.py`` and add these two routes: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 25-26 + :lines: 29-30 :linenos: :language: python @@ -333,7 +333,7 @@ when we're done: .. literalinclude:: src/authorization/tutorial/__init__.py :linenos: - :emphasize-lines: 2-3,7,16-18,20-22,25-26 + :emphasize-lines: 2-3,7,23-24,20-26,29-30 :language: python (Only the highlighted lines need to be added.) diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst index b3184c4fc..dbd130c36 100644 --- a/docs/tutorials/wiki2/basiclayout.rst +++ b/docs/tutorials/wiki2/basiclayout.rst @@ -51,21 +51,33 @@ The main function first creates a SQLAlchemy database engine using (something like ``sqlite://``): .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 9 + :lines: 12 :linenos: :language: py -``main`` then initializes our SQL database using SQLAlchemy, passing it the +``main`` then initializes our SQLAlchemy session object, passing it the engine: .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 10 + :lines: 13 + :language: py + +``main`` subsequently initializes our SQLAlchemy declarative Base object, +assigning the engine we created to the ``bind`` attribute of it's +``metadata`` object. This allows table definitions done imperatively +(instead of declaratively, via a class statement) to work. We won't use any +such tables in our application, but if you add one later, long after you've +forgotten about this tutorial, you won't be left scratching your head when it +doesn't work. + + .. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 14 :language: py The next step of ``main`` is to construct a :term:`Configurator` object: .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 11 + :lines: 15 :language: py ``settings`` is passed to the Configurator as a keyword argument with the @@ -78,7 +90,7 @@ deployment-related values such as ``pyramid.reload_templates``, two arguments: ``static`` (the name), and ``static`` (the path): .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 12 + :lines: 16 :language: py This registers a static resource view which will match any URL that starts @@ -96,7 +108,7 @@ via the :meth:`pyramid.config.Configurator.add_route` method that will be used when the URL is ``/``: .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 13 + :lines: 17 :language: py Since this route has a ``pattern`` equalling ``/`` it is the route that will @@ -109,7 +121,7 @@ view configuration will be registered, which will allow one of our application URLs to be mapped to some code. .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 14 + :lines: 18 :language: py Finally, ``main`` is finished configuring things, so it uses the @@ -117,7 +129,7 @@ Finally, ``main`` is finished configuring things, so it uses the :term:`WSGI` application: .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 15 + :lines: 19 :language: py View Declarations via ``views.py`` diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst index 24ac4338d..a54996e3c 100644 --- a/docs/tutorials/wiki2/definingviews.rst +++ b/docs/tutorials/wiki2/definingviews.rst @@ -342,7 +342,7 @@ something like: .. literalinclude:: src/views/tutorial/__init__.py :linenos: :language: python - :emphasize-lines: 13-16 + :emphasize-lines: 17-20 (The highlighted lines are the ones that need to be added or edited.) diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py index 7e290a1e1..8922a3cc0 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py @@ -6,13 +6,17 @@ from sqlalchemy import engine_from_config from tutorial.security import groupfinder -from .models import DBSession +from .models import ( + DBSession, + Base, + ) def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) + Base.metadata.bind = engine authn_policy = AuthTktAuthenticationPolicy( 'sosecret', callback=groupfinder) authz_policy = ACLAuthorizationPolicy() diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py index 253341563..e39f619ed 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py @@ -1,13 +1,17 @@ from pyramid.config import Configurator from sqlalchemy import engine_from_config -from .models import DBSession +from .models import ( + DBSession, + Base, + ) def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) + Base.metadata.bind = engine config = Configurator(settings=settings) config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('home', '/') diff --git a/docs/tutorials/wiki2/src/models/tutorial/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/__init__.py index 253341563..e39f619ed 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/models/tutorial/__init__.py @@ -1,13 +1,17 @@ from pyramid.config import Configurator from sqlalchemy import engine_from_config -from .models import DBSession +from .models import ( + DBSession, + Base, + ) def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) + Base.metadata.bind = engine config = Configurator(settings=settings) config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('home', '/') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py index 7e290a1e1..8922a3cc0 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py @@ -6,13 +6,17 @@ from sqlalchemy import engine_from_config from tutorial.security import groupfinder -from .models import DBSession +from .models import ( + DBSession, + Base, + ) def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) + Base.metadata.bind = engine authn_policy = AuthTktAuthenticationPolicy( 'sosecret', callback=groupfinder) authz_policy = ACLAuthorizationPolicy() diff --git a/docs/tutorials/wiki2/src/views/tutorial/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/__init__.py index b30d593cf..810e92f75 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/views/tutorial/__init__.py @@ -1,13 +1,17 @@ from pyramid.config import Configurator from sqlalchemy import engine_from_config -from .models import DBSession +from .models import ( + DBSession, + Base, + ) def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) + Base.metadata.bind = engine config = Configurator(settings=settings) config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('view_wiki', '/') diff --git a/pyramid/scaffolds/alchemy/+package+/__init__.py b/pyramid/scaffolds/alchemy/+package+/__init__.py index 253341563..e39f619ed 100644 --- a/pyramid/scaffolds/alchemy/+package+/__init__.py +++ b/pyramid/scaffolds/alchemy/+package+/__init__.py @@ -1,13 +1,17 @@ from pyramid.config import Configurator from sqlalchemy import engine_from_config -from .models import DBSession +from .models import ( + DBSession, + Base, + ) def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) + Base.metadata.bind = engine config = Configurator(settings=settings) config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('home', '/') -- cgit v1.2.3 From 072cbf7ae84e80185ebc122d0c11a6838ac36093 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 27 Sep 2012 11:40:57 -0400 Subject: prep for 1.4a2 --- CHANGES.txt | 4 ++-- docs/conf.py | 2 +- docs/whatsnew-1.4.rst | 3 +++ setup.py | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 0b27a74c3..cfdaf4216 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,5 @@ -Next release -============ +1.4a2 (2012-09-27) +================== Bug Fixes --------- diff --git a/docs/conf.py b/docs/conf.py index 7abae7a85..337b1d8bf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -81,7 +81,7 @@ copyright = '%s, Agendaless Consulting' % datetime.datetime.now().year # other places throughout the built documents. # # The short X.Y version. -version = '1.4a1' +version = '1.4a2' # The full version, including alpha/beta/rc tags. release = version diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst index 86bfc7c0a..4e64d8162 100644 --- a/docs/whatsnew-1.4.rst +++ b/docs/whatsnew-1.4.rst @@ -162,6 +162,9 @@ Minor Feature Additions token in the request's session, the view will be permitted to execute. Otherwise, it will not be permitted to execute. +- Add ``Base.metadata.bind = engine`` to ``alchemy`` scaffold, so that tables + defined imperatively will work. + Backwards Incompatibilities --------------------------- diff --git a/setup.py b/setup.py index bb0bf45a7..9af2f2100 100644 --- a/setup.py +++ b/setup.py @@ -68,7 +68,7 @@ testing_extras = tests_require + [ ] setup(name='pyramid', - version='1.4a1', + version='1.4a2', description=('The Pyramid web application development framework, a ' 'Pylons project'), long_description=README + '\n\n' + CHANGES, -- 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(-) 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 From d6fb00161a4d482dcfff856ce59b9dc34f78c2b1 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 30 Sep 2012 18:49:29 -0400 Subject: - 1.4a ``pyramid.scripting.prepare`` behaved differently than 1.3 series function of same name. In particular, if passed a request, it would not set the ``registry`` attribute of the request like 1.3 did. A symptom would be that passing a request to ``pyramid.paster.bootstrap`` (which uses the function) that did not have a ``registry`` attribute could assume that the registry would be attached to the request by Pyramid. This assumption could be made in 1.3, but not in 1.4. The assumption can now be made in 1.4 too (a registry is attached to a request passed to bootstrap or prepare). --- CHANGES.txt | 16 ++++++++++++++++ pyramid/scripting.py | 4 ++++ pyramid/tests/test_scripting.py | 13 ++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index cfdaf4216..e40401528 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,19 @@ +Next release +============ + +Bug Fixes +--------- + +- 1.4a ``pyramid.scripting.prepare`` behaved differently than 1.3 series + function of same name. In particular, if passed a request, it would not + set the ``registry`` attribute of the request like 1.3 did. A symptom + would be that passing a request to ``pyramid.paster.bootstrap`` (which uses + the function) that did not have a ``registry`` attribute could assume that + the registry would be attached to the request by Pyramid. This assumption + could be made in 1.3, but not in 1.4. The assumption can now be made in + 1.4 too (a registry is attached to a request passed to bootstrap or + prepare). + 1.4a2 (2012-09-27) ================== diff --git a/pyramid/scripting.py b/pyramid/scripting.py index 00177986f..fdb4aa430 100644 --- a/pyramid/scripting.py +++ b/pyramid/scripting.py @@ -71,6 +71,10 @@ def prepare(request=None, registry=None): 'before trying to activate it.') if request is None: request = _make_request('/', registry) + # NB: even though _make_request might have already set registry on + # request, we reset it in case someone has passed in their own + # request. + request.registry = registry threadlocals = {'registry':registry, 'request':request} threadlocal_manager.push(threadlocals) extensions = registry.queryUtility(IRequestExtensions) diff --git a/pyramid/tests/test_scripting.py b/pyramid/tests/test_scripting.py index 1ccc7af3b..a36d1ed71 100644 --- a/pyramid/tests/test_scripting.py +++ b/pyramid/tests/test_scripting.py @@ -72,7 +72,7 @@ class Test_prepare(unittest.TestCase): self.assertEqual(self.default, self.manager.get()) self.assertEqual(request.context, root) - def test_it_withrequest(self): + def test_it_withrequest_hasregistry(self): request = DummyRequest({}) registry = request.registry = self._makeRegistry() info = self._callFUT(request=request) @@ -85,6 +85,17 @@ class Test_prepare(unittest.TestCase): closer() self.assertEqual(self.default, self.manager.get()) self.assertEqual(request.context, root) + self.assertEqual(request.registry, registry) + + def test_it_withrequest_noregistry(self): + request = DummyRequest({}) + registry = self._makeRegistry() + info = self._callFUT(request=request, registry=registry) + root, closer, request = info['root'], info['closer'], info['request'] + closer() + self.assertEqual(request.context, root) + # should be set by prepare + self.assertEqual(request.registry, registry) def test_it_with_request_and_registry(self): request = DummyRequest({}) -- cgit v1.2.3 From d3e9c271ccf004effc6b8121412b7805928bce2f Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 30 Sep 2012 21:57:40 -0400 Subject: An attempt at better behavior when reload cannot restart the controlled application, see issue #681 --- pyramid/scripts/pserve.py | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/pyramid/scripts/pserve.py b/pyramid/scripts/pserve.py index 9fbf0729a..f89652b51 100644 --- a/pyramid/scripts/pserve.py +++ b/pyramid/scripts/pserve.py @@ -150,7 +150,8 @@ class PServeCommand(object): _reloader_environ_key = 'PYTHON_RELOADER_SHOULD_RUN' _monitor_environ_key = 'PASTE_MONITOR_SHOULD_RUN' - possible_subcommands = ('start', 'stop', 'restart', 'status') + possible_subcommands = ('start', 'stop', 'restart', 'status', + 'handle_reload_error') def __init__(self, argv, quiet=False): self.quiet = quiet @@ -191,6 +192,34 @@ class PServeCommand(object): install_reloader(int(self.options.reload_interval), [app_spec]) # if self.requires_config_file: # watch_file(self.args[0]) + if cmd == 'handle_reload_error': + self.out( + 'There was a reload error: your application did not ' + 'start properly when restarted by the reloader. You ' + 'will need to examine the traceback above, and fix ' + 'the issue. The process will restart after each code ' + 'change until the problem is fixed. In some ' + 'circumstances (such as when there is an ImportError ' + 'raised at module scope), changes you make to the ' + 'offending module will not cause a restart ' + 'and you will need to either change the __init__.py ' + 'of your application to force a reload. If that ' + 'does not work, you will need to restart the process ' + 'by hand.') + app_name = self.options.app_name + base = os.getcwd() + vars = self.parse_vars(restvars) + if not self._scheme_re.search(app_spec): + app_spec = 'config:' + app_spec + try: # populate sys.modules + app = self.loadapp( + app_spec, name=app_name, + relative_to=base, global_conf=vars) + except: # but ignore any exceptions + pass + while 1: + time.sleep(1) + else: return self.restart_with_reloader() @@ -526,8 +555,10 @@ class PServeCommand(object): if reloader: # Reloader always exits with code 3; but if we are # a monitor, any exit code will restart - if exit_code != 3: - return exit_code + while exit_code != 3: + handle_error_args = args + ['handle_reload_error'] + proc = subprocess.Popen(handle_error_args, env=new_environ) + exit_code = proc.wait() if self.verbose > 0: self.out('%s %s %s' % ('-' * 20, 'Restarting', '-' * 20)) -- cgit v1.2.3 From 24e14af20902f7d5c491092fc1643787fc0a802a Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 30 Sep 2012 21:59:45 -0400 Subject: s/either// --- pyramid/scripts/pserve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyramid/scripts/pserve.py b/pyramid/scripts/pserve.py index f89652b51..533f708fc 100644 --- a/pyramid/scripts/pserve.py +++ b/pyramid/scripts/pserve.py @@ -202,7 +202,7 @@ class PServeCommand(object): 'circumstances (such as when there is an ImportError ' 'raised at module scope), changes you make to the ' 'offending module will not cause a restart ' - 'and you will need to either change the __init__.py ' + 'and you will need to change the __init__.py ' 'of your application to force a reload. If that ' 'does not work, you will need to restart the process ' 'by hand.') -- cgit v1.2.3 From ccf286e6641184adb6e4bf739c88c6b109466843 Mon Sep 17 00:00:00 2001 From: "David\\ Beitey" Date: Wed, 3 Oct 2012 10:09:34 +1000 Subject: Clarify documentation for pyramid.session.check_csrf_token function --- pyramid/session.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyramid/session.py b/pyramid/session.py index 3b2834693..a5e6a8d3a 100644 --- a/pyramid/session.py +++ b/pyramid/session.py @@ -83,8 +83,9 @@ def signed_deserialize(serialized, secret, hmac=hmac): def check_csrf_token(request, token='csrf_token', raises=True): """ Check the CSRF token in the request's session against the value in - ``request.params.get(token)``. If ``token`` is not supplied, the string - value ``csrf_token`` will be used as the token value. If the value in + ``request.params.get(token)``. If a ``token`` keyword is not supplied + to this function, the string ``csrf_token`` will be used to look up + the token within ``request.params``. If the value in ``request.params.get(token)`` doesn't match the value supplied by ``request.session.get_csrf_token()``, and ``raises`` is ``True``, this function will raise an :exc:`pyramid.httpexceptions.HTTPBadRequest` -- cgit v1.2.3 From fa587efc26c285cdc7e23990f947fdbd233ab53a Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 5 Oct 2012 14:23:09 -0400 Subject: fix caching of template registrations that reference macros --- pyramid/renderers.py | 31 +++++++++++++++++++------------ pyramid/tests/fixtures/withmacro.pt | 1 + pyramid/tests/test_chameleon_zpt.py | 9 +++++++-- pyramid/tests/test_renderers.py | 7 ++++++- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/pyramid/renderers.py b/pyramid/renderers.py index 1368e190e..57a61ebba 100644 --- a/pyramid/renderers.py +++ b/pyramid/renderers.py @@ -367,6 +367,12 @@ class JSONP(JSON): @implementer(IChameleonLookup) class ChameleonRendererLookup(object): + spec_re = re.compile( + r'(?P[\w_.:/-]+)' + r'(?:\#(?P[\w_]+))?' + r'(\.(?P.*))' + ) + def __init__(self, impl, registry): self.impl = impl self.registry = registry @@ -417,6 +423,12 @@ class ChameleonRendererLookup(object): return False return settings.get('reload_templates', False) + def _crack_spec(self, spec): + asset, macro, ext = self.spec_re.match(spec).group( + 'asset', 'defname', 'ext' + ) + return asset, macro, ext + def __call__(self, info): spec = self.get_spec(info.name, info.package) registry = info.registry @@ -436,27 +448,22 @@ class ChameleonRendererLookup(object): # spec is a package:relpath asset spec renderer = registry.queryUtility(ITemplateRenderer, name=spec) if renderer is None: - p = re.compile( - r'(?P[\w_.:/-]+)' - r'(?:\#(?P[\w_]+))?' - r'(\.(?P.*))' - ) - asset, macro, ext = p.match(spec).group( - 'asset', 'defname', 'ext' - ) - spec = '%s.%s' % (asset, ext) + asset, macro, ext = self._crack_spec(spec) + spec_without_macro = '%s.%s' % (asset, ext) try: - package_name, filename = spec.split(':', 1) + package_name, filename = spec_without_macro.split(':', 1) except ValueError: # pragma: no cover # somehow we were passed a relative pathname; this # should die package_name = caller_package(4).__name__ - filename = spec + filename = spec_without_macro abspath = pkg_resources.resource_filename(package_name, filename) if not pkg_resources.resource_exists(package_name, filename): raise ValueError( - 'Missing template asset: %s (%s)' % (spec, abspath)) + 'Missing template asset: %s (%s)' % ( + spec_without_macro, abspath) + ) renderer = self.impl(abspath, self, macro=macro) settings = info.settings if not settings.get('reload_assets'): diff --git a/pyramid/tests/fixtures/withmacro.pt b/pyramid/tests/fixtures/withmacro.pt index 8bca01e4d..6fa654645 100644 --- a/pyramid/tests/fixtures/withmacro.pt +++ b/pyramid/tests/fixtures/withmacro.pt @@ -1,4 +1,5 @@ +Outside macro Hello! diff --git a/pyramid/tests/test_chameleon_zpt.py b/pyramid/tests/test_chameleon_zpt.py index 37538e83e..5ac57f869 100644 --- a/pyramid/tests/test_chameleon_zpt.py +++ b/pyramid/tests/test_chameleon_zpt.py @@ -132,8 +132,13 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): result = instance.implementation()() self.assertEqual(result, '\n Hello!\n') - - + def test_macro_notsupplied(self): + minimal = self._getTemplatePath('withmacro.pt') + lookup = DummyLookup() + instance = self._makeOne(minimal, lookup) + result = instance.implementation()() + self.assertEqual(result, + '\nOutside macro\n\n Hello!\n\n\n\n') class DummyLookup(object): auto_reload=True diff --git a/pyramid/tests/test_renderers.py b/pyramid/tests/test_renderers.py index af9188abc..cb6c364a7 100644 --- a/pyramid/tests/test_renderers.py +++ b/pyramid/tests/test_renderers.py @@ -295,6 +295,7 @@ class TestChameleonRendererLookup(unittest.TestCase): self.assertEqual(factory.kw, {'macro':None}) def test___call__spec_withmacro(self): + from pyramid.interfaces import ITemplateRenderer import os from pyramid import tests module_name = tests.__name__ @@ -302,10 +303,11 @@ class TestChameleonRendererLookup(unittest.TestCase): renderer = {} factory = DummyFactory(renderer) spec = '%s:%s' % (module_name, relpath) + reg = self.config.registry info = DummyRendererInfo({ 'name':spec, 'package':None, - 'registry':self.config.registry, + 'registry':reg, 'settings':{}, 'type':'type', }) @@ -318,6 +320,9 @@ class TestChameleonRendererLookup(unittest.TestCase): 'withmacro.pt') self.assertTrue(factory.path.startswith(path)) self.assertEqual(factory.kw, {'macro':'foo'}) + self.assertTrue( + reg.getUtility(ITemplateRenderer, name=spec) is renderer + ) def test___call__reload_assets_true(self): import pyramid.tests -- cgit v1.2.3 From 66d277a1f6cdf752c0fd3716c3ef1780421b4eb1 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 5 Oct 2012 14:26:07 -0400 Subject: garden --- CHANGES.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index e40401528..4b3dabbec 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -14,6 +14,13 @@ Bug Fixes 1.4 too (a registry is attached to a request passed to bootstrap or prepare). +- When registering a view configuration that named a Chameleon ZPT renderer + with a macro name in it (e.g. ``renderer='some/template#somemacro.pt``) as + well as a view configuration without a macro name it it that pointed to the + same template (e.g. ``renderer='some/template.pt'), internal caching could + confuse the two, and your code might have rendered one instead of the + other. + 1.4a2 (2012-09-27) ================== -- cgit v1.2.3 From 7d8e08ecff656fd0f525a0fd655cdf20915f5fa8 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 5 Oct 2012 14:37:36 -0400 Subject: remove unintended commit --- pyramid/scripts/pserve.py | 37 +++---------------------------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/pyramid/scripts/pserve.py b/pyramid/scripts/pserve.py index 533f708fc..9fbf0729a 100644 --- a/pyramid/scripts/pserve.py +++ b/pyramid/scripts/pserve.py @@ -150,8 +150,7 @@ class PServeCommand(object): _reloader_environ_key = 'PYTHON_RELOADER_SHOULD_RUN' _monitor_environ_key = 'PASTE_MONITOR_SHOULD_RUN' - possible_subcommands = ('start', 'stop', 'restart', 'status', - 'handle_reload_error') + possible_subcommands = ('start', 'stop', 'restart', 'status') def __init__(self, argv, quiet=False): self.quiet = quiet @@ -192,34 +191,6 @@ class PServeCommand(object): install_reloader(int(self.options.reload_interval), [app_spec]) # if self.requires_config_file: # watch_file(self.args[0]) - if cmd == 'handle_reload_error': - self.out( - 'There was a reload error: your application did not ' - 'start properly when restarted by the reloader. You ' - 'will need to examine the traceback above, and fix ' - 'the issue. The process will restart after each code ' - 'change until the problem is fixed. In some ' - 'circumstances (such as when there is an ImportError ' - 'raised at module scope), changes you make to the ' - 'offending module will not cause a restart ' - 'and you will need to change the __init__.py ' - 'of your application to force a reload. If that ' - 'does not work, you will need to restart the process ' - 'by hand.') - app_name = self.options.app_name - base = os.getcwd() - vars = self.parse_vars(restvars) - if not self._scheme_re.search(app_spec): - app_spec = 'config:' + app_spec - try: # populate sys.modules - app = self.loadapp( - app_spec, name=app_name, - relative_to=base, global_conf=vars) - except: # but ignore any exceptions - pass - while 1: - time.sleep(1) - else: return self.restart_with_reloader() @@ -555,10 +526,8 @@ class PServeCommand(object): if reloader: # Reloader always exits with code 3; but if we are # a monitor, any exit code will restart - while exit_code != 3: - handle_error_args = args + ['handle_reload_error'] - proc = subprocess.Popen(handle_error_args, env=new_environ) - exit_code = proc.wait() + if exit_code != 3: + return exit_code if self.verbose > 0: self.out('%s %s %s' % ('-' * 20, 'Restarting', '-' * 20)) -- cgit v1.2.3 From 1273d56ee5c038f447dce0525844cd3ea6c15e4d Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 7 Oct 2012 02:03:47 -0400 Subject: - The Configurator ``testing_securitypolicy`` method now returns the policy object it creates. - The Configurator ``testing_securitypolicy`` method accepts two new arguments: ``remember_result`` and ``forget_result``. If supplied, these values influence the result of the policy's ``remember`` and ``forget`` methods, respectively. - The DummySecurityPolicy created by ``testing_securitypolicy`` now sets a ``forgotten`` value on the policy (the value ``True``) when its ``forget`` method is called. - The DummySecurityPolicy created by ``testing_securitypolicy`` now sets a ``remembered`` value on the policy, which is the value of the ``principal`` argument it's called with when its ``remember`` method is called. --- CHANGES.txt | 19 +++++++++++++++++++ pyramid/config/testing.py | 26 ++++++++++++++++++++++++-- pyramid/testing.py | 15 ++++++++++++--- pyramid/tests/test_config/test_testing.py | 24 ++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 4b3dabbec..df4ada7e9 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -21,6 +21,25 @@ Bug Fixes confuse the two, and your code might have rendered one instead of the other. +Features +-------- + +- The Configurator ``testing_securitypolicy`` method now returns the policy + object it creates. + +- The Configurator ``testing_securitypolicy`` method accepts two new + arguments: ``remember_result`` and ``forget_result``. If supplied, these + values influence the result of the policy's ``remember`` and ``forget`` + methods, respectively. + +- The DummySecurityPolicy created by ``testing_securitypolicy`` now sets a + ``forgotten`` value on the policy (the value ``True``) when its ``forget`` + method is called. + +- The DummySecurityPolicy created by ``testing_securitypolicy`` now sets a + ``remembered`` value on the policy, which is the value of the ``principal`` + argument it's called with when its ``remember`` method is called. + 1.4a2 (2012-09-27) ================== diff --git a/pyramid/config/testing.py b/pyramid/config/testing.py index f40cf25a7..abbbffc10 100644 --- a/pyramid/config/testing.py +++ b/pyramid/config/testing.py @@ -19,7 +19,8 @@ from pyramid.config.util import action_method class TestingConfiguratorMixin(object): # testing API def testing_securitypolicy(self, userid=None, groupids=(), - permissive=True): + permissive=True, remember_result=None, + forget_result=None): """Unit/integration testing helper: Registers a pair of faux :app:`Pyramid` security policies: a :term:`authentication policy` and a :term:`authorization policy`. @@ -31,6 +32,24 @@ class TestingConfiguratorMixin(object): nonpermissive :term:`authorization policy` is registered; this policy denies all access. + ``remember_result``, if provided, should be the result returned by + the ``remember`` method of the faux authentication policy. If it is + not provided (or it is provided, and is ``None``), the default value + ``[]`` (the empty list) will be returned by ``remember``. + + .. note:: + + ``remember_result`` is new as of Pyramid 1.4. + + ``forget_result``, if provided, should be the result returned by + the ``forget`` method of the faux authentication policy. If it is + not provided (or it is provided, and is ``None``), the default value + ``[]`` (the empty list) will be returned by ``forget``. + + .. note:: + + ``forget_result`` is new as of Pyramid 1.4. + The behavior of the registered :term:`authentication policy` depends on the values provided for the ``userid`` and ``groupids`` argument. The authentication policy will return @@ -47,9 +66,12 @@ class TestingConfiguratorMixin(object): :func:`pyramid.security.principals_allowed_by_permission`. """ from pyramid.testing import DummySecurityPolicy - policy = DummySecurityPolicy(userid, groupids, permissive) + policy = DummySecurityPolicy( + userid, groupids, permissive, remember_result, forget_result + ) self.registry.registerUtility(policy, IAuthorizationPolicy) self.registry.registerUtility(policy, IAuthenticationPolicy) + return policy def testing_resources(self, resources): """Unit/integration testing helper: registers a dictionary of diff --git a/pyramid/testing.py b/pyramid/testing.py index 9e8f2bff3..cecf13469 100644 --- a/pyramid/testing.py +++ b/pyramid/testing.py @@ -53,10 +53,17 @@ class DummyRootFactory(object): class DummySecurityPolicy(object): """ A standin for both an IAuthentication and IAuthorization policy """ - def __init__(self, userid=None, groupids=(), permissive=True): + def __init__(self, userid=None, groupids=(), permissive=True, + remember_result=None, forget_result=None): self.userid = userid self.groupids = groupids self.permissive = permissive + if remember_result is None: + remember_result = [] + if forget_result is None: + forget_result = [] + self.remember_result = remember_result + self.forget_result = forget_result def authenticated_userid(self, request): return self.userid @@ -73,10 +80,12 @@ class DummySecurityPolicy(object): return effective_principals def remember(self, request, principal, **kw): - return [] + self.remembered = principal + return self.remember_result def forget(self, request): - return [] + self.forgotten = True + return self.forget_result def permits(self, context, principals, permission): return self.permissive diff --git a/pyramid/tests/test_config/test_testing.py b/pyramid/tests/test_config/test_testing.py index 6c048b46d..1089f09fc 100644 --- a/pyramid/tests/test_config/test_testing.py +++ b/pyramid/tests/test_config/test_testing.py @@ -23,6 +23,30 @@ class TestingConfiguratorMixinTests(unittest.TestCase): self.assertEqual(ut.groupids, ('group1', 'group2')) self.assertEqual(ut.permissive, False) + def test_testing_securitypolicy_remember_result(self): + from pyramid.security import remember + config = self._makeOne(autocommit=True) + pol = config.testing_securitypolicy( + 'user', ('group1', 'group2'), + permissive=False, remember_result=True) + request = DummyRequest() + request.registry = config.registry + val = remember(request, 'fred') + self.assertEqual(pol.remembered, 'fred') + self.assertEqual(val, True) + + def test_testing_securitypolicy_forget_result(self): + from pyramid.security import forget + config = self._makeOne(autocommit=True) + pol = config.testing_securitypolicy( + 'user', ('group1', 'group2'), + permissive=False, forget_result=True) + request = DummyRequest() + request.registry = config.registry + val = forget(request) + self.assertEqual(pol.forgotten, True) + self.assertEqual(val, True) + def test_testing_resources(self): from pyramid.traversal import find_resource from pyramid.interfaces import ITraverser -- cgit v1.2.3