summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCasey Duncan <casey.duncan@gmail.com>2010-11-22 17:12:13 -0700
committerCasey Duncan <casey.duncan@gmail.com>2010-11-22 17:12:13 -0700
commit51bed35bfb3bb862034514da257a348e33d53860 (patch)
tree2f4a770510c71872cb42dc943f5a0fae7fdb03c9
parent18fc334f0fb0b3f8925f415031a87016ce574320 (diff)
parenteba45fd998b68d72b6e11f5b0bfa86d0ab17ee43 (diff)
downloadpyramid-51bed35bfb3bb862034514da257a348e33d53860.tar.gz
pyramid-51bed35bfb3bb862034514da257a348e33d53860.tar.bz2
pyramid-51bed35bfb3bb862034514da257a348e33d53860.zip
Merge https://github.com/Pylons/pyramid
-rw-r--r--.gitignore1
-rw-r--r--CHANGES.txt56
-rw-r--r--TODO.txt66
-rw-r--r--docs/api/interfaces.rst1
-rw-r--r--docs/conf.py2
-rw-r--r--docs/designdefense.rst37
-rw-r--r--docs/index.rst51
-rw-r--r--docs/narr/MyProject/development.ini26
-rw-r--r--docs/narr/contextfinding.rst2
-rw-r--r--docs/narr/declarative.rst2
-rw-r--r--docs/narr/handlers.rst10
-rw-r--r--docs/narr/hybrid.rst30
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst41
-rw-r--r--docs/tutorials/wiki2/definingviews.rst8
-rw-r--r--docs/tutorials/wiki2/src/authorization/development.ini37
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/__init__.py15
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/models.py4
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/tests.py8
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/development.ini37
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py9
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/models.py4
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py3
-rw-r--r--docs/tutorials/wiki2/src/models/development.ini37
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/__init__.py9
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/models.py4
-rw-r--r--docs/tutorials/wiki2/src/views/development.ini37
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/__init__.py15
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/models.py4
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/tests.py8
-rw-r--r--docs/zcml/route.rst6
-rw-r--r--pyramid/configuration.py38
-rw-r--r--pyramid/interfaces.py40
-rwxr-xr-xpyramid/paster_templates/alchemy/+package+/__init__.py_tmpl9
-rwxr-xr-xpyramid/paster_templates/alchemy/+package+/models.py7
-rw-r--r--pyramid/paster_templates/alchemy/development.ini_tmpl37
-rw-r--r--pyramid/paster_templates/pylons_basic/+package+/__init__.py_tmpl2
-rw-r--r--pyramid/paster_templates/pylons_basic/development.ini_tmpl31
-rw-r--r--pyramid/paster_templates/pylons_minimal/+package+/__init__.py_tmpl2
-rw-r--r--pyramid/paster_templates/pylons_minimal/development.ini_tmpl26
-rw-r--r--pyramid/paster_templates/pylons_sqla/+package+/__init__.py_tmpl15
-rw-r--r--pyramid/paster_templates/pylons_sqla/+package+/models.py3
-rw-r--r--pyramid/paster_templates/pylons_sqla/+package+/tests.py_tmpl3
-rw-r--r--pyramid/paster_templates/pylons_sqla/development.ini_tmpl39
-rw-r--r--pyramid/paster_templates/routesalchemy/+package+/__init__.py_tmpl9
-rw-r--r--pyramid/paster_templates/routesalchemy/+package+/models.py4
-rw-r--r--pyramid/paster_templates/routesalchemy/+package+/tests.py_tmpl5
-rw-r--r--pyramid/paster_templates/routesalchemy/development.ini_tmpl43
-rw-r--r--pyramid/paster_templates/starter/development.ini_tmpl26
-rw-r--r--pyramid/paster_templates/starter_zcml/development.ini_tmpl26
-rw-r--r--pyramid/paster_templates/zodb/development.ini_tmpl26
-rw-r--r--pyramid/testing.py23
-rw-r--r--pyramid/tests/test_configuration.py44
-rw-r--r--pyramid/url.py4
53 files changed, 705 insertions, 327 deletions
diff --git a/.gitignore b/.gitignore
index 706f6493d..ae0b17b8e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
*.pt.py
*.txt.py
.coverage
+tutorial.db
env26/
env24/
env27/
diff --git a/CHANGES.txt b/CHANGES.txt
index 692e3cc35..2ea0ac448 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,14 +4,54 @@ Next release
Features
--------
+- Add logging configuration to all paster templates.
+
+- ``pyramid_alchemy``, ``pyramid_routesalchemy``, and ``pylons_sqla`` paster
+ templates now use idiomatic SQLAlchemy configuration in their respective
+ ``.ini`` files and Python code.
+
+- ``pyramid.testig.DummyRequest`` now has a class variable, ``query_string``,
+ which defaults to the empty string.
+
+Bug Fixes
+---------
+
+- The ``pyramid_routesalchemy`` paster template's unit tests failed
+ (``AssertionError: 'SomeProject' != 'someproject'``). This is fixed.
+
+- Make default renderer work (renderer factory registered with no name, which
+ is active for every view unless the view names a specific renderer).
+
+Documentation
+-------------
+
+- "Sample Applications" section of docs changed to note existence of Cluegun,
+ Shootout and Virginia sample applications, ported from their repoze.bfg
+ origin packages.
+
+- SQLAlchemy+URLDispatch tutorial updated to integrate changes to
+ ``pyramid_routesalchemy`` template.
+
+- Add ``pyramid.interfaces.ITemplateRenderer`` interface to Interfaces API
+ chapter (has ``implementation()`` method, required to be used when getting
+ at Chameleon macros).
+
+
+1.0a4 (2010-11-21)
+==================
+
+Features
+--------
+
- URL Dispatch now allows for replacement markers to be located anywhere
in the pattern, instead of immediately following a ``/``.
- URL Dispatch now uses the form ``{marker}`` to denote a replace marker in
- the route pattern instead of ``:marker``. The old syntax is still backwards
- compatible and accepted. The new format allows a regular expression for that
- marker location to be used instead of the default ``[^/]+``, for example
- ``{marker:\d+}`` is now valid to require the marker to be digits.
+ the route pattern instead of ``:marker``. The old colon-style marker syntax
+ is still accepted for backwards compatibility. The new format allows a
+ regular expression for that marker location to be used instead of the
+ default ``[^/]+``, for example ``{marker:\d+}`` is now valid to require the
+ marker to be digits.
- Add a ``pyramid.url.route_path`` API, allowing folks to generate relative
URLs. Calling ``route_path`` is the same as calling
@@ -30,6 +70,10 @@ Features
``config.end()`` is no longer necessary. All paster templates have been
changed to no longer call these functions.
+- Fix configurator to not convert ``ImportError`` to ``ConfigurationError``
+ if the import that failed was unrelated to the import requested via a
+ dotted name when resolving dotted names (such as view dotted names).
+
Documentation
-------------
@@ -58,14 +102,14 @@ Bug Fixes
ASCII string rather than being passed along to downstream code as a
convenience to the user and to prevent puzzling second-order failures from
cropping up (all failures will occur within ``pyramid.traversal.traverse``
- rather than later down the line as the result of calling
+ rather than later down the line as the result of calling e.g.
``traversal_path``).
Backwards Incompatibilities
---------------------------
- The ``pyramid.testing.zcml_configure`` API has been removed. It had been
- advertised as removed since 1.2a1, but hadn't actually been.
+ advertised as removed since repoze.bfg 1.2a1, but hadn't actually been.
Deprecations
------------
diff --git a/TODO.txt b/TODO.txt
index ab2b521ae..4319e3cca 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -6,58 +6,17 @@ Must-Have (before 1.0)
- Add a ``handler`` ZCML directive. This implies some slightly dicey
refactoring of the configurator to allow it to generate ZCML
- "discriminators" for views and routes.
+ "discriminators" for views and routes, that could be implemented in terms
+ of "twophase configuration" in "should have" below.
- Provide a .flash API on session object.
-- Make default renderer work (renderer registered with no name, which is
- active for every view unless the view names a specific renderer).
-
- Use ``@register_view`` instead of ``@view_config`` and change view docs to
use "view registration" instead of "view configuration".
-- SQLAlchemy idiomatics:
-
- <RaFromBRC> mcdonc: those paster templates all look pretty good... the
- only thing i'd consider is adjusting your config variable names to match
- exactly what sqlalchemy uses as parameter names, see here:
- http://www.sqlalchemy.org/docs/core/engines.html
-
- <RaFromBRC> mcdonc: especially in the pylons_sqla ini file, where the db
- initialization is mixed in w/ the app config...
-
- <RaFromBRC> ... i'd use "sqlalchemy.PARAMETER" for all of the sqla
- settings, so it could easily be handed to engine_from_config w/o any need
- to parse by hand
-
- <RaFromBRC> mcdonc: in the other ini files, where sqlalchemy is given its
- own part, the "sqlalchemy." prefix probably isn't necessary, but matching
- the parameter names (e.g. 'url' instead of 'db_string') is still probably
- a good idea
-
-- Non-bwcompat use of threadlocals that need to be documented or ameliorated:
-
- security.principals_allowed_by_permission
-
- resource.OverrideProvider._get_overrides: can't credibly be removed,
- because it stores an overrideprovider as a module-scope global.
-
- traversal.traverse: this API is a stepchild, and needs to be changed.
-
- Configurator.add_translation_dirs: not passed any context but a message,
- can't credibly be removed.
-
-- Better ``config.add_handler`` documentation.
-
-- Fix DottedNameResolver to not convert ImportError to ConfigurationError if
- the import that failed was unrelated to the import requested via a dotted
- name.
-
Should-Have
-----------
-- Try to make test suite pass on IronPython.
-
- Add docs for httpexceptions module for each webob.exc class that inherits
from WSGIHTTPException.
@@ -74,9 +33,27 @@ Should-Have
- Change "Cleaning up After a Request" in the urldispatch chapter to
use ``request.add_response_callback``.
+- Twophase configuration (config = Configurator(autocommit=False)). Maybe
+ use ``zope.configuration`` ConfigurationContext as config.registry.ctx and
+ push execution into the configurator.
+
Nice-to-Have
------------
+- Try to make test suite pass on IronPython.
+
+- Non-bwcompat use of threadlocals that need to be documented or ameliorated:
+
+ security.principals_allowed_by_permission
+
+ resource.OverrideProvider._get_overrides: can't credibly be removed,
+ because it stores an overrideprovider as a module-scope global.
+
+ traversal.traverse: this API is a stepchild, and needs to be changed.
+
+ Configurator.add_translation_dirs: not passed any context but a message,
+ can't credibly be removed.
+
- Supply ``X-Vhm-Host`` support.
- Basic WSGI documentation (pipeline / app / server).
@@ -85,7 +62,8 @@ Nice-to-Have
- Change docs about creating a venusian decorator to not use ZCA.
-- ``decorator=`` parameter to bfg_view.
+- ``decorator=`` parameter to view_config. This would replace the existing
+ _map_view "decorator" if it existed.
- Try to better explain the relationship between a renderer and a
template in the templates chapter and elsewhere. Scan the
diff --git a/docs/api/interfaces.rst b/docs/api/interfaces.rst
index b27428d89..b3c14e5f7 100644
--- a/docs/api/interfaces.rst
+++ b/docs/api/interfaces.rst
@@ -33,4 +33,5 @@ Other Interfaces
.. autointerface:: IRendererInfo
+ .. autointerface:: ITemplateRenderer
diff --git a/docs/conf.py b/docs/conf.py
index 81096da3b..e520c9d82 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -76,7 +76,7 @@ copyright = '%s, Agendaless Consulting' % datetime.datetime.now().year
# other places throughout the built documents.
#
# The short X.Y version.
-version = '1.0a3'
+version = '1.0a4'
# The full version, including alpha/beta/rc tags.
release = version
diff --git a/docs/designdefense.rst b/docs/designdefense.rst
index 92facf13c..e3a816269 100644
--- a/docs/designdefense.rst
+++ b/docs/designdefense.rst
@@ -40,9 +40,7 @@ Too Complex
if __name__ == '__main__':
config = Configurator()
- config.begin()
config.add_view(hello_world)
- config.end()
app = config.make_wsgi_app()
serve(app)
@@ -549,9 +547,7 @@ everything done completely imperatively. For example, the very most basic
if __name__ == '__main__':
config = Configurator()
- config.begin()
config.add_view(hello_world)
- config.end()
app = config.make_wsgi_app()
serve(app)
@@ -1674,37 +1670,6 @@ can interface with a WSGI application is placed on the server
developer, not the web framework developer, making it more likely to
be timely and correct.
-:meth:`pyramid.configuration.Configurator.begin` and :meth:`pyramid.configuration.Configurator.end` methods
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-The methods :meth:`pyramid.configuration.Configurator.begin` and
-:meth:`pyramid.configuration.Configurator.end` are used to bracket
-the configuration phase of a :app:`Pyramid` application.
-
-These exist because existing legacy third party *configuration* (not
-runtime) code relies on a threadlocal stack being populated. The
-``begin`` method pushes data on to a threadlocal stack. The ``end``
-method pops it back off.
-
-For the simplest applications, these lines are actually not required.
-I *could* omit them from every Pyramid hello world app without ill
-effect. However, when users use certain configuration methods (ones
-not represented in the hello world app), calling code will begin to
-fail when it is not bracketed between a ``begin()`` and an ``end()``.
-It is just easier to tell users that this bracketing is required than
-to try to explain to them which circumstances it is actually required
-and which it is not, because the explanation is often torturous.
-
-The effectively-required execution of these two methods is a wholly
-bogus artifact of an early bad design decision which encouraged
-application developers to use threadlocal data structures during the
-execution of configuration plugins. However, I don't hate my
-framework's users enough to break backwards compatibility for the sake
-of removing two boilerplate lines of code, so it stays, at least for
-the foreseeable future. If I eventually figure out a way to remove
-the requirement, these methods will turn into no-ops and they will be
-removed from the documenation.
-
Wrapping Up
+++++++++++
@@ -1724,9 +1689,7 @@ where comments take into account what we've discussed in the
if __name__ == '__main__':
from pyramid.configuration import Configurator
config = Configurator() # no global application object.
- config.begin() # bogus, but required.
config.add_view(hello_world) # explicit non-decorator registration
- config.end() # bogus, but required.
app = config.make_wsgi_app() # explicitly WSGI
serve(app, host='0.0.0.0') # explicitly WSGI
diff --git a/docs/index.rst b/docs/index.rst
index bfe956af2..72c21bbc8 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -113,38 +113,39 @@ Design Documentation
Sample Applications
===================
-.. warning::
+`cluegun <https://github.com/Pylons/cluegun>`_ is a simple pastebin
+application based on Rocky Burt's `ClueBin
+<http://pypi.python.org/pypi/ClueBin/0.2.3>`_. It demonstrates form
+processing, security, and the use of :term:`ZODB` within a :app:`Pyramid`
+application. Check this application out via::
- These applications are for an older version of :app:`Pyramid`,
- which was named :mod:`repoze.bfg`. We'll be updating them soon to
- use :app:`Pyramid`.
+ git clone git://github.com/Pylons/cluegun.git
-`repoze.cluegun <http://svn.repoze.org/repoze.cluegun/trunk/>`_ is a
-simple pastebin application based on Rocky Burt's `ClueBin
-<http://pypi.python.org/pypi/ClueBin/0.2.3>`_. It demonstrates form
-processing, security, and the use of :term:`ZODB` within a
-:mod:`repoze.bfg` application. It also has very simple
-:term:`repoze.who` integration. Check this application out of
-Subversion via::
+`virginia <https://github.com/Pylons/virginia>`_ is a very simple dynamic
+file rendering application. It is willing to render structured text
+documents, HTML documents, and images from a filesystem directory. An
+earlier version of this application runs the `repoze.org
+<http://repoze.org>`_ website. Check this application out via::
- svn co http://svn.repoze.org/repoze.cluegun/trunk repoze.cluegun
+ git clone git://github.com/Pylons/virginia.git
-`repoze.virginia <http://svn.repoze.org/repoze.virginia/trunk/>`_ is a
-very simple dynamic file rendering application. It is willing to
-render structured text documents, HTML documents, and images from a
-filesystem directory. This application runs the `repoze.org
-<http://repoze.org>`_ website. Check this application out of
-Subversion via::
+`shootout <https://github.com/Pylons/shootout>`_ is an example "idea
+competition" application by Carlos de la Guardia. It demonstrates a hybrid
+of :term:`URL dispatch` and :term:`traversal` and integration with
+`SQLAlchemy <http://www.sqlalchemy.org/>`_, :term:`repoze.who`, and
+`Deliverance <http://www.deliveranceproject.org/>`_. Check this application
+out of version control via::
- svn co http://svn.repoze.org/repoze.virginia/trunk repoze.virginia
+ git clone git://github.com/Pylons/shootout.git
-`repoze.shootout <http://svn.repoze.org/repoze.shootout/trunk/>`_ is
-an example "idea competition" application by Carlos de la Guardia. It
-demonstrates a hybrid of :term:`URL dispatch` and :term:`traversal`
-and integration with `SQLAlchemy <http://www.sqlalchemy.org/>`_ and
-:term:`repoze.who`. Check this application out of Subversion via::
+Older Sample Applications (repoze.bfg)
+======================================
+
+.. note::
- svn co http://svn.repoze.org/repoze.shootout/trunk repoze.shootout
+ These applications are for an older version of :app:`Pyramid`, which was
+ named :mod:`repoze.bfg`. They won't work unmodified under Pyramid, but
+ might provide useful clues.
`bfgsite <http://svn.repoze.org/bfgsite/trunk>`_ is the software which
runs the `bfg.repoze.org <http://bfg.repoze.org>`_ website. It
diff --git a/docs/narr/MyProject/development.ini b/docs/narr/MyProject/development.ini
index 9c51cfe6e..80d89e46a 100644
--- a/docs/narr/MyProject/development.ini
+++ b/docs/narr/MyProject/development.ini
@@ -15,3 +15,29 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/docs/narr/contextfinding.rst b/docs/narr/contextfinding.rst
index 457e1a526..691ad7b8e 100644
--- a/docs/narr/contextfinding.rst
+++ b/docs/narr/contextfinding.rst
@@ -74,7 +74,7 @@ URL dispatch can easily handle URLs such as
``http://example.com/members/Chris``, where it's assumed that each
item "below" ``members`` in the URL represents a single member in some
system. You just match everything "below" ``members`` to a particular
-:term:`view callable`, e.g. ``/members/:memberid``.
+:term:`view callable`, e.g. ``/members/{memberid}``.
However, URL dispatch is not very convenient if you'd like your URLs
to represent an arbitrary hierarchy. For example, if you need to
diff --git a/docs/narr/declarative.rst b/docs/narr/declarative.rst
index 48a3ea134..b9dbcab7d 100644
--- a/docs/narr/declarative.rst
+++ b/docs/narr/declarative.rst
@@ -655,7 +655,7 @@ declaration` causes a route to be added to the application.
<route
name="myroute"
- pattern="/prefix/:one/:two"
+ pattern="/prefix/{one}/{two}"
view=".views.myview"
/>
diff --git a/docs/narr/handlers.rst b/docs/narr/handlers.rst
index b8e7b5d9b..022f27115 100644
--- a/docs/narr/handlers.rst
+++ b/docs/narr/handlers.rst
@@ -59,11 +59,11 @@ be performed in order to register it with the system:
.. code-block:: python
- config.add_handler('hello', '/hello/:action', handler=Hello)
+ config.add_handler('hello', '/hello/{action}', handler=Hello)
This example will result in a route being added for the pattern
-``/hello/:action``, each method of the ``Hello`` class will then be examined
-to register the views. The value of ``:action`` in the route pattern will be
+``/hello/{action}``, each method of the ``Hello`` class will then be examined
+to register the views. The value of ``{action}`` in the route pattern will be
used to determine which view should be called, and each view in the class will
be setup with a view predicate that requires a specific ``action`` name.
@@ -98,7 +98,7 @@ For example:
.. code-block:: python
- config.add_handler('hello', '/hello/:action',
+ config.add_handler('hello', '/hello/{action}',
handler='mypackage.handlers:MyHandler')
In larger applications, it is advised to use a :term:`resource specification`
@@ -219,7 +219,7 @@ Example:
return {}
# in the config
- config.add_handler('hello', '/hello/:action', handler=Hello)
+ config.add_handler('hello', '/hello/{action}', handler=Hello)
With this configuration, the url ``/hello/home`` will find a view configuration
that results in calling the ``show_template`` method, then rendering the
diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst
index b89d10c9f..e704463c7 100644
--- a/docs/narr/hybrid.rst
+++ b/docs/narr/hybrid.rst
@@ -42,8 +42,8 @@ configuration:
# config is an instance of pyramid.configuration.Configurator
- config.add_route('foobar', ':foo/:bar', view='myproject.views.foobar')
- config.add_route('bazbuz', ':baz/:buz', view='myproject.views.bazbuz')
+ config.add_route('foobar', '{foo}/{bar}', view='myproject.views.foobar')
+ config.add_route('bazbuz', '{baz}/{buz}', view='myproject.views.bazbuz')
Each :term:`route` typically corresponds to a single view callable,
and when that route is matched during a request, the view callable
@@ -185,7 +185,7 @@ of a route's pattern:
.. code-block:: python
:linenos:
- config.add_route('home', ':foo/:bar/*traverse')
+ config.add_route('home', '{foo}/{bar}/*traverse')
A ``*traverse`` token at the end of the pattern in a route's
configuration implies a "remainder" *capture* value. When it is used,
@@ -243,7 +243,7 @@ route configuration statement:
.. code-block:: python
:linenos:
- config.add_route('home', ':foo/:bar/*traverse',
+ config.add_route('home', '{foo}/{bar}/*traverse',
factory='mypackage.routes.root_factory')
The ``factory`` above points at the function we've defined. It
@@ -267,14 +267,14 @@ to do.
When the route configuration named ``home`` above is matched during a
request, the matchdict generated will be based on its pattern:
-``:foo/:bar/*traverse``. The "capture value" implied by the
+``{foo}/{bar}/*traverse``. The "capture value" implied by the
``*traverse`` element in the pattern will be used to traverse the
graph in order to find a context, starting from the root object
returned from the root factory. In the above example, the
:term:`root` object found will be the instance named ``root`` in
``routes.py``.
-If the URL that matched a route with the pattern ``:foo/:bar/*traverse``,
+If the URL that matched a route with the pattern ``{foo}/{bar}/*traverse``,
is ``http://example.com/one/two/a/b/c``, the traversal path used
against the root object will be ``a/b/c``. As a result,
:app:`Pyramid` will attempt to traverse through the edges ``a``,
@@ -296,7 +296,7 @@ invoked after a route matches:
.. code-block:: python
:linenos:
- config.add_route('home', ':foo/:bar/*traverse',
+ config.add_route('home', '{foo}/{bar}/*traverse',
factory='mypackage.routes.root_factory')
config.add_view('mypackage.views.myview', route_name='home')
@@ -326,7 +326,7 @@ when a hybrid route is matched:
.. code-block:: python
:linenos:
- config.add_route('home', ':foo/:bar/*traverse',
+ config.add_route('home', '{foo}/{bar}/*traverse',
factory='mypackage.routes.root_factory')
config.add_view('mypackage.views.myview', name='home')
config.add_view('mypackage.views.another_view', name='another',
@@ -371,14 +371,14 @@ Here's a use of the ``traverse`` pattern in a call to
.. code-block:: python
:linenos:
- config.add_route('abc', '/articles/:article/edit',
- traverse='/articles/:article')
+ config.add_route('abc', '/articles/{article}/edit',
+ traverse='/articles/{article}')
The syntax of the ``traverse`` argument is the same as it is for
``pattern``.
-If, as above, the ``pattern`` provided is ``articles/:article/edit``,
-and the ``traverse`` argument provided is ``/:article``, when a
+If, as above, the ``pattern`` provided is ``articles/{article}/edit``,
+and the ``traverse`` argument provided is ``/{article}``, when a
request comes in that causes the route to match in such a way that the
``article`` match value is ``1`` (when the request URI is
``/articles/1/edit``), the traversal path will be generated as ``/1``.
@@ -467,7 +467,7 @@ startup time.
.. code-block:: python
:linenos:
- config.add_route('home', ':foo/:bar/*traverse',
+ config.add_route('home', '{foo}/{bar}/*traverse',
view='myproject.views.home')
config.add_view('myproject.views.another', route_name='home')
@@ -479,7 +479,7 @@ supply a view attribute. For example, this ``add_route`` call:
.. code-block:: python
:linenos:
- config.add_route('home', ':foo/:bar/*traverse',
+ config.add_route('home', '{foo}/{bar}/*traverse',
view='myproject.views.home')
Can also be spelled like so:
@@ -487,7 +487,7 @@ Can also be spelled like so:
.. code-block:: python
:linenos:
- config.add_route('home', ':foo/:bar/*traverse')
+ config.add_route('home', '{foo}/{bar}/*traverse')
config.add_view('myproject.views.home', route_name='home')
The two spellings are logically equivalent. In fact, the former is
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index 9bcc17e97..01fdd351e 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -32,27 +32,21 @@ entry point happens to be the ``app`` function within the file named
#. *Lines 1-4*. Imports to support later code.
-#. *Lines 9-11*. Get the database configuration string from the
- ``development.ini`` file's ``[app:sqlalchemy]`` section. This will be a
- URI (something like ``sqlite://``).
+#. *Line 9*. Create a SQLAlchemy database engine from the ``sqlalchemy.``
+ prefixed settings in the ``development.ini`` file's ``[app:tutorial]``
+ section. This will be a URI (something like ``sqlite://``).
-#. *Line 12*. Get the database echo setting from ``development.ini``
- file's ``[app:sqlalchemy]`` section. This will either be ``true``
- or ``false``. If ``true``, the application will print SQL to the
- console as it is generated and run by SQLAlchemy. By default, it
- is false.
+#. *Line 10*. We initialize our SQL database using SQLAlchemy, passing
+ it the engine
-#. Line *13*. We initialize our SQL database using SQLAlchemy, passing
- it the db string and a variant of the db_echo value.
-
-#. *Line 14*. We construct a :term:`Configurator`. ``settings`` is
+#. *Line 11*. We construct a :term:`Configurator`. ``settings`` is
passed as a keyword argument with the dictionary values passed by
PasteDeploy as the ``settings`` argument. This will be a
dictionary of settings parsed by PasteDeploy, which contains
deployment-related values such as ``reload_templates``,
``db_string``, etc.
-#. *Line 15*. We call
+#. *Line 12*. We call
:meth:`pyramid.configuration.Configurator.add_static_view` with the
arguments ``static`` (the name), and ``tutorial:static`` (the path). This
registers a static resource view which will match any URL that starts with
@@ -64,7 +58,7 @@ entry point happens to be the ``app`` function within the file named
``/static/foo``) will be used to compose a path to a static file resource,
such as a CSS file.
-#. *Lines 16-17*. Register a :term:`route configuration` via the
+#. *Lines 13-14*. Register a :term:`route configuration` via the
:meth:`pyramid.configuration.Configurator.add_route` method that will be
used when the URL is ``/``. Since this route has an ``pattern`` equalling
``/`` it is the "default" route. The argument named ``view`` with the
@@ -78,7 +72,7 @@ entry point happens to be the ``app`` function within the file named
``tutorial.views.my_view`` view returns a dictionary, a :term:`renderer`
will use this template to create a response.
-#. *Line 18*. We use the
+#. *Line 15*. We use the
:meth:`pyramid.configuration.Configurator.make_wsgi_app` method to return
a :term:`WSGI` application.
@@ -97,29 +91,28 @@ Here is the source for ``models.py``:
:linenos:
:language: py
-#. *Lines 1-14*. Imports to support later code.
+#. *Lines 1-13*. Imports to support later code.
-#. *Line 16*. We set up a SQLAlchemy "DBSession" object here. We
+#. *Line 15*. We set up a SQLAlchemy "DBSession" object here. We
specify that we'd like to use the "ZopeTransactionExtension". This
extension is an extension which allows us to use a *transaction
manager* instead of controlling commits and aborts to database
operations by hand.
-#. *Line 17*. We create a declarative ``Base`` object to use as a
+#. *Line 16*. We create a declarative ``Base`` object to use as a
base class for our model.
-#. *Lines 19-27*. A model class named ``MyModel``. It has an
+#. *Lines 18-26*. A model class named ``MyModel``. It has an
``__init__`` that takes a two arguments (``name``, and ``value``).
It stores these values as ``self.name`` and ``self.value`` 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.
-#. *Lines 29-34*. A function named ``populate`` which adds a single
+#. *Lines 28-33*. A function named ``populate`` which adds a single
model instance into our SQL storage and commits a transaction.
-#. *Lines 36-44*. A function named ``initialize_sql`` which sets up
- an actual SQL database and binds it to our SQLAlchemy DBSession
- object. It also calls the ``populate`` function, to do initial
- database population.
+#. *Lines 35-42*. 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.
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index b87cd6a64..0f446bb4e 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -24,7 +24,7 @@ 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.configuration.Configurator.add_route` in
-``__init__.py`` had the pattern ``:one/:two``, and the URL at
+``__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``.
@@ -277,16 +277,16 @@ the order they're found in the ``__init__.py`` file.
to the view named ``view_wiki`` in our ``views.py`` file with the name
``view_wiki``. This is the :term:`default view` for the wiki.
-#. Add a declaration which maps the pattern ``/:pagename`` to the view named
+#. Add a declaration which maps the pattern ``/{pagename}`` to the view named
``view_page`` in our ``views.py`` file with the view name ``view_page``.
This is the regular view for a page.
#. Add a declaration which maps the pattern
- ``/add_page/:pagename`` to the view named ``add_page`` in our
+ ``/add_page/{pagename}`` to the view named ``add_page`` in our
``views.py`` file with the name ``add_page``. This is the add view
for a new page.
-#. Add a declaration which maps the pattern ``/:pagename/edit_page`` to the
+#. Add a declaration which maps the pattern ``/{pagename}/edit_page`` to the
view named ``edit_page`` in our ``views.py`` file with the name
``edit_page``. This is the edit view for a page.
diff --git a/docs/tutorials/wiki2/src/authorization/development.ini b/docs/tutorials/wiki2/src/authorization/development.ini
index e1d0ab598..23b01a338 100644
--- a/docs/tutorials/wiki2/src/authorization/development.ini
+++ b/docs/tutorials/wiki2/src/authorization/development.ini
@@ -5,8 +5,7 @@ debug_authorization = false
debug_notfound = false
debug_templates = true
default_locale_name = en
-db_string = sqlite:///%(here)s/tutorial.db
-db_echo = false
+sqlalchemy.url = sqlite:///%(here)s/tutorial.db
[pipeline:main]
pipeline =
@@ -18,3 +17,37 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root, sqlalchemy
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_sqlalchemy]
+level = INFO
+handlers =
+qualname = sqlalchemy.engine
+# "level = INFO" logs SQL queries.
+# "level = DEBUG" logs SQL queries and results.
+# "level = WARN" logs neither. (Recommended for production systems.)
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
index 8269617f2..dbac349b9 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
@@ -2,7 +2,7 @@ from pyramid.configuration import Configurator
from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
-from pyramid.settings import asbool
+from sqlalchemy import engine_from_config
from tutorial.models import initialize_sql
from tutorial.security import groupfinder
@@ -10,11 +10,8 @@ from tutorial.security import groupfinder
def main(global_config, **settings):
""" This function returns a WSGI application.
"""
- db_string = settings.get('db_string')
- if db_string is None:
- raise ValueError("No 'db_string' value in application configuration.")
- db_echo = settings.get('db_echo', 'false')
- initialize_sql(db_string, asbool(db_echo))
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ initialize_sql(engine)
authn_policy = AuthTktAuthenticationPolicy(
'sosecret', callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
@@ -29,14 +26,14 @@ def main(global_config, **settings):
view_renderer='tutorial:templates/login.pt')
config.add_route('logout', '/logout',
view='tutorial.login.logout')
- config.add_route('view_page', '/:pagename',
+ config.add_route('view_page', '/{pagename}',
view='tutorial.views.view_page',
view_renderer='tutorial:templates/view.pt')
- config.add_route('add_page', '/add_page/:pagename',
+ config.add_route('add_page', '/add_page/{pagename}',
view='tutorial.views.add_page',
view_renderer='tutorial:templates/edit.pt',
view_permission='edit')
- config.add_route('edit_page', '/:pagename/edit_page',
+ config.add_route('edit_page', '/{pagename}/edit_page',
view='tutorial.views.edit_page',
view_renderer='tutorial:templates/edit.pt',
view_permission='edit')
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models.py b/docs/tutorials/wiki2/src/authorization/tutorial/models.py
index 7580220b6..487299c4c 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/models.py
@@ -3,7 +3,6 @@ import transaction
from pyramid.security import Allow
from pyramid.security import Everyone
-from sqlalchemy import create_engine
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import Text
@@ -30,8 +29,7 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(db_string, echo=False):
- engine = create_engine(db_string, echo=echo)
+def initialize_sql(engine):
DBSession.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all(engine)
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/tests.py b/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
index 65330ce17..c78899797 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
@@ -14,9 +14,9 @@ def _initTestingDB():
return DBSession
def _registerRoutes(config):
- config.add_route('view_page', ':pagename')
- config.add_route('edit_page', ':pagename/edit_page')
- config.add_route('add_page', 'add_page/:pagename')
+ config.add_route('view_page', '{pagename}')
+ config.add_route('edit_page', '{pagename}/edit_page')
+ config.add_route('add_page', 'add_page/{pagename}')
class ViewWikiTests(unittest.TestCase):
def setUp(self):
@@ -28,7 +28,7 @@ class ViewWikiTests(unittest.TestCase):
def test_it(self):
from tutorial.views import view_wiki
- self.config.add_route('view_page', ':pagename')
+ self.config.add_route('view_page', '{pagename}')
request = testing.DummyRequest()
response = view_wiki(request)
self.assertEqual(response.location, 'http://example.com/FrontPage')
diff --git a/docs/tutorials/wiki2/src/basiclayout/development.ini b/docs/tutorials/wiki2/src/basiclayout/development.ini
index e1d0ab598..23b01a338 100644
--- a/docs/tutorials/wiki2/src/basiclayout/development.ini
+++ b/docs/tutorials/wiki2/src/basiclayout/development.ini
@@ -5,8 +5,7 @@ debug_authorization = false
debug_notfound = false
debug_templates = true
default_locale_name = en
-db_string = sqlite:///%(here)s/tutorial.db
-db_echo = false
+sqlalchemy.url = sqlite:///%(here)s/tutorial.db
[pipeline:main]
pipeline =
@@ -18,3 +17,37 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root, sqlalchemy
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_sqlalchemy]
+level = INFO
+handlers =
+qualname = sqlalchemy.engine
+# "level = INFO" logs SQL queries.
+# "level = DEBUG" logs SQL queries and results.
+# "level = WARN" logs neither. (Recommended for production systems.)
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
index 0ae61fccd..5236a538d 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
@@ -1,16 +1,13 @@
from pyramid.configuration import Configurator
-from pyramid.settings import asbool
+from sqlalchemy import engine_from_config
from tutorial.models import initialize_sql
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
- db_string = settings.get('db_string')
- if db_string is None:
- raise ValueError("No 'db_string' value in application configuration.")
- db_echo = settings.get('db_echo', 'false')
- initialize_sql(db_string, asbool(db_echo))
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'tutorial:static')
config.add_route('home', '/', view='tutorial.views.my_view',
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
index a1726ebf4..9da906752 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
@@ -1,6 +1,5 @@
import transaction
-from sqlalchemy import create_engine
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import Unicode
@@ -33,8 +32,7 @@ def populate():
session.flush()
transaction.commit()
-def initialize_sql(db_string, db_echo=False):
- engine = create_engine(db_string, echo=db_echo)
+def initialize_sql(engine):
DBSession.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all(engine)
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
index 72f0c89d8..2db1bc5b6 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
@@ -3,8 +3,9 @@ from pyramid.configuration import Configurator
from pyramid import testing
def _initTestingDB():
+ from sqlalchemy import create_engine
from tutorial.models import initialize_sql
- session = initialize_sql('sqlite://')
+ session = initialize_sql(create_engine('sqlite://'))
return session
class TestMyView(unittest.TestCase):
diff --git a/docs/tutorials/wiki2/src/models/development.ini b/docs/tutorials/wiki2/src/models/development.ini
index e1d0ab598..23b01a338 100644
--- a/docs/tutorials/wiki2/src/models/development.ini
+++ b/docs/tutorials/wiki2/src/models/development.ini
@@ -5,8 +5,7 @@ debug_authorization = false
debug_notfound = false
debug_templates = true
default_locale_name = en
-db_string = sqlite:///%(here)s/tutorial.db
-db_echo = false
+sqlalchemy.url = sqlite:///%(here)s/tutorial.db
[pipeline:main]
pipeline =
@@ -18,3 +17,37 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root, sqlalchemy
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_sqlalchemy]
+level = INFO
+handlers =
+qualname = sqlalchemy.engine
+# "level = INFO" logs SQL queries.
+# "level = DEBUG" logs SQL queries and results.
+# "level = WARN" logs neither. (Recommended for production systems.)
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/docs/tutorials/wiki2/src/models/tutorial/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/__init__.py
index 6e291ffdf..e1baa2d64 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/__init__.py
@@ -1,16 +1,13 @@
from pyramid.configuration import Configurator
-from pyramid.settings import asbool
+from sqlalchemy import engine_from_config
from tutorial.models import initialize_sql
def main(global_config, **settings):
""" This function returns a WSGI application.
"""
- db_string = settings.get('db_string')
- if db_string is None:
- raise ValueError("No 'db_string' value in application configuration.")
- db_echo = settings.get('db_echo', 'false')
- initialize_sql(db_string, asbool(db_echo))
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'tutorial:static')
config.add_route('home', '/', view='tutorial.views.my_view',
diff --git a/docs/tutorials/wiki2/src/models/tutorial/models.py b/docs/tutorials/wiki2/src/models/tutorial/models.py
index ec9d2b25c..23b8afab8 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/models.py
@@ -1,6 +1,5 @@
import transaction
-from sqlalchemy import create_engine
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import Text
@@ -27,8 +26,7 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(db_string, echo=False):
- engine = create_engine(db_string, echo=echo)
+def initialize_sql(engine):
DBSession.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all(engine)
diff --git a/docs/tutorials/wiki2/src/views/development.ini b/docs/tutorials/wiki2/src/views/development.ini
index e1d0ab598..23b01a338 100644
--- a/docs/tutorials/wiki2/src/views/development.ini
+++ b/docs/tutorials/wiki2/src/views/development.ini
@@ -5,8 +5,7 @@ debug_authorization = false
debug_notfound = false
debug_templates = true
default_locale_name = en
-db_string = sqlite:///%(here)s/tutorial.db
-db_echo = false
+sqlalchemy.url = sqlite:///%(here)s/tutorial.db
[pipeline:main]
pipeline =
@@ -18,3 +17,37 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root, sqlalchemy
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_sqlalchemy]
+level = INFO
+handlers =
+qualname = sqlalchemy.engine
+# "level = INFO" logs SQL queries.
+# "level = DEBUG" logs SQL queries and results.
+# "level = WARN" logs neither. (Recommended for production systems.)
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/docs/tutorials/wiki2/src/views/tutorial/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
index 947ce9b93..91c299e24 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
@@ -1,26 +1,23 @@
from pyramid.configuration import Configurator
-from pyramid.settings import asbool
+from sqlalchemy import engine_from_config
from tutorial.models import initialize_sql
def main(global_config, **settings):
""" This function returns a WSGI application.
"""
- db_string = settings.get('db_string')
- if db_string is None:
- raise ValueError("No 'db_string' value in application configuration.")
- db_echo = settings.get('db_echo', 'false')
- initialize_sql(db_string, asbool(db_echo))
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'tutorial:static')
config.add_route('home', '/', view='tutorial.views.view_wiki')
- config.add_route('view_page', '/:pagename',
+ config.add_route('view_page', '/{pagename}',
view='tutorial.views.view_page',
view_renderer='tutorial:templates/view.pt')
- config.add_route('add_page', '/add_page/:pagename',
+ config.add_route('add_page', '/add_page/{pagename}',
view='tutorial.views.add_page',
view_renderer='tutorial:templates/edit.pt')
- config.add_route('edit_page', '/:pagename/edit_page',
+ config.add_route('edit_page', '/{pagename}/edit_page',
view='tutorial.views.edit_page',
view_renderer='tutorial:templates/edit.pt')
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 ec9d2b25c..23b8afab8 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/models.py
@@ -1,6 +1,5 @@
import transaction
-from sqlalchemy import create_engine
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import Text
@@ -27,8 +26,7 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(db_string, echo=False):
- engine = create_engine(db_string, echo=echo)
+def initialize_sql(engine):
DBSession.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all(engine)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/tests.py b/docs/tutorials/wiki2/src/views/tutorial/tests.py
index 40336fca4..435e4b588 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/tests.py
@@ -14,9 +14,9 @@ def _initTestingDB():
return DBSession
def _registerRoutes(config):
- config.add_route('view_page', ':pagename')
- config.add_route('edit_page', ':pagename/edit_page')
- config.add_route('add_page', 'add_page/:pagename')
+ config.add_route('view_page', '{pagename}')
+ config.add_route('edit_page', '{pagename}/edit_page')
+ config.add_route('add_page', 'add_page/{pagename}')
class ViewWikiTests(unittest.TestCase):
def setUp(self):
@@ -28,7 +28,7 @@ class ViewWikiTests(unittest.TestCase):
def test_it(self):
from tutorial.views import view_wiki
- self.config.add_route('view_page', ':pagename')
+ self.config.add_route('view_page', '{pagename}')
request = testing.DummyRequest()
response = view_wiki(request)
self.assertEqual(response.location, 'http://example.com/FrontPage')
diff --git a/docs/zcml/route.rst b/docs/zcml/route.rst
index ed849e3c1..c3bec72df 100644
--- a/docs/zcml/route.rst
+++ b/docs/zcml/route.rst
@@ -10,7 +10,7 @@ Attributes
~~~~~~~~~~
``pattern``
- The pattern of the route e.g. ``ideas/:idea``. This attribute is
+ The pattern of the route e.g. ``ideas/{idea}``. This attribute is
required. See :ref:`route_pattern_syntax` for information
about the syntax of route patterns.
@@ -51,9 +51,9 @@ Attributes
The syntax of the ``traverse`` argument is the same as it is for
``pattern``. For example, if the ``pattern`` provided to the
- ``route`` directive is ``articles/:article/edit``, and the
+ ``route`` directive is ``articles/{article}/edit``, and the
``traverse`` argument provided to the ``route`` directive is
- ``/:article``, when a request comes in that causes the route to
+ ``/{article}``, when a request comes in that causes the route to
match in such a way that the ``article`` match value is '1' (when
the request URI is ``/articles/1/edit``), the traversal path will be
generated as ``/1``. This means that the root object's
diff --git a/pyramid/configuration.py b/pyramid/configuration.py
index 63d09efe3..6ebb56ec3 100644
--- a/pyramid/configuration.py
+++ b/pyramid/configuration.py
@@ -296,12 +296,17 @@ class Configurator(object):
attr=None, renderer=None, wrapper_viewname=None,
viewname=None, accept=None, order=MAX_ORDER,
phash=DEFAULT_PHASH):
+ if renderer is None: # use default renderer if one exists
+ default_renderer_factory = self.registry.queryUtility(
+ IRendererFactory)
+ if default_renderer_factory is not None:
+ renderer = {'name':None, 'package':self.package}
view = self.maybe_dotted(view)
authn_policy = self.registry.queryUtility(IAuthenticationPolicy)
authz_policy = self.registry.queryUtility(IAuthorizationPolicy)
settings = self.registry.settings
logger = self.registry.queryUtility(IDebugLogger)
- mapped_view = _map_view(view, attr, renderer, self.registry)
+ mapped_view = _map_view(view, self.registry, attr, renderer)
owrapped_view = _owrap_view(mapped_view, viewname, wrapper_viewname)
secured_view = _secure_view(owrapped_view, permission,
authn_policy, authz_policy)
@@ -699,6 +704,8 @@ class Configurator(object):
Any extra keyword arguments are passed along to ``add_route``.
+ See :ref:`handlers_chapter` for more explanatory documentation.
+
This method returns the result of add_route."""
handler = self.maybe_dotted(handler)
@@ -1260,9 +1267,9 @@ class Configurator(object):
The syntax of the ``traverse`` argument is the same as it is
for ``pattern``. For example, if the ``pattern`` provided to
- ``add_route`` is ``articles/:article/edit``, and the
+ ``add_route`` is ``articles/{article}/edit``, and the
``traverse`` argument provided to ``add_route`` is
- ``/:article``, when a request comes in that causes the route
+ ``/{article}``, when a request comes in that causes the route
to match in such a way that the ``article`` match value is
'1' (when the request URI is ``/articles/1/edit``), the
traversal path will be generated as ``/1``. This means that
@@ -1306,7 +1313,7 @@ class Configurator(object):
pattern
- The pattern of the route e.g. ``ideas/:idea``. This
+ The pattern of the route e.g. ``ideas/{idea}``. This
argument is required. See :ref:`route_path_pattern_syntax`
for information about the syntax of route patterns. If the
pattern doesn't match the current URL, route matching
@@ -1591,7 +1598,9 @@ class Configurator(object):
Add a :app:`Pyramid` :term:`renderer` factory to the
current configuration state.
- The ``name`` argument is the renderer name.
+ The ``name`` argument is the renderer name. Use ``None`` to
+ represent the default renderer (a renderer which will be used for all
+ views unless they name another renderer specifically).
The ``factory`` argument is Python reference to an
implementation of a :term:`renderer` factory or a
@@ -1605,6 +1614,11 @@ class Configurator(object):
to use this method.
"""
factory = self.maybe_dotted(factory)
+ # if name is None or the empty string, we're trying to register
+ # a default renderer, but registerUtility is too dumb to accept None
+ # as a name
+ if not name:
+ name = ''
self.registry.registerUtility(
factory, IRendererFactory, name=name, info=_info)
@@ -2426,7 +2440,7 @@ def is_response(ob):
return True
return False
-def _map_view(view, attr=None, renderer=None, registry=None):
+def _map_view(view, registry, attr=None, renderer=None):
wrapped_view = view
helper = None
@@ -2844,14 +2858,10 @@ class DottedNameResolver(object):
def maybe_resolve(self, dotted):
if isinstance(dotted, basestring):
- try:
- if ':' in dotted:
- return self._pkg_resources_style(dotted)
- else:
- return self._zope_dottedname_style(dotted)
- except ImportError:
- raise ConfigurationError(
- 'The dotted name %r cannot be imported' % (dotted,))
+ if ':' in dotted:
+ return self._pkg_resources_style(dotted)
+ else:
+ return self._zope_dottedname_style(dotted)
return dotted
diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py
index 9b895e020..f021ba60b 100644
--- a/pyramid/interfaces.py
+++ b/pyramid/interfaces.py
@@ -100,6 +100,26 @@ class IBeforeRender(Interface):
""" Return the value for key ``k`` from the renderer globals
dictionary, or the default if no such value exists."""
+class IRenderer(Interface):
+ def __call__(value, system):
+ """ Call a the renderer implementation with the result of the
+ view (``value``) passed in and return a result (a string or
+ unicode object useful as a response body). Values computed by
+ the system are passed by the system in the ``system``
+ parameter, which is a dictionary. Keys in the dictionary
+ include: ``view`` (the view callable that returned the value),
+ ``renderer_name`` (the template name or simple name of the
+ renderer), ``context`` (the context object passed to the
+ view), and ``request`` (the request object passed to the
+ view)."""
+
+class ITemplateRenderer(IRenderer):
+ def implementation():
+ """ Return the object that the underlying templating system
+ uses to render the template; it is typically a callable that
+ accepts arbitrary keyword arguments and returns a string or
+ unicode object """
+
# internal interfaces
class IRequest(Interface):
@@ -233,19 +253,6 @@ class ITraverser(Interface):
ITraverserFactory = ITraverser # b / c for 1.0 code
-class IRenderer(Interface):
- def __call__(value, system):
- """ Call a the renderer implementation with the result of the
- view (``value``) passed in and return a result (a string or
- unicode object useful as a response body). Values computed by
- the system are passed by the system in the ``system``
- parameter, which is a dictionary. Keys in the dictionary
- include: ``view`` (the view callable that returned the value),
- ``renderer_name`` (the template name or simple name of the
- renderer), ``context`` (the context object passed to the
- view), and ``request`` (the request object passed to the
- view)."""
-
class IRendererFactory(Interface):
def __call__(name):
""" Return an object that implements ``IRenderer`` """
@@ -259,13 +266,6 @@ class IRendererGlobalsFactory(Interface):
``renderer_name``, which will be the name of the renderer in
use."""
-class ITemplateRenderer(IRenderer):
- def implementation():
- """ Return the object that the underlying templating system
- uses to render the template; it is typically a callable that
- accepts arbitrary keyword arguments and returns a string or
- unicode object """
-
class IViewPermission(Interface):
def __call__(context, request):
""" Return True if the permission allows, return False if it denies. """
diff --git a/pyramid/paster_templates/alchemy/+package+/__init__.py_tmpl b/pyramid/paster_templates/alchemy/+package+/__init__.py_tmpl
index c20e7dd15..f6591ab32 100755
--- a/pyramid/paster_templates/alchemy/+package+/__init__.py_tmpl
+++ b/pyramid/paster_templates/alchemy/+package+/__init__.py_tmpl
@@ -1,16 +1,13 @@
from pyramid.configuration import Configurator
-from pyramid.settings import asbool
+from sqlalchemy import engine_from_config
from {{package}}.models import appmaker
def main(global_config, **settings):
""" This function returns a WSGI application.
"""
- db_string = settings.get('db_string')
- if db_string is None:
- raise ValueError("No 'db_string' value in application configuration.")
- db_echo = settings.get('db_echo', 'false')
- get_root = appmaker(db_string, asbool(db_echo))
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ get_root = appmaker(engine)
config = Configurator(settings=settings, root_factory=get_root)
config.add_static_view('static', '{{package}}:static')
config.add_view('{{package}}.views.view_root',
diff --git a/pyramid/paster_templates/alchemy/+package+/models.py b/pyramid/paster_templates/alchemy/+package+/models.py
index 336613cf9..1134cce07 100755
--- a/pyramid/paster_templates/alchemy/+package+/models.py
+++ b/pyramid/paster_templates/alchemy/+package+/models.py
@@ -73,8 +73,7 @@ def populate():
session.flush()
transaction.commit()
-def initialize_sql(db_string, db_echo=False):
- engine = create_engine(db_string, echo=db_echo)
+def initialize_sql(engine):
DBSession.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all(engine)
@@ -83,6 +82,6 @@ def initialize_sql(db_string, db_echo=False):
except IntegrityError:
pass
-def appmaker(db_string, db_echo=False):
- initialize_sql(db_string, db_echo)
+def appmaker(engine):
+ initialize_sql(engine)
return default_get_root
diff --git a/pyramid/paster_templates/alchemy/development.ini_tmpl b/pyramid/paster_templates/alchemy/development.ini_tmpl
index de4605e33..4f4b98ac0 100644
--- a/pyramid/paster_templates/alchemy/development.ini_tmpl
+++ b/pyramid/paster_templates/alchemy/development.ini_tmpl
@@ -5,8 +5,7 @@ debug_authorization = false
debug_notfound = false
debug_templates = true
default_locale_name = en
-db_string = sqlite:///%(here)s/{{package}}.db
-db_echo = false
+sqlalchemy.url = sqlite:///%(here)s/{{project}}.db
[pipeline:main]
pipeline =
@@ -18,3 +17,37 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root, sqlalchemy
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_sqlalchemy]
+level = INFO
+handlers =
+qualname = sqlalchemy.engine
+# "level = INFO" logs SQL queries.
+# "level = DEBUG" logs SQL queries and results.
+# "level = WARN" logs neither. (Recommended for production systems.)
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/pyramid/paster_templates/pylons_basic/+package+/__init__.py_tmpl b/pyramid/paster_templates/pylons_basic/+package+/__init__.py_tmpl
index dd6edd3cf..9f3793538 100644
--- a/pyramid/paster_templates/pylons_basic/+package+/__init__.py_tmpl
+++ b/pyramid/paster_templates/pylons_basic/+package+/__init__.py_tmpl
@@ -8,7 +8,7 @@ def main(global_config, **settings):
session_factory = session_factory_from_settings(settings)
config.set_session_factory(session_factory)
config.add_static_view('static', '{{package}}:static/')
- config.add_handler('action', '/:action',
+ config.add_handler('action', '/{action}',
'{{package}}.handlers.hello:HelloHandler')
config.add_handler('home', '/', '{{package}}.handlers.hello:HelloHandler',
action='index')
diff --git a/pyramid/paster_templates/pylons_basic/development.ini_tmpl b/pyramid/paster_templates/pylons_basic/development.ini_tmpl
index 569256739..b14ecc7e2 100644
--- a/pyramid/paster_templates/pylons_basic/development.ini_tmpl
+++ b/pyramid/paster_templates/pylons_basic/development.ini_tmpl
@@ -13,10 +13,37 @@ session.key = {{project}}
session.secret = {{random_string}}
[pipeline:main]
-pipeline = egg:WebError#evalerror
- {{project}}
+pipeline =
+ egg:WebError#evalerror
+ {{project}}
[server:main]
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/pyramid/paster_templates/pylons_minimal/+package+/__init__.py_tmpl b/pyramid/paster_templates/pylons_minimal/+package+/__init__.py_tmpl
index 57371eec9..5e284ec88 100644
--- a/pyramid/paster_templates/pylons_minimal/+package+/__init__.py_tmpl
+++ b/pyramid/paster_templates/pylons_minimal/+package+/__init__.py_tmpl
@@ -8,7 +8,7 @@ def main(global_config, **settings):
session_factory = session_factory_from_settings(settings)
config.set_session_factory(session_factory)
config.add_static_view('static', '{{package}}:static/')
- config.add_handler('action', '/:action', '{{package}}.handlers:MyHandler')
+ config.add_handler('action', '/{action}', '{{package}}.handlers:MyHandler')
config.add_handler('home', '/', '{{package}}.handlers:MyHandler',
action='index')
config.add_subscriber('{{package}}.subscribers.add_renderer_globals',
diff --git a/pyramid/paster_templates/pylons_minimal/development.ini_tmpl b/pyramid/paster_templates/pylons_minimal/development.ini_tmpl
index 569256739..d31cd1ca2 100644
--- a/pyramid/paster_templates/pylons_minimal/development.ini_tmpl
+++ b/pyramid/paster_templates/pylons_minimal/development.ini_tmpl
@@ -20,3 +20,29 @@ pipeline = egg:WebError#evalerror
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/pyramid/paster_templates/pylons_sqla/+package+/__init__.py_tmpl b/pyramid/paster_templates/pylons_sqla/+package+/__init__.py_tmpl
index 0a4313976..b67a2c35b 100644
--- a/pyramid/paster_templates/pylons_sqla/+package+/__init__.py_tmpl
+++ b/pyramid/paster_templates/pylons_sqla/+package+/__init__.py_tmpl
@@ -1,22 +1,21 @@
from pyramid.configuration import Configurator
-from pyramid.settings import asbool
from pyramid_beaker import session_factory_from_settings
+from sqlalchemy import engine_from_config
+
+from {{package}}.models import initialize_sql
+
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
- from {{package}}.models import initialize_sql
- db_string = settings.get('db_string')
- if db_string is None:
- raise ValueError("No 'db_string' value in application "
- "configuration.")
- initialize_sql(db_string, asbool(settings.get('db_echo')))
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ initialize_sql(engine)
config = Configurator(settings=settings)
session_factory = session_factory_from_settings(settings)
config.set_session_factory(session_factory)
config.add_static_view('static', '{{package}}:static/')
- config.add_handler('main', '/:action', '{{package}}.handlers:MyHandler')
+ config.add_handler('main', '/{action}', '{{package}}.handlers:MyHandler')
config.add_handler('home', '/', '{{package}}.handlers:MyHandler',
action='index')
config.add_subscriber('{{package}}.subscribers.add_renderer_globals',
diff --git a/pyramid/paster_templates/pylons_sqla/+package+/models.py b/pyramid/paster_templates/pylons_sqla/+package+/models.py
index 092166902..6418f0c8b 100644
--- a/pyramid/paster_templates/pylons_sqla/+package+/models.py
+++ b/pyramid/paster_templates/pylons_sqla/+package+/models.py
@@ -36,8 +36,7 @@ def populate():
DBSession.flush()
transaction.commit()
-def initialize_sql(db_string, db_echo=False):
- engine = create_engine(db_string, echo=db_echo)
+def initialize_sql(engine):
DBSession.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all(engine)
diff --git a/pyramid/paster_templates/pylons_sqla/+package+/tests.py_tmpl b/pyramid/paster_templates/pylons_sqla/+package+/tests.py_tmpl
index 099df47bd..b55760b37 100644
--- a/pyramid/paster_templates/pylons_sqla/+package+/tests.py_tmpl
+++ b/pyramid/paster_templates/pylons_sqla/+package+/tests.py_tmpl
@@ -3,8 +3,9 @@ import unittest
class MyHandlerTests(unittest.TestCase):
def setUp(self):
from pyramid.configuration import Configurator
+ from sqlalchemy import create_engine
from {{package}}.models import initialize_sql
- self.session = initialize_sql('sqlite://')
+ self.session = initialize_sql(create_engine('sqlite://'))
self.config = Configurator()
self.config.begin()
diff --git a/pyramid/paster_templates/pylons_sqla/development.ini_tmpl b/pyramid/paster_templates/pylons_sqla/development.ini_tmpl
index 936d41b29..1cc1a42e4 100644
--- a/pyramid/paster_templates/pylons_sqla/development.ini_tmpl
+++ b/pyramid/paster_templates/pylons_sqla/development.ini_tmpl
@@ -1,13 +1,12 @@
[app:{{project}}]
use = egg:{{project}}
reload_templates = true
-mako.directories = {{package}}:templates
debug_authorization = false
debug_notfound = false
debug_templates = true
default_locale_name = en
-db_string = sqlite:///%(here)s/tutorial.db
-db_echo = true
+mako.directories = {{package}}:templates
+sqlalchemy.url = sqlite:///%(here)s/{{project}}.db
session.type = file
session.data_dir = %(here)s/data/sessions/data
session.lock_dir = %(here)s/data/sessions/lock
@@ -24,3 +23,37 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root, sqlalchemy
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_sqlalchemy]
+level = INFO
+handlers =
+qualname = sqlalchemy.engine
+# "level = INFO" logs SQL queries.
+# "level = DEBUG" logs SQL queries and results.
+# "level = WARN" logs neither. (Recommended for production systems.)
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/pyramid/paster_templates/routesalchemy/+package+/__init__.py_tmpl b/pyramid/paster_templates/routesalchemy/+package+/__init__.py_tmpl
index e68e0ed66..5c326caa8 100644
--- a/pyramid/paster_templates/routesalchemy/+package+/__init__.py_tmpl
+++ b/pyramid/paster_templates/routesalchemy/+package+/__init__.py_tmpl
@@ -1,16 +1,13 @@
from pyramid.configuration import Configurator
-from pyramid.settings import asbool
+from sqlalchemy import engine_from_config
from {{package}}.models import initialize_sql
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
- db_string = settings.get('db_string')
- if db_string is None:
- raise ValueError("No 'db_string' value in application configuration.")
- db_echo = settings.get('db_echo', 'false')
- initialize_sql(db_string, asbool(db_echo))
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', '{{package}}:static')
config.add_route('home', '/', view='{{package}}.views.my_view',
diff --git a/pyramid/paster_templates/routesalchemy/+package+/models.py b/pyramid/paster_templates/routesalchemy/+package+/models.py
index a1726ebf4..9da906752 100644
--- a/pyramid/paster_templates/routesalchemy/+package+/models.py
+++ b/pyramid/paster_templates/routesalchemy/+package+/models.py
@@ -1,6 +1,5 @@
import transaction
-from sqlalchemy import create_engine
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import Unicode
@@ -33,8 +32,7 @@ def populate():
session.flush()
transaction.commit()
-def initialize_sql(db_string, db_echo=False):
- engine = create_engine(db_string, echo=db_echo)
+def initialize_sql(engine):
DBSession.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all(engine)
diff --git a/pyramid/paster_templates/routesalchemy/+package+/tests.py_tmpl b/pyramid/paster_templates/routesalchemy/+package+/tests.py_tmpl
index de75e5df0..cfab37670 100644
--- a/pyramid/paster_templates/routesalchemy/+package+/tests.py_tmpl
+++ b/pyramid/paster_templates/routesalchemy/+package+/tests.py_tmpl
@@ -3,8 +3,9 @@ from pyramid.configuration import Configurator
from pyramid import testing
def _initTestingDB():
+ from sqlalchemy import create_engine
from {{package}}.models import initialize_sql
- session = initialize_sql('sqlite://')
+ session = initialize_sql(create_engine('sqlite://'))
return session
class TestMyView(unittest.TestCase):
@@ -21,4 +22,4 @@ class TestMyView(unittest.TestCase):
request = testing.DummyRequest()
info = my_view(request)
self.assertEqual(info['root'].name, 'root')
- self.assertEqual(info['project'], '{{package}}')
+ self.assertEqual(info['project'], '{{project}}')
diff --git a/pyramid/paster_templates/routesalchemy/development.ini_tmpl b/pyramid/paster_templates/routesalchemy/development.ini_tmpl
index de4605e33..a1cbff75f 100644
--- a/pyramid/paster_templates/routesalchemy/development.ini_tmpl
+++ b/pyramid/paster_templates/routesalchemy/development.ini_tmpl
@@ -1,20 +1,53 @@
-[app:{{package}}]
-use = egg:{{package}}
+[app:{{project}}]
+use = egg:{{project}}
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_templates = true
default_locale_name = en
-db_string = sqlite:///%(here)s/{{package}}.db
-db_echo = false
+sqlalchemy.url = sqlite:///%(here)s/{{project}}.db
[pipeline:main]
pipeline =
egg:WebError#evalerror
egg:repoze.tm2#tm
- {{package}}
+ {{project}}
[server:main]
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root, sqlalchemy
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_sqlalchemy]
+level = INFO
+handlers =
+qualname = sqlalchemy.engine
+# "level = INFO" logs SQL queries.
+# "level = DEBUG" logs SQL queries and results.
+# "level = WARN" logs neither. (Recommended for production systems.)
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/pyramid/paster_templates/starter/development.ini_tmpl b/pyramid/paster_templates/starter/development.ini_tmpl
index 5031742db..328422ef8 100644
--- a/pyramid/paster_templates/starter/development.ini_tmpl
+++ b/pyramid/paster_templates/starter/development.ini_tmpl
@@ -15,3 +15,29 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/pyramid/paster_templates/starter_zcml/development.ini_tmpl b/pyramid/paster_templates/starter_zcml/development.ini_tmpl
index 5031742db..328422ef8 100644
--- a/pyramid/paster_templates/starter_zcml/development.ini_tmpl
+++ b/pyramid/paster_templates/starter_zcml/development.ini_tmpl
@@ -15,3 +15,29 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/pyramid/paster_templates/zodb/development.ini_tmpl b/pyramid/paster_templates/zodb/development.ini_tmpl
index 85a0681b7..671c8b069 100644
--- a/pyramid/paster_templates/zodb/development.ini_tmpl
+++ b/pyramid/paster_templates/zodb/development.ini_tmpl
@@ -18,3 +18,29 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/pyramid/testing.py b/pyramid/testing.py
index 4acede879..cc0ee5c5b 100644
--- a/pyramid/testing.py
+++ b/pyramid/testing.py
@@ -41,7 +41,7 @@ def registerDummySecurityPolicy(userid=None, groupids=(), permissive=True):
argument. The authentication policy will return the userid
identifier implied by the ``userid`` argument and the group ids
implied by the ``groupids`` argument when the
- :func:`pyramid.security.authenticated_userid` or
+ :func:`pyramid.security.authenticated_userid` or
:func:`pyramid.security.effective_principals` APIs are used.
This function is most useful when testing code that uses the APIs
@@ -211,7 +211,7 @@ def registerAdapter(impl, for_=Interface, provides=Interface, name=''):
The ``name`` argument is the empty string by default; it implies
the name under which the adapter is registered.
-
+
See `The ZCA book <http://www.muthukadan.net/docs/zca.html>`_ for
more information about ZCA adapters.
@@ -282,7 +282,7 @@ def registerSettings(dictarg=None, **kw):
registerSettings({'external_uri':'http://example.com'})
Or a set of key/value pairs::
-
+
registerSettings(external_uri='http://example.com')
Use of this function is required when you need to test code that calls
@@ -361,7 +361,7 @@ class DummyTemplateRenderer(object):
def implementation(self):
return self._implementation
-
+
def __call__(self, kw, system=None):
if system:
self._received.update(system)
@@ -393,7 +393,7 @@ class DummyTemplateRenderer(object):
raise AssertionError(
'A value for key "%s" was not passed to the renderer'
% k)
-
+
if myval != v:
raise AssertionError(
'\nasserted value for %s: %r\nactual value: %r' % (
@@ -431,7 +431,7 @@ class DummyModel:
val.__name__ = name
val.__parent__ = self
self.subs[name] = val
-
+
def __getitem__(self, name):
""" Return a named subobject (see ``__setitem__``)"""
ob = self.subs[name]
@@ -465,7 +465,7 @@ class DummyModel:
def __contains__(self, name):
return name in self.subs
-
+
def clone(self, __name__=_marker, __parent__=_marker, **kw):
""" Create a clone of the model object. If ``__name__`` or
``__parent__`` arguments are passed, use these values to
@@ -485,7 +485,7 @@ class DummyModel:
class DummyRequest(object):
""" A dummy request object (imitates a :term:`request` object).
-
+
The ``params``, ``environ``, ``headers``, ``path``, and
``cookies`` arguments correspond to their :term`WebOb`
equivalents.
@@ -503,6 +503,7 @@ class DummyRequest(object):
application_url = 'http://example.com'
host = 'example.com:80'
content_length = 0
+ query_string = ''
response_callbacks = ()
def __init__(self, params=None, environ=None, headers=None, path='/',
cookies=None, post=None, **kw):
@@ -721,8 +722,8 @@ class DummyRendererFactory(object):
raise KeyError('No testing renderer registered for %r' %
spec)
return renderer
-
-
+
+
class MockTemplate(object):
def __init__(self, response):
self._received = {}
@@ -750,7 +751,7 @@ def skip_on(*platforms):
return decorator
skip_on.os_name = os.name # for testing
try: # pragma: no cover
- import __pypy__
+ import __pypy__
skip_on.pypy = True
except ImportError:
skip_on.pypy = False
diff --git a/pyramid/tests/test_configuration.py b/pyramid/tests/test_configuration.py
index a8ea63f54..5113d1f4e 100644
--- a/pyramid/tests/test_configuration.py
+++ b/pyramid/tests/test_configuration.py
@@ -216,9 +216,8 @@ class ConfiguratorTests(unittest.TestCase):
self.assertEqual(result, pyramid.tests)
def test_maybe_dotted_string_fail(self):
- from pyramid.configuration import ConfigurationError
config = self._makeOne()
- self.assertRaises(ConfigurationError,
+ self.assertRaises(ImportError,
config.maybe_dotted, 'cant.be.found')
def test_maybe_dotted_notstring_success(self):
@@ -2559,6 +2558,36 @@ class ConfiguratorTests(unittest.TestCase):
self.failIf(result is view)
self.assertEqual(result(None, None).body, 'moo')
+ def test_derive_view_with_default_renderer_no_explicit_renderer(self):
+ def view(request):
+ return 'OK'
+ config = self._makeOne()
+ class moo(object):
+ def __init__(self, *arg, **kw):
+ pass
+ def __call__(self, *arg, **kw):
+ return 'moo'
+ config.add_renderer(None, moo)
+ result = config.derive_view(view)
+ self.failIf(result is view)
+ self.assertEqual(result(None, None).body, 'moo')
+
+ def test_derive_view_with_default_renderer_with_explicit_renderer(self):
+ def view(request):
+ return 'OK'
+ config = self._makeOne()
+ class moo(object): pass
+ class foo(object):
+ def __init__(self, *arg, **kw):
+ pass
+ def __call__(self, *arg, **kw):
+ return 'foo'
+ config.add_renderer(None, moo)
+ config.add_renderer('foo', foo)
+ result = config.derive_view(view, renderer='foo')
+ self.failIf(result is view)
+ self.assertEqual(result(None, None).body, 'foo')
+
def test_derive_view_class_without_attr(self):
class View(object):
def __init__(self, request):
@@ -3242,9 +3271,9 @@ class Test__map_view(unittest.TestCase):
request.registry = self.registry
return request
- def _callFUT(self, *arg, **kw):
+ def _callFUT(self, view, **kw):
from pyramid.configuration import _map_view
- return _map_view(*arg, **kw)
+ return _map_view(view, self.registry, **kw)
def test__map_view_as_function_context_and_request(self):
def view(context, request):
@@ -3543,8 +3572,7 @@ class Test__map_view(unittest.TestCase):
def view(context, request):
return {'a':'1'}
info = {'name':renderer.spec, 'package':None}
- result = self._callFUT(view, renderer=info,
- registry=self.registry)
+ result = self._callFUT(view, renderer=info)
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
@@ -4397,9 +4425,7 @@ class TestDottedNameResolver(unittest.TestCase):
def test_resolve_missing_raises(self):
typ = self._makeOne()
- e = self.config_exc(typ.resolve, 'cant.be.found')
- self.assertEqual(e.args[0],
- "The dotted name 'cant.be.found' cannot be imported")
+ self.assertRaises(ImportError, typ.resolve, 'cant.be.found')
def test_ctor_string_module_resolveable(self):
import pyramid.tests
diff --git a/pyramid/url.py b/pyramid/url.py
index 76d95689c..2e73e9cf5 100644
--- a/pyramid/url.py
+++ b/pyramid/url.py
@@ -32,7 +32,7 @@ def route_url(route_name, request, *elements, **kw):
enough arguments, for example).
For example, if you've defined a route named "foobar" with the path
- ``:foo/:bar/*traverse``::
+ ``:foo/{bar}/*traverse``::
route_url('foobar', request, foo='1') => <KeyError exception>
route_url('foobar', request, foo='1', bar='2') => <KeyError exception>
@@ -166,7 +166,7 @@ def route_path(route_name, request, *elements, **kw):
and anchor data are present in the returned string.
For example, if you've defined a route named 'foobar' with the path
- ``/:foo/:bar``, this call to ``route_path``::
+ ``/{foo}/{bar}``, this call to ``route_path``::
route_path('foobar', request, foo='1', bar='2')