ยปCore Development>Code coverage>Lib/test/test_fstring.py

Python code coverage for Lib/test/test_fstring.py

#countcontent
1n/aimport ast
2n/aimport types
3n/aimport decimal
4n/aimport unittest
5n/a
6n/aa_global = 'global variable'
7n/a
8n/a# You could argue that I'm too strict in looking for specific error
9n/a# values with assertRaisesRegex, but without it it's way too easy to
10n/a# make a syntax error in the test strings. Especially with all of the
11n/a# triple quotes, raw strings, backslashes, etc. I think it's a
12n/a# worthwhile tradeoff. When I switched to this method, I found many
13n/a# examples where I wasn't testing what I thought I was.
14n/a
15n/aclass TestCase(unittest.TestCase):
16n/a def assertAllRaise(self, exception_type, regex, error_strings):
17n/a for str in error_strings:
18n/a with self.subTest(str=str):
19n/a with self.assertRaisesRegex(exception_type, regex):
20n/a eval(str)
21n/a
22n/a def test__format__lookup(self):
23n/a # Make sure __format__ is looked up on the type, not the instance.
24n/a class X:
25n/a def __format__(self, spec):
26n/a return 'class'
27n/a
28n/a x = X()
29n/a
30n/a # Add a bound __format__ method to the 'y' instance, but not
31n/a # the 'x' instance.
32n/a y = X()
33n/a y.__format__ = types.MethodType(lambda self, spec: 'instance', y)
34n/a
35n/a self.assertEqual(f'{y}', format(y))
36n/a self.assertEqual(f'{y}', 'class')
37n/a self.assertEqual(format(x), format(y))
38n/a
39n/a # __format__ is not called this way, but still make sure it
40n/a # returns what we expect (so we can make sure we're bypassing
41n/a # it).
42n/a self.assertEqual(x.__format__(''), 'class')
43n/a self.assertEqual(y.__format__(''), 'instance')
44n/a
45n/a # This is how __format__ is actually called.
46n/a self.assertEqual(type(x).__format__(x, ''), 'class')
47n/a self.assertEqual(type(y).__format__(y, ''), 'class')
48n/a
49n/a def test_ast(self):
50n/a # Inspired by http://bugs.python.org/issue24975
51n/a class X:
52n/a def __init__(self):
53n/a self.called = False
54n/a def __call__(self):
55n/a self.called = True
56n/a return 4
57n/a x = X()
58n/a expr = """
59n/aa = 10
60n/af'{a * x()}'"""
61n/a t = ast.parse(expr)
62n/a c = compile(t, '', 'exec')
63n/a
64n/a # Make sure x was not called.
65n/a self.assertFalse(x.called)
66n/a
67n/a # Actually run the code.
68n/a exec(c)
69n/a
70n/a # Make sure x was called.
71n/a self.assertTrue(x.called)
72n/a
73n/a def test_docstring(self):
74n/a def f():
75n/a f'''Not a docstring'''
76n/a self.assertIsNone(f.__doc__)
77n/a def g():
78n/a '''Not a docstring''' \
79n/a f''
80n/a self.assertIsNone(g.__doc__)
81n/a
82n/a def test_literal_eval(self):
83n/a with self.assertRaisesRegex(ValueError, 'malformed node or string'):
84n/a ast.literal_eval("f'x'")
85n/a
86n/a def test_ast_compile_time_concat(self):
87n/a x = ['']
88n/a
89n/a expr = """x[0] = 'foo' f'{3}'"""
90n/a t = ast.parse(expr)
91n/a c = compile(t, '', 'exec')
92n/a exec(c)
93n/a self.assertEqual(x[0], 'foo3')
94n/a
95n/a def test_compile_time_concat_errors(self):
96n/a self.assertAllRaise(SyntaxError,
97n/a 'cannot mix bytes and nonbytes literals',
98n/a [r"""f'' b''""",
99n/a r"""b'' f''""",
100n/a ])
101n/a
102n/a def test_literal(self):
103n/a self.assertEqual(f'', '')
104n/a self.assertEqual(f'a', 'a')
105n/a self.assertEqual(f' ', ' ')
106n/a
107n/a def test_unterminated_string(self):
108n/a self.assertAllRaise(SyntaxError, 'f-string: unterminated string',
109n/a [r"""f'{"x'""",
110n/a r"""f'{"x}'""",
111n/a r"""f'{("x'""",
112n/a r"""f'{("x}'""",
113n/a ])
114n/a
115n/a def test_mismatched_parens(self):
116n/a self.assertAllRaise(SyntaxError, 'f-string: mismatched',
117n/a ["f'{((}'",
118n/a ])
119n/a
120n/a def test_double_braces(self):
121n/a self.assertEqual(f'{{', '{')
122n/a self.assertEqual(f'a{{', 'a{')
123n/a self.assertEqual(f'{{b', '{b')
124n/a self.assertEqual(f'a{{b', 'a{b')
125n/a self.assertEqual(f'}}', '}')
126n/a self.assertEqual(f'a}}', 'a}')
127n/a self.assertEqual(f'}}b', '}b')
128n/a self.assertEqual(f'a}}b', 'a}b')
129n/a self.assertEqual(f'{{}}', '{}')
130n/a self.assertEqual(f'a{{}}', 'a{}')
131n/a self.assertEqual(f'{{b}}', '{b}')
132n/a self.assertEqual(f'{{}}c', '{}c')
133n/a self.assertEqual(f'a{{b}}', 'a{b}')
134n/a self.assertEqual(f'a{{}}c', 'a{}c')
135n/a self.assertEqual(f'{{b}}c', '{b}c')
136n/a self.assertEqual(f'a{{b}}c', 'a{b}c')
137n/a
138n/a self.assertEqual(f'{{{10}', '{10')
139n/a self.assertEqual(f'}}{10}', '}10')
140n/a self.assertEqual(f'}}{{{10}', '}{10')
141n/a self.assertEqual(f'}}a{{{10}', '}a{10')
142n/a
143n/a self.assertEqual(f'{10}{{', '10{')
144n/a self.assertEqual(f'{10}}}', '10}')
145n/a self.assertEqual(f'{10}}}{{', '10}{')
146n/a self.assertEqual(f'{10}}}a{{' '}', '10}a{}')
147n/a
148n/a # Inside of strings, don't interpret doubled brackets.
149n/a self.assertEqual(f'{"{{}}"}', '{{}}')
150n/a
151n/a self.assertAllRaise(TypeError, 'unhashable type',
152n/a ["f'{ {{}} }'", # dict in a set
153n/a ])
154n/a
155n/a def test_compile_time_concat(self):
156n/a x = 'def'
157n/a self.assertEqual('abc' f'## {x}ghi', 'abc## defghi')
158n/a self.assertEqual('abc' f'{x}' 'ghi', 'abcdefghi')
159n/a self.assertEqual('abc' f'{x}' 'gh' f'i{x:4}', 'abcdefghidef ')
160n/a self.assertEqual('{x}' f'{x}', '{x}def')
161n/a self.assertEqual('{x' f'{x}', '{xdef')
162n/a self.assertEqual('{x}' f'{x}', '{x}def')
163n/a self.assertEqual('{{x}}' f'{x}', '{{x}}def')
164n/a self.assertEqual('{{x' f'{x}', '{{xdef')
165n/a self.assertEqual('x}}' f'{x}', 'x}}def')
166n/a self.assertEqual(f'{x}' 'x}}', 'defx}}')
167n/a self.assertEqual(f'{x}' '', 'def')
168n/a self.assertEqual('' f'{x}' '', 'def')
169n/a self.assertEqual('' f'{x}', 'def')
170n/a self.assertEqual(f'{x}' '2', 'def2')
171n/a self.assertEqual('1' f'{x}' '2', '1def2')
172n/a self.assertEqual('1' f'{x}', '1def')
173n/a self.assertEqual(f'{x}' f'-{x}', 'def-def')
174n/a self.assertEqual('' f'', '')
175n/a self.assertEqual('' f'' '', '')
176n/a self.assertEqual('' f'' '' f'', '')
177n/a self.assertEqual(f'', '')
178n/a self.assertEqual(f'' '', '')
179n/a self.assertEqual(f'' '' f'', '')
180n/a self.assertEqual(f'' '' f'' '', '')
181n/a
182n/a self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
183n/a ["f'{3' f'}'", # can't concat to get a valid f-string
184n/a ])
185n/a
186n/a def test_comments(self):
187n/a # These aren't comments, since they're in strings.
188n/a d = {'#': 'hash'}
189n/a self.assertEqual(f'{"#"}', '#')
190n/a self.assertEqual(f'{d["#"]}', 'hash')
191n/a
192n/a self.assertAllRaise(SyntaxError, "f-string expression part cannot include '#'",
193n/a ["f'{1#}'", # error because the expression becomes "(1#)"
194n/a "f'{3(#)}'",
195n/a "f'{#}'",
196n/a "f'{)#}'", # When wrapped in parens, this becomes
197n/a # '()#)'. Make sure that doesn't compile.
198n/a ])
199n/a
200n/a def test_many_expressions(self):
201n/a # Create a string with many expressions in it. Note that
202n/a # because we have a space in here as a literal, we're actually
203n/a # going to use twice as many ast nodes: one for each literal
204n/a # plus one for each expression.
205n/a def build_fstr(n, extra=''):
206n/a return "f'" + ('{x} ' * n) + extra + "'"
207n/a
208n/a x = 'X'
209n/a width = 1
210n/a
211n/a # Test around 256.
212n/a for i in range(250, 260):
213n/a self.assertEqual(eval(build_fstr(i)), (x+' ')*i)
214n/a
215n/a # Test concatenating 2 largs fstrings.
216n/a self.assertEqual(eval(build_fstr(255)*256), (x+' ')*(255*256))
217n/a
218n/a s = build_fstr(253, '{x:{width}} ')
219n/a self.assertEqual(eval(s), (x+' ')*254)
220n/a
221n/a # Test lots of expressions and constants, concatenated.
222n/a s = "f'{1}' 'x' 'y'" * 1024
223n/a self.assertEqual(eval(s), '1xy' * 1024)
224n/a
225n/a def test_format_specifier_expressions(self):
226n/a width = 10
227n/a precision = 4
228n/a value = decimal.Decimal('12.34567')
229n/a self.assertEqual(f'result: {value:{width}.{precision}}', 'result: 12.35')
230n/a self.assertEqual(f'result: {value:{width!r}.{precision}}', 'result: 12.35')
231n/a self.assertEqual(f'result: {value:{width:0}.{precision:1}}', 'result: 12.35')
232n/a self.assertEqual(f'result: {value:{1}{0:0}.{precision:1}}', 'result: 12.35')
233n/a self.assertEqual(f'result: {value:{ 1}{ 0:0}.{ precision:1}}', 'result: 12.35')
234n/a self.assertEqual(f'{10:#{1}0x}', ' 0xa')
235n/a self.assertEqual(f'{10:{"#"}1{0}{"x"}}', ' 0xa')
236n/a self.assertEqual(f'{-10:-{"#"}1{0}x}', ' -0xa')
237n/a self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', ' -0xa')
238n/a self.assertEqual(f'{10:#{3 != {4:5} and width}x}', ' 0xa')
239n/a
240n/a self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
241n/a ["""f'{"s"!r{":10"}}'""",
242n/a
243n/a # This looks like a nested format spec.
244n/a ])
245n/a
246n/a self.assertAllRaise(SyntaxError, "invalid syntax",
247n/a [# Invalid syntax inside a nested spec.
248n/a "f'{4:{/5}}'",
249n/a ])
250n/a
251n/a self.assertAllRaise(SyntaxError, "f-string: expressions nested too deeply",
252n/a [# Can't nest format specifiers.
253n/a "f'result: {value:{width:{0}}.{precision:1}}'",
254n/a ])
255n/a
256n/a self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
257n/a [# No expansion inside conversion or for
258n/a # the : or ! itself.
259n/a """f'{"s"!{"r"}}'""",
260n/a ])
261n/a
262n/a def test_side_effect_order(self):
263n/a class X:
264n/a def __init__(self):
265n/a self.i = 0
266n/a def __format__(self, spec):
267n/a self.i += 1
268n/a return str(self.i)
269n/a
270n/a x = X()
271n/a self.assertEqual(f'{x} {x}', '1 2')
272n/a
273n/a def test_missing_expression(self):
274n/a self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed',
275n/a ["f'{}'",
276n/a "f'{ }'"
277n/a "f' {} '",
278n/a "f'{!r}'",
279n/a "f'{ !r}'",
280n/a "f'{10:{ }}'",
281n/a "f' { } '",
282n/a
283n/a # Catch the empty expression before the
284n/a # invalid conversion.
285n/a "f'{!x}'",
286n/a "f'{ !xr}'",
287n/a "f'{!x:}'",
288n/a "f'{!x:a}'",
289n/a "f'{ !xr:}'",
290n/a "f'{ !xr:a}'",
291n/a
292n/a "f'{!}'",
293n/a "f'{:}'",
294n/a
295n/a # We find the empty expression before the
296n/a # missing closing brace.
297n/a "f'{!'",
298n/a "f'{!s:'",
299n/a "f'{:'",
300n/a "f'{:x'",
301n/a ])
302n/a
303n/a def test_parens_in_expressions(self):
304n/a self.assertEqual(f'{3,}', '(3,)')
305n/a
306n/a # Add these because when an expression is evaluated, parens
307n/a # are added around it. But we shouldn't go from an invalid
308n/a # expression to a valid one. The added parens are just
309n/a # supposed to allow whitespace (including newlines).
310n/a self.assertAllRaise(SyntaxError, 'invalid syntax',
311n/a ["f'{,}'",
312n/a "f'{,}'", # this is (,), which is an error
313n/a ])
314n/a
315n/a self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
316n/a ["f'{3)+(4}'",
317n/a ])
318n/a
319n/a self.assertAllRaise(SyntaxError, 'EOL while scanning string literal',
320n/a ["f'{\n}'",
321n/a ])
322n/a
323n/a def test_backslashes_in_string_part(self):
324n/a self.assertEqual(f'\t', '\t')
325n/a self.assertEqual(r'\t', '\\t')
326n/a self.assertEqual(rf'\t', '\\t')
327n/a self.assertEqual(f'{2}\t', '2\t')
328n/a self.assertEqual(f'{2}\t{3}', '2\t3')
329n/a self.assertEqual(f'\t{3}', '\t3')
330n/a
331n/a self.assertEqual(f'\u0394', '\u0394')
332n/a self.assertEqual(r'\u0394', '\\u0394')
333n/a self.assertEqual(rf'\u0394', '\\u0394')
334n/a self.assertEqual(f'{2}\u0394', '2\u0394')
335n/a self.assertEqual(f'{2}\u0394{3}', '2\u03943')
336n/a self.assertEqual(f'\u0394{3}', '\u03943')
337n/a
338n/a self.assertEqual(f'\U00000394', '\u0394')
339n/a self.assertEqual(r'\U00000394', '\\U00000394')
340n/a self.assertEqual(rf'\U00000394', '\\U00000394')
341n/a self.assertEqual(f'{2}\U00000394', '2\u0394')
342n/a self.assertEqual(f'{2}\U00000394{3}', '2\u03943')
343n/a self.assertEqual(f'\U00000394{3}', '\u03943')
344n/a
345n/a self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}', '\u0394')
346n/a self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
347n/a self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}{3}', '2\u03943')
348n/a self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}{3}', '\u03943')
349n/a self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
350n/a self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}3', '2\u03943')
351n/a self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}3', '\u03943')
352n/a
353n/a self.assertEqual(f'\x20', ' ')
354n/a self.assertEqual(r'\x20', '\\x20')
355n/a self.assertEqual(rf'\x20', '\\x20')
356n/a self.assertEqual(f'{2}\x20', '2 ')
357n/a self.assertEqual(f'{2}\x20{3}', '2 3')
358n/a self.assertEqual(f'\x20{3}', ' 3')
359n/a
360n/a self.assertEqual(f'2\x20', '2 ')
361n/a self.assertEqual(f'2\x203', '2 3')
362n/a self.assertEqual(f'\x203', ' 3')
363n/a
364n/a def test_misformed_unicode_character_name(self):
365n/a # These test are needed because unicode names are parsed
366n/a # differently inside f-strings.
367n/a self.assertAllRaise(SyntaxError, r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape",
368n/a [r"f'\N'",
369n/a r"f'\N{'",
370n/a r"f'\N{GREEK CAPITAL LETTER DELTA'",
371n/a
372n/a # Here are the non-f-string versions,
373n/a # which should give the same errors.
374n/a r"'\N'",
375n/a r"'\N{'",
376n/a r"'\N{GREEK CAPITAL LETTER DELTA'",
377n/a ])
378n/a
379n/a def test_no_backslashes_in_expression_part(self):
380n/a self.assertAllRaise(SyntaxError, 'f-string expression part cannot include a backslash',
381n/a [r"f'{\'a\'}'",
382n/a r"f'{\t3}'",
383n/a r"f'{\}'",
384n/a r"rf'{\'a\'}'",
385n/a r"rf'{\t3}'",
386n/a r"rf'{\}'",
387n/a r"""rf'{"\N{LEFT CURLY BRACKET}"}'""",
388n/a r"f'{\n}'",
389n/a ])
390n/a
391n/a def test_no_escapes_for_braces(self):
392n/a """
393n/a Only literal curly braces begin an expression.
394n/a """
395n/a # \x7b is '{'.
396n/a self.assertEqual(f'\x7b1+1}}', '{1+1}')
397n/a self.assertEqual(f'\x7b1+1', '{1+1')
398n/a self.assertEqual(f'\u007b1+1', '{1+1')
399n/a self.assertEqual(f'\N{LEFT CURLY BRACKET}1+1\N{RIGHT CURLY BRACKET}', '{1+1}')
400n/a
401n/a def test_newlines_in_expressions(self):
402n/a self.assertEqual(f'{0}', '0')
403n/a self.assertEqual(rf'''{3+
404n/a4}''', '7')
405n/a
406n/a def test_lambda(self):
407n/a x = 5
408n/a self.assertEqual(f'{(lambda y:x*y)("8")!r}', "'88888'")
409n/a self.assertEqual(f'{(lambda y:x*y)("8")!r:10}', "'88888' ")
410n/a self.assertEqual(f'{(lambda y:x*y)("8"):10}', "88888 ")
411n/a
412n/a # lambda doesn't work without parens, because the colon
413n/a # makes the parser think it's a format_spec
414n/a self.assertAllRaise(SyntaxError, 'unexpected EOF while parsing',
415n/a ["f'{lambda x:x}'",
416n/a ])
417n/a
418n/a def test_yield(self):
419n/a # Not terribly useful, but make sure the yield turns
420n/a # a function into a generator
421n/a def fn(y):
422n/a f'y:{yield y*2}'
423n/a
424n/a g = fn(4)
425n/a self.assertEqual(next(g), 8)
426n/a
427n/a def test_yield_send(self):
428n/a def fn(x):
429n/a yield f'x:{yield (lambda i: x * i)}'
430n/a
431n/a g = fn(10)
432n/a the_lambda = next(g)
433n/a self.assertEqual(the_lambda(4), 40)
434n/a self.assertEqual(g.send('string'), 'x:string')
435n/a
436n/a def test_expressions_with_triple_quoted_strings(self):
437n/a self.assertEqual(f"{'''x'''}", 'x')
438n/a self.assertEqual(f"{'''eric's'''}", "eric's")
439n/a
440n/a # Test concatenation within an expression
441n/a self.assertEqual(f'{"x" """eric"s""" "y"}', 'xeric"sy')
442n/a self.assertEqual(f'{"x" """eric"s"""}', 'xeric"s')
443n/a self.assertEqual(f'{"""eric"s""" "y"}', 'eric"sy')
444n/a self.assertEqual(f'{"""x""" """eric"s""" "y"}', 'xeric"sy')
445n/a self.assertEqual(f'{"""x""" """eric"s""" """y"""}', 'xeric"sy')
446n/a self.assertEqual(f'{r"""x""" """eric"s""" """y"""}', 'xeric"sy')
447n/a
448n/a def test_multiple_vars(self):
449n/a x = 98
450n/a y = 'abc'
451n/a self.assertEqual(f'{x}{y}', '98abc')
452n/a
453n/a self.assertEqual(f'X{x}{y}', 'X98abc')
454n/a self.assertEqual(f'{x}X{y}', '98Xabc')
455n/a self.assertEqual(f'{x}{y}X', '98abcX')
456n/a
457n/a self.assertEqual(f'X{x}Y{y}', 'X98Yabc')
458n/a self.assertEqual(f'X{x}{y}Y', 'X98abcY')
459n/a self.assertEqual(f'{x}X{y}Y', '98XabcY')
460n/a
461n/a self.assertEqual(f'X{x}Y{y}Z', 'X98YabcZ')
462n/a
463n/a def test_closure(self):
464n/a def outer(x):
465n/a def inner():
466n/a return f'x:{x}'
467n/a return inner
468n/a
469n/a self.assertEqual(outer('987')(), 'x:987')
470n/a self.assertEqual(outer(7)(), 'x:7')
471n/a
472n/a def test_arguments(self):
473n/a y = 2
474n/a def f(x, width):
475n/a return f'x={x*y:{width}}'
476n/a
477n/a self.assertEqual(f('foo', 10), 'x=foofoo ')
478n/a x = 'bar'
479n/a self.assertEqual(f(10, 10), 'x= 20')
480n/a
481n/a def test_locals(self):
482n/a value = 123
483n/a self.assertEqual(f'v:{value}', 'v:123')
484n/a
485n/a def test_missing_variable(self):
486n/a with self.assertRaises(NameError):
487n/a f'v:{value}'
488n/a
489n/a def test_missing_format_spec(self):
490n/a class O:
491n/a def __format__(self, spec):
492n/a if not spec:
493n/a return '*'
494n/a return spec
495n/a
496n/a self.assertEqual(f'{O():x}', 'x')
497n/a self.assertEqual(f'{O()}', '*')
498n/a self.assertEqual(f'{O():}', '*')
499n/a
500n/a self.assertEqual(f'{3:}', '3')
501n/a self.assertEqual(f'{3!s:}', '3')
502n/a
503n/a def test_global(self):
504n/a self.assertEqual(f'g:{a_global}', 'g:global variable')
505n/a self.assertEqual(f'g:{a_global!r}', "g:'global variable'")
506n/a
507n/a a_local = 'local variable'
508n/a self.assertEqual(f'g:{a_global} l:{a_local}',
509n/a 'g:global variable l:local variable')
510n/a self.assertEqual(f'g:{a_global!r}',
511n/a "g:'global variable'")
512n/a self.assertEqual(f'g:{a_global} l:{a_local!r}',
513n/a "g:global variable l:'local variable'")
514n/a
515n/a self.assertIn("module 'unittest' from", f'{unittest}')
516n/a
517n/a def test_shadowed_global(self):
518n/a a_global = 'really a local'
519n/a self.assertEqual(f'g:{a_global}', 'g:really a local')
520n/a self.assertEqual(f'g:{a_global!r}', "g:'really a local'")
521n/a
522n/a a_local = 'local variable'
523n/a self.assertEqual(f'g:{a_global} l:{a_local}',
524n/a 'g:really a local l:local variable')
525n/a self.assertEqual(f'g:{a_global!r}',
526n/a "g:'really a local'")
527n/a self.assertEqual(f'g:{a_global} l:{a_local!r}',
528n/a "g:really a local l:'local variable'")
529n/a
530n/a def test_call(self):
531n/a def foo(x):
532n/a return 'x=' + str(x)
533n/a
534n/a self.assertEqual(f'{foo(10)}', 'x=10')
535n/a
536n/a def test_nested_fstrings(self):
537n/a y = 5
538n/a self.assertEqual(f'{f"{0}"*3}', '000')
539n/a self.assertEqual(f'{f"{y}"*3}', '555')
540n/a
541n/a def test_invalid_string_prefixes(self):
542n/a self.assertAllRaise(SyntaxError, 'unexpected EOF while parsing',
543n/a ["fu''",
544n/a "uf''",
545n/a "Fu''",
546n/a "fU''",
547n/a "Uf''",
548n/a "uF''",
549n/a "ufr''",
550n/a "urf''",
551n/a "fur''",
552n/a "fru''",
553n/a "rfu''",
554n/a "ruf''",
555n/a "FUR''",
556n/a "Fur''",
557n/a "fb''",
558n/a "fB''",
559n/a "Fb''",
560n/a "FB''",
561n/a "bf''",
562n/a "bF''",
563n/a "Bf''",
564n/a "BF''",
565n/a ])
566n/a
567n/a def test_leading_trailing_spaces(self):
568n/a self.assertEqual(f'{ 3}', '3')
569n/a self.assertEqual(f'{ 3}', '3')
570n/a self.assertEqual(f'{3 }', '3')
571n/a self.assertEqual(f'{3 }', '3')
572n/a
573n/a self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]}}',
574n/a 'expr={1: 2}')
575n/a self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]} }',
576n/a 'expr={1: 2}')
577n/a
578n/a def test_not_equal(self):
579n/a # There's a special test for this because there's a special
580n/a # case in the f-string parser to look for != as not ending an
581n/a # expression. Normally it would, while looking for !s or !r.
582n/a
583n/a self.assertEqual(f'{3!=4}', 'True')
584n/a self.assertEqual(f'{3!=4:}', 'True')
585n/a self.assertEqual(f'{3!=4!s}', 'True')
586n/a self.assertEqual(f'{3!=4!s:.3}', 'Tru')
587n/a
588n/a def test_conversions(self):
589n/a self.assertEqual(f'{3.14:10.10}', ' 3.14')
590n/a self.assertEqual(f'{3.14!s:10.10}', '3.14 ')
591n/a self.assertEqual(f'{3.14!r:10.10}', '3.14 ')
592n/a self.assertEqual(f'{3.14!a:10.10}', '3.14 ')
593n/a
594n/a self.assertEqual(f'{"a"}', 'a')
595n/a self.assertEqual(f'{"a"!r}', "'a'")
596n/a self.assertEqual(f'{"a"!a}', "'a'")
597n/a
598n/a # Not a conversion.
599n/a self.assertEqual(f'{"a!r"}', "a!r")
600n/a
601n/a # Not a conversion, but show that ! is allowed in a format spec.
602n/a self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!')
603n/a
604n/a self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
605n/a ["f'{3!g}'",
606n/a "f'{3!A}'",
607n/a "f'{3!3}'",
608n/a "f'{3!G}'",
609n/a "f'{3!!}'",
610n/a "f'{3!:}'",
611n/a "f'{3! s}'", # no space before conversion char
612n/a ])
613n/a
614n/a self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
615n/a ["f'{x!s{y}}'",
616n/a "f'{3!ss}'",
617n/a "f'{3!ss:}'",
618n/a "f'{3!ss:s}'",
619n/a ])
620n/a
621n/a def test_assignment(self):
622n/a self.assertAllRaise(SyntaxError, 'invalid syntax',
623n/a ["f'' = 3",
624n/a "f'{0}' = x",
625n/a "f'{x}' = x",
626n/a ])
627n/a
628n/a def test_del(self):
629n/a self.assertAllRaise(SyntaxError, 'invalid syntax',
630n/a ["del f''",
631n/a "del '' f''",
632n/a ])
633n/a
634n/a def test_mismatched_braces(self):
635n/a self.assertAllRaise(SyntaxError, "f-string: single '}' is not allowed",
636n/a ["f'{{}'",
637n/a "f'{{}}}'",
638n/a "f'}'",
639n/a "f'x}'",
640n/a "f'x}x'",
641n/a r"f'\u007b}'",
642n/a
643n/a # Can't have { or } in a format spec.
644n/a "f'{3:}>10}'",
645n/a "f'{3:}}>10}'",
646n/a ])
647n/a
648n/a self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
649n/a ["f'{3:{{>10}'",
650n/a "f'{3'",
651n/a "f'{3!'",
652n/a "f'{3:'",
653n/a "f'{3!s'",
654n/a "f'{3!s:'",
655n/a "f'{3!s:3'",
656n/a "f'x{'",
657n/a "f'x{x'",
658n/a "f'{x'",
659n/a "f'{3:s'",
660n/a "f'{{{'",
661n/a "f'{{}}{'",
662n/a "f'{'",
663n/a ])
664n/a
665n/a # But these are just normal strings.
666n/a self.assertEqual(f'{"{"}', '{')
667n/a self.assertEqual(f'{"}"}', '}')
668n/a self.assertEqual(f'{3:{"}"}>10}', '}}}}}}}}}3')
669n/a self.assertEqual(f'{2:{"{"}>10}', '{{{{{{{{{2')
670n/a
671n/a def test_if_conditional(self):
672n/a # There's special logic in compile.c to test if the
673n/a # conditional for an if (and while) are constants. Exercise
674n/a # that code.
675n/a
676n/a def test_fstring(x, expected):
677n/a flag = 0
678n/a if f'{x}':
679n/a flag = 1
680n/a else:
681n/a flag = 2
682n/a self.assertEqual(flag, expected)
683n/a
684n/a def test_concat_empty(x, expected):
685n/a flag = 0
686n/a if '' f'{x}':
687n/a flag = 1
688n/a else:
689n/a flag = 2
690n/a self.assertEqual(flag, expected)
691n/a
692n/a def test_concat_non_empty(x, expected):
693n/a flag = 0
694n/a if ' ' f'{x}':
695n/a flag = 1
696n/a else:
697n/a flag = 2
698n/a self.assertEqual(flag, expected)
699n/a
700n/a test_fstring('', 2)
701n/a test_fstring(' ', 1)
702n/a
703n/a test_concat_empty('', 2)
704n/a test_concat_empty(' ', 1)
705n/a
706n/a test_concat_non_empty('', 1)
707n/a test_concat_non_empty(' ', 1)
708n/a
709n/a def test_empty_format_specifier(self):
710n/a x = 'test'
711n/a self.assertEqual(f'{x}', 'test')
712n/a self.assertEqual(f'{x:}', 'test')
713n/a self.assertEqual(f'{x!s:}', 'test')
714n/a self.assertEqual(f'{x!r:}', "'test'")
715n/a
716n/a def test_str_format_differences(self):
717n/a d = {'a': 'string',
718n/a 0: 'integer',
719n/a }
720n/a a = 0
721n/a self.assertEqual(f'{d[0]}', 'integer')
722n/a self.assertEqual(f'{d["a"]}', 'string')
723n/a self.assertEqual(f'{d[a]}', 'integer')
724n/a self.assertEqual('{d[a]}'.format(d=d), 'string')
725n/a self.assertEqual('{d[0]}'.format(d=d), 'integer')
726n/a
727n/a def test_invalid_expressions(self):
728n/a self.assertAllRaise(SyntaxError, 'invalid syntax',
729n/a [r"f'{a[4)}'",
730n/a r"f'{a(4]}'",
731n/a ])
732n/a
733n/a def test_errors(self):
734n/a # see issue 26287
735n/a self.assertAllRaise(TypeError, 'unsupported',
736n/a [r"f'{(lambda: 0):x}'",
737n/a r"f'{(0,):x}'",
738n/a ])
739n/a self.assertAllRaise(ValueError, 'Unknown format code',
740n/a [r"f'{1000:j}'",
741n/a r"f'{1000:j}'",
742n/a ])
743n/a
744n/a def test_loop(self):
745n/a for i in range(1000):
746n/a self.assertEqual(f'i:{i}', 'i:' + str(i))
747n/a
748n/a def test_dict(self):
749n/a d = {'"': 'dquote',
750n/a "'": 'squote',
751n/a 'foo': 'bar',
752n/a }
753n/a self.assertEqual(f'''{d["'"]}''', 'squote')
754n/a self.assertEqual(f"""{d['"']}""", 'dquote')
755n/a
756n/a self.assertEqual(f'{d["foo"]}', 'bar')
757n/a self.assertEqual(f"{d['foo']}", 'bar')
758n/a
759n/aif __name__ == '__main__':
760n/a unittest.main()