1# mode: run
2# tag: f_strings, pep498, werror
3
4####
5# Cython specific PEP 498 tests in addition to test_fstring.pyx from CPython
6####
7
8cimport cython
9
10import sys
11IS_PYPY = hasattr(sys, 'pypy_version_info')
12
13from libc.limits cimport INT_MAX, LONG_MAX, LONG_MIN
14
15max_int = INT_MAX
16max_long = LONG_MAX
17min_long = LONG_MIN
18
19
20@cython.test_fail_if_path_exists(
21    "//FormattedValueNode",
22    "//JoinedStrNode",
23    "//AddNode",
24)
25def escaping():
26    """
27    >>> escaping()
28    """
29    assert f'{{{{{"abc"}}}}}{{}}{{' == '{{abc}}{}{'
30    s = f'{{{{{"abc"}}}}}{{}}{{'
31    assert s == '{{abc}}{}{', s
32
33    assert f'\x7b}}' == '{}'
34    s = f'\x7b}}'
35    assert s == '{}', s
36
37    assert f'{"{{}}"}' == '{{}}'
38    s = f'{"{{}}"}'
39    assert s == '{{}}', s
40
41
42@cython.test_fail_if_path_exists(
43    "//FormattedValueNode",
44    "//JoinedStrNode",
45    "//AddNode",
46)
47def nested_constant():
48    """
49    >>> print(nested_constant())
50    xyabc123321
51    """
52    return f"""{f'''xy{f"abc{123}{'321'}"!s}'''}"""
53
54
55def format2(ab, cd):
56    """
57    >>> a, b, c = format2(1, 2)
58    >>> print(a)
59    ab2
60    >>> print(b)
61    1cd
62    >>> print(c)
63    12
64
65    >>> a, b, c = format2('ab', 'cd')
66    >>> print(a)
67    abcd
68    >>> print(b)
69    abcd
70    >>> print(c)
71    abcd
72    """
73    a = f"ab{cd}"
74    assert isinstance(a, unicode), type(a)
75    b = f"{ab}cd"
76    assert isinstance(b, unicode), type(b)
77    c = f"{ab}{cd}"
78    assert isinstance(c, unicode) or (IS_PYPY and isinstance(c, str)), type(c)
79    return a, b, c
80
81
82ctypedef enum TestValues:
83    enum_ABC = 1
84    enum_XYZ = 2
85
86
87@cython.test_fail_if_path_exists(
88    "//CoerceToPyTypeNode",
89)
90def format_c_enum():
91    """
92    >>> s = format_c_enum()
93    >>> s == '1-2' or s
94    True
95    """
96    return f"{enum_ABC}-{enum_XYZ}"
97
98
99def format_c_numbers(signed char c, short s, int n, long l, float f, double d):
100    """
101    >>> s1, s2, s3, s4 = format_c_numbers(123, 135, 12, 12312312, 2.3456, 3.1415926)
102    >>> print(s1)
103    123 13512312312122.35
104    >>> print(s2)
105    3.14 2.3
106    >>> print(s3)
107      12f
108    >>> print(s4)
109    0C014 3.14
110
111    >>> s1, s2, s3, s4 = format_c_numbers(-123, -135, -12, -12312312, -2.3456, -3.1415926)
112    >>> print(s1)
113    -123-135-12312312-12-2.35
114    >>> print(s2)
115    -3.14-2.3
116    >>> print(s3)
117     -12f
118    >>> print(s4)
119    -C-14-3.14
120
121    >>> s1, s2, s3, s4 = format_c_numbers(0, 0, 0, 0, -2.3456, -0.1415926)
122    >>> print(s1)
123    0   000-2.35
124    >>> print(s2)
125    -0.142-2.3
126    >>> print(s3)
127       0f
128    >>> print(s4)
129    00000-0.142
130
131    """
132    s1 = f"{c}{s:4}{l}{n}{f:.3}"
133    assert isinstance(s1, unicode), type(s1)
134    s2 = f"{d:.3}{f:4.2}"
135    assert isinstance(s2, unicode), type(s2)
136    s3 = f"{n:-4}f"
137    assert isinstance(s3, unicode), type(s3)
138    s4 = f"{n:02X}{n:03o}{d:5.3}"
139    assert isinstance(s4, unicode), type(s4)
140    return s1, s2, s3, s4
141
142
143def format_c_numbers_unsigned(unsigned char c, unsigned short s, unsigned int n, unsigned long l):
144    """
145    >>> s1, s2, s3 = format_c_numbers_unsigned(123, 135, 12, 12312312)
146    >>> print(s1)
147    123 135 5675737012
148    >>> print(s2)
149      12f
150    >>> print(s3)
151    0C014    bbdef8
152
153    """
154    s1 = f"{c}{s:4} {l:o}{n}"
155    assert isinstance(s1, unicode), type(s1)
156    s2 = f"{n:-4}f"
157    assert isinstance(s2, unicode), type(s2)
158    s3 = f"{n:02X}{n:03o}{l:10x}"
159    assert isinstance(s3, unicode), type(s3)
160    return s1, s2, s3
161
162
163@cython.test_fail_if_path_exists(
164    "//CoerceToPyTypeNode",
165)
166def format_c_numbers_max(int n, long l):
167    """
168    >>> n, l = max_int, max_long
169    >>> s1, s2 = format_c_numbers_max(n, l)
170    >>> s1 == '{n}:{l}'.format(n=n, l=l) or s1
171    True
172    >>> s2 == '{n:012X}:{l:020X}'.format(n=n, l=l) or s2
173    True
174
175    >>> n, l = -max_int-1, -max_long-1
176    >>> s1, s2 = format_c_numbers_max(n, l)
177    >>> s1 == '{n}:{l}'.format(n=n, l=l) or s1
178    True
179    >>> s2 == '{n:012X}:{l:020X}'.format(n=n, l=l) or s2
180    True
181    """
182    s1 = f"{n}:{l}"
183    assert isinstance(s1, unicode), type(s1)
184    s2 = f"{n:012X}:{l:020X}"
185    assert isinstance(s2, unicode), type(s2)
186    return s1, s2
187
188
189def format_c_number_const():
190    """
191    >>> s = format_c_number_const()
192    >>> s == '{0}'.format(max_long) or s
193    True
194    """
195    return f"{LONG_MAX}"
196
197
198@cython.test_fail_if_path_exists(
199    "//CoerceToPyTypeNode",
200)
201def format_c_number_range(int n):
202    """
203    >>> for i in range(-1000, 1001):
204    ...     assert format_c_number_range(i) == str(i)
205    """
206    return f'{n}'
207
208
209@cython.test_fail_if_path_exists(
210    "//CoerceToPyTypeNode",
211)
212def format_c_number_range_width(int n):
213    """
214    >>> for i in range(-1000, 1001):
215    ...     formatted = format_c_number_range_width(i)
216    ...     expected = '{n:04d}'.format(n=i)
217    ...     assert formatted == expected, "%r != %r" % (formatted, expected)
218    """
219    return f'{n:04}'
220
221
222def format_c_number_range_width0(int n):
223    """
224    >>> for i in range(-100, 101):
225    ...     formatted = format_c_number_range_width0(i)
226    ...     expected = '{n:00d}'.format(n=i)
227    ...     assert formatted == expected, "%r != %r" % (formatted, expected)
228    """
229    return f'{n:00}'
230
231
232@cython.test_fail_if_path_exists(
233    "//CoerceToPyTypeNode",
234)
235def format_c_number_range_width1(int n):
236    """
237    >>> for i in range(-100, 101):
238    ...     formatted = format_c_number_range_width1(i)
239    ...     expected = '{n:01d}'.format(n=i)
240    ...     assert formatted == expected, "%r != %r" % (formatted, expected)
241    """
242    return f'{n:01}'
243
244
245@cython.test_fail_if_path_exists(
246    "//CoerceToPyTypeNode",
247)
248def format_c_number_range_width_m4(int n):
249    """
250    >>> for i in range(-100, 101):
251    ...     formatted = format_c_number_range_width_m4(i)
252    ...     expected = '{n:-4d}'.format(n=i)
253    ...     assert formatted == expected, "%r != %r" % (formatted, expected)
254    """
255    return f'{n:-4}'
256
257
258def format_c_number_range_dyn_width(int n, int width):
259    """
260    >>> for i in range(-1000, 1001):
261    ...     assert format_c_number_range_dyn_width(i, 0) == str(i), format_c_number_range_dyn_width(i, 0)
262    ...     assert format_c_number_range_dyn_width(i, 1) == '%01d' % i, format_c_number_range_dyn_width(i, 1)
263    ...     assert format_c_number_range_dyn_width(i, 4) == '%04d' % i, format_c_number_range_dyn_width(i, 4)
264    ...     assert format_c_number_range_dyn_width(i, 5) == '%05d' % i, format_c_number_range_dyn_width(i, 5)
265    ...     assert format_c_number_range_dyn_width(i, 6) == '%06d' % i, format_c_number_range_dyn_width(i, 6)
266    """
267    return f'{n:0{width}}'
268
269
270@cython.test_fail_if_path_exists(
271    "//CoerceToPyTypeNode",
272)
273def format_bool(bint x):
274    """
275    >>> a, b, c, d = format_bool(1)
276    >>> print(a)  # 1
277    True
278    >>> print(b)  # 1
279    True
280    >>> print(c)  # 1
281    False
282    >>> print(d)  # 1
283    False
284
285    >>> a, b, c, d = format_bool(2)
286    >>> print(a)  # 2
287    True
288    >>> print(b)  # 2
289    True
290    >>> print(c)  # 2
291    False
292    >>> print(d)  # 2
293    False
294
295    >>> a, b, c, d = format_bool(0)
296    >>> print(a)  # 3
297    False
298    >>> print(b)  # 3
299    True
300    >>> print(c)  # 3
301    False
302    >>> print(d)  # 3
303    False
304    """
305    return f'{x}', f'{True}', f'{x == 2}', f'{2 > 3}'
306
307
308def format_c_values(Py_UCS4 uchar, Py_UNICODE pyunicode):
309    """
310    >>> s, s1, s2, s3 = format_c_values(b'A'.decode('ascii'), b'X'.decode('ascii'))
311    >>> print(s)
312    AXAX
313    >>> print(s1)
314    A
315    >>> print(s2)
316    X
317    >>> print(s3)
318    None
319
320    """
321    s = f"{uchar}{pyunicode}{uchar!s}{pyunicode!s}"
322    assert isinstance(s, unicode), type(s)
323    s1 = f"{uchar}"
324    assert isinstance(s1, unicode), type(s1)
325    s2 = f"{pyunicode}"
326    assert isinstance(s2, unicode), type(s2)
327    l = [1, 2, 3]
328    s3 = f"{l.reverse()}"  # C int return value => 'None'
329    assert isinstance(s3, unicode), type(s3)
330    assert l == [3, 2, 1]
331    return s, s1, s2, s3
332
333
334xyz_ustring = u'xÄyÖz'
335
336def format_strings(str s, unicode u):
337    u"""
338    >>> a, b, c, d, e, f, g = format_strings('abc', b'xyz'.decode('ascii'))
339    >>> print(a)
340    abcxyz
341    >>> print(b)
342    xyzabc
343    >>> print(c)
344    uxyzsabc
345    >>> print(d)
346    sabcuxyz
347    >>> print(e)
348    sabcuÄÄuxyz
349    >>> print(f)
350    sabcu\N{SNOWMAN}uxyz
351    >>> print(g)
352    sabcu\N{OLD PERSIAN SIGN A}uxyz\N{SNOWMAN}
353
354    >>> a, b, c, d, e, f, g = format_strings('abc', xyz_ustring)
355    >>> print(a)
356    abcxÄyÖz
357    >>> print(b)
358    xÄyÖzabc
359    >>> print(c)
360    uxÄyÖzsabc
361    >>> print(d)
362    sabcuxÄyÖz
363    >>> print(e)
364    sabcuÄÄuxÄyÖz
365    >>> print(f)
366    sabcu\N{SNOWMAN}uxÄyÖz
367    >>> print(g)
368    sabcu\N{OLD PERSIAN SIGN A}uxÄyÖz\N{SNOWMAN}
369    """
370    a = f"{s}{u}"
371    assert isinstance(a, unicode), type(a)
372    b = f"{u}{s}"
373    assert isinstance(b, unicode), type(b)
374    c = f"u{u}s{s}"
375    assert isinstance(c, unicode), type(c)
376    d = f"s{s}u{u}"
377    assert isinstance(d, unicode), type(d)
378    e = f"s{s}uÄÄu{u}"
379    assert isinstance(e, unicode), type(e)
380    f = f"s{s}u\N{SNOWMAN}u{u}"
381    assert isinstance(f, unicode), type(f)
382    g = f"s{s}u\N{OLD PERSIAN SIGN A}u{u}\N{SNOWMAN}"
383    assert isinstance(g, unicode), type(g)
384    return a, b, c, d, e, f, g
385
386
387def format_pystr(str s1, str s2):
388    """
389    >>> a, b, c, d = format_pystr('abc', 'xyz')
390    >>> print(a)
391    abcxyz
392    >>> print(b)
393    xyzabc
394    >>> print(c)
395    uxyzsabc
396    >>> print(d)
397    sabcuxyz
398    """
399    a = f"{s1}{s2}"
400    assert isinstance(a, unicode) or (IS_PYPY and isinstance(a, str)), type(a)
401    b = f"{s2}{s1}"
402    assert isinstance(b, unicode) or (IS_PYPY and isinstance(a, str)), type(b)
403    c = f"u{s2}s{s1}"
404    assert isinstance(c, unicode), type(c)
405    d = f"s{s1}u{s2}"
406    assert isinstance(d, unicode), type(d)
407    return a, b, c, d
408
409
410def raw_fstring(value):
411    """
412    >>> print(raw_fstring('abc'))
413    abc\\x61
414    """
415    return fr'{value}\x61'
416
417
418def format_repr(value):
419    """
420    >>> a, b = format_repr('abc')
421    >>> print('x{value!r}x'.format(value='abc'))
422    x'abc'x
423    >>> print('x{value!r:6}x'.format(value='abc'))
424    x'abc' x
425    >>> print(a)
426    x'abc'x
427    >>> print(b)
428    x'abc' x
429    """
430    a = f'x{value!r}x'
431    assert isinstance(a, unicode), type(a)
432    b = f'x{value!r:6}x'
433    assert isinstance(b, unicode), type(b)
434    return a, b
435
436
437def format_str(value):
438    """
439    >>> a, b = format_str('abc')
440    >>> print('x{value!s}x'.format(value='abc'))
441    xabcx
442    >>> print('x{value!s:6}x'.format(value='abc'))
443    xabc   x
444    >>> print(a)
445    xabcx
446    >>> print(b)
447    xabc   x
448    """
449    a = f'x{value!s}x'
450    assert isinstance(a, unicode), type(a)
451    b = f'x{value!s:6}x'
452    assert isinstance(b, unicode), type(b)
453    return a, b
454
455
456@cython.test_fail_if_path_exists(
457    "//FormattedValueNode",  # bytes.decode() returns unicode => formatting is useless
458    "//JoinedStrNode",       # replaced by call to PyUnicode_Concat()
459    "//PythonCapiCallNode//PythonCapiCallNode",
460)
461def format_decoded_bytes(bytes value):
462    """
463    >>> print(format_decoded_bytes(b'xyz'))
464    U-xyz
465    """
466    return f"U-{value.decode('utf-8')}"
467
468
469@cython.test_fail_if_path_exists(
470    "//AddNode",
471    "//ModNode",
472)
473@cython.test_assert_path_exists(
474    "//FormattedValueNode",
475    "//JoinedStrNode",
476)
477def generated_fstring(int i, float f, unicode u not None, o):
478    """
479    >>> i, f, u, o = 11, 1.3125, u'xyz', [1]
480    >>> print(((
481    ...     u"(i) %s-%.3s-%r-%.3r-%d-%3d-%-3d-%o-%04o-%x-%4x-%X-%03X-%.1f-%04.2f %% "
482    ...     u"(u) %s-%.2s-%r-%.7r-%05s-%-5s %% "
483    ...     u"(o) %s-%.2s-%r-%.2r %% "
484    ...     u"(f) %.2f-%d"
485    ... ) % (
486    ...     i, i, i, i, i, i, i, i, i, i, i, i, i, i, i,
487    ...     u, u, u, u, u, u,
488    ...     o, o, o, o,
489    ...     f, f,
490    ... )).replace("-u'xyz'", "-'xyz'"))
491    (i) 11-11-11-11-11- 11-11 -13-0013-b-   b-B-00B-11.0-11.00 % (u) xyz-xy-'xyz'-'xyz'-  xyz-xyz   % (o) [1]-[1-[1]-[1 % (f) 1.31-1
492
493    >>> print(generated_fstring(i, f, u, o).replace("-u'xyz'", "-'xyz'"))
494    (i) 11-11-11-11-11- 11-11 -13-0013-b-   b-B-00B-11.0-11.00 % (u) xyz-xy-'xyz'-'xyz'-  xyz-xyz   % (o) [1]-[1-[1]-[1 % (f) 1.31-1
495    """
496    return (
497        u"(i) %s-%.3s-%r-%.3r-%d-%3d-%-3d-%o-%04o-%x-%4x-%X-%03X-%.1f-%04.2f %% "
498        u"(u) %s-%.2s-%r-%.7r-%05s-%-5s %% "
499        u"(o) %s-%.2s-%r-%.2r %% "
500        u"(f) %.2f-%d"
501    ) % (
502        i, i, i, i, i, i, i, i, i, i, i, i, i, i, i,
503        u, u, u, u, u, u,
504        o, o, o, o,
505        f, f,
506    )
507
508
509@cython.test_assert_path_exists(
510    "//FormattedValueNode",
511    "//JoinedStrNode",
512)
513def percent_s_unicode(u, int i):
514    u"""
515    >>> u = u'x\u0194z'
516    >>> print(percent_s_unicode(u, 12))
517    x\u0194z-12
518    """
519    return u"%s-%d" % (u, i)
520
521
522########################################
523# await inside f-string
524
525def test_await_inside_f_string():
526    """
527    >>> test_await_inside_f_string()
528    PARSED_SUCCESSFULLY
529    """
530
531    async def f():
532        return "some value"
533
534    async def main():
535        print(f"{await f()}")
536
537    print("PARSED_SUCCESSFULLY")
538