circuitpython/tests/basics/string_pep498_fstring.py

114 lines
3.7 KiB
Python

# Tests against https://www.python.org/dev/peps/pep-0498/
assert f'no interpolation' == 'no interpolation'
assert f"no interpolation" == 'no interpolation'
# Quoth the PEP:
# Backslashes may not appear anywhere within expressions. Comments, using the
# '#' character, are not allowed inside an expression
#
# CPython (3.7.4 on Linux) raises a SyntaxError here:
# >>> f'{#}'
# File "<stdin>", line 1
# SyntaxError: f-string expression part cannot include '#'
# >>> f'{\}'
# File "<stdin>", line 1
# SyntaxError: f-string expression part cannot include a backslash
# >>> f'{\\}'
# File "<stdin>", line 1
# SyntaxError: f-string expression part cannot include a backslash
# >>> f'{\#}'
# File "<stdin>", line 1
# SyntaxError: f-string expression part cannot include a backslash
# Backslashes and comments allowed outside expression
assert f"\\" == "\\"
assert f'#' == '#'
## But not inside
try:
eval("f'{\}'")
except SyntaxError:
pass
else:
raise AssertionError('f-string with backslash in expression did not raise SyntaxError')
try:
eval("f'{#}'")
except SyntaxError:
pass
else:
raise AssertionError('f-string with \'#\' in expression did not raise SyntaxError')
# Quoth the PEP:
# While scanning the string for expressions, any doubled braces '{{' or '}}'
# inside literal portions of an f-string are replaced by the corresponding
# single brace. Doubled literal opening braces do not signify the start of an
# expression. A single closing curly brace '}' in the literal portion of a
# string is an error: literal closing curly braces must be doubled '}}' in
# order to represent a single closing brace.
#
# CPython (3.7.4 on Linux) raises a SyntaxError for the last case:
# >>> f'{{}'
# File "<stdin>", line 1
# SyntaxError: f-string: single '}' is not allowed
assert f'{{}}' == '{}'
try:
eval("f'{{}'")
except ValueError:
pass
else:
raise RuntimeError('Expected ValueError for invalid f-string literal bracing')
x = 1
assert f'{x}' == '1'
# Quoth the PEP:
# The expressions that are extracted from the string are evaluated in the
# context where the f-string appeared. This means the expression has full
# access to local and global variables. Any valid Python expression can be
# used, including function and method calls. Because the f-strings are
# evaluated where the string appears in the source code, there is no additional
# expressiveness available with f-strings. There are also no additional
# security concerns: you could have also just written the same expression, not
# inside of an f-string:
def foo():
return 20
assert f'result={foo()}' == 'result=20'
assert f'result={foo()}' == 'result={}'.format(foo())
assert f'result={foo()}' == 'result={result}'.format(result=foo())
# Quoth the PEP:
# Adjacent f-strings and regular strings are concatenated. Regular strings are
# concatenated at compile time, and f-strings are concatenated at run time. For
# example, the expression:
#
# >>> x = 10
# >>> y = 'hi'
# >>> 'a' 'b' f'{x}' '{c}' f'str<{y:^4}>' 'd' 'e'
#
# yields the value: 'ab10{c}str< hi >de'
#
# Because strings are concatenated at lexer time rather than parser time in
# MicroPython for mostly RAM efficiency reasons (see
# https://github.com/micropython/micropython/commit/534b7c368dc2af7720f3aaed0c936ef46d773957),
# and because f-strings here are implemented as a syntax translation
# (f'{something}' => '{}'.format(something)), this particular functionality is unimplemented,
# and in the above example, the '{c}' portion will trigger a KeyError on String.format()
x = 10
y = 'hi'
assert (f'h' f'i') == 'hi'
#assert (f'h' 'i') == 'hi'
#assert ('h' f'i') == 'hi'
assert f'{x:^4}' == ' 10 '
#assert ('a' 'b' f'{x}' f'str<{y:^4}>' 'd' 'e') == 'ab10str< hi >de'
# Other tests
assert f'{{{4*10}}}' == '{40}'