summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt9
-rw-r--r--docs/tutorials/wiki/definingmodels.rst3
-rw-r--r--docs/tutorials/wiki/definingviews.rst4
-rw-r--r--docs/tutorials/wiki/design.rst134
-rw-r--r--docs/tutorials/wiki/index.rst1
-rw-r--r--docs/tutorials/wiki/installation.rst2
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst45
-rw-r--r--docs/tutorials/wiki2/definingmodels.rst9
-rw-r--r--docs/tutorials/wiki2/definingviews.rst3
-rw-r--r--docs/tutorials/wiki2/design.rst132
-rw-r--r--docs/tutorials/wiki2/index.rst1
-rw-r--r--docs/tutorials/wiki2/installation.rst2
-rw-r--r--pyramid/config/views.py14
-rw-r--r--pyramid/testing.py2
-rw-r--r--pyramid/tests/test_config/test_init.py58
-rw-r--r--pyramid/tests/test_config/test_rendering.py37
-rw-r--r--pyramid/tests/test_config/test_settings.py32
-rw-r--r--pyramid/tests/test_config/test_views.py12
18 files changed, 396 insertions, 104 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 8076bc35d..abdb3d80a 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,12 @@
+Next release
+============
+
+Bug Fixes
+---------
+
+- ``config.add_view(<aninstancemethod>)`` raised AttributeError involving
+ ``__text__``. See https://github.com/Pylons/pyramid/issues/461
+
1.3b2 (2012-03-02)
==================
diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst
index cdf3b6092..982d6ea74 100644
--- a/docs/tutorials/wiki/definingmodels.rst
+++ b/docs/tutorials/wiki/definingmodels.rst
@@ -88,7 +88,8 @@ View the Application in a Browser
We can't. At this point, our system is in a "non-runnable" state; we'll need
to change view-related files in the next chapter to be able to start the
-application successfully. If you try to start the application, you'll wind
+application successfully. If you try to start the application (See
+:ref:`wiki-start-the-application`), you'll wind
up with a Python traceback on your console that ends with this exception:
.. code-block:: text
diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst
index 371cae8eb..53e60fda3 100644
--- a/docs/tutorials/wiki/definingviews.rst
+++ b/docs/tutorials/wiki/definingviews.rst
@@ -301,8 +301,8 @@ subdirectories) and are just referred to by URL.
Viewing the Application in a Browser
====================================
-We can finally examine our application in a
-browser. The views we'll try are as follows:
+We can finally examine our application in a browser (See
+:ref:`wiki-start-the-application`). The views we'll try are as follows:
- Visiting ``http://localhost:6543/`` in a browser invokes the ``view_wiki``
view. This always redirects to the ``view_page`` view of the ``FrontPage``
diff --git a/docs/tutorials/wiki/design.rst b/docs/tutorials/wiki/design.rst
new file mode 100644
index 000000000..ea7076f60
--- /dev/null
+++ b/docs/tutorials/wiki/design.rst
@@ -0,0 +1,134 @@
+==========
+Design
+==========
+
+Following is a quick overview of our wiki application, to help
+us understand the changes that we will be doing next in our
+default files generated by the paster scafffold.
+
+Overall
+-------
+
+We choose to use ``reStructuredText`` markup in the wiki text.
+Translation from reStructuredText to HTML is provided by the
+widely used docutils Python module. We will add this module
+in the dependency list on the project ``setup.py`` file.
+
+Models
+------
+
+The root resource, named *Wiki*, will be a mapping of wiki page
+names to page resources. The page resources will be instances
+of a *Page* class and they store the text content.
+
+URLs like ``/PageName`` will be traversed using Wiki[
+*PageName* ] => page, and the context that results is the page
+resource of an existing page.
+
+To add a page to the wiki, a new instance of the page resource
+is created and its name and reference are added to the Wiki
+mapping.
+
+A page named *FrontPage* containing the text *This is the front
+page*, will be created when the storage is initialized, and will
+be used as the wiki home page.
+
+Views
+-----
+
+There will be four views to handle the normal operations of
+viewing, editing and adding wiki pages. Two additional views
+will handle the login and logout tasks related to security.
+
+Security
+--------
+
+- USERS, a dictionary mapping users names to their
+ corresponding passwords.
+- GROUPS, a dictionary mapping user names to a
+ list of groups they belong to.
+- *groupfinder*, an *authorization callback* that looks up
+ USERS and GROUPS. It will be provided in a new
+ *security.py* file.
+- An :term:`ACL` is attached to the root resource. Each
+ row below details an :term:`ACE`:
+
+ +----------+----------------+----------------+
+ | Action | Principal | Permission |
+ +==========+================+================+
+ | Allow | Everyone | View |
+ +----------+----------------+----------------+
+ | Allow | group:editors | Edit |
+ +----------+----------------+----------------+
+
+- Permission declarations for the views.
+
+
+Summary
+-------
+
+The URL, context, actions, template and permission associated to each view are
+listed in the following table:
+
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| URL | View | Context | Action | Template | Permission |
+| | | | | | |
++======================+=============+=================+=======================+============+============+
+| / | view_wiki | Wiki | Redirect to | | |
+| | | | /FrontPage | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| /PageName | view_page | Page | Display existing | view.pt | view |
+| | [1]_ | | page [2]_ | | |
+| | | | | | |
+| | | | | | |
+| | | | | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| /PageName/edit_page | edit_page | Page | Display edit form | edit.pt | edit |
+| | | | with existing | | |
+| | | | content. | | |
+| | | | | | |
+| | | | If the form was | | |
+| | | | submitted, redirect | | |
+| | | | to /PageName | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| /add_page/PageName | add_page | Wiki | Create the page | edit.pt | edit |
+| | | | *PageName* in | | |
+| | | | storage, display | | |
+| | | | the edit form | | |
+| | | | without content. | | |
+| | | | | | |
+| | | | If the form was | | |
+| | | | submitted, | | |
+| | | | redirect to | | |
+| | | | /PageName | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| /login | login | Wiki, | Display login form. | login.pt | |
+| | | Forbidden [3]_ | | | |
+| | | | If the form was | | |
+| | | | submitted, | | |
+| | | | authenticate. | | |
+| | | | | | |
+| | | | - If authentication | | |
+| | | | successful, | | |
+| | | | redirect to the | | |
+| | | | page that we | | |
+| | | | came from. | | |
+| | | | | | |
+| | | | - If authentication | | |
+| | | | fails, display | | |
+| | | | login form with | | |
+| | | | "login failed" | | |
+| | | | message. | | |
+| | | | | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| /logout | logout | Wiki | Redirect to | | |
+| | | | /FrontPage | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+
+.. [1] This is the default view for a Page context
+ when there is no view name.
+.. [2] Pyramid will return a default 404 Not Found page
+ if the page *PageName* does not exist yet.
+.. [3] pyramid.exceptions.Forbidden is reached when a
+ user tries to invoke a view that is
+ not authorized by the authorization policy.
diff --git a/docs/tutorials/wiki/index.rst b/docs/tutorials/wiki/index.rst
index 3edc6ba04..f07f45bd0 100644
--- a/docs/tutorials/wiki/index.rst
+++ b/docs/tutorials/wiki/index.rst
@@ -18,6 +18,7 @@ tutorial can be browsed at
:maxdepth: 2
background
+ design
installation
basiclayout
definingmodels
diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst
index 330b17c86..63b30da5a 100644
--- a/docs/tutorials/wiki/installation.rst
+++ b/docs/tutorials/wiki/installation.rst
@@ -228,6 +228,8 @@ Looks like the code in the ``zodb`` scaffold for ZODB projects is
missing some test coverage, particularly in the file named
``models.py``.
+.. _wiki-start-the-application:
+
Start the Application
=====================
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index e4200ae0f..0fca0edf9 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -16,8 +16,10 @@ Application Configuration with ``__init__.py``
A directory on disk can be turned into a Python :term:`package` by containing
an ``__init__.py`` file. Even if empty, this marks a directory as a Python
package. We use ``__init__.py`` both as a marker indicating the directory
-it's contained within is a package, and to contain configuration code. Our
-``__init__.py`` file will look like this:
+it's contained within is a package, and to contain configuration code.
+
+Open ``tutorial/tutorial/__init__.py``. It should already contain
+the following:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
:linenos:
@@ -41,9 +43,7 @@ the ``main`` function we've defined in our ``__init__.py``:
When you invoke the ``pserve development.ini`` command, the ``main`` function
above is executed. It accepts some settings and returns a :term:`WSGI`
-application. You can read :ref:`startup_chapter` for details about *how*
-this function is found and called when you run ``pserve``, but for purposes
-of brevity, we'll elide the details here.
+application. (See :ref:`startup_chapter` for more about ``pserve``.)
The main function first creates a SQLAlchemy database engine using
``engine_from_config`` from the ``sqlalchemy.`` prefixed settings in the
@@ -128,30 +128,27 @@ pattern matches is done by registering a :term:`view configuration`. Our
application uses the :meth:`pyramid.view.view_config` decorator to map view
callables to each route, thereby mapping URL patterns to code.
-Here is the entirety of code in the ``views.py`` file within our package:
+Open ``tutorial/tutorial/views.py``. It should already contain the following:
.. literalinclude:: src/basiclayout/tutorial/views.py
:linenos:
:language: py
-The important part to point out here is the ``@view_config`` decorator which
-sits atop the ``my_view`` function. In fact, ``@view_config`` is so
-important that we're going to ignore the rest of the code in the module at
-this point just to explain it. The ``@view_config`` decorator associates the
-function it decorates with a :term:`view configuration`. The view
-configuration names a ``route_name`` (``home``), and names a ``renderer``,
-which is a template which lives in the ``templates`` subdirectory of the
-package.
+The important part here is that the ``@view_config`` decorator associates the
+function it decorates (``my_view``) with a :term:`view configuration`,
+consisting of:
+
+ * a ``route_name`` (``home``)
+ * a ``renderer``, which is a template from the ``templates`` subdirectory
+ of the package.
-As the result of this view configuration, when the pattern associated with
-the view named ``home`` is matched during a request, the function named
-``my_view`` will be executed. The function named ``my_view`` returns a
-dictionary; the renderer will use the ``templates/mytemplate.pt`` template to
-create a response based on the values in the dictionary.
+When the pattern associated with the ``home`` view is matched during a request,
+``my_view()`` will be executed. ``my_view()`` returns a dictionary; the
+renderer will use the ``templates/mytemplate.pt`` template to create a response
+based on the values in the dictionary.
-Note that the decorated function named ``my_view`` accepts a single argument
-named ``request``. This is the standard call signature for a Pyramid
-:term:`view callable`.
+Note that ``my_view()`` accepts a single argument named ``request``. This is
+the standard call signature for a Pyramid :term:`view callable`.
Remember in our ``__init__.py`` when we executed the
:meth:`pyramid.config.Configurator.scan` method, e.g. ``config.scan()``? The
@@ -168,13 +165,13 @@ In a SQLAlchemy-based application, a *model* object is an object composed by
querying the SQL database. The ``models.py`` file is where the ``alchemy``
scaffold put the classes that implement our models.
-Here is the complete source for ``models.py``:
+Open ``tutorial/tutorial/models.py``. It should already contain the following:
.. literalinclude:: src/basiclayout/tutorial/models.py
:linenos:
:language: py
-Let's take a look. First, we need some imports to support later code.
+Let's examine this in detail. First, we need some imports to support later code:
.. literalinclude:: src/basiclayout/tutorial/models.py
:end-before: DBSession
diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst
index 2b8932a98..ca0493f32 100644
--- a/docs/tutorials/wiki2/definingmodels.rst
+++ b/docs/tutorials/wiki2/definingmodels.rst
@@ -21,11 +21,15 @@ Making Edits to ``models.py``
(or they may live in a Python subpackage of your application package named
``models``) , but this is only by convention.
-Here's what our ``models.py`` file should look like after this step:
+Open ``tutorial/tutorial/models.py`` file and edit it to look like the
+following:
.. literalinclude:: src/models/tutorial/models.py
:linenos:
:language: py
+ :emphasize-lines: 19-21,24,26,28
+
+(The highlighted lines are the ones that need to be changed.)
The first thing we've done is to do is remove the stock ``MyModel`` class
from the generated ``models.py`` file. The ``MyModel`` class is only a
@@ -122,7 +126,8 @@ Viewing the Application in a Browser
We can't. At this point, our system is in a "non-runnable" state; we'll need
to change view-related files in the next chapter to be able to start the
-application successfully. If you try to start the application, you'll wind
+application successfully. If you try to start the application (See
+:ref:`wiki2-start-the-application`), you'll wind
up with a Python traceback on your console that ends with this exception:
.. code-block:: text
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index a067dbd66..592b183a4 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -323,7 +323,8 @@ something like so:
Viewing the Application in a Browser
====================================
-We can finally examine our application in a browser. The views we'll try are
+We can finally examine our application in a browser (See
+:ref:`wiki2-start-the-application`). The views we'll try are
as follows:
- Visiting ``http://localhost:6543`` in a browser invokes the
diff --git a/docs/tutorials/wiki2/design.rst b/docs/tutorials/wiki2/design.rst
new file mode 100644
index 000000000..ade40ab18
--- /dev/null
+++ b/docs/tutorials/wiki2/design.rst
@@ -0,0 +1,132 @@
+==========
+Design
+==========
+
+Following is a quick overview of our wiki application, to help
+us understand the changes that we will be doing next in our
+default files generated by the paster scafffold.
+
+Overall
+-------
+
+We choose to use ``reStructuredText`` markup in the wiki text.
+Translation from reStructuredText to HTML is provided by the
+widely used docutils Python module. We will add this module
+in the dependency list on the project ``setup.py`` file.
+
+Models
+------
+
+We define a single table named `tables`, whose elements will
+store the wiki pages. There are two columns: `name` and
+`data`.
+
+URLs like ``/PageName`` will try to find an element in
+the table whose `name` corresponds.
+
+To add a page to the wiki, a new row is created and the text
+is stored in `data`.
+
+A page named *FrontPage* containing the text *This is the front
+page*, will be created when the storage is initialized, and will
+be used as the wiki home page.
+
+Views
+-----
+
+There will be four views to handle the normal operations of
+viewing, editing and adding wiki pages. Two additional views
+will handle the login and logout tasks related to security.
+
+Security
+--------
+
+- USERS, a dictionary mapping users names to their
+ corresponding passwords.
+- GROUPS, a dictionary mapping user names to a
+ list of groups they belong to.
+- *groupfinder*, an *authorization callback* that looks up
+ USERS and GROUPS. It will be provided in a new
+ *security.py* file.
+- An :term:`ACL` is attached to the root resource. Each
+ row below details an :term:`ACE`:
+
+ +----------+----------------+----------------+
+ | Action | Principal | Permission |
+ +==========+================+================+
+ | Allow | Everyone | View |
+ +----------+----------------+----------------+
+ | Allow | group:editors | Edit |
+ +----------+----------------+----------------+
+
+- Permission declarations for the views.
+
+
+Summary
+-------
+
+The URL, context, actions, template and permission associated to each view are
+listed in the following table:
+
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| URL | View | Context | Action | Template | Permission |
+| | | | | | |
++======================+=============+=================+=======================+============+============+
+| / | view_wiki | Wiki | Redirect to | | |
+| | | | /FrontPage | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| /PageName | view_page | Page | Display existing | view.pt | view |
+| | [1]_ | | page [2]_ | | |
+| | | | | | |
+| | | | | | |
+| | | | | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| /edit_page/PageName | edit_page | Page | Display edit form | edit.pt | edit |
+| | | | with existing | | |
+| | | | content. | | |
+| | | | | | |
+| | | | If the form was | | |
+| | | | submitted, redirect | | |
+| | | | to /PageName | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| /add_page/PageName | add_page | Wiki | Create the page | edit.pt | edit |
+| | | | *PageName* in | | |
+| | | | storage, display | | |
+| | | | the edit form | | |
+| | | | without content. | | |
+| | | | | | |
+| | | | If the form was | | |
+| | | | submitted, | | |
+| | | | redirect to | | |
+| | | | /PageName | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| /login | login | Wiki, | Display login form. | login.pt | |
+| | | Forbidden [3]_ | | | |
+| | | | If the form was | | |
+| | | | submitted, | | |
+| | | | authenticate. | | |
+| | | | | | |
+| | | | - If authentication | | |
+| | | | successful, | | |
+| | | | redirect to the | | |
+| | | | page that we | | |
+| | | | came from. | | |
+| | | | | | |
+| | | | - If authentication | | |
+| | | | fails, display | | |
+| | | | login form with | | |
+| | | | "login failed" | | |
+| | | | message. | | |
+| | | | | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+| /logout | logout | Wiki | Redirect to | | |
+| | | | /FrontPage | | |
++----------------------+-------------+-----------------+-----------------------+------------+------------+
+
+.. [1] This is the default view for a Page context
+ when there is no view name.
+.. [2] Pyramid will return a default 404 Not Found page
+ if the page *PageName* does not exist yet.
+.. [3] pyramid.exceptions.Forbidden is reached when a
+ user tries to invoke a view that is
+ not authorized by the authorization policy.
diff --git a/docs/tutorials/wiki2/index.rst b/docs/tutorials/wiki2/index.rst
index d05d70f3c..3a165291a 100644
--- a/docs/tutorials/wiki2/index.rst
+++ b/docs/tutorials/wiki2/index.rst
@@ -18,6 +18,7 @@ tutorial can be browsed at
:maxdepth: 2
background
+ design
installation
basiclayout
definingmodels
diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst
index be97f1cb3..e5d2a0b5b 100644
--- a/docs/tutorials/wiki2/installation.rst
+++ b/docs/tutorials/wiki2/installation.rst
@@ -215,6 +215,8 @@ If successful, you will see output something like this::
Looks like our package doesn't quite have 100% test coverage.
+.. _wiki2-start-the-application:
+
Starting the Application
========================
diff --git a/pyramid/config/views.py b/pyramid/config/views.py
index 0f70c604f..432db79cf 100644
--- a/pyramid/config/views.py
+++ b/pyramid/config/views.py
@@ -139,7 +139,19 @@ class ViewDeriver(object):
self.http_cached_view(
self.decorated_view(
self.rendered_view(
- self.mapped_view(view)))))))))
+ self.mapped_view(
+ self.text_wrapped_view(
+ view))))))))))
+
+ @wraps_view
+ def text_wrapped_view(self, view):
+ # if the method is an instance method, we need to wrap it in order
+ # to be able to assign a __text__ value to it later. see #461.
+ if inspect.ismethod(view):
+ def text_wrapper(context, request):
+ return view(context, request)
+ return text_wrapper
+ return view
@wraps_view
def mapped_view(self, view):
diff --git a/pyramid/testing.py b/pyramid/testing.py
index d32a7fe0b..40e90cda6 100644
--- a/pyramid/testing.py
+++ b/pyramid/testing.py
@@ -632,7 +632,7 @@ class DummySession(dict):
return storage
def new_csrf_token(self):
- token = 'csrft'
+ token = '0123456789012345678901234567890123456789'
self['_csrft_'] = token
return token
diff --git a/pyramid/tests/test_config/test_init.py b/pyramid/tests/test_config/test_init.py
index da331e5ee..37c3de275 100644
--- a/pyramid/tests/test_config/test_init.py
+++ b/pyramid/tests/test_config/test_init.py
@@ -1,4 +1,5 @@
import unittest
+import warnings
import os
@@ -545,39 +546,33 @@ class ConfiguratorTests(unittest.TestCase):
self.assertEqual(utility, pyramid.tests.test_config)
def test_setup_registry_renderer_globals_factory(self):
- import warnings
- warnings.filterwarnings('ignore')
- try:
- from pyramid.registry import Registry
- from pyramid.interfaces import IRendererGlobalsFactory
- reg = Registry()
- config = self._makeOne(reg)
- factory = object()
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRendererGlobalsFactory
+ reg = Registry()
+ config = self._makeOne(reg)
+ factory = object()
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore')
config.setup_registry(renderer_globals_factory=factory)
- self.assertEqual(reg.queryUtility(IRendererGlobalsFactory), None)
- config.commit()
- utility = reg.getUtility(IRendererGlobalsFactory)
- self.assertEqual(utility, factory)
- finally:
- warnings.resetwarnings()
+ self.assertEqual(reg.queryUtility(IRendererGlobalsFactory), None)
+ config.commit()
+ utility = reg.getUtility(IRendererGlobalsFactory)
+ self.assertEqual(utility, factory)
def test_setup_registry_renderer_globals_factory_dottedname(self):
- import warnings
- warnings.filterwarnings('ignore')
- try:
- from pyramid.registry import Registry
- from pyramid.interfaces import IRendererGlobalsFactory
- reg = Registry()
- config = self._makeOne(reg)
- import pyramid.tests.test_config
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRendererGlobalsFactory
+ reg = Registry()
+ config = self._makeOne(reg)
+ import pyramid.tests.test_config
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore')
config.setup_registry(
renderer_globals_factory='pyramid.tests.test_config')
- self.assertEqual(reg.queryUtility(IRendererGlobalsFactory), None)
- config.commit()
- utility = reg.getUtility(IRendererGlobalsFactory)
- self.assertEqual(utility, pyramid.tests.test_config)
- finally:
- warnings.resetwarnings()
+ self.assertEqual(reg.queryUtility(IRendererGlobalsFactory), None)
+ config.commit()
+ utility = reg.getUtility(IRendererGlobalsFactory)
+ self.assertEqual(utility, pyramid.tests.test_config)
def test_setup_registry_alternate_renderers(self):
from pyramid.registry import Registry
@@ -1182,13 +1177,14 @@ pyramid.tests.test_config.dummy_include2""",
self.assertTrue(getattr(foo_meth, im_func) is foo)
class TestConfiguratorDeprecatedFeatures(unittest.TestCase):
+
def setUp(self):
- import warnings
+ self.warnings = warnings.catch_warnings()
+ self.warnings.__enter__()
warnings.filterwarnings('ignore')
def tearDown(self):
- import warnings
- warnings.resetwarnings()
+ self.warnings.__exit__(None, None, None)
def _makeOne(self, *arg, **kw):
from pyramid.config import Configurator
diff --git a/pyramid/tests/test_config/test_rendering.py b/pyramid/tests/test_config/test_rendering.py
index 655735511..e6ee9ad70 100644
--- a/pyramid/tests/test_config/test_rendering.py
+++ b/pyramid/tests/test_config/test_rendering.py
@@ -1,4 +1,5 @@
import unittest
+import warnings
from pyramid.tests.test_config import dummyfactory
@@ -9,32 +10,26 @@ class TestRenderingConfiguratorMixin(unittest.TestCase):
return config
def test_set_renderer_globals_factory(self):
- import warnings
- warnings.filterwarnings('ignore')
- try:
- from pyramid.interfaces import IRendererGlobalsFactory
- config = self._makeOne(autocommit=True)
- factory = object()
+ from pyramid.interfaces import IRendererGlobalsFactory
+ config = self._makeOne(autocommit=True)
+ factory = object()
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore')
config.set_renderer_globals_factory(factory)
- self.assertEqual(
- config.registry.getUtility(IRendererGlobalsFactory),
- factory)
- finally:
- warnings.resetwarnings()
+ self.assertEqual(
+ config.registry.getUtility(IRendererGlobalsFactory),
+ factory)
def test_set_renderer_globals_factory_dottedname(self):
- import warnings
- warnings.filterwarnings('ignore')
- try:
- from pyramid.interfaces import IRendererGlobalsFactory
- config = self._makeOne(autocommit=True)
+ from pyramid.interfaces import IRendererGlobalsFactory
+ config = self._makeOne(autocommit=True)
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore')
config.set_renderer_globals_factory(
'pyramid.tests.test_config.dummyfactory')
- self.assertEqual(
- config.registry.getUtility(IRendererGlobalsFactory),
- dummyfactory)
- finally:
- warnings.resetwarnings()
+ self.assertEqual(
+ config.registry.getUtility(IRendererGlobalsFactory),
+ dummyfactory)
def test_add_renderer(self):
from pyramid.interfaces import IRendererFactory
diff --git a/pyramid/tests/test_config/test_settings.py b/pyramid/tests/test_config/test_settings.py
index 8a385b8ab..0f5239915 100644
--- a/pyramid/tests/test_config/test_settings.py
+++ b/pyramid/tests/test_config/test_settings.py
@@ -48,20 +48,6 @@ class TestSettingsConfiguratorMixin(unittest.TestCase):
self.assertEqual(settings['a'], 1)
class TestSettings(unittest.TestCase):
- def setUp(self):
- self.warnings = []
- import warnings
- warnings.old_showwarning = warnings.showwarning
- warnings.showwarning = self._showwarning
-
- def tearDown(self):
- del self.warnings
- import warnings
- warnings.showwarning = warnings.old_showwarning
-
- def _showwarning(self, message, category, filename, lineno, file=None,
- line=None):
- self.warnings.append(message)
def _getTargetClass(self):
from pyramid.config.settings import Settings
@@ -74,14 +60,20 @@ class TestSettings(unittest.TestCase):
return klass(d, _environ_=environ)
def test_getattr_success(self):
- settings = self._makeOne({'reload_templates':False})
- self.assertEqual(settings.reload_templates, False)
- self.assertEqual(len(self.warnings), 1)
+ import warnings
+ with warnings.catch_warnings(record=True) as w:
+ warnings.filterwarnings('always')
+ settings = self._makeOne({'reload_templates':False})
+ self.assertEqual(settings.reload_templates, False)
+ self.assertEqual(len(w), 1)
def test_getattr_fail(self):
- settings = self._makeOne({})
- self.assertRaises(AttributeError, settings.__getattr__, 'wontexist')
- self.assertEqual(len(self.warnings), 0)
+ import warnings
+ with warnings.catch_warnings(record=True) as w:
+ warnings.filterwarnings('always')
+ settings = self._makeOne({})
+ self.assertRaises(AttributeError, settings.__getattr__, 'wontexist')
+ self.assertEqual(len(w), 0)
def test_getattr_raises_attribute_error(self):
settings = self._makeOne()
diff --git a/pyramid/tests/test_config/test_views.py b/pyramid/tests/test_config/test_views.py
index 7bfe174b7..8877c011e 100644
--- a/pyramid/tests/test_config/test_views.py
+++ b/pyramid/tests/test_config/test_views.py
@@ -218,6 +218,18 @@ class TestViewsConfigurationMixin(unittest.TestCase):
result = wrapper(None, None)
self.assertEqual(result, 'OK')
+ def test_add_view_as_instancemethod(self):
+ from pyramid.renderers import null_renderer
+ class View:
+ def index(self, context, request):
+ return 'OK'
+ view = View()
+ config=self._makeOne(autocommit=True)
+ config.add_view(view=view.index, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
def test_add_view_as_instance_requestonly(self):
from pyramid.renderers import null_renderer
class AView: