diff options
| author | Chris McDonough <chrism@plope.com> | 2011-01-16 01:32:43 -0500 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2011-01-16 01:32:43 -0500 |
| commit | 659d5f6b1f7605daaa0666fab7061bba9848d241 (patch) | |
| tree | 4de47bbc52737bc717cd515806c48a57b5bb2bcb | |
| parent | fe847fad6768c9a7f2cb1b61d88164a370f6b2db (diff) | |
| parent | da358e42a1dda347f04d9331bb1e43f065546133 (diff) | |
| download | pyramid-659d5f6b1f7605daaa0666fab7061bba9848d241.tar.gz pyramid-659d5f6b1f7605daaa0666fab7061bba9848d241.tar.bz2 pyramid-659d5f6b1f7605daaa0666fab7061bba9848d241.zip | |
Merge branch 'gawel-config_extend'
| -rw-r--r-- | docs/api/config.rst | 2 | ||||
| -rw-r--r-- | pyramid/config.py | 28 | ||||
| -rw-r--r-- | pyramid/tests/__init__.py | 4 | ||||
| -rw-r--r-- | pyramid/tests/test_config.py | 83 |
4 files changed, 116 insertions, 1 deletions
diff --git a/docs/api/config.rst b/docs/api/config.rst index 3f37e739c..51666f53f 100644 --- a/docs/api/config.rst +++ b/docs/api/config.rst @@ -76,6 +76,8 @@ .. automethod:: set_renderer_globals_factory + .. automethod:: add_directive + .. automethod:: testing_securitypolicy .. automethod:: testing_resources diff --git a/pyramid/config.py b/pyramid/config.py index 9604833f3..b144b8fe3 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -2,6 +2,7 @@ import inspect import os import re import sys +import types import threading import traceback @@ -302,6 +303,9 @@ class Configurator(object): session_factory=session_factory, default_view_mapper=default_view_mapper, ) + if hasattr(registry, '_directives'): + for name, directive in registry._directives.items(): + self.add_directive(name, directive) def _set_settings(self, mapping): settings = Settings(mapping or {}) @@ -558,6 +562,30 @@ class Configurator(object): config = self.__class__.with_context(context) c(config) + def add_directive(self, name, directive): + """ + Add a directive method to the configurator. + + Framework extenders can add directive methods to a configurator by + instructing their users to call ``config.add_directive('somename', + 'some.callable')``. This will make ``some.callable`` accessible as + ``config.somename``. ``some.callable`` should be a function which + accepts ``config`` as a first argument, and arbitrary positional and + keyword arguments following. It should use config.action as + necessary to perform actions. Directive methods can then be invoked + like 'built-in' directives such as ``add_view``, ``add_route``, etc. + + ``add_directive`` does not participate in conflict detection, and + later calls to ``add_directive`` will override earlier calls. + """ + c = self.maybe_dotted(directive) + if not hasattr(self.registry, '_directives'): + self.registry._directives = {} + self.registry._directives[name] = c + c = action_method(c) + m = types.MethodType(c, self, self.__class__) + setattr(self, name, m) + @classmethod def with_context(cls, context): """A classmethod used by ZCML directives, diff --git a/pyramid/tests/__init__.py b/pyramid/tests/__init__.py index 5bb534f79..a62c29f47 100644 --- a/pyramid/tests/__init__.py +++ b/pyramid/tests/__init__.py @@ -1 +1,3 @@ -# package + +def dummy_extend(*args): + """used to test Configurator.extend""" diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py index ac459d7e3..61a665f5a 100644 --- a/pyramid/tests/test_config.py +++ b/pyramid/tests/test_config.py @@ -3216,6 +3216,83 @@ class ConfiguratorTests(unittest.TestCase): for confinst in conflict: yield confinst[2] +class TestConfigurator_add_directive(unittest.TestCase): + + def setUp(self): + from pyramid.config import Configurator + self.config = Configurator() + + def test_extend_with_dotted_name(self): + from pyramid import tests + config = self.config + config.add_directive( + 'dummy_extend', 'pyramid.tests.test_config.dummy_extend') + self.assert_(hasattr(config, 'dummy_extend')) + config.dummy_extend('discrim') + context_after = config._ctx + actions = context_after.actions + self.assertEqual(len(actions), 1) + self.assertEqual( + context_after.actions[0][:3], + ('discrim', None, tests), + ) + + def test_extend_with_python_callable(self): + from pyramid import tests + config = self.config + config.add_directive( + 'dummy_extend', dummy_extend) + self.assert_(hasattr(config, 'dummy_extend')) + config.dummy_extend('discrim') + context_after = config._ctx + actions = context_after.actions + self.assertEqual(len(actions), 1) + self.assertEqual( + context_after.actions[0][:3], + ('discrim', None, tests), + ) + + def test_extend_same_name_doesnt_conflict(self): + config = self.config + config.add_directive( + 'dummy_extend', dummy_extend) + config.add_directive( + 'dummy_extend', dummy_extend2) + self.assert_(hasattr(config, 'dummy_extend')) + config.dummy_extend('discrim') + context_after = config._ctx + actions = context_after.actions + self.assertEqual(len(actions), 1) + self.assertEqual( + context_after.actions[0][:3], + ('discrim', None, config.registry), + ) + + def test_extend_action_method_successful(self): + from zope.configuration.config import ConfigurationConflictError + config = self.config + config.add_directive( + 'dummy_extend', dummy_extend) + config.dummy_extend('discrim') + config.dummy_extend('discrim') + self.assertRaises(ConfigurationConflictError, config.commit) + + def test_directive_persists_across_configurator_creations(self): + from zope.configuration.config import GroupingContextDecorator + config = self.config + config.add_directive('dummy_extend', dummy_extend) + context = config._make_context(autocommit=False) + context = GroupingContextDecorator(context) + config2 = config.with_context(context) + config2.dummy_extend('discrim') + context_after = config2._ctx + actions = context_after.actions + self.assertEqual(len(actions), 1) + self.assertEqual( + context_after.actions[0][:3], + ('discrim', None, config2.package), + ) + class TestViewDeriver(unittest.TestCase): def setUp(self): self.config = testing.setUp() @@ -4943,4 +5020,10 @@ class DummyHandler(object): # pragma: no cover def dummy_include(config): config.action('discrim', None, config.package) + +def dummy_extend(config, discrim): + config.action(discrim, None, config.package) + +def dummy_extend2(config, discrim): + config.action(discrim, None, config.registry) |
