diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..4abc80f0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: False diff --git a/__pkginfo__.py b/__pkginfo__.py index d01a8bf4..4b6d9fe6 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -75,7 +75,7 @@ entry_points = { ] } ftp_url = None -install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 6.0.2, < 6.1.0"] +install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 6.0.2, < 6.2.0"] license = "GPL3" mailing_list = "python-debugger@googlegroups.com" diff --git a/test/test_pythonlib.py b/test/test_pythonlib.py index cbef614f..6d06e1d2 100755 --- a/test/test_pythonlib.py +++ b/test/test_pythonlib.py @@ -29,11 +29,18 @@ Step 2: Run the test: from __future__ import print_function -import getopt, os, py_compile, sys, shutil, tempfile, time - +import getopt +import os +import py_compile +import shutil +import sys +import tempfile +import time from fnmatch import fnmatch + +from xdis.version_info import PYTHON_VERSION_TRIPLE + from uncompyle6.main import main -from xdis.version_info import PYTHON_VERSION def get_srcdir(): @@ -164,10 +171,10 @@ def do_tests(src_dir, obj_patterns, target_dir, opts): if opts["do_compile"]: compiled_version = opts["compiled_version"] - if compiled_version and PYTHON_VERSION != compiled_version: + if compiled_version and PYTHON_VERSION_TRIPLE != compiled_version: print( "Not compiling: desired Python version is %s but we are running %s" - % (compiled_version, PYTHON_VERSION), + % (compiled_version, PYTHON_VERSION_TRIPLE), file=sys.stderr, ) else: diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index 58286b00..2553bf82 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2017, 2019-2020, 2022 Rocky Bernstein +# Copyright (c) 2016-2017, 2019-2020, 2022-2023 Rocky Bernstein """ Python 3.7 base code. We keep non-custom-generated grammar rules out of this file. """ @@ -431,35 +431,39 @@ class Python37BaseParser(PythonParser): "BUILD_TUPLE", "BUILD_TUPLE_UNPACK", ): - v = token.attr + collection_size = token.attr is_LOAD_CLOSURE = False if opname_base == "BUILD_TUPLE": # If is part of a "load_closure", then it is not part of a # "list". is_LOAD_CLOSURE = True - for j in range(v): + for j in range(collection_size): if tokens[i - j - 1].kind != "LOAD_CLOSURE": is_LOAD_CLOSURE = False break if is_LOAD_CLOSURE: - rule = "load_closure ::= %s%s" % (("LOAD_CLOSURE " * v), opname) + rule = "load_closure ::= %s%s" % ( + ("LOAD_CLOSURE " * collection_size), + opname, + ) self.add_unique_rule(rule, opname, token.attr, customize) - if not is_LOAD_CLOSURE or v == 0: + if not is_LOAD_CLOSURE or collection_size == 0: # We do this complicated test to speed up parsing of # pathelogically long literals, especially those over 1024. - build_count = token.attr - thousands = build_count // 1024 - thirty32s = (build_count // 32) % 32 + thousands = collection_size // 1024 + thirty32s = (collection_size // 32) % 32 if thirty32s > 0: rule = "expr32 ::=%s" % (" expr" * 32) - self.add_unique_rule(rule, opname_base, build_count, customize) + self.add_unique_rule( + rule, opname_base, collection_size, customize + ) pass if thousands > 0: self.add_unique_rule( "expr1024 ::=%s" % (" expr32" * 32), opname_base, - build_count, + collection_size, customize, ) pass @@ -468,7 +472,7 @@ class Python37BaseParser(PythonParser): ("%s ::= " % collection) + "expr1024 " * thousands + "expr32 " * thirty32s - + "expr " * (build_count % 32) + + "expr " * (collection_size % 32) + opname ) self.add_unique_rules(["expr ::= %s" % collection, rule], customize) @@ -478,8 +482,8 @@ class Python37BaseParser(PythonParser): if token.attr == 2: self.add_unique_rules( [ - "expr ::= build_slice2", - "build_slice2 ::= expr expr BUILD_SLICE_2", + "expr ::= slice2", + "slice2 ::= expr expr BUILD_SLICE_2", ], customize, ) @@ -489,8 +493,8 @@ class Python37BaseParser(PythonParser): ) self.add_unique_rules( [ - "expr ::= build_slice3", - "build_slice3 ::= expr expr expr BUILD_SLICE_3", + "expr ::= slice3", + "slice3 ::= expr expr expr BUILD_SLICE_3", ], customize, ) @@ -524,6 +528,7 @@ class Python37BaseParser(PythonParser): if opname == "CALL_FUNCTION" and token.attr == 1: rule = """ + expr ::= dict_comp dict_comp ::= LOAD_DICTCOMP LOAD_STR MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1 @@ -558,11 +563,12 @@ class Python37BaseParser(PythonParser): nak = (len(opname_base) - len("CALL_METHOD")) // 3 rule = ( "call ::= expr " - + ("expr " * args_pos) + + ("pos_arg " * args_pos) + ("kwarg " * args_kw) + "expr " * nak + opname ) + self.add_unique_rule(rule, opname, token.attr, customize) elif opname == "CONTINUE": @@ -1252,21 +1258,9 @@ class Python37BaseParser(PythonParser): try: if fn: return fn(self, lhs, n, rule, ast, tokens, first, last) - except: + except Exception: import sys, traceback - print( - ("Exception in %s %s\n" - + "rule: %s\n" - + "offsets %s .. %s") - % ( - fn.__name__, - sys.exc_info()[1], - rule2str(rule), - tokens[first].offset, - tokens[last].offset, - ) - ) print(traceback.print_tb(sys.exc_info()[2], -1)) raise ParserError(tokens[last], tokens[last].off2int(), self.debug["rules"]) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index f58ce171..ace74a02 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016-2021 by Rocky Bernstein +# Copyright (c) 2016-2021, 2023 by Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock # @@ -180,7 +180,7 @@ class Token: elif name == "LOAD_ASSERT": return "%s%s %s" % (prefix, offset_opname, pattr) elif self.op in self.opc.NAME_OPS: - if self.opc.version >= 3.0: + if self.opc.version_tuple >= (3, 0): return "%s%s%s %s" % (prefix, offset_opname, argstr, self.attr) elif name == "EXTENDED_ARG": return "%s%s%s 0x%x << %s = %s" % ( diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index a94f44b2..30bacc01 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -170,6 +170,7 @@ def customize_for_version36(self, version): class_name = node[1][1].attr if self.is_pypy and class_name.find("") > 0: class_name = class_name.split(".")[-1] + else: class_name = node[1][2].attr build_class = node @@ -206,23 +207,24 @@ def customize_for_version36(self, version): elif build_class[1][0] == "load_closure": # Python 3 with closures not functions load_closure = build_class[1] - if hasattr(load_closure[-3], "attr"): - # Python 3.3 classes with closures work like this. - # Note have to test before 3.2 case because - # index -2 also has an attr. - subclass_code = load_closure[-3].attr - elif hasattr(load_closure[-2], "attr"): - # Python 3.2 works like this - subclass_code = load_closure[-2].attr - else: - raise "Internal Error n_classdef: cannot find class body" + subclass_code = None + for i in range(-4, -1): + if load_closure[i] == "LOAD_CODE": + subclass_code = load_closure[i].attr + break + if subclass_code is None: + raise RuntimeError( + "Internal Error n_classdef: cannot find " "class body" + ) if hasattr(build_class[3], "__len__"): if not subclass_info: subclass_info = build_class[3] elif hasattr(build_class[2], "__len__"): subclass_info = build_class[2] else: - raise "Internal Error n_classdef: cannot superclass name" + raise RuntimeError( + "Internal Error n_classdef: cannot " "superclass name" + ) elif node == "classdefdeco2": subclass_info = node subclass_code = build_class[1][0].attr diff --git a/uncompyle6/semantics/customize37.py b/uncompyle6/semantics/customize37.py index d5ac3bc4..97109997 100644 --- a/uncompyle6/semantics/customize37.py +++ b/uncompyle6/semantics/customize37.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2022 by Rocky Bernstein +# Copyright (c) 2019-2023 by Rocky Bernstein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,12 +16,8 @@ """ import re -from uncompyle6.semantics.consts import ( - PRECEDENCE, - TABLE_DIRECT, - INDENT_PER_LEVEL, -) +from uncompyle6.semantics.consts import INDENT_PER_LEVEL, PRECEDENCE, TABLE_DIRECT from uncompyle6.semantics.helper import flatten_list FSTRING_CONVERSION_MAP = {1: "!s", 2: "!r", 3: "!a", "X": ":X"} @@ -54,10 +50,13 @@ def customize_for_version37(self, version): { "and_not": ("%c and not %c", (0, "expr"), (2, "expr")), "ann_assign": ( - "%|%[2]{attr}: %c\n", 0, + "%|%[2]{attr}: %c\n", + 0, ), "ann_assign_init": ( - "%|%[2]{attr}: %c = %c\n", 0, 1, + "%|%[2]{attr}: %c = %c\n", + 0, + 1, ), "async_for_stmt": ( "%|async for %c in %c:\n%+%c%-\n\n", @@ -89,9 +88,8 @@ def customize_for_version37(self, version): "attributes37": ( "%[0]{pattr} import %c", (0, "IMPORT_NAME_ATTR"), - (1, "IMPORT_FROM") + (1, "IMPORT_FROM"), ), - # nested await expressions like: # return await (await bar()) # need parenthesis. @@ -126,19 +124,24 @@ def customize_for_version37(self, version): (0, PRECEDENCE["compare"] - 1), (-2, PRECEDENCE["compare"] - 1), ), - "compare_chained2a_37": ('%[1]{pattr.replace("-", " ")} %p', (0, PRECEDENCE["compare"] - 1)), - "compare_chained2b_false_37": ('%[1]{pattr.replace("-", " ")} %p', (0, PRECEDENCE["compare"] - 1)), - "compare_chained2a_false_37": ('%[1]{pattr.replace("-", " ")} %p', (0, PRECEDENCE["compare"] - 1)), + "compare_chained2a_37": ( + '%[1]{pattr.replace("-", " ")} %p', + (0, PRECEDENCE["compare"] - 1), + ), + "compare_chained2b_false_37": ( + '%[1]{pattr.replace("-", " ")} %p', + (0, PRECEDENCE["compare"] - 1), + ), + "compare_chained2a_false_37": ( + '%[1]{pattr.replace("-", " ")} %p', + (0, PRECEDENCE["compare"] - 1), + ), "compare_chained2c_37": ( '%[3]{pattr.replace("-", " ")} %p %p', (0, PRECEDENCE["compare"] - 1), (6, PRECEDENCE["compare"] - 1), ), - 'if_exp37': ( - '%p if %c else %c', - (1, 'expr', 27), 0, 3 - ), - + "if_exp37": ("%p if %c else %c", (1, "expr", 27), 0, 3), "except_return": ("%|except:\n%+%c%-", 3), "if_exp_37a": ( "%p if %p else %p", @@ -153,9 +156,7 @@ def customize_for_version37(self, version): (5, "expr", 27), ), "ifstmtl": ("%|if %c:\n%+%c%-", (0, "testexpr"), (1, "_ifstmts_jumpl")), - 'import_as37': ( - "%|import %c as %c\n", 2, -2 - ), + "import_as37": ("%|import %c as %c\n", 2, -2), "import_from37": ("%|from %[2]{pattr} import %c\n", (3, "importlist37")), "import_from_as37": ( "%|from %c as %c\n", @@ -178,12 +179,11 @@ def customize_for_version37(self, version): (0, "get_aiter"), (3, "list_iter"), ), - "list_if37": (" if %p%c", (0, 27), 1), "list_if37_not": (" if not %p%c", (0, 27), 1), "testfalse_not_or": ("not %c or %c", (0, "expr"), (2, "expr")), "testfalse_not_and": ("not (%c)", 0), - "testfalsel": ("not %c", (0, "expr")), + "testfalsel": ("not %c", (0, "expr")), "try_except36": ("%|try:\n%+%c%-%c\n\n", 1, -2), "tryfinally36": ("%|try:\n%+%c%-%|finally:\n%+%c%-\n\n", (1, "returns"), 3), "dict_unpack": ("{**%C}", (0, -1, ", **")), diff --git a/uncompyle6/semantics/transform.py b/uncompyle6/semantics/transform.py index 6e5607d4..464ca911 100644 --- a/uncompyle6/semantics/transform.py +++ b/uncompyle6/semantics/transform.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2022 by Rocky Bernstein +# Copyright (c) 2019-2023 by Rocky Bernstein # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -119,15 +119,10 @@ class TreeTransform(GenericASTTraversal, object): mkfunc_pattr = node[-1].pattr if isinstance(mkfunc_pattr, tuple): - assert len(mkfunc_pattr, 4) and isinstance(mkfunc_pattr, int) - is_closure = node[-1].pattr[3] != 0 - else: - # FIXME: This is what we had before. It is hoaky and probably wrong. - is_closure = mkfunc_pattr == "closure" + assert len(mkfunc_pattr) == 4 and isinstance(mkfunc_pattr, int) if ( - (not is_closure) - and len(code.co_consts) > 0 + len(code.co_consts) > 0 and isinstance(code.co_consts[0], str) ): docstring_node = SyntaxTree( diff --git a/uncompyle6/util.py b/uncompyle6/util.py index 6f01995b..888ed368 100644 --- a/uncompyle6/util.py +++ b/uncompyle6/util.py @@ -3,7 +3,7 @@ # More could be done here though. from math import copysign -from xdis.version_info import PYTHON_VERSION +from xdis.version_info import PYTHON_VERSION_TRIPLE def is_negative_zero(n): @@ -36,7 +36,7 @@ def better_repr(v, version): if len(v) == 1: return "(%s,)" % better_repr(v[0], version) return "(%s)" % ", ".join(better_repr(i, version) for i in v) - elif PYTHON_VERSION < 3.0 and isinstance(v, long): + elif PYTHON_VERSION_TRIPLE < (3, 0) and isinstance(v, long): s = repr(v) if version >= 3.0 and s[-1] == "L": return s[:-1]