summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Merickel <michael@merickel.org>2011-07-11 04:53:46 -0500
committerMichael Merickel <michael@merickel.org>2011-07-14 19:55:47 -0500
commit981c054d746e29f42ac16da48c838729537f2eea (patch)
treee65ebc949ed8625d8b670d057174604d6ce3c0ea
parent68d12cd78c6406e21e2b861c3fcfd3b37f038953 (diff)
downloadpyramid-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.py56
-rw-r--r--pyramid/tests/test_config.py89
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