diff --git a/test/bytecode_3.6/01_fstring.pyc b/test/bytecode_3.6/01_fstring.pyc deleted file mode 100644 index 7d959b54..00000000 Binary files a/test/bytecode_3.6/01_fstring.pyc and /dev/null differ diff --git a/test/bytecode_3.6/02_kwargs.pyc b/test/bytecode_3.6/02_kwargs.pyc index 9d10442a..380321ca 100644 Binary files a/test/bytecode_3.6/02_kwargs.pyc and b/test/bytecode_3.6/02_kwargs.pyc differ diff --git a/test/bytecode_3.6_run/01_fstring.pyc b/test/bytecode_3.6_run/01_fstring.pyc new file mode 100644 index 00000000..8f6a2a1d Binary files /dev/null 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 d9db44dc..26bc3904 100644 --- a/test/simple_source/bug36/01_fstring.py +++ b/test/simple_source/bug36/01_fstring.py @@ -1,5 +1,18 @@ +# Self-checking 3.6+ string interpolation tests + var1 = 'x' var2 = 'y' -print(f'interpolate {var1} strings {var2!r} {var2!s} py36') -print(f'{abc}0') -print(f'{abc}{abc!s}') +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)" diff --git a/test/simple_source/bug36/02_kwargs.py b/test/simple_source/bug36/02_kwargs.py index 5c56adae..5b5af9e9 100644 --- a/test/simple_source/bug36/02_kwargs.py +++ b/test/simple_source/bug36/02_kwargs.py @@ -1,5 +1,13 @@ # From 3.6 _markupbase _parse_doctype_subset() -def bug(self, j): +def bug(self, j, a, b): self.parse_comment(j, report=0) self.parse_comment(j, report=1, foo=2) self.parse_comment(a, b, report=3) + +# From 3.6 fnmatch.py +# Bug was precidence parenthesis around decorator + +import functools +@functools.lru_cache(maxsize=256, typed=True) +def _compile_pattern(pat): + pass diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 682899f5..8071c4fa 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -317,6 +317,10 @@ MAP = { # See https://docs.python.org/2/reference/expressions.html # or https://docs.python.org/3/reference/expressions.html # for a list. + +# Things at the top of this list below with low-value precidence will +# tend to have parenthesis around them. Things at the bottom +# of the list will tend not to have parenthesis around them. PRECEDENCE = { 'list': 0, 'dict': 0, @@ -377,8 +381,9 @@ PRECEDENCE = { 'ret_cond_not': 28, '_mklambda': 30, - 'yield': 101, - 'yield_from': 101 + 'call_kw': 100, # 100 seems to to be module/function precidence + 'yield': 101, + 'yield_from': 101 } ASSIGN_TUPLE_PARAM = lambda param_name: \ diff --git a/uncompyle6/semantics/customize.py b/uncompyle6/semantics/customize.py index 57098598..3e88842e 100644 --- a/uncompyle6/semantics/customize.py +++ b/uncompyle6/semantics/customize.py @@ -357,8 +357,10 @@ def customize_for_version(self, is_pypy, version): 'tryfinally36': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', (1, 'returns'), 3 ), 'fstring_expr': ( "{%c%{conversion}}", 0), - 'fstring_single': ( "f'{%c%{conversion}}'", 0), - 'fstring_multi': ( "f'%c'", 0), + # FIXME: the below assumes the format strings + # don't have ''' in them. Fix this properly + 'fstring_single': ( "f'''{%c%{conversion}}'''", 0), + 'fstring_multi': ( "f'''%c'''", 0), 'func_args36': ( "%c(**", 0), 'try_except36': ( '%|try:\n%+%c%-%c\n\n', 1, 2 ), 'unpack_list': ( '*%c', (0, 'list') ), @@ -603,6 +605,14 @@ def customize_for_version(self, is_pypy, version): FSTRING_CONVERSION_MAP = {1: '!s', 2: '!r', 3: '!a'} + def n_formatted_value(node): + if node[0] == 'LOAD_CONST': + self.write(node[0].attr) + self.prune() + else: + self.default(node) + self.n_formatted_value = n_formatted_value + def f_conversion(node): node.conversion = FSTRING_CONVERSION_MAP.get(node.data[1].attr, '')