diff --git a/test/bytecode_3.6_run/01_fstring.pyc b/test/bytecode_3.6_run/01_fstring.pyc index 8f6a2a1d..54711a34 100644 Binary files a/test/bytecode_3.6_run/01_fstring.pyc and b/test/bytecode_3.6_run/01_fstring.pyc differ diff --git a/test/simple_source/bug36/01_fstring.py b/test/simple_source/bug36/01_fstring.py index c03aaa79..0b753075 100644 --- a/test/simple_source/bug36/01_fstring.py +++ b/test/simple_source/bug36/01_fstring.py @@ -17,3 +17,10 @@ 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' diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 1225bb68..ef0dee17 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -184,8 +184,17 @@ class Python36Parser(Python35Parser): self.add_unique_doc_rules(rules_str, customize) elif opname == 'FORMAT_VALUE': rules_str = """ - expr ::= fstring_single - fstring_single ::= expr FORMAT_VALUE + expr ::= fstring_single + fstring_single ::= expr FORMAT_VALUE + expr ::= fstring_expr + fstring_expr ::= expr FORMAT_VALUE + + # FIXME: need to look inside FORMAT_VALUE to see if 4 + fstring_single ::= expr expr FORMAT_VALUE + str ::= LOAD_CONST + formatted_value ::= fstring_expr + formatted_value ::= str + """ self.add_unique_doc_rules(rules_str, customize) elif opname == 'MAKE_FUNCTION_8': @@ -233,12 +242,6 @@ class Python36Parser(Python35Parser): v = token.attr joined_str_n = "formatted_value_%s" % v rules_str = """ - expr ::= fstring_expr - fstring_expr ::= expr FORMAT_VALUE - str ::= LOAD_CONST - formatted_value ::= fstring_expr - formatted_value ::= str - expr ::= fstring_multi fstring_multi ::= joined_str BUILD_STRING joined_str ::= formatted_value+ diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 5b283ad1..f2a3bf1f 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -324,7 +324,7 @@ def customize_for_version36(self, version): self.call36_dict = call36_dict - FSTRING_CONVERSION_MAP = {1: '!s', 2: '!r', 3: '!a'} + FSTRING_CONVERSION_MAP = {1: '!s', 2: '!r', 3: '!a', 'X':':X'} def n_except_suite_finalize(node): if node[1] == 'returns' and self.hide_internal: @@ -351,7 +351,12 @@ def customize_for_version36(self, version): self.n_formatted_value = n_formatted_value def f_conversion(node): - node.conversion = FSTRING_CONVERSION_MAP.get(node.data[1].attr, '') + fmt_node = node.data[1] + if fmt_node == 'expr' and fmt_node[0] == 'LOAD_CONST': + data = fmt_node[0].attr + else: + data = fmt_node + node.conversion = FSTRING_CONVERSION_MAP.get(data, '') def fstring_expr(node): f_conversion(node)