summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-11-28 16:19:04 -0500
committerChris McDonough <chrism@plope.com>2011-11-28 16:19:04 -0500
commitdafb0b3271f525fb8552d155a4dd840ced1656c8 (patch)
tree786cccbf8f2287be8e2fa43afd33e503b5366739
parent8786a5719950900ba7a8390323476076e737ac9e (diff)
parent14e5fa938b5354154f724101f444b1826b01aa3a (diff)
downloadpyramid-dafb0b3271f525fb8552d155a4dd840ced1656c8.tar.gz
pyramid-dafb0b3271f525fb8552d155a4dd840ced1656c8.tar.bz2
pyramid-dafb0b3271f525fb8552d155a4dd840ced1656c8.zip
merge master to feature.introspection
-rw-r--r--.gitmodules3
-rw-r--r--CHANGES.txt17
-rw-r--r--docs/.gitignore1
-rw-r--r--docs/Makefile8
m---------docs/_themes0
-rw-r--r--docs/api/paster.rst11
-rw-r--r--docs/conf.py29
-rw-r--r--docs/glossary.rst5
-rw-r--r--docs/narr/MyProject/myproject/static/pylons.css15
-rw-r--r--docs/narr/MyProject/myproject/templates/mytemplate.pt76
-rw-r--r--docs/tutorials/wiki/authorization.rst37
-rw-r--r--docs/tutorials/wiki/basiclayout.rst4
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/login.py43
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/views.py45
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/login.py43
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/views.py45
-rw-r--r--docs/tutorials/wiki/tests.rst7
-rw-r--r--docs/tutorials/wiki2/authorization.rst153
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst195
-rw-r--r--docs/tutorials/wiki2/definingmodels.rst103
-rw-r--r--docs/tutorials/wiki2/definingviews.rst161
-rw-r--r--docs/tutorials/wiki2/installation.rst148
-rw-r--r--docs/tutorials/wiki2/src/authorization/README.txt3
-rw-r--r--docs/tutorials/wiki2/src/authorization/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/authorization/production.ini1
-rw-r--r--docs/tutorials/wiki2/src/authorization/setup.py3
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/__init__.py25
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/login.py37
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/models.py37
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/scripts/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/scripts/populate.py35
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/security.py1
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/tests.py23
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/views.py76
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/README.txt3
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/production.ini1
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/setup.py2
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py10
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/models.py37
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/populate.py35
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt2
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py25
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/views.py14
-rw-r--r--docs/tutorials/wiki2/src/models/README.txt3
-rw-r--r--docs/tutorials/wiki2/src/models/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/models/production.ini1
-rw-r--r--docs/tutorials/wiki2/src/models/setup.py2
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/__init__.py12
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/models.py33
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/scripts/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/scripts/populate.py35
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt2
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/tests.py24
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/views.py14
-rw-r--r--docs/tutorials/wiki2/src/tests/README.txt3
-rw-r--r--docs/tutorials/wiki2/src/tests/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/tests/production.ini1
-rw-r--r--docs/tutorials/wiki2/src/tests/setup.py3
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/__init__.py25
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/login.py37
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/models.py37
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/scripts/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/scripts/populate.py36
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/security.py1
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/tests.py63
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/views.py76
-rw-r--r--docs/tutorials/wiki2/src/views/README.txt3
-rw-r--r--docs/tutorials/wiki2/src/views/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/views/production.ini1
-rw-r--r--docs/tutorials/wiki2/src/views/setup.py2
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/__init__.py17
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/models.py30
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/scripts/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/scripts/populate.py35
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt2
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/tests.py17
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/views.py17
-rw-r--r--docs/tutorials/wiki2/tests.rst4
-rw-r--r--pyramid/asset.py6
-rw-r--r--pyramid/authentication.py32
-rw-r--r--pyramid/authorization.py13
-rw-r--r--pyramid/config/__init__.py43
-rw-r--r--pyramid/config/factories.py10
-rw-r--r--pyramid/config/i18n.py8
-rw-r--r--pyramid/config/rendering.py17
-rw-r--r--pyramid/config/routes.py16
-rw-r--r--pyramid/config/security.py12
-rw-r--r--pyramid/config/testing.py10
-rw-r--r--pyramid/config/tweens.py16
-rw-r--r--pyramid/config/util.py16
-rw-r--r--pyramid/config/views.py87
-rw-r--r--pyramid/encode.py12
-rw-r--r--pyramid/events.py12
-rw-r--r--pyramid/exceptions.py6
-rw-r--r--pyramid/httpexceptions.py11
-rw-r--r--pyramid/i18n.py19
-rw-r--r--pyramid/interfaces.py6
-rw-r--r--pyramid/mako_templating.py20
-rw-r--r--pyramid/paster.py54
-rw-r--r--pyramid/renderers.py33
-rw-r--r--pyramid/request.py25
-rw-r--r--pyramid/router.py51
-rw-r--r--pyramid/scaffolds/__init__.py13
-rw-r--r--pyramid/scaffolds/alchemy/+package+/models.py16
-rw-r--r--pyramid/scaffolds/alchemy/+package+/scripts/populate.py35
-rw-r--r--pyramid/scaffolds/alchemy/+package+/scripts/populate.py_tmpl27
-rw-r--r--pyramid/scaffolds/alchemy/+package+/tests.py_tmpl2
-rw-r--r--pyramid/scaffolds/alchemy/+package+/views.py_tmpl8
-rw-r--r--pyramid/scripting.py8
-rw-r--r--pyramid/scripts/pserve.py4
-rw-r--r--pyramid/scripts/pshell.py4
-rw-r--r--pyramid/security.py10
-rw-r--r--pyramid/session.py13
-rw-r--r--pyramid/static.py35
-rw-r--r--pyramid/testing.py59
-rw-r--r--pyramid/tests/test_paster.py80
-rw-r--r--pyramid/traversal.py33
-rw-r--r--pyramid/tweens.py7
-rw-r--r--pyramid/url.py23
-rw-r--r--pyramid/urldispatch.py30
-rw-r--r--pyramid/view.py19
123 files changed, 1875 insertions, 1186 deletions
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 45397942b..000000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "docs/_themes"]
- path = docs/_themes
- url = git://github.com/Pylons/pylons_sphinx_theme.git
diff --git a/CHANGES.txt b/CHANGES.txt
index 183c7406b..c1a4f0216 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -17,6 +17,14 @@ Features
- ``bpython`` interpreter compatibility in ``pshell``. See the "Command-Line
Pyramid" narrative docs chapter for more information.
+- Added ``get_appsettings`` API function to the ``pyramid.paster`` module.
+ This function returns the settings defined within an ``[app:...]`` section
+ in a PasteDeploy ini file.
+
+- Added ``setup_logging`` API function to the ``pyramid.paster`` module.
+ This function sets up Python logging according to the logging configuration
+ in a PasteDeploy ini file.
+
Bug Fixes
---------
@@ -60,7 +68,7 @@ Backwards Incompatibilities
``paste.httpserver`` server. Rationale: Rationale: the Paste and
PasteScript packages do not run under Python 3.
-- The ``pshell`` command (nee "paster pshell") no longer accepts a
+- The ``pshell`` command (see "paster pshell") no longer accepts a
``--disable-ipython`` command-line argument. Instead, it accepts a ``-p``
or ``--python-shell`` argument, which can be any of the values ``python``,
``ipython`` or ``bpython``.
@@ -78,6 +86,13 @@ Dependencies
- Pyramid no longer depends on the Paste or PasteScript packages.
+Documentation
+-------------
+
+- The SQLAlchemy Wiki tutorial has been updated. It now uses
+ ``@view_config`` decorators and an explicit database population script.
+
+- Minor updates to the ZODB Wiki tutorial.
Scaffolds
---------
diff --git a/docs/.gitignore b/docs/.gitignore
index 30d731d4a..da7abd0c0 100644
--- a/docs/.gitignore
+++ b/docs/.gitignore
@@ -1,3 +1,4 @@
+_themes
_build
diff --git a/docs/Makefile b/docs/Makefile
index 373d549af..bb381fc53 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -23,9 +23,9 @@ help:
@echo " linkcheck to check all external links for integrity"
clean:
- -rm -rf _build/* _themes
+ -rm -rf _build/*
-html: _themes
+html:
mkdir -p _build/html _build/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
@echo
@@ -47,7 +47,7 @@ pickle:
web: pickle
-htmlhelp: _themes
+htmlhelp:
mkdir -p _build/htmlhelp _build/doctrees
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
@echo
@@ -84,5 +84,3 @@ epub:
@echo
@echo "Build finished. The epub file is in _build/epub."
-_themes:
- cd ..; git submodule update --init; cd docs
diff --git a/docs/_themes b/docs/_themes
deleted file mode 160000
-Subproject 03e5e5aaaeddc4c9aea887478c7e7b379a127b6
diff --git a/docs/api/paster.rst b/docs/api/paster.rst
index 2a32e07e9..3f7a1c364 100644
--- a/docs/api/paster.rst
+++ b/docs/api/paster.rst
@@ -5,13 +5,10 @@
.. automodule:: pyramid.paster
- .. function:: get_app(config_uri, name=None)
+ .. autofunction:: bootstrap
- Return the WSGI application named ``name`` in the PasteDeploy
- config file specified by ``config_uri``.
+ .. autofunction:: get_app(config_uri, name=None)
- If the ``name`` is None, this will attempt to parse the name from
- the ``config_uri`` string expecting the format ``inifile#name``.
- If no name is found, the name will default to "main".
+ .. autofunction:: get_appsettings(config_uri, name=None)
- .. autofunction:: bootstrap
+ .. autofunction:: setup_logging(config_uri)
diff --git a/docs/conf.py b/docs/conf.py
index 20236842b..530703e14 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -141,14 +141,29 @@ if book:
# -----------------------
# Add and use Pylons theme
+from subprocess import call, Popen, PIPE
+
+p = Popen('which git', shell=True, stdout=PIPE)
+git = p.stdout.read().strip()
+cwd = os.getcwd()
+_themes = os.path.join(cwd, '_themes')
+
+if not os.path.isdir(_themes):
+ call([git, 'clone', 'git://github.com/Pylons/pylons_sphinx_theme.git',
+ '_themes'])
+else:
+ os.chdir(_themes)
+ call([git, 'checkout', 'master'])
+ call([git, 'pull'])
+ os.chdir(cwd)
+
sys.path.append(os.path.abspath('_themes'))
html_theme_path = ['_themes']
html_theme = 'pyramid'
-
-html_theme_options = {
- 'github_url': 'https://github.com/Pylons/pyramid'
-}
-
+html_theme_options = dict(
+ github_url='https://github.com/Pylons/pyramid',
+ 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
# given in html_static_path.
@@ -461,7 +476,7 @@ def resig(app, what, name, obj, options, signature, return_annotation):
# -- Options for Epub output ---------------------------------------------------
# Bibliographic Dublin Core info.
-epub_title = 'The Pyramid Web Application Development Framework, Version 1.2'
+epub_title = 'The Pyramid Web Application Development Framework, Version 1.3dev'
epub_author = 'Chris McDonough'
epub_publisher = 'Agendaless Consulting'
epub_copyright = '2008-2011'
@@ -478,7 +493,7 @@ epub_scheme = 'ISBN'
epub_identifier = '0615445675'
# A unique identification for the text.
-epub_uid = 'The Pyramid Web Application Development Framework, Version 1.2'
+epub_uid = 'The Pyramid Web Application Development Framework, Version 1.3dev'
# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
diff --git a/docs/glossary.rst b/docs/glossary.rst
index c98637698..39933cf4c 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -936,3 +936,8 @@ Glossary
email. See its `documentation
<https://docs.pylonsproject.org/projects/pyramid_exclog/dev/>`_.
+ console script
+ A script written to the ``bin`` (on UNIX, or ``Scripts`` on Windows)
+ directory of a Python installation or virtualenv as the result of
+ running ``setup.py install`` or ``setup.py develop``.
+
diff --git a/docs/narr/MyProject/myproject/static/pylons.css b/docs/narr/MyProject/myproject/static/pylons.css
index 33b21ac1a..c54499ddd 100644
--- a/docs/narr/MyProject/myproject/static/pylons.css
+++ b/docs/narr/MyProject/myproject/static/pylons.css
@@ -23,7 +23,7 @@ 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 "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
+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,
@@ -31,19 +31,20 @@ body h2,
body h3,
body h4,
body h5,
-body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
+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,#bottom{width:100%;}
-#top{color:#000000;height:230px;
-background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;}
+#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,.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;}
.app-welcome{margin-top:25px;}
.app-name{color:#000000;font-weight:bold;}
@@ -58,7 +59,7 @@ 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]{width:205px;}
+input[type=text],input[type=password]{width:205px;}
input[type=submit]{background-color:#ddd;font-weight:bold;}
/*Opera Fix*/
body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
diff --git a/docs/narr/MyProject/myproject/templates/mytemplate.pt b/docs/narr/MyProject/myproject/templates/mytemplate.pt
index 97f1e1aa3..ab698123e 100644
--- a/docs/narr/MyProject/myproject/templates/mytemplate.pt
+++ b/docs/narr/MyProject/myproject/templates/mytemplate.pt
@@ -1,42 +1,29 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"
- xml:lang="en"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
<title>The Pyramid Web Application Development Framework</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
- <link rel="shortcut icon"
- href="${request.static_url('myproject:static/favicon.ico')}" />
- <link rel="stylesheet"
- href="${request.static_url('myproject:static/pylons.css')}"
- type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet"
- href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin"
- type="text/css" media="screen" charset="utf-8" />
+ <link rel="shortcut icon" href="/static/favicon.ico" />
+ <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
+ <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
<!--[if lte IE 6]>
- <link rel="stylesheet"
- href="${request.static_url('myproject:static/ie6.css')}"
- type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
</head>
<body>
<div id="wrap">
<div id="top">
<div class="top align-center">
- <div>
- <img src="${request.static_url('myproject:static/pyramid.png')}"
- width="750" height="169" alt="pyramid"/>
- </div>
+ <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div>
</div>
</div>
<div id="middle">
<div class="middle align-center">
<p class="app-welcome">
- Welcome to <span class="app-name">${project}</span>,
- an application generated by<br/>
+ Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
the Pyramid web application development framework.
</p>
</div>
@@ -45,62 +32,45 @@
<div class="bottom">
<div id="left" class="align-right">
<h2>Search documentation</h2>
- <form method="get"
- action="http://docs.pylonsproject.org/pyramid/current/search.html">
- <input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Go" />
- </form>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html">
+ <input type="text" id="q" name="q" value="" />
+ <input type="submit" id="x" value="Go" />
+ </form>
</div>
<div id="right" class="align-left">
<h2>Pyramid links</h2>
<ul class="links">
<li>
- <a href="http://pylonsproject.org">
- Pylons Website
- </a>
+ <a href="http://pylonsproject.org">Pylons Website</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">
- Narrative Documentation
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">
- API Documentation
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">
- Tutorials
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">
- Change History
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">
- Sample Applications
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">
- Support and Development
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a>
</li>
<li>
- <a href="irc://irc.freenode.net#pyramid">
- IRC Channel
- </a>
+ <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
</li>
- </ul>
+ </ul>
</div>
</div>
</div>
</div>
<div id="footer">
- <div class="footer">&copy; Copyright 2008-2010, Agendaless Consulting.</div>
+ <div class="footer">&copy; Copyright 2008-2011, Agendaless Consulting.</div>
</div>
</body>
</html>
diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst
index d900f17a3..fa18d4a41 100644
--- a/docs/tutorials/wiki/authorization.rst
+++ b/docs/tutorials/wiki/authorization.rst
@@ -128,18 +128,24 @@ We'll also add a ``logout`` view to our application and provide a link
to it. This view will clear the credentials of the logged in user and
redirect back to the front page.
-We'll add a different file (for presentation convenience) to add login
-and logout views. Add a file named ``login.py`` to your application
-(in the same directory as ``views.py``) with the following content:
+We'll add these views to the existing ``views.py`` file we have in our
+project. Here's what the ``login`` view callable will look like:
-.. literalinclude:: src/authorization/tutorial/login.py
+.. literalinclude:: src/authorization/tutorial/views.py
+ :pyobject: login
:linenos:
:language: python
-Note that the ``login`` view callable in the ``login.py`` file has *two* view
-configuration decorators. The order of these decorators is unimportant.
-Each just adds a different :term:`view configuration` for the ``login`` view
-callable.
+Here's what the ``logout`` view callable will look like:
+
+.. literalinclude:: src/authorization/tutorial/views.py
+ :pyobject: logout
+ :linenos:
+ :language: python
+
+Note that the ``login`` view callable has *two* view configuration
+decorators. The order of these decorators is unimportant. Each just adds a
+different :term:`view configuration` for the ``login`` view callable.
The first view configuration decorator configures the ``login`` view callable
so it will be invoked when someone visits ``/login`` (when the context is a
@@ -156,14 +162,18 @@ login form. Before being allowed to continue on to the add or edit form, he
will have to provide credentials that give him permission to add or edit via
this login form.
+Note that we're relying on some additional imports within the bodies of these
+views (e.g. ``remember`` and ``forget``). We'll see a rendering of the
+entire views.py file a little later here to show you where those come from.
+
Change Existing Views
~~~~~~~~~~~~~~~~~~~~~
-Then we need to change each of our ``view_page``, ``edit_page`` and
-``add_page`` views in ``views.py`` to pass a "logged in" parameter
-into its template. We'll add something like this to each view body:
+In order to indicate whether the current user is logged in, we need to change
+each of our ``view_page``, ``edit_page`` and ``add_page`` views in
+``views.py`` to pass a "logged in" parameter into its template. We'll add
+something like this to each view body:
-.. ignore-next-block
.. code-block:: python
:linenos:
@@ -174,7 +184,6 @@ We'll then change the return value of each view that has an associated
``renderer`` to pass the resulting ``logged_in`` value to the
template. For example:
-.. ignore-next-block
.. code-block:: python
:linenos:
@@ -219,7 +228,7 @@ Add the ``login.pt`` Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Add a ``login.pt`` template to your templates directory. It's
-referred to within the login view we just added to ``login.py``.
+referred to within the login view we just added to ``views.py``.
.. literalinclude:: src/authorization/tutorial/templates/login.pt
:language: xml
diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst
index 439da24d9..56f817a85 100644
--- a/docs/tutorials/wiki/basiclayout.rst
+++ b/docs/tutorials/wiki/basiclayout.rst
@@ -10,8 +10,8 @@ The source code for this tutorial stage can be browsed via
`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/basiclayout/
<http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/basiclayout/>`_.
-App Startup with ``__init__.py``
---------------------------------
+Appplication Configuration with ``__init__.py``
+------------------------------------------------
A directory on disk can be turned into a Python :term:`package` by containing
an ``__init__.py`` file. Even if empty, this marks a directory as a Python
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/login.py b/docs/tutorials/wiki/src/authorization/tutorial/login.py
deleted file mode 100644
index 11dea050f..000000000
--- a/docs/tutorials/wiki/src/authorization/tutorial/login.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from pyramid.httpexceptions import HTTPFound
-
-from pyramid.security import remember
-from pyramid.security import forget
-from pyramid.view import view_config
-
-from .security import USERS
-
-@view_config(context='.models.Wiki', name='login',
- renderer='templates/login.pt')
-@view_config(context='pyramid.httpexceptions.HTTPForbidden',
- renderer='templates/login.pt')
-def login(request):
- login_url = request.resource_url(request.context, 'login')
- referrer = request.url
- if referrer == login_url:
- referrer = '/' # never use the login form itself as came_from
- came_from = request.params.get('came_from', referrer)
- message = ''
- login = ''
- password = ''
- if 'form.submitted' in request.params:
- login = request.params['login']
- password = request.params['password']
- if USERS.get(login) == password:
- headers = remember(request, login)
- return HTTPFound(location = came_from,
- headers = headers)
- message = 'Failed login'
-
- return dict(
- message = message,
- url = request.application_url + '/login',
- came_from = came_from,
- login = login,
- password = password,
- )
-
-@view_config(context='.models.Wiki', name='logout')
-def logout(request):
- headers = forget(request)
- return HTTPFound(location = request.resource_url(request.context),
- headers = headers)
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views.py b/docs/tutorials/wiki/src/authorization/tutorial/views.py
index 7ac5eeab6..2f0502c17 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/views.py
@@ -2,9 +2,16 @@ from docutils.core import publish_parts
import re
from pyramid.httpexceptions import HTTPFound
+
from pyramid.view import view_config
-from pyramid.security import authenticated_userid
+from pyramid.security import (
+ authenticated_userid,
+ remember,
+ forget,
+ )
+
+from .security import USERS
from .models import Page
# regular expression used to find WikiWords
@@ -72,3 +79,39 @@ def edit_page(context, request):
return dict(page = context,
save_url = request.resource_url(context, 'edit_page'),
logged_in = logged_in)
+
+@view_config(context='.models.Wiki', name='login',
+ renderer='templates/login.pt')
+@view_config(context='pyramid.httpexceptions.HTTPForbidden',
+ renderer='templates/login.pt')
+def login(request):
+ login_url = request.resource_url(request.context, 'login')
+ referrer = request.url
+ if referrer == login_url:
+ referrer = '/' # never use the login form itself as came_from
+ came_from = request.params.get('came_from', referrer)
+ message = ''
+ login = ''
+ password = ''
+ if 'form.submitted' in request.params:
+ login = request.params['login']
+ password = request.params['password']
+ if USERS.get(login) == password:
+ headers = remember(request, login)
+ return HTTPFound(location = came_from,
+ headers = headers)
+ message = 'Failed login'
+
+ return dict(
+ message = message,
+ url = request.application_url + '/login',
+ came_from = came_from,
+ login = login,
+ password = password,
+ )
+
+@view_config(context='.models.Wiki', name='logout')
+def logout(request):
+ headers = forget(request)
+ return HTTPFound(location = request.resource_url(request.context),
+ headers = headers)
diff --git a/docs/tutorials/wiki/src/tests/tutorial/login.py b/docs/tutorials/wiki/src/tests/tutorial/login.py
deleted file mode 100644
index 11dea050f..000000000
--- a/docs/tutorials/wiki/src/tests/tutorial/login.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from pyramid.httpexceptions import HTTPFound
-
-from pyramid.security import remember
-from pyramid.security import forget
-from pyramid.view import view_config
-
-from .security import USERS
-
-@view_config(context='.models.Wiki', name='login',
- renderer='templates/login.pt')
-@view_config(context='pyramid.httpexceptions.HTTPForbidden',
- renderer='templates/login.pt')
-def login(request):
- login_url = request.resource_url(request.context, 'login')
- referrer = request.url
- if referrer == login_url:
- referrer = '/' # never use the login form itself as came_from
- came_from = request.params.get('came_from', referrer)
- message = ''
- login = ''
- password = ''
- if 'form.submitted' in request.params:
- login = request.params['login']
- password = request.params['password']
- if USERS.get(login) == password:
- headers = remember(request, login)
- return HTTPFound(location = came_from,
- headers = headers)
- message = 'Failed login'
-
- return dict(
- message = message,
- url = request.application_url + '/login',
- came_from = came_from,
- login = login,
- password = password,
- )
-
-@view_config(context='.models.Wiki', name='logout')
-def logout(request):
- headers = forget(request)
- return HTTPFound(location = request.resource_url(request.context),
- headers = headers)
diff --git a/docs/tutorials/wiki/src/tests/tutorial/views.py b/docs/tutorials/wiki/src/tests/tutorial/views.py
index 7ac5eeab6..2f0502c17 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/views.py
+++ b/docs/tutorials/wiki/src/tests/tutorial/views.py
@@ -2,9 +2,16 @@ from docutils.core import publish_parts
import re
from pyramid.httpexceptions import HTTPFound
+
from pyramid.view import view_config
-from pyramid.security import authenticated_userid
+from pyramid.security import (
+ authenticated_userid,
+ remember,
+ forget,
+ )
+
+from .security import USERS
from .models import Page
# regular expression used to find WikiWords
@@ -72,3 +79,39 @@ def edit_page(context, request):
return dict(page = context,
save_url = request.resource_url(context, 'edit_page'),
logged_in = logged_in)
+
+@view_config(context='.models.Wiki', name='login',
+ renderer='templates/login.pt')
+@view_config(context='pyramid.httpexceptions.HTTPForbidden',
+ renderer='templates/login.pt')
+def login(request):
+ login_url = request.resource_url(request.context, 'login')
+ referrer = request.url
+ if referrer == login_url:
+ referrer = '/' # never use the login form itself as came_from
+ came_from = request.params.get('came_from', referrer)
+ message = ''
+ login = ''
+ password = ''
+ if 'form.submitted' in request.params:
+ login = request.params['login']
+ password = request.params['password']
+ if USERS.get(login) == password:
+ headers = remember(request, login)
+ return HTTPFound(location = came_from,
+ headers = headers)
+ message = 'Failed login'
+
+ return dict(
+ message = message,
+ url = request.application_url + '/login',
+ came_from = came_from,
+ login = login,
+ password = password,
+ )
+
+@view_config(context='.models.Wiki', name='logout')
+def logout(request):
+ headers = forget(request)
+ return HTTPFound(location = request.resource_url(request.context),
+ headers = headers)
diff --git a/docs/tutorials/wiki/tests.rst b/docs/tutorials/wiki/tests.rst
index 941302d67..1ddb8f408 100644
--- a/docs/tutorials/wiki/tests.rst
+++ b/docs/tutorials/wiki/tests.rst
@@ -9,10 +9,9 @@ that it continues to work after some changes are made in the future.
Test the Models
===============
-We write tests for the model
-classes and the appmaker. Changing ``tests.py``, we'll write a separate test
-class for each model class, and we'll write a test class for the
-``appmaker``.
+We write tests for the model classes and the appmaker. Changing
+``tests.py``, we'll write a separate test class for each model class, and
+we'll write a test class for the ``appmaker``.
To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided as a
result of the ``zodb`` project generator. We'll add three test
diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst
index df5e228fd..ab04ea405 100644
--- a/docs/tutorials/wiki2/authorization.rst
+++ b/docs/tutorials/wiki2/authorization.rst
@@ -4,27 +4,22 @@
Adding Authorization
====================
-Our application currently allows anyone with access to the server to
-view, edit, and add pages to our wiki. For purposes of demonstration
-we'll change our application to allow only people whom possess a
-specific username (`editor`) to add and edit wiki pages but we'll
-continue allowing anyone with access to the server to view pages.
-:app:`Pyramid` provides facilities for :term:`authorization` and
-:term:`authentication`. We'll make use of both features to provide security
-to our application.
-
-We will add an :term:`authentication policy` and an
-:term:`authorization policy` to our :term:`application
-registry`, add a ``security.py`` module, create a :term:`root factory`
-with an :term:`ACL`, and add :term:`permission` declarations to
-the ``edit_page`` and ``add_page`` views.
-
-Then we will add ``login`` and ``logout`` views, and modify the
-existing views to make them return a ``logged_in`` flag to the
-renderer.
-
-Finally, we will add a ``login.pt`` template and change the existing
-``view.pt`` and ``edit.pt`` to show a "Logout" link when not logged in.
+:app:`Pyramid` provides facilities for :term:`authentication` and
+:term:`authorization`. We'll make use of both features to provide security
+to our application. Our application currently allows anyone with access to
+the server to view, edit, and add pages to our wiki. We'll change our
+application to allow only people whom possess a specific username (`editor`)
+to add and edit wiki pages but we'll continue allowing anyone with access to
+the server to view pages.
+
+To do so, we'll add an :term:`authentication policy` and an
+:term:`authorization policy`. We'll also add a ``security.py`` module,
+create a :term:`root factory` with an :term:`ACL`, and add :term:`permission`
+declarations to the ``edit_page`` and ``add_page`` views. Then we'll add
+``login`` and ``logout`` views, and modify the existing views to make them
+return a ``logged_in`` flag to the renderer. Finally, we will add a
+``login.pt`` template and change the existing ``view.pt`` and ``edit.pt`` to
+show a "Logout" link when not logged in.
The source code for this tutorial stage can be browsed at
`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src/authorization/
@@ -54,7 +49,7 @@ inside our ``models.py`` file. Add the following statements to your
``models.py`` file:
.. literalinclude:: src/authorization/tutorial/models.py
- :lines: 3-4,45-50
+ :lines: 1-4,35-39
:linenos:
:language: python
@@ -92,14 +87,14 @@ We'll change our ``__init__.py`` file to enable an
declarative security checking. We need to import the new policies:
.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 2-3,8
+ :lines: 2-3,7
:linenos:
:language: python
Then, we'll add those policies to the configuration:
.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 15-21
+ :lines: 16-22
:linenos:
:language: python
@@ -111,49 +106,12 @@ represented by this policy: it is required. The ``callback`` is a
``groupfinder`` function in the current directory's ``security.py`` file. We
haven't added that module yet, but we're about to.
-We'll also change ``__init__.py``, adding a call to
-:meth:`pyramid.config.Configurator.add_view` that points at our ``login``
-:term:`view callable`. This is also known as a :term:`forbidden view`:
-
-.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 25,41-43
- :linenos:
- :language: python
-
-A forbidden view configures our newly created login view to show up when
-:app:`Pyramid` detects that a view invocation can not be authorized.
-
-A ``logout`` :term:`view callable` will allow users to log out later:
-
-.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 26,34
- :linenos:
- :language: python
-
-We'll also add ``permission`` arguments with the value ``edit`` to the
-``edit_page`` and ``add_page`` views. This indicates that the view
-callables which these views reference cannot be invoked without the
-authenticated user possessing the ``edit`` permission with respect to the
-current context.
-
-.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 37-40
- :linenos:
- :language: python
-
-Adding these ``permission`` arguments causes Pyramid to make the
-assertion that only users who possess the effective ``edit`` permission at
-the time of the request may invoke those two views. We've granted the
-``group:editors`` principal the ``edit`` permission at the root model via its
-ACL, so only the a user whom is a member of the group named ``group:editors``
-will able to invoke the views associated with the ``add_page`` or
-``edit_page`` routes.
-
Viewing Your Changes
~~~~~~~~~~~~~~~~~~~~
-When we're done configuring a root factory, adding an authorization policy,
-and adding views, your application's ``__init__.py`` will look like this:
+When we're done configuring a root factory, adding a authentication and
+authorization policies, and adding routes for ``/login`` and ``/logout``,
+your application's ``__init__.py`` will look like this:
.. literalinclude:: src/authorization/tutorial/__init__.py
:linenos:
@@ -191,30 +149,54 @@ views, the ``editor`` user should be able to add and edit pages.
Adding Login and Logout Views
-----------------------------
-We'll add a ``login`` view callable which renders a login form and
-processes the post from the login form, checking credentials.
+To our ``views.py`` we'll add a ``login`` view callable which renders a login
+form and processes the post from the login form, checking credentials.
We'll also add a ``logout`` view callable to our application and
provide a link to it. This view will clear the credentials of the
logged in user and redirect back to the front page.
-We'll add a different file (for presentation convenience) to add login
-and the logout view callables. Add a file named ``login.py`` to your
-application (in the same directory as ``views.py``) with the following
-content:
+The ``login`` view callable will look something like this:
-.. literalinclude:: src/authorization/tutorial/login.py
+.. literalinclude:: src/authorization/tutorial/views.py
+ :pyobject: login
:linenos:
:language: python
+The ``logout`` view callable will look something like this:
+
+.. literalinclude:: src/authorization/tutorial/views.py
+ :pyobject: logout
+ :linenos:
+ :language: python
+
+The ``login`` view callable is decorated with two ``@view_config``
+decorators, one which associates it with the ``login`` route, the other which
+associates it with the ``HTTPForbidden`` context. The one which associates
+it with the ``login`` route makes it visible when we visit ``/login``. The
+one which associates it with the ``HTTPForbidden`` context makes it the
+:term:`forbidden view`. The forbidden view is displayed whenever Pyramid or
+your application raises an HTTPForbidden exception. In this case, we'll be
+relying on the forbidden view to show the login form whenver someone attempts
+to execute an action which they're not yet authorized to perform.
+
+The ``logout`` view callable is decorated with a ``@view_config`` decorator
+which associates it with the ``logout`` route. This makes it visible when we
+visit ``/login``.
+
+We'll need to import some stuff to service the needs of these two functions:
+the ``HTTPForbidden`` exception, a number of values from the
+``pyramid.security`` module, and a value from our newly added
+``tutorial.security`` package.
+
Changing Existing Views
-----------------------
Then we need to change each of our ``view_page``, ``edit_page`` and
-``add_page`` views in ``views.py`` to pass a "logged in" parameter to its
-template. We'll add something like this to each view body:
+``add_page`` view callables in ``views.py``. Within each of these views,
+we'll need to pass a "logged in" parameter to its template. We'll add
+something like this to each view body:
-.. ignore-next-block
.. code-block:: python
:linenos:
@@ -224,7 +206,6 @@ template. We'll add something like this to each view body:
We'll then change the return value of these views to pass the `resulting
`logged_in`` value to the template, e.g.:
-.. ignore-next-block
.. code-block:: python
:linenos:
@@ -233,6 +214,28 @@ We'll then change the return value of these views to pass the `resulting
logged_in = logged_in,
edit_url = edit_url)
+We'll also need to add a ``permission`` value to the ``@view_config``
+decorator for each of the ``add_page`` and ``edit_page`` view callables. For
+each, we'll add ``permission='edit'``, for example:
+
+.. code-block:: python
+ :linenos:
+
+ @view_config(route_name='edit_page', renderer='templates/edit.pt',
+ permission='edit')
+
+See the ``permission='edit'`` we added there? This indicates that the view
+callables which these views reference cannot be invoked without the
+authenticated user possessing the ``edit`` permission with respect to the
+current :term:`context`.
+
+Adding these ``permission`` arguments causes Pyramid to make the assertion
+that only users who possess the effective ``edit`` permission at the time of
+the request may invoke those two views. We've granted the ``group:editors``
+principal the ``edit`` permission at the root model via its ACL, so only the
+a user whom is a member of the group named ``group:editors`` will able to
+invoke the views associated with the ``add_page`` or ``edit_page`` routes.
+
Adding the ``login.pt`` Template
--------------------------------
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index db8ab1fbe..77658970d 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -2,82 +2,96 @@
Basic Layout
============
-The starter files generated by the ``alchemy`` scaffold are
-basic, but they provide a good orientation for the high-level patterns common
-to most :term:`url dispatch` -based :app:`Pyramid` projects.
+The starter files generated by the ``alchemy`` scaffold are very basic, but
+they provide a good orientation for the high-level patterns common to most
+:term:`url dispatch` -based :app:`Pyramid` projects.
The source code for this tutorial stage can be browsed at
`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src/basiclayout/
<http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src/basiclayout/>`_.
-App Startup with ``__init__.py``
---------------------------------
+Application Configuration with ``__init__.py``
+----------------------------------------------
A directory on disk can be turned into a Python :term:`package` by containing
an ``__init__.py`` file. Even if empty, this marks a directory as a Python
-package. We use ``__init__.py`` both as a package marker and to contain
-configuration code.
+package. We use ``__init__.py`` both as a marker indicating the directory
+it's contained within is a package, and to contain configuration code. Our
+``__init__.py`` file will look like this:
-The generated ``development.ini`` file is read by ``pserve`` which looks for
-the application module in the ``use`` variable of the ``app:main``
-section. The *entry point* is defined in the Setuptools configuration of this
-module, specifically in the ``setup.py`` file. For this tutorial, the *entry
-point* is defined as ``tutorial:main`` and points to a function named
-``main``.
+ .. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :linenos:
+ :language: py
-First we need some imports to support later code:
+Let's go over this piece-by-piece. First, we need some imports to support
+later code:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
:end-before: main
:linenos:
:language: py
-Next we define the main function and create a SQLAlchemy database engine from
-the ``sqlalchemy.`` prefixed settings in the ``development.ini`` file's
-``[app:main]`` section. This will be a URI (something like
-``sqlite://``):
+``__init__.py`` defines a function named ``main``. Here is the entirety of
+the ``main`` function we've defined in our ``__init__.py``:
+
+ .. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :pyobject: main
+ :linenos:
+ :language: py
+
+When you invoke the ``pserve development.ini`` command, the ``main`` function
+above is executed. It accepts some settings and returns a :term:`WSGI`
+application. You can read :ref:`startup_chapter` for details about *how*
+this function is found and called when you run ``pserve``, but for purposes
+of brevity, we'll elide the details here.
+
+The main function first creates a SQLAlchemy database engine using
+``engine_from_config`` from the ``sqlalchemy.`` prefixed settings in the
+``development.ini`` file's ``[app:main]`` section. This will be a URI
+(something like ``sqlite://``):
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 6-9
+ :lines: 9
:linenos:
:language: py
-We then initialize our SQL database using SQLAlchemy, passing
-it the engine:
+``main`` then initializes our SQL database using SQLAlchemy, passing it the
+engine:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
:lines: 10
:language: py
-The next step is to construct a :term:`Configurator`:
+The next step of ``main`` is to construct a :term:`Configurator` object:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
:lines: 11
:language: py
``settings`` is passed to the Configurator as a keyword argument with the
-dictionary values passed by PasteDeploy as the ``**settings`` argument. This
-will be a dictionary of settings parsed from the ``.ini`` file, which
-contains deployment-related values such as ``pyramid.reload_templates``,
+dictionary values passed as the ``**settings`` argument. This will be a
+dictionary of settings parsed from the ``.ini`` file, which contains
+deployment-related values such as ``pyramid.reload_templates``,
``db_string``, etc.
-We now can call :meth:`pyramid.config.Configurator.add_static_view` with the
-arguments ``static`` (the name), and ``tutorial:static`` (the path):
+``'main`` now calls :meth:`pyramid.config.Configurator.add_static_view` with
+two arguments: ``static`` (the name), and ``static`` (the path):
.. literalinclude:: src/basiclayout/tutorial/__init__.py
:lines: 12
:language: py
-This registers a static resource view which will match any URL that starts with
-``/static/``. This will serve up static resources for us from within the
-``static`` directory of our ``tutorial`` package, in this case,
-via ``http://localhost:6543/static/`` and below. With this declaration,
-we're saying that any URL that starts with ``/static`` should go to the
-static view; any remainder of its path (e.g. the ``/foo`` in
-``/static/foo``) will be used to compose a path to a static file resource,
-such as a CSS file.
+This registers a static resource view which will match any URL that starts
+with the prefix ``/static`` (by virtue of the first argument to add_static
+view). This will serve up static resources for us from within the ``static``
+directory of our ``tutorial`` package, in this case, via
+``http://localhost:6543/static/`` and below (by virtue of the second argument
+to add_static_view). With this declaration, we're saying that any URL that
+starts with ``/static`` should go to the static view; any remainder of its
+path (e.g. the ``/foo`` in ``/static/foo``) will be used to compose a path to
+a static file resource, such as a CSS file.
-Using the configurator we can also register a :term:`route configuration`
+Using the configurator ``main`` also registers a :term:`route configuration`
via the :meth:`pyramid.config.Configurator.add_route` method that will be
used when the URL is ``/``:
@@ -88,44 +102,77 @@ used when the URL is ``/``:
Since this route has a ``pattern`` equalling ``/`` it is the route that will
be matched when the URL ``/`` is visted, e.g. ``http://localhost:6543/``.
-Mapping the ``home`` route to code is done by registering a view. You will
-use :meth:`pyramid.config.Configurator.add_view` in :term:`URL dispatch` to
-register views for the routes, mapping your patterns to code:
+``main`` next calls the ``scan`` method of the configurator, which will
+recursively scan our ``tutorial`` package, looking for ``@view_config`` (and
+other special) decorators. When it finds a ``@view_config`` decorator, a
+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-15
+ :lines: 14
:language: py
-The first positional ``add_view`` argument ``tutorial.views.my_view`` is the
-dotted name to a *function* we write (generated by the
-``alchemy`` scaffold) that is given a ``request`` object and
-which returns a response or a dictionary. This view also names a
-``renderer``, which is a template which lives in the ``templates``
-subdirectory of the package. When the ``tutorial.views.my_view`` view
-returns a dictionary, a :term:`renderer` will use this template to create a
-response.
-
-Finally, we use the :meth:`pyramid.config.Configurator.make_wsgi_app`
-method to return a :term:`WSGI` application:
+Finally, ``main`` is finished configuring things, so it uses the
+:meth:`pyramid.config.Configurator.make_wsgi_app` method to return a
+:term:`WSGI` application:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 16
+ :lines: 15
:language: py
-Our final ``__init__.py`` file will look like this:
+View Declarations via ``views.py``
+----------------------------------
- .. literalinclude:: src/basiclayout/tutorial/__init__.py
+Mapping a :term:`route` to code that will be executed when that route's
+pattern matches is done by registering a :term:`view configuration`. Our
+application uses the :meth:`pyramid.view.view_config` decorator to map view
+callables to each route, thereby mapping URL patterns to code.
+
+Here is the entirety of code in the ``views.py`` file within our package:
+
+ .. literalinclude:: src/basiclayout/tutorial/views.py
:linenos:
:language: py
+The important part to point out here is the ``@view_config`` decorator which
+sits atop the ``my_view`` function. In fact, ``@view_config`` is so
+important that we're going to ignore the rest of the code in the module at
+this point just to explain it. The ``@view_config`` decorator associates the
+function it decorates with a :term:`view configuration`. The view
+configuration names a ``route_name`` (``home``), and names a ``renderer``,
+which is a template which lives in the ``templates`` subdirectory of the
+package.
+
+As the result of this view configuration, when the pattern associated with
+the view named ``home`` is matched during a request, the function named
+``my_view`` will be executed. The the function named ``my_view`` returns a
+dictionary; the renderer will use the ``templates/mytemplate.pt`` template to
+create a response based on the values in the dictionary.
+
+Note that the decorated function named ``my_view`` accepts a single argument
+named ``request``. This is the standard call signature for a Pyramid
+:term:`view callable`.
+
+Remember in our ``__init__.py`` when we executed the
+:meth:`pyramid.config.Configurator.scan` method, e.g. ``config.scan()``? The
+purpose of calling the scan method was to find and process this
+``@view_config`` decorator in order to create a view configuration within our
+application. Without being processed by ``scan``, the decorator effectively
+does nothing. ``@view_config`` is inert without being detected via a
+:term:`scan`.
+
Content Models with ``models.py``
---------------------------------
-In a SQLAlchemy-based application, a *model* object is an object
-composed by querying the SQL database which backs an application.
-SQLAlchemy is an "object relational mapper" (an ORM). The
-``models.py`` file is where the ``alchemy`` scaffold
-put the classes that implement our models.
+In a SQLAlchemy-based application, a *model* object is an object composed by
+querying the SQL database. The ``models.py`` file is where the ``alchemy``
+scaffold put the classes that implement our models.
+
+Here is the complete source for ``models.py``:
+
+ .. literalinclude:: src/basiclayout/tutorial/models.py
+ :linenos:
+ :language: py
Let's take a look. First, we need some imports to support later code.
@@ -137,7 +184,7 @@ Let's take a look. First, we need some imports to support later code.
Next we set up a SQLAlchemy "DBSession" object:
.. literalinclude:: src/basiclayout/tutorial/models.py
- :lines: 15-16
+ :lines: 16
:linenos:
:language: py
@@ -161,30 +208,6 @@ within the ``__init__`` function itself. The ``MyModel`` class also has a
``__tablename__`` attribute. This informs SQLAlchemy which table to use to
store the data representing instances of this class.
-Next we define a function named ``populate`` which adds a single
-model instance into our SQL storage and commits a transaction:
-
- .. literalinclude:: src/basiclayout/tutorial/models.py
- :pyobject: populate
- :linenos:
- :language: py
-
-The function doesn't do a lot in this case, but it's there to illustrate
-how an application requiring many objects to be set up could work.
-
-Lastly we have a function named ``initialize_sql`` which receives a SQL
-database engine and binds it to our SQLAlchemy DBSession object. It also
-calls the ``populate`` function, to do initial database population. This
-is the initialization function that is called from __init__.py above.
-
- .. literalinclude:: src/basiclayout/tutorial/models.py
- :pyobject: initialize_sql
- :linenos:
- :language: py
-
-Here is the complete source for ``models.py``:
-
- .. literalinclude:: src/basiclayout/tutorial/models.py
- :linenos:
- :language: py
+That's about all there is to it to models, views, and initialization code in
+our stock application.
diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst
index 083ec0aa8..cd295e993 100644
--- a/docs/tutorials/wiki2/definingmodels.rst
+++ b/docs/tutorials/wiki2/definingmodels.rst
@@ -15,29 +15,25 @@ Making Edits to ``models.py``
.. note::
- There is nothing automagically special about the filename
- ``models.py``. A project may have many models throughout its
- codebase in arbitrarily-named files. Files implementing models
- often have ``model`` in their filenames (or they may live in a
- Python subpackage of your application package named ``models``) ,
- but this is only by convention.
+ There is nothing automagically special about the filename ``models.py``. A
+ project may have many models throughout its codebase in arbitrarily-named
+ files. Files implementing models often have ``model`` in their filenames
+ (or they may live in a Python subpackage of your application package named
+ ``models``) , but this is only by convention.
-The first thing we want to do is remove the stock ``MyModel`` class from the
-generated ``models.py`` file. The ``MyModel`` class is only a sample and
-we're not going to use it.
-
-Next, we'll remove the :class:`sqlalchemy.Unicode` import and replace it
-with :class:`sqlalchemy.Text`.
+Here's what our ``models.py`` file should look like after this step:
.. literalinclude:: src/models/tutorial/models.py
- :lines: 5
:linenos:
:language: py
-Then, we'll add a ``Page`` class. Because this is a SQLAlchemy
-application, this class should inherit from an instance of
-:class:`sqlalchemy.ext.declarative.declarative_base`. Declarative
-SQLAlchemy models are easier to use than directly-mapped ones.
+The first thing we've done is to do is remove the stock ``MyModel`` class
+from the generated ``models.py`` file. The ``MyModel`` class is only a
+sample and we're not going to use it.
+
+Then, we added a ``Page`` class. Because this is a SQLAlchemy application,
+this class inherits from an instance of
+:class:`sqlalchemy.ext.declarative.declarative_base`.
.. literalinclude:: src/models/tutorial/models.py
:pyobject: Page
@@ -54,24 +50,18 @@ in the table. The ``name`` attribute will be a text attribute, each value of
which needs to be unique within the column. The ``data`` attribute is a text
attribute that will hold the body of each page.
-We'll also remove our ``populate`` function. We'll inline the populate step
-into ``initialize_sql``, changing our ``initialize_sql`` function to add a
-FrontPage object to our database at startup time.
+Changing ``scripts/populate.py``
+--------------------------------
-.. literalinclude:: src/models/tutorial/models.py
- :pyobject: initialize_sql
- :linenos:
- :language: python
+We haven't looked at the guts of this file yet, but within the ``scripts``
+directory of your ``tutorial`` package is a file named ``populate.py``. Code
+in this file is executed whenever we run the ``populate_tutorial`` command
+(as we did in the installation step of this tutorial).
-Here, we're using a slightly different binding syntax. It is otherwise
-largely the same as the ``initialize_sql`` in the pcreate-generated
-``models.py``.
-
-Our ``DBSession`` assignment stays the same as the original generated
-``models.py``.
-
-Looking at the Result of all Our Edits to ``models.py``
--------------------------------------------------------
+Since we've changed our model, we need to make changes to our ``populate.py``
+script. In particular, we'll replace our import of ``MyModel`` with one of
+``Page`` and we'll change the very end of the script to create a ``Page``
+rather than a ``MyModel`` and add it to our ``DBSession``.
The result of all of our edits to ``models.py`` will end up looking
something like this:
@@ -80,6 +70,53 @@ something like this:
:linenos:
:language: python
+Repopulating the Database
+-------------------------
+
+Because our model has changed, in order to repopulate the database, we need
+to rerun the ``populate_tutorial`` command to pick up the changes you've made
+to both the models.py file and to the populate.py file. From the root of the
+``tutorial`` project, directory execute the following commands.
+
+On UNIX:
+
+.. code-block:: text
+
+ $ ../bin/populate_tutorial development.ini
+
+On Windows:
+
+.. code-block:: text
+
+ c:\pyramidtut\tutorial> ..\Scripts\populate_tutorial development.ini
+
+Success will look something like this::
+
+ 2011-11-27 01:22:45,277 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ PRAGMA table_info("pages")
+ 2011-11-27 01:22:45,277 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
+ 2011-11-27 01:22:45,277 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ CREATE TABLE pages (
+ id INTEGER NOT NULL,
+ name TEXT,
+ data TEXT,
+ PRIMARY KEY (id),
+ UNIQUE (name)
+ )
+
+
+ 2011-11-27 01:22:45,278 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
+ 2011-11-27 01:22:45,397 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ COMMIT
+ 2011-11-27 01:22:45,400 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ BEGIN (implicit)
+ 2011-11-27 01:22:45,401 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ INSERT INTO pages (name, data) VALUES (?, ?)
+ 2011-11-27 01:22:45,401 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ ('FrontPage', 'This is the front page')
+ 2011-11-27 01:22:45,402 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ COMMIT
+
Viewing the Application in a Browser
------------------------------------
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index 21b97f7aa..7f533b635 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -2,34 +2,19 @@
Defining Views
==============
-A :term:`view callable` in a :term:`url dispatch` -based :app:`Pyramid`
-application is typically a simple Python function that accepts a single
-parameter named :term:`request`. A view callable is assumed to return a
-:term:`response` object.
-
-.. note::
-
- A :app:`Pyramid` view can also be defined as callable
- which accepts *two* arguments: a :term:`context` and a
- :term:`request`. You'll see this two-argument pattern used in
- other :app:`Pyramid` tutorials and applications. Either calling
- convention will work in any :app:`Pyramid` application; the
- calling conventions can be used interchangeably as necessary. In
- :term:`url dispatch` based applications, however, the context
- object is rarely used in the view body itself, so within this
- tutorial we define views as callables that accept only a request to
- avoid the visual "noise". If you do need the ``context`` within a
- view function that only takes the request as a single argument, you
- can obtain it via ``request.context``.
-
-The request passed to every view that is called as the result of a route
-match has an attribute named ``matchdict`` that contains the elements placed
-into the URL by the ``pattern`` of a ``route`` statement. For instance, if a
-call to :meth:`pyramid.config.Configurator.add_route` in ``__init__.py`` had
-the pattern ``{one}/{two}``, and the URL at ``http://example.com/foo/bar``
-was invoked, matching this pattern, the ``matchdict`` dictionary attached to
-the request passed to the view would have a ``'one'`` key with the value
-``'foo'`` and a ``'two'`` key with the value ``'bar'``.
+A :term:`view callable` in a :app:`Pyramid` application is typically a simple
+Python function that accepts a single parameter named :term:`request`. A
+view callable is assumed to return a :term:`response` object.
+
+The request object passed to every view that is called as the result of a
+route match has an attribute named ``matchdict`` that contains the elements
+placed into the URL by the ``pattern`` of a ``route`` statement. For
+instance, if a call to :meth:`pyramid.config.Configurator.add_route` in
+``__init__.py`` had the pattern ``{one}/{two}``, and the URL at
+``http://example.com/foo/bar`` was invoked, matching this pattern, the
+``matchdict`` dictionary attached to the request passed to the view would
+have a ``'one'`` key with the value ``'foo'`` and a ``'two'`` key with the
+value ``'bar'``.
The source code for this tutorial stage can be browsed at
`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src/views/
@@ -52,24 +37,56 @@ Our resulting ``setup.py`` should look like so:
:linenos:
:language: python
-.. note:: After these new dependencies are added, you will need to
- rerun ``python setup.py develop`` inside the root of the
- ``tutorial`` package to obtain and register the newly added
- dependency package.
+Running ``setup.py develop``
+============================
+
+Since a new software dependency was added, you will need to rerun ``python
+setup.py develop`` inside the root of the ``tutorial`` package to obtain and
+register the newly added dependency distribution.
+
+Make sure your current working directory is the root of the project (the
+directory in which setup.py lives) and execute the following command.
+
+On UNIX:
+
+.. code-block:: text
+
+ $ cd tutorial
+ $ ../bin/python setup.py develop
-Adding View Functions
-=====================
+On Windows:
-We'll get rid of our ``my_view`` view function in our ``views.py`` file.
-It's only an example and isn't relevant to our application.
+.. code-block:: text
-Then we're going to add four :term:`view callable` functions to our
-``views.py`` module. One view callable (named ``view_wiki``) will display
-the wiki itself (it will answer on the root URL), another named ``view_page``
-will display an individual page, another named ``add_page`` will allow a page
-to be added, and a final view callable named ``edit_page`` will allow a page
-to be edited. We'll describe each one briefly and show the resulting
-``views.py`` file afterward.
+ c:\pyramidtut> cd tutorial
+ c:\pyramidtut\tutorial> ..\Scripts\python setup.py develop
+
+Success executing this command will end with a line to the console something
+like::
+
+ Finished processing dependencies for tutorial==0.0
+
+Changing the ``views.py`` File
+==============================
+
+We're going to edit our ``views.py`` in a rather major way. The result of
+all of our edits to ``views.py`` will leave it looking like this:
+
+.. literalinclude:: src/views/tutorial/views.py
+ :linenos:
+ :language: python
+
+We've gotten rid of the ``my_view`` view function and its decorator that was
+added when we originally rendered the ``alchemy`` scaffold. It was only an
+example and isn't relevant to our application.
+
+Then we added four :term:`view callable` functions to our ``views.py``
+module. One view callable (named ``view_wiki``) will display the wiki itself
+(it will answer on the root URL), another named ``view_page`` will display an
+individual page, another named ``add_page`` will allow a page to be added,
+and a final view callable named ``edit_page`` will allow a page to be edited.
+We'll describe each one briefly and show the resulting ``views.py`` file
+afterward.
.. note::
@@ -195,16 +212,6 @@ If the view execution *is* a result of a form submission (if the expression
attribute of the page object. It then redirects to the ``view_page`` view
of the wiki page.
-Viewing the Result of all Our Edits to ``views.py``
-===================================================
-
-The result of all of our edits to ``views.py`` will leave it looking
-like this:
-
-.. literalinclude:: src/views/tutorial/views.py
- :linenos:
- :language: python
-
Adding Templates
================
@@ -270,47 +277,41 @@ subdirectories) and are just referred to by URL or by using the convenience
method ``static_url``
e.g. ``request.static_url('{{package}}:static/foo.css')`` within templates.
-Mapping Views to URLs in ``__init__.py``
-========================================
+Adding Routes to ``__init__.py``
+================================
The ``__init__.py`` file contains
-:meth:`pyramid.config.Configurator.add_view` calls which serve to map
-routes via :term:`url dispatch` to views. First, we’ll get rid of the
-existing route created by the template using the name ``'home'``. It’s only an
-example and isn’t relevant to our application.
+:meth:`pyramid.config.Configurator.add_route` calls which serve to add routes
+to our application. First, we’ll get rid of the existing route created by
+the template using the name ``'home'``. It’s only an example and isn’t
+relevant to our application.
We then need to add four calls to ``add_route``. Note that the *ordering* of
these declarations is very important. ``route`` declarations are matched in
the order they're found in the ``__init__.py`` file.
#. Add a declaration which maps the pattern ``/`` (signifying the root URL)
- to the route named ``view_wiki``.
+ to the route named ``view_wiki``. It maps to our ``view_wiki`` view
+ callable by virtue of the ``@view_config`` attached to the ``view_wiki``
+ view function indicating ``route_name='view_wiki'``.
#. Add a declaration which maps the pattern ``/{pagename}`` to the route named
- ``view_page``. This is the regular view for a page.
+ ``view_page``. This is the regular view for a page. It maps
+ to our ``view_page`` view callable by virtue of the ``@view_config``
+ attached to the ``view_page`` view function indicating
+ ``route_name='view_page'``.
#. Add a declaration which maps the pattern ``/add_page/{pagename}`` to the
- route named ``add_page``. This is the add view for a new page.
+ route named ``add_page``. This is the add view for a new page. It maps
+ to our ``add_page`` view callable by virtue of the ``@view_config``
+ attached to the ``add_page`` view function indicating
+ ``route_name='add_page'``.
#. Add a declaration which maps the pattern ``/{pagename}/edit_page`` to the
- route named ``edit_page``. This is the edit view for a page.
-
-After we've defined the routes for our application, we can register views
-to handle the processing and rendering that needs to happen when each route is
-requested.
-
-#. Add a declaration which maps the ``view_wiki`` route to the view named
- ``view_wiki`` in our ``views.py`` file. This is the :term:`default view`
- for the wiki.
-
-#. Add a declaration which maps the ``view_page`` route to the view named
- ``view_page`` in our ``views.py`` file.
-
-#. Add a declaration which maps the ``add_page`` route to the view named
- ``add_page`` in our ``views.py`` file.
-
-#. Add a declaration which maps the ``edit_page`` route to the view named
- ``edit_page`` in our ``views.py`` file.
+ route named ``edit_page``. This is the edit view for a page. It maps
+ to our ``edit_page`` view callable by virtue of the ``@view_config``
+ attached to the ``edit_page`` view function indicating
+ ``route_name='edit_page'``.
As a result of our edits, the ``__init__.py`` file should look
something like so:
diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst
index 147f7f563..be97f1cb3 100644
--- a/docs/tutorials/wiki2/installation.rst
+++ b/docs/tutorials/wiki2/installation.rst
@@ -40,13 +40,6 @@ Preparation, UNIX
$ bin/easy_install pyramid
-#. Use ``easy_install`` to install various packages from PyPI.
-
- .. code-block:: text
-
- $ bin/easy_install docutils nose coverage zope.sqlalchemy \
- SQLAlchemy pyramid_tm
-
Preparation, Windows
--------------------
@@ -69,14 +62,6 @@ Preparation, Windows
c:\pyramidtut> Scripts\easy_install pyramid
-#. Use ``easy_install`` to install various packages from PyPI.
-
- .. code-block:: text
-
- c:\pyramidtut> Scripts\easy_install docutils \
- nose coverage zope.sqlalchemy SQLAlchemy pyramid_tm
-
-
.. _sql_making_a_project:
Making a Project
@@ -108,6 +93,13 @@ On Windows:
startup problems, try putting both the virtualenv and the project
into directories that do not contain spaces in their paths.
+Success executing this command will end with a line to the console something
+like::
+
+ Please run the "populate_tutorial" script to set up the SQL
+ database before starting the application (e.g.
+ "$myvirtualenv/bin/populate_tutorial development.ini".)
+
Installing the Project in "Development Mode"
============================================
@@ -131,6 +123,11 @@ On Windows:
c:\pyramidtut> cd tutorial
c:\pyramidtut\tutorial> ..\Scripts\python setup.py develop
+Success executing this command will end with a line to the console something
+like::
+
+ Finished processing dependencies for tutorial==0.0
+
.. _sql_running_tests:
Running the Tests
@@ -151,6 +148,14 @@ On Windows:
c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
+For a successful test run, you should see output like this::
+
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.094s
+
+ OK
+
Exposing Test Coverage Information
==================================
@@ -191,8 +196,24 @@ On Windows:
c:\pyramidtut\tutorial> ..\Scripts\nosetests --cover-package=tutorial ^
--cover-erase --with-coverage
-Looks like our package's ``models`` module doesn't quite have 100%
-test coverage.
+If successful, you will see output something like this::
+
+ .
+ Name Stmts Miss Cover Missing
+ ------------------------------------------------
+ tutorial 11 7 36% 9-15
+ tutorial.models 17 0 100%
+ tutorial.scripts 0 0 100%
+ tutorial.tests 24 0 100%
+ tutorial.views 6 0 100%
+ ------------------------------------------------
+ TOTAL 58 7 88%
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.459s
+
+ OK
+
+Looks like our package doesn't quite have 100% test coverage.
Starting the Application
========================
@@ -211,11 +232,96 @@ On Windows:
c:\pyramidtut\tutorial> ..\Scripts\pserve development.ini --reload
-Visit the Application in a Browser
-==================================
+If successful, you will see something like this on your console::
+
+ Starting subprocess with file monitor
+ Starting server in PID 8966.
+ Starting HTTP server on http://0.0.0.0:6543
+
+This means the server is ready to accept requests.
+
+Populating the Database
+=======================
+
+In a web browser, visit ``http://localhost:6543/``.
+
+You will see an error page with a title something like this::
+
+ sqlalchemy.exc.OperationalError
+
+ OperationalError: (OperationalError) no such table: models ...
+
+Oh no! Something isn't working!
+
+This happens because we haven't populated the SQL database with any table
+information yet. We need to use the ``populate_tutorial`` :term:`console
+script` to populate our database before we can see the page render correctly.
+
+Stop the running Pyramid application by pressing ``ctrl-C`` in the console.
+Make sure you're still in the ``tutorial`` directory (the directory with a
+``development.ini`` in it) and type the following command:
+
+On UNIX:
+
+.. code-block:: text
+
+ $ ../bin/populate_tutorial development.ini
+
+On Windows:
+
+.. code-block:: text
+
+ c:\pyramidtut\tutorial> ..\Scripts\populate_tutorial development.ini
+
+The output to your console should be something like this::
+
+ 2011-11-26 14:42:25,012 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ PRAGMA table_info("models")
+ 2011-11-26 14:42:25,013 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
+ 2011-11-26 14:42:25,013 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ CREATE TABLE models (
+ id INTEGER NOT NULL,
+ name VARCHAR(255),
+ value INTEGER,
+ PRIMARY KEY (id),
+ UNIQUE (name)
+ )
+ 2011-11-26 14:42:25,013 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
+ 2011-11-26 14:42:25,135 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ COMMIT
+ 2011-11-26 14:42:25,137 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ BEGIN (implicit)
+ 2011-11-26 14:42:25,138 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ INSERT INTO models (name, value) VALUES (?, ?)
+ 2011-11-26 14:42:25,139 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ (u'one', 1)
+ 2011-11-26 14:42:25,140 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ COMMIT
+
+Success! You should now have a ``tutorial.db`` file in your current working
+directory. This will be a SQLite database with a single table defined in it
+(``models``).
+
+Starting the Application (Again)
+================================
+
+Start the application again.
+
+On UNIX:
+
+.. code-block:: text
+
+ $ ../bin/pserve development.ini --reload
+
+On Windows:
+
+.. code-block:: text
+
+ c:\pyramidtut\tutorial> ..\Scripts\pserve development.ini --reload
-In a browser, visit ``http://localhost:6543/``. You will see the
-generated application's default page.
+At this point, when you visit ``http://localhost:6543/`` in your web browser,
+you will no longer see an error; instead you will see the generated
+application's default page.
One thing you'll notice is the "debug toolbar" icon on right hand side of the
page. You can read more about the purpose of the icon at
diff --git a/docs/tutorials/wiki2/src/authorization/README.txt b/docs/tutorials/wiki2/src/authorization/README.txt
index d41f7f90f..6f851e9b7 100644
--- a/docs/tutorials/wiki2/src/authorization/README.txt
+++ b/docs/tutorials/wiki2/src/authorization/README.txt
@@ -1,4 +1 @@
tutorial README
-
-
-
diff --git a/docs/tutorials/wiki2/src/authorization/development.ini b/docs/tutorials/wiki2/src/authorization/development.ini
index d1e262324..4f7493cba 100644
--- a/docs/tutorials/wiki2/src/authorization/development.ini
+++ b/docs/tutorials/wiki2/src/authorization/development.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
@@ -19,7 +20,7 @@ port = 6543
# Begin logging configuration
[loggers]
-keys = root, sqlalchemy
+keys = root, tutorial, sqlalchemy
[handlers]
keys = console
@@ -31,6 +32,11 @@ keys = generic
level = INFO
handlers = console
+[logger_tutorial]
+level = DEBUG
+handlers =
+qualname = tutorial
+
[logger_sqlalchemy]
level = INFO
handlers =
diff --git a/docs/tutorials/wiki2/src/authorization/production.ini b/docs/tutorials/wiki2/src/authorization/production.ini
index ac02acf3f..53eaf20a1 100644
--- a/docs/tutorials/wiki2/src/authorization/production.ini
+++ b/docs/tutorials/wiki2/src/authorization/production.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
diff --git a/docs/tutorials/wiki2/src/authorization/setup.py b/docs/tutorials/wiki2/src/authorization/setup.py
index 439a86923..09769bfff 100644
--- a/docs/tutorials/wiki2/src/authorization/setup.py
+++ b/docs/tutorials/wiki2/src/authorization/setup.py
@@ -42,6 +42,7 @@ setup(name='tutorial',
entry_points = """\
[paste.app_factory]
main = tutorial:main
+ [console_scripts]
+ populate_tutorial = tutorial.scripts.populate:main
""",
)
-
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
index cca52fdfe..04dd5fe82 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
@@ -4,14 +4,15 @@ from pyramid.authorization import ACLAuthorizationPolicy
from sqlalchemy import engine_from_config
-from tutorial.models import initialize_sql
from tutorial.security import groupfinder
+from .models import DBSession
+
def main(global_config, **settings):
- """ This function returns a WSGI application.
+ """ This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
- initialize_sql(engine)
+ DBSession.configure(bind=engine)
authn_policy = AuthTktAuthenticationPolicy(
'sosecret', callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
@@ -19,27 +20,13 @@ def main(global_config, **settings):
root_factory='tutorial.models.RootFactory',
authentication_policy=authn_policy,
authorization_policy=authz_policy)
- config.add_static_view('static', 'tutorial:static', cache_max_age=3600)
-
+ config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('view_wiki', '/')
config.add_route('login', '/login')
config.add_route('logout', '/logout')
config.add_route('view_page', '/{pagename}')
config.add_route('add_page', '/add_page/{pagename}')
config.add_route('edit_page', '/{pagename}/edit_page')
-
- config.add_view('tutorial.views.view_wiki', route_name='view_wiki')
- config.add_view('tutorial.login.login', route_name='login',
- renderer='tutorial:templates/login.pt')
- config.add_view('tutorial.login.logout', route_name='logout')
- config.add_view('tutorial.views.view_page', route_name='view_page',
- renderer='tutorial:templates/view.pt')
- config.add_view('tutorial.views.add_page', route_name='add_page',
- renderer='tutorial:templates/edit.pt', permission='edit')
- config.add_view('tutorial.views.edit_page', route_name='edit_page',
- renderer='tutorial:templates/edit.pt', permission='edit')
- config.add_view('tutorial.login.login',
- context='pyramid.httpexceptions.HTTPForbidden',
- renderer='tutorial:templates/login.pt')
+ config.scan()
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/login.py b/docs/tutorials/wiki2/src/authorization/tutorial/login.py
deleted file mode 100644
index 5a825d8d6..000000000
--- a/docs/tutorials/wiki2/src/authorization/tutorial/login.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from pyramid.httpexceptions import HTTPFound
-from pyramid.security import remember
-from pyramid.security import forget
-
-from tutorial.security import USERS
-
-def login(request):
- login_url = request.route_url('login')
- referrer = request.url
- if referrer == login_url:
- referrer = '/' # never use the login form itself as came_from
- came_from = request.params.get('came_from', referrer)
- message = ''
- login = ''
- password = ''
- if 'form.submitted' in request.params:
- login = request.params['login']
- password = request.params['password']
- if USERS.get(login) == password:
- headers = remember(request, login)
- return HTTPFound(location = came_from,
- headers = headers)
- message = 'Failed login'
-
- return dict(
- message = message,
- url = request.application_url + '/login',
- came_from = came_from,
- login = login,
- password = password,
- )
-
-def logout(request):
- headers = forget(request)
- return HTTPFound(location = request.route_url('view_wiki'),
- headers = headers)
-
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models.py b/docs/tutorials/wiki2/src/authorization/tutorial/models.py
index 832545cb1..c3bdcbea5 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/models.py
@@ -1,17 +1,20 @@
-import transaction
+from pyramid.security import (
+ Allow,
+ Everyone,
+ )
-from pyramid.security import Allow
-from pyramid.security import Everyone
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Text
-
-from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
@@ -29,20 +32,6 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(engine):
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
- Base.metadata.create_all(engine)
- try:
- transaction.begin()
- session = DBSession()
- page = Page('FrontPage', 'This is the front page')
- session.add(page)
- transaction.commit()
- except IntegrityError:
- # already created
- transaction.abort()
-
class RootFactory(object):
__acl__ = [ (Allow, Everyone, 'view'),
(Allow, 'group:editors', 'edit') ]
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/scripts/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/scripts/populate.py b/docs/tutorials/wiki2/src/authorization/tutorial/scripts/populate.py
new file mode 100644
index 000000000..981adff38
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/scripts/populate.py
@@ -0,0 +1,35 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ Page,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv, settings=None):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/security.py b/docs/tutorials/wiki2/src/authorization/tutorial/security.py
index cfd13071e..d88c9c71f 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/security.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/security.py
@@ -5,4 +5,3 @@ GROUPS = {'editor':['group:editors']}
def groupfinder(userid, request):
if userid in USERS:
return GROUPS.get(userid, [])
-
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/tests.py b/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
index 332031ba4..31d2dc6d5 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
@@ -1,15 +1,20 @@
import unittest
-
+import transaction
from pyramid import testing
def _initTestingDB():
- from tutorial.models import DBSession
- from tutorial.models import Base
from sqlalchemy import create_engine
+ from tutorial.models import (
+ DBSession,
+ Page,
+ Base
+ )
engine = create_engine('sqlite://')
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
Base.metadata.create_all(engine)
+ DBSession.configure(bind=engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
return DBSession
def _registerRoutes(config):
@@ -20,14 +25,16 @@ def _registerRoutes(config):
class ViewWikiTests(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
+ self.session = _initTestingDB()
def tearDown(self):
+ self.session.remove()
testing.tearDown()
def _callFUT(self, request):
from tutorial.views import view_wiki
return view_wiki(request)
-
+
def test_it(self):
_registerRoutes(self.config)
request = testing.DummyRequest()
@@ -40,6 +47,7 @@ class ViewPageTests(unittest.TestCase):
self.config = testing.setUp()
def tearDown(self):
+ self.session.remove()
testing.tearDown()
def _callFUT(self, request):
@@ -121,7 +129,8 @@ class EditPageTests(unittest.TestCase):
self.session.add(page)
info = self._callFUT(request)
self.assertEqual(info['page'], page)
- self.assertEqual(info['save_url'], 'http://example.com/abc/edit_page')
+ self.assertEqual(info['save_url'],
+ 'http://example.com/abc/edit_page')
def test_it_submitted(self):
from tutorial.models import Page
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/views.py b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
index fc85d4585..375f1f5a5 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
@@ -1,20 +1,36 @@
import re
-
from docutils.core import publish_parts
-from pyramid.httpexceptions import HTTPFound, HTTPNotFound
-from pyramid.security import authenticated_userid
+from pyramid.httpexceptions import (
+ HTTPFound,
+ HTTPNotFound,
+ HTTPForbidden,
+ )
+
+from pyramid.view import view_config
+
+from pyramid.security import (
+ remember,
+ forget,
+ authenticated_userid,
+ )
-from tutorial.models import DBSession
-from tutorial.models import Page
+from .models import (
+ DBSession,
+ Page,
+ )
+
+from .security import USERS
# regular expression used to find WikiWords
wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
+@view_config(route_name='view_wiki')
def view_wiki(request):
return HTTPFound(location = request.route_url('view_page',
pagename='FrontPage'))
+@view_config(route_name='view_page', renderer='templates/view.pt')
def view_page(request):
pagename = request.matchdict['pagename']
session = DBSession()
@@ -35,10 +51,11 @@ def view_page(request):
content = publish_parts(page.data, writer_name='html')['html_body']
content = wikiwords.sub(check, content)
edit_url = request.route_url('edit_page', pagename=pagename)
- logged_in = authenticated_userid(request)
return dict(page=page, content=content, edit_url=edit_url,
- logged_in=logged_in)
+ logged_in=authenticated_userid(request))
+@view_config(route_name='add_page', renderer='templates/edit.pt',
+ permission='edit')
def add_page(request):
name = request.matchdict['pagename']
if 'form.submitted' in request.params:
@@ -50,9 +67,11 @@ def add_page(request):
pagename=name))
save_url = request.route_url('add_page', pagename=name)
page = Page('', '')
- logged_in = authenticated_userid(request)
- return dict(page=page, save_url=save_url, logged_in=logged_in)
+ return dict(page=page, save_url=save_url,
+ logged_in=authenticated_userid(request))
+@view_config(route_name='edit_page', renderer='templates/edit.pt',
+ permission='edit')
def edit_page(request):
name = request.matchdict['pagename']
session = DBSession()
@@ -62,10 +81,43 @@ def edit_page(request):
session.add(page)
return HTTPFound(location = request.route_url('view_page',
pagename=name))
-
- logged_in = authenticated_userid(request)
return dict(
page=page,
save_url = request.route_url('edit_page', pagename=name),
- logged_in = logged_in,
+ logged_in=authenticated_userid(request),
)
+
+@view_config(route_name='login', renderer='templates/login.pt')
+@view_config(context=HTTPForbidden, renderer='templates/login.pt')
+def login(request):
+ login_url = request.route_url('login')
+ referrer = request.url
+ if referrer == login_url:
+ referrer = '/' # never use the login form itself as came_from
+ came_from = request.params.get('came_from', referrer)
+ message = ''
+ login = ''
+ password = ''
+ if 'form.submitted' in request.params:
+ login = request.params['login']
+ password = request.params['password']
+ if USERS.get(login) == password:
+ headers = remember(request, login)
+ return HTTPFound(location = came_from,
+ headers = headers)
+ message = 'Failed login'
+
+ return dict(
+ message = message,
+ url = request.application_url + '/login',
+ came_from = came_from,
+ login = login,
+ password = password,
+ )
+
+@view_config(route_name='logout')
+def logout(request):
+ headers = forget(request)
+ return HTTPFound(location = request.route_url('view_wiki'),
+ headers = headers)
+
diff --git a/docs/tutorials/wiki2/src/basiclayout/README.txt b/docs/tutorials/wiki2/src/basiclayout/README.txt
index d41f7f90f..6f851e9b7 100644
--- a/docs/tutorials/wiki2/src/basiclayout/README.txt
+++ b/docs/tutorials/wiki2/src/basiclayout/README.txt
@@ -1,4 +1 @@
tutorial README
-
-
-
diff --git a/docs/tutorials/wiki2/src/basiclayout/development.ini b/docs/tutorials/wiki2/src/basiclayout/development.ini
index d1e262324..4f7493cba 100644
--- a/docs/tutorials/wiki2/src/basiclayout/development.ini
+++ b/docs/tutorials/wiki2/src/basiclayout/development.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
@@ -19,7 +20,7 @@ port = 6543
# Begin logging configuration
[loggers]
-keys = root, sqlalchemy
+keys = root, tutorial, sqlalchemy
[handlers]
keys = console
@@ -31,6 +32,11 @@ keys = generic
level = INFO
handlers = console
+[logger_tutorial]
+level = DEBUG
+handlers =
+qualname = tutorial
+
[logger_sqlalchemy]
level = INFO
handlers =
diff --git a/docs/tutorials/wiki2/src/basiclayout/production.ini b/docs/tutorials/wiki2/src/basiclayout/production.ini
index ac02acf3f..53eaf20a1 100644
--- a/docs/tutorials/wiki2/src/basiclayout/production.ini
+++ b/docs/tutorials/wiki2/src/basiclayout/production.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
diff --git a/docs/tutorials/wiki2/src/basiclayout/setup.py b/docs/tutorials/wiki2/src/basiclayout/setup.py
index 3ab493912..0ca918cab 100644
--- a/docs/tutorials/wiki2/src/basiclayout/setup.py
+++ b/docs/tutorials/wiki2/src/basiclayout/setup.py
@@ -41,6 +41,8 @@ setup(name='tutorial',
entry_points = """\
[paste.app_factory]
main = tutorial:main
+ [console_scripts]
+ populate_tutorial = tutorial.scripts.populate:main
""",
)
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
index b4038de3c..253341563 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
@@ -1,18 +1,16 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
-from tutorial.models import initialize_sql
+from .models import DBSession
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
- initialize_sql(engine)
+ DBSession.configure(bind=engine)
config = Configurator(settings=settings)
- config.add_static_view('static', 'tutorial:static', cache_max_age=3600)
+ config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
- config.add_view('tutorial.views.my_view', route_name='home',
- renderer='templates/mytemplate.pt')
+ config.scan()
return config.make_wsgi_app()
-
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
index 9b687931b..b6ac15429 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
@@ -1,43 +1,28 @@
-import transaction
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Unicode
-
-from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
-DBSession = scoped_session(sessionmaker(
- extension=ZopeTransactionExtension()))
+DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
class MyModel(Base):
__tablename__ = 'models'
id = Column(Integer, primary_key=True)
- name = Column(Unicode(255), unique=True)
+ name = Column(Text, unique=True)
value = Column(Integer)
def __init__(self, name, value):
self.name = name
self.value = value
-def populate():
- session = DBSession()
- model = MyModel(name=u'root',value=55)
- session.add(model)
- session.flush()
- transaction.commit()
-
-def initialize_sql(engine):
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
- Base.metadata.create_all(engine)
- try:
- populate()
- except IntegrityError:
- transaction.abort()
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/populate.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/populate.py
new file mode 100644
index 000000000..0e828465f
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/populate.py
@@ -0,0 +1,35 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ MyModel,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = MyModel(name='one', value=1)
+ DBSession.add(model)
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt
index 14b88d16a..fbfa9870b 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt
@@ -6,9 +6,9 @@
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
<link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
- <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<!--[if lte IE 6]>
<link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
index 5efa6affa..653d061e4 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
@@ -1,23 +1,32 @@
import unittest
+import transaction
+
from pyramid import testing
-def _initTestingDB():
- from sqlalchemy import create_engine
- from tutorial.models import initialize_sql
- session = initialize_sql(create_engine('sqlite://'))
- return session
+from .models import DBSession
class TestMyView(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
- _initTestingDB()
+ from sqlalchemy import create_engine
+ engine = create_engine('sqlite://')
+ from .models import (
+ Base,
+ MyModel,
+ )
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = MyModel(name='one', value=55)
+ DBSession.add(model)
def tearDown(self):
+ DBSession.remove()
testing.tearDown()
def test_it(self):
- from tutorial.views import my_view
+ from .views import my_view
request = testing.DummyRequest()
info = my_view(request)
- self.assertEqual(info['root'].name, 'root')
+ self.assertEqual(info['one'].name, 'one')
self.assertEqual(info['project'], 'tutorial')
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/views.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/views.py
index e550e3257..3e6abf2c2 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/views.py
@@ -1,7 +1,11 @@
-from tutorial.models import DBSession
-from tutorial.models import MyModel
+from pyramid.view import view_config
+from .models import (
+ DBSession,
+ MyModel,
+ )
+
+@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
- dbsession = DBSession()
- root = dbsession.query(MyModel).filter(MyModel.name==u'root').first()
- return {'root':root, 'project':'tutorial'}
+ one = DBSession.query(MyModel).filter(MyModel.name=='one').first()
+ return {'one':one, 'project':'tutorial'}
diff --git a/docs/tutorials/wiki2/src/models/README.txt b/docs/tutorials/wiki2/src/models/README.txt
index d41f7f90f..6f851e9b7 100644
--- a/docs/tutorials/wiki2/src/models/README.txt
+++ b/docs/tutorials/wiki2/src/models/README.txt
@@ -1,4 +1 @@
tutorial README
-
-
-
diff --git a/docs/tutorials/wiki2/src/models/development.ini b/docs/tutorials/wiki2/src/models/development.ini
index d1e262324..4f7493cba 100644
--- a/docs/tutorials/wiki2/src/models/development.ini
+++ b/docs/tutorials/wiki2/src/models/development.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
@@ -19,7 +20,7 @@ port = 6543
# Begin logging configuration
[loggers]
-keys = root, sqlalchemy
+keys = root, tutorial, sqlalchemy
[handlers]
keys = console
@@ -31,6 +32,11 @@ keys = generic
level = INFO
handlers = console
+[logger_tutorial]
+level = DEBUG
+handlers =
+qualname = tutorial
+
[logger_sqlalchemy]
level = INFO
handlers =
diff --git a/docs/tutorials/wiki2/src/models/production.ini b/docs/tutorials/wiki2/src/models/production.ini
index ac02acf3f..53eaf20a1 100644
--- a/docs/tutorials/wiki2/src/models/production.ini
+++ b/docs/tutorials/wiki2/src/models/production.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
diff --git a/docs/tutorials/wiki2/src/models/setup.py b/docs/tutorials/wiki2/src/models/setup.py
index 3ab493912..0ca918cab 100644
--- a/docs/tutorials/wiki2/src/models/setup.py
+++ b/docs/tutorials/wiki2/src/models/setup.py
@@ -41,6 +41,8 @@ setup(name='tutorial',
entry_points = """\
[paste.app_factory]
main = tutorial:main
+ [console_scripts]
+ populate_tutorial = tutorial.scripts.populate:main
""",
)
diff --git a/docs/tutorials/wiki2/src/models/tutorial/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/__init__.py
index fda7c9ce6..253341563 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/__init__.py
@@ -1,16 +1,16 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
-from tutorial.models import initialize_sql
+from .models import DBSession
def main(global_config, **settings):
- """ This function returns a WSGI application.
+ """ This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
- initialize_sql(engine)
+ DBSession.configure(bind=engine)
config = Configurator(settings=settings)
- config.add_static_view('static', 'tutorial:static', cache_max_age=3600)
+ config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
- config.add_view('tutorial.views.my_view', route_name='home',
- renderer='templates/mytemplate.pt')
+ config.scan()
return config.make_wsgi_app()
+
diff --git a/docs/tutorials/wiki2/src/models/tutorial/models.py b/docs/tutorials/wiki2/src/models/tutorial/models.py
index 30f77a0b9..499396c5b 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/models.py
@@ -1,19 +1,19 @@
-import transaction
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Text
-
-from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
-DBSession = scoped_session(sessionmaker(
- extension=ZopeTransactionExtension()))
+DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
class Page(Base):
@@ -27,16 +27,3 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(engine):
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
- Base.metadata.create_all(engine)
- try:
- transaction.begin()
- session = DBSession()
- page = Page('FrontPage', 'This is the front page')
- session.add(page)
- transaction.commit()
- except IntegrityError:
- # already created
- transaction.abort()
diff --git a/docs/tutorials/wiki2/src/models/tutorial/scripts/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/docs/tutorials/wiki2/src/models/tutorial/scripts/populate.py b/docs/tutorials/wiki2/src/models/tutorial/scripts/populate.py
new file mode 100644
index 000000000..03188e8ad
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/scripts/populate.py
@@ -0,0 +1,35 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ Page,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
diff --git a/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt
index 14b88d16a..fbfa9870b 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt
@@ -6,9 +6,9 @@
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
<link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
- <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<!--[if lte IE 6]>
<link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
diff --git a/docs/tutorials/wiki2/src/models/tutorial/tests.py b/docs/tutorials/wiki2/src/models/tutorial/tests.py
index 71f5e21e3..653d061e4 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/tests.py
@@ -1,22 +1,32 @@
import unittest
+import transaction
+
from pyramid import testing
-def _initTestingDB():
- from tutorial.models import initialize_sql
- session = initialize_sql('sqlite://')
- return session
+from .models import DBSession
class TestMyView(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
- _initTestingDB()
+ from sqlalchemy import create_engine
+ engine = create_engine('sqlite://')
+ from .models import (
+ Base,
+ MyModel,
+ )
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = MyModel(name='one', value=55)
+ DBSession.add(model)
def tearDown(self):
+ DBSession.remove()
testing.tearDown()
def test_it(self):
- from tutorial.views import my_view
+ from .views import my_view
request = testing.DummyRequest()
info = my_view(request)
- self.assertEqual(info['root'].name, 'root')
+ self.assertEqual(info['one'].name, 'one')
self.assertEqual(info['project'], 'tutorial')
diff --git a/docs/tutorials/wiki2/src/models/tutorial/views.py b/docs/tutorials/wiki2/src/models/tutorial/views.py
index e550e3257..3e6abf2c2 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/views.py
@@ -1,7 +1,11 @@
-from tutorial.models import DBSession
-from tutorial.models import MyModel
+from pyramid.view import view_config
+from .models import (
+ DBSession,
+ MyModel,
+ )
+
+@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
- dbsession = DBSession()
- root = dbsession.query(MyModel).filter(MyModel.name==u'root').first()
- return {'root':root, 'project':'tutorial'}
+ one = DBSession.query(MyModel).filter(MyModel.name=='one').first()
+ return {'one':one, 'project':'tutorial'}
diff --git a/docs/tutorials/wiki2/src/tests/README.txt b/docs/tutorials/wiki2/src/tests/README.txt
index d41f7f90f..6f851e9b7 100644
--- a/docs/tutorials/wiki2/src/tests/README.txt
+++ b/docs/tutorials/wiki2/src/tests/README.txt
@@ -1,4 +1 @@
tutorial README
-
-
-
diff --git a/docs/tutorials/wiki2/src/tests/development.ini b/docs/tutorials/wiki2/src/tests/development.ini
index d1e262324..4f7493cba 100644
--- a/docs/tutorials/wiki2/src/tests/development.ini
+++ b/docs/tutorials/wiki2/src/tests/development.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
@@ -19,7 +20,7 @@ port = 6543
# Begin logging configuration
[loggers]
-keys = root, sqlalchemy
+keys = root, tutorial, sqlalchemy
[handlers]
keys = console
@@ -31,6 +32,11 @@ keys = generic
level = INFO
handlers = console
+[logger_tutorial]
+level = DEBUG
+handlers =
+qualname = tutorial
+
[logger_sqlalchemy]
level = INFO
handlers =
diff --git a/docs/tutorials/wiki2/src/tests/production.ini b/docs/tutorials/wiki2/src/tests/production.ini
index ac02acf3f..53eaf20a1 100644
--- a/docs/tutorials/wiki2/src/tests/production.ini
+++ b/docs/tutorials/wiki2/src/tests/production.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py
index 6de8a1fbe..f965ccc6e 100644
--- a/docs/tutorials/wiki2/src/tests/setup.py
+++ b/docs/tutorials/wiki2/src/tests/setup.py
@@ -43,6 +43,7 @@ setup(name='tutorial',
entry_points = """\
[paste.app_factory]
main = tutorial:main
+ [console_scripts]
+ populate_tutorial = tutorial.scripts.populate:main
""",
)
-
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py
index cca52fdfe..04dd5fe82 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py
@@ -4,14 +4,15 @@ from pyramid.authorization import ACLAuthorizationPolicy
from sqlalchemy import engine_from_config
-from tutorial.models import initialize_sql
from tutorial.security import groupfinder
+from .models import DBSession
+
def main(global_config, **settings):
- """ This function returns a WSGI application.
+ """ This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
- initialize_sql(engine)
+ DBSession.configure(bind=engine)
authn_policy = AuthTktAuthenticationPolicy(
'sosecret', callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
@@ -19,27 +20,13 @@ def main(global_config, **settings):
root_factory='tutorial.models.RootFactory',
authentication_policy=authn_policy,
authorization_policy=authz_policy)
- config.add_static_view('static', 'tutorial:static', cache_max_age=3600)
-
+ config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('view_wiki', '/')
config.add_route('login', '/login')
config.add_route('logout', '/logout')
config.add_route('view_page', '/{pagename}')
config.add_route('add_page', '/add_page/{pagename}')
config.add_route('edit_page', '/{pagename}/edit_page')
-
- config.add_view('tutorial.views.view_wiki', route_name='view_wiki')
- config.add_view('tutorial.login.login', route_name='login',
- renderer='tutorial:templates/login.pt')
- config.add_view('tutorial.login.logout', route_name='logout')
- config.add_view('tutorial.views.view_page', route_name='view_page',
- renderer='tutorial:templates/view.pt')
- config.add_view('tutorial.views.add_page', route_name='add_page',
- renderer='tutorial:templates/edit.pt', permission='edit')
- config.add_view('tutorial.views.edit_page', route_name='edit_page',
- renderer='tutorial:templates/edit.pt', permission='edit')
- config.add_view('tutorial.login.login',
- context='pyramid.httpexceptions.HTTPForbidden',
- renderer='tutorial:templates/login.pt')
+ config.scan()
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/login.py b/docs/tutorials/wiki2/src/tests/tutorial/login.py
deleted file mode 100644
index 5a825d8d6..000000000
--- a/docs/tutorials/wiki2/src/tests/tutorial/login.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from pyramid.httpexceptions import HTTPFound
-from pyramid.security import remember
-from pyramid.security import forget
-
-from tutorial.security import USERS
-
-def login(request):
- login_url = request.route_url('login')
- referrer = request.url
- if referrer == login_url:
- referrer = '/' # never use the login form itself as came_from
- came_from = request.params.get('came_from', referrer)
- message = ''
- login = ''
- password = ''
- if 'form.submitted' in request.params:
- login = request.params['login']
- password = request.params['password']
- if USERS.get(login) == password:
- headers = remember(request, login)
- return HTTPFound(location = came_from,
- headers = headers)
- message = 'Failed login'
-
- return dict(
- message = message,
- url = request.application_url + '/login',
- came_from = came_from,
- login = login,
- password = password,
- )
-
-def logout(request):
- headers = forget(request)
- return HTTPFound(location = request.route_url('view_wiki'),
- headers = headers)
-
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models.py b/docs/tutorials/wiki2/src/tests/tutorial/models.py
index 832545cb1..c3bdcbea5 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/models.py
@@ -1,17 +1,20 @@
-import transaction
+from pyramid.security import (
+ Allow,
+ Everyone,
+ )
-from pyramid.security import Allow
-from pyramid.security import Everyone
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Text
-
-from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
@@ -29,20 +32,6 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(engine):
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
- Base.metadata.create_all(engine)
- try:
- transaction.begin()
- session = DBSession()
- page = Page('FrontPage', 'This is the front page')
- session.add(page)
- transaction.commit()
- except IntegrityError:
- # already created
- transaction.abort()
-
class RootFactory(object):
__acl__ = [ (Allow, Everyone, 'view'),
(Allow, 'group:editors', 'edit') ]
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/scripts/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/docs/tutorials/wiki2/src/tests/tutorial/scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/scripts/populate.py b/docs/tutorials/wiki2/src/tests/tutorial/scripts/populate.py
new file mode 100644
index 000000000..de74f4d63
--- /dev/null
+++ b/docs/tutorials/wiki2/src/tests/tutorial/scripts/populate.py
@@ -0,0 +1,36 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ Page,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv, settings=None):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ if settings is None:
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/security.py b/docs/tutorials/wiki2/src/tests/tutorial/security.py
index cfd13071e..d88c9c71f 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/security.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/security.py
@@ -5,4 +5,3 @@ GROUPS = {'editor':['group:editors']}
def groupfinder(userid, request):
if userid in USERS:
return GROUPS.get(userid, [])
-
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests.py b/docs/tutorials/wiki2/src/tests/tutorial/tests.py
index 8439e2748..557d1b1be 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/tests.py
@@ -1,16 +1,20 @@
import unittest
-
+import transaction
from pyramid import testing
-
def _initTestingDB():
- from tutorial.models import DBSession
- from tutorial.models import Base
from sqlalchemy import create_engine
- engine = create_engine('sqlite:///:memory:')
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
+ from tutorial.models import (
+ DBSession,
+ Page,
+ Base
+ )
+ engine = create_engine('sqlite://')
Base.metadata.create_all(engine)
+ DBSession.configure(bind=engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
return DBSession
def _registerRoutes(config):
@@ -39,28 +43,6 @@ class PageModelTests(unittest.TestCase):
self.assertEqual(instance.name, 'SomeName')
self.assertEqual(instance.data, 'some data')
-class InitializeSqlTests(unittest.TestCase):
-
- def setUp(self):
- from tutorial.models import DBSession
- DBSession.remove()
-
- def tearDown(self):
- from tutorial.models import DBSession
- DBSession.remove()
-
- def _callFUT(self, engine):
- from tutorial.models import initialize_sql
- return initialize_sql(engine)
-
- def test_it(self):
- from sqlalchemy import create_engine
- engine = create_engine('sqlite:///:memory:')
- self._callFUT(engine)
- from tutorial.models import DBSession, Page
- self.assertEqual(DBSession.query(Page).one().data,
- 'This is the front page')
-
class ViewWikiTests(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
@@ -191,10 +173,11 @@ class FunctionalTests(unittest.TestCase):
def setUp(self):
from tutorial import main
- settings = { 'sqlalchemy.url': 'sqlite:///:memory:'}
+ settings = { 'sqlalchemy.url': 'sqlite://'}
app = main({}, **settings)
from webtest import TestApp
self.testapp = TestApp(app)
+ _initTestingDB()
def tearDown(self):
del self.testapp
@@ -263,3 +246,23 @@ class FunctionalTests(unittest.TestCase):
self.testapp.get(self.editor_login, status=302)
res = self.testapp.get('/FrontPage', status=200)
self.assertTrue('FrontPage' in res.body)
+
+class Test_populate(unittest.TestCase):
+ def setUp(self):
+ from tutorial.models import DBSession
+ DBSession.remove()
+
+ def tearDown(self):
+ from tutorial.models import DBSession
+ DBSession.remove()
+
+ def _callFUT(self, settings):
+ from tutorial.scripts.populate import main
+ main(['foo', 'development.ini'], settings)
+
+ def test_it(self):
+ self._callFUT({'sqlalchemy.url':'sqlite://'})
+ from tutorial.models import DBSession, Page
+ self.assertEqual(DBSession.query(Page).one().data,
+ 'This is the front page')
+
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views.py b/docs/tutorials/wiki2/src/tests/tutorial/views.py
index fc85d4585..375f1f5a5 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/views.py
@@ -1,20 +1,36 @@
import re
-
from docutils.core import publish_parts
-from pyramid.httpexceptions import HTTPFound, HTTPNotFound
-from pyramid.security import authenticated_userid
+from pyramid.httpexceptions import (
+ HTTPFound,
+ HTTPNotFound,
+ HTTPForbidden,
+ )
+
+from pyramid.view import view_config
+
+from pyramid.security import (
+ remember,
+ forget,
+ authenticated_userid,
+ )
-from tutorial.models import DBSession
-from tutorial.models import Page
+from .models import (
+ DBSession,
+ Page,
+ )
+
+from .security import USERS
# regular expression used to find WikiWords
wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
+@view_config(route_name='view_wiki')
def view_wiki(request):
return HTTPFound(location = request.route_url('view_page',
pagename='FrontPage'))
+@view_config(route_name='view_page', renderer='templates/view.pt')
def view_page(request):
pagename = request.matchdict['pagename']
session = DBSession()
@@ -35,10 +51,11 @@ def view_page(request):
content = publish_parts(page.data, writer_name='html')['html_body']
content = wikiwords.sub(check, content)
edit_url = request.route_url('edit_page', pagename=pagename)
- logged_in = authenticated_userid(request)
return dict(page=page, content=content, edit_url=edit_url,
- logged_in=logged_in)
+ logged_in=authenticated_userid(request))
+@view_config(route_name='add_page', renderer='templates/edit.pt',
+ permission='edit')
def add_page(request):
name = request.matchdict['pagename']
if 'form.submitted' in request.params:
@@ -50,9 +67,11 @@ def add_page(request):
pagename=name))
save_url = request.route_url('add_page', pagename=name)
page = Page('', '')
- logged_in = authenticated_userid(request)
- return dict(page=page, save_url=save_url, logged_in=logged_in)
+ return dict(page=page, save_url=save_url,
+ logged_in=authenticated_userid(request))
+@view_config(route_name='edit_page', renderer='templates/edit.pt',
+ permission='edit')
def edit_page(request):
name = request.matchdict['pagename']
session = DBSession()
@@ -62,10 +81,43 @@ def edit_page(request):
session.add(page)
return HTTPFound(location = request.route_url('view_page',
pagename=name))
-
- logged_in = authenticated_userid(request)
return dict(
page=page,
save_url = request.route_url('edit_page', pagename=name),
- logged_in = logged_in,
+ logged_in=authenticated_userid(request),
)
+
+@view_config(route_name='login', renderer='templates/login.pt')
+@view_config(context=HTTPForbidden, renderer='templates/login.pt')
+def login(request):
+ login_url = request.route_url('login')
+ referrer = request.url
+ if referrer == login_url:
+ referrer = '/' # never use the login form itself as came_from
+ came_from = request.params.get('came_from', referrer)
+ message = ''
+ login = ''
+ password = ''
+ if 'form.submitted' in request.params:
+ login = request.params['login']
+ password = request.params['password']
+ if USERS.get(login) == password:
+ headers = remember(request, login)
+ return HTTPFound(location = came_from,
+ headers = headers)
+ message = 'Failed login'
+
+ return dict(
+ message = message,
+ url = request.application_url + '/login',
+ came_from = came_from,
+ login = login,
+ password = password,
+ )
+
+@view_config(route_name='logout')
+def logout(request):
+ headers = forget(request)
+ return HTTPFound(location = request.route_url('view_wiki'),
+ headers = headers)
+
diff --git a/docs/tutorials/wiki2/src/views/README.txt b/docs/tutorials/wiki2/src/views/README.txt
index d41f7f90f..6f851e9b7 100644
--- a/docs/tutorials/wiki2/src/views/README.txt
+++ b/docs/tutorials/wiki2/src/views/README.txt
@@ -1,4 +1 @@
tutorial README
-
-
-
diff --git a/docs/tutorials/wiki2/src/views/development.ini b/docs/tutorials/wiki2/src/views/development.ini
index d1e262324..4f7493cba 100644
--- a/docs/tutorials/wiki2/src/views/development.ini
+++ b/docs/tutorials/wiki2/src/views/development.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
@@ -19,7 +20,7 @@ port = 6543
# Begin logging configuration
[loggers]
-keys = root, sqlalchemy
+keys = root, tutorial, sqlalchemy
[handlers]
keys = console
@@ -31,6 +32,11 @@ keys = generic
level = INFO
handlers = console
+[logger_tutorial]
+level = DEBUG
+handlers =
+qualname = tutorial
+
[logger_sqlalchemy]
level = INFO
handlers =
diff --git a/docs/tutorials/wiki2/src/views/production.ini b/docs/tutorials/wiki2/src/views/production.ini
index ac02acf3f..53eaf20a1 100644
--- a/docs/tutorials/wiki2/src/views/production.ini
+++ b/docs/tutorials/wiki2/src/views/production.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
diff --git a/docs/tutorials/wiki2/src/views/setup.py b/docs/tutorials/wiki2/src/views/setup.py
index 439a86923..9c0e88eb0 100644
--- a/docs/tutorials/wiki2/src/views/setup.py
+++ b/docs/tutorials/wiki2/src/views/setup.py
@@ -42,6 +42,8 @@ setup(name='tutorial',
entry_points = """\
[paste.app_factory]
main = tutorial:main
+ [console_scripts]
+ populate_tutorial = tutorial.scripts.populate:main
""",
)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
index 7d79f7a1f..b30d593cf 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
@@ -1,25 +1,18 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
-from tutorial.models import initialize_sql
+from .models import DBSession
def main(global_config, **settings):
- """ This function returns a WSGI application.
+ """ This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
- initialize_sql(engine)
+ DBSession.configure(bind=engine)
config = Configurator(settings=settings)
- config.add_static_view('static', 'tutorial:static', cache_max_age=3600)
+ config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('view_wiki', '/')
config.add_route('view_page', '/{pagename}')
config.add_route('add_page', '/add_page/{pagename}')
config.add_route('edit_page', '/{pagename}/edit_page')
- config.add_view('tutorial.views.view_wiki', route_name='view_wiki')
- config.add_view('tutorial.views.view_page', route_name='view_page',
- renderer='tutorial:templates/view.pt')
- config.add_view('tutorial.views.add_page', route_name='add_page',
- renderer='tutorial:templates/edit.pt')
- config.add_view('tutorial.views.edit_page', route_name='edit_page',
- renderer='tutorial:templates/edit.pt')
+ config.scan()
return config.make_wsgi_app()
-
diff --git a/docs/tutorials/wiki2/src/views/tutorial/models.py b/docs/tutorials/wiki2/src/views/tutorial/models.py
index 30506f67e..499396c5b 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/models.py
@@ -1,14 +1,15 @@
-import transaction
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Text
-
-from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
@@ -26,16 +27,3 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(engine):
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
- Base.metadata.create_all(engine)
- try:
- transaction.begin()
- session = DBSession()
- page = Page('FrontPage', 'initial data')
- session.add(page)
- transaction.commit()
- except IntegrityError:
- # already created
- transaction.abort()
diff --git a/docs/tutorials/wiki2/src/views/tutorial/scripts/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/docs/tutorials/wiki2/src/views/tutorial/scripts/populate.py b/docs/tutorials/wiki2/src/views/tutorial/scripts/populate.py
new file mode 100644
index 000000000..03188e8ad
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/scripts/populate.py
@@ -0,0 +1,35 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ Page,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt
index 14b88d16a..fbfa9870b 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt
@@ -6,9 +6,9 @@
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
<link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
- <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<!--[if lte IE 6]>
<link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
diff --git a/docs/tutorials/wiki2/src/views/tutorial/tests.py b/docs/tutorials/wiki2/src/views/tutorial/tests.py
index 668bf5479..31d2dc6d5 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/tests.py
@@ -1,15 +1,20 @@
import unittest
-
+import transaction
from pyramid import testing
def _initTestingDB():
- from tutorial.models import DBSession
- from tutorial.models import Base
from sqlalchemy import create_engine
+ from tutorial.models import (
+ DBSession,
+ Page,
+ Base
+ )
engine = create_engine('sqlite://')
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
Base.metadata.create_all(engine)
+ DBSession.configure(bind=engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
return DBSession
def _registerRoutes(config):
@@ -20,8 +25,10 @@ def _registerRoutes(config):
class ViewWikiTests(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
+ self.session = _initTestingDB()
def tearDown(self):
+ self.session.remove()
testing.tearDown()
def _callFUT(self, request):
diff --git a/docs/tutorials/wiki2/src/views/tutorial/views.py b/docs/tutorials/wiki2/src/views/tutorial/views.py
index e04b96ae4..5c49dd2e8 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/views.py
@@ -1,19 +1,26 @@
import re
-
from docutils.core import publish_parts
-from pyramid.httpexceptions import HTTPFound, HTTPNotFound
+from pyramid.httpexceptions import (
+ HTTPFound,
+ HTTPNotFound,
+ )
+from pyramid.view import view_config
-from tutorial.models import DBSession
-from tutorial.models import Page
+from .models import (
+ DBSession,
+ Page,
+ )
# regular expression used to find WikiWords
wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
+@view_config(route_name='view_wiki')
def view_wiki(request):
return HTTPFound(location = request.route_url('view_page',
pagename='FrontPage'))
+@view_config(route_name='view_page', renderer='templates/view.pt')
def view_page(request):
pagename = request.matchdict['pagename']
session = DBSession()
@@ -36,6 +43,7 @@ def view_page(request):
edit_url = request.route_url('edit_page', pagename=pagename)
return dict(page=page, content=content, edit_url=edit_url)
+@view_config(route_name='add_page', renderer='templates/edit.pt')
def add_page(request):
name = request.matchdict['pagename']
if 'form.submitted' in request.params:
@@ -49,6 +57,7 @@ def add_page(request):
page = Page('', '')
return dict(page=page, save_url=save_url)
+@view_config(route_name='edit_page', renderer='templates/edit.pt')
def edit_page(request):
name = request.matchdict['pagename']
session = DBSession()
diff --git a/docs/tutorials/wiki2/tests.rst b/docs/tutorials/wiki2/tests.rst
index 8fa8ea3ae..25cf2c25e 100644
--- a/docs/tutorials/wiki2/tests.rst
+++ b/docs/tutorials/wiki2/tests.rst
@@ -14,8 +14,8 @@ for the ``initialize_sql`` function.
To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided as a
result of the ``alchemy`` scaffold. We'll add two test classes: one for the
-``Page`` model named ``PageModelTests``, one for the ``initialize_sql``
-function named ``InitializeSqlTests``.
+``Page`` model named ``PageModelTests``, and one for the ``populate`` script
+named ``Test_populate``.
Testing the Views
=================
diff --git a/pyramid/asset.py b/pyramid/asset.py
index 4bf0d7bf4..63be78c72 100644
--- a/pyramid/asset.py
+++ b/pyramid/asset.py
@@ -3,8 +3,10 @@ import pkg_resources
from pyramid.compat import string_types
-from pyramid.path import package_path
-from pyramid.path import package_name
+from pyramid.path import (
+ package_path,
+ package_name,
+ )
def resolve_asset_spec(spec, pname='__main__'):
if pname and not isinstance(pname, string_types):
diff --git a/pyramid/authentication.py b/pyramid/authentication.py
index 3909ce2d8..13ec4284a 100644
--- a/pyramid/authentication.py
+++ b/pyramid/authentication.py
@@ -8,19 +8,25 @@ import time as time_mod
from zope.interface import implementer
-from pyramid.compat import long
-from pyramid.compat import text_type
-from pyramid.compat import binary_type
-from pyramid.compat import url_unquote
-from pyramid.compat import url_quote
-from pyramid.compat import bytes_
-from pyramid.compat import ascii_native_
-
-from pyramid.interfaces import IAuthenticationPolicy
-from pyramid.interfaces import IDebugLogger
-
-from pyramid.security import Authenticated
-from pyramid.security import Everyone
+from pyramid.compat import (
+ long,
+ text_type,
+ binary_type,
+ url_unquote,
+ url_quote,
+ bytes_,
+ ascii_native_,
+ )
+
+from pyramid.interfaces import (
+ IAuthenticationPolicy,
+ IDebugLogger,
+ )
+
+from pyramid.security import (
+ Authenticated,
+ Everyone,
+ )
from pyramid.util import strings_differ
diff --git a/pyramid/authorization.py b/pyramid/authorization.py
index b1ef10033..fc711e88b 100644
--- a/pyramid/authorization.py
+++ b/pyramid/authorization.py
@@ -3,11 +3,14 @@ from zope.interface import implementer
from pyramid.interfaces import IAuthorizationPolicy
from pyramid.location import lineage
-from pyramid.security import ACLAllowed
-from pyramid.security import ACLDenied
-from pyramid.security import Allow
-from pyramid.security import Deny
-from pyramid.security import Everyone
+
+from pyramid.security import (
+ ACLAllowed,
+ ACLDenied,
+ Allow,
+ Deny,
+ Everyone,
+ )
@implementer(IAuthorizationPolicy)
class ACLAuthorizationPolicy(object):
diff --git a/pyramid/config/__init__.py b/pyramid/config/__init__.py
index e993d0700..b0c86f0cd 100644
--- a/pyramid/config/__init__.py
+++ b/pyramid/config/__init__.py
@@ -16,25 +16,44 @@ from pyramid.interfaces import (
)
from pyramid.asset import resolve_asset_spec
+
from pyramid.authorization import ACLAuthorizationPolicy
-from pyramid.compat import text_
-from pyramid.compat import reraise
-from pyramid.compat import string_types
-from pyramid.compat import PY3
+
+from pyramid.compat import (
+ text_,
+ reraise,
+ string_types,
+ PY3,
+ )
+
from pyramid.events import ApplicationCreated
-from pyramid.exceptions import ConfigurationConflictError
-from pyramid.exceptions import ConfigurationError
-from pyramid.exceptions import ConfigurationExecutionError
+
+from pyramid.exceptions import (
+ ConfigurationConflictError,
+ ConfigurationError,
+ ConfigurationExecutionError,
+ )
+
from pyramid.httpexceptions import default_exceptionresponse_view
-from pyramid.path import caller_package
-from pyramid.path import package_of
+
+from pyramid.path import (
+ caller_package,
+ package_of,
+ )
+
from pyramid.registry import Registry
+
from pyramid.router import Router
+
from pyramid.settings import aslist
+
from pyramid.threadlocal import manager
-from pyramid.util import DottedNameResolver
-from pyramid.util import WeakOrderedSet
-from pyramid.util import object_description
+
+from pyramid.util import (
+ DottedNameResolver,
+ WeakOrderedSet,
+ object_description,
+ )
from pyramid.config.adapters import AdaptersConfiguratorMixin
from pyramid.config.assets import AssetsConfiguratorMixin
diff --git a/pyramid/config/factories.py b/pyramid/config/factories.py
index 2ab9fc7db..cfa91d6d9 100644
--- a/pyramid/config/factories.py
+++ b/pyramid/config/factories.py
@@ -1,9 +1,11 @@
from pyramid.config.util import action_method
-from pyramid.interfaces import IDefaultRootFactory
-from pyramid.interfaces import IRequestFactory
-from pyramid.interfaces import IRootFactory
-from pyramid.interfaces import ISessionFactory
+from pyramid.interfaces import (
+ IDefaultRootFactory,
+ IRequestFactory,
+ IRootFactory,
+ ISessionFactory,
+ )
from pyramid.traversal import DefaultRootFactory
diff --git a/pyramid/config/i18n.py b/pyramid/config/i18n.py
index b405f3683..2c149923c 100644
--- a/pyramid/config/i18n.py
+++ b/pyramid/config/i18n.py
@@ -3,9 +3,11 @@ import sys
from translationstring import ChameleonTranslate
-from pyramid.interfaces import IChameleonTranslate
-from pyramid.interfaces import ILocaleNegotiator
-from pyramid.interfaces import ITranslationDirectories
+from pyramid.interfaces import (
+ IChameleonTranslate,
+ ILocaleNegotiator,
+ ITranslationDirectories,
+ )
from pyramid.exceptions import ConfigurationError
from pyramid.i18n import get_localizer
diff --git a/pyramid/config/rendering.py b/pyramid/config/rendering.py
index f828f453b..0d37e201f 100644
--- a/pyramid/config/rendering.py
+++ b/pyramid/config/rendering.py
@@ -1,14 +1,19 @@
import warnings
-from pyramid.interfaces import IRendererFactory
-from pyramid.interfaces import IRendererGlobalsFactory
-from pyramid.interfaces import PHASE1_CONFIG
+from pyramid.interfaces import (
+ IRendererFactory,
+ IRendererGlobalsFactory,
+ PHASE1_CONFIG,
+ )
from pyramid.config.util import action_method
-from pyramid import renderers
-from pyramid import chameleon_text
-from pyramid import chameleon_zpt
+from pyramid import (
+ renderers,
+ chameleon_text,
+ chameleon_zpt,
+ )
+
from pyramid.mako_templating import renderer_factory as mako_renderer_factory
DEFAULT_RENDERERS = (
diff --git a/pyramid/config/routes.py b/pyramid/config/routes.py
index 0ab380ec1..ab62d4c75 100644
--- a/pyramid/config/routes.py
+++ b/pyramid/config/routes.py
@@ -1,16 +1,20 @@
import warnings
-from pyramid.interfaces import IRequest
-from pyramid.interfaces import IRouteRequest
-from pyramid.interfaces import IRoutesMapper
-from pyramid.interfaces import PHASE2_CONFIG
+from pyramid.interfaces import (
+ IRequest,
+ IRouteRequest,
+ IRoutesMapper,
+ PHASE2_CONFIG,
+ )
from pyramid.exceptions import ConfigurationError
from pyramid.request import route_request_iface
from pyramid.urldispatch import RoutesMapper
-from pyramid.config.util import action_method
-from pyramid.config.util import make_predicates
+from pyramid.config.util import (
+ action_method,
+ make_predicates,
+ )
class RoutesConfiguratorMixin(object):
@action_method
diff --git a/pyramid/config/security.py b/pyramid/config/security.py
index 20c830e75..1830fb900 100644
--- a/pyramid/config/security.py
+++ b/pyramid/config/security.py
@@ -1,8 +1,10 @@
-from pyramid.interfaces import IAuthorizationPolicy
-from pyramid.interfaces import IAuthenticationPolicy
-from pyramid.interfaces import IDefaultPermission
-from pyramid.interfaces import PHASE1_CONFIG
-from pyramid.interfaces import PHASE2_CONFIG
+from pyramid.interfaces import (
+ IAuthorizationPolicy,
+ IAuthenticationPolicy,
+ IDefaultPermission,
+ PHASE1_CONFIG,
+ PHASE2_CONFIG,
+ )
from pyramid.exceptions import ConfigurationError
from pyramid.config.util import action_method
diff --git a/pyramid/config/testing.py b/pyramid/config/testing.py
index 36729acdf..3cdc1aa24 100644
--- a/pyramid/config/testing.py
+++ b/pyramid/config/testing.py
@@ -1,9 +1,11 @@
from zope.interface import Interface
-from pyramid.interfaces import ITraverser
-from pyramid.interfaces import IAuthorizationPolicy
-from pyramid.interfaces import IAuthenticationPolicy
-from pyramid.interfaces import IRendererFactory
+from pyramid.interfaces import (
+ ITraverser,
+ IAuthorizationPolicy,
+ IAuthenticationPolicy,
+ IRendererFactory,
+ )
from pyramid.renderers import RendererHelper
from pyramid.traversal import traversal_path_info
diff --git a/pyramid/config/tweens.py b/pyramid/config/tweens.py
index 39ac018d0..76efe4af5 100644
--- a/pyramid/config/tweens.py
+++ b/pyramid/config/tweens.py
@@ -2,11 +2,19 @@ from zope.interface import implementer
from pyramid.interfaces import ITweens
-from pyramid.compat import string_types
-from pyramid.compat import is_nonstr_iter
+from pyramid.compat import (
+ string_types,
+ is_nonstr_iter,
+ )
+
from pyramid.exceptions import ConfigurationError
-from pyramid.tweens import excview_tween_factory
-from pyramid.tweens import MAIN, INGRESS, EXCVIEW
+
+from pyramid.tweens import (
+ excview_tween_factory,
+ MAIN,
+ INGRESS,
+ EXCVIEW,
+ )
from pyramid.config.util import action_method
diff --git a/pyramid/config/util.py b/pyramid/config/util.py
index 0336b103d..cbec2e0c2 100644
--- a/pyramid/config/util.py
+++ b/pyramid/config/util.py
@@ -1,12 +1,18 @@
import re
import traceback
-from pyramid.compat import string_types
-from pyramid.compat import bytes_
-from pyramid.compat import is_nonstr_iter
+from pyramid.compat import (
+ string_types,
+ bytes_,
+ is_nonstr_iter,
+ )
+
from pyramid.exceptions import ConfigurationError
-from pyramid.traversal import find_interface
-from pyramid.traversal import traversal_path_info
+
+from pyramid.traversal import (
+ find_interface,
+ traversal_path_info,
+ )
from hashlib import md5
diff --git a/pyramid/config/views.py b/pyramid/config/views.py
index 00ea2fdd2..16c0a8253 100644
--- a/pyramid/config/views.py
+++ b/pyramid/config/views.py
@@ -1,50 +1,67 @@
import inspect
import operator
-from zope.interface import Interface
-from zope.interface import classProvides
-from zope.interface import implementedBy
-from zope.interface import implementer
+from zope.interface import (
+ Interface,
+ classProvides,
+ implementedBy,
+ implementer,
+ )
+
from zope.interface.interfaces import IInterface
-from pyramid.interfaces import IAuthenticationPolicy
-from pyramid.interfaces import IAuthorizationPolicy
-from pyramid.interfaces import IDebugLogger
-from pyramid.interfaces import IDefaultPermission
-from pyramid.interfaces import IException
-from pyramid.interfaces import IExceptionViewClassifier
-from pyramid.interfaces import IMultiView
-from pyramid.interfaces import IRendererFactory
-from pyramid.interfaces import IRequest
-from pyramid.interfaces import IResponse
-from pyramid.interfaces import IRouteRequest
-from pyramid.interfaces import ISecuredView
-from pyramid.interfaces import IStaticURLInfo
-from pyramid.interfaces import IView
-from pyramid.interfaces import IViewClassifier
-from pyramid.interfaces import IViewMapper
-from pyramid.interfaces import IViewMapperFactory
-from pyramid.interfaces import PHASE1_CONFIG
+from pyramid.interfaces import (
+ IAuthenticationPolicy,
+ IAuthorizationPolicy,
+ IDebugLogger,
+ IDefaultPermission,
+ IException,
+ IExceptionViewClassifier,
+ IMultiView,
+ IRendererFactory,
+ IRequest,
+ IResponse,
+ IRouteRequest,
+ ISecuredView,
+ IStaticURLInfo,
+ IView,
+ IViewClassifier,
+ IViewMapper,
+ IViewMapperFactory,
+ PHASE1_CONFIG,
+ )
from pyramid import renderers
-from pyramid.compat import string_types
-from pyramid.compat import urlparse
-from pyramid.compat import im_func
-from pyramid.compat import url_quote
-from pyramid.exceptions import ConfigurationError
-from pyramid.exceptions import PredicateMismatch
-from pyramid.httpexceptions import HTTPForbidden
-from pyramid.httpexceptions import HTTPNotFound
+
+from pyramid.compat import (
+ string_types,
+ urlparse,
+ im_func,
+ url_quote,
+ )
+
+from pyramid.exceptions import (
+ ConfigurationError,
+ PredicateMismatch,
+ )
+
+from pyramid.httpexceptions import (
+ HTTPForbidden,
+ HTTPNotFound,
+ )
+
from pyramid.security import NO_PERMISSION_REQUIRED
from pyramid.static import static_view
from pyramid.threadlocal import get_current_registry
from pyramid.view import render_view_to_response
-from pyramid.config.util import DEFAULT_PHASH
-from pyramid.config.util import MAX_ORDER
-from pyramid.config.util import action_method
-from pyramid.config.util import as_sorted_tuple
-from pyramid.config.util import make_predicates
+from pyramid.config.util import (
+ DEFAULT_PHASH,
+ MAX_ORDER,
+ action_method,
+ as_sorted_tuple,
+ make_predicates,
+ )
urljoin = urlparse.urljoin
url_parse = urlparse.urlparse
diff --git a/pyramid/encode.py b/pyramid/encode.py
index a259d1414..65bc95032 100644
--- a/pyramid/encode.py
+++ b/pyramid/encode.py
@@ -1,8 +1,10 @@
-from pyramid.compat import text_type
-from pyramid.compat import binary_type
-from pyramid.compat import is_nonstr_iter
-from pyramid.compat import url_quote as _url_quote
-from pyramid.compat import url_quote_plus as quote_plus # bw compat api (dnr)
+from pyramid.compat import (
+ text_type,
+ binary_type,
+ is_nonstr_iter,
+ url_quote as _url_quote,
+ url_quote_plus as quote_plus, # bw compat api (dnr)
+ )
def url_quote(s, safe=''): # bw compat api
return _url_quote(s, safe=safe)
diff --git a/pyramid/events.py b/pyramid/events.py
index 4a2cd6240..9cb8b31ad 100644
--- a/pyramid/events.py
+++ b/pyramid/events.py
@@ -2,11 +2,13 @@ import venusian
from zope.interface import implementer
-from pyramid.interfaces import IContextFound
-from pyramid.interfaces import INewRequest
-from pyramid.interfaces import INewResponse
-from pyramid.interfaces import IApplicationCreated
-from pyramid.interfaces import IBeforeRender
+from pyramid.interfaces import (
+ IContextFound,
+ INewRequest,
+ INewResponse,
+ IApplicationCreated,
+ IBeforeRender,
+ )
class subscriber(object):
""" Decorator activated via a :term:`scan` which treats the
diff --git a/pyramid/exceptions.py b/pyramid/exceptions.py
index ff598fe2d..04b6e20b7 100644
--- a/pyramid/exceptions.py
+++ b/pyramid/exceptions.py
@@ -1,5 +1,7 @@
-from pyramid.httpexceptions import HTTPNotFound
-from pyramid.httpexceptions import HTTPForbidden
+from pyramid.httpexceptions import (
+ HTTPNotFound,
+ HTTPForbidden,
+ )
NotFound = HTTPNotFound # bw compat
Forbidden = HTTPForbidden # bw compat
diff --git a/pyramid/httpexceptions.py b/pyramid/httpexceptions.py
index bd745df87..c82d6900c 100644
--- a/pyramid/httpexceptions.py
+++ b/pyramid/httpexceptions.py
@@ -128,12 +128,15 @@ from zope.interface import implementer
from webob import html_escape as _html_escape
+from pyramid.compat import (
+ class_types,
+ text_type,
+ binary_type,
+ text_,
+ )
+
from pyramid.interfaces import IExceptionResponse
from pyramid.response import Response
-from pyramid.compat import class_types
-from pyramid.compat import text_type
-from pyramid.compat import binary_type
-from pyramid.compat import text_
def _no_escape(value):
if value is None:
diff --git a/pyramid/i18n.py b/pyramid/i18n.py
index 889227130..b4bc0eaa7 100644
--- a/pyramid/i18n.py
+++ b/pyramid/i18n.py
@@ -1,18 +1,23 @@
import gettext
import os
-from translationstring import Translator
-from translationstring import Pluralizer
-from translationstring import TranslationString # API
-from translationstring import TranslationStringFactory # API
+from translationstring import (
+ Translator,
+ Pluralizer,
+ TranslationString, # API
+ TranslationStringFactory, # API
+ )
TranslationString = TranslationString # PyFlakes
TranslationStringFactory = TranslationStringFactory # PyFlakes
from pyramid.compat import PY3
-from pyramid.interfaces import ILocalizer
-from pyramid.interfaces import ITranslationDirectories
-from pyramid.interfaces import ILocaleNegotiator
+
+from pyramid.interfaces import (
+ ILocalizer,
+ ITranslationDirectories,
+ ILocaleNegotiator,
+ )
from pyramid.threadlocal import get_current_registry
diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py
index 81ff6df1e..475b52313 100644
--- a/pyramid/interfaces.py
+++ b/pyramid/interfaces.py
@@ -1,5 +1,7 @@
-from zope.interface import Attribute
-from zope.interface import Interface
+from zope.interface import (
+ Attribute,
+ Interface,
+ )
from pyramid.compat import PY3
diff --git a/pyramid/mako_templating.py b/pyramid/mako_templating.py
index e4571ba1b..761695220 100644
--- a/pyramid/mako_templating.py
+++ b/pyramid/mako_templating.py
@@ -2,13 +2,21 @@ import os
import sys
import threading
-from zope.interface import implementer
-from zope.interface import Interface
+from zope.interface import (
+ implementer,
+ Interface,
+ )
+
+from pyramid.asset import (
+ resolve_asset_spec,
+ abspath_from_asset_spec,
+ )
+
+from pyramid.compat import (
+ is_nonstr_iter,
+ reraise,
+ )
-from pyramid.asset import resolve_asset_spec
-from pyramid.asset import abspath_from_asset_spec
-from pyramid.compat import is_nonstr_iter
-from pyramid.compat import reraise
from pyramid.interfaces import ITemplateRenderer
from pyramid.settings import asbool
from pyramid.util import DottedNameResolver
diff --git a/pyramid/paster.py b/pyramid/paster.py
index 3fec6c556..cee437ec4 100644
--- a/pyramid/paster.py
+++ b/pyramid/paster.py
@@ -1,11 +1,17 @@
import os
import zope.deprecation
-from paste.deploy import loadapp
-from pyramid.scripting import prepare
+from paste.deploy import (
+ loadapp,
+ appconfig,
+ )
+from pyramid.compat import configparser
+from logging.config import fileConfig
+from pyramid.scripting import prepare
from pyramid.scaffolds import PyramidTemplate # bw compat
+
PyramidTemplate = PyramidTemplate # pyflakes
zope.deprecation.deprecated(
@@ -20,16 +26,52 @@ def get_app(config_uri, name=None, loadapp=loadapp):
If the ``name`` is None, this will attempt to parse the name from
the ``config_uri`` string expecting the format ``inifile#name``.
If no name is found, the name will default to "main"."""
+ path, section = _getpathsec(config_uri, name)
+ config_name = 'config:%s' % path
+ here_dir = os.getcwd()
+ app = loadapp(config_name, name=section, relative_to=here_dir)
+ return app
+
+def get_appsettings(config_uri, name=None, appconfig=appconfig):
+ """ Return a dictionary representing the key/value pairs in an ``app`
+ section within the file represented by ``config_uri``.
+
+ If the ``name`` is None, this will attempt to parse the name from
+ the ``config_uri`` string expecting the format ``inifile#name``.
+ If no name is found, the name will default to "main"."""
+ path, section = _getpathsec(config_uri, name)
+ config_name = 'config:%s' % path
+ here_dir = os.getcwd()
+ return appconfig(config_name, name=section, relative_to=here_dir)
+
+def setup_logging(config_uri, fileConfig=fileConfig,
+ configparser=configparser):
+ """
+ Set up logging via the logging module's fileConfig function with the
+ filename specified via ``config_uri`` (a string in the form
+ ``filename#sectionname``).
+
+ ConfigParser defaults are specified for the special ``__file__``
+ and ``here`` variables, similar to PasteDeploy config loading.
+ """
+ path, _ = _getpathsec(config_uri, None)
+ parser = configparser.ConfigParser()
+ parser.read([path])
+ if parser.has_section('loggers'):
+ config_file = os.path.abspath(path)
+ return fileConfig(
+ config_file,
+ dict(__file__=config_file, here=os.path.dirname(config_file))
+ )
+
+def _getpathsec(config_uri, name):
if '#' in config_uri:
path, section = config_uri.split('#', 1)
else:
path, section = config_uri, 'main'
if name:
section = name
- config_name = 'config:%s' % path
- here_dir = os.getcwd()
- app = loadapp(config_name, name=section, relative_to=here_dir)
- return app
+ return path, section
def bootstrap(config_uri, request=None):
""" Load a WSGI application from the PasteDeploy config file specified
diff --git a/pyramid/renderers.py b/pyramid/renderers.py
index 3197ca6b8..89e5f03ea 100644
--- a/pyramid/renderers.py
+++ b/pyramid/renderers.py
@@ -6,21 +6,32 @@ import threading
from zope.interface import implementer
from zope.deprecation import deprecated
-from pyramid.interfaces import IChameleonLookup
-from pyramid.interfaces import IChameleonTranslate
-from pyramid.interfaces import IRendererGlobalsFactory
-from pyramid.interfaces import IRendererFactory
-from pyramid.interfaces import IResponseFactory
-from pyramid.interfaces import ITemplateRenderer
-from pyramid.interfaces import IRendererInfo
+from pyramid.interfaces import (
+ IChameleonLookup,
+ IChameleonTranslate,
+ IRendererGlobalsFactory,
+ IRendererFactory,
+ IResponseFactory,
+ ITemplateRenderer,
+ IRendererInfo,
+ )
from pyramid.asset import asset_spec_from_abspath
-from pyramid.compat import string_types
-from pyramid.compat import text_type
+
+from pyramid.compat import (
+ string_types,
+ text_type,
+ )
+
from pyramid.decorator import reify
+
from pyramid.events import BeforeRender
-from pyramid.path import caller_package
-from pyramid.path import package_path
+
+from pyramid.path import (
+ caller_package,
+ package_path,
+ )
+
from pyramid.response import Response
from pyramid.threadlocal import get_current_registry
diff --git a/pyramid/request.py b/pyramid/request.py
index 8f5dfbbb8..4005213fa 100644
--- a/pyramid/request.py
+++ b/pyramid/request.py
@@ -7,15 +7,22 @@ from zope.interface.interface import InterfaceClass
from webob import BaseRequest
-from pyramid.interfaces import IRequest
-from pyramid.interfaces import IResponse
-from pyramid.interfaces import ISessionFactory
-from pyramid.interfaces import IResponseFactory
-
-from pyramid.compat import iterkeys_, itervalues_, iteritems_
-from pyramid.compat import text_
-from pyramid.compat import bytes_
-from pyramid.compat import native_
+from pyramid.interfaces import (
+ IRequest,
+ IResponse,
+ ISessionFactory,
+ IResponseFactory,
+ )
+
+from pyramid.compat import (
+ iterkeys_,
+ itervalues_,
+ iteritems_,
+ text_,
+ bytes_,
+ native_,
+ )
+
from pyramid.decorator import reify
from pyramid.response import Response
from pyramid.url import URLMethodsMixin
diff --git a/pyramid/router.py b/pyramid/router.py
index fdb55779b..0c115a1ac 100644
--- a/pyramid/router.py
+++ b/pyramid/router.py
@@ -1,26 +1,37 @@
-from zope.interface import implementer
-from zope.interface import providedBy
-
-from pyramid.interfaces import IDebugLogger
-from pyramid.interfaces import IRequest
-from pyramid.interfaces import IRootFactory
-from pyramid.interfaces import IRouteRequest
-from pyramid.interfaces import IRouter
-from pyramid.interfaces import IRequestFactory
-from pyramid.interfaces import IRoutesMapper
-from pyramid.interfaces import ITraverser
-from pyramid.interfaces import IView
-from pyramid.interfaces import IViewClassifier
-from pyramid.interfaces import ITweens
-
-from pyramid.events import ContextFound
-from pyramid.events import NewRequest
-from pyramid.events import NewResponse
+from zope.interface import (
+ implementer,
+ providedBy,
+ )
+
+from pyramid.interfaces import (
+ IDebugLogger,
+ IRequest,
+ IRootFactory,
+ IRouteRequest,
+ IRouter,
+ IRequestFactory,
+ IRoutesMapper,
+ ITraverser,
+ IView,
+ IViewClassifier,
+ ITweens,
+ )
+
+from pyramid.events import (
+ ContextFound,
+ NewRequest,
+ NewResponse,
+ )
+
from pyramid.httpexceptions import HTTPNotFound
from pyramid.request import Request
from pyramid.threadlocal import manager
-from pyramid.traversal import DefaultRootFactory
-from pyramid.traversal import ResourceTreeTraverser
+
+from pyramid.traversal import (
+ DefaultRootFactory,
+ ResourceTreeTraverser,
+ )
+
from pyramid.tweens import excview_tween_factory
@implementer(IRouter)
diff --git a/pyramid/scaffolds/__init__.py b/pyramid/scaffolds/__init__.py
index 20840a5d4..dc6926024 100644
--- a/pyramid/scaffolds/__init__.py
+++ b/pyramid/scaffolds/__init__.py
@@ -2,16 +2,12 @@ import binascii
import os
from pyramid.compat import native_
-from pyramid.compat import text_
from pyramid.scaffolds.template import Template
class PyramidTemplate(Template):
def pre(self, command, output_dir, vars):
vars['random_string'] = native_(binascii.hexlify(os.urandom(20)))
- # placeholder text values
- vars['one'] = text_('one')
- vars['two'] = text_('two')
package_logger = vars['package']
if package_logger == 'root':
# Rename the app logger in the rare case a project is named 'root'
@@ -37,4 +33,11 @@ class ZODBProjectTemplate(PyramidTemplate):
class AlchemyProjectTemplate(PyramidTemplate):
_template_dir = 'alchemy'
summary = 'Pyramid SQLAlchemy project using url dispatch'
-
+ def post(self, command, output_dir, vars): # pragma: no cover
+ val = PyramidTemplate.post(self, command, output_dir, vars)
+ self.out('')
+ self.out('Please run the "populate_%(package)s" script to set up the '
+ 'SQL database before starting the application (e.g. '
+ '"$myvirtualenv/bin/populate_%(package)s development.ini".)'
+ % vars)
+ return val
diff --git a/pyramid/scaffolds/alchemy/+package+/models.py b/pyramid/scaffolds/alchemy/+package+/models.py
index 000dadd91..b6ac15429 100644
--- a/pyramid/scaffolds/alchemy/+package+/models.py
+++ b/pyramid/scaffolds/alchemy/+package+/models.py
@@ -1,11 +1,15 @@
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Unicode
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
@@ -15,7 +19,7 @@ Base = declarative_base()
class MyModel(Base):
__tablename__ = 'models'
id = Column(Integer, primary_key=True)
- name = Column(Unicode(255), unique=True)
+ name = Column(Text, unique=True)
value = Column(Integer)
def __init__(self, name, value):
diff --git a/pyramid/scaffolds/alchemy/+package+/scripts/populate.py b/pyramid/scaffolds/alchemy/+package+/scripts/populate.py
new file mode 100644
index 000000000..0e828465f
--- /dev/null
+++ b/pyramid/scaffolds/alchemy/+package+/scripts/populate.py
@@ -0,0 +1,35 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ MyModel,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = MyModel(name='one', value=1)
+ DBSession.add(model)
diff --git a/pyramid/scaffolds/alchemy/+package+/scripts/populate.py_tmpl b/pyramid/scaffolds/alchemy/+package+/scripts/populate.py_tmpl
deleted file mode 100644
index 7af326be9..000000000
--- a/pyramid/scaffolds/alchemy/+package+/scripts/populate.py_tmpl
+++ /dev/null
@@ -1,27 +0,0 @@
-import os
-import sys
-
-from paste.deploy.loadwsgi import appconfig
-from sqlalchemy import engine_from_config
-import transaction
-
-from ..models import DBSession
-from ..models import MyModel
-from ..models import Base
-
-def usage(argv):
- print('usage: %s <Pyramid ini filename>' % os.path.basename(argv[0]))
- sys.exit(1)
-
-def main(argv=sys.argv):
- try:
- config_filename = argv[1]
- except IndexError:
- usage(argv)
- settings = appconfig('config:' + os.path.abspath(config_filename))
- engine = engine_from_config(settings, 'sqlalchemy.')
- DBSession.configure(bind=engine)
- Base.metadata.create_all(engine)
- with transaction.manager:
- model = MyModel(name={{repr(one)}}, value=1)
- DBSession.add(model)
diff --git a/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl b/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl
index 3b4b028a9..729b337cb 100644
--- a/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl
+++ b/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl
@@ -17,7 +17,7 @@ class TestMyView(unittest.TestCase):
DBSession.configure(bind=engine)
Base.metadata.create_all(engine)
with transaction.manager:
- model = MyModel(name={{repr(one)}}, value=55)
+ model = MyModel(name='one', value=55)
DBSession.add(model)
def tearDown(self):
diff --git a/pyramid/scaffolds/alchemy/+package+/views.py_tmpl b/pyramid/scaffolds/alchemy/+package+/views.py_tmpl
index 568b73c18..b7b23fc67 100644
--- a/pyramid/scaffolds/alchemy/+package+/views.py_tmpl
+++ b/pyramid/scaffolds/alchemy/+package+/views.py_tmpl
@@ -1,9 +1,11 @@
from pyramid.view import view_config
-from .models import DBSession
-from .models import MyModel
+from .models import (
+ DBSession,
+ MyModel,
+ )
@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
- one = DBSession.query(MyModel).filter(MyModel.name=={{repr(one)}}).first()
+ one = DBSession.query(MyModel).filter(MyModel.name=='one').first()
return {'one':one, 'project':'{{project}}'}
diff --git a/pyramid/scripting.py b/pyramid/scripting.py
index 47178c22e..f1dc24637 100644
--- a/pyramid/scripting.py
+++ b/pyramid/scripting.py
@@ -1,8 +1,12 @@
from pyramid.config import global_registries
from pyramid.exceptions import ConfigurationError
from pyramid.request import Request
-from pyramid.interfaces import IRequestFactory
-from pyramid.interfaces import IRootFactory
+
+from pyramid.interfaces import (
+ IRequestFactory,
+ IRootFactory,
+ )
+
from pyramid.threadlocal import manager as threadlocal_manager
from pyramid.traversal import DefaultRootFactory
diff --git a/pyramid/scripts/pserve.py b/pyramid/scripts/pserve.py
index c6e8f0374..a0a3a8a70 100644
--- a/pyramid/scripts/pserve.py
+++ b/pyramid/scripts/pserve.py
@@ -22,7 +22,7 @@ import traceback
from paste.deploy import loadapp, loadserver
-from pyramid.scripts.common import logging_file_config
+from pyramid.paster import setup_logging
MAXFD = 1024
@@ -266,7 +266,7 @@ class PServeCommand(object):
log_fn = None
if log_fn:
log_fn = os.path.join(base, log_fn)
- logging_file_config(log_fn)
+ setup_logging(log_fn)
server = self.loadserver(server_spec, name=server_name,
relative_to=base, global_conf=vars)
diff --git a/pyramid/scripts/pshell.py b/pyramid/scripts/pshell.py
index 72e2c0a89..dfac9dbce 100644
--- a/pyramid/scripts/pshell.py
+++ b/pyramid/scripts/pshell.py
@@ -6,7 +6,7 @@ from pyramid.compat import configparser
from pyramid.util import DottedNameResolver
from pyramid.paster import bootstrap
-from pyramid.scripts.common import logging_file_config
+from pyramid.paster import setup_logging
def main(argv=sys.argv, quiet=False):
command = PShellCommand(argv, quiet)
@@ -85,7 +85,7 @@ class PShellCommand(object):
return
config_uri = self.args[0]
config_file = config_uri.split('#', 1)[0]
- logging_file_config(config_file)
+ setup_logging(config_file)
self.pshell_file_config(config_file)
# bootstrap the environ
diff --git a/pyramid/security.py b/pyramid/security.py
index a552b613a..f29edd678 100644
--- a/pyramid/security.py
+++ b/pyramid/security.py
@@ -1,9 +1,11 @@
from zope.interface import providedBy
-from pyramid.interfaces import IAuthenticationPolicy
-from pyramid.interfaces import IAuthorizationPolicy
-from pyramid.interfaces import ISecuredView
-from pyramid.interfaces import IViewClassifier
+from pyramid.interfaces import (
+ IAuthenticationPolicy,
+ IAuthorizationPolicy,
+ ISecuredView,
+ IViewClassifier,
+ )
from pyramid.compat import map_
from pyramid.threadlocal import get_current_registry
diff --git a/pyramid/session.py b/pyramid/session.py
index 8d0c6c423..76b2b30b1 100644
--- a/pyramid/session.py
+++ b/pyramid/session.py
@@ -7,11 +7,14 @@ import os
from zope.interface import implementer
-from pyramid.compat import pickle
-from pyramid.compat import PY3
-from pyramid.compat import text_
-from pyramid.compat import bytes_
-from pyramid.compat import native_
+from pyramid.compat import (
+ pickle,
+ PY3,
+ text_,
+ bytes_,
+ native_,
+ )
+
from pyramid.interfaces import ISession
from pyramid.util import strings_differ
diff --git a/pyramid/static.py b/pyramid/static.py
index ba4ac0fa1..61ee67573 100644
--- a/pyramid/static.py
+++ b/pyramid/static.py
@@ -1,23 +1,34 @@
# -*- coding: utf-8 -*-
import mimetypes
import os
-from os.path import normcase
-from os.path import normpath
-from os.path import join
-from os.path import getmtime
-from os.path import getsize
-from os.path import isdir
-from os.path import exists
-from pkg_resources import resource_exists
-from pkg_resources import resource_filename
-from pkg_resources import resource_isdir
+
+from os.path import (
+ normcase,
+ normpath,
+ join,
+ getmtime,
+ getsize,
+ isdir,
+ exists,
+ )
+
+from pkg_resources import (
+ resource_exists,
+ resource_filename,
+ resource_isdir,
+ )
from repoze.lru import lru_cache
from pyramid.asset import resolve_asset_spec
+
from pyramid.compat import text_
-from pyramid.httpexceptions import HTTPNotFound
-from pyramid.httpexceptions import HTTPMovedPermanently
+
+from pyramid.httpexceptions import (
+ HTTPNotFound,
+ HTTPMovedPermanently,
+ )
+
from pyramid.path import caller_package
from pyramid.response import Response
from pyramid.traversal import traversal_path_info
diff --git a/pyramid/testing.py b/pyramid/testing.py
index 0e27c301e..025730ac5 100644
--- a/pyramid/testing.py
+++ b/pyramid/testing.py
@@ -3,32 +3,49 @@ import os
from zope.deprecation import deprecated
-from zope.interface import implementer
-from zope.interface import Interface
-from zope.interface import alsoProvides
-
-from pyramid.interfaces import IRequest
-from pyramid.interfaces import IResponseFactory
-from pyramid.interfaces import ISecuredView
-from pyramid.interfaces import IView
-from pyramid.interfaces import IViewClassifier
-from pyramid.interfaces import ISession
-
-from pyramid.compat import PY3
-from pyramid.compat import PYPY
-from pyramid.compat import class_types
+from zope.interface import (
+ implementer,
+ Interface,
+ alsoProvides,
+ )
+
+from pyramid.interfaces import (
+ IRequest,
+ IResponseFactory,
+ ISecuredView,
+ IView,
+ IViewClassifier,
+ ISession,
+ )
+
+from pyramid.compat import (
+ PY3,
+ PYPY,
+ class_types,
+ )
+
from pyramid.config import Configurator
from pyramid.decorator import reify
from pyramid.httpexceptions import HTTPForbidden
from pyramid.response import Response
from pyramid.registry import Registry
-from pyramid.security import Authenticated
-from pyramid.security import Everyone
-from pyramid.security import has_permission
-from pyramid.threadlocal import get_current_registry
-from pyramid.threadlocal import manager
-from pyramid.request import DeprecatedRequestMethodsMixin
-from pyramid.request import CallbackMethodsMixin
+
+from pyramid.security import (
+ Authenticated,
+ Everyone,
+ has_permission,
+ )
+
+from pyramid.threadlocal import (
+ get_current_registry,
+ manager,
+ )
+
+from pyramid.request import (
+ DeprecatedRequestMethodsMixin,
+ CallbackMethodsMixin,
+ )
+
from pyramid.url import URLMethodsMixin
_marker = object()
diff --git a/pyramid/tests/test_paster.py b/pyramid/tests/test_paster.py
index d23c156c2..5901c0416 100644
--- a/pyramid/tests/test_paster.py
+++ b/pyramid/tests/test_paster.py
@@ -1,6 +1,6 @@
import unittest
-class TestGetApp(unittest.TestCase):
+class Test_get_app(unittest.TestCase):
def _callFUT(self, config_file, section_name, loadapp):
from pyramid.paster import get_app
return get_app(config_file, section_name, loadapp)
@@ -8,7 +8,7 @@ class TestGetApp(unittest.TestCase):
def test_it(self):
import os
app = DummyApp()
- loadapp = DummyLoadApp(app)
+ loadapp = DummyLoadWSGI(app)
result = self._callFUT('/foo/bar/myapp.ini', 'myapp', loadapp)
self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
self.assertEqual(loadapp.section_name, 'myapp')
@@ -18,7 +18,7 @@ class TestGetApp(unittest.TestCase):
def test_it_with_hash(self):
import os
app = DummyApp()
- loadapp = DummyLoadApp(app)
+ loadapp = DummyLoadWSGI(app)
result = self._callFUT('/foo/bar/myapp.ini#myapp', None, loadapp)
self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
self.assertEqual(loadapp.section_name, 'myapp')
@@ -28,14 +28,64 @@ class TestGetApp(unittest.TestCase):
def test_it_with_hash_and_name_override(self):
import os
app = DummyApp()
- loadapp = DummyLoadApp(app)
+ loadapp = DummyLoadWSGI(app)
result = self._callFUT('/foo/bar/myapp.ini#myapp', 'yourapp', loadapp)
self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
self.assertEqual(loadapp.section_name, 'yourapp')
self.assertEqual(loadapp.relative_to, os.getcwd())
self.assertEqual(result, app)
-class TestBootstrap(unittest.TestCase):
+class Test_get_appsettings(unittest.TestCase):
+ def _callFUT(self, config_file, section_name, appconfig):
+ from pyramid.paster import get_appsettings
+ return get_appsettings(config_file, section_name, appconfig)
+
+ def test_it(self):
+ import os
+ values = {'a':1}
+ appconfig = DummyLoadWSGI(values)
+ result = self._callFUT('/foo/bar/myapp.ini', 'myapp', appconfig)
+ self.assertEqual(appconfig.config_name, 'config:/foo/bar/myapp.ini')
+ self.assertEqual(appconfig.section_name, 'myapp')
+ self.assertEqual(appconfig.relative_to, os.getcwd())
+ self.assertEqual(result, values)
+
+ def test_it_with_hash(self):
+ import os
+ values = {'a':1}
+ appconfig = DummyLoadWSGI(values)
+ result = self._callFUT('/foo/bar/myapp.ini#myapp', None, appconfig)
+ self.assertEqual(appconfig.config_name, 'config:/foo/bar/myapp.ini')
+ self.assertEqual(appconfig.section_name, 'myapp')
+ self.assertEqual(appconfig.relative_to, os.getcwd())
+ self.assertEqual(result, values)
+
+ def test_it_with_hash_and_name_override(self):
+ import os
+ values = {'a':1}
+ appconfig = DummyLoadWSGI(values)
+ result = self._callFUT('/foo/bar/myapp.ini#myapp', 'yourapp', appconfig)
+ self.assertEqual(appconfig.config_name, 'config:/foo/bar/myapp.ini')
+ self.assertEqual(appconfig.section_name, 'yourapp')
+ self.assertEqual(appconfig.relative_to, os.getcwd())
+ self.assertEqual(result, values)
+
+class Test_setup_logging(unittest.TestCase):
+ def _callFUT(self, config_file):
+ from pyramid.paster import setup_logging
+ dummy_cp = DummyConfigParserModule
+ return setup_logging(config_file, self.fileConfig, dummy_cp)
+
+ def test_it(self):
+ config_file, dict = self._callFUT('/abc')
+ self.assertEqual(config_file, '/abc')
+ self.assertEqual(dict['__file__'], '/abc')
+ self.assertEqual(dict['here'], '/')
+
+ def fileConfig(self, config_file, dict):
+ return config_file, dict
+
+class Test_bootstrap(unittest.TestCase):
def _callFUT(self, config_uri, request=None):
from pyramid.paster import bootstrap
return bootstrap(config_uri, request)
@@ -82,15 +132,15 @@ class DummyRegistry(object):
dummy_registry = DummyRegistry()
-class DummyLoadApp:
- def __init__(self, app):
- self.app = app
+class DummyLoadWSGI:
+ def __init__(self, result):
+ self.result = result
def __call__(self, config_name, name=None, relative_to=None):
self.config_name = config_name
self.section_name = name
self.relative_to = relative_to
- return self.app
+ return self.result
class DummyApp:
def __init__(self):
@@ -103,3 +153,15 @@ class DummyRequest:
self.environ = environ
self.matchdict = {}
+class DummyConfigParser(object):
+ def read(self, x):
+ pass
+
+ def has_section(self, name):
+ return True
+
+class DummyConfigParserModule(object):
+ ConfigParser = DummyConfigParser
+
+
+
diff --git a/pyramid/traversal.py b/pyramid/traversal.py
index ee6b5fb7a..cd624fd30 100644
--- a/pyramid/traversal.py
+++ b/pyramid/traversal.py
@@ -5,20 +5,25 @@ from zope.interface.interfaces import IInterface
from repoze.lru import lru_cache
-from pyramid.interfaces import IContextURL
-from pyramid.interfaces import IRequestFactory
-from pyramid.interfaces import ITraverser
-from pyramid.interfaces import VH_ROOT_KEY
-
-from pyramid.compat import PY3
-from pyramid.compat import native_
-from pyramid.compat import text_
-from pyramid.compat import bytes_
-from pyramid.compat import ascii_native_
-from pyramid.compat import text_type
-from pyramid.compat import binary_type
-from pyramid.compat import url_unquote_native
-from pyramid.compat import is_nonstr_iter
+from pyramid.interfaces import (
+ IContextURL,
+ IRequestFactory,
+ ITraverser,
+ VH_ROOT_KEY,
+ )
+
+from pyramid.compat import (
+ PY3,
+ native_,
+ text_,
+ bytes_,
+ ascii_native_,
+ text_type,
+ binary_type,
+ url_unquote_native,
+ is_nonstr_iter,
+ )
+
from pyramid.encode import url_quote
from pyramid.exceptions import URLDecodeError
from pyramid.location import lineage
diff --git a/pyramid/tweens.py b/pyramid/tweens.py
index 65d7c3919..73a95e1b8 100644
--- a/pyramid/tweens.py
+++ b/pyramid/tweens.py
@@ -1,6 +1,9 @@
import sys
-from pyramid.interfaces import IExceptionViewClassifier
-from pyramid.interfaces import IView
+
+from pyramid.interfaces import (
+ IExceptionViewClassifier,
+ IView,
+ )
from zope.interface import providedBy
diff --git a/pyramid/url.py b/pyramid/url.py
index 617529955..3f934b364 100644
--- a/pyramid/url.py
+++ b/pyramid/url.py
@@ -4,17 +4,24 @@ import os
from repoze.lru import lru_cache
-from pyramid.interfaces import IContextURL
-from pyramid.interfaces import IRoutesMapper
-from pyramid.interfaces import IStaticURLInfo
-
-from pyramid.compat import native_
-from pyramid.compat import text_type
+from pyramid.interfaces import (
+ IContextURL,
+ IRoutesMapper,
+ IStaticURLInfo,
+ )
+
+from pyramid.compat import (
+ native_,
+ text_type,
+ )
from pyramid.encode import urlencode
from pyramid.path import caller_package
from pyramid.threadlocal import get_current_registry
-from pyramid.traversal import TraversalContextURL
-from pyramid.traversal import quote_path_segment
+
+from pyramid.traversal import (
+ TraversalContextURL,
+ quote_path_segment,
+ )
class URLMethodsMixin(object):
""" Request methods mixin for BaseRequest having to do with URL
diff --git a/pyramid/urldispatch.py b/pyramid/urldispatch.py
index 662615845..c7520b8d2 100644
--- a/pyramid/urldispatch.py
+++ b/pyramid/urldispatch.py
@@ -1,18 +1,26 @@
import re
from zope.interface import implementer
-from pyramid.interfaces import IRoutesMapper
-from pyramid.interfaces import IRoute
-
-from pyramid.compat import native_
-from pyramid.compat import bytes_
-from pyramid.compat import text_type
-from pyramid.compat import string_types
-from pyramid.compat import is_nonstr_iter
-from pyramid.compat import url_quote
+from pyramid.interfaces import (
+ IRoutesMapper,
+ IRoute,
+ )
+
+from pyramid.compat import (
+ native_,
+ bytes_,
+ text_type,
+ string_types,
+ is_nonstr_iter,
+ url_quote,
+ )
+
from pyramid.exceptions import URLDecodeError
-from pyramid.traversal import traversal_path_info
-from pyramid.traversal import quote_path_segment
+
+from pyramid.traversal import (
+ traversal_path_info,
+ quote_path_segment,
+ )
_marker = object()
diff --git a/pyramid/view.py b/pyramid/view.py
index 13d5cfe7b..da5a71c4c 100644
--- a/pyramid/view.py
+++ b/pyramid/view.py
@@ -3,13 +3,17 @@ import venusian
from zope.interface import providedBy
from zope.deprecation import deprecated
-from pyramid.interfaces import IRoutesMapper
-from pyramid.interfaces import IView
-from pyramid.interfaces import IViewClassifier
+from pyramid.interfaces import (
+ IRoutesMapper,
+ IView,
+ IViewClassifier,
+ )
from pyramid.compat import map_
-from pyramid.httpexceptions import HTTPFound
-from pyramid.httpexceptions import default_exceptionresponse_view
+from pyramid.httpexceptions import (
+ HTTPFound,
+ default_exceptionresponse_view,
+ )
from pyramid.path import caller_package
from pyramid.static import static_view
from pyramid.threadlocal import get_current_registry
@@ -156,11 +160,12 @@ class view_config(object):
backwards compatibility purposes, as the name
:class:`pyramid.view.bfg_view`.
- The following arguments are supported as arguments to
+ The following arguments are supported to
:class:`pyramid.view.view_config`: ``context``, ``permission``, ``name``,
``request_type``, ``route_name``, ``request_method``, ``request_param``,
``containment``, ``xhr``, ``accept``, ``header``, ``path_info``,
- ``custom_predicates``, ``decorator``, ``mapper``, and ``http_cache``.
+ ``custom_predicates``, ``decorator``, ``mapper``, ``http_cache``,
+ and ``match_param``.
The meanings of these arguments are the same as the arguments passed to
:meth:`pyramid.config.Configurator.add_view`.