1# yield-from a user-defined generator with a throw() method
2
3class Iter:
4    def __iter__(self):
5        return self
6
7    def __next__(self):
8        return 1
9
10    def throw(self, x):
11        print('throw', x)
12        return 456
13
14def gen():
15    yield from Iter()
16
17# calling close() should not call throw()
18g = gen()
19print(next(g))
20g.close()
21
22# can throw a non-exception object
23g = gen()
24print(next(g))
25print(g.throw(123))
26
27# throwing an exception class just injects that class
28g = gen()
29print(next(g))
30print(g.throw(ZeroDivisionError))
31
32# this user-defined generator doesn't have a throw() method
33class Iter2:
34    def __iter__(self):
35        return self
36
37    def __next__(self):
38        return 1
39
40def gen2():
41    yield from Iter2()
42
43# the thrown ValueError is not intercepted by the user class
44g = gen2()
45print(next(g))
46try:
47    g.throw(ValueError)
48except:
49    print('ValueError')
50
51# the thrown 123 is not an exception so raises a TypeError
52g = gen2()
53print(next(g))
54try:
55    g.throw(123)
56except TypeError:
57    print('TypeError')
58