You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-02 16:44:46 +08:00
lambda formatting in f-string
In a formatted string using "lambda', we should not add "\n". For example in: f'{(lambda x:x)("8")!r}' Adding a "\n" after "lambda x: x" will give an error message: SyntaxError: f-string expression part cannot include a backslash
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,13 +2,17 @@
|
|||||||
# String interpolation tests
|
# String interpolation tests
|
||||||
|
|
||||||
# RUNNABLE!
|
# RUNNABLE!
|
||||||
var1 = 'x'
|
"""This program is self-checking!"""
|
||||||
var2 = 'y'
|
|
||||||
abc = 'def'
|
var1 = "x"
|
||||||
assert (f"interpolate {var1} strings {var2!r} {var2!s} 'py36" ==
|
var2 = "y"
|
||||||
"interpolate x strings 'y' y 'py36")
|
abc = "def"
|
||||||
assert 'def0' == f'{abc}0'
|
assert (
|
||||||
assert 'defdef' == f'{abc}{abc!s}'
|
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
|
# From 3.6 functools.py
|
||||||
# Bug was handling format operator strings.
|
# Bug was handling format operator strings.
|
||||||
@@ -21,51 +25,51 @@ assert y == "functools.1=['2'](2)"
|
|||||||
|
|
||||||
# From 3.6 http/client.py
|
# From 3.6 http/client.py
|
||||||
# Bug is in handling X
|
# Bug is in handling X
|
||||||
chunk = ['a', 'b', 'c']
|
chunk = ["a", "b", "c"]
|
||||||
chunk2 = 'd'
|
chunk2 = "d"
|
||||||
chunk = f'{len(chunk):X}' + chunk2
|
chunk = f"{len(chunk):X}" + chunk2
|
||||||
assert chunk == '3d'
|
assert chunk == "3d"
|
||||||
|
|
||||||
chunk = b'abc'
|
chunk = b"abc"
|
||||||
chunk2 = 'd'
|
chunk2 = "d"
|
||||||
chunk = f'{len(chunk):X}\r\n'.encode('ascii') + chunk \
|
chunk = f"{len(chunk):X}\r\n".encode("ascii") + chunk + b"\r\n"
|
||||||
+ b'\r\n'
|
assert chunk == b"3\r\nabc\r\n"
|
||||||
assert chunk == b'3\r\nabc\r\n'
|
|
||||||
|
|
||||||
# From 3.6.8 idlelib/pyshell.py
|
# From 3.6.8 idlelib/pyshell.py
|
||||||
# Bug was handling '''
|
# Bug was handling '''
|
||||||
import os
|
import os
|
||||||
filename = '.'
|
|
||||||
source = 'foo'
|
filename = "."
|
||||||
source = (f"__file__ = r'''{os.path.abspath(filename)}'''\n"
|
source = "foo"
|
||||||
+ source + "\ndel __file__")
|
source = f"__file__ = r'''{os.path.abspath(filename)}'''\n" + source + "\ndel __file__"
|
||||||
|
|
||||||
# Note how { and } are *not* escaped here
|
# Note how { and } are *not* escaped here
|
||||||
f = 'one'
|
f = "one"
|
||||||
name = 'two'
|
name = "two"
|
||||||
assert(f"{f}{'{{name}}'} {f}{'{name}'}") == 'one{{name}} one{name}'
|
assert (f"{f}{'{{name}}'} {f}{'{name}'}") == "one{{name}} one{name}"
|
||||||
|
|
||||||
# From 3.7.3 dataclasses.py
|
# From 3.7.3 dataclasses.py
|
||||||
log_rounds = 5
|
log_rounds = 5
|
||||||
assert "05$" == f'{log_rounds:02d}$'
|
assert "05$" == f"{log_rounds:02d}$"
|
||||||
|
|
||||||
|
|
||||||
def testit(a, b, l):
|
def testit(a, b, l):
|
||||||
# print(l)
|
# print(l)
|
||||||
return l
|
return l
|
||||||
|
|
||||||
|
|
||||||
# The call below shows the need for BUILD_STRING to count expr arguments.
|
# 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
|
# Also note that we use {{ }} to escape braces in contrast to the example
|
||||||
# above.
|
# above.
|
||||||
def _repr_fn(fields):
|
def _repr_fn(fields):
|
||||||
return testit('__repr__',
|
return testit(
|
||||||
('self',),
|
"__repr__",
|
||||||
['return xx + f"(' +
|
("self",),
|
||||||
', '.join([f"{f}={{self.{f}!r}}"
|
['return xx + f"(' + ", ".join([f"{f}={{self.{f}!r}}" for f in fields]) + ')"'],
|
||||||
for f in fields]) +
|
)
|
||||||
')"'])
|
|
||||||
|
|
||||||
fields = ['a', 'b', 'c']
|
|
||||||
|
fields = ["a", "b", "c"]
|
||||||
assert _repr_fn(fields) == ['return xx + f"(a={self.a!r}, b={self.b!r}, c={self.c!r})"']
|
assert _repr_fn(fields) == ['return xx + f"(a={self.a!r}, b={self.b!r}, c={self.c!r})"']
|
||||||
|
|
||||||
|
|
||||||
@@ -85,28 +89,31 @@ else:
|
|||||||
assert False, "f'{lambda x:x}' should be a syntax error"
|
assert False, "f'{lambda x:x}' should be a syntax error"
|
||||||
|
|
||||||
(x, y, width) = ("foo", 2, 10)
|
(x, y, width) = ("foo", 2, 10)
|
||||||
assert f'x={x*y:{width}}' == 'x=foofoo '
|
assert f"x={x*y:{width}}" == "x=foofoo "
|
||||||
|
|
||||||
# Why the fact that the distinction of docstring versus stmt is a
|
# Why the fact that the distinction of docstring versus stmt is a
|
||||||
# string expression is important academic, but we will decompile an
|
# string expression is important academic, but we will decompile an
|
||||||
# equivalent thing. For compatiblity with older Python we'll use "%"
|
# equivalent thing. For compatiblity with older Python we'll use "%"
|
||||||
# instead of a format string
|
# instead of a format string
|
||||||
def f():
|
def f():
|
||||||
f'''Not a docstring'''
|
f"""Not a docstring"""
|
||||||
|
|
||||||
|
|
||||||
def g():
|
def g():
|
||||||
'''Not a docstring''' \
|
"""Not a docstring""" f""
|
||||||
f''
|
|
||||||
|
|
||||||
assert f.__doc__ is None
|
assert f.__doc__ is None
|
||||||
assert g.__doc__ is None
|
assert g.__doc__ is None
|
||||||
|
|
||||||
import decimal
|
import decimal
|
||||||
width, precision, value = (10, 4, decimal.Decimal('12.34567'))
|
|
||||||
|
width, precision, value = (10, 4, decimal.Decimal("12.34567"))
|
||||||
|
|
||||||
# Make sure we don't have additional f'..' inside the format strings below.
|
# 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}.{precision}}" == "result: 12.35"
|
||||||
assert f'result: {value:{width:0}.{precision:1}}' == 'result: 12.35'
|
assert f"result: {value:{width:0}.{precision:1}}" == "result: 12.35"
|
||||||
assert f'{2}\t' == '2\t'
|
assert f"{2}\t" == "2\t"
|
||||||
|
|
||||||
# But below we *do* need the additional f".."
|
# But below we *do* need the additional f".."
|
||||||
assert f'{f"{0}"*3}' == "000"
|
assert f'{f"{0}"*3}' == "000"
|
||||||
@@ -115,4 +122,4 @@ assert f'{f"{0}"*3}' == "000"
|
|||||||
# ^
|
# ^
|
||||||
# The former, {{ confuses the format strings so dictionary/set comprehensions
|
# The former, {{ confuses the format strings so dictionary/set comprehensions
|
||||||
# don't work.
|
# don't work.
|
||||||
assert f'expr={ {x: y for x, y in [(1, 2), ]}}' == 'expr={1: 2}'
|
assert f"expr={ {x: y for x, y in [(1, 2), ]}}" == "expr={1: 2}"
|
||||||
|
@@ -2553,7 +2553,16 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
else:
|
else:
|
||||||
self.customize(customize)
|
self.customize(customize)
|
||||||
self.text = self.traverse(ast, is_lambda=is_lambda)
|
self.text = self.traverse(ast, is_lambda=is_lambda)
|
||||||
self.println(self.text)
|
# In a formatted string using "lambda', we should not add "\n".
|
||||||
|
# For example in:
|
||||||
|
# f'{(lambda x:x)("8")!r}'
|
||||||
|
# Adding a "\n" after "lambda x: x" will give an error message:
|
||||||
|
# SyntaxError: f-string expression part cannot include a backslash
|
||||||
|
# So avoid that.
|
||||||
|
printfn = (
|
||||||
|
self.write if self.in_format_string and is_lambda else self.println
|
||||||
|
)
|
||||||
|
printfn(self.text)
|
||||||
self.name = old_name
|
self.name = old_name
|
||||||
self.return_none = rn
|
self.return_none = rn
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user