From f6f0e344d02925630e4b5c78a36ef8144dd78938 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 3 Nov 2021 02:23:19 -0400 Subject: [PATCH] Python 3.6+ specialization --- pytest/test_deparse.py | 8 +++--- pytest/test_pysource.py-notyet | 12 +++------ pytest/test_single_compile.py | 33 ++++++++++++------------- uncompyle6/scanners/scanner2.py | 30 +++------------------- uncompyle6/scanners/scanner26.py | 16 ++---------- uncompyle6/scanners/scanner3.py | 6 ++--- uncompyle6/scanners/tok.py | 6 ++--- uncompyle6/semantics/consts.py | 11 +++------ uncompyle6/semantics/helper.py | 22 +++-------------- uncompyle6/semantics/make_function2.py | 6 +---- uncompyle6/semantics/make_function36.py | 15 ++++------- uncompyle6/verify.py | 13 +++------- 12 files changed, 47 insertions(+), 131 deletions(-) diff --git a/pytest/test_deparse.py b/pytest/test_deparse.py index 50f02aff..074a87af 100644 --- a/pytest/test_deparse.py +++ b/pytest/test_deparse.py @@ -1,5 +1,5 @@ from uncompyle6.semantics.fragments import code_deparse as deparse -from xdis.version_info import PYTHON_VERSION, PYTHON3 +from xdis.version_info import PYTHON_VERSION_TRIPLE def map_stmts(x, y): x = [] @@ -29,8 +29,8 @@ def list_comp(): [y for y in range(3)] def get_parsed_for_fn(fn): - code = fn.__code__ if PYTHON3 else fn.func_code - return deparse(code, version=PYTHON_VERSION) + code = fn.__code__ + return deparse(code, version=PYTHON_VERSION_TRIPLE) def check_expect(expect, parsed, fn_name): debug = False @@ -316,5 +316,3 @@ for i in range(2): ... . """.split("\n") parsed = get_parsed_for_fn(for_range_stmt) - if not PYTHON3: - check_expect(expect, parsed, 'range_stmt') diff --git a/pytest/test_pysource.py-notyet b/pytest/test_pysource.py-notyet index cdb9ef06..08ec9645 100644 --- a/pytest/test_pysource.py-notyet +++ b/pytest/test_pysource.py-notyet @@ -5,15 +5,9 @@ from uncompyle6.semantics.consts import ( # RETURN_NONE, PASS, RETURN_LOCALS ) -from xdis.version_info import PYTHON3 -if PYTHON3: - from io import StringIO - def iteritems(d): - return d.items() -else: - from StringIO import StringIO - def iteritems(d): - return d.iteritems() +from io import StringIO +def iteritems(d): + return d.items() from uncompyle6.semantics.pysource import (SourceWalker, deparse_code2str) diff --git a/pytest/test_single_compile.py b/pytest/test_single_compile.py index 2820bec4..9028edde 100644 --- a/pytest/test_single_compile.py +++ b/pytest/test_single_compile.py @@ -2,22 +2,21 @@ import pytest from uncompyle6 import code_deparse from xdis.version_info import PYTHON_VERSION_TRIPLE pytestmark = pytest.mark.skip(PYTHON_VERSION_TRIPLE < (2, 7), - reason="need at least Python 2.7") + reason="need Python < 2.7") -if PYTHON_VERSION_TRIPLE > (2, 6): - def test_single_mode(): - single_expressions = ( - 'i = 1', - 'i and (j or k)', - 'i += 1', - 'i = j % 4', - 'i = {}', - 'i = []', - 'for i in range(10):\n i\n', - 'for i in range(10):\n for j in range(10):\n i + j\n', - 'try:\n i\nexcept Exception:\n j\nelse:\n k\n' - ) +def test_single_mode(): + single_expressions = ( + 'i = 1', + 'i and (j or k)', + 'i += 1', + 'i = j % 4', + 'i = {}', + 'i = []', + 'for i in range(10):\n i\n', + 'for i in range(10):\n for j in range(10):\n i + j\n', + 'try:\n i\nexcept Exception:\n j\nelse:\n k\n' + ) - for expr in single_expressions: - code = compile(expr + '\n', '', 'single') - assert code_deparse(code, compile_mode='single').text == expr + '\n' + for expr in single_expressions: + code = compile(expr + '\n', '', 'single') + assert code_deparse(code, compile_mode='single').text == expr + '\n' diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index fccbf677..d790c8ca 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -39,14 +39,10 @@ from copy import copy from xdis import code2num, iscode, op_has_argument, instruction_size from xdis.bytecode import _get_const_info - -from xdis.version_info import PYTHON3 - -if PYTHON3: - from sys import intern - from uncompyle6.scanner import Scanner, Token +from sys import intern + class Scanner2(Scanner): def __init__(self, version, show_asm=None, is_pypy=False): @@ -147,10 +143,7 @@ class Scanner2(Scanner): In Python2 this always the operand value shifted 16 bits since the operand is always 2 bytes. In Python 3.6+ this changes to one byte. """ - if PYTHON3: - return arg << 16 - else: - return arg << long(16) + return arg << 16 @staticmethod def unmangle_name(name, classname): @@ -1428,20 +1421,3 @@ class Scanner2(Scanner): instr_offsets = filtered filtered = [] return instr_offsets - - -if __name__ == "__main__": - from uncompyle6 import PYTHON_VERSION - - if 2.0 <= PYTHON_VERSION < 3.0: - import inspect - - co = inspect.currentframe().f_code - from uncompyle6 import PYTHON_VERSION - - tokens, customize = Scanner2(PYTHON_VERSION).ingest(co) - for t in tokens: - print(t) - else: - print("Need to be Python 2.x to demo; I am %s." % PYTHON_VERSION) - pass diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 25b683f6..ce9e34ec 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -23,10 +23,6 @@ use in deparsing. """ import sys -from xdis.version_info import PYTHON3 -if PYTHON3: - intern = sys.intern - import uncompyle6.scanners.scanner2 as scan from uncompyle6.scanner import L65536 @@ -36,6 +32,8 @@ from xdis.bytecode import _get_const_info from uncompyle6.scanner import Token +intern = sys.intern + JUMP_OPS = opcode_26.JUMP_OPS class Scanner26(scan.Scanner2): @@ -282,13 +280,3 @@ class Scanner26(scan.Scanner2): print(t.format(line_prefix="")) print() return tokens, customize - -if __name__ == "__main__": - from uncompyle6 import PYTHON_VERSION - if PYTHON_VERSION == 2.6: - import inspect - co = inspect.currentframe().f_code - tokens, customize = Scanner26(show_asm=True).ingest(co) - else: - print("Need to be Python 2.6 to demo; I am %s." % - PYTHON_VERSION) diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index cc5745e5..b097c5af 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -47,10 +47,8 @@ import xdis.opcodes.opcode_33 as op3 from uncompyle6.scanner import Scanner import sys -from xdis.version_info import PYTHON3 -if PYTHON3: - intern = sys.intern +intern = sys.intern globals().update(op3.opmap) @@ -379,7 +377,7 @@ class Scanner3(Scanner): # pattr = 'code_object @ 0x%x %s->%s' %\ # (id(const), const.co_filename, const.co_name) pattr = "" - elif isinstance(const, str) or xdis.PYTHON_VERSION <= 2.7 and isinstance(const, unicode): + elif isinstance(const, str): opname = "LOAD_STR" else: if isinstance(inst.arg, int) and inst.arg < len(co.co_consts): diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 42723539..f98b6306 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -16,10 +16,8 @@ # along with this program. If not, see . import re, sys -from xdis.version_info import PYTHON3 -if PYTHON3: - intern = sys.intern +intern = sys.intern def off2int(offset, prefer_last=True): @@ -93,7 +91,7 @@ class Token: pass else: if version_tuple > (3, 9): - print(f"Python versions 3.9 and greater are not supported.") + print("Python versions 3.9 and greater are not supported.") else: print(f"xdis might need to be informed about version {e}") return diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 07ccc7c3..93a805d5 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2020 by Rocky Bernstein +# Copyright (c) 2017-2021 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 @@ -17,14 +17,9 @@ import re, sys from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.scanners.tok import Token, NoneToken -from xdis.version_info import PYTHON3 -if PYTHON3: - minint = -sys.maxsize - 1 - maxint = sys.maxsize -else: - minint = -sys.maxint - 1 - maxint = sys.maxint +minint = -sys.maxsize - 1 +maxint = sys.maxsize # Operator precidence See diff --git a/uncompyle6/semantics/helper.py b/uncompyle6/semantics/helper.py index 392bd5f9..43782231 100644 --- a/uncompyle6/semantics/helper.py +++ b/uncompyle6/semantics/helper.py @@ -3,13 +3,8 @@ import sys from xdis import iscode from uncompyle6.parsers.treenode import SyntaxTree -from xdis.version_info import PYTHON3 -if PYTHON3: - minint = -sys.maxsize-1 - maxint = sys.maxsize -else: - minint = -sys.maxint-1 - maxint = sys.maxint +minint = -sys.maxsize-1 +maxint = sys.maxsize read_write_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL', 'LOAD_GLOBAL')) read_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL')) @@ -145,18 +140,7 @@ def print_docstring(self, indent, docstring): quote = "'''" self.write(indent) - if not PYTHON3 and not isinstance(docstring, str): - # Must be unicode in Python2 - self.write('u') - docstring = repr(docstring.expandtabs())[2:-1] - elif PYTHON3 and (2, 4) <= self.version[:2] <= (2, 7): - try: - repr(docstring.expandtabs())[1:-1].encode("ascii") - except UnicodeEncodeError: - self.write('u') - docstring = repr(docstring.expandtabs())[1:-1] - else: - docstring = repr(docstring.expandtabs())[1:-1] + docstring = repr(docstring.expandtabs())[1:-1] for (orig, replace) in (('\\\\', '\t'), ('\\r\\n', '\n'), diff --git a/uncompyle6/semantics/make_function2.py b/uncompyle6/semantics/make_function2.py index 190abe2a..be93c796 100644 --- a/uncompyle6/semantics/make_function2.py +++ b/uncompyle6/semantics/make_function2.py @@ -27,12 +27,8 @@ from uncompyle6.semantics.helper import ( find_none, ) from xdis import iscode, code_has_star_arg, code_has_star_star_arg -from xdis.version_info import PYTHON3 -if PYTHON3: - from itertools import zip_longest -else: - from itertools import izip_longest as zip_longest +from itertools import zip_longest from uncompyle6.show import maybe_show_tree_param_default diff --git a/uncompyle6/semantics/make_function36.py b/uncompyle6/semantics/make_function36.py index 5124c5fc..3ea8efbd 100644 --- a/uncompyle6/semantics/make_function36.py +++ b/uncompyle6/semantics/make_function36.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2020 by Rocky Bernstein +# Copyright (c) 2019-2021 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 @@ -31,12 +31,7 @@ from uncompyle6.semantics.helper import ( find_globals_and_nonlocals, find_none, ) -from xdis.version_info import PYTHON3 - -if PYTHON3: - from itertools import zip_longest -else: - from itertools import izip_longest as zip_longest +from itertools import zip_longest from uncompyle6.show import maybe_show_tree_param_default @@ -266,13 +261,14 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None): if fn_bits[-1]: index -= 1 if fn_bits[-2]: - ann_dict = node[index] + # ann_dict = node[index] index -= 1 if fn_bits[-3]: kw_dict = node[index] index -= 1 if fn_bits[-4]: - default_tup = node[index] + # default_tup = node[index] + pass if kw_dict == "expr": kw_dict = kw_dict[0] @@ -285,7 +281,6 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None): defaults = [self.traverse(n, indent="") for n in kw_dict[:-2]] names = eval(self.traverse(kw_dict[-2])) assert len(defaults) == len(names) - sep = "" # FIXME: possibly handle line breaks for i, n in enumerate(names): idx = kwargs.index(n) diff --git a/uncompyle6/verify.py b/uncompyle6/verify.py index 302c6036..285b2dae 100755 --- a/uncompyle6/verify.py +++ b/uncompyle6/verify.py @@ -1,5 +1,5 @@ # -# (C) Copyright 2015-2018, 2020 by Rocky Bernstein +# (C) Copyright 2015-2018, 2020-2021 by Rocky Bernstein # (C) Copyright 2000-2002 by hartmut Goebel # # This program is free software: you can redistribute it and/or modify @@ -27,14 +27,9 @@ from subprocess import call import uncompyle6 from uncompyle6.scanner import Token as ScannerToken, get_scanner from xdis import iscode, load_file, load_module, pretty_code_flags, PYTHON_MAGIC_INT -from xdis.version_info import PYTHON3 -# FIXME: DRY -if PYTHON3: - truediv = operator.truediv - from functools import reduce -else: - truediv = operator.div +truediv = operator.truediv +from functools import reduce def code_equal(a, b): @@ -230,7 +225,7 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2, verify, name=""): scanner = get_scanner(version, is_pypy, show_asm=False) global JUMP_OPS - JUMP_OPS = list(scan.JUMP_OPS) + ["JUMP_BACK"] + JUMP_OPS = list(JUMP_OPS) + ["JUMP_BACK"] # use changed Token class # We (re)set this here to save exception handling,