Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 41deb1e

Browse files
committed
PEP 205, Weak References -- initial checkin.
1 parent 2de7471 commit 41deb1e

9 files changed

Lines changed: 1158 additions & 4 deletions

File tree

Include/classobject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ typedef struct {
2424
PyObject_HEAD
2525
PyClassObject *in_class; /* The class object */
2626
PyObject *in_dict; /* A dictionary */
27+
PyObject *in_weakreflist; /* List of weak references */
2728
} PyInstanceObject;
2829

2930
typedef struct {

Include/object.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,8 @@ typedef struct _typeobject {
246246
/* rich comparisons */
247247
richcmpfunc tp_richcompare;
248248

249-
/* More spares */
250-
long tp_xxx8;
249+
/* weak reference enabler */
250+
long tp_weaklistoffset;
251251

252252
#ifdef COUNT_ALLOCS
253253
/* these must be last */
@@ -284,6 +284,8 @@ extern DL_IMPORT(int) PyCallable_Check(PyObject *);
284284
extern DL_IMPORT(int) PyNumber_Coerce(PyObject **, PyObject **);
285285
extern DL_IMPORT(int) PyNumber_CoerceEx(PyObject **, PyObject **);
286286

287+
extern DL_IMPORT(int) (*PyObject_ClearWeakRefs)(PyObject *);
288+
287289
/* Helpers for printing recursive container types */
288290
extern DL_IMPORT(int) Py_ReprEnter(PyObject *);
289291
extern DL_IMPORT(void) Py_ReprLeave(PyObject *);
@@ -418,7 +420,7 @@ extern DL_IMPORT(long) _Py_RefTotal;
418420

419421
#define Py_INCREF(op) (_Py_RefTotal++, (op)->ob_refcnt++)
420422
#define Py_DECREF(op) \
421-
if (--_Py_RefTotal, --(op)->ob_refcnt != 0) \
423+
if (--_Py_RefTotal, (--((op)->ob_refcnt) != 0)) \
422424
; \
423425
else \
424426
_Py_Dealloc((PyObject *)(op))

Include/objimpl.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,11 @@ extern DL_IMPORT(void) _PyObject_Del(PyObject *);
160160
/* Macros trading binary compatibility for speed. See also pymem.h.
161161
Note that these macros expect non-NULL object pointers.*/
162162
#define PyObject_INIT(op, typeobj) \
163-
( (op)->ob_type = (typeobj), _Py_NewReference((PyObject *)(op)), (op) )
163+
((op)->ob_type = (typeobj), _Py_NewReference((PyObject *)(op)), \
164+
(PyType_SUPPORTS_WEAKREFS((typeobj)) \
165+
? *(PyObject_GET_WEAKREFS_LISTPTR(op)) = NULL \
166+
: NULL), \
167+
(op))
164168
#define PyObject_INIT_VAR(op, typeobj, size) \
165169
( (op)->ob_size = (size), PyObject_INIT((op), (typeobj)) )
166170

@@ -266,6 +270,12 @@ extern DL_IMPORT(void) _PyGC_Dump(PyGC_Head *);
266270

267271
#endif /* WITH_CYCLE_GC */
268272

273+
/* Test if a type supports weak references */
274+
#define PyType_SUPPORTS_WEAKREFS(t) ((t)->tp_weaklistoffset > 0)
275+
276+
#define PyObject_GET_WEAKREFS_LISTPTR(o) \
277+
((PyObject **) (((char *) (o)) + (o)->ob_type->tp_weaklistoffset))
278+
269279
#ifdef __cplusplus
270280
}
271281
#endif

Lib/test/output/test_weakref

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
test_weakref
2+
Basic Weak References
3+
-- Liveness and referent identity
4+
-- Reference objects with callbacks
5+
-- Proxy objects with callbacks
6+
-- Re-use of weak reference objects
7+
reference objects
8+
proxy objects
9+
clearing ref 2
10+
clearing ref 1
11+
clearing ref 2
12+
clearing ref 1
13+
14+
Weak Valued Dictionaries
15+
objects are stored in weak dict
16+
weak dict test complete
17+
18+
Non-callable Proxy References
19+
XXX -- tests not written!
20+
21+
Callable Proxy References

Lib/test/test_weakref.py

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
import sys
2+
import weakref
3+
4+
from test_support import TestFailed, verify
5+
6+
7+
class C:
8+
pass
9+
10+
11+
print "Basic Weak References"
12+
13+
print "-- Liveness and referent identity"
14+
15+
o = C()
16+
ref = weakref.ref(o)
17+
verify(ref() is not None, "weak reference to live object should be live")
18+
o2 = ref()
19+
verify(ref() is not None, "weak ref should still be live")
20+
verify(o is o2, "<ref>() should return original object if live")
21+
del o, o2
22+
del ref
23+
24+
cbcalled = 0
25+
def callback(o):
26+
global cbcalled
27+
cbcalled = 1
28+
29+
o = C()
30+
ref2 = weakref.ref(o, callback)
31+
del o
32+
verify(cbcalled,
33+
"callback did not properly set 'cbcalled'")
34+
verify(ref2() is None,
35+
"ref2 should be dead after deleting object reference")
36+
del ref2
37+
38+
39+
print "-- Reference objects with callbacks"
40+
o = C()
41+
o.bar = 1
42+
ref1 = weakref.ref(o, id)
43+
ref2 = weakref.ref(o, id)
44+
del o
45+
verify(ref1() is None,
46+
"expected reference to be invalidated")
47+
verify(ref2() is None,
48+
"expected reference to be invalidated")
49+
50+
51+
print "-- Proxy objects with callbacks"
52+
o = C()
53+
o.bar = 1
54+
ref1 = weakref.proxy(o, id)
55+
ref2 = weakref.proxy(o, id)
56+
del o
57+
try:
58+
ref1.bar
59+
except weakref.ReferenceError:
60+
pass
61+
else:
62+
raise TestFailed("expected ReferenceError exception")
63+
try:
64+
ref2.bar
65+
except weakref.ReferenceError:
66+
pass
67+
else:
68+
raise TestFailed("expected ReferenceError exception")
69+
70+
71+
print "-- Re-use of weak reference objects"
72+
print " reference objects"
73+
74+
o = C()
75+
ref1 = weakref.ref(o)
76+
# create a proxy to make sure that there's an intervening creation
77+
# between these two; it should make no difference
78+
proxy = weakref.proxy(o)
79+
ref2 = weakref.ref(o)
80+
verify(ref1 is ref2,
81+
"reference object w/out callback should have been re-used")
82+
83+
o = C()
84+
proxy = weakref.proxy(o)
85+
ref1 = weakref.ref(o)
86+
ref2 = weakref.ref(o)
87+
verify(ref1 is ref2,
88+
"reference object w/out callback should have been re-used")
89+
verify(weakref.getweakrefcount(o) == 2,
90+
"wrong weak ref count for object")
91+
del proxy
92+
verify(weakref.getweakrefcount(o) == 1,
93+
"wrong weak ref count for object after deleting proxy")
94+
95+
print " proxy objects"
96+
97+
o = C()
98+
ref3 = weakref.proxy(o)
99+
ref4 = weakref.proxy(o)
100+
verify(ref3 is ref4,
101+
"proxy object w/out callback should have been re-used")
102+
103+
104+
def clearing1(r):
105+
print "clearing ref 1"
106+
107+
def clearing2(r):
108+
print "clearing ref 2"
109+
110+
o = C()
111+
ref1 = weakref.ref(o, clearing1)
112+
ref2 = weakref.ref(o, clearing2)
113+
verify(weakref.getweakrefcount(o) == 2,
114+
"got wrong number of weak reference objects")
115+
del o
116+
117+
o = C()
118+
ref1 = weakref.ref(o, clearing1)
119+
ref2 = weakref.ref(o, clearing2)
120+
del ref1
121+
verify(weakref.getweakrefs(o) == [ref2],
122+
"list of refs does not match")
123+
del o
124+
125+
o = C()
126+
ref1 = weakref.ref(o, clearing1)
127+
ref2 = weakref.ref(o, clearing2)
128+
del ref2
129+
verify(weakref.getweakrefs(o) == [ref1],
130+
"list of refs does not match")
131+
del o
132+
133+
print
134+
print "Weak Valued Dictionaries"
135+
136+
class Object:
137+
def __init__(self, arg):
138+
self.arg = arg
139+
def __repr__(self):
140+
return "<Object %r>" % self.arg
141+
142+
dict = weakref.mapping()
143+
objects = map(Object, range(10))
144+
for o in objects:
145+
dict[o.arg] = o
146+
print "objects are stored in weak dict"
147+
for o in objects:
148+
verify(weakref.getweakrefcount(o) == 1,
149+
"wrong number of weak references to %r!" % o)
150+
verify(o is dict[o.arg],
151+
"wrong object returned by weak dict!")
152+
dict.clear()
153+
print "weak dict test complete"
154+
155+
print
156+
print "Non-callable Proxy References"
157+
print "XXX -- tests not written!"
158+
159+
160+
def test_proxy(o, proxy):
161+
o.foo = 1
162+
verify(proxy.foo == 1,
163+
"proxy does not reflect attribute addition")
164+
o.foo = 2
165+
verify(proxy.foo == 2,
166+
"proxy does not reflect attribute modification")
167+
del o.foo
168+
verify(not hasattr(proxy, 'foo'),
169+
"proxy does not reflect attribute removal")
170+
171+
proxy.foo = 1
172+
verify(o.foo == 1,
173+
"object does not reflect attribute addition via proxy")
174+
proxy.foo = 2
175+
verify(o.foo == 2,
176+
"object does not reflect attribute modification via proxy")
177+
del proxy.foo
178+
verify(not hasattr(o, 'foo'),
179+
"object does not reflect attribute removal via proxy")
180+
181+
182+
o = C()
183+
test_proxy(o, weakref.proxy(o))
184+
185+
print
186+
print "Callable Proxy References"
187+
188+
class Callable:
189+
bar = None
190+
def __call__(self, x):
191+
self.bar = x
192+
193+
o = Callable()
194+
ref1 = weakref.proxy(o)
195+
196+
test_proxy(o, ref1)
197+
198+
verify(type(ref1) is weakref.CallableProxyType,
199+
"proxy is not of callable type")
200+
ref1('twinkies!')
201+
verify(o.bar == 'twinkies!',
202+
"call through proxy not passed through to original")
203+
204+
try:
205+
ref1()
206+
except TypeError:
207+
# expect due to too few args
208+
pass
209+
else:
210+
raise TestFailed("did not catch expected TypeError -- too few args")
211+
212+
try:
213+
ref1(1, 2, 3)
214+
except TypeError:
215+
# expect due to too many args
216+
pass
217+
else:
218+
raise TestFailed("did not catch expected TypeError -- too many args")

0 commit comments

Comments
 (0)