1# cython: language_level=3, binding=True, annotation_typing=False
2# mode: run
3# tag: generators, python3, exceptions, gh2230, gh2811
4
5print(end='')  # test that language_level 3 applies immediately at the module start, for the first token.
6
7cimport cython
8
9__doc__ = """
10>>> items = sorted(locals_function(1).items())
11>>> for item in items:
12...     print('%s = %r' % item)
13a = 1
14b = 2
15x = u'abc'
16
17>>> except_as_deletes
18True
19>>> no_match_does_not_touch_target
20True
21"""
22
23import sys
24IS_PY2 = sys.version_info[0] < 3
25if not IS_PY2:
26    __doc__ = __doc__.replace(" u'", " '")
27
28def locals_function(a, b=2):
29    x = 'abc'
30    return locals()
31
32
33### true division
34
35def truediv(x):
36    """
37    >>> truediv(4)
38    2.0
39    >>> truediv(3)
40    1.5
41    """
42    return x / 2
43
44
45def truediv_int(int x):
46    """
47    >>> truediv_int(4)
48    2.0
49    >>> truediv_int(3)
50    1.5
51    """
52    return x / 2
53
54
55@cython.cdivision(True)
56def cdiv_int(int x):
57    """
58    >>> cdiv_int(4)
59    2
60    >>> cdiv_int(3)
61    1
62    """
63    return x / 2
64
65
66### module level except-as tests
67
68exc = [None]
69e = None
70try:
71    raise KeyError
72except AttributeError as e:
73    exc[0] = e
74except KeyError       as e:
75    exc[0] = e
76except IndexError     as e:
77    exc[0] = e
78except:
79    exc[0] = 'SOMETHING ELSE'
80
81try:
82    e
83except NameError:
84    except_as_deletes = True
85else:
86    except_as_deletes = False
87
88
89e = 123
90try:
91    raise TypeError
92except NameError as e:
93    pass
94except TypeError:
95    pass
96no_match_does_not_touch_target = (e == 123)
97
98
99### more except-as tests
100
101def except_as_no_raise_does_not_touch_target(a):
102    """
103    >>> except_as_no_raise_does_not_touch_target(TypeError)
104    (1, 1)
105    """
106    d = a  # mark used
107
108    b = 1
109    try:
110        i = 1
111    except a as b:
112        i = 2
113    return i, b
114
115
116def except_as_raise_deletes_target(x, a):
117    """
118    >>> except_as_raise_deletes_target(None, TypeError)
119    1
120    1
121    >>> except_as_raise_deletes_target(TypeError('test'), TypeError)
122    Traceback (most recent call last):
123    UnboundLocalError: local variable 'b' referenced before assignment
124    >>> except_as_raise_deletes_target(ValueError('test'), TypeError)
125    Traceback (most recent call last):
126    ValueError: test
127    >>> except_as_raise_deletes_target(None, TypeError)
128    1
129    1
130    """
131    b = 1
132    try:
133        i = 1
134        if x:
135            raise x
136    except a as b:
137        i = 2
138        assert isinstance(b, a)
139    print(b)  # raises UnboundLocalError if except clause was executed
140    return i
141
142
143def except_as_raise_deletes_target_even_after_del(x, a):
144    """
145    >>> except_as_raise_deletes_target_even_after_del(None, TypeError)
146    1
147    1
148    >>> except_as_raise_deletes_target_even_after_del(TypeError('test'), TypeError)
149    2
150    >>> except_as_raise_deletes_target_even_after_del(ValueError('test'), TypeError)
151    Traceback (most recent call last):
152    ValueError: test
153    >>> except_as_raise_deletes_target_even_after_del(None, TypeError)
154    1
155    1
156    """
157    b = 1
158    try:
159        i = 1
160        if x:
161            raise x
162    except a as b:
163        i = 2
164        assert isinstance(b, a)
165        del b  # let's see if Cython can still 'del' it after this line!
166    try:
167        print(b)  # raises UnboundLocalError if except clause was executed
168    except UnboundLocalError:
169        pass
170    else:
171        if x:
172            print("UnboundLocalError not raised!")
173    return i
174
175
176def except_as_raise_deletes_target_on_error(x, a):
177    """
178    >>> except_as_raise_deletes_target_on_error(None, TypeError)
179    1
180    1
181    >>> except_as_raise_deletes_target_on_error(TypeError('test'), TypeError)
182    Traceback (most recent call last):
183    UnboundLocalError: local variable 'b' referenced before assignment
184    >>> except_as_raise_deletes_target_on_error(ValueError('test'), TypeError)
185    Traceback (most recent call last):
186    ValueError: test
187    >>> except_as_raise_deletes_target_on_error(None, TypeError)
188    1
189    1
190    """
191    b = 1
192    try:
193        try:
194            i = 1
195            if x:
196                raise x
197        except a as b:
198            i = 2
199            raise IndexError("TEST")
200    except IndexError as e:
201        assert 'TEST' in str(e), str(e)
202    print(b)  # raises UnboundLocalError if except clause was executed
203    return i
204
205
206def except_as_raise_with_empty_except(x, a):
207    """
208    >>> except_as_raise_with_empty_except(None, TypeError)
209    1
210    >>> except_as_raise_with_empty_except(TypeError('test'), TypeError)
211    >>> except_as_raise_with_empty_except(ValueError('test'), TypeError)
212    Traceback (most recent call last):
213    ValueError: test
214    >>> except_as_raise_with_empty_except(None, TypeError)
215    1
216    """
217    try:
218        if x:
219            raise x
220        b = 1
221    except a as b:  # previously raised UnboundLocalError
222        pass
223    try:
224        print(b)  # raises UnboundLocalError if except clause was executed
225    except UnboundLocalError:
226        if not x:
227            print("unexpected UnboundLocalError raised!")
228    else:
229        if x:
230            print("expected UnboundLocalError not raised!")
231
232
233def except_as_deletes_target_in_gen(x, a):
234    """
235    >>> list(except_as_deletes_target_in_gen(None, TypeError))
236    [(1, 1), (2, 1), (5, 1)]
237    >>> list(except_as_deletes_target_in_gen(TypeError('test'), TypeError))
238    [(1, 1), 3, 6]
239    >>> list(except_as_deletes_target_in_gen(ValueError('test'), TypeError))
240    [(1, 1), (4, 1), (5, 1)]
241    """
242    b = 1
243    try:
244        i = 1
245        yield (1, b)
246        if x:
247            raise x
248        yield (2, b)
249    except a as b:
250        i = 2
251        assert isinstance(b, a)
252        yield 3
253    except:
254        yield (4, b)
255    try:
256        yield (5, b)
257    except UnboundLocalError:
258        yield 6
259
260
261def nested_except_gh3666(a=False, b=False):
262    """
263    >>> print(nested_except_gh3666())
264    A
265    >>> print(nested_except_gh3666(a=True))
266    B-V
267    >>> print(nested_except_gh3666(a=True, b=True))
268    B-V-T
269    """
270    try:
271        if a:
272            raise ValueError
273        return "A"
274    except TypeError as exc:
275        return "A-T"
276    except ValueError as exc:
277        try:
278            if b:
279                raise TypeError
280            return "B-V"
281        except ValueError as exc:
282            return "B-V-V"
283        except TypeError as exc:
284            return "B-V-T"
285
286
287### Py3 feature tests
288
289def print_function(*args):
290    """
291    >>> print_function(1,2,3)
292    1 2 3
293    """
294    print(*args) # this isn't valid Py2 syntax
295
296
297def exec3_function(cmd):
298    """
299    >>> exec3_function('a = 1+1')['a']
300    2
301    """
302    g = {}
303    l = {}
304    exec(cmd, g, l)
305    return l
306
307
308def exec2_function(cmd):
309    """
310    >>> exec2_function('a = 1+1')['a']
311    2
312    """
313    g = {}
314    exec(cmd, g)
315    return g
316
317
318EXEC_GLOBAL = [5]
319
320def exec1_function(cmd):
321    """
322    >>> exec1_function('EXEC_GLOBAL.append(1)')
323    [1]
324    """
325    old = len(EXEC_GLOBAL)
326    exec(cmd)
327    return EXEC_GLOBAL[old:]
328
329
330ustring = "abcdefg"
331
332def unicode_literals():
333    """
334    >>> print( unicode_literals() )
335    True
336    abcdefg
337    """
338    print(isinstance(ustring, unicode) or type(ustring))
339    return ustring
340
341
342def non_ascii_unprefixed_str():
343    u"""
344    >>> s = non_ascii_unprefixed_str()
345    >>> isinstance(s, bytes)
346    False
347    >>> len(s)
348    3
349    """
350    s = 'ø\x20\u0020'
351    assert isinstance(s, unicode)
352    return s
353
354
355def non_ascii_raw_str():
356    u"""
357    >>> s = non_ascii_raw_str()
358    >>> isinstance(s, bytes)
359    False
360    >>> len(s)
361    11
362    """
363    s = r'ø\x20\u0020'
364    assert isinstance(s, unicode)
365    return s
366
367
368def non_ascii_raw_prefixed_unicode():
369    u"""
370    >>> s = non_ascii_raw_prefixed_unicode()
371    >>> isinstance(s, bytes)
372    False
373    >>> len(s)
374    11
375    """
376    s = ru'ø\x20\u0020'
377    assert isinstance(s, unicode)
378    return s
379
380
381def str_type_is_unicode():
382    """
383    >>> str_type, s = str_type_is_unicode()
384    >>> isinstance(s, type(ustring)) or (s, str_type)
385    True
386    >>> isinstance(s, str_type) or (s, str_type)
387    True
388    >>> isinstance(ustring, str_type) or str_type
389    True
390    """
391    cdef str s = 'abc'
392    return str, s
393
394
395def loop_over_unicode_literal():
396    """
397    >>> print( loop_over_unicode_literal() )
398    Py_UCS4
399    """
400    # Py_UCS4 can represent any Unicode character
401    for uchar in 'abcdefg':
402        assert uchar in 'abcdefg'
403    return cython.typeof(uchar)
404
405
406def list_comp():
407    """
408    >>> list_comp()
409    [0, 4, 8]
410    """
411    x = 'abc'
412    result = [x*2 for x in range(5) if x % 2 == 0]
413    assert x == 'abc' # don't leak in Py3 code
414    return result
415
416
417def list_comp_iterable(it):
418    """
419    >>> list_comp_iterable([])
420    []
421    >>> list_comp_iterable([0])
422    [0]
423    >>> list_comp_iterable([1])
424    []
425    >>> list_comp_iterable([0, 1])
426    [0]
427    >>> list_comp_iterable([2])
428    [4]
429    >>> list_comp_iterable(range(5))
430    [0, 4, 8]
431    """
432    x = 'abc'
433    result = [x*2 for x in it if x % 2 == 0]
434    assert x == 'abc' # don't leak in Py3 code
435    return result
436
437
438def list_comp_with_lambda():
439    """
440    >>> list_comp_with_lambda()
441    [0, 4, 8]
442    """
443    x = 'abc'
444    result = [x*2 for x in range(5) if (lambda x:x % 2)(x) == 0]
445    assert x == 'abc' # don't leak in Py3 code
446    return result
447
448
449class ListCompInClass(object):
450    """
451    >>> x = ListCompInClass()
452    >>> x.listcomp
453    [1, 2, 3]
454    """
455    listcomp = [i+1 for i in range(3)]
456
457
458cdef class ListCompInCClass:
459    """
460    >>> x = ListCompInCClass()
461    >>> x.listcomp
462    [1, 2, 3]
463    """
464    listcomp = [i+1 for i in range(3)]
465
466
467module_level_lc = [ module_level_loopvar*2 for module_level_loopvar in range(4) ]
468def list_comp_module_level():
469    """
470    >>> module_level_lc
471    [0, 2, 4, 6]
472    >>> module_level_loopvar         # doctest: +ELLIPSIS
473    Traceback (most recent call last):
474    NameError: ...name 'module_level_loopvar' is not defined
475    """
476
477
478module_level_list_genexp = list(module_level_genexp_loopvar*2 for module_level_genexp_loopvar in range(4))
479def genexpr_module_level():
480    """
481    >>> module_level_list_genexp
482    [0, 2, 4, 6]
483    >>> module_level_genexp_loopvar         # doctest: +ELLIPSIS
484    Traceback (most recent call last):
485    NameError: ...name 'module_level_genexp_loopvar' is not defined
486    """
487
488
489def list_comp_unknown_type(l):
490    """
491    >>> list_comp_unknown_type(range(5))
492    [0, 4, 8]
493    """
494    return [x*2 for x in l if x % 2 == 0]
495
496
497def listcomp_as_condition(sequence):
498    """
499    >>> listcomp_as_condition(['a', 'b', '+'])
500    True
501    >>> listcomp_as_condition('ab+')
502    True
503    >>> listcomp_as_condition('abc')
504    False
505    """
506    if [1 for c in sequence if c in '+-*/<=>!%&|([^~,']:
507        return True
508    return False
509
510
511def set_comp():
512    """
513    >>> sorted(set_comp())
514    [0, 4, 8]
515    """
516    x = 'abc'
517    result = {x*2 for x in range(5) if x % 2 == 0}
518    assert x == 'abc' # don't leak
519    return result
520
521
522def dict_comp():
523    """
524    >>> sorted(dict_comp().items())
525    [(0, 0), (2, 4), (4, 8)]
526    """
527    x = 'abc'
528    result = {x:x*2 for x in range(5) if x % 2 == 0}
529    assert x == 'abc' # don't leak
530    return result
531
532
533# in Python 3, d.keys/values/items() are the iteration methods
534@cython.test_assert_path_exists(
535    "//WhileStatNode",
536    "//WhileStatNode//DictIterationNextNode")
537@cython.test_fail_if_path_exists(
538    "//ForInStatNode")
539def dict_iter(dict d):
540    """
541    >>> d = {'a' : 1, 'b' : 2, 'c' : 3}
542    >>> keys, values, items = dict_iter(d)
543    >>> sorted(keys)
544    ['a', 'b', 'c']
545    >>> sorted(values)
546    [1, 2, 3]
547    >>> sorted(items)
548    [('a', 1), ('b', 2), ('c', 3)]
549
550    >>> dict_iter({})
551    ([], [], [])
552    """
553    keys = [ key for key in d.keys() ]
554    values = [ value for value in d.values() ]
555    items = [ item for item in d.items() ]
556    return keys, values, items
557
558
559@cython.test_assert_path_exists(
560    "//WhileStatNode",
561    "//WhileStatNode//DictIterationNextNode")
562@cython.test_fail_if_path_exists(
563    "//ForInStatNode")
564def dict_iter_new_dict():
565    """
566    >>> dict_keys, keys, values, items = dict_iter_new_dict()
567    >>> sorted(dict_keys)
568    [11, 22, 33]
569    >>> sorted(keys)
570    [11, 22, 33]
571    >>> sorted(values)
572    [1, 2, 3]
573    >>> sorted(items)
574    [(11, 1), (22, 2), (33, 3)]
575    """
576    dict_keys = [ key for key in {11 : 1, 22 : 2, 33 : 3} ]
577    keys = [ key for key in {11 : 1, 22 : 2, 33 : 3}.keys() ]
578    values = [ value for value in {11 : 1, 22 : 2, 33 : 3}.values() ]
579    items = [ item for item in {11 : 1, 22 : 2, 33 : 3}.items() ]
580    return dict_keys, keys, values, items
581
582
583def int_literals():
584    """
585    >>> int_literals()
586    long
587    long
588    unsigned long
589    unsigned long
590    """
591    print(cython.typeof(1L))
592    print(cython.typeof(10000000000000L))
593    print(cython.typeof(1UL))
594    print(cython.typeof(10000000000000UL))
595
596
597def annotation_syntax(a: "test new test", b : "other" = 2, *args: "ARGS", **kwargs: "KWARGS") -> "ret":
598    """
599    >>> annotation_syntax(1)
600    3
601    >>> annotation_syntax(1,3)
602    4
603
604    >>> len(annotation_syntax.__annotations__)
605    5
606    >>> print(annotation_syntax.__annotations__['a'])
607    test new test
608    >>> print(annotation_syntax.__annotations__['b'])
609    other
610    >>> print(annotation_syntax.__annotations__['args'])
611    ARGS
612    >>> print(annotation_syntax.__annotations__['kwargs'])
613    KWARGS
614    >>> print(annotation_syntax.__annotations__['return'])
615    ret
616    """
617    result : int = a + b
618
619    return result
620
621
622def builtin_as_annotation(text: str):
623    # See https://github.com/cython/cython/issues/2811
624    """
625    >>> builtin_as_annotation("abc")
626    a
627    b
628    c
629    """
630    for c in text:
631        print(c)
632
633
634async def async_def_annotations(x: 'int') -> 'float':
635    """
636    >>> ret, arg = sorted(async_def_annotations.__annotations__.items())
637    >>> print(ret[0]); print(ret[1])
638    return
639    float
640    >>> print(arg[0]); print(arg[1])
641    x
642    int
643    """
644    return float(x)
645
646
647'''
648def repr_returns_str(x) -> str:
649    """
650    >>> repr_returns_str(123)
651    '123'
652    """
653    return repr(x)
654'''
655