summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt11
-rw-r--r--TODO.txt42
-rw-r--r--docs/api.rst1
-rw-r--r--docs/api/decorator.rst9
-rw-r--r--docs/changes.rst2
-rw-r--r--docs/index.rst1
-rw-r--r--docs/latexindex.rst2
-rw-r--r--docs/narr/advconfig.rst7
-rw-r--r--docs/narr/templates.rst36
-rw-r--r--docs/narr/upgrading.rst232
-rw-r--r--docs/tutorials/modwsgi/index.rst22
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/views.py10
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/views.py10
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/views.py10
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/views.py16
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/views.py16
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/views.py16
-rw-r--r--pyramid/chameleon_text.py13
-rw-r--r--pyramid/chameleon_zpt.py13
-rw-r--r--pyramid/config/factories.py2
-rw-r--r--pyramid/decorator.py28
-rw-r--r--pyramid/mako_templating.py9
-rw-r--r--pyramid/renderers.py18
-rw-r--r--pyramid/scripts/pserve.py8
-rw-r--r--pyramid/testing.py2
-rw-r--r--pyramid/tests/test_chameleon_text.py10
-rw-r--r--pyramid/tests/test_chameleon_zpt.py10
27 files changed, 402 insertions, 154 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 44e594afb..94c331cef 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -160,6 +160,9 @@ Features
- ``request.context`` of environment request during ``bootstrap`` is now the
root object if a context isn't already set on a provided request.
+- The ``pyramid.decorator.reify`` function is now an API, and was added to
+ the API documentation.
+
Deprecations
------------
@@ -246,6 +249,14 @@ Backwards Incompatibilities
* ``registerSettings``, use
``pyramid.config.Configurator.add_settings`` instead.
+Documentation
+-------------
+
+- Added an "Upgrading Pyramid" chapter to the narrative documentation. It
+ describes how to cope with deprecations and removals of Pyramid APIs and
+ how to show Pyramid-generated deprecation warnings while running tests and
+ while running a server.
+
Dependencies
------------
diff --git a/TODO.txt b/TODO.txt
index 627eff7e8..202d1afbb 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -95,6 +95,45 @@ Nice-to-Have
- Update App engine chapter with less creaky directions.
+- Idea from Zart:
+
+ diff --git a/pyramid/paster.py b/pyramid/paster.py
+ index b0e4d79..b3bd82a 100644
+ --- a/pyramid/paster.py
+ +++ b/pyramid/paster.py
+ @@ -8,6 +8,7 @@ from paste.deploy import (
+ from pyramid.compat import configparser
+ from logging.config import fileConfig
+ from pyramid.scripting import prepare
+ +from pyramid.config import Configurator
+
+ def get_app(config_uri, name=None, loadapp=loadapp):
+ """ Return the WSGI application named ``name`` in the PasteDeploy
+ @@ -111,3 +112,10 @@ def bootstrap(config_uri, request=None):
+ env['app'] = app
+ return env
+
+ +def make_pyramid_app(global_conf, app=None, **settings):
+ + """Return pyramid application configured with provided settings"""
+ + config = Configurator(package='pyramid', settings=settings)
+ + if app:
+ + config.include(app)
+ + app = config.make_wsgi_app()
+ + return app
+ diff --git a/setup.py b/setup.py
+ index 03ebb42..91e0e21 100644
+ --- a/setup.py
+ +++ b/setup.py
+ @@ -118,6 +118,8 @@ setup(name='pyramid',
+ [paste.server_runner]
+ wsgiref = pyramid.scripts.pserve:wsgiref_server_runner
+ cherrypy = pyramid.scripts.pserve:cherrypy_server_runner
+ + [paster.app_factory]
+ + main = pyramid.paster:make_pyramid_app
+ """
+ )
+
+
Future
------
@@ -104,7 +143,8 @@ Future
original dict (after ``__getattr__`` deprecation period, it was deprecated
in 1.2).
-- 1.5: Remove ``pyramid.requests.DeprecatedRequestMethodsMixin``.
+- 1.5: Remove ``pyramid.requests.DeprecatedRequestMethodsMixin`` and code in
+ renderers module that looks for _response_content_type, et. al.
- 1.5: Maybe? deprecate set_request_property in favor of pointing people at
add_request_method, schedule removal for 1.8?
diff --git a/docs/api.rst b/docs/api.rst
index e33fd6a74..9e540b49b 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -12,6 +12,7 @@ documentation is organized alphabetically by module name.
api/authentication
api/compat
api/config
+ api/decorator
api/events
api/exceptions
api/httpexceptions
diff --git a/docs/api/decorator.rst b/docs/api/decorator.rst
new file mode 100644
index 000000000..35d9131df
--- /dev/null
+++ b/docs/api/decorator.rst
@@ -0,0 +1,9 @@
+.. _decorator_module:
+
+:mod:`pyramid.decorator`
+--------------------------
+
+.. automodule:: pyramid.decorator
+
+.. autofunction:: reify
+
diff --git a/docs/changes.rst b/docs/changes.rst
index 6294123ed..fdeaf1e99 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -1,3 +1,5 @@
+.. _changelog:
+
:app:`Pyramid` Change History
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/index.rst b/docs/index.rst
index c84314274..321fe1fed 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -88,6 +88,7 @@ Narrative documentation in chapter form explaining how to use
narr/advconfig
narr/extconfig
narr/scaffolding
+ narr/upgrading
narr/threadlocals
narr/zca
diff --git a/docs/latexindex.rst b/docs/latexindex.rst
index 99ec2f54d..604e6e7c6 100644
--- a/docs/latexindex.rst
+++ b/docs/latexindex.rst
@@ -85,8 +85,6 @@ API Reference
api/authorization
api/authentication
- api/chameleon_text
- api/chameleon_zpt
api/config
api/events
api/exceptions
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index 165cf7474..ad22a82c9 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -414,3 +414,10 @@ constraints: the routes they imply require relative ordering. Such ordering
constraints are not absolved by two-phase configuration. Routes are still
added in configuration execution order.
+More Information
+----------------
+
+For more information, see the article entitled `"A Whirlwind Rour of Advanced
+Configuration Tactics"
+<http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/whirlwind_tour.html>`_
+in the Pyramid Cookbook.
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 656cf4773..ba72ebfbf 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -46,20 +46,6 @@ within the body of a view callable like so:
{'foo':1, 'bar':2},
request=request)
-.. warning::
-
- Earlier iterations of this documentation
- (pre-version-1.3) encouraged the application developer to use
- ZPT-specific APIs such as
- :func:`pyramid.chameleon_zpt.render_template_to_response` and
- :func:`pyramid.chameleon_zpt.render_template` to render templates
- directly. This style of rendering still works, but at least for
- purposes of this documentation, those functions are deprecated.
- Application developers are encouraged instead to use the functions
- available in the :mod:`pyramid.renderers` module to perform
- rendering tasks. This set of functions works to render templates
- for all renderer extensions registered with :app:`Pyramid`.
-
The ``sample_view`` :term:`view callable` function above returns a
:term:`response` object which contains the body of the
``templates/foo.pt`` template. In this case, the ``templates``
@@ -79,12 +65,12 @@ prefix on Windows.
.. warning::
Only :term:`Chameleon` templates support defining a renderer for a
- template relative to the location of the module where the view
- callable is defined. Mako templates, and other templating system
- bindings work differently. In particular, Mako templates use a
- "lookup path" as defined by the ``mako.directories`` configuration
- file instead of treating relative paths as relative to the current
- view module. See :ref:`mako_templates`.
+ template relative to the location of the module where the view callable is
+ defined. Mako templates, and other templating system bindings work
+ differently. In particular, Mako templates use a "lookup path" as defined
+ by the ``mako.directories`` configuration file instead of treating
+ relative paths as relative to the current view module. See
+ :ref:`mako_templates`.
The path can alternately be a :term:`asset specification` in the form
``some.dotted.package_name:relative/path``. This makes it possible to
@@ -542,7 +528,7 @@ Sommetime you'd like to render a macro inside of a Chameleon ZPT template
instead of the full Chameleon ZPT template. To render the content of a
``define-macro`` field inside a Chameleon ZPT template, given a Chameleon
template file named ``foo.pt`` and a macro named ``bar`` defined within it
-(e.g. ``<div metal:define-macro="bar">...</div>``, you can configure the
+(e.g. ``<div metal:define-macro="bar">...</div>``), you can configure the
template as a :term:`renderer` like so:
.. code-block:: python
@@ -554,8 +540,8 @@ template as a :term:`renderer` like so:
def my_view(request):
return {'project':'my project'}
-The above will render the ``bar`` macro from within the ``foo.pt`` template
-instead of the entire template.
+The above will render only the ``bar`` macro defined within the ``foo.pt``
+template instead of the entire template.
.. note::
@@ -600,10 +586,6 @@ When the template is rendered, it will show:
Hello, world!
-If you'd rather use templates directly within a view callable (without
-the indirection of using a renderer), see :ref:`chameleon_text_module`
-for the API description.
-
See also :ref:`built_in_renderers` for more general information about
renderers, including Chameleon text renderers.
diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst
new file mode 100644
index 000000000..92f125c0a
--- /dev/null
+++ b/docs/narr/upgrading.rst
@@ -0,0 +1,232 @@
+Upgrading Pyramid
+=================
+
+When a new version of Pyramid is released, it will sometimes deprecate a
+feature or remove a feature that was deprecated in an older release. When
+features are removed from Pyramid, applications that depend on those features
+will begin to break. This chapter explains how to ensure your Pyramid
+applications keep working when you upgrade the Pyramid version you're using.
+
+.. sidebar:: About Release Numbering
+
+ Conventionally, application version numbering in Python is described as
+ ``major.minor.micro``. If your Pyramid version is "1.2.3", it means
+ you're running a version of Pyramid with the major version "1", the minor
+ version "2" and the micro version "3". A "major" release is one that
+ increments the first-dot number; 2.X.X might follow 1.X.X. A "minor"
+ release is one that increments the second-dot number; 1.3.X might follow
+ 1.2.X. A "micro" release is one that increments the third-dot number;
+ 1.2.3 might follow 1.2.2. In general, micro releases are "bugfix-only",
+ and contain no new features, minor releases contain new features but are
+ largely backwards compatible with older versions, and a major release
+ indicates a large set of backwards incompatibilities.
+
+The Pyramid core team is conservative when it comes to removing features. We
+don't remove features unnecessarily, but we're human, and we make mistakes
+which cause some features to be evolutionary dead ends. Though we are
+willing to support dead-end features for some amount of time, some eventually
+have to be removed when the cost of supporting them outweighs the benefit of
+keeping them around, because each feature in Pyramid represents a certain
+documentation and maintenance burden.
+
+Deprecation and Removal Policy
+------------------------------
+
+When a feature is scheduled for removal from Pyramid or any of its official
+add-ons, the core development team takes these steps:
+
+- Using the feature will begin to generate a `DeprecationWarning`, indicating
+ the version in which the feature became deprecated.
+
+- A note is added to the documentation indicating that the feature is
+ deprecated.
+
+- A note is added to the :ref:`changelog` about the deprecation.
+
+When a deprecated feature is eventually removed:
+
+- The feature is removed.
+
+- A note is added to the :ref:`changelog` about the removal.
+
+Features are never removed in *micro* releases. They are only removed in
+minor and major releases. Deprecated features are kept around for at least
+*three* minor releases from the time the feature became deprecated.
+Therefore, if a feature is added in Pyramid 1.0, but it's deprecated in
+Pyramid 1.1, it will be kept around through all 1.1.X releases, all 1.2.X
+releases and all 1.3.X releases. It will finally be removed in the first
+1.4.X release.
+
+Sometimes features are "docs-deprecated" instead of formally deprecated.
+This means that the feature will be kept around indefinitely, but it will be
+removed from the documentation or a note will be added to the documentation
+telling folks to use some other newer feature. This happens when the cost of
+keeping an old feature around is very minimal and the support and
+documentation burden is very low. For example, we might rename a function
+that is an API without changing the arguments it accepts. In this case,
+we'll often rename the function, and change the docs to point at the new
+function name, but leave around a backwards compatibility alias to the old
+function name so older code doesn't break.
+
+"Docs deprecated" features tend to work "forever", meaning that they won't be
+removed, and they'll never generate a deprecation warning. However, such
+changes are noted in the :ref:`changelog`, so it's possible to know that you
+should change older spellings to newer ones to ensure that people reading
+your code can find the APIs you're using in the Pyramid docs.
+
+Consulting the Change History
+-----------------------------
+
+Your first line of defense against application failures caused by upgrading
+to a newer Pyramid release is always to read the :ref:`changelog`. to find
+the deprecations and removals for each release between the release you're
+currently running and the one you wish to upgrade to. The change history
+notes every deprecation within a ``Deprecation`` section and every removal
+within a ``Backwards Incompatibilies`` section for each release.
+
+The change history often contains instructions for changing your code to
+avoid deprecation warnings and how to change docs-deprecated spellings to
+newer ones. You can follow along with each deprecation explanation in the
+change history, simply doing a grep or other code search to your application,
+using the change log examples to remediate each potential problem.
+
+.. _testing_under_new_release:
+
+Testing Your Application Under a New Pyramid Release
+----------------------------------------------------
+
+Once you've upgraded your application to a new Pyramid release and you've
+remediated as much as possible by using the change history notes, you'll want
+to run your application's tests (see :ref:`running_tests`) in such a way that
+you can see DeprecationWarnings printed to the console when the tests run.
+
+.. code-block:: bash
+
+ $ python -Wd setup.py test -q
+
+The ``-Wd`` argument is an argument that tells Python to print deprecation
+warnings to the console. Note that the ``-Wd`` flag is only required for
+Python 2.7 and better: Python versions 2.6 and older print deprecation
+warnings to the console by default. See `the Python -W flag documentation
+<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more
+information.
+
+As your tests run, deprecation warnings will be printed to the console
+explaining the deprecation and providing instructions about how to prevent
+the deprecation warning from being issued. For example:
+
+.. code-block:: text
+
+ $ python -Wd setup.py test -q
+ # .. elided ...
+ running build_ext
+ /home/chrism/projects/pyramid/env27/myproj/myproj/views.py:3:
+ DeprecationWarning: static: The "pyramid.view.static" class is deprecated
+ as of Pyramid 1.1; use the "pyramid.static.static_view" class instead with
+ the "use_subpath" argument set to True.
+ from pyramid.view import static
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.014s
+
+ OK
+
+In the above case, it's line #3 in the ``myproj.views`` module (``from
+pyramid.view import static``) that is causing the problem:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+
+ from pyramid.view import static
+ myview = static('static', 'static')
+
+The deprecation warning tells me how to fix it, so I can change the code to
+do things the newer way:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view. import view_config
+
+ from pyramid.static import static_view
+ myview = static_view('static', 'static', use_subpath=True)
+
+When I run the tests again, the deprecation warning is no longer printed to
+my console:
+
+.. code-block:: text
+
+ $ python -Wd setup.py test -q
+ # .. elided ...
+ running build_ext
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.014s
+
+ OK
+
+
+My Application Doesn't Have Any Tests or Has Few Tests
+------------------------------------------------------
+
+If your application has no tests, or has only moderate test coverage, running
+tests won't tell you very much, because the Pyramid codepaths that generate
+deprecation warnings won't be executed.
+
+In this circumstance, you can start your application interactively under a
+server run with the ``PYTHONWARNINGS`` environment variable set to
+``default``. On UNIX, you can do that via:
+
+.. code-block:: bash
+
+ $ PYTHONWARNINGS=default bin/pserve development.ini
+
+On Windows, you need to issue two commands:
+
+.. code-block:: bash
+
+ C:\> set PYTHONWARNINGS=default
+ C:\> Scripts/pserve.exe development.ini
+
+At this point, it's ensured that deprecation warnings will be printed to the
+console whenever a codepath is hit that generates one. You can then click
+around in your application interactively to try to generate them, and
+remediate as explained in :ref:`testing_under_new_release`.
+
+See `the PYTHONWARNINGS environment variable documentation
+<http://docs.python.org/using/cmdline.html#envvar-PYTHONWARNINGS>`_ or `the
+Python -W flag documentation
+<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more
+information.
+
+Upgrading to the Very Latest Pyramid Release
+--------------------------------------------
+
+When you upgrade your application to the very most recent Pyramid release,
+it's advisable to upgrade step-wise through each most recent minor release,
+beginning with the one that you know your application currently runs under,
+and ending on the most recent release. For example, if your application is
+running in production on Pyramid 1.2.1, and the most recent Pyramid 1.3
+release is Pyramid 1.3.3, and the most recent Pyramid release is 1.4.4, it's
+advisable to do this:
+
+- Upgrade your environment to the most recent 1.2 release. For example, the
+ most recent 1.2 release might be 1.2.3, so upgrade to it. Then run your
+ application's tests under 1.2.3 as described in
+ :ref:`testing_under_new_release`. Note any deprecation warnings and
+ remediate.
+
+- Upgrade to the most recent 1.3 release, 1.3.3. Run your application's
+ tests, note any deprecation warnings and remediate.
+
+- Upgrade to 1.4.4. Run your application's tests, note any deprecation
+ warnings and remediate.
+
+If you skip testing your application under each minor release (for example if
+you upgrade directly from 1.2.1 to 1.4.4), you might miss a deprecation
+warning and waste more time trying to figure out an error caused by a feature
+removal than it would take to upgrade stepwise through each minor release.
+
+
diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst
index d11167344..a22f12610 100644
--- a/docs/tutorials/modwsgi/index.rst
+++ b/docs/tutorials/modwsgi/index.rst
@@ -7,12 +7,11 @@ Running a :app:`Pyramid` Application under ``mod_wsgi``
It allows :term:`WSGI` programs to be served using the Apache web
server.
-This guide will outline broad steps that can be used to get a
-:app:`Pyramid` application running under Apache via ``mod_wsgi``.
-This particular tutorial was developed under Apple's Mac OS X platform
-(Snow Leopard, on a 32-bit Mac), but the instructions should be
-largely the same for all systems, delta specific path information for
-commands and files.
+This guide will outline broad steps that can be used to get a :app:`Pyramid`
+application running under Apache via ``mod_wsgi``. This particular tutorial
+was developed under Apple's Mac OS X platform (Snow Leopard, on a 32-bit
+Mac), but the instructions should be largely the same for all systems, delta
+specific path information for commands and files.
.. note:: Unfortunately these instructions almost certainly won't work for
deploying a :app:`Pyramid` application on a Windows system using
@@ -90,12 +89,11 @@ commands and files.
`logging` module to allow logging within your application.
See :ref:`logging_config`.
-#. Make the ``pyramid.wsgi`` script executable.
-
- .. code-block:: text
-
- $ cd ~/modwsgi/env
- $ chmod 755 pyramid.wsgi
+ There is no need to make the ``pyramid.wsgi`` script executable.
+ However, you'll need to make sure that *two* users have access to change
+ into the ``~/modwsgi/env`` directory: your current user (mine is
+ ``chrism`` and the user that Apache will run as often named ``apache`` or
+ ``httpd``). Make sure both of these users can "cd" into that directory.
#. Edit your Apache configuration and add some stuff. I happened to
create a file named ``/etc/apache2/other/modwsgi.conf`` on my own
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views.py b/docs/tutorials/wiki/src/authorization/tutorial/views.py
index 21f12b31d..50485d279 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/views.py
@@ -51,17 +51,17 @@ def view_page(context, request):
renderer='templates/edit.pt',
permission='edit')
def add_page(context, request):
- name = request.subpath[0]
+ pagename = request.subpath[0]
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(body)
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
- context[name] = page
+ context[pagename] = page
return HTTPFound(location = request.resource_url(page))
- save_url = request.resource_url(context, 'add_page', name)
+ save_url = request.resource_url(context, 'add_page', pagename)
page = Page('')
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
return dict(page = page, save_url = save_url,
diff --git a/docs/tutorials/wiki/src/tests/tutorial/views.py b/docs/tutorials/wiki/src/tests/tutorial/views.py
index 21f12b31d..50485d279 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/views.py
+++ b/docs/tutorials/wiki/src/tests/tutorial/views.py
@@ -51,17 +51,17 @@ def view_page(context, request):
renderer='templates/edit.pt',
permission='edit')
def add_page(context, request):
- name = request.subpath[0]
+ pagename = request.subpath[0]
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(body)
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
- context[name] = page
+ context[pagename] = page
return HTTPFound(location = request.resource_url(page))
- save_url = request.resource_url(context, 'add_page', name)
+ save_url = request.resource_url(context, 'add_page', pagename)
page = Page('')
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
return dict(page = page, save_url = save_url,
diff --git a/docs/tutorials/wiki/src/views/tutorial/views.py b/docs/tutorials/wiki/src/views/tutorial/views.py
index 016f5b6bb..b0c15297f 100644
--- a/docs/tutorials/wiki/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki/src/views/tutorial/views.py
@@ -35,17 +35,17 @@ def view_page(context, request):
@view_config(name='add_page', context='.models.Wiki',
renderer='templates/edit.pt')
def add_page(context, request):
- name = request.subpath[0]
+ pagename = request.subpath[0]
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(body)
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
- context[name] = page
+ context[pagename] = page
return HTTPFound(location = request.resource_url(page))
- save_url = request.resource_url(context, 'add_page', name)
+ save_url = request.resource_url(context, 'add_page', pagename)
page = Page('')
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
return dict(page = page, save_url = save_url)
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/views.py b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
index c7670b049..0d085b0e2 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
@@ -60,14 +60,14 @@ def view_page(request):
@view_config(route_name='add_page', renderer='templates/edit.pt',
permission='edit')
def add_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
if 'form.submitted' in request.params:
body = request.params['body']
- page = Page(name, body)
+ page = Page(pagename, body)
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
- save_url = request.route_url('add_page', pagename=name)
+ pagename=pagename))
+ save_url = request.route_url('add_page', pagename=pagename)
page = Page('', '')
return dict(page=page, save_url=save_url,
logged_in=authenticated_userid(request))
@@ -75,16 +75,16 @@ def add_page(request):
@view_config(route_name='edit_page', renderer='templates/edit.pt',
permission='edit')
def edit_page(request):
- name = request.matchdict['pagename']
- page = DBSession.query(Page).filter_by(name=name).one()
+ pagename = request.matchdict['pagename']
+ page = DBSession.query(Page).filter_by(name=pagename).one()
if 'form.submitted' in request.params:
page.data = request.params['body']
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
+ pagename=pagename))
return dict(
page=page,
- save_url = request.route_url('edit_page', pagename=name),
+ save_url = request.route_url('edit_page', pagename=pagename),
logged_in=authenticated_userid(request),
)
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views.py b/docs/tutorials/wiki2/src/tests/tutorial/views.py
index f2a33af1e..42ac0eb7f 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/views.py
@@ -61,15 +61,15 @@ def view_page(request):
@view_config(route_name='add_page', renderer='templates/edit.pt',
permission='edit')
def add_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
if 'form.submitted' in request.params:
session = DBSession()
body = request.params['body']
- page = Page(name, body)
+ page = Page(pagename, body)
session.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
- save_url = request.route_url('add_page', pagename=name)
+ pagename=pagename))
+ save_url = request.route_url('add_page', pagename=pagename)
page = Page('', '')
return dict(page=page, save_url=save_url,
logged_in=authenticated_userid(request))
@@ -77,17 +77,17 @@ def add_page(request):
@view_config(route_name='edit_page', renderer='templates/edit.pt',
permission='edit')
def edit_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
session = DBSession()
- page = session.query(Page).filter_by(name=name).one()
+ page = session.query(Page).filter_by(name=pagename).one()
if 'form.submitted' in request.params:
page.data = request.params['body']
session.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
+ pagename=pagename))
return dict(
page=page,
- save_url = request.route_url('edit_page', pagename=name),
+ save_url = request.route_url('edit_page', pagename=pagename),
logged_in=authenticated_userid(request),
)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/views.py b/docs/tutorials/wiki2/src/views/tutorial/views.py
index c2a94a96b..5a9c75a61 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/views.py
@@ -44,27 +44,27 @@ def view_page(request):
@view_config(route_name='add_page', renderer='templates/edit.pt')
def add_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
if 'form.submitted' in request.params:
body = request.params['body']
- page = Page(name, body)
+ page = Page(pagename, body)
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
- save_url = request.route_url('add_page', pagename=name)
+ pagename=pagename))
+ save_url = request.route_url('add_page', pagename=pagename)
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']
- page = DBSession.query(Page).filter_by(name=name).one()
+ pagename = request.matchdict['pagename']
+ page = DBSession.query(Page).filter_by(name=pagename).one()
if 'form.submitted' in request.params:
page.data = request.params['body']
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
+ pagename=pagename))
return dict(
page=page,
- save_url = request.route_url('edit_page', pagename=name),
+ save_url = request.route_url('edit_page', pagename=pagename),
)
diff --git a/pyramid/chameleon_text.py b/pyramid/chameleon_text.py
index 3484b7973..21dc85528 100644
--- a/pyramid/chameleon_text.py
+++ b/pyramid/chameleon_text.py
@@ -2,18 +2,7 @@ import sys
from zope.interface import implementer
-from pyramid.compat import reraise
-
-try:
- from chameleon.zpt.template import PageTextTemplateFile
- # prevent pyflakes complaining about a redefinition below
- PageTextTemplateFile
-except ImportError: # pragma: no cover
- exc_class, exc, tb = sys.exc_info()
- # Chameleon doesn't work on non-CPython platforms
- class PageTextTemplateFile(object):
- def __init__(self, *arg, **kw):
- reraise(ImportError, exc, tb)
+from chameleon.zpt.template import PageTextTemplateFile
from pyramid.interfaces import ITemplateRenderer
diff --git a/pyramid/chameleon_zpt.py b/pyramid/chameleon_zpt.py
index d9f4337fa..862e996b9 100644
--- a/pyramid/chameleon_zpt.py
+++ b/pyramid/chameleon_zpt.py
@@ -2,20 +2,9 @@ import sys
from zope.interface import implementer
-from pyramid.compat import reraise
-
-try:
- from chameleon.zpt.template import PageTemplateFile
- PageTemplateFile # prevent pyflakes complaining about a redefinition below
-except ImportError: # pragma: no cover
- exc_class, exc, tb = sys.exc_info()
- # Chameleon doesn't work on non-CPython platforms
- class PageTemplateFile(object):
- def __init__(self, *arg, **kw):
- reraise(ImportError, exc, tb)
+from chameleon.zpt.template import PageTemplateFile
from pyramid.interfaces import ITemplateRenderer
-
from pyramid.decorator import reify
from pyramid import renderers
diff --git a/pyramid/config/factories.py b/pyramid/config/factories.py
index c5d453654..e46519bf5 100644
--- a/pyramid/config/factories.py
+++ b/pyramid/config/factories.py
@@ -184,7 +184,7 @@ class FactoriesConfiguratorMixin(object):
.. warning::
- This method has been deprecated as of Pyramid 1.4.
+ This method has been docs-deprecated as of Pyramid 1.4.
:meth:`pyramid.config.Configurator.add_request_method` should be
used instead.
diff --git a/pyramid/decorator.py b/pyramid/decorator.py
index 98d7b36b5..82d2b1280 100644
--- a/pyramid/decorator.py
+++ b/pyramid/decorator.py
@@ -1,9 +1,31 @@
class reify(object):
+ """ Use as a class method decorator. It operates almost exactly like the
+ Python ``@property`` decorator, but it puts the result of the method it
+ decorates into the instance dict after the first call, effectively
+ replacing the function it decorates with an instance variable. It is, in
+ Python parlance, a non-data descriptor. An example:
- """ Put the result of a method which uses this (non-data)
- descriptor decorator in the instance dict after the first call,
- effectively replacing the decorator with an instance variable."""
+ .. code-block:: python
+ class Foo(object):
+ @reify
+ def jammy(self):
+ print 'jammy called'
+ return 1
+
+ And usage of Foo:
+
+ .. code-block:: text
+
+ >>> f = Foo()
+ >>> v = f.jammy
+ 'jammy called'
+ >>> print v
+ 1
+ >>> f.jammy
+ 1
+ >>> # jammy func not called the second time; it replaced itself with 1
+ """
def __init__(self, wrapped):
self.wrapped = wrapped
try:
diff --git a/pyramid/mako_templating.py b/pyramid/mako_templating.py
index 2b09e8d45..5d09cad01 100644
--- a/pyramid/mako_templating.py
+++ b/pyramid/mako_templating.py
@@ -95,7 +95,9 @@ class MakoRendererFactoryHelper(object):
r'(?:\#(?P<defname>[\w_]+))?'
r'(\.(?P<ext>.*))'
)
- asset, defname, ext = p.match(info.name).group('asset', 'defname', 'ext')
+ asset, defname, ext = p.match(info.name).group(
+ 'asset', 'defname', 'ext'
+ )
path = '%s.%s' % (asset, ext)
registry = info.registry
settings = info.settings
@@ -154,12 +156,9 @@ class MakoRendererFactoryHelper(object):
preprocessor=preprocessor
)
- registry_lock.acquire()
- try:
+ with registry_lock:
registry.registerUtility(lookup, IMakoLookup,
name=settings_prefix)
- finally:
- registry_lock.release()
return MakoLookupTemplateRenderer(path, defname, lookup)
diff --git a/pyramid/renderers.py b/pyramid/renderers.py
index fe9df33d1..3252c2c93 100644
--- a/pyramid/renderers.py
+++ b/pyramid/renderers.py
@@ -429,12 +429,9 @@ class ChameleonRendererLookup(object):
if renderer is None:
renderer = self.impl(spec, self, macro=None)
# cache the template
- try:
- self.lock.acquire()
+ with self.lock:
registry.registerUtility(renderer,
ITemplateRenderer, name=spec)
- finally:
- self.lock.release()
else:
# spec is a package:relpath asset spec
renderer = registry.queryUtility(ITemplateRenderer, name=spec)
@@ -445,7 +442,8 @@ class ChameleonRendererLookup(object):
r'(\.(?P<ext>.*))'
)
asset, macro, ext = p.match(spec).group(
- 'asset', 'defname', 'ext')
+ 'asset', 'defname', 'ext'
+ )
spec = '%s.%s' % (asset, ext)
try:
package_name, filename = spec.split(':', 1)
@@ -463,12 +461,9 @@ class ChameleonRendererLookup(object):
settings = info.settings
if not settings.get('reload_assets'):
# cache the template
- self.lock.acquire()
- try:
+ with self.lock:
registry.registerUtility(renderer, ITemplateRenderer,
name=spec)
- finally:
- self.lock.release()
return renderer
@@ -479,11 +474,8 @@ def template_renderer_factory(info, impl, lock=registry_lock):
lookup = registry.queryUtility(IChameleonLookup, name=info.type)
if lookup is None:
lookup = ChameleonRendererLookup(impl, registry)
- lock.acquire()
- try:
+ with lock:
registry.registerUtility(lookup, IChameleonLookup, name=info.type)
- finally:
- lock.release()
return lookup(info)
@implementer(IRendererInfo)
diff --git a/pyramid/scripts/pserve.py b/pyramid/scripts/pserve.py
index ea2a4ae09..9fbf0729a 100644
--- a/pyramid/scripts/pserve.py
+++ b/pyramid/scripts/pserve.py
@@ -583,12 +583,8 @@ class LazyWriter(object):
def open(self):
if self.fileobj is None:
- self.lock.acquire()
- try:
- if self.fileobj is None:
- self.fileobj = open(self.filename, self.mode)
- finally:
- self.lock.release()
+ with self.lock:
+ self.fileobj = open(self.filename, self.mode)
return self.fileobj
def close(self):
diff --git a/pyramid/testing.py b/pyramid/testing.py
index 750effb83..e091bac4f 100644
--- a/pyramid/testing.py
+++ b/pyramid/testing.py
@@ -293,7 +293,7 @@ class DummyRequest(DeprecatedRequestMethodsMixin, URLMethodsMixin,
request. For example, by default, the DummyRequest ``GET`` and ``POST``
attributes are of type ``dict``, unlike a normal Request's GET and POST,
which are of type ``MultiDict``. If your code uses the features of
- MultiDict, you should either use a"real" :class:`pyramid.request.Request`
+ MultiDict, you should either use a real :class:`pyramid.request.Request`
or adapt your DummyRequest by replacing the attributes with ``MultiDict``
instances.
diff --git a/pyramid/tests/test_chameleon_text.py b/pyramid/tests/test_chameleon_text.py
index 297e96554..d9f20f241 100644
--- a/pyramid/tests/test_chameleon_text.py
+++ b/pyramid/tests/test_chameleon_text.py
@@ -2,7 +2,6 @@ import sys
import unittest
from pyramid.compat import binary_type
-from pyramid.testing import skip_on
from pyramid import testing
class Base(object):
@@ -50,7 +49,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
from pyramid.interfaces import ITemplateRenderer
verifyClass(ITemplateRenderer, self._getTargetClass())
- @skip_on('java')
def test_template_reified(self):
minimal = self._getTemplatePath('minimal.txt')
lookup = DummyLookup()
@@ -59,7 +57,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template, instance.__dict__['template'])
- @skip_on('java')
def test_template_with_ichameleon_translate(self):
minimal = self._getTemplatePath('minimal.txt')
lookup = DummyLookup()
@@ -68,7 +65,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template.translate, lookup.translate)
- @skip_on('java')
def test_template_with_debug_templates(self):
minimal = self._getTemplatePath('minimal.txt')
lookup = DummyLookup()
@@ -78,7 +74,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template.debug, True)
- @skip_on('java')
def test_template_with_reload_templates(self):
minimal = self._getTemplatePath('minimal.txt')
lookup = DummyLookup()
@@ -88,7 +83,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template.auto_reload, True)
- @skip_on('java')
def test_template_without_reload_templates(self):
minimal = self._getTemplatePath('minimal.txt')
lookup = DummyLookup()
@@ -98,7 +92,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template.auto_reload, False)
- @skip_on('java')
def test_call(self):
minimal = self._getTemplatePath('minimal.txt')
lookup = DummyLookup()
@@ -107,14 +100,12 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
self.assertTrue(isinstance(result, binary_type))
self.assertEqual(result, b'Hello.\n')
- @skip_on('java')
def test_call_with_nondict_value(self):
minimal = self._getTemplatePath('minimal.txt')
lookup = DummyLookup()
instance = self._makeOne(minimal, lookup)
self.assertRaises(ValueError, instance, None, {})
- @skip_on('java')
def test_call_nonminimal(self):
nonminimal = self._getTemplatePath('nonminimal.txt')
lookup = DummyLookup()
@@ -123,7 +114,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
self.assertTrue(isinstance(result, binary_type))
self.assertEqual(result, b'Hello, Chris!\n')
- @skip_on('java')
def test_implementation(self):
minimal = self._getTemplatePath('minimal.txt')
lookup = DummyLookup()
diff --git a/pyramid/tests/test_chameleon_zpt.py b/pyramid/tests/test_chameleon_zpt.py
index 5d197dac4..37538e83e 100644
--- a/pyramid/tests/test_chameleon_zpt.py
+++ b/pyramid/tests/test_chameleon_zpt.py
@@ -1,7 +1,6 @@
import sys
import unittest
-from pyramid.testing import skip_on
from pyramid import testing
from pyramid.compat import text_type
@@ -50,7 +49,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
from pyramid.interfaces import ITemplateRenderer
verifyClass(ITemplateRenderer, self._getTargetClass())
- @skip_on('java')
def test_call(self):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()
@@ -60,7 +58,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
self.assertEqual(result.rstrip('\n'),
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
- @skip_on('java')
def test_template_reified(self):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()
@@ -69,7 +66,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template, instance.__dict__['template'])
- @skip_on('java')
def test_template_with_ichameleon_translate(self):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()
@@ -78,7 +74,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template.translate, lookup.translate)
- @skip_on('java')
def test_template_with_debug_templates(self):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()
@@ -88,7 +83,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template.debug, True)
- @skip_on('java')
def test_template_without_debug_templates(self):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()
@@ -98,7 +92,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template.debug, False)
- @skip_on('java')
def test_template_with_reload_templates(self):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()
@@ -108,7 +101,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template.auto_reload, True)
- @skip_on('java')
def test_template_without_reload_templates(self):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()
@@ -118,14 +110,12 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template.auto_reload, False)
- @skip_on('java')
def test_call_with_nondict_value(self):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()
instance = self._makeOne(minimal, lookup)
self.assertRaises(ValueError, instance, None, {})
- @skip_on('java')
def test_implementation(self):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()