From 59c5df5bfabf15e50a1cb6ddbe3033c0656923c7 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 28 Nov 2009 23:46:59 +0000 Subject: - Unit tests which use ``zope.testing.cleanup.cleanUp`` for the purpose of isolating tests from one another may now begin to fail due to lack of isolation between tests. Here's why: In repoze.bfg 1.1 and prior, the registry returned by ``repoze.bfg.threadlocal.get_current_registry`` when no other registry had been pushed on to the threadlocal stack was the ``zope.component.globalregistry.base`` global registry (aka the result of ``zope.component.getGlobalSiteManager()``). In repoze.bfg 1.2+, however, the registry returned in this situation is the new module-scope ``repoze.bfg.registry.global_registry`` object. The ``zope.testing.cleanup.cleanUp`` function clears the ``zope.component.globalregistry.base`` global registry unconditionally. However, it does not know about the ``repoze.bfg.registry.global_registry`` object, so it does not clear it. If you use the ``zope.testing.cleanup.cleanUp`` function in the ``setUp`` of test cases in your unit test suite instead of using the (more correct as of 1.1) ``repoze.bfg.testing.setUp``, you will need to replace all calls to ``zope.testing.cleanup.cleanUp`` with a call to ``repoze.bfg.testing.setUp``. If replacing all calls to ``zope.testing.cleanup.cleanUp`` with a call to ``repoze.bfg.testing.setUp`` is infeasible, you can put this bit of code somewhere that is executed exactly **once** (*not* for each test in a test suite; in the `` __init__.py`` of your package would be a reasonable place):: import zope.testing.cleanup from repoze.bfg.testing import setUp zope.testing.cleanup.addCleanUp(setUp) - When there is no "current registry" in the ``repoze.bfg.threadlocal.manager`` threadlocal data structure (this is the case when there is no "current request" or we're not in the midst of a ``r.b.testing.setUp``-bounded unit test), the ``.get`` method of the manager returns a data structure containing a *global* registry. In previous releases, this function returned the global Zope "base" registry: the result of ``zope.component.getGlobalSiteManager``, which is an instance of the ``zope.component.registry.Component`` class. In this release, however, the global registry returns a globally importable instance of the ``repoze.bfg.registry.Registry`` class. This registry instance can always be imported as ``repoze.bfg.registry.global_registry``. Effectively, this means that when you call ``repoze.bfg.threadlocal.get_current_registry`` when no request or ``setUp`` bounded unit test is in effect, you will always get back the global registry that lives in ``repoze.bfg.registry.global_registry``. It also means that :mod:`repoze.bfg` APIs that *call* ``get_current_registry`` will use this registry. This change was made because :mod:`repoze.bfg` now expects the registry it uses to have a slightly different API than a bare instance of ``zope.component.registry.Components``. --- CHANGES.txt | 59 ++++++++++++++++++++++++++++++++++++ docs/whatsnew-1.2.rst | 59 ++++++++++++++++++++++++++++++++++++ repoze/bfg/registry.py | 1 + repoze/bfg/testing.py | 1 + repoze/bfg/tests/test_threadlocal.py | 4 +-- repoze/bfg/threadlocal.py | 5 ++- 6 files changed, 124 insertions(+), 5 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index e3cd85cc7..fbc032d17 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -224,6 +224,65 @@ Internals Backwards Incompatibilites -------------------------- +- Unit tests which use ``zope.testing.cleanup.cleanUp`` for the + purpose of isolating tests from one another may now begin to fail + due to lack of isolation between tests. + + Here's why: In repoze.bfg 1.1 and prior, the registry returned by + ``repoze.bfg.threadlocal.get_current_registry`` when no other + registry had been pushed on to the threadlocal stack was the + ``zope.component.globalregistry.base`` global registry (aka the + result of ``zope.component.getGlobalSiteManager()``). In repoze.bfg + 1.2+, however, the registry returned in this situation is the new + module-scope ``repoze.bfg.registry.global_registry`` object. The + ``zope.testing.cleanup.cleanUp`` function clears the + ``zope.component.globalregistry.base`` global registry + unconditionally. However, it does not know about the + ``repoze.bfg.registry.global_registry`` object, so it does not clear + it. + + If you use the ``zope.testing.cleanup.cleanUp`` function in the + ``setUp`` of test cases in your unit test suite instead of using the + (more correct as of 1.1) ``repoze.bfg.testing.setUp``, you will need + to replace all calls to ``zope.testing.cleanup.cleanUp`` with a call + to ``repoze.bfg.testing.setUp``. + + If replacing all calls to ``zope.testing.cleanup.cleanUp`` with a + call to ``repoze.bfg.testing.setUp`` is infeasible, you can put this + bit of code somewhere that is executed exactly **once** (*not* for + each test in a test suite; in the `` __init__.py`` of your + package would be a reasonable place):: + + import zope.testing.cleanup + from repoze.bfg.testing import setUp + zope.testing.cleanup.addCleanUp(setUp) + +- When there is no "current registry" in the + ``repoze.bfg.threadlocal.manager`` threadlocal data structure (this + is the case when there is no "current request" or we're not in the + midst of a ``r.b.testing.setUp``-bounded unit test), the ``.get`` + method of the manager returns a data structure containing a *global* + registry. In previous releases, this function returned the global + Zope "base" registry: the result of + ``zope.component.getGlobalSiteManager``, which is an instance of the + ``zope.component.registry.Component`` class. In this release, + however, the global registry returns a globally importable instance + of the ``repoze.bfg.registry.Registry`` class. This registry + instance can always be imported as + ``repoze.bfg.registry.global_registry``. + + Effectively, this means that when you call + ``repoze.bfg.threadlocal.get_current_registry`` when no request or + ``setUp`` bounded unit test is in effect, you will always get back + the global registry that lives in + ``repoze.bfg.registry.global_registry``. It also means that + :mod:`repoze.bfg` APIs that *call* ``get_current_registry`` will use + this registry. + + This change was made because :mod:`repoze.bfg` now expects the + registry it uses to have a slightly different API than a bare + instance of ``zope.component.registry.Components``. + - View registration no longer registers a ``repoze.bfg.interfaces.IViewPermission`` adapter (it is no longer checked by the framework; since 1.1, views have been responsible for diff --git a/docs/whatsnew-1.2.rst b/docs/whatsnew-1.2.rst index 93866bdb0..9fad73de0 100644 --- a/docs/whatsnew-1.2.rst +++ b/docs/whatsnew-1.2.rst @@ -82,6 +82,65 @@ Minor Miscellaneous Feature Additions Backwards Incompatibilites -------------------------- +- Unit tests which use ``zope.testing.cleanup.cleanUp`` for the + purpose of isolating tests from one another may now begin to fail + due to lack of isolation between tests. + + Here's why: In repoze.bfg 1.1 and prior, the registry returned by + ``repoze.bfg.threadlocal.get_current_registry`` when no other + registry had been pushed on to the threadlocal stack was the + ``zope.component.globalregistry.base`` global registry (aka the + result of ``zope.component.getGlobalSiteManager()``). In repoze.bfg + 1.2+, however, the registry returned in this situation is the new + module-scope ``repoze.bfg.registry.global_registry`` object. The + ``zope.testing.cleanup.cleanUp`` function clears the + ``zope.component.globalregistry.base`` global registry + unconditionally. However, it does not know about the + ``repoze.bfg.registry.global_registry`` object, so it does not clear + it. + + If you use the ``zope.testing.cleanup.cleanUp`` function in the + ``setUp`` of test cases in your unit test suite instead of using the + (more correct as of 1.1) ``repoze.bfg.testing.setUp``, you will need + to replace all calls to ``zope.testing.cleanup.cleanUp`` with a call + to ``repoze.bfg.testing.setUp``. + + If replacing all calls to ``zope.testing.cleanup.cleanUp`` with a + call to ``repoze.bfg.testing.setUp`` is infeasible, you can put this + bit of code somewhere that is executed exactly **once** (*not* for + each test in a test suite; in the `` __init__.py`` of your + package would be a reasonable place):: + + import zope.testing.cleanup + from repoze.bfg.testing import setUp + zope.testing.cleanup.addCleanUp(setUp) + +- When there is no "current registry" in the + ``repoze.bfg.threadlocal.manager`` threadlocal data structure (this + is the case when there is no "current request" or we're not in the + midst of a ``r.b.testing.setUp``-bounded unit test), the ``.get`` + method of the manager returns a data structure containing a *global* + registry. In previous releases, this function returned the global + Zope "base" registry: the result of + ``zope.component.getGlobalSiteManager``, which is an instance of the + ``zope.component.registry.Component`` class. In this release, + however, the global registry returns a globally importable instance + of the ``repoze.bfg.registry.Registry`` class. This registry + instance can always be imported as + ``repoze.bfg.registry.global_registry``. + + Effectively, this means that when you call + ``repoze.bfg.threadlocal.get_current_registry`` when no request or + ``setUp`` bounded unit test is in effect, you will always get back + the global registry that lives in + ``repoze.bfg.registry.global_registry``. It also means that + :mod:`repoze.bfg` APIs that *call* ``get_current_registry`` will use + this registry. + + This change was made because :mod:`repoze.bfg` now expects the + registry it uses to have a slightly different API than a bare + instance of ``zope.component.registry.Components``. + - View registration no longer registers a ``repoze.bfg.interfaces.IViewPermission`` adapter (it is no longer checked by the framework; since 1.1, views have been responsible for diff --git a/repoze/bfg/registry.py b/repoze/bfg/registry.py index 68de05c34..e935ac165 100644 --- a/repoze/bfg/registry.py +++ b/repoze/bfg/registry.py @@ -21,3 +21,4 @@ class Registry(Components, dict): # iterating over subscribers assures they get executed [ _ for _ in self.subscribers(events, None) ] +global_registry = Registry('global') diff --git a/repoze/bfg/testing.py b/repoze/bfg/testing.py index 88a803aac..f8136789f 100644 --- a/repoze/bfg/testing.py +++ b/repoze/bfg/testing.py @@ -637,3 +637,4 @@ def cleanUp(*arg, **kw): effectively deprecated as of :mod:`repoze.bfg` 1.1, due to its extensive production usage, it will never be removed.""" setUp(*arg, **kw) + diff --git a/repoze/bfg/tests/test_threadlocal.py b/repoze/bfg/tests/test_threadlocal.py index b277d6cb9..6bb18c4ff 100644 --- a/repoze/bfg/tests/test_threadlocal.py +++ b/repoze/bfg/tests/test_threadlocal.py @@ -90,6 +90,6 @@ class GetCurrentRegistryWithoutTestingRegistry(unittest.TestCase): return get_current_registry() def test_it(self): - from zope.component import getGlobalSiteManager - self.assertEqual(self._callFUT(), getGlobalSiteManager()) + from repoze.bfg.registry import global_registry + self.assertEqual(self._callFUT(), global_registry) diff --git a/repoze/bfg/threadlocal.py b/repoze/bfg/threadlocal.py index 7e0de86ca..7d1b4eeda 100644 --- a/repoze/bfg/threadlocal.py +++ b/repoze/bfg/threadlocal.py @@ -1,6 +1,6 @@ import threading -from zope.component import getGlobalSiteManager +from repoze.bfg.registry import global_registry class ThreadLocalManager(threading.local): def __init__(self, default=None): @@ -31,8 +31,7 @@ class ThreadLocalManager(threading.local): self.stack[:] = [] def defaults(): - reg = getGlobalSiteManager() - return {'request':None, 'registry':reg} + return {'request':None, 'registry':global_registry} manager = ThreadLocalManager(default=defaults) -- cgit v1.2.3