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))
|