From 3c58b3041b2312c6f4429f54458a49b0eaee57ea Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 4 Dec 2010 02:48:04 -0500 Subject: add include method --- pyramid/configuration.py | 60 ++++++++++++++++++++++++++++++------- pyramid/tests/test_configuration.py | 37 +++++++++++++++++++++++ pyramid/tests/test_zcml.py | 3 +- 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/pyramid/configuration.py b/pyramid/configuration.py index d2d2fb73c..a8f343dfd 100644 --- a/pyramid/configuration.py +++ b/pyramid/configuration.py @@ -1,14 +1,16 @@ +import inspect import os import re import sys import threading -import inspect import venusian from translationstring import ChameleonTranslate from zope.configuration import xmlconfig +from zope.configuration.config import GroupingContextDecorator +from zope.configuration.config import GroupingStackItem from zope.interface import Interface from zope.interface import implementedBy @@ -98,15 +100,15 @@ if chameleon_text: if chameleon_zpt: DEFAULT_RENDERERS += (('.txt', chameleon_text.renderer_factory),) -def config_method(wrapped): - def wrapper(self, *arg, **kw): - result = wrapped(self, *arg, **kw) - if self.registry.autocommit: - self.commit() - return result - wrapper.__doc__ = wrapped.__doc__ - wrapper.__name__ = wrapped.__name__ - return wrapper +## def config_method(wrapped): +## def wrapper(self, *arg, **kw): +## result = wrapped(self, *arg, **kw) +## if self.registry.autocommit: +## self.commit() +## return result +## wrapper.__doc__ = wrapped.__doc__ +## wrapper.__name__ = wrapped.__name__ +## return wrapper class Configurator(object): """ @@ -708,6 +710,42 @@ class Configurator(object): self.manager.pop() return registry + def include(self, *funcs): + """ Include one or more configuration callables. A configuration + callable should be a callable that accepts a single argument named + ``config``, which will be an instance of a :term:`Configurator`. (be + warned that it will not be the same configurator instance on which + you call this method, however). The code which runs as the result of + calling the callable should invoke methods on the configurator which + add configuration state. The return value of a callable will be + ignored. + + Values allowed to be presented via the ``*funcs`` argument to this + method: any callable Python object or any :term:`dotted Python name` + which resolves to a callable Python object. + """ + sourcefiles = [] + + for func in funcs: + func = self.maybe_dotted(func) + sourcefile = inspect.getsourcefile(func) + module = inspect.getmodule(func) + sourcefiles.append((sourcefile, func, module)) + + sourcefiles.sort() + + _context = self.registry.ctx + + for filename, func, module in sourcefiles: + context = GroupingContextDecorator(_context) + context.basepath = os.path.dirname(filename) + context.includepath = _context.includepath + (filename,) + self.registry.ctx = context + try: + func(self.with_package(module)) + finally: + self.registry.ctx = _context + def add_handler(self, route_name, pattern, handler, action=None, **kw): """ Add a Pylons-style view handler. This function adds a @@ -1674,6 +1712,8 @@ class Configurator(object): # as a name if not name: name = '' + # we need to register renderers eagerly because they are used during + # view configuration self.registry.registerUtility( factory, IRendererFactory, name=name, info=self.ctx_info()) self.action((IRendererFactory, name), None) diff --git a/pyramid/tests/test_configuration.py b/pyramid/tests/test_configuration.py index 9d6d98b0e..d8895e0fa 100644 --- a/pyramid/tests/test_configuration.py +++ b/pyramid/tests/test_configuration.py @@ -651,6 +651,40 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(dummylock.acquired, True) self.assertEqual(dummylock.released, True) + def test_include_with_dotted_name(self): + from pyramid import tests + import os + here = os.path.dirname(__file__) + fname = os.path.join(here, 'test_configuration.py') + config = self._makeOne() + context_before = config.registry.ctx + config.include('pyramid.tests.test_configuration.dummy_include') + context_after = config.registry.ctx + self.assertEqual( + context_after.actions, + [('discrim', None, tests, {},(fname,))] + ) + self.assertEqual(context_after.basepath, None) + self.assertEqual(context_after.includepath, ()) + self.failUnless(context_after is context_before) + + def test_include_with_python_callable(self): + from pyramid import tests + import os + here = os.path.dirname(__file__) + fname = os.path.join(here, 'test_configuration.py') + config = self._makeOne() + context_before = config.registry.ctx + config.include(dummy_include) + context_after = config.registry.ctx + self.assertEqual( + context_after.actions, + [('discrim', None, tests, {},(fname,))] + ) + self.assertEqual(context_after.basepath, None) + self.assertEqual(context_after.includepath, ()) + self.failUnless(context_after is context_before) + def test_add_view_view_callable_None_no_renderer(self): from pyramid.exceptions import ConfigurationError config = self._makeOne() @@ -4700,3 +4734,6 @@ class DummyHandler(object): # pragma: no cover def action2(self): return 'response 2' +def dummy_include(config): + config.action('discrim', None, config.package) + diff --git a/pyramid/tests/test_zcml.py b/pyramid/tests/test_zcml.py index fe2ec6522..95dd958b7 100644 --- a/pyramid/tests/test_zcml.py +++ b/pyramid/tests/test_zcml.py @@ -841,8 +841,7 @@ class TestZCMLScanDirective(unittest.TestCase): def test_it(self): dummy_module = DummyModule() - def foo(): - pass + def foo(): pass def bar(scanner, name, ob): dummy_module.scanned = True foo.__venusian_callbacks__ = {'pyramid':[bar]} -- cgit v1.2.3