Python 3.6+ specialization

This commit is contained in:
rocky
2021-11-03 02:23:19 -04:00
parent 6af63deaa3
commit f6f0e344d0
12 changed files with 47 additions and 131 deletions

View File

@@ -1,5 +1,5 @@
from uncompyle6.semantics.fragments import code_deparse as deparse 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): def map_stmts(x, y):
x = [] x = []
@@ -29,8 +29,8 @@ def list_comp():
[y for y in range(3)] [y for y in range(3)]
def get_parsed_for_fn(fn): def get_parsed_for_fn(fn):
code = fn.__code__ if PYTHON3 else fn.func_code code = fn.__code__
return deparse(code, version=PYTHON_VERSION) return deparse(code, version=PYTHON_VERSION_TRIPLE)
def check_expect(expect, parsed, fn_name): def check_expect(expect, parsed, fn_name):
debug = False debug = False
@@ -316,5 +316,3 @@ for i in range(2): ...
. .
""".split("\n") """.split("\n")
parsed = get_parsed_for_fn(for_range_stmt) parsed = get_parsed_for_fn(for_range_stmt)
if not PYTHON3:
check_expect(expect, parsed, 'range_stmt')

View File

@@ -5,15 +5,9 @@ from uncompyle6.semantics.consts import (
# RETURN_NONE, PASS, RETURN_LOCALS # RETURN_NONE, PASS, RETURN_LOCALS
) )
from xdis.version_info import PYTHON3 from io import StringIO
if PYTHON3: def iteritems(d):
from io import StringIO return d.items()
def iteritems(d):
return d.items()
else:
from StringIO import StringIO
def iteritems(d):
return d.iteritems()
from uncompyle6.semantics.pysource import (SourceWalker, deparse_code2str) from uncompyle6.semantics.pysource import (SourceWalker, deparse_code2str)

View File

@@ -2,22 +2,21 @@ import pytest
from uncompyle6 import code_deparse from uncompyle6 import code_deparse
from xdis.version_info import PYTHON_VERSION_TRIPLE from xdis.version_info import PYTHON_VERSION_TRIPLE
pytestmark = pytest.mark.skip(PYTHON_VERSION_TRIPLE < (2, 7), 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():
def test_single_mode(): single_expressions = (
single_expressions = ( 'i = 1',
'i = 1', 'i and (j or k)',
'i and (j or k)', 'i += 1',
'i += 1', 'i = j % 4',
'i = j % 4', 'i = {}',
'i = {}', 'i = []',
'i = []', 'for i in range(10):\n i\n',
'for i in range(10):\n i\n', 'for i in range(10):\n for j in range(10):\n i + j\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'
'try:\n i\nexcept Exception:\n j\nelse:\n k\n' )
)
for expr in single_expressions: for expr in single_expressions:
code = compile(expr + '\n', '<string>', 'single') code = compile(expr + '\n', '<string>', 'single')
assert code_deparse(code, compile_mode='single').text == expr + '\n' assert code_deparse(code, compile_mode='single').text == expr + '\n'

View File

@@ -39,14 +39,10 @@ from copy import copy
from xdis import code2num, iscode, op_has_argument, instruction_size from xdis import code2num, iscode, op_has_argument, instruction_size
from xdis.bytecode import _get_const_info 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 uncompyle6.scanner import Scanner, Token
from sys import intern
class Scanner2(Scanner): class Scanner2(Scanner):
def __init__(self, version, show_asm=None, is_pypy=False): 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 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. the operand is always 2 bytes. In Python 3.6+ this changes to one byte.
""" """
if PYTHON3: return arg << 16
return arg << 16
else:
return arg << long(16)
@staticmethod @staticmethod
def unmangle_name(name, classname): def unmangle_name(name, classname):
@@ -1428,20 +1421,3 @@ class Scanner2(Scanner):
instr_offsets = filtered instr_offsets = filtered
filtered = [] filtered = []
return instr_offsets 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

View File

@@ -23,10 +23,6 @@ use in deparsing.
""" """
import sys import sys
from xdis.version_info import PYTHON3
if PYTHON3:
intern = sys.intern
import uncompyle6.scanners.scanner2 as scan import uncompyle6.scanners.scanner2 as scan
from uncompyle6.scanner import L65536 from uncompyle6.scanner import L65536
@@ -36,6 +32,8 @@ from xdis.bytecode import _get_const_info
from uncompyle6.scanner import Token from uncompyle6.scanner import Token
intern = sys.intern
JUMP_OPS = opcode_26.JUMP_OPS JUMP_OPS = opcode_26.JUMP_OPS
class Scanner26(scan.Scanner2): class Scanner26(scan.Scanner2):
@@ -282,13 +280,3 @@ class Scanner26(scan.Scanner2):
print(t.format(line_prefix="")) print(t.format(line_prefix=""))
print() print()
return tokens, customize 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)

View File

@@ -47,10 +47,8 @@ import xdis.opcodes.opcode_33 as op3
from uncompyle6.scanner import Scanner from uncompyle6.scanner import Scanner
import sys import sys
from xdis.version_info import PYTHON3
if PYTHON3: intern = sys.intern
intern = sys.intern
globals().update(op3.opmap) globals().update(op3.opmap)
@@ -379,7 +377,7 @@ class Scanner3(Scanner):
# pattr = 'code_object @ 0x%x %s->%s' %\ # pattr = 'code_object @ 0x%x %s->%s' %\
# (id(const), const.co_filename, const.co_name) # (id(const), const.co_filename, const.co_name)
pattr = "<code_object " + const.co_name + ">" pattr = "<code_object " + const.co_name + ">"
elif isinstance(const, str) or xdis.PYTHON_VERSION <= 2.7 and isinstance(const, unicode): elif isinstance(const, str):
opname = "LOAD_STR" opname = "LOAD_STR"
else: else:
if isinstance(inst.arg, int) and inst.arg < len(co.co_consts): if isinstance(inst.arg, int) and inst.arg < len(co.co_consts):

View File

@@ -16,10 +16,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import re, sys import re, sys
from xdis.version_info import PYTHON3
if PYTHON3: intern = sys.intern
intern = sys.intern
def off2int(offset, prefer_last=True): def off2int(offset, prefer_last=True):
@@ -93,7 +91,7 @@ class Token:
pass pass
else: else:
if version_tuple > (3, 9): 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: else:
print(f"xdis might need to be informed about version {e}") print(f"xdis might need to be informed about version {e}")
return return

View File

@@ -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 # 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 # it under the terms of the GNU General Public License as published by
@@ -17,14 +17,9 @@
import re, sys import re, sys
from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.parsers.treenode import SyntaxTree
from uncompyle6.scanners.tok import Token, NoneToken from uncompyle6.scanners.tok import Token, NoneToken
from xdis.version_info import PYTHON3
if PYTHON3: minint = -sys.maxsize - 1
minint = -sys.maxsize - 1 maxint = sys.maxsize
maxint = sys.maxsize
else:
minint = -sys.maxint - 1
maxint = sys.maxint
# Operator precidence See # Operator precidence See

View File

@@ -3,13 +3,8 @@ import sys
from xdis import iscode from xdis import iscode
from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.parsers.treenode import SyntaxTree
from xdis.version_info import PYTHON3 minint = -sys.maxsize-1
if PYTHON3: maxint = sys.maxsize
minint = -sys.maxsize-1
maxint = sys.maxsize
else:
minint = -sys.maxint-1
maxint = sys.maxint
read_write_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL', 'LOAD_GLOBAL')) read_write_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL', 'LOAD_GLOBAL'))
read_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL')) read_global_ops = frozenset(('STORE_GLOBAL', 'DELETE_GLOBAL'))
@@ -145,18 +140,7 @@ def print_docstring(self, indent, docstring):
quote = "'''" quote = "'''"
self.write(indent) self.write(indent)
if not PYTHON3 and not isinstance(docstring, str): docstring = repr(docstring.expandtabs())[1:-1]
# 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]
for (orig, replace) in (('\\\\', '\t'), for (orig, replace) in (('\\\\', '\t'),
('\\r\\n', '\n'), ('\\r\\n', '\n'),

View File

@@ -27,12 +27,8 @@ from uncompyle6.semantics.helper import (
find_none, find_none,
) )
from xdis import iscode, code_has_star_arg, code_has_star_star_arg 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
from itertools import zip_longest
else:
from itertools import izip_longest as zip_longest
from uncompyle6.show import maybe_show_tree_param_default from uncompyle6.show import maybe_show_tree_param_default

View File

@@ -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 # 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 # 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_globals_and_nonlocals,
find_none, find_none,
) )
from xdis.version_info import PYTHON3 from itertools import zip_longest
if PYTHON3:
from itertools import zip_longest
else:
from itertools import izip_longest as zip_longest
from uncompyle6.show import maybe_show_tree_param_default 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]: if fn_bits[-1]:
index -= 1 index -= 1
if fn_bits[-2]: if fn_bits[-2]:
ann_dict = node[index] # ann_dict = node[index]
index -= 1 index -= 1
if fn_bits[-3]: if fn_bits[-3]:
kw_dict = node[index] kw_dict = node[index]
index -= 1 index -= 1
if fn_bits[-4]: if fn_bits[-4]:
default_tup = node[index] # default_tup = node[index]
pass
if kw_dict == "expr": if kw_dict == "expr":
kw_dict = kw_dict[0] 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]] defaults = [self.traverse(n, indent="") for n in kw_dict[:-2]]
names = eval(self.traverse(kw_dict[-2])) names = eval(self.traverse(kw_dict[-2]))
assert len(defaults) == len(names) assert len(defaults) == len(names)
sep = ""
# FIXME: possibly handle line breaks # FIXME: possibly handle line breaks
for i, n in enumerate(names): for i, n in enumerate(names):
idx = kwargs.index(n) idx = kwargs.index(n)

View File

@@ -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 <h.goebel@crazy-compilers.com> # (C) Copyright 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@@ -27,14 +27,9 @@ from subprocess import call
import uncompyle6 import uncompyle6
from uncompyle6.scanner import Token as ScannerToken, get_scanner 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 import iscode, load_file, load_module, pretty_code_flags, PYTHON_MAGIC_INT
from xdis.version_info import PYTHON3
# FIXME: DRY truediv = operator.truediv
if PYTHON3: from functools import reduce
truediv = operator.truediv
from functools import reduce
else:
truediv = operator.div
def code_equal(a, b): 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) scanner = get_scanner(version, is_pypy, show_asm=False)
global JUMP_OPS global JUMP_OPS
JUMP_OPS = list(scan.JUMP_OPS) + ["JUMP_BACK"] JUMP_OPS = list(JUMP_OPS) + ["JUMP_BACK"]
# use changed Token class # use changed Token class
# We (re)set this here to save exception handling, # We (re)set this here to save exception handling,