summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-09-03 21:44:27 -0400
committerChris McDonough <chrism@plope.com>2011-09-03 21:44:27 -0400
commitb86fa95c850130e1b21b804f9fb87666a80dbe18 (patch)
treee1f270f128dc1369214eec702a47c1e974a01798
parent940ab0d43fd38588da3b5d7937e8787287b7c000 (diff)
downloadpyramid-b86fa95c850130e1b21b804f9fb87666a80dbe18.tar.gz
pyramid-b86fa95c850130e1b21b804f9fb87666a80dbe18.tar.bz2
pyramid-b86fa95c850130e1b21b804f9fb87666a80dbe18.zip
all tests pass; pyramid_zcml still broken with this branch
-rw-r--r--pyramid/config/__init__.py159
-rw-r--r--pyramid/tests/test_config/test_init.py179
-rw-r--r--pyramid/tests/test_config/test_routes.py2
3 files changed, 163 insertions, 177 deletions
diff --git a/pyramid/config/__init__.py b/pyramid/config/__init__.py
index a3cec37fe..067448c9a 100644
--- a/pyramid/config/__init__.py
+++ b/pyramid/config/__init__.py
@@ -205,8 +205,10 @@ class Configurator(
manager = manager # for testing injection
venusian = venusian # for testing injection
- _ctx = None
_ainfo = None
+ basepath = None
+ includepath = ()
+ info = ''
def __init__(self,
registry=None,
@@ -442,20 +444,14 @@ class Configurator(
if kw is None:
kw = {}
- context = self._ctx
-
- if context is None:
- autocommit = self.autocommit
- else:
- autocommit = context.autocommit
+ autocommit = self.autocommit
if autocommit:
if callable is not None:
callable(*args, **kw)
+
else:
- if context is None: # defer expensive creation of context
- context = self._ctx = self._make_context(self.autocommit)
- info = context.info
+ info = self.info
if not info:
# Try to provide more accurate info for conflict reports by
# wrapping the context in a decorator and attaching caller info
@@ -465,7 +461,29 @@ class Configurator(
info = self._ainfo[0]
else:
info = ''
- context.action(discriminator, callable, args, kw, order, info=info)
+ self.action_state.action(
+ discriminator,
+ callable,
+ args,
+ kw,
+ order,
+ info=info,
+ includepath=self.includepath,
+ )
+
+ def _get_action_state(self):
+ registry = self.registry
+ try:
+ state = registry.action_state
+ except AttributeError:
+ state = ActionState()
+ registry.action_state = state
+ return state
+
+ def _set_action_state(self, state):
+ self.registry.action_state = state
+
+ action_state = property(_get_action_state, _set_action_state)
def commit(self):
""" Commit any pending configuration actions. If a configuration
@@ -474,11 +492,8 @@ class Configurator(
of this error will be information about the source of the conflict,
usually including file names and line numbers of the cause of the
configuration conflicts."""
- if self._ctx is None:
- return
- self._ctx.execute_actions()
- # unwrap and reset the context
- self._ctx = None
+ self.action_state.execute_actions()
+ self.action_state = ActionState() # old actions have been processed
def include(self, callable, route_prefix=None):
"""Include a configuration callables, to support imperative
@@ -502,7 +517,7 @@ class Configurator(
Python :term:`module`, in which case, the module will be searched for
a callable named ``includeme``, which will be treated as the
configuration callable.
-
+
For example, if the ``includeme`` function below lives in a module
named ``myapp.myconfig``:
@@ -573,10 +588,9 @@ class Configurator(
The ``route_prefix`` parameter is new as of Pyramid 1.2.
"""
+ ## """ <-- emacs gets confused if this isn't here
- _context = self._ctx
- if _context is None:
- _context = self._ctx = self._make_context(self.autocommit)
+ action_state = self.action_state
if self.route_prefix:
old_prefix = self.route_prefix.rstrip('/') + '/'
@@ -592,15 +606,18 @@ class Configurator(
c = getattr(module, 'includeme')
spec = module.__name__ + ':' + c.__name__
sourcefile = inspect.getsourcefile(c)
- if _context.processSpec(spec):
- context = ActionStateWrapper(_context)
- context.basepath = os.path.dirname(sourcefile)
- context.includepath = _context.includepath + (spec,)
- context.package = package_of(module)
- context.route_prefix = route_prefix
- config = self.__class__.with_context(context)
- c(config)
+ if action_state.processSpec(spec):
+ configurator = self.__class__(
+ registry=self.registry,
+ package=package_of(module),
+ autocommit=self.autocommit,
+ route_prefix=route_prefix,
+ )
+ configurator.basepath = os.path.dirname(sourcefile)
+ configurator.includepath = self.includepath + (spec,)
+ c(configurator)
+
def add_directive(self, name, directive, action_wrap=True):
"""
Add a directive method to the configurator.
@@ -650,10 +667,15 @@ class Configurator(
:meth:`pyramid.config.Configurator.with_package`, and
:meth:`pyramid.config.Configurator.include` to obtain a configurator
with 'the right' context. Returns a new Configurator instance."""
- configurator = cls(registry=context.registry, package=context.package,
- autocommit=context.autocommit,
- route_prefix=context.route_prefix)
- configurator._ctx = context
+ configurator = cls(
+ registry=context.registry,
+ package=context.package,
+ autocommit=context.autocommit,
+ route_prefix=context.route_prefix
+ )
+ configurator.basepath = context.basepath
+ configurator.includepath = context.includepath
+ configurator.info = context.info
return configurator
def with_package(self, package):
@@ -662,12 +684,16 @@ class Configurator(
``package`` argument to the new configurator. ``package`` may
be an actual Python package object or a :term:`dotted Python name`
representing a package."""
- context = self._ctx
- if context is None:
- context = self._ctx = self._make_context(self.autocommit)
- context = ActionStateWrapper(context)
- context.package = package
- return self.__class__.with_context(context)
+ configurator = self.__class__(
+ registry=self.registry,
+ package=package,
+ autocommit=self.autocommit,
+ route_prefix=self.route_prefix,
+ )
+ configurator.basepath = self.basepath
+ configurator.includepath = self.includepath
+ configurator.info = self.info
+ return configurator
def maybe_dotted(self, dotted):
""" Resolve the :term:`dotted Python name` ``dotted`` to a
@@ -788,8 +814,9 @@ class Configurator(
return app
-class ActionStateBase(object):
+class ActionState(object):
def __init__(self):
+ self.actions = []
self._seen_files = set()
def processSpec(self, spec):
@@ -806,8 +833,8 @@ class ActionStateBase(object):
self._seen_files.add(spec)
return True
- def action(self, discriminator, callable=None, args=(), kw={}, order=0,
- includepath=None, info=None):
+ def action(self, discriminator, callable=None, args=(), kw=None, order=0,
+ includepath=(), info=''):
"""Add an action with the given discriminator, callable and arguments
For testing purposes, the callable and arguments may be omitted.
@@ -869,45 +896,14 @@ class ActionStateBase(object):
(None, None, (), {}, ('foo.zcml',), 'abc')
"""
- if info is None:
- info = getattr(self, 'info', '')
-
- if includepath is None:
- includepath = getattr(self, 'includepath', ())
-
+ if kw is None:
+ kw = {}
action = (discriminator, callable, args, kw, includepath, info, order)
-
# remove trailing false items
while (len(action) > 2) and not action[-1]:
action = action[:-1]
-
self.actions.append(action)
-
-class ActionStateWrapper(ActionStateBase):
- """ Wrap an action state.
- """
- def __init__(self, state):
- self.state = state
-
- def __getattr__(self, name):
- v = getattr(self.state, name)
- # cache result in self
- setattr(self, name, v)
- return v
-
-class ActionState(ActionStateBase):
- autocommit = False
- route_prefix = None
- package = None
- basepath = None
- includepath = ()
- info = ''
-
- def __init__(self):
- super(ActionState, self).__init__()
- self.actions = []
-
def execute_actions(self, clear=True):
"""Execute the configuration actions
@@ -959,8 +955,7 @@ class ActionState(ActionStateBase):
"""
try:
for action in resolveConflicts(self.actions):
- (discriminator, callable, args, kw, includepath, info, order
- ) = expand_action(*action)
+ _, callable, args, kw, _, info, _ = expand_action(*action)
if callable is None:
continue
try:
@@ -969,7 +964,10 @@ class ActionState(ActionStateBase):
raise
except:
t, v, tb = sys.exc_info()
- raise ConfigurationExecutionError(t, v, info), None, tb
+ try:
+ raise ConfigurationExecutionError(t, v, info), None, tb
+ finally:
+ del t, v, tb
finally:
if clear:
del self.actions[:]
@@ -1082,10 +1080,11 @@ def resolveConflicts(actions):
return r
-def expand_action(discriminator, callable=None, args=(), kw={},
+def expand_action(discriminator, callable=None, args=(), kw=None,
includepath=(), info='', order=0):
- return (discriminator, callable, args, kw,
- includepath, info, order)
+ if kw is None:
+ kw = {}
+ return (discriminator, callable, args, kw, includepath, info, order)
global_registries = WeakOrderedSet()
diff --git a/pyramid/tests/test_config/test_init.py b/pyramid/tests/test_config/test_init.py
index 0df96af40..9422f7dfe 100644
--- a/pyramid/tests/test_config/test_init.py
+++ b/pyramid/tests/test_config/test_init.py
@@ -243,23 +243,22 @@ class ConfiguratorTests(unittest.TestCase):
newconfig = config.with_package(pyramid.tests.test_config)
self.assertEqual(newconfig.package, pyramid.tests.test_config)
- def test_with_package_context_is_not_None(self):
- import pyramid.tests.test_config
- config = self._makeOne()
- config._ctx = DummyContext()
- config._ctx.registry = None
- config._ctx.autocommit = True
- config._ctx.route_prefix = None
- newconfig = config.with_package(pyramid.tests.test_config)
- self.assertEqual(newconfig.package, pyramid.tests.test_config)
-
- def test_with_package_context_is_None(self):
- import pyramid.tests.test_config
+ def test_with_package(self):
+ import pyramid.tests
config = self._makeOne()
- config._ctx = None
- newconfig = config.with_package(pyramid.tests.test_config)
- self.assertEqual(newconfig.package, pyramid.tests.test_config)
- self.assertEqual(config._ctx.package, None)
+ config.basepath = 'basepath'
+ config.info = 'info'
+ config.includepath = ('spec',)
+ config.autocommit = True
+ config.route_prefix = 'prefix'
+ newconfig = config.with_package(pyramid.tests)
+ self.assertEqual(newconfig.package, pyramid.tests)
+ self.assertEqual(newconfig.registry, config.registry)
+ self.assertEqual(newconfig.autocommit, True)
+ self.assertEqual(newconfig.route_prefix, 'prefix')
+ self.assertEqual(newconfig.info, 'info')
+ self.assertEqual(newconfig.basepath, 'basepath')
+ self.assertEqual(newconfig.includepath, ('spec',))
def test_maybe_dotted_string_success(self):
import pyramid.tests.test_config
@@ -659,53 +658,38 @@ pyramid.tests.test_config.dummy_include2""",
def test_include_with_dotted_name(self):
from pyramid.tests import test_config
config = self._makeOne()
- context_before = config._make_context()
- config._ctx = context_before
config.include('pyramid.tests.test_config.dummy_include')
- context_after = config._ctx
- actions = context_after.actions
+ after = config.action_state
+ actions = after.actions
self.assertEqual(len(actions), 1)
self.assertEqual(
- context_after.actions[0][:3],
+ after.actions[0][:3],
('discrim', None, test_config),
)
- self.assertEqual(context_after.basepath, None)
- self.assertEqual(context_after.includepath, ())
- self.assertTrue(context_after is context_before)
def test_include_with_python_callable(self):
from pyramid.tests import test_config
config = self._makeOne()
- context_before = config._make_context()
- config._ctx = context_before
config.include(dummy_include)
- context_after = config._ctx
- actions = context_after.actions
+ after = config.action_state
+ actions = after.actions
self.assertEqual(len(actions), 1)
self.assertEqual(
actions[0][:3],
('discrim', None, test_config),
)
- self.assertEqual(context_after.basepath, None)
- self.assertEqual(context_after.includepath, ())
- self.assertTrue(context_after is context_before)
def test_include_with_module_defaults_to_includeme(self):
from pyramid.tests import test_config
config = self._makeOne()
- context_before = config._make_context()
- config._ctx = context_before
config.include('pyramid.tests.test_config')
- context_after = config._ctx
- actions = context_after.actions
+ after = config.action_state
+ actions = after.actions
self.assertEqual(len(actions), 1)
self.assertEqual(
actions[0][:3],
('discrim', None, test_config),
)
- self.assertEqual(context_after.basepath, None)
- self.assertEqual(context_after.includepath, ())
- self.assertTrue(context_after is context_before)
def test_include_with_route_prefix(self):
root_config = self._makeOne(autocommit=True)
@@ -721,9 +705,22 @@ pyramid.tests.test_config.dummy_include2""",
def test_with_context(self):
config = self._makeOne()
- ctx = config._make_context()
- newconfig = config.with_context(ctx)
- self.assertEqual(newconfig._ctx, ctx)
+ context = DummyZCMLContext()
+ context.basepath = 'basepath'
+ context.includepath = ('spec',)
+ context.package = 'pyramid'
+ context.autocommit = True
+ context.registry = 'abc'
+ context.route_prefix = 'buz'
+ context.info = 'info'
+ newconfig = config.with_context(context)
+ self.assertEqual(newconfig.package_name, 'pyramid')
+ self.assertEqual(newconfig.autocommit, True)
+ self.assertEqual(newconfig.registry, 'abc')
+ self.assertEqual(newconfig.route_prefix, 'buz')
+ self.assertEqual(newconfig.basepath, 'basepath')
+ self.assertEqual(newconfig.includepath, ('spec',))
+ self.assertEqual(newconfig.info, 'info')
def test_action_branching_kw_is_None(self):
config = self._makeOne(autocommit=True)
@@ -733,29 +730,31 @@ pyramid.tests.test_config.dummy_include2""",
config = self._makeOne(autocommit=True)
self.assertEqual(config.action('discrim', kw={'a':1}), None)
- def test_action_branching_nonautocommit_with_context_info(self):
+ def test_action_branching_nonautocommit_with_config_info(self):
config = self._makeOne(autocommit=False)
+ config.info = 'abc'
state = DummyActionState()
state.autocommit = False
- state.info = 'abc'
- config._ctx = state
+ config.action_state = state
config.action('discrim', kw={'a':1})
self.assertEqual(
state.actions,
- [(('discrim', None, (), {'a': 1}, 0), {'info': 'abc'})]
+ [(('discrim', None, (), {'a': 1}, 0),
+ {'info': 'abc', 'includepath':()})]
)
- def test_action_branching_nonautocommit_without_context_info(self):
+ def test_action_branching_nonautocommit_without_config_info(self):
config = self._makeOne(autocommit=False)
+ config.info = ''
+ config._ainfo = ['z']
state = DummyActionState()
+ config.action_state = state
state.autocommit = False
- state.info = ''
- config._ctx = state
- config._ainfo = ['z']
config.action('discrim', kw={'a':1})
self.assertEqual(
state.actions,
- [(('discrim', None, (), {'a': 1}, 0), {'info': 'z'})]
+ [(('discrim', None, (), {'a': 1}, 0),
+ {'info': 'z', 'includepath':()})]
)
def test_scan_integration(self):
@@ -1301,9 +1300,9 @@ class TestConfigurator_add_directive(unittest.TestCase):
'dummy_extend', 'pyramid.tests.test_config.dummy_extend')
self.assert_(hasattr(config, 'dummy_extend'))
config.dummy_extend('discrim')
- context_after = config._ctx
+ after = config.action_state
self.assertEqual(
- context_after.actions[-1][:3],
+ after.actions[-1][:3],
('discrim', None, test_config),
)
@@ -1314,9 +1313,9 @@ class TestConfigurator_add_directive(unittest.TestCase):
'dummy_extend', dummy_extend)
self.assert_(hasattr(config, 'dummy_extend'))
config.dummy_extend('discrim')
- context_after = config._ctx
+ after = config.action_state
self.assertEqual(
- context_after.actions[-1][:3],
+ after.actions[-1][:3],
('discrim', None, test_config),
)
@@ -1328,9 +1327,9 @@ class TestConfigurator_add_directive(unittest.TestCase):
'dummy_extend', dummy_extend2)
self.assert_(hasattr(config, 'dummy_extend'))
config.dummy_extend('discrim')
- context_after = config._ctx
+ after = config.action_state
self.assertEqual(
- context_after.actions[-1][:3],
+ after.actions[-1][:3],
('discrim', None, config.registry),
)
@@ -1343,18 +1342,15 @@ class TestConfigurator_add_directive(unittest.TestCase):
self.assertRaises(ConfigurationConflictError, config.commit)
def test_directive_persists_across_configurator_creations(self):
- from pyramid.config import ActionStateWrapper
config = self.config
config.add_directive('dummy_extend', dummy_extend)
- context = config._make_context(autocommit=False)
- context = ActionStateWrapper(context)
- config2 = config.with_context(context)
+ config2 = config.with_package('pyramid.tests')
config2.dummy_extend('discrim')
- context_after = config2._ctx
- actions = context_after.actions
+ after = config2.action_state
+ actions = after.actions
self.assertEqual(len(actions), 1)
self.assertEqual(
- context_after.actions[0][:3],
+ after.actions[0][:3],
('discrim', None, config2.package),
)
@@ -1365,8 +1361,7 @@ class TestActionState(unittest.TestCase):
def test_it(self):
c = self._makeOne()
- self.assertEqual(c.autocommit, False)
- self.assertEqual(c.route_prefix, None)
+ self.assertEqual(c.actions, [])
def test_action_simple(self):
from pyramid.tests.test_config import dummyfactory as f
@@ -1377,32 +1372,28 @@ class TestActionState(unittest.TestCase):
c.action(None)
self.assertEqual(c.actions, [(1, f, (1,), {'x': 1}), (None, None)])
- def test_action_with_includepath_and_info(self):
+ def test_action_with_includepath(self):
c = self._makeOne()
c.actions = []
- c.includepath = ('foo.zcml',)
- c.info = '?'
- c.action(None)
- self.assertEqual(c.actions,
- [(None, None, (), {}, ('foo.zcml',), '?')])
+ c.action(None, includepath=('abc',))
+ self.assertEqual(c.actions, [(None, None, (), {}, ('abc',))])
- def test_action_with_order(self):
+ def test_action_with_info(self):
c = self._makeOne()
- c.actions = []
- c.action(None, order=99999)
- self.assertEqual(c.actions, [(None, None, (), {}, (), '', 99999)])
+ c.action(None, info='abc')
+ self.assertEqual(c.actions, [(None, None, (), {}, (), 'abc')])
- def test_action_with_includepath_dynamic(self):
+ def test_action_with_includepath_and_info(self):
c = self._makeOne()
- c.actions = []
- c.action(None, includepath=('abc',))
- self.assertEqual(c.actions, [(None, None, (), {}, ('abc',))])
+ c.action(None, includepath=('spec',), info='bleh')
+ self.assertEqual(c.actions,
+ [(None, None, (), {}, ('spec',), 'bleh')])
- def test_action_with_info_dynamic(self):
+ def test_action_with_order(self):
c = self._makeOne()
c.actions = []
- c.action(None, info='abc')
- self.assertEqual(c.actions, [(None, None, (), {}, (), 'abc')])
+ c.action(None, order=99999)
+ self.assertEqual(c.actions, [(None, None, (), {}, (), '', 99999)])
def test_processSpec(self):
c = self._makeOne()
@@ -1439,20 +1430,6 @@ class TestActionState(unittest.TestCase):
self.assertRaises(ConfigurationExecutionError, c.execute_actions)
self.assertEqual(output, [('f', (1,), {}), ('f', (2,), {})])
-class TestActionStateWrapper(unittest.TestCase):
- def _makeOne(self, state):
- from pyramid.config import ActionStateWrapper
- return ActionStateWrapper(state)
-
- def test___getattr__(self):
- state = DummyContext()
- state.foo = 1
- state.bar = 2
- wrapper = self._makeOne(state)
- self.assertEqual(wrapper.foo, 1)
- wrapper.bar = 2
- self.assertEqual(state.bar, 2)
-
class Test_resolveConflicts(unittest.TestCase):
def _callFUT(self, actions):
from pyramid.config import resolveConflicts
@@ -1583,3 +1560,13 @@ class DummyActionState(object):
self.actions = []
def action(self, *arg, **kw):
self.actions.append((arg, kw))
+
+class DummyZCMLContext(object):
+ package = None
+ registry = None
+ autocommit = False
+ route_prefix = None
+ basepath = None
+ includepath = ()
+ info = ''
+
diff --git a/pyramid/tests/test_config/test_routes.py b/pyramid/tests/test_config/test_routes.py
index 6eea92a70..1646561cd 100644
--- a/pyramid/tests/test_config/test_routes.py
+++ b/pyramid/tests/test_config/test_routes.py
@@ -52,7 +52,7 @@ class RoutesConfiguratorMixinTests(unittest.TestCase):
def test_add_route_discriminator(self):
config = self._makeOne()
config.add_route('name', 'path')
- self.assertEqual(config._ctx.actions[-1][0], ('route', 'name'))
+ self.assertEqual(config.action_state.actions[-1][0], ('route', 'name'))
def test_add_route_with_factory(self):
config = self._makeOne(autocommit=True)