all tests pass; pyramid_zcml still broken with this branch
| | |
| | | |
| | | manager = manager # for testing injection |
| | | venusian = venusian # for testing injection |
| | | _ctx = None |
| | | _ainfo = None |
| | | basepath = None |
| | | includepath = () |
| | | info = '' |
| | | |
| | | def __init__(self, |
| | | registry=None, |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | 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``: |
| | | |
| | |
| | | |
| | | 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('/') + '/' |
| | |
| | | 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. |
| | |
| | | :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): |
| | |
| | | ``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 |
| | |
| | | |
| | | return app |
| | | |
| | | class ActionStateBase(object): |
| | | class ActionState(object): |
| | | def __init__(self): |
| | | self.actions = [] |
| | | self._seen_files = set() |
| | | |
| | | def processSpec(self, spec): |
| | |
| | | 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. |
| | |
| | | (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 |
| | |
| | | """ |
| | | 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: |
| | |
| | | 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[:] |
| | |
| | | |
| | | 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() |
| | | |
| | |
| | | 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 |
| | | def test_with_package(self): |
| | | import pyramid.tests |
| | | 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 |
| | | 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 |
| | |
| | | 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) |
| | |
| | | |
| | | 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) |
| | |
| | | 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) |
| | | state = DummyActionState() |
| | | state.autocommit = False |
| | | state.info = '' |
| | | config._ctx = state |
| | | config.info = '' |
| | | config._ainfo = ['z'] |
| | | state = DummyActionState() |
| | | config.action_state = state |
| | | state.autocommit = False |
| | | 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): |
| | |
| | | '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), |
| | | ) |
| | | |
| | |
| | | '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), |
| | | ) |
| | | |
| | |
| | | '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), |
| | | ) |
| | | |
| | |
| | | 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), |
| | | ) |
| | | |
| | |
| | | |
| | | 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 |
| | |
| | | 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) |
| | | c.action(None, includepath=('abc',)) |
| | | self.assertEqual(c.actions, [(None, None, (), {}, ('abc',))]) |
| | | |
| | | def test_action_with_info(self): |
| | | c = self._makeOne() |
| | | c.action(None, info='abc') |
| | | self.assertEqual(c.actions, [(None, None, (), {}, (), 'abc')]) |
| | | |
| | | def test_action_with_includepath_and_info(self): |
| | | c = self._makeOne() |
| | | c.action(None, includepath=('spec',), info='bleh') |
| | | self.assertEqual(c.actions, |
| | | [(None, None, (), {}, ('foo.zcml',), '?')]) |
| | | [(None, None, (), {}, ('spec',), 'bleh')]) |
| | | |
| | | def test_action_with_order(self): |
| | | c = self._makeOne() |
| | | c.actions = [] |
| | | c.action(None, order=99999) |
| | | self.assertEqual(c.actions, [(None, None, (), {}, (), '', 99999)]) |
| | | |
| | | def test_action_with_includepath_dynamic(self): |
| | | c = self._makeOne() |
| | | c.actions = [] |
| | | c.action(None, includepath=('abc',)) |
| | | self.assertEqual(c.actions, [(None, None, (), {}, ('abc',))]) |
| | | |
| | | def test_action_with_info_dynamic(self): |
| | | c = self._makeOne() |
| | | c.actions = [] |
| | | c.action(None, info='abc') |
| | | self.assertEqual(c.actions, [(None, None, (), {}, (), 'abc')]) |
| | | |
| | | def test_processSpec(self): |
| | | c = self._makeOne() |
| | |
| | | ] |
| | | 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): |
| | |
| | | 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 = '' |
| | | |
| | |
| | | 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) |