Permalink
Browse files

- Previously, If a ``BeforeRender`` event subscriber added a value vi…

…a the

  ``__setitem__`` or ``update`` methods of the event object with a key that
  already existed in the renderer globals dictionary, a ``KeyError`` was
  raised.  With the deprecation of the "add_renderer_globals" feature of the
  configurator, there was no way to override an existing value in the
  renderer globals dictionary that already existed.  Now, the event object
  will overwrite an older value that is already in the globals dictionary
  when its ``__setitem__`` or ``update`` is called (as well as the new
  ``setdefault`` method), just like a plain old dictionary.  As a result, for
  maximum interoperability with other third-party subscribers, if you write
  an event subscriber meant to be used as a BeforeRender subscriber, your
  subscriber code will now need to (using ``.get`` or ``__contains__`` of the
  event object) ensure no value already exists in the renderer globals
  dictionary before setting an overriding value.
  • Loading branch information...
1 parent f9896b6 commit 82efa44c0d8f4b18b4f341519f54ecad68b56364 @mcdonc mcdonc committed Jul 12, 2011
Showing with 85 additions and 31 deletions.
  1. +21 −0 CHANGES.txt
  2. +16 −0 docs/whatsnew-1.1.rst
  3. +26 −19 pyramid/events.py
  4. +9 −4 pyramid/interfaces.py
  5. +13 −8 pyramid/tests/test_events.py
View
@@ -1,3 +1,24 @@
+Next Release
+============
+
+Behavior Changes
+----------------
+
+- Previously, If a ``BeforeRender`` event subscriber added a value via the
+ ``__setitem__`` or ``update`` methods of the event object with a key that
+ already existed in the renderer globals dictionary, a ``KeyError`` was
+ raised. With the deprecation of the "add_renderer_globals" feature of the
+ configurator, there was no way to override an existing value in the
+ renderer globals dictionary that already existed. Now, the event object
+ will overwrite an older value that is already in the globals dictionary
+ when its ``__setitem__`` or ``update`` is called (as well as the new
+ ``setdefault`` method), just like a plain old dictionary. As a result, for
+ maximum interoperability with other third-party subscribers, if you write
+ an event subscriber meant to be used as a BeforeRender subscriber, your
+ subscriber code will now need to (using ``.get`` or ``__contains__`` of the
+ event object) ensure no value already exists in the renderer globals
+ dictionary before setting an overriding value.
+
1.1b1 (2011-07-10)
==================
View
@@ -481,6 +481,22 @@ Deprecations and Behavior Differences
def expects_object_event(object, event):
print object, event
+- In 1.0, if a :class:`pyramid.events.BeforeRender` event subscriber added a
+ value via the ``__setitem__`` or ``update`` methods of the event object
+ with a key that already existed in the renderer globals dictionary, a
+ ``KeyError`` was raised. With the deprecation of the
+ "add_renderer_globals" feature of the configurator, there was no way to
+ override an existing value in the renderer globals dictionary that already
+ existed. Now, the event object will overwrite an older value that is
+ already in the globals dictionary when its ``__setitem__`` or ``update`` is
+ called (as well as the new ``setdefault`` method), just like a plain old
+ dictionary. As a result, for maximum interoperability with other
+ third-party subscribers, if you write an event subscriber meant to be used
+ as a BeforeRender subscriber, your subscriber code will now need to (using
+ ``.get`` or ``__contains__`` of the event object) ensure no value already
+ exists in the renderer globals dictionary before setting an overriding
+ value.
+
Dependency Changes
------------------
View
@@ -179,35 +179,42 @@ def add_global(event):
event['mykey'] = 'foo'
An object of this type is sent as an event just before a :term:`renderer`
- is invoked (but *after* the application-level renderer globals factory
- added via
- :class:`pyramid.config.Configurator.set_renderer_globals_factory`,
- if any, has injected its own keys into the renderer globals dictionary).
-
- If a subscriber attempts to add a key that already exist in the renderer
- globals dictionary, a :exc:`KeyError` is raised. This limitation is
- enforced because event subscribers do not possess any relative ordering.
- The set of keys added to the renderer globals dictionary by all
- :class:`pyramid.events.BeforeRender` subscribers and renderer globals
- factories must be unique. """
+ is invoked (but *after* the -- deprecated -- application-level renderer
+ globals factory added via
+ :class:`pyramid.config.Configurator.set_renderer_globals_factory`, if
+ any, has injected its own keys into the renderer globals dictionary).
+
+ If a subscriber adds a key via ``__setitem__`` or that already exists in
+ the renderer globals dictionary, it will overwrite an older value that is
+ already in the globals dictionary. This can be problematic because event
+ subscribers to the BeforeRender event do not possess any relative
+ ordering. For maximum interoperability with other third-party
+ subscribers, if you write an event subscriber meant to be used as a
+ BeforeRender subscriber, your subscriber code will need to (using
+ ``.get`` or ``__contains__`` of the event object) ensure no value already
+ exists in the renderer globals dictionary before setting an overriding
+ value."""
def __init__(self, system):
self._system = system
def __setitem__(self, name, value):
""" Set a name/value pair into the dictionary which is passed to a
- renderer as the renderer globals dictionary. If the ``name`` already
- exists in the target dictionary, a :exc:`KeyError` will be raised."""
- if name in self._system:
- raise KeyError('%s is already a renderer globals value' % name)
+ renderer as the renderer globals dictionary."""
self._system[name] = value
+ def setdefault(self, name, default=None):
+ """ Return the existing value for ``name`` in the renderers globals
+ dictionary. If no value with ``name`` exists in the dictionary, set
+ the ``default`` value into the renderer globals dictionary under the
+ name passed. If a value already existed in the dictionary, return
+ it. If a value did not exist in the dictionary, return the default"""
+ return self._system.setdefault(name, default)
+
def update(self, d):
""" Update the renderer globals dictionary with another dictionary
- ``d``. If any of the key names in the source dictionary already exist
- in the target dictionary, a :exc:`KeyError` will be raised"""
- for k, v in d.items():
- self[k] = v
+ ``d``."""
+ return self._system.update(d)
def __contains__(self, k):
""" Return ``True`` if ``k`` exists in the renderer globals
View
@@ -284,13 +284,18 @@ def add_global(event):
"""
def __setitem__(name, value):
""" Set a name/value pair into the dictionary which is passed to a
- renderer as the renderer globals dictionary. If the ``name`` already
- exists in the target dictionary, a :exc:`KeyError` will be raised."""
+ renderer as the renderer globals dictionary. """
+
+ def setdefault(name, default=None):
+ """ Return the existing value for ``name`` in the renderers globals
+ dictionary. If no value with ``name`` exists in the dictionary, set
+ the ``default`` value into the renderer globals dictionary under the
+ name passed. If a value already existed in the dictionary, return
+ it. If a value did not exist in the dictionary, return the default"""
def update(d):
""" Update the renderer globals dictionary with another dictionary
- ``d``. If any of the key names in the source dictionary already exist
- in the target dictionary, a :exc:`KeyError` will be raised"""
+ ``d``. """
def __contains__(k):
""" Return ``True`` if ``k`` exists in the renderer globals
@@ -195,22 +195,27 @@ def test_setitem_success(self):
event['a'] = 1
self.assertEqual(system, {'a':1})
- def test_setitem_fail(self):
- system = {'a':1}
+ def test_setdefault_fail(self):
+ system = {}
+ event = self._makeOne(system)
+ result = event.setdefault('a', 1)
+ self.assertEqual(result, 1)
+ self.assertEqual(system, {'a':1})
+
+ def test_setdefault_success(self):
+ system = {}
event = self._makeOne(system)
- self.assertRaises(KeyError, event.__setitem__, 'a', 1)
+ event['a'] = 1
+ result = event.setdefault('a', 2)
+ self.assertEqual(result, 1)
+ self.assertEqual(system, {'a':1})
def test_update_success(self):
system = {'a':1}
event = self._makeOne(system)
event.update({'b':2})
self.assertEqual(system, {'a':1, 'b':2})
- def test_update_fail(self):
- system = {'a':1}
- event = self._makeOne(system)
- self.assertRaises(KeyError, event.update, {'a':1})
-
def test__contains__True(self):
system = {'a':1}
event = self._makeOne(system)

0 comments on commit 82efa44

Please sign in to comment.