diff options
| author | Michael Merickel <michael@merickel.org> | 2011-07-11 04:53:46 -0500 |
|---|---|---|
| committer | Michael Merickel <michael@merickel.org> | 2011-07-14 19:55:47 -0500 |
| commit | 981c054d746e29f42ac16da48c838729537f2eea (patch) | |
| tree | e65ebc949ed8625d8b670d057174604d6ce3c0ea | |
| parent | 68d12cd78c6406e21e2b861c3fcfd3b37f038953 (diff) | |
| download | pyramid-981c054d746e29f42ac16da48c838729537f2eea.tar.gz pyramid-981c054d746e29f42ac16da48c838729537f2eea.tar.bz2 pyramid-981c054d746e29f42ac16da48c838729537f2eea.zip | |
Added tracking of p.config.global_registries for created apps.
| -rw-r--r-- | pyramid/config.py | 56 | ||||
| -rw-r--r-- | pyramid/tests/test_config.py | 89 |
2 files changed, 129 insertions, 16 deletions
diff --git a/pyramid/config.py b/pyramid/config.py index dff88b574..93ef51163 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -1,3 +1,4 @@ +import collections import inspect import os import re @@ -982,6 +983,7 @@ class Configurator(object): self.commit() from pyramid.router import Router # avoid circdep app = Router(self.registry) + global_registries.add(self.registry) # We push the registry on to the stack here in case any code # that depends on the registry threadlocal APIs used in # listeners subscribed to the IApplicationCreated event. @@ -991,13 +993,6 @@ class Configurator(object): finally: self.manager.pop() - # see the comments on p.config.last_registry to understand why - def cleanup_last_registry(ref): - global last_registry - last_registry = None - global last_registry - last_registry = weakref.ref(self.registry, cleanup_last_registry) - return app @action_method @@ -3327,8 +3322,45 @@ def isexception(o): (inspect.isclass(o) and (issubclass(o, Exception))) ) -# last_registry is a hack to keep track of the registry for the last Pyramid -# application created. This is useful to access the registry after the app -# itself has been wrapped in a WSGI stack, specifically for scripting -# purposes in pyramid.scripting. -last_registry = None +class WeakOrderedSet(object): + """ Maintain a set of items. + + Each item is stored as a weakref to avoid extending their lifetime. + + The values may be iterated over or the last item added may be + accessed via the ``last`` property. + """ + + def __init__(self): + self._items = {} + self._order = [] + + def add(self, item): + """ Add a registry to the set.""" + oid = id(item) + if oid in self._items: + return + def cleanup(ref): + del self._items[oid] + self._order.remove(oid) + ref = weakref.ref(item, cleanup) + self._items[oid] = ref + self._order.append(oid) + + def __len__(self): + return len(self._order) + + def __contains__(self, item): + oid = id(item) + return oid in self._items + + def __iter__(self): + return (self._items[oid]() for oid in self._order) + + @property + def last(self): + if self._order: + oid = self._order[-1] + return self._items[oid]() + +global_registries = WeakOrderedSet() diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py index f49a693f0..1e73573ae 100644 --- a/pyramid/tests/test_config.py +++ b/pyramid/tests/test_config.py @@ -684,13 +684,30 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(manager.pushed['registry'], config.registry) self.assertEqual(manager.pushed['request'], None) self.assertTrue(manager.popped) - self.assertEqual(pyramid.config.last_registry(), app.registry) + self.assertEqual(pyramid.config.global_registries.last, app.registry) self.assertEqual(len(subscriber), 1) self.assertTrue(IApplicationCreated.providedBy(subscriber[0])) - def test_uninitialized_last_registry(self): - import pyramid.config - self.assertEqual(pyramid.config.last_registry, None) + def test_global_registries_empty(self): + import gc + from pyramid.config import global_registries + gc.collect() # force weakref updates + self.assertEqual(global_registries.last, None) + + def test_global_registries(self): + import gc + from pyramid.config import global_registries + config1 = self._makeOne() + config1.make_wsgi_app() + self.assertEqual(global_registries.last, config1.registry) + config2 = self._makeOne() + config2.make_wsgi_app() + self.assertEqual(global_registries.last, config2.registry) + self.assertEqual(list(global_registries), + [config1.registry, config2.registry]) + del config2 + gc.collect() # force weakref updates + self.assertEqual(global_registries.last, config1.registry) def test_include_with_dotted_name(self): from pyramid import tests @@ -5307,6 +5324,70 @@ class Test_isexception(unittest.TestCase): pass self.assertEqual(self._callFUT(ISubException), True) +class Test_WeakOrderedSet(unittest.TestCase): + def _makeOne(self): + from pyramid.config import WeakOrderedSet + return WeakOrderedSet() + + def test_empty(self): + wos = self._makeOne() + self.assertEqual(len(wos), 0) + self.assertEqual(wos.last, None) + + def test_add_item(self): + wos = self._makeOne() + reg = DummyRegistry() + wos.add(reg) + self.assertEqual(list(wos), [reg]) + self.assert_(reg in wos) + self.assertEqual(wos.last, reg) + + def test_add_multiple_items(self): + wos = self._makeOne() + reg1 = DummyRegistry() + reg2 = DummyRegistry() + wos.add(reg1) + wos.add(reg2) + self.assertEqual(len(wos), 2) + self.assertEqual(list(wos), [reg1, reg2]) + self.assert_(reg1 in wos) + self.assert_(reg2 in wos) + self.assertEqual(wos.last, reg2) + + def test_add_duplicate_items(self): + wos = self._makeOne() + reg = DummyRegistry() + wos.add(reg) + wos.add(reg) + self.assertEqual(len(wos), 1) + self.assertEqual(list(wos), [reg]) + self.assert_(reg in wos) + self.assertEqual(wos.last, reg) + + def test_weakref_removal(self): + import gc + wos = self._makeOne() + reg = DummyRegistry() + wos.add(reg) + del reg + gc.collect() # force gc + self.assertEqual(len(wos), 0) + self.assertEqual(list(wos), []) + self.assertEqual(wos.last, None) + + def test_last_updated(self): + import gc + wos = self._makeOne() + reg = DummyRegistry() + reg2 = DummyRegistry() + wos.add(reg) + wos.add(reg2) + del reg2 + gc.collect() # force gc + self.assertEqual(len(wos), 1) + self.assertEqual(list(wos), [reg]) + self.assertEqual(wos.last, reg) + class DummyRequest: subpath = () matchdict = None |
