1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
# Test to make sure there's no sequence hazard even when a __set_name__ implementation
# mutates and reorders the namespace of its owner class.
# VERY hard bug to prove out except via a stochastic test.
try:
from random import choice
import re
except ImportError:
print("SKIP")
raise SystemExit
def skip_if_no_descriptors():
class Descriptor:
def __get__(self, obj, cls):
return
class TestClass:
Forward = Descriptor()
a = TestClass()
try:
a.__class__
except AttributeError:
# Target doesn't support __class__.
print("SKIP")
raise SystemExit
b = a.Forward
if "Descriptor" in repr(b.__class__):
# Target doesn't support descriptors.
print("SKIP")
raise SystemExit
skip_if_no_descriptors()
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
# Would be r"[A-Z]{5}", but not all ports support the {n} quantifier.
junk_re = re.compile(r"[A-Z][A-Z][A-Z][A-Z][A-Z]")
def junk_fill(obj, n=10): # Add randomly-generated attributes to an object.
for i in range(n):
name = "".join(choice(letters) for j in range(5))
setattr(obj, name, object())
def junk_clear(obj): # Remove attributes added by junk_fill.
to_del = [name for name in dir(obj) if junk_re.match(name)]
for name in to_del:
delattr(obj, name)
def junk_sequencer():
global runs
try:
while True:
owner, name = yield
runs[name] = runs.get(name, 0) + 1
junk_fill(owner)
finally:
junk_clear(owner)
class JunkMaker:
def __set_name__(self, owner, name):
global seq
seq.send((owner, name))
runs = {}
seq = junk_sequencer()
next(seq)
class Main:
a = JunkMaker()
b = JunkMaker()
c = JunkMaker()
d = JunkMaker()
e = JunkMaker()
f = JunkMaker()
g = JunkMaker()
h = JunkMaker()
i = JunkMaker()
j = JunkMaker()
k = JunkMaker()
l = JunkMaker()
m = JunkMaker()
n = JunkMaker()
o = JunkMaker()
p = JunkMaker()
q = JunkMaker()
r = JunkMaker()
s = JunkMaker()
t = JunkMaker()
u = JunkMaker()
v = JunkMaker()
w = JunkMaker()
x = JunkMaker()
y = JunkMaker()
z = JunkMaker()
seq.close()
for k in letters.lower():
print(k, runs.get(k, 0))
|