SF patch #520382:  Expand shelve.py to have a full dictionary interface
and add a mixin to UserDict.py to make it easier to implement a full
dictionary interface.
diff --git a/Doc/lib/libshelve.tex b/Doc/lib/libshelve.tex
index 76eaaf4..1e02c7b 100644
--- a/Doc/lib/libshelve.tex
+++ b/Doc/lib/libshelve.tex
@@ -33,6 +33,10 @@
 d.close()       # close it
 \end{verbatim}
 
+In addition to the above, shelve supports all methods that are
+supported by dictionaries.  This eases the transition from dictionary
+based scripts to those requiring persistent storage.
+
 Restrictions:
 
 \begin{itemize}
diff --git a/Doc/lib/libuserdict.tex b/Doc/lib/libuserdict.tex
index d665686..e01c546 100644
--- a/Doc/lib/libuserdict.tex
+++ b/Doc/lib/libuserdict.tex
@@ -15,7 +15,13 @@
 them and override existing methods or add new ones.  In this way one
 can add new behaviors to dictionaries.
 
-The \module{UserDict} module defines the \class{UserDict} class:
+The module also defines a mixin defining all dictionary methods for
+classes that already have a minimum mapping interface.  This greatly
+simplifies writing classes that need to be substitutable for
+dictionaries (such as the shelve module).
+
+The \module{UserDict} module defines the \class{UserDict} class
+and \class{DictMixin}:
 
 \begin{classdesc}{UserDict}{\optional{initialdata}}
 Class that simulates a dictionary.  The instance's
@@ -35,6 +41,23 @@
 class.
 \end{memberdesc}
 
+\begin{classdesc}{DictMixin}{}
+Mixin defining all dictionary methods for classes that already have
+a minimum dictionary interface including\method{__getitem__},
+\method{__setitem__}, \method{__delitem__}, and \method{keys}.
+
+This mixin should be used as a superclass.  Adding each of the
+above methods adds progressively more functionality.  For instance,
+the absence of \method{__delitem__} precludes only \method{pop}
+and \method{popitem}.
+
+While the four methods listed above are sufficient to support the
+entire dictionary interface, progessively more efficiency comes
+with defining \method{__contains__}, \method{__iter__}, and
+\method{iteritems}.
+
+\end{classdesc}
+
 
 \section{\module{UserList} ---
          Class wrapper for list objects}
diff --git a/Lib/UserDict.py b/Lib/UserDict.py
index 91af83c..b6b36b2 100644
--- a/Lib/UserDict.py
+++ b/Lib/UserDict.py
@@ -60,3 +60,67 @@
 class IterableUserDict(UserDict):
     def __iter__(self):
         return iter(self.data)
+
+class DictMixin:
+    '''Mixin defining all dictionary methods for classes that already have
+       a minimum dictionary interface including getitem, setitem, delitem,
+       and keys '''
+
+    # first level provided by subclass: getitem, setitem, delitem, and keys
+
+    # second level definitions which assume only getitem and keys
+    def has_key(self, key):
+        try:
+            value = self[key]
+        except KeyError:
+            return False
+        return True
+    __contains__ = has_key
+    def __iter__(self):
+        for k in self.keys():
+            yield k
+    def __len__(self):
+        return len(self.keys())
+
+    # third level uses second level instead of first
+    def iteritems(self):
+        for k in self:
+            yield (k, self[k])
+    iterkeys = __iter__
+
+    # fourth level uses second and third levels instead of first
+    def itervalues(self):
+        for _, v in self.iteritems():
+            yield v
+    def values(self):
+        return [self[key] for key in self.keys()]
+    def items(self):
+        return list(self.iteritems())
+    def clear(self):
+        for key in self.keys():
+            del self[key]
+    def setdefault(self, key, default):
+        if key not in self:
+            self[key] = default
+            return default
+        return self[key]
+    def pop(self, key):
+        value = self[key]
+        del self[key]
+        return value
+    def popitem(self):
+        try:
+            k, v = self.iteritems().next()
+        except StopIteration:
+            raise KeyError, 'dictionary is empty'
+        del self[k]
+        return (k, v)
+    def update(self, other):
+        for key in other.keys():
+            self[key] = other[key]
+    def get(self, key, default=None):
+        if key in self:
+            return self[key]
+        return default
+    def __repr__(self):
+        return repr(dict(self.items()))
diff --git a/Lib/shelve.py b/Lib/shelve.py
index ae8df3f..7a318a6 100644
--- a/Lib/shelve.py
+++ b/Lib/shelve.py
@@ -40,9 +40,11 @@
 except ImportError:
     from StringIO import StringIO
 
+import UserDict
+
 __all__ = ["Shelf","BsdDbShelf","DbfilenameShelf","open"]
 
-class Shelf:
+class Shelf(UserDict.DictMixin):
     """Base class for shelf implementations.
 
     This is initialized with a dictionary-like object.
diff --git a/Misc/NEWS b/Misc/NEWS
index 34f70b7..7a6b780 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -381,6 +381,15 @@
 Library
 -------
 
+- UserDict.py now defines a DictMixin class which defines all dictionary
+  methods for classes that already have a minimum mapping interface.
+  This greatly simplifies writing classes that need to be substitutable
+  for dictionaries (such as the shelve module).
+
+- shelve.py now subclasses from UserDict.DictMixin.  Now shelve supports
+  all dictionary methods.  This eases the transition to persistent
+  storage for scripts originally written with dictionaries in mind.								
+
 - A new package, logging, implements the logging API defined by PEP
   282.  The code is written by Vinay Sajip.