summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/anydbm.py51
-rw-r--r--Lib/copy.py98
-rw-r--r--Lib/shelve.py66
3 files changed, 169 insertions, 46 deletions
diff --git a/Lib/anydbm.py b/Lib/anydbm.py
index 49e819b..d24efe7 100644
--- a/Lib/anydbm.py
+++ b/Lib/anydbm.py
@@ -1,9 +1,50 @@
-"""A generic interface to all dbm clones."""
+"""A generic interface to all dbm clones.
+
+Instead of
+
+ import dbm
+ d = dbm.open(file, 'rw', 0666)
+
+use
+
+ import anydbm
+ d = anydbm.open(file)
+
+The returned object is a dbm, gdbm or (on the Mac) dbmac object,
+dependent on availability of the modules (tested in this order).
+
+It has the following interface (key and data are strings):
+
+ d[key] = data # store data at key (may override data at
+ # existing key)
+ data = d[key] # retrieve data at key (raise KeyError if no
+ # such key)
+ del d[key] # delete data stored at key (raises KeyError
+ # if no such key)
+ flag = d.has_key(key) # true if the key exists
+ list = d.keys() # return a list of all existing keys (slow!)
+
+Future versions may change the order in which implementations are
+tested for existence, add interfaces to other db-like implementations
+(e.g. BSD Hash), and (in the presence of multiple implementations)
+decide which module to use based upon the extension or contents of an
+existing database file.
+
+The open function has an optional second argument. This can be set to
+'r' to open the database for reading only. Don't pas an explicit 'w'
+or 'rw' to open it for writing, as the different interfaces have
+different interpretation of their mode argument if it isn't 'r'.
+"""
try:
import dbm
- def open(file, mode = 'rw'):
- return dbm.open(file, mode, 0666)
+ def open(filename, mode = 'rw'):
+ return dbm.open(filename, mode, 0666)
except ImportError:
- import dbmac
- open = dbmac.open
+ try:
+ import gdbm
+ def open(filename, mode = 'w'):
+ return gdbm.open(filename, mode, 0666)
+ except ImportError:
+ import dbmac
+ open = dbmac.open
diff --git a/Lib/copy.py b/Lib/copy.py
index fe4c4fb..966bfa2 100644
--- a/Lib/copy.py
+++ b/Lib/copy.py
@@ -1,49 +1,73 @@
-# Generic (shallow and deep) copying operations
-# =============================================
-#
-# The difference between shallow and deep copying is only relevant for
-# compound objects (objects that contain other objects, like lists or class
-# instances).
-#
-# - A shallow copy constructs a new compound object and then (to the extent
-# possible) inserts *the same objects* into in that the original contains.
-#
-# - A deep copy constructs a new compound object and then, recursively,
-# inserts *copies* into it of the objects found in the original.
-#
-# Two problems often exist with deep copy operations that don't exist with
-# shallow copy operations:
-#
-# (a) recursive objects (compound objects that, directly or indirectly,
-# contain a reference to themselves) may cause a recursive loop
-#
-# (b) because deep copy copies *everything* it may copy too much, e.g.
-# administrative data structures that should be shared even between copies
-#
-# Python's deep copy operation avoids these problems by:
-#
-# (a) keeping a table of objects already copied during the current copying pass
-#
-# (b) letting user-defined classes override the copying operation or the set
-# of components copied
-#
-# This version does not copy types like module, class, function, method,
-# nor stack trace, stack frame, nor file, socket, window, nor array,
-# nor any similar types.
+"""\
+Generic (shallow and deep) copying operations
+=============================================
+Interface summary:
+
+ import copy
+
+ x = copy.copy(y) # make a shallow copy of y
+ x = copy.deepcopy(y) # make a deep copy of y
+
+For module specific errors, copy.Error is raised.
+
+The difference between shallow and deep copying is only relevant for
+compound objects (objects that contain other objects, like lists or
+class instances).
+
+- A shallow copy constructs a new compound object and then (to the
+ extent possible) inserts *the same objects* into in that the
+ original contains.
+
+- A deep copy constructs a new compound object and then, recursively,
+ inserts *copies* into it of the objects found in the original.
+
+Two problems often exist with deep copy operations that don't exist
+with shallow copy operations:
+
+(a) recursive objects (compound objects that, directly or indirectly,
+ contain a reference to themselves) may cause a recursive loop
+
+(b) because deep copy copies *everything* it may copy too much, e.g.
+ administrative data structures that should be shared even between
+ copies
+
+Python's deep copy operation avoids these problems by:
+
+(a) keeping a table of objects already copied during the current
+copying pass
+
+(b) letting user-defined classes override the copying operation or the
+ set of components copied
+
+This version does not copy types like module, class, function, method,
+nor stack trace, stack frame, nor file, socket, window, nor array, nor
+any similar types.
+
+Classes can use the same interfaces to control copying that they use
+to control pickling: they can define methods called __getinitargs__(),
+__getstate__() and __setstate__(). See the __doc__ string of module
+"pickle" for information on these methods.
+"""
import types
Error = 'copy.Error'
def copy(x):
+ """Shallow copy operation on arbitrary Python objects.
+
+ See the module's __doc__ string for more info.
+ """
+
try:
copierfunction = _copy_dispatch[type(x)]
except KeyError:
try:
copier = x.__copy__
except AttributeError:
- raise Error, "un(shallow)copyable object of type %s" % type(x)
+ raise Error, \
+ "un(shallow)copyable object of type %s" % type(x)
y = copier()
else:
y = copierfunction(x)
@@ -100,6 +124,11 @@ d[types.InstanceType] = _copy_inst
del d
def deepcopy(x, memo = None):
+ """Deep copy operation on arbitrary Python objects.
+
+ See the module's __doc__ string for more info.
+ """
+
if memo is None:
memo = {}
d = id(x)
@@ -111,7 +140,8 @@ def deepcopy(x, memo = None):
try:
copier = x.__deepcopy__
except AttributeError:
- raise Error, "un-deep-copyable object of type %s" % type(x)
+ raise Error, \
+ "un-deep-copyable object of type %s" % type(x)
y = copier(memo)
else:
y = copierfunction(x, memo)
diff --git a/Lib/shelve.py b/Lib/shelve.py
index b90e641..a7f289f 100644
--- a/Lib/shelve.py
+++ b/Lib/shelve.py
@@ -1,9 +1,43 @@
-"""Manage shelves of pickled objects."""
+"""Manage shelves of pickled objects.
+
+A "shelf" is a persistent, dictionary-like object. The difference
+with dbm databases is that the values (not the keys!) in a shelf can
+be essentially arbitrary Python objects -- anything that the "pickle"
+module can handle. This includes most class instances, recursive data
+types, and objects containing lots of shared sub-objects. The keys
+are ordinary strings.
+
+To summarize the interface (key is a string, data is an arbitrary
+object):
+
+ import shelve
+ d = shelve.open(filename) # open, with (g)dbm filename
+
+ d[key] = data # store data at key (overwrites old data if
+ # using an existing key)
+ data = d[key] # retrieve data at key (raise KeyError if no
+ # such key)
+ del d[key] # delete data stored at key (raises KeyError
+ # if no such key)
+ flag = d.has_key(key) # true if the key exists
+ list = d.keys() # a list of all existing keys (slow!)
+
+ d.close() # close it
+
+Dependent on the implementation, closing a persistent dictionary may
+or may not be necessary to flush changes to disk.
+"""
import pickle
import StringIO
+
class Shelf:
+ """Base class for shelf implementations.
+
+ This is initialized with a dictionary-like object.
+ See the module's __doc__ string for an overview of the interface.
+ """
def __init__(self, dict):
self.dict = dict
@@ -18,7 +52,8 @@ class Shelf:
return self.dict.has_key(key)
def __getitem__(self, key):
- return pickle.Unpickler(StringIO.StringIO(self.dict[key])).load()
+ f = StringIO.StringIO(self.dict[key])
+ return pickle.Unpickler(f).load()
def __setitem__(self, key, value):
f = StringIO.StringIO()
@@ -30,14 +65,31 @@ class Shelf:
del self.dict[key]
def close(self):
- self.db.close()
+ if hasattr(self.db, 'close'):
+ self.db.close()
self.db = None
+ def __del__(self):
+ self.close()
+
+
class DbShelf(Shelf):
+ """Shelf implementation using the "anydbm" generic dbm interface.
+
+ This is initialized with the filename for the dbm database.
+ See the module's __doc__ string for an overview of the interface.
+ """
- def __init__(self, file):
+ def __init__(self, filename):
import anydbm
- Shelf.__init__(self, anydbm.open(file))
+ Shelf.__init__(self, anydbm.open(filename))
-def open(file):
- return DbShelf(file)
+
+def open(filename):
+ """Open a persistent dictionary for reading and writing.
+
+ Argument is the filename for the dbm database.
+ See the module's __doc__ string for an overview of the interface.
+ """
+
+ return DbShelf(filename)