PEP 205, Weak References -- initial checkin.
diff --git a/Lib/test/output/test_weakref b/Lib/test/output/test_weakref
new file mode 100644
index 0000000..b3d6f97
--- /dev/null
+++ b/Lib/test/output/test_weakref
@@ -0,0 +1,21 @@
+test_weakref
+Basic Weak References
+-- Liveness and referent identity
+-- Reference objects with callbacks
+-- Proxy objects with callbacks
+-- Re-use of weak reference objects
+     reference objects
+     proxy objects
+clearing ref 2
+clearing ref 1
+clearing ref 2
+clearing ref 1
+
+Weak Valued Dictionaries
+objects are stored in weak dict
+weak dict test complete
+
+Non-callable Proxy References
+XXX -- tests not written!
+
+Callable Proxy References
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
new file mode 100644
index 0000000..fe19373
--- /dev/null
+++ b/Lib/test/test_weakref.py
@@ -0,0 +1,218 @@
+import sys
+import weakref
+
+from test_support import TestFailed, verify
+
+
+class C:
+    pass
+
+
+print "Basic Weak References"
+
+print "-- Liveness and referent identity"
+
+o = C()
+ref = weakref.ref(o)
+verify(ref() is not None, "weak reference to live object should be live")
+o2 = ref()
+verify(ref() is not None, "weak ref should still be live")
+verify(o is o2, "<ref>() should return original object if live")
+del o, o2
+del ref
+
+cbcalled = 0
+def callback(o):
+    global cbcalled
+    cbcalled = 1
+
+o = C()
+ref2 = weakref.ref(o, callback)
+del o
+verify(cbcalled,
+       "callback did not properly set 'cbcalled'")
+verify(ref2() is None,
+       "ref2 should be dead after deleting object reference")
+del ref2
+
+
+print "-- Reference objects with callbacks"
+o = C()
+o.bar = 1
+ref1 = weakref.ref(o, id)
+ref2 = weakref.ref(o, id)
+del o
+verify(ref1() is None,
+       "expected reference to be invalidated")
+verify(ref2() is None,
+       "expected reference to be invalidated")
+
+
+print "-- Proxy objects with callbacks"
+o = C()
+o.bar = 1
+ref1 = weakref.proxy(o, id)
+ref2 = weakref.proxy(o, id)
+del o
+try:
+    ref1.bar
+except weakref.ReferenceError:
+    pass
+else:
+    raise TestFailed("expected ReferenceError exception")
+try:
+    ref2.bar
+except weakref.ReferenceError:
+    pass
+else:
+    raise TestFailed("expected ReferenceError exception")
+
+
+print "-- Re-use of weak reference objects"
+print "     reference objects"
+
+o = C()
+ref1 = weakref.ref(o)
+# create a proxy to make sure that there's an intervening creation
+# between these two; it should make no difference
+proxy = weakref.proxy(o)
+ref2 = weakref.ref(o)
+verify(ref1 is ref2,
+       "reference object w/out callback should have been re-used")
+
+o = C()
+proxy = weakref.proxy(o)
+ref1 = weakref.ref(o)
+ref2 = weakref.ref(o)
+verify(ref1 is ref2,
+       "reference object w/out callback should have been re-used")
+verify(weakref.getweakrefcount(o) == 2,
+       "wrong weak ref count for object")
+del proxy
+verify(weakref.getweakrefcount(o) == 1,
+       "wrong weak ref count for object after deleting proxy")
+
+print "     proxy objects"
+
+o = C()
+ref3 = weakref.proxy(o)
+ref4 = weakref.proxy(o)
+verify(ref3 is ref4,
+       "proxy object w/out callback should have been re-used")
+
+
+def clearing1(r):
+    print "clearing ref 1"
+
+def clearing2(r):
+    print "clearing ref 2"
+
+o = C()
+ref1 = weakref.ref(o, clearing1)
+ref2 = weakref.ref(o, clearing2)
+verify(weakref.getweakrefcount(o) == 2,
+       "got wrong number of weak reference objects")
+del o
+
+o = C()
+ref1 = weakref.ref(o, clearing1)
+ref2 = weakref.ref(o, clearing2)
+del ref1
+verify(weakref.getweakrefs(o) == [ref2],
+       "list of refs does not match")
+del o
+
+o = C()
+ref1 = weakref.ref(o, clearing1)
+ref2 = weakref.ref(o, clearing2)
+del ref2
+verify(weakref.getweakrefs(o) == [ref1],
+       "list of refs does not match")
+del o
+
+print
+print "Weak Valued Dictionaries"
+
+class Object:
+    def __init__(self, arg):
+        self.arg = arg
+    def __repr__(self):
+        return "<Object %r>" % self.arg
+
+dict = weakref.mapping()
+objects = map(Object, range(10))
+for o in objects:
+    dict[o.arg] = o
+print "objects are stored in weak dict"
+for o in objects:
+    verify(weakref.getweakrefcount(o) == 1,
+           "wrong number of weak references to %r!" % o)
+    verify(o is dict[o.arg],
+           "wrong object returned by weak dict!")
+dict.clear()
+print "weak dict test complete"
+
+print
+print "Non-callable Proxy References"
+print "XXX -- tests not written!"
+
+
+def test_proxy(o, proxy):
+    o.foo = 1
+    verify(proxy.foo == 1,
+           "proxy does not reflect attribute addition")
+    o.foo = 2
+    verify(proxy.foo == 2,
+           "proxy does not reflect attribute modification")
+    del o.foo
+    verify(not hasattr(proxy, 'foo'),
+           "proxy does not reflect attribute removal")
+
+    proxy.foo = 1
+    verify(o.foo == 1,
+           "object does not reflect attribute addition via proxy")
+    proxy.foo = 2
+    verify(o.foo == 2,
+           "object does not reflect attribute modification via proxy")
+    del proxy.foo
+    verify(not hasattr(o, 'foo'),
+           "object does not reflect attribute removal via proxy")
+
+
+o = C()
+test_proxy(o, weakref.proxy(o))
+
+print
+print "Callable Proxy References"
+
+class Callable:
+    bar = None
+    def __call__(self, x):
+        self.bar = x
+
+o = Callable()
+ref1 = weakref.proxy(o)
+
+test_proxy(o, ref1)
+
+verify(type(ref1) is weakref.CallableProxyType,
+       "proxy is not of callable type")
+ref1('twinkies!')
+verify(o.bar == 'twinkies!',
+       "call through proxy not passed through to original")
+
+try:
+    ref1()
+except TypeError:
+    # expect due to too few args
+    pass
+else:
+    raise TestFailed("did not catch expected TypeError -- too few args")
+
+try:
+    ref1(1, 2, 3)
+except TypeError:
+    # expect due to too many args
+    pass
+else:
+    raise TestFailed("did not catch expected TypeError -- too many args")
diff --git a/Lib/weakref.py b/Lib/weakref.py
new file mode 100644
index 0000000..f6e07c9
--- /dev/null
+++ b/Lib/weakref.py
@@ -0,0 +1,117 @@
+"""Weak reference support for Python.
+
+This module is an implementation of PEP 205:
+
+http://python.sourceforge.net/peps/pep-0205.html
+"""
+
+import UserDict
+
+from _weakref import \
+     getweakrefcount, \
+     getweakrefs, \
+     ref, \
+     proxy, \
+     ReferenceError, \
+     CallableProxyType, \
+     ProxyType, \
+     ReferenceType
+
+ProxyTypes = (ProxyType, CallableProxyType)
+
+
+def mapping(dict=None):
+    return WeakDictionary(dict)
+
+
+class WeakDictionary(UserDict.UserDict):
+
+    # We inherit the constructor without worrying about the input
+    # dictionary; since it uses our .update() method, we get the right
+    # checks (if the other dictionary is a WeakDictionary, objects are
+    # unwrapped on the way out, and we always wrap on the way in).
+
+    def __getitem__(self, key):
+        o = self.data.get(key)()
+        if o is None:
+            raise KeyError, key
+        else:
+            return o
+
+    def __repr__(self):
+        return "<WeakDictionary at %s>" % id(self)
+
+    def __setitem__(self, key, value):
+        def remove(o, data=self.data, key=key):
+            del data[key]
+        self.data[key] = ref(value, remove)
+
+    def copy(self):
+        new = WeakDictionary()
+        for key, ref in self.data.items():
+            o = ref()
+            if o is not None:
+                new[key] = o
+
+    def get(self, key, default):
+        try:
+            ref = self.data[key]
+        except KeyError:
+            return default
+        else:
+            o = ref()
+            if o is None:
+                # This should only happen
+                return default
+            else:
+                return o
+
+    def items(self):
+        L = self.data.items()
+        for i in range(len(L)):
+            key, ref = L[i]
+            o = ref()
+            if o is not None:
+                L[i] = key, o
+        return L
+
+    def popitem(self):
+        while 1:
+            key, ref = self.data.popitem()
+            o = ref()
+            if o is not None:
+                return key, o
+
+    def setdefault(self, key, default):
+        try:
+            ref = self.data[key]
+        except KeyError:
+            def remove(o, data=self.data, key=key):
+                del data[key]
+            ref = ref(default, remove)
+            self.data[key] = ref
+            return default
+        else:
+            return ref()
+
+    def update(self, dict):
+        d = self.data
+        L = []
+        for key, o in dict.items():
+            def remove(o, data=d, key=key):
+                del data[key]
+            L.append(key, ref(o, remove))
+        for key, r in L:
+            d[key] = r
+
+    def values(self):
+        L = []
+        for ref in self.data.values():
+            o = ref()
+            if o is not None:
+                L.append(o)
+        return L
+
+
+# no longer needed
+del UserDict