From db6c7159f83b7ded526e7fd5c32f7e3917200108 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 3 Feb 2024 14:47:08 -0500 Subject: [PATCH] lint --- .gitignore | 3 +- test/test_pythonlib.py | 2 +- uncompyle6/main.py | 44 +++++---- uncompyle6/semantics/linemap.py | 14 +-- uncompyle6/semantics/pysource.py | 148 ++++++++++++++++++------------- 5 files changed, 119 insertions(+), 92 deletions(-) diff --git a/.gitignore b/.gitignore index 34a0cc62..195e4cfa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.pyo *_dis *~ +.mypy_cache /.cache /.eggs /.hypothesis @@ -10,7 +11,6 @@ /.pytest_cache /.python-version /.tox -.mypy_cache /.venv* /README /__pkginfo__.pyc @@ -20,6 +20,7 @@ /tmp /uncompyle6.egg-info /unpyc +/venv ChangeLog __pycache__ build diff --git a/test/test_pythonlib.py b/test/test_pythonlib.py index 6d06e1d2..99d2f90b 100755 --- a/test/test_pythonlib.py +++ b/test/test_pythonlib.py @@ -216,7 +216,7 @@ def do_tests(src_dir, obj_patterns, target_dir, opts): print("Output directory: ", target_dir) try: _, _, failed_files, failed_verify = main( - src_dir, target_dir, files, [], do_verify=opts["do_verify"] + src_dir, target_dir, files, [] ) if failed_files != 0: sys.exit(2) diff --git a/uncompyle6/main.py b/uncompyle6/main.py index 4285736c..44f23380 100644 --- a/uncompyle6/main.py +++ b/uncompyle6/main.py @@ -90,7 +90,7 @@ def decompile( run_pypy_str = "PyPy " if IS_PYPY else "" sys_version_lines = sys.version.split("\n") if source_encoding: - write("# -*- coding: %s -*-" % source_encoding) + write(f"# -*- coding: {source_encoding} -*-") write( "# uncompyle6 version %s\n" "# %sPython bytecode version base %s%s\n# Decompiled from: %sPython %s" @@ -104,9 +104,9 @@ def decompile( ) ) if co.co_filename: - write("# Embedded file name: %s" % co.co_filename) + write(f"# Embedded file name: {co.co_filename}") if timestamp: - write("# Compiled at: %s" % datetime.datetime.fromtimestamp(timestamp)) + write(f"# Compiled at: {datetime.datetime.fromtimestamp(timestamp)}") if source_size: write("# Size of source mod 2**32: %d bytes" % source_size) @@ -129,13 +129,14 @@ def decompile( version=bytecode_version, code_objects=code_objects, is_pypy=is_pypy, + debug_opts=debug_opts, ) header_count = 3 + len(sys_version_lines) linemap = [ (line_no, deparsed.source_linemap[line_no] + header_count) for line_no in sorted(deparsed.source_linemap.keys()) ] - mapstream.write("\n\n# %s\n" % linemap) + mapstream.write(f"\n\n# {linemap}\n") else: if do_fragments: deparse_fn = code_deparse_fragments @@ -163,11 +164,11 @@ def compile_file(source_path: str) -> str: basename = source_path if hasattr(sys, "pypy_version_info"): - bytecode_path = "%s-pypy%s.pyc" % (basename, version_tuple_to_str()) + bytecode_path = f"{basename}-pypy{version_tuple_to_str()}.pyc" else: - bytecode_path = "%s-%s.pyc" % (basename, version_tuple_to_str()) + bytecode_path = f"{basename}-{version_tuple_to_str()}.pyc" - print("compiling %s to %s" % (source_path, bytecode_path)) + print(f"compiling {source_path} to {bytecode_path}") py_compile.compile(source_path, bytecode_path, "exec") return bytecode_path @@ -232,7 +233,6 @@ def decompile_file( compile_mode="exec", ) ] - co = None return deparsed @@ -245,7 +245,6 @@ def main( outfile=None, showasm: Optional[str] = None, showast={}, - do_verify=False, showgrammar=False, source_encoding=None, raise_on_error=False, @@ -274,7 +273,7 @@ def main( infile = os.path.join(in_base, filename) # print("XXX", infile) if not os.path.exists(infile): - sys.stderr.write("File '%s' doesn't exist. Skipped\n" % infile) + sys.stderr.write(f"File '{infile}' doesn't exist. Skipped\n") continue if do_linemaps: @@ -322,13 +321,13 @@ def main( ): if e[0] != last_mod: line = "=" * len(e[0]) - outstream.write("%s\n%s\n%s\n" % (line, e[0], line)) + outstream.write(f"{line}\n{e[0]}\n{line}\n") last_mod = e[0] info = offsets[e] - extractInfo = d.extract_node_info(info) - outstream.write("%s" % info.node.format().strip() + "\n") - outstream.write(extractInfo.selectedLine + "\n") - outstream.write(extractInfo.markerLine + "\n\n") + extract_info = d.extract_node_info(info) + outstream.write(f"{info.node.format().strip()}" + "\n") + outstream.write(extract_info.selectedLine + "\n") + outstream.write(extract_info.markerLine + "\n\n") pass pass tot_files += 1 @@ -349,14 +348,14 @@ def main( if str(e).startswith("Unsupported Python"): sys.stdout.write("\n") sys.stderr.write( - "\n# Unsupported bytecode in file %s\n# %s\n" % (infile, e) + f"\n# Unsupported bytecode in file {infile}\n# {e}\n" ) else: if outfile: outstream.close() os.remove(outfile) sys.stdout.write("\n") - sys.stderr.write("\nLast file: %s " % (infile)) + sys.stderr.write(f"\nLast file: {infile} ") raise # except: @@ -376,7 +375,7 @@ def main( okay_files += 1 if not current_outfile: mess = "\n# okay decompiling" - # mem_usage = __memUsage() + # mem_usage = __mem_usage() print(mess, infile) if current_outfile: sys.stdout.write( @@ -384,7 +383,6 @@ def main( % ( infile, status_msg( - do_verify, tot_files, okay_files, failed_files, @@ -405,14 +403,14 @@ def main( except Exception: pass pass - return (tot_files, okay_files, failed_files, verify_failed_files) + return tot_files, okay_files, failed_files, verify_failed_files # ---- main ---- if sys.platform.startswith("linux") and os.uname()[2][:2] in ["2.", "3.", "4."]: - def __memUsage(): + def __mem_sage(): mi = open("/proc/self/stat", "r") mu = mi.readline().split()[22] mi.close() @@ -420,11 +418,11 @@ if sys.platform.startswith("linux") and os.uname()[2][:2] in ["2.", "3.", "4."]: else: - def __memUsage(): + def __mem_usage(): return "" -def status_msg(do_verify, tot_files, okay_files, failed_files, verify_failed_files): +def status_msg(tot_files, okay_files, failed_files, verify_failed_files): if tot_files == 1: if failed_files: return "\n# decompile failed" diff --git a/uncompyle6/semantics/linemap.py b/uncompyle6/semantics/linemap.py index 3a447afb..1c760b43 100644 --- a/uncompyle6/semantics/linemap.py +++ b/uncompyle6/semantics/linemap.py @@ -1,5 +1,6 @@ # Copyright (c) 2018, 2024 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 # the Free Software Foundation, either version 3 of the License, or @@ -13,7 +14,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from uncompyle6.semantics.fragments import FragmentsWalker, code_deparse as fragments_code_deparse +from uncompyle6.semantics.fragments import ( + FragmentsWalker, + code_deparse as fragments_code_deparse, +) from uncompyle6.semantics.pysource import SourceWalker, code_deparse @@ -25,9 +29,9 @@ class LineMapWalker(SourceWalker): self.current_line_number = 1 def write(self, *data): - """Augment write routine to keep track of current line""" + """Augment write routine to keep track of current line.""" for line in data: - ## print("XXX write: '%s'" % l) + # print(f"XXX write: '{line}'") for i in str(line): if i == "\n": self.current_line_number += 1 @@ -39,7 +43,7 @@ class LineMapWalker(SourceWalker): # Note n_expr needs treatment too def default(self, node): - """Augment write default routine to record line number changes""" + """Augment default-write routine to record line number changes.""" if hasattr(node, "linestart"): if node.linestart: self.source_linemap[self.current_line_number] = node.linestart @@ -85,7 +89,7 @@ def code_deparse_with_fragments_and_map(*args, **kwargs): if __name__ == "__main__": def deparse_test(co): - "This is a docstring" + """This is a docstring""" deparsed = code_deparse_with_map(co) a = 1 b = 2 diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index a43075c9..5a6566fe 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -141,17 +141,25 @@ from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.scanner import Code, get_scanner from uncompyle6.scanners.tok import Token from uncompyle6.semantics.check_ast import checker -from uncompyle6.semantics.consts import (ASSIGN_TUPLE_PARAM, - INDENT_PER_LEVEL, LINE_LENGTH, MAP, - MAP_DIRECT, NAME_MODULE, NONE, PASS, - PRECEDENCE, RETURN_LOCALS, - RETURN_NONE, TAB, TABLE_R, escape) +from uncompyle6.semantics.consts import ( + ASSIGN_TUPLE_PARAM, + INDENT_PER_LEVEL, + LINE_LENGTH, + MAP, + MAP_DIRECT, + NAME_MODULE, + NONE, + PASS, + PRECEDENCE, + RETURN_LOCALS, + RETURN_NONE, + TAB, + TABLE_R, + escape, +) from uncompyle6.semantics.customize import customize_for_version from uncompyle6.semantics.gencomp import ComprehensionMixin -from uncompyle6.semantics.helper import ( - find_globals_and_nonlocals, - print_docstring -) +from uncompyle6.semantics.helper import find_globals_and_nonlocals, print_docstring from uncompyle6.semantics.make_function1 import make_function1 from uncompyle6.semantics.make_function2 import make_function2 from uncompyle6.semantics.make_function3 import make_function3 @@ -162,9 +170,11 @@ from uncompyle6.semantics.transform import TreeTransform, is_docstring from uncompyle6.show import maybe_show_tree from uncompyle6.util import better_repr -DEFAULT_DEBUG_OPTS = {"asm": False, "tree": False, "grammar": False} -def unicode(x): return x +def unicode(x): + return x + + from io import StringIO PARSER_DEFAULT_DEBUG = { @@ -200,6 +210,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): Class to traverses a Parse Tree of the bytecode instruction built from parsing to produce some sort of source text. The Parse tree may be turned an Abstract Syntax tree as an intermediate step. """ + stacked_params = ("f", "indent", "is_lambda", "_globals") def __init__( @@ -288,7 +299,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): self.in_format_string = None # hide_internal suppresses displaying the additional instructions that sometimes - # exist in code but but were not written in the source code. + # exist in code but were not written in the source code. # An example is: # __module__ = __name__ self.hide_internal = True @@ -355,7 +366,6 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): indent += " " i = 0 for node in ast: - if hasattr(node, "__repr1__"): if enumerate_children: child = self.str_with_template1(node, indent, i) @@ -375,9 +385,9 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): i += 1 return rv - def indent_if_source_nl(self, line_number, indent): + def indent_if_source_nl(self, line_number: int, indent: int): if line_number != self.line_number: - self.write("\n" + self.indent + INDENT_PER_LEVEL[:-1]) + self.write("\n" + indent + INDENT_PER_LEVEL[:-1]) return self.line_number f = property( @@ -685,7 +695,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): def template_engine(self, entry, startnode): """The format template interpretation engine. See the comment at the - beginning of this module for the how we interpret format + beginning of this module for how we interpret format specifications such as %c, %C, and so on. """ @@ -729,20 +739,31 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): if isinstance(index[1], str): # if node[index[0]] != index[1]: # from trepan.api import debug; debug() - assert node[index[0]] == index[1], ( - "at %s[%d], expected '%s' node; got '%s'" - % (node.kind, arg, index[1], node[index[0]].kind,) + assert ( + node[index[0]] == index[1] + ), "at %s[%d], expected '%s' node; got '%s'" % ( + node.kind, + arg, + index[1], + node[index[0]].kind, ) else: - assert node[index[0]] in index[1], ( - "at %s[%d], expected to be in '%s' node; got '%s'" - % (node.kind, arg, index[1], node[index[0]].kind,) + assert ( + node[index[0]] in index[1] + ), "at %s[%d], expected to be in '%s' node; got '%s'" % ( + node.kind, + arg, + index[1], + node[index[0]].kind, ) index = index[0] - assert isinstance(index, int), ( - "at %s[%d], %s should be int or tuple" - % (node.kind, arg, type(index),) + assert isinstance( + index, int + ), "at %s[%d], %s should be int or tuple" % ( + node.kind, + arg, + type(index), ) try: @@ -765,14 +786,22 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): if len(tup) == 3: (index, nonterm_name, self.prec) = tup if isinstance(tup[1], str): - assert node[index] == nonterm_name, ( - "at %s[%d], expected '%s' node; got '%s'" - % (node.kind, arg, nonterm_name, node[index].kind,) + assert ( + node[index] == nonterm_name + ), "at %s[%d], expected '%s' node; got '%s'" % ( + node.kind, + arg, + nonterm_name, + node[index].kind, ) else: - assert node[tup[0]] in tup[1], ( - "at %s[%d], expected to be in '%s' node; got '%s'" - % (node.kind, arg, index[1], node[index[0]].kind,) + assert ( + node[tup[0]] in tup[1] + ), "at %s[%d], expected to be in '%s' node; got '%s'" % ( + node.kind, + arg, + index[1], + node[index[0]].kind, ) else: @@ -885,52 +914,51 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): "CALL_FUNCTION_VAR_KW", "CALL_FUNCTION_KW", ): - # FIXME: handle everything in customize. # Right now, some of this is here, and some in that. if v == 0: - str = "%c(%C" # '%C' is a dummy here ... - p2 = (0, 0, None) # .. because of the None in this + template_str = "%c(%C" # '%C' is a dummy here ... + p2 = (0, 0, None) # because of the None in this else: - str = "%c(%C, " + template_str = "%c(%C, " p2 = (1, -2, ", ") if op == "CALL_FUNCTION_VAR": # Python 3.5 only puts optional args (the VAR part) # the lowest down the stack if self.version == (3, 5): - if str == "%c(%C, ": + if template_str == "%c(%C, ": entry = ("%c(*%C, %c)", 0, p2, -2) - elif str == "%c(%C": + elif template_str == "%c(%C": entry = ("%c(*%C)", 0, (1, 100, "")) elif self.version == (3, 4): # CALL_FUNCTION_VAR's top element of the stack contains # the variable argument list if v == 0: - str = "%c(*%c)" - entry = (str, 0, -2) + template_str = "%c(*%c)" + entry = (template_str, 0, -2) else: - str = "%c(%C, *%c)" - entry = (str, 0, p2, -2) + template_str = "%c(%C, *%c)" + entry = (template_str, 0, p2, -2) else: - str += "*%c)" - entry = (str, 0, p2, -2) + template_str += "*%c)" + entry = (template_str, 0, p2, -2) elif op == "CALL_FUNCTION_KW": - str += "**%c)" - entry = (str, 0, p2, -2) + template_str += "**%c)" + entry = (template_str, 0, p2, -2) elif op == "CALL_FUNCTION_VAR_KW": - str += "*%c, **%c)" + template_str += "*%c, **%c)" # Python 3.5 only puts optional args (the VAR part) # the lowest down the stack na = v & 0xFF # positional parameters if self.version == (3, 5) and na == 0: if p2[2]: p2 = (2, -2, ", ") - entry = (str, 0, p2, 1, -2) + entry = (template_str, 0, p2, 1, -2) else: if p2[2]: p2 = (1, -3, ", ") - entry = (str, 0, p2, -3, -2) + entry = (template_str, 0, p2, -3, -2) pass else: assert False, "Unhandled CALL_FUNCTION %s" % op @@ -1014,7 +1042,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): if ast[0] == "sstmt": ast[0] = ast[0][0] first_stmt = ast[0] - except: + except Exception: pass try: @@ -1023,7 +1051,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): del ast[0] first_stmt = ast[0] pass - except: + except Exception: pass have_qualname = False @@ -1035,17 +1063,15 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): if self.version < (3, 0): # Should we ditch this in favor of the "else" case? qualname = ".".join(self.classes) - QUAL_NAME = SyntaxTree( + qual_name_tree = SyntaxTree( "assign", [ SyntaxTree("expr", [Token("LOAD_CONST", pattr=qualname)]), - SyntaxTree( - "store", [Token("STORE_NAME", pattr="__qualname__")] - ), + SyntaxTree("store", [Token("STORE_NAME", pattr="__qualname__")]), ], ) # FIXME: is this right now that we've redone the grammar? - have_qualname = ast[0] == QUAL_NAME + have_qualname = ast[0] == qual_name_tree else: # Python 3.4+ has constants like 'cmp_to_key..K' # which are not simple classes like the < 3 case. @@ -1057,7 +1083,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): and first_stmt[1][0] == Token("STORE_NAME", pattr="__qualname__") ): have_qualname = True - except: + except Exception: pass if have_qualname: @@ -1078,7 +1104,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): try: # FIXME: Is there an extra [0]? docstring = ast[i][0][0][0][0].pattr - except: + except Exception: docstring = code.co_consts[0] if print_docstring(self, indent, docstring): self.println() @@ -1104,7 +1130,6 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): # else: # print stmt[-1] - globals, nonlocals = find_globals_and_nonlocals( ast, set(), set(), code, self.version ) @@ -1148,7 +1173,7 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): else: self.customize(customize) self.text = self.traverse(ast, is_lambda=is_lambda) - # In a formatted string using "lambda', we should not add "\n". + # 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: @@ -1167,7 +1192,6 @@ class SourceWalker(GenericASTTraversal, NonterminalActions, ComprehensionMixin): noneInNames=False, is_top_level_module=False, ): - # FIXME: DRY with fragments.py # assert isinstance(tokens[0], Token) @@ -1298,7 +1322,7 @@ def code_deparse( is_top_level_module=is_top_level_module, ) - #### XXX workaround for profiling + # XXX workaround for profiling if deparsed.ast is None: return None @@ -1406,7 +1430,7 @@ def deparse_code2str( if __name__ == "__main__": def deparse_test(co): - "This is a docstring" + """This is a docstring""" s = deparse_code2str(co) # s = deparse_code2str(co, debug_opts={"asm": "after", "tree": {'before': False, 'after': False}}) print(s)