# Self-checking test. # String interpolation tests # RUNNABLE! var1 = 'x' var2 = 'y' abc = 'def' assert (f"interpolate {var1} strings {var2!r} {var2!s} 'py36" == "interpolate x strings 'y' y 'py36") assert 'def0' == f'{abc}0' assert 'defdef' == f'{abc}{abc!s}' # From 3.6 functools.py # Bug was handling format operator strings. k, v = "1", ["2"] x = f"{k}={v!r}" y = f"functools.{x}({', '.join(v)})" assert x == "1=['2']" assert y == "functools.1=['2'](2)" # From 3.6 http/client.py # Bug is in handling X chunk = ['a', 'b', 'c'] chunk2 = 'd' chunk = f'{len(chunk):X}' + chunk2 assert chunk == '3d' chunk = b'abc' chunk2 = 'd' chunk = f'{len(chunk):X}\r\n'.encode('ascii') + chunk \ + b'\r\n' assert chunk == b'3\r\nabc\r\n' # From 3.6.8 idlelib/pyshell.py # Bug was handling ''' import os filename = '.' source = 'foo' source = (f"__file__ = r'''{os.path.abspath(filename)}'''\n" + source + "\ndel __file__") # Note how { and } are *not* escaped here f = 'one' name = 'two' assert(f"{f}{'{{name}}'} {f}{'{name}'}") == 'one{{name}} one{name}' # From 3.7.3 dataclasses.py log_rounds = 5 assert "05$" == f'{log_rounds:02d}$' def testit(a, b, l): # print(l) return l # The call below shows the need for BUILD_STRING to count expr arguments. # Also note that we use {{ }} to escape braces in contrast to the example # above. def _repr_fn(fields): return testit('__repr__', ('self',), ['return xx + f"(' + ', '.join([f"{f}={{self.{f}!r}}" for f in fields]) + ')"']) fields = ['a', 'b', 'c'] assert _repr_fn(fields) == ['return xx + f"(a={self.a!r}, b={self.b!r}, c={self.c!r})"'] ################################# # From Python 3.7 test_fstring.py x = 5 assert f'{(lambda y:x*y)("8")!r}' == "'88888'" assert f'{(lambda y:x*y)("8")!r:10}' == "'88888' " assert f'{(lambda y:x*y)("8"):10}' == "88888 " try: eval("f'{lambda x:x}'") except SyntaxError: pass else: assert False, "f'{lambda x:x}' should be a syntax error" (x, y, width) = ("foo", 2, 10) assert f'x={x*y:{width}}' == 'x=foofoo ' # Why the fact that the distinction of docstring versus stmt is a # string expression is important academic, but we will decompile an # equivalent thing. For compatiblity with older Python we'll use "%" # instead of a format string def f(): f'''Not a docstring''' def g(): '''Not a docstring''' \ f'' assert f.__doc__ is None assert g.__doc__ is None import decimal width, precision, value = (10, 4, decimal.Decimal('12.34567')) # Make sure we don't have additional f'..' inside the format strings below. assert f'result: {value:{width}.{precision}}' == 'result: 12.35' assert f'result: {value:{width:0}.{precision:1}}' == 'result: 12.35' assert f'{2}\t' == '2\t' # But below we *do* need the additional f".." assert f'{f"{0}"*3}' == "000" # We need to make sure we have { {x:... not {{x: ... # ^ # The former, {{ confuses the format strings so dictionary/set comprehensions # don't work. assert f'expr={ {x: y for x, y in [(1, 2), ]}}' == 'expr={1: 2}'