17db96d56Sopenharmony_ciimport sys 27db96d56Sopenharmony_ciimport doctest 37db96d56Sopenharmony_ciimport unittest 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_cidoctests = """ 77db96d56Sopenharmony_ci 87db96d56Sopenharmony_ciTest simple loop with conditional 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ci >>> sum(i*i for i in range(100) if i&1 == 1) 117db96d56Sopenharmony_ci 166650 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ciTest simple nesting 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ci >>> list((i,j) for i in range(3) for j in range(4) ) 167db96d56Sopenharmony_ci [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ciTest nesting with the inner expression dependent on the outer 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_ci >>> list((i,j) for i in range(4) for j in range(i) ) 217db96d56Sopenharmony_ci [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)] 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ciTest the idiom for temporary variable assignment in comprehensions. 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ci >>> list((j*j for i in range(4) for j in [i+1])) 267db96d56Sopenharmony_ci [1, 4, 9, 16] 277db96d56Sopenharmony_ci >>> list((j*k for i in range(4) for j in [i+1] for k in [j+1])) 287db96d56Sopenharmony_ci [2, 6, 12, 20] 297db96d56Sopenharmony_ci >>> list((j*k for i in range(4) for j, k in [(i+1, i+2)])) 307db96d56Sopenharmony_ci [2, 6, 12, 20] 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_ciNot assignment 337db96d56Sopenharmony_ci 347db96d56Sopenharmony_ci >>> list((i*i for i in [*range(4)])) 357db96d56Sopenharmony_ci [0, 1, 4, 9] 367db96d56Sopenharmony_ci >>> list((i*i for i in (*range(4),))) 377db96d56Sopenharmony_ci [0, 1, 4, 9] 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ciMake sure the induction variable is not exposed 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ci >>> i = 20 427db96d56Sopenharmony_ci >>> sum(i*i for i in range(100)) 437db96d56Sopenharmony_ci 328350 447db96d56Sopenharmony_ci >>> i 457db96d56Sopenharmony_ci 20 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ciTest first class 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_ci >>> g = (i*i for i in range(4)) 507db96d56Sopenharmony_ci >>> type(g) 517db96d56Sopenharmony_ci <class 'generator'> 527db96d56Sopenharmony_ci >>> list(g) 537db96d56Sopenharmony_ci [0, 1, 4, 9] 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ciTest direct calls to next() 567db96d56Sopenharmony_ci 577db96d56Sopenharmony_ci >>> g = (i*i for i in range(3)) 587db96d56Sopenharmony_ci >>> next(g) 597db96d56Sopenharmony_ci 0 607db96d56Sopenharmony_ci >>> next(g) 617db96d56Sopenharmony_ci 1 627db96d56Sopenharmony_ci >>> next(g) 637db96d56Sopenharmony_ci 4 647db96d56Sopenharmony_ci >>> next(g) 657db96d56Sopenharmony_ci Traceback (most recent call last): 667db96d56Sopenharmony_ci File "<pyshell#21>", line 1, in -toplevel- 677db96d56Sopenharmony_ci next(g) 687db96d56Sopenharmony_ci StopIteration 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ciDoes it stay stopped? 717db96d56Sopenharmony_ci 727db96d56Sopenharmony_ci >>> next(g) 737db96d56Sopenharmony_ci Traceback (most recent call last): 747db96d56Sopenharmony_ci File "<pyshell#21>", line 1, in -toplevel- 757db96d56Sopenharmony_ci next(g) 767db96d56Sopenharmony_ci StopIteration 777db96d56Sopenharmony_ci >>> list(g) 787db96d56Sopenharmony_ci [] 797db96d56Sopenharmony_ci 807db96d56Sopenharmony_ciTest running gen when defining function is out of scope 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ci >>> def f(n): 837db96d56Sopenharmony_ci ... return (i*i for i in range(n)) 847db96d56Sopenharmony_ci >>> list(f(10)) 857db96d56Sopenharmony_ci [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 867db96d56Sopenharmony_ci 877db96d56Sopenharmony_ci >>> def f(n): 887db96d56Sopenharmony_ci ... return ((i,j) for i in range(3) for j in range(n)) 897db96d56Sopenharmony_ci >>> list(f(4)) 907db96d56Sopenharmony_ci [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] 917db96d56Sopenharmony_ci >>> def f(n): 927db96d56Sopenharmony_ci ... return ((i,j) for i in range(3) for j in range(4) if j in range(n)) 937db96d56Sopenharmony_ci >>> list(f(4)) 947db96d56Sopenharmony_ci [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] 957db96d56Sopenharmony_ci >>> list(f(2)) 967db96d56Sopenharmony_ci [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)] 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_ciVerify that parenthesis are required in a statement 997db96d56Sopenharmony_ci 1007db96d56Sopenharmony_ci >>> def f(n): 1017db96d56Sopenharmony_ci ... return i*i for i in range(n) 1027db96d56Sopenharmony_ci Traceback (most recent call last): 1037db96d56Sopenharmony_ci ... 1047db96d56Sopenharmony_ci SyntaxError: invalid syntax 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_ciVerify that parenthesis are required when used as a keyword argument value 1077db96d56Sopenharmony_ci 1087db96d56Sopenharmony_ci >>> dict(a = i for i in range(10)) 1097db96d56Sopenharmony_ci Traceback (most recent call last): 1107db96d56Sopenharmony_ci ... 1117db96d56Sopenharmony_ci SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='? 1127db96d56Sopenharmony_ci 1137db96d56Sopenharmony_ciVerify that parenthesis are required when used as a keyword argument value 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ci >>> dict(a = (i for i in range(10))) #doctest: +ELLIPSIS 1167db96d56Sopenharmony_ci {'a': <generator object <genexpr> at ...>} 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_ciVerify early binding for the outermost for-expression 1197db96d56Sopenharmony_ci 1207db96d56Sopenharmony_ci >>> x=10 1217db96d56Sopenharmony_ci >>> g = (i*i for i in range(x)) 1227db96d56Sopenharmony_ci >>> x = 5 1237db96d56Sopenharmony_ci >>> list(g) 1247db96d56Sopenharmony_ci [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_ciVerify that the outermost for-expression makes an immediate check 1277db96d56Sopenharmony_cifor iterability 1287db96d56Sopenharmony_ci 1297db96d56Sopenharmony_ci >>> (i for i in 6) 1307db96d56Sopenharmony_ci Traceback (most recent call last): 1317db96d56Sopenharmony_ci File "<pyshell#4>", line 1, in -toplevel- 1327db96d56Sopenharmony_ci (i for i in 6) 1337db96d56Sopenharmony_ci TypeError: 'int' object is not iterable 1347db96d56Sopenharmony_ci 1357db96d56Sopenharmony_ciVerify late binding for the outermost if-expression 1367db96d56Sopenharmony_ci 1377db96d56Sopenharmony_ci >>> include = (2,4,6,8) 1387db96d56Sopenharmony_ci >>> g = (i*i for i in range(10) if i in include) 1397db96d56Sopenharmony_ci >>> include = (1,3,5,7,9) 1407db96d56Sopenharmony_ci >>> list(g) 1417db96d56Sopenharmony_ci [1, 9, 25, 49, 81] 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ciVerify late binding for the innermost for-expression 1447db96d56Sopenharmony_ci 1457db96d56Sopenharmony_ci >>> g = ((i,j) for i in range(3) for j in range(x)) 1467db96d56Sopenharmony_ci >>> x = 4 1477db96d56Sopenharmony_ci >>> list(g) 1487db96d56Sopenharmony_ci [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] 1497db96d56Sopenharmony_ci 1507db96d56Sopenharmony_ciVerify re-use of tuples (a side benefit of using genexps over listcomps) 1517db96d56Sopenharmony_ci 1527db96d56Sopenharmony_ci >>> tupleids = list(map(id, ((i,i) for i in range(10)))) 1537db96d56Sopenharmony_ci >>> int(max(tupleids) - min(tupleids)) 1547db96d56Sopenharmony_ci 0 1557db96d56Sopenharmony_ci 1567db96d56Sopenharmony_ciVerify that syntax error's are raised for genexps used as lvalues 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci >>> (y for y in (1,2)) = 10 1597db96d56Sopenharmony_ci Traceback (most recent call last): 1607db96d56Sopenharmony_ci ... 1617db96d56Sopenharmony_ci SyntaxError: cannot assign to generator expression 1627db96d56Sopenharmony_ci 1637db96d56Sopenharmony_ci >>> (y for y in (1,2)) += 10 1647db96d56Sopenharmony_ci Traceback (most recent call last): 1657db96d56Sopenharmony_ci ... 1667db96d56Sopenharmony_ci SyntaxError: 'generator expression' is an illegal expression for augmented assignment 1677db96d56Sopenharmony_ci 1687db96d56Sopenharmony_ci 1697db96d56Sopenharmony_ci########### Tests borrowed from or inspired by test_generators.py ############ 1707db96d56Sopenharmony_ci 1717db96d56Sopenharmony_ciMake a generator that acts like range() 1727db96d56Sopenharmony_ci 1737db96d56Sopenharmony_ci >>> yrange = lambda n: (i for i in range(n)) 1747db96d56Sopenharmony_ci >>> list(yrange(10)) 1757db96d56Sopenharmony_ci [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 1767db96d56Sopenharmony_ci 1777db96d56Sopenharmony_ciGenerators always return to the most recent caller: 1787db96d56Sopenharmony_ci 1797db96d56Sopenharmony_ci >>> def creator(): 1807db96d56Sopenharmony_ci ... r = yrange(5) 1817db96d56Sopenharmony_ci ... print("creator", next(r)) 1827db96d56Sopenharmony_ci ... return r 1837db96d56Sopenharmony_ci >>> def caller(): 1847db96d56Sopenharmony_ci ... r = creator() 1857db96d56Sopenharmony_ci ... for i in r: 1867db96d56Sopenharmony_ci ... print("caller", i) 1877db96d56Sopenharmony_ci >>> caller() 1887db96d56Sopenharmony_ci creator 0 1897db96d56Sopenharmony_ci caller 1 1907db96d56Sopenharmony_ci caller 2 1917db96d56Sopenharmony_ci caller 3 1927db96d56Sopenharmony_ci caller 4 1937db96d56Sopenharmony_ci 1947db96d56Sopenharmony_ciGenerators can call other generators: 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci >>> def zrange(n): 1977db96d56Sopenharmony_ci ... for i in yrange(n): 1987db96d56Sopenharmony_ci ... yield i 1997db96d56Sopenharmony_ci >>> list(zrange(5)) 2007db96d56Sopenharmony_ci [0, 1, 2, 3, 4] 2017db96d56Sopenharmony_ci 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_ciVerify that a gen exp cannot be resumed while it is actively running: 2047db96d56Sopenharmony_ci 2057db96d56Sopenharmony_ci >>> g = (next(me) for i in range(10)) 2067db96d56Sopenharmony_ci >>> me = g 2077db96d56Sopenharmony_ci >>> next(me) 2087db96d56Sopenharmony_ci Traceback (most recent call last): 2097db96d56Sopenharmony_ci File "<pyshell#30>", line 1, in -toplevel- 2107db96d56Sopenharmony_ci next(me) 2117db96d56Sopenharmony_ci File "<pyshell#28>", line 1, in <generator expression> 2127db96d56Sopenharmony_ci g = (next(me) for i in range(10)) 2137db96d56Sopenharmony_ci ValueError: generator already executing 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ciVerify exception propagation 2167db96d56Sopenharmony_ci 2177db96d56Sopenharmony_ci >>> g = (10 // i for i in (5, 0, 2)) 2187db96d56Sopenharmony_ci >>> next(g) 2197db96d56Sopenharmony_ci 2 2207db96d56Sopenharmony_ci >>> next(g) 2217db96d56Sopenharmony_ci Traceback (most recent call last): 2227db96d56Sopenharmony_ci File "<pyshell#37>", line 1, in -toplevel- 2237db96d56Sopenharmony_ci next(g) 2247db96d56Sopenharmony_ci File "<pyshell#35>", line 1, in <generator expression> 2257db96d56Sopenharmony_ci g = (10 // i for i in (5, 0, 2)) 2267db96d56Sopenharmony_ci ZeroDivisionError: integer division or modulo by zero 2277db96d56Sopenharmony_ci >>> next(g) 2287db96d56Sopenharmony_ci Traceback (most recent call last): 2297db96d56Sopenharmony_ci File "<pyshell#38>", line 1, in -toplevel- 2307db96d56Sopenharmony_ci next(g) 2317db96d56Sopenharmony_ci StopIteration 2327db96d56Sopenharmony_ci 2337db96d56Sopenharmony_ciMake sure that None is a valid return value 2347db96d56Sopenharmony_ci 2357db96d56Sopenharmony_ci >>> list(None for i in range(10)) 2367db96d56Sopenharmony_ci [None, None, None, None, None, None, None, None, None, None] 2377db96d56Sopenharmony_ci 2387db96d56Sopenharmony_ciCheck that generator attributes are present 2397db96d56Sopenharmony_ci 2407db96d56Sopenharmony_ci >>> g = (i*i for i in range(3)) 2417db96d56Sopenharmony_ci >>> expected = set(['gi_frame', 'gi_running']) 2427db96d56Sopenharmony_ci >>> set(attr for attr in dir(g) if not attr.startswith('__')) >= expected 2437db96d56Sopenharmony_ci True 2447db96d56Sopenharmony_ci 2457db96d56Sopenharmony_ci >>> from test.support import HAVE_DOCSTRINGS 2467db96d56Sopenharmony_ci >>> print(g.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implement next(self).') 2477db96d56Sopenharmony_ci Implement next(self). 2487db96d56Sopenharmony_ci >>> import types 2497db96d56Sopenharmony_ci >>> isinstance(g, types.GeneratorType) 2507db96d56Sopenharmony_ci True 2517db96d56Sopenharmony_ci 2527db96d56Sopenharmony_ciCheck the __iter__ slot is defined to return self 2537db96d56Sopenharmony_ci 2547db96d56Sopenharmony_ci >>> iter(g) is g 2557db96d56Sopenharmony_ci True 2567db96d56Sopenharmony_ci 2577db96d56Sopenharmony_ciVerify that the running flag is set properly 2587db96d56Sopenharmony_ci 2597db96d56Sopenharmony_ci >>> g = (me.gi_running for i in (0,1)) 2607db96d56Sopenharmony_ci >>> me = g 2617db96d56Sopenharmony_ci >>> me.gi_running 2627db96d56Sopenharmony_ci 0 2637db96d56Sopenharmony_ci >>> next(me) 2647db96d56Sopenharmony_ci 1 2657db96d56Sopenharmony_ci >>> me.gi_running 2667db96d56Sopenharmony_ci 0 2677db96d56Sopenharmony_ci 2687db96d56Sopenharmony_ciVerify that genexps are weakly referencable 2697db96d56Sopenharmony_ci 2707db96d56Sopenharmony_ci >>> import weakref 2717db96d56Sopenharmony_ci >>> g = (i*i for i in range(4)) 2727db96d56Sopenharmony_ci >>> wr = weakref.ref(g) 2737db96d56Sopenharmony_ci >>> wr() is g 2747db96d56Sopenharmony_ci True 2757db96d56Sopenharmony_ci >>> p = weakref.proxy(g) 2767db96d56Sopenharmony_ci >>> list(p) 2777db96d56Sopenharmony_ci [0, 1, 4, 9] 2787db96d56Sopenharmony_ci 2797db96d56Sopenharmony_ci 2807db96d56Sopenharmony_ci""" 2817db96d56Sopenharmony_ci 2827db96d56Sopenharmony_ci# Trace function can throw off the tuple reuse test. 2837db96d56Sopenharmony_ciif hasattr(sys, 'gettrace') and sys.gettrace(): 2847db96d56Sopenharmony_ci __test__ = {} 2857db96d56Sopenharmony_cielse: 2867db96d56Sopenharmony_ci __test__ = {'doctests' : doctests} 2877db96d56Sopenharmony_ci 2887db96d56Sopenharmony_cidef load_tests(loader, tests, pattern): 2897db96d56Sopenharmony_ci tests.addTest(doctest.DocTestSuite()) 2907db96d56Sopenharmony_ci return tests 2917db96d56Sopenharmony_ci 2927db96d56Sopenharmony_ci 2937db96d56Sopenharmony_ciif __name__ == "__main__": 2947db96d56Sopenharmony_ci unittest.main() 295