diff options
| -rw-r--r-- | CHANGES.txt | 9 | ||||
| -rw-r--r-- | docs/tutorials/wiki/definingmodels.rst | 3 | ||||
| -rw-r--r-- | docs/tutorials/wiki/definingviews.rst | 4 | ||||
| -rw-r--r-- | docs/tutorials/wiki/design.rst | 134 | ||||
| -rw-r--r-- | docs/tutorials/wiki/index.rst | 1 | ||||
| -rw-r--r-- | docs/tutorials/wiki/installation.rst | 2 | ||||
| -rw-r--r-- | docs/tutorials/wiki2/basiclayout.rst | 45 | ||||
| -rw-r--r-- | docs/tutorials/wiki2/definingmodels.rst | 9 | ||||
| -rw-r--r-- | docs/tutorials/wiki2/definingviews.rst | 3 | ||||
| -rw-r--r-- | docs/tutorials/wiki2/design.rst | 132 | ||||
| -rw-r--r-- | docs/tutorials/wiki2/index.rst | 1 | ||||
| -rw-r--r-- | docs/tutorials/wiki2/installation.rst | 2 | ||||
| -rw-r--r-- | pyramid/config/views.py | 14 | ||||
| -rw-r--r-- | pyramid/testing.py | 2 | ||||
| -rw-r--r-- | pyramid/tests/test_config/test_init.py | 58 | ||||
| -rw-r--r-- | pyramid/tests/test_config/test_rendering.py | 37 | ||||
| -rw-r--r-- | pyramid/tests/test_config/test_settings.py | 32 | ||||
| -rw-r--r-- | pyramid/tests/test_config/test_views.py | 12 |
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: |
