test_yield_from.py 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  1. # -*- coding: utf-8 -*-
  2. """
  3. Test suite for PEP 380 implementation
  4. adapted from original tests written by Greg Ewing
  5. see <http://www.cosc.canterbury.ac.nz/greg.ewing/python/yield-from/YieldFrom-Python3.1.2-rev5.zip>
  6. """
  7. import unittest
  8. import inspect
  9. from test.support import captured_stderr, disable_gc, gc_collect
  10. from test import support
  11. class TestPEP380Operation(unittest.TestCase):
  12. """
  13. Test semantics.
  14. """
  15. def test_delegation_of_initial_next_to_subgenerator(self):
  16. """
  17. Test delegation of initial next() call to subgenerator
  18. """
  19. trace = []
  20. def g1():
  21. trace.append("Starting g1")
  22. yield from g2()
  23. trace.append("Finishing g1")
  24. def g2():
  25. trace.append("Starting g2")
  26. yield 42
  27. trace.append("Finishing g2")
  28. for x in g1():
  29. trace.append("Yielded %s" % (x,))
  30. self.assertEqual(trace,[
  31. "Starting g1",
  32. "Starting g2",
  33. "Yielded 42",
  34. "Finishing g2",
  35. "Finishing g1",
  36. ])
  37. def test_raising_exception_in_initial_next_call(self):
  38. """
  39. Test raising exception in initial next() call
  40. """
  41. trace = []
  42. def g1():
  43. try:
  44. trace.append("Starting g1")
  45. yield from g2()
  46. finally:
  47. trace.append("Finishing g1")
  48. def g2():
  49. try:
  50. trace.append("Starting g2")
  51. raise ValueError("spanish inquisition occurred")
  52. finally:
  53. trace.append("Finishing g2")
  54. try:
  55. for x in g1():
  56. trace.append("Yielded %s" % (x,))
  57. except ValueError as e:
  58. self.assertEqual(e.args[0], "spanish inquisition occurred")
  59. else:
  60. self.fail("subgenerator failed to raise ValueError")
  61. self.assertEqual(trace,[
  62. "Starting g1",
  63. "Starting g2",
  64. "Finishing g2",
  65. "Finishing g1",
  66. ])
  67. def test_delegation_of_next_call_to_subgenerator(self):
  68. """
  69. Test delegation of next() call to subgenerator
  70. """
  71. trace = []
  72. def g1():
  73. trace.append("Starting g1")
  74. yield "g1 ham"
  75. yield from g2()
  76. yield "g1 eggs"
  77. trace.append("Finishing g1")
  78. def g2():
  79. trace.append("Starting g2")
  80. yield "g2 spam"
  81. yield "g2 more spam"
  82. trace.append("Finishing g2")
  83. for x in g1():
  84. trace.append("Yielded %s" % (x,))
  85. self.assertEqual(trace,[
  86. "Starting g1",
  87. "Yielded g1 ham",
  88. "Starting g2",
  89. "Yielded g2 spam",
  90. "Yielded g2 more spam",
  91. "Finishing g2",
  92. "Yielded g1 eggs",
  93. "Finishing g1",
  94. ])
  95. def test_raising_exception_in_delegated_next_call(self):
  96. """
  97. Test raising exception in delegated next() call
  98. """
  99. trace = []
  100. def g1():
  101. try:
  102. trace.append("Starting g1")
  103. yield "g1 ham"
  104. yield from g2()
  105. yield "g1 eggs"
  106. finally:
  107. trace.append("Finishing g1")
  108. def g2():
  109. try:
  110. trace.append("Starting g2")
  111. yield "g2 spam"
  112. raise ValueError("hovercraft is full of eels")
  113. yield "g2 more spam"
  114. finally:
  115. trace.append("Finishing g2")
  116. try:
  117. for x in g1():
  118. trace.append("Yielded %s" % (x,))
  119. except ValueError as e:
  120. self.assertEqual(e.args[0], "hovercraft is full of eels")
  121. else:
  122. self.fail("subgenerator failed to raise ValueError")
  123. self.assertEqual(trace,[
  124. "Starting g1",
  125. "Yielded g1 ham",
  126. "Starting g2",
  127. "Yielded g2 spam",
  128. "Finishing g2",
  129. "Finishing g1",
  130. ])
  131. def test_delegation_of_send(self):
  132. """
  133. Test delegation of send()
  134. """
  135. trace = []
  136. def g1():
  137. trace.append("Starting g1")
  138. x = yield "g1 ham"
  139. trace.append("g1 received %s" % (x,))
  140. yield from g2()
  141. x = yield "g1 eggs"
  142. trace.append("g1 received %s" % (x,))
  143. trace.append("Finishing g1")
  144. def g2():
  145. trace.append("Starting g2")
  146. x = yield "g2 spam"
  147. trace.append("g2 received %s" % (x,))
  148. x = yield "g2 more spam"
  149. trace.append("g2 received %s" % (x,))
  150. trace.append("Finishing g2")
  151. g = g1()
  152. y = next(g)
  153. x = 1
  154. try:
  155. while 1:
  156. y = g.send(x)
  157. trace.append("Yielded %s" % (y,))
  158. x += 1
  159. except StopIteration:
  160. pass
  161. self.assertEqual(trace,[
  162. "Starting g1",
  163. "g1 received 1",
  164. "Starting g2",
  165. "Yielded g2 spam",
  166. "g2 received 2",
  167. "Yielded g2 more spam",
  168. "g2 received 3",
  169. "Finishing g2",
  170. "Yielded g1 eggs",
  171. "g1 received 4",
  172. "Finishing g1",
  173. ])
  174. def test_handling_exception_while_delegating_send(self):
  175. """
  176. Test handling exception while delegating 'send'
  177. """
  178. trace = []
  179. def g1():
  180. trace.append("Starting g1")
  181. x = yield "g1 ham"
  182. trace.append("g1 received %s" % (x,))
  183. yield from g2()
  184. x = yield "g1 eggs"
  185. trace.append("g1 received %s" % (x,))
  186. trace.append("Finishing g1")
  187. def g2():
  188. trace.append("Starting g2")
  189. x = yield "g2 spam"
  190. trace.append("g2 received %s" % (x,))
  191. raise ValueError("hovercraft is full of eels")
  192. x = yield "g2 more spam"
  193. trace.append("g2 received %s" % (x,))
  194. trace.append("Finishing g2")
  195. def run():
  196. g = g1()
  197. y = next(g)
  198. x = 1
  199. try:
  200. while 1:
  201. y = g.send(x)
  202. trace.append("Yielded %s" % (y,))
  203. x += 1
  204. except StopIteration:
  205. trace.append("StopIteration")
  206. self.assertRaises(ValueError,run)
  207. self.assertEqual(trace,[
  208. "Starting g1",
  209. "g1 received 1",
  210. "Starting g2",
  211. "Yielded g2 spam",
  212. "g2 received 2",
  213. ])
  214. def test_delegating_close(self):
  215. """
  216. Test delegating 'close'
  217. """
  218. trace = []
  219. def g1():
  220. try:
  221. trace.append("Starting g1")
  222. yield "g1 ham"
  223. yield from g2()
  224. yield "g1 eggs"
  225. finally:
  226. trace.append("Finishing g1")
  227. def g2():
  228. try:
  229. trace.append("Starting g2")
  230. yield "g2 spam"
  231. yield "g2 more spam"
  232. finally:
  233. trace.append("Finishing g2")
  234. g = g1()
  235. for i in range(2):
  236. x = next(g)
  237. trace.append("Yielded %s" % (x,))
  238. g.close()
  239. self.assertEqual(trace,[
  240. "Starting g1",
  241. "Yielded g1 ham",
  242. "Starting g2",
  243. "Yielded g2 spam",
  244. "Finishing g2",
  245. "Finishing g1"
  246. ])
  247. def test_handing_exception_while_delegating_close(self):
  248. """
  249. Test handling exception while delegating 'close'
  250. """
  251. trace = []
  252. def g1():
  253. try:
  254. trace.append("Starting g1")
  255. yield "g1 ham"
  256. yield from g2()
  257. yield "g1 eggs"
  258. finally:
  259. trace.append("Finishing g1")
  260. def g2():
  261. try:
  262. trace.append("Starting g2")
  263. yield "g2 spam"
  264. yield "g2 more spam"
  265. finally:
  266. trace.append("Finishing g2")
  267. raise ValueError("nybbles have exploded with delight")
  268. try:
  269. g = g1()
  270. for i in range(2):
  271. x = next(g)
  272. trace.append("Yielded %s" % (x,))
  273. g.close()
  274. except ValueError as e:
  275. self.assertEqual(e.args[0], "nybbles have exploded with delight")
  276. self.assertIsInstance(e.__context__, GeneratorExit)
  277. else:
  278. self.fail("subgenerator failed to raise ValueError")
  279. self.assertEqual(trace,[
  280. "Starting g1",
  281. "Yielded g1 ham",
  282. "Starting g2",
  283. "Yielded g2 spam",
  284. "Finishing g2",
  285. "Finishing g1",
  286. ])
  287. def test_delegating_throw(self):
  288. """
  289. Test delegating 'throw'
  290. """
  291. trace = []
  292. def g1():
  293. try:
  294. trace.append("Starting g1")
  295. yield "g1 ham"
  296. yield from g2()
  297. yield "g1 eggs"
  298. finally:
  299. trace.append("Finishing g1")
  300. def g2():
  301. try:
  302. trace.append("Starting g2")
  303. yield "g2 spam"
  304. yield "g2 more spam"
  305. finally:
  306. trace.append("Finishing g2")
  307. try:
  308. g = g1()
  309. for i in range(2):
  310. x = next(g)
  311. trace.append("Yielded %s" % (x,))
  312. e = ValueError("tomato ejected")
  313. g.throw(e)
  314. except ValueError as e:
  315. self.assertEqual(e.args[0], "tomato ejected")
  316. else:
  317. self.fail("subgenerator failed to raise ValueError")
  318. self.assertEqual(trace,[
  319. "Starting g1",
  320. "Yielded g1 ham",
  321. "Starting g2",
  322. "Yielded g2 spam",
  323. "Finishing g2",
  324. "Finishing g1",
  325. ])
  326. def test_value_attribute_of_StopIteration_exception(self):
  327. """
  328. Test 'value' attribute of StopIteration exception
  329. """
  330. trace = []
  331. def pex(e):
  332. trace.append("%s: %s" % (e.__class__.__name__, e))
  333. trace.append("value = %s" % (e.value,))
  334. e = StopIteration()
  335. pex(e)
  336. e = StopIteration("spam")
  337. pex(e)
  338. e.value = "eggs"
  339. pex(e)
  340. self.assertEqual(trace,[
  341. "StopIteration: ",
  342. "value = None",
  343. "StopIteration: spam",
  344. "value = spam",
  345. "StopIteration: spam",
  346. "value = eggs",
  347. ])
  348. def test_exception_value_crash(self):
  349. # There used to be a refcount error when the return value
  350. # stored in the StopIteration has a refcount of 1.
  351. def g1():
  352. yield from g2()
  353. def g2():
  354. yield "g2"
  355. return [42]
  356. self.assertEqual(list(g1()), ["g2"])
  357. def test_generator_return_value(self):
  358. """
  359. Test generator return value
  360. """
  361. trace = []
  362. def g1():
  363. trace.append("Starting g1")
  364. yield "g1 ham"
  365. ret = yield from g2()
  366. trace.append("g2 returned %r" % (ret,))
  367. for v in 1, (2,), StopIteration(3):
  368. ret = yield from g2(v)
  369. trace.append("g2 returned %r" % (ret,))
  370. yield "g1 eggs"
  371. trace.append("Finishing g1")
  372. def g2(v = None):
  373. trace.append("Starting g2")
  374. yield "g2 spam"
  375. yield "g2 more spam"
  376. trace.append("Finishing g2")
  377. if v:
  378. return v
  379. for x in g1():
  380. trace.append("Yielded %s" % (x,))
  381. self.assertEqual(trace,[
  382. "Starting g1",
  383. "Yielded g1 ham",
  384. "Starting g2",
  385. "Yielded g2 spam",
  386. "Yielded g2 more spam",
  387. "Finishing g2",
  388. "g2 returned None",
  389. "Starting g2",
  390. "Yielded g2 spam",
  391. "Yielded g2 more spam",
  392. "Finishing g2",
  393. "g2 returned 1",
  394. "Starting g2",
  395. "Yielded g2 spam",
  396. "Yielded g2 more spam",
  397. "Finishing g2",
  398. "g2 returned (2,)",
  399. "Starting g2",
  400. "Yielded g2 spam",
  401. "Yielded g2 more spam",
  402. "Finishing g2",
  403. "g2 returned StopIteration(3)",
  404. "Yielded g1 eggs",
  405. "Finishing g1",
  406. ])
  407. def test_delegation_of_next_to_non_generator(self):
  408. """
  409. Test delegation of next() to non-generator
  410. """
  411. trace = []
  412. def g():
  413. yield from range(3)
  414. for x in g():
  415. trace.append("Yielded %s" % (x,))
  416. self.assertEqual(trace,[
  417. "Yielded 0",
  418. "Yielded 1",
  419. "Yielded 2",
  420. ])
  421. def test_conversion_of_sendNone_to_next(self):
  422. """
  423. Test conversion of send(None) to next()
  424. """
  425. trace = []
  426. def g():
  427. yield from range(3)
  428. gi = g()
  429. for x in range(3):
  430. y = gi.send(None)
  431. trace.append("Yielded: %s" % (y,))
  432. self.assertEqual(trace,[
  433. "Yielded: 0",
  434. "Yielded: 1",
  435. "Yielded: 2",
  436. ])
  437. def test_delegation_of_close_to_non_generator(self):
  438. """
  439. Test delegation of close() to non-generator
  440. """
  441. trace = []
  442. def g():
  443. try:
  444. trace.append("starting g")
  445. yield from range(3)
  446. trace.append("g should not be here")
  447. finally:
  448. trace.append("finishing g")
  449. gi = g()
  450. next(gi)
  451. with captured_stderr() as output:
  452. gi.close()
  453. self.assertEqual(output.getvalue(), '')
  454. self.assertEqual(trace,[
  455. "starting g",
  456. "finishing g",
  457. ])
  458. def test_delegating_throw_to_non_generator(self):
  459. """
  460. Test delegating 'throw' to non-generator
  461. """
  462. trace = []
  463. def g():
  464. try:
  465. trace.append("Starting g")
  466. yield from range(10)
  467. finally:
  468. trace.append("Finishing g")
  469. try:
  470. gi = g()
  471. for i in range(5):
  472. x = next(gi)
  473. trace.append("Yielded %s" % (x,))
  474. e = ValueError("tomato ejected")
  475. gi.throw(e)
  476. except ValueError as e:
  477. self.assertEqual(e.args[0],"tomato ejected")
  478. else:
  479. self.fail("subgenerator failed to raise ValueError")
  480. self.assertEqual(trace,[
  481. "Starting g",
  482. "Yielded 0",
  483. "Yielded 1",
  484. "Yielded 2",
  485. "Yielded 3",
  486. "Yielded 4",
  487. "Finishing g",
  488. ])
  489. def test_attempting_to_send_to_non_generator(self):
  490. """
  491. Test attempting to send to non-generator
  492. """
  493. trace = []
  494. def g():
  495. try:
  496. trace.append("starting g")
  497. yield from range(3)
  498. trace.append("g should not be here")
  499. finally:
  500. trace.append("finishing g")
  501. try:
  502. gi = g()
  503. next(gi)
  504. for x in range(3):
  505. y = gi.send(42)
  506. trace.append("Should not have yielded: %s" % (y,))
  507. except AttributeError as e:
  508. self.assertIn("send", e.args[0])
  509. else:
  510. self.fail("was able to send into non-generator")
  511. self.assertEqual(trace,[
  512. "starting g",
  513. "finishing g",
  514. ])
  515. def test_broken_getattr_handling(self):
  516. """
  517. Test subiterator with a broken getattr implementation
  518. """
  519. class Broken:
  520. def __iter__(self):
  521. return self
  522. def __next__(self):
  523. return 1
  524. def __getattr__(self, attr):
  525. 1/0
  526. def g():
  527. yield from Broken()
  528. with self.assertRaises(ZeroDivisionError):
  529. gi = g()
  530. self.assertEqual(next(gi), 1)
  531. gi.send(1)
  532. with self.assertRaises(ZeroDivisionError):
  533. gi = g()
  534. self.assertEqual(next(gi), 1)
  535. gi.throw(AttributeError)
  536. with support.catch_unraisable_exception() as cm:
  537. gi = g()
  538. self.assertEqual(next(gi), 1)
  539. gi.close()
  540. self.assertEqual(ZeroDivisionError, cm.unraisable.exc_type)
  541. def test_exception_in_initial_next_call(self):
  542. """
  543. Test exception in initial next() call
  544. """
  545. trace = []
  546. def g1():
  547. trace.append("g1 about to yield from g2")
  548. yield from g2()
  549. trace.append("g1 should not be here")
  550. def g2():
  551. yield 1/0
  552. def run():
  553. gi = g1()
  554. next(gi)
  555. self.assertRaises(ZeroDivisionError,run)
  556. self.assertEqual(trace,[
  557. "g1 about to yield from g2"
  558. ])
  559. def test_attempted_yield_from_loop(self):
  560. """
  561. Test attempted yield-from loop
  562. """
  563. trace = []
  564. def g1():
  565. trace.append("g1: starting")
  566. yield "y1"
  567. trace.append("g1: about to yield from g2")
  568. yield from g2()
  569. trace.append("g1 should not be here")
  570. def g2():
  571. trace.append("g2: starting")
  572. yield "y2"
  573. trace.append("g2: about to yield from g1")
  574. yield from gi
  575. trace.append("g2 should not be here")
  576. try:
  577. gi = g1()
  578. for y in gi:
  579. trace.append("Yielded: %s" % (y,))
  580. except ValueError as e:
  581. self.assertEqual(e.args[0],"generator already executing")
  582. else:
  583. self.fail("subgenerator didn't raise ValueError")
  584. self.assertEqual(trace,[
  585. "g1: starting",
  586. "Yielded: y1",
  587. "g1: about to yield from g2",
  588. "g2: starting",
  589. "Yielded: y2",
  590. "g2: about to yield from g1",
  591. ])
  592. def test_returning_value_from_delegated_throw(self):
  593. """
  594. Test returning value from delegated 'throw'
  595. """
  596. trace = []
  597. def g1():
  598. try:
  599. trace.append("Starting g1")
  600. yield "g1 ham"
  601. yield from g2()
  602. yield "g1 eggs"
  603. finally:
  604. trace.append("Finishing g1")
  605. def g2():
  606. try:
  607. trace.append("Starting g2")
  608. yield "g2 spam"
  609. yield "g2 more spam"
  610. except LunchError:
  611. trace.append("Caught LunchError in g2")
  612. yield "g2 lunch saved"
  613. yield "g2 yet more spam"
  614. class LunchError(Exception):
  615. pass
  616. g = g1()
  617. for i in range(2):
  618. x = next(g)
  619. trace.append("Yielded %s" % (x,))
  620. e = LunchError("tomato ejected")
  621. g.throw(e)
  622. for x in g:
  623. trace.append("Yielded %s" % (x,))
  624. self.assertEqual(trace,[
  625. "Starting g1",
  626. "Yielded g1 ham",
  627. "Starting g2",
  628. "Yielded g2 spam",
  629. "Caught LunchError in g2",
  630. "Yielded g2 yet more spam",
  631. "Yielded g1 eggs",
  632. "Finishing g1",
  633. ])
  634. def test_next_and_return_with_value(self):
  635. """
  636. Test next and return with value
  637. """
  638. trace = []
  639. def f(r):
  640. gi = g(r)
  641. next(gi)
  642. try:
  643. trace.append("f resuming g")
  644. next(gi)
  645. trace.append("f SHOULD NOT BE HERE")
  646. except StopIteration as e:
  647. trace.append("f caught %r" % (e,))
  648. def g(r):
  649. trace.append("g starting")
  650. yield
  651. trace.append("g returning %r" % (r,))
  652. return r
  653. f(None)
  654. f(1)
  655. f((2,))
  656. f(StopIteration(3))
  657. self.assertEqual(trace,[
  658. "g starting",
  659. "f resuming g",
  660. "g returning None",
  661. "f caught StopIteration()",
  662. "g starting",
  663. "f resuming g",
  664. "g returning 1",
  665. "f caught StopIteration(1)",
  666. "g starting",
  667. "f resuming g",
  668. "g returning (2,)",
  669. "f caught StopIteration((2,))",
  670. "g starting",
  671. "f resuming g",
  672. "g returning StopIteration(3)",
  673. "f caught StopIteration(StopIteration(3))",
  674. ])
  675. def test_send_and_return_with_value(self):
  676. """
  677. Test send and return with value
  678. """
  679. trace = []
  680. def f(r):
  681. gi = g(r)
  682. next(gi)
  683. try:
  684. trace.append("f sending spam to g")
  685. gi.send("spam")
  686. trace.append("f SHOULD NOT BE HERE")
  687. except StopIteration as e:
  688. trace.append("f caught %r" % (e,))
  689. def g(r):
  690. trace.append("g starting")
  691. x = yield
  692. trace.append("g received %r" % (x,))
  693. trace.append("g returning %r" % (r,))
  694. return r
  695. f(None)
  696. f(1)
  697. f((2,))
  698. f(StopIteration(3))
  699. self.assertEqual(trace, [
  700. "g starting",
  701. "f sending spam to g",
  702. "g received 'spam'",
  703. "g returning None",
  704. "f caught StopIteration()",
  705. "g starting",
  706. "f sending spam to g",
  707. "g received 'spam'",
  708. "g returning 1",
  709. 'f caught StopIteration(1)',
  710. 'g starting',
  711. 'f sending spam to g',
  712. "g received 'spam'",
  713. 'g returning (2,)',
  714. 'f caught StopIteration((2,))',
  715. 'g starting',
  716. 'f sending spam to g',
  717. "g received 'spam'",
  718. 'g returning StopIteration(3)',
  719. 'f caught StopIteration(StopIteration(3))'
  720. ])
  721. def test_catching_exception_from_subgen_and_returning(self):
  722. """
  723. Test catching an exception thrown into a
  724. subgenerator and returning a value
  725. """
  726. def inner():
  727. try:
  728. yield 1
  729. except ValueError:
  730. trace.append("inner caught ValueError")
  731. return value
  732. def outer():
  733. v = yield from inner()
  734. trace.append("inner returned %r to outer" % (v,))
  735. yield v
  736. for value in 2, (2,), StopIteration(2):
  737. trace = []
  738. g = outer()
  739. trace.append(next(g))
  740. trace.append(repr(g.throw(ValueError)))
  741. self.assertEqual(trace, [
  742. 1,
  743. "inner caught ValueError",
  744. "inner returned %r to outer" % (value,),
  745. repr(value),
  746. ])
  747. def test_throwing_GeneratorExit_into_subgen_that_returns(self):
  748. """
  749. Test throwing GeneratorExit into a subgenerator that
  750. catches it and returns normally.
  751. """
  752. trace = []
  753. def f():
  754. try:
  755. trace.append("Enter f")
  756. yield
  757. trace.append("Exit f")
  758. except GeneratorExit:
  759. return
  760. def g():
  761. trace.append("Enter g")
  762. yield from f()
  763. trace.append("Exit g")
  764. try:
  765. gi = g()
  766. next(gi)
  767. gi.throw(GeneratorExit)
  768. except GeneratorExit:
  769. pass
  770. else:
  771. self.fail("subgenerator failed to raise GeneratorExit")
  772. self.assertEqual(trace,[
  773. "Enter g",
  774. "Enter f",
  775. ])
  776. def test_throwing_GeneratorExit_into_subgenerator_that_yields(self):
  777. """
  778. Test throwing GeneratorExit into a subgenerator that
  779. catches it and yields.
  780. """
  781. trace = []
  782. def f():
  783. try:
  784. trace.append("Enter f")
  785. yield
  786. trace.append("Exit f")
  787. except GeneratorExit:
  788. yield
  789. def g():
  790. trace.append("Enter g")
  791. yield from f()
  792. trace.append("Exit g")
  793. try:
  794. gi = g()
  795. next(gi)
  796. gi.throw(GeneratorExit)
  797. except RuntimeError as e:
  798. self.assertEqual(e.args[0], "generator ignored GeneratorExit")
  799. else:
  800. self.fail("subgenerator failed to raise GeneratorExit")
  801. self.assertEqual(trace,[
  802. "Enter g",
  803. "Enter f",
  804. ])
  805. def test_throwing_GeneratorExit_into_subgen_that_raises(self):
  806. """
  807. Test throwing GeneratorExit into a subgenerator that
  808. catches it and raises a different exception.
  809. """
  810. trace = []
  811. def f():
  812. try:
  813. trace.append("Enter f")
  814. yield
  815. trace.append("Exit f")
  816. except GeneratorExit:
  817. raise ValueError("Vorpal bunny encountered")
  818. def g():
  819. trace.append("Enter g")
  820. yield from f()
  821. trace.append("Exit g")
  822. try:
  823. gi = g()
  824. next(gi)
  825. gi.throw(GeneratorExit)
  826. except ValueError as e:
  827. self.assertEqual(e.args[0], "Vorpal bunny encountered")
  828. self.assertIsInstance(e.__context__, GeneratorExit)
  829. else:
  830. self.fail("subgenerator failed to raise ValueError")
  831. self.assertEqual(trace,[
  832. "Enter g",
  833. "Enter f",
  834. ])
  835. def test_yield_from_empty(self):
  836. def g():
  837. yield from ()
  838. self.assertRaises(StopIteration, next, g())
  839. def test_delegating_generators_claim_to_be_running(self):
  840. # Check with basic iteration
  841. def one():
  842. yield 0
  843. yield from two()
  844. yield 3
  845. def two():
  846. yield 1
  847. try:
  848. yield from g1
  849. except ValueError:
  850. pass
  851. yield 2
  852. g1 = one()
  853. self.assertEqual(list(g1), [0, 1, 2, 3])
  854. # Check with send
  855. g1 = one()
  856. res = [next(g1)]
  857. try:
  858. while True:
  859. res.append(g1.send(42))
  860. except StopIteration:
  861. pass
  862. self.assertEqual(res, [0, 1, 2, 3])
  863. # Check with throw
  864. class MyErr(Exception):
  865. pass
  866. def one():
  867. try:
  868. yield 0
  869. except MyErr:
  870. pass
  871. yield from two()
  872. try:
  873. yield 3
  874. except MyErr:
  875. pass
  876. def two():
  877. try:
  878. yield 1
  879. except MyErr:
  880. pass
  881. try:
  882. yield from g1
  883. except ValueError:
  884. pass
  885. try:
  886. yield 2
  887. except MyErr:
  888. pass
  889. g1 = one()
  890. res = [next(g1)]
  891. try:
  892. while True:
  893. res.append(g1.throw(MyErr))
  894. except StopIteration:
  895. pass
  896. except:
  897. self.assertEqual(res, [0, 1, 2, 3])
  898. raise
  899. # Check with close
  900. class MyIt(object):
  901. def __iter__(self):
  902. return self
  903. def __next__(self):
  904. return 42
  905. def close(self_):
  906. self.assertTrue(g1.gi_running)
  907. self.assertRaises(ValueError, next, g1)
  908. def one():
  909. yield from MyIt()
  910. g1 = one()
  911. next(g1)
  912. g1.close()
  913. def test_delegator_is_visible_to_debugger(self):
  914. def call_stack():
  915. return [f[3] for f in inspect.stack()]
  916. def gen():
  917. yield call_stack()
  918. yield call_stack()
  919. yield call_stack()
  920. def spam(g):
  921. yield from g
  922. def eggs(g):
  923. yield from g
  924. for stack in spam(gen()):
  925. self.assertTrue('spam' in stack)
  926. for stack in spam(eggs(gen())):
  927. self.assertTrue('spam' in stack and 'eggs' in stack)
  928. def test_custom_iterator_return(self):
  929. # See issue #15568
  930. class MyIter:
  931. def __iter__(self):
  932. return self
  933. def __next__(self):
  934. raise StopIteration(42)
  935. def gen():
  936. nonlocal ret
  937. ret = yield from MyIter()
  938. ret = None
  939. list(gen())
  940. self.assertEqual(ret, 42)
  941. def test_close_with_cleared_frame(self):
  942. # See issue #17669.
  943. #
  944. # Create a stack of generators: outer() delegating to inner()
  945. # delegating to innermost(). The key point is that the instance of
  946. # inner is created first: this ensures that its frame appears before
  947. # the instance of outer in the GC linked list.
  948. #
  949. # At the gc.collect call:
  950. # - frame_clear is called on the inner_gen frame.
  951. # - gen_dealloc is called on the outer_gen generator (the only
  952. # reference is in the frame's locals).
  953. # - gen_close is called on the outer_gen generator.
  954. # - gen_close_iter is called to close the inner_gen generator, which
  955. # in turn calls gen_close, and gen_yf.
  956. #
  957. # Previously, gen_yf would crash since inner_gen's frame had been
  958. # cleared (and in particular f_stacktop was NULL).
  959. def innermost():
  960. yield
  961. def inner():
  962. outer_gen = yield
  963. yield from innermost()
  964. def outer():
  965. inner_gen = yield
  966. yield from inner_gen
  967. with disable_gc():
  968. inner_gen = inner()
  969. outer_gen = outer()
  970. outer_gen.send(None)
  971. outer_gen.send(inner_gen)
  972. outer_gen.send(outer_gen)
  973. del outer_gen
  974. del inner_gen
  975. gc_collect()
  976. def test_send_tuple_with_custom_generator(self):
  977. # See issue #21209.
  978. class MyGen:
  979. def __iter__(self):
  980. return self
  981. def __next__(self):
  982. return 42
  983. def send(self, what):
  984. nonlocal v
  985. v = what
  986. return None
  987. def outer():
  988. v = yield from MyGen()
  989. g = outer()
  990. next(g)
  991. v = None
  992. g.send((1, 2, 3, 4))
  993. self.assertEqual(v, (1, 2, 3, 4))
  994. if __name__ == '__main__':
  995. unittest.main()