2
# tag: f_strings, pep498, werror
5
# Cython specific PEP 498 tests in addition to test_fstring.pyx from CPython
11
IS_PYPY = hasattr(sys, 'pypy_version_info')
13
from libc.limits cimport INT_MAX, LONG_MAX, LONG_MIN
20
@cython.test_fail_if_path_exists(
23
@cython.test_assert_path_exists(
26
def concat_strings(a, b):
28
>>> concat_strings("", "")
35
>>> concat_strings("a", "")
42
>>> concat_strings("", "b")
49
>>> concat_strings("a", "b")
56
>>> concat_strings("".join(["a", "b"]), "") # fresh temp string left
63
>>> concat_strings("", "".join(["a", "b"])) # fresh temp string right
74
print(f"{a+'x'}{b}") # fresh temp string left
75
print(f"{a}{'x'+b}") # fresh temp string right
76
print(f"{a+'x'}{'x'+b}") # fresh temp strings right and left
79
@cython.test_fail_if_path_exists(
80
"//FormattedValueNode",
88
assert f'{{{{{"abc"}}}}}{{}}{{' == '{{abc}}{}{'
89
s = f'{{{{{"abc"}}}}}{{}}{{'
90
assert s == '{{abc}}{}{', s
92
assert f'\x7b}}' == '{}'
96
assert f'{"{{}}"}' == '{{}}'
101
@cython.test_fail_if_path_exists(
102
"//FormattedValueNode",
106
def nested_constant():
108
>>> print(nested_constant())
111
return f"""{f'''xy{f"abc{123}{'321'}"!s}'''}"""
116
>>> a, b, c = format2(1, 2)
124
>>> a, b, c = format2('ab', 'cd')
133
assert isinstance(a, unicode), type(a)
135
assert isinstance(b, unicode), type(b)
137
assert isinstance(c, unicode) or (IS_PYPY and isinstance(c, str)), type(c)
141
ctypedef enum TestValues:
146
@cython.test_fail_if_path_exists(
147
"//CoerceToPyTypeNode",
151
>>> s = format_c_enum()
155
return f"{enum_ABC}-{enum_XYZ}"
158
def format_c_numbers(signed char c, short s, int n, long l, float f, double d):
160
>>> s1, s2, s3, s4 = format_c_numbers(123, 135, 12, 12312312, 2.3456, 3.1415926)
162
123 13512312312122.35
170
>>> s1, s2, s3, s4 = format_c_numbers(-123, -135, -12, -12312312, -2.3456, -3.1415926)
172
-123-135-12312312-12-2.35
180
>>> s1, s2, s3, s4 = format_c_numbers(0, 0, 0, 0, -2.3456, -0.1415926)
191
s1 = f"{c}{s:4}{l}{n}{f:.3}"
192
assert isinstance(s1, unicode), type(s1)
193
s2 = f"{d:.3}{f:4.2}"
194
assert isinstance(s2, unicode), type(s2)
196
assert isinstance(s3, unicode), type(s3)
197
s4 = f"{n:02X}{n:03o}{d:5.3}"
198
assert isinstance(s4, unicode), type(s4)
199
return s1, s2, s3, s4
202
def format_c_numbers_unsigned(unsigned char c, unsigned short s, unsigned int n, unsigned long l):
204
>>> s1, s2, s3 = format_c_numbers_unsigned(123, 135, 12, 12312312)
213
s1 = f"{c}{s:4} {l:o}{n}"
214
assert isinstance(s1, unicode), type(s1)
216
assert isinstance(s2, unicode), type(s2)
217
s3 = f"{n:02X}{n:03o}{l:10x}"
218
assert isinstance(s3, unicode), type(s3)
222
@cython.test_fail_if_path_exists(
223
"//CoerceToPyTypeNode",
225
def format_c_numbers_max(int n, long l):
227
>>> n, l = max_int, max_long
228
>>> s1, s2 = format_c_numbers_max(n, l)
229
>>> s1 == '{n}:{l}'.format(n=n, l=l) or s1
231
>>> s2 == '{n:012X}:{l:020X}'.format(n=n, l=l) or s2
234
>>> n, l = -max_int-1, -max_long-1
235
>>> s1, s2 = format_c_numbers_max(n, l)
236
>>> s1 == '{n}:{l}'.format(n=n, l=l) or s1
238
>>> s2 == '{n:012X}:{l:020X}'.format(n=n, l=l) or s2
242
assert isinstance(s1, unicode), type(s1)
243
s2 = f"{n:012X}:{l:020X}"
244
assert isinstance(s2, unicode), type(s2)
248
def format_c_number_const():
250
>>> s = format_c_number_const()
251
>>> s == '{0}'.format(max_long) or s
257
@cython.test_fail_if_path_exists(
258
"//CoerceToPyTypeNode",
260
def format_c_number_range(int n):
262
>>> for i in range(-1000, 1001):
263
... assert format_c_number_range(i) == str(i)
268
@cython.test_fail_if_path_exists(
269
"//CoerceToPyTypeNode",
271
def format_c_number_range_width(int n):
273
>>> for i in range(-1000, 1001):
274
... formatted = format_c_number_range_width(i)
275
... expected = '{n:04d}'.format(n=i)
276
... assert formatted == expected, "%r != %r" % (formatted, expected)
281
def format_c_number_range_width0(int n):
283
>>> for i in range(-100, 101):
284
... formatted = format_c_number_range_width0(i)
285
... expected = '{n:00d}'.format(n=i)
286
... assert formatted == expected, "%r != %r" % (formatted, expected)
291
@cython.test_fail_if_path_exists(
292
"//CoerceToPyTypeNode",
294
def format_c_number_range_width1(int n):
296
>>> for i in range(-100, 101):
297
... formatted = format_c_number_range_width1(i)
298
... expected = '{n:01d}'.format(n=i)
299
... assert formatted == expected, "%r != %r" % (formatted, expected)
304
@cython.test_fail_if_path_exists(
305
"//CoerceToPyTypeNode",
307
def format_c_number_range_width_m4(int n):
309
>>> for i in range(-100, 101):
310
... formatted = format_c_number_range_width_m4(i)
311
... expected = '{n:-4d}'.format(n=i)
312
... assert formatted == expected, "%r != %r" % (formatted, expected)
317
def format_c_number_range_dyn_width(int n, int width):
319
>>> for i in range(-1000, 1001):
320
... assert format_c_number_range_dyn_width(i, 0) == str(i), format_c_number_range_dyn_width(i, 0)
321
... assert format_c_number_range_dyn_width(i, 1) == '%01d' % i, format_c_number_range_dyn_width(i, 1)
322
... assert format_c_number_range_dyn_width(i, 4) == '%04d' % i, format_c_number_range_dyn_width(i, 4)
323
... assert format_c_number_range_dyn_width(i, 5) == '%05d' % i, format_c_number_range_dyn_width(i, 5)
324
... assert format_c_number_range_dyn_width(i, 6) == '%06d' % i, format_c_number_range_dyn_width(i, 6)
326
return f'{n:0{width}}'
329
@cython.test_fail_if_path_exists(
330
"//CoerceToPyTypeNode",
332
def format_bool(bint x):
334
>>> a, b, c, d = format_bool(1)
344
>>> a, b, c, d = format_bool(2)
354
>>> a, b, c, d = format_bool(0)
364
return f'{x}', f'{True}', f'{x == 2}', f'{2 > 3}'
367
def format_c_values(Py_UCS4 uchar, Py_UNICODE pyunicode):
369
>>> s, s1, s2, s3 = format_c_values(b'A'.decode('ascii'), b'X'.decode('ascii'))
380
s = f"{uchar}{pyunicode}{uchar!s}{pyunicode!s}"
381
assert isinstance(s, unicode), type(s)
383
assert isinstance(s1, unicode), type(s1)
385
assert isinstance(s2, unicode), type(s2)
387
s3 = f"{l.reverse()}" # C int return value => 'None'
388
assert isinstance(s3, unicode), type(s3)
389
assert l == [3, 2, 1]
393
xyz_ustring = u'xÄyÖz'
395
def format_strings(str s, unicode u):
397
>>> a, b, c, d, e, f, g = format_strings('abc', b'xyz'.decode('ascii'))
411
sabcu\N{OLD PERSIAN SIGN A}uxyz\N{SNOWMAN}
413
>>> a, b, c, d, e, f, g = format_strings('abc', xyz_ustring)
425
sabcu\N{SNOWMAN}uxÄyÖz
427
sabcu\N{OLD PERSIAN SIGN A}uxÄyÖz\N{SNOWMAN}
430
assert isinstance(a, unicode), type(a)
432
assert isinstance(b, unicode), type(b)
434
assert isinstance(c, unicode), type(c)
436
assert isinstance(d, unicode), type(d)
438
assert isinstance(e, unicode), type(e)
439
f = f"s{s}u\N{SNOWMAN}u{u}"
440
assert isinstance(f, unicode), type(f)
441
g = f"s{s}u\N{OLD PERSIAN SIGN A}u{u}\N{SNOWMAN}"
442
assert isinstance(g, unicode), type(g)
443
return a, b, c, d, e, f, g
446
def format_pystr(str s1, str s2):
448
>>> a, b, c, d = format_pystr('abc', 'xyz')
459
assert isinstance(a, unicode) or (IS_PYPY and isinstance(a, str)), type(a)
461
assert isinstance(b, unicode) or (IS_PYPY and isinstance(a, str)), type(b)
463
assert isinstance(c, unicode), type(c)
465
assert isinstance(d, unicode), type(d)
469
def raw_fstring(value):
471
>>> print(raw_fstring('abc'))
474
return fr'{value}\x61'
477
def format_repr(value):
479
>>> a, b = format_repr('abc')
480
>>> print('x{value!r}x'.format(value='abc'))
482
>>> print('x{value!r:6}x'.format(value='abc'))
490
assert isinstance(a, unicode), type(a)
492
assert isinstance(b, unicode), type(b)
496
def format_str(value):
498
>>> a, b = format_str('abc')
499
>>> print('x{value!s}x'.format(value='abc'))
501
>>> print('x{value!s:6}x'.format(value='abc'))
509
assert isinstance(a, unicode), type(a)
511
assert isinstance(b, unicode), type(b)
515
@cython.test_fail_if_path_exists(
516
"//FormattedValueNode", # bytes.decode() returns unicode => formatting is useless
517
"//JoinedStrNode", # replaced by call to PyUnicode_Concat()
518
"//PythonCapiCallNode//PythonCapiCallNode",
520
def format_decoded_bytes(bytes value):
522
>>> print(format_decoded_bytes(b'xyz'))
525
return f"U-{value.decode('utf-8')}"
528
@cython.test_fail_if_path_exists(
529
"//CoerceToPyTypeNode",
531
def format_uchar(int x):
534
('\\x00', ' \\x00', ' \\x00')
536
('\\r', ' \\r', ' \\r')
537
>>> format_uchar(1114111 + 1)
538
Traceback (most recent call last):
539
OverflowError: %c arg not in range(0x110000)
541
return f"{x:c}", f"{x:12c}", f"{x:>8c}"
544
@cython.test_fail_if_path_exists(
548
@cython.test_assert_path_exists(
549
"//FormattedValueNode",
552
def generated_fstring(int i, float f, unicode u not None, o):
554
>>> i, f, u, o = 11, 1.3125, u'xyz', [1]
556
... u"(i) %s-%.3s-%r-%.3r-%d-%3d-%-3d-%o-%04o-%x-%4x-%X-%03X-%.1f-%04.2f %% "
557
... u"(u) %s-%.2s-%r-%.7r-%05s-%-5s %% "
558
... u"(o) %s-%.2s-%r-%.2r %% "
561
... i, i, i, i, i, i, i, i, i, i, i, i, i, i, i,
562
... u, u, u, u, u, u,
565
... )).replace("-u'xyz'", "-'xyz'"))
566
(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
568
>>> print(generated_fstring(i, f, u, o).replace("-u'xyz'", "-'xyz'"))
569
(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
572
u"(i) %s-%.3s-%r-%.3r-%d-%3d-%-3d-%o-%04o-%x-%4x-%X-%03X-%.1f-%04.2f %% "
573
u"(u) %s-%.2s-%r-%.7r-%05s-%-5s %% "
574
u"(o) %s-%.2s-%r-%.2r %% "
577
i, i, i, i, i, i, i, i, i, i, i, i, i, i, i,
584
@cython.test_assert_path_exists(
585
"//FormattedValueNode",
588
def percent_s_unicode(u, int i):
591
>>> print(percent_s_unicode(u, 12))
594
return u"%s-%d" % (u, i)
597
@cython.test_assert_path_exists(
598
"//FormattedValueNode",
602
>>> class Listish(list):
603
... def __format__(self, format_spec):
604
... self.append("format called")
605
... return repr(self)
606
... def append(self, item):
607
... list.append(self, item)
611
>>> sideeffect(l) if getattr(sys, 'pypy_version_info', ())[:2] != (7,3) else [123, 'format called'] # 7.3.4, 7.3.5
612
[123, 'format called']
614
f"{l.append(123)}" # unused f-string !
618
########################################
619
# await inside f-string
621
def test_await_inside_f_string():
623
>>> test_await_inside_f_string()
631
print(f"{await f()}")
633
print("PARSED_SUCCESSFULLY")