You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
DRY scanner code more...
Expand 2.6 testing
This commit is contained in:
2
Makefile
2
Makefile
@@ -28,7 +28,7 @@ check-short: pytest
|
|||||||
$(MAKE) -C test check-short
|
$(MAKE) -C test check-short
|
||||||
|
|
||||||
#: Tests for Python 2.7, 3.3 and 3.4
|
#: Tests for Python 2.7, 3.3 and 3.4
|
||||||
check-2.7 check-3.3 check-3.4: pytest
|
check-2.6 check-2.7 check-3.3 check-3.4: pytest
|
||||||
$(MAKE) -C test $@
|
$(MAKE) -C test $@
|
||||||
|
|
||||||
#: Tests for Python 3.2 and 3.5 - pytest doesn't work here
|
#: Tests for Python 3.2 and 3.5 - pytest doesn't work here
|
||||||
|
@@ -23,12 +23,7 @@ def test_if_in_for():
|
|||||||
code = bug.__code__
|
code = bug.__code__
|
||||||
scan = get_scanner(PYTHON_VERSION)
|
scan = get_scanner(PYTHON_VERSION)
|
||||||
if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY:
|
if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY:
|
||||||
bytecode = scan.build_instructions(code)
|
scan.build_instructions(code)
|
||||||
scan.lines = scan.build_lines_data(code)
|
|
||||||
scan.insts = list(bytecode)
|
|
||||||
scan.offset2inst_index = {}
|
|
||||||
for i, inst in enumerate(scan.insts):
|
|
||||||
scan.offset2inst_index[inst.offset] = i
|
|
||||||
fjt = scan.find_jump_targets(False)
|
fjt = scan.find_jump_targets(False)
|
||||||
|
|
||||||
## FIXME: the data below is wrong.
|
## FIXME: the data below is wrong.
|
||||||
@@ -43,12 +38,7 @@ def test_if_in_for():
|
|||||||
# {'start': 62, 'end': 63, 'type': 'for-else'}]
|
# {'start': 62, 'end': 63, 'type': 'for-else'}]
|
||||||
|
|
||||||
code = bug_loop.__code__
|
code = bug_loop.__code__
|
||||||
bytecode = scan.build_instructions(code)
|
scan.build_instructions(code)
|
||||||
scan.lines = scan.build_lines_data(code)
|
|
||||||
scan.insts = list(bytecode)
|
|
||||||
scan.offset2inst_index = {}
|
|
||||||
for i, inst in enumerate(scan.insts):
|
|
||||||
scan.offset2inst_index[inst.offset] = i
|
|
||||||
fjt = scan.find_jump_targets(False)
|
fjt = scan.find_jump_targets(False)
|
||||||
assert{64: [42], 67: [42, 42], 42: [16, 41], 19: [6]} == fjt
|
assert{64: [42], 67: [42, 42], 42: [16, 41], 19: [6]} == fjt
|
||||||
assert scan.structs == [
|
assert scan.structs == [
|
||||||
@@ -62,12 +52,7 @@ def test_if_in_for():
|
|||||||
{'start': 48, 'end': 67, 'type': 'while-loop'}]
|
{'start': 48, 'end': 67, 'type': 'while-loop'}]
|
||||||
|
|
||||||
elif 3.2 < PYTHON_VERSION <= 3.4:
|
elif 3.2 < PYTHON_VERSION <= 3.4:
|
||||||
bytecode = scan.build_instructions(code)
|
scan.build_instructions(code)
|
||||||
scan.lines = scan.build_lines_data(code)
|
|
||||||
scan.insts = list(bytecode)
|
|
||||||
scan.offset2inst_index = {}
|
|
||||||
for i, inst in enumerate(scan.insts):
|
|
||||||
scan.offset2inst_index[inst.offset] = i
|
|
||||||
fjt = scan.find_jump_targets(False)
|
fjt = scan.find_jump_targets(False)
|
||||||
assert {69: [66], 63: [18]} == fjt
|
assert {69: [66], 63: [18]} == fjt
|
||||||
assert scan.structs == \
|
assert scan.structs == \
|
||||||
|
@@ -6,7 +6,7 @@ import pytest
|
|||||||
# uncompyle
|
# uncompyle
|
||||||
from validate import validate_uncompyle
|
from validate import validate_uncompyle
|
||||||
from test_fstring import expressions
|
from test_fstring import expressions
|
||||||
|
from uncompyle6 import PYTHON_VERSION
|
||||||
|
|
||||||
alpha = st.sampled_from(string.ascii_lowercase)
|
alpha = st.sampled_from(string.ascii_lowercase)
|
||||||
numbers = st.sampled_from(string.digits)
|
numbers = st.sampled_from(string.digits)
|
||||||
@@ -81,10 +81,11 @@ def function_calls(draw,
|
|||||||
def test_function_no_args():
|
def test_function_no_args():
|
||||||
validate_uncompyle("fn()")
|
validate_uncompyle("fn()")
|
||||||
|
|
||||||
|
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||||
|
reason="need at least Python 2.7")
|
||||||
def isolated_function_calls(which):
|
def isolated_function_calls(which):
|
||||||
"""
|
"""
|
||||||
Returns a strategy for generating function calls, but isolated to
|
Returns a strategy for generating function calls, but isolated to
|
||||||
particular types of arguments, for example only positional arguments.
|
particular types of arguments, for example only positional arguments.
|
||||||
|
|
||||||
This can help reason about debugging errors in specific types of function
|
This can help reason about debugging errors in specific types of function
|
||||||
@@ -108,21 +109,29 @@ def isolated_function_calls(which):
|
|||||||
|
|
||||||
with settings(max_examples=25):
|
with settings(max_examples=25):
|
||||||
|
|
||||||
|
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||||
|
reason="need at least Python 2.7")
|
||||||
@given(isolated_function_calls('positional'))
|
@given(isolated_function_calls('positional'))
|
||||||
@example("fn(0)")
|
@example("fn(0)")
|
||||||
def test_function_positional_only(expr):
|
def test_function_positional_only(expr):
|
||||||
validate_uncompyle(expr)
|
validate_uncompyle(expr)
|
||||||
|
|
||||||
|
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||||
|
reason="need at least Python 2.7")
|
||||||
@given(isolated_function_calls('keyword'))
|
@given(isolated_function_calls('keyword'))
|
||||||
@example("fn(a=0)")
|
@example("fn(a=0)")
|
||||||
def test_function_call_keyword_only(expr):
|
def test_function_call_keyword_only(expr):
|
||||||
validate_uncompyle(expr)
|
validate_uncompyle(expr)
|
||||||
|
|
||||||
|
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||||
|
reason="need at least Python 2.7")
|
||||||
@given(isolated_function_calls('star'))
|
@given(isolated_function_calls('star'))
|
||||||
@example("fn(*items)")
|
@example("fn(*items)")
|
||||||
def test_function_call_star_only(expr):
|
def test_function_call_star_only(expr):
|
||||||
validate_uncompyle(expr)
|
validate_uncompyle(expr)
|
||||||
|
|
||||||
|
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||||
|
reason="need at least Python 2.7")
|
||||||
@given(isolated_function_calls('double_star'))
|
@given(isolated_function_calls('double_star'))
|
||||||
@example("fn(**{})")
|
@example("fn(**{})")
|
||||||
def test_function_call_double_star_only(expr):
|
def test_function_call_double_star_only(expr):
|
||||||
|
@@ -20,13 +20,17 @@ def test_grammar():
|
|||||||
# We have custom rules that create the below
|
# We have custom rules that create the below
|
||||||
expect_lhs = set(['pos_arg', 'get_iter', 'attribute'])
|
expect_lhs = set(['pos_arg', 'get_iter', 'attribute'])
|
||||||
|
|
||||||
unused_rhs = set(['list', 'mkfunc', 'dict',
|
unused_rhs = set(['list', 'mkfunc',
|
||||||
'mklambda',
|
'mklambda',
|
||||||
'unpack',])
|
'unpack',])
|
||||||
expect_right_recursive = set([('designList',
|
expect_right_recursive = set([('designList',
|
||||||
('store', 'DUP_TOP', 'designList'))])
|
('store', 'DUP_TOP', 'designList'))])
|
||||||
expect_lhs.add('kvlist')
|
|
||||||
expect_lhs.add('kv3')
|
if PYTHON_VERSION > 2.6:
|
||||||
|
expect_lhs.add('kvlist')
|
||||||
|
expect_lhs.add('kv3')
|
||||||
|
unused_rhs.add('dict')
|
||||||
|
|
||||||
if PYTHON3:
|
if PYTHON3:
|
||||||
expect_lhs.add('load_genexpr')
|
expect_lhs.add('load_genexpr')
|
||||||
|
|
||||||
@@ -85,6 +89,8 @@ def test_grammar():
|
|||||||
""".split())
|
""".split())
|
||||||
if 2.6 <= PYTHON_VERSION <= 2.7:
|
if 2.6 <= PYTHON_VERSION <= 2.7:
|
||||||
opcode_set = set(s.opc.opname).union(ignore_set)
|
opcode_set = set(s.opc.opname).union(ignore_set)
|
||||||
|
if PYTHON_VERSION == 2.6:
|
||||||
|
opcode_set.add("THEN")
|
||||||
check_tokens(tokens, opcode_set)
|
check_tokens(tokens, opcode_set)
|
||||||
elif PYTHON_VERSION == 3.4:
|
elif PYTHON_VERSION == 3.4:
|
||||||
ignore_set.add('LOAD_CLASSNAME')
|
ignore_set.add('LOAD_CLASSNAME')
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from uncompyle6 import PYTHON_VERSION, PYTHON3, deparse_code
|
from uncompyle6 import PYTHON_VERSION, deparse_code
|
||||||
|
|
||||||
|
@pytest.mark.skip(PYTHON_VERSION < 2.7,
|
||||||
|
reason="need at least Python 2.7")
|
||||||
def test_single_mode():
|
def test_single_mode():
|
||||||
single_expressions = (
|
single_expressions = (
|
||||||
'i = 1',
|
'i = 1',
|
||||||
|
@@ -105,6 +105,11 @@ class Scanner(object):
|
|||||||
bytecode = Bytecode(co, self.opc)
|
bytecode = Bytecode(co, self.opc)
|
||||||
self.build_prev_op()
|
self.build_prev_op()
|
||||||
self.insts = self.remove_extended_args(list(bytecode))
|
self.insts = self.remove_extended_args(list(bytecode))
|
||||||
|
self.lines = self.build_lines_data(co)
|
||||||
|
self.offset2inst_index = {}
|
||||||
|
for i, inst in enumerate(self.insts):
|
||||||
|
self.offset2inst_index[inst.offset] = i
|
||||||
|
|
||||||
return bytecode
|
return bytecode
|
||||||
|
|
||||||
def build_lines_data(self, code_obj):
|
def build_lines_data(self, code_obj):
|
||||||
@@ -117,10 +122,6 @@ class Scanner(object):
|
|||||||
linestarts = list(self.opc.findlinestarts(code_obj))
|
linestarts = list(self.opc.findlinestarts(code_obj))
|
||||||
self.linestarts = dict(linestarts)
|
self.linestarts = dict(linestarts)
|
||||||
|
|
||||||
# Plain set with offsets of first ops on line.
|
|
||||||
# FIXME: we probably could do without
|
|
||||||
self.linestart_offsets = set(a for (a, _) in linestarts)
|
|
||||||
|
|
||||||
# 'List-map' which shows line number of current op and offset of
|
# 'List-map' which shows line number of current op and offset of
|
||||||
# first op on following line, given offset of op as index
|
# first op on following line, given offset of op as index
|
||||||
lines = []
|
lines = []
|
||||||
@@ -452,6 +453,9 @@ class Scanner(object):
|
|||||||
Go through passed offsets, filtering ifs
|
Go through passed offsets, filtering ifs
|
||||||
located somewhere mid-line.
|
located somewhere mid-line.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# FIXME: this doesn't work for Python 3.6+
|
||||||
|
|
||||||
filtered = []
|
filtered = []
|
||||||
for i in ifs:
|
for i in ifs:
|
||||||
# For each offset, if line number of current and next op
|
# For each offset, if line number of current and next op
|
||||||
|
@@ -171,11 +171,6 @@ class Scanner2(Scanner):
|
|||||||
customize['PyPy'] = 0
|
customize['PyPy'] = 0
|
||||||
|
|
||||||
codelen = len(self.code)
|
codelen = len(self.code)
|
||||||
self.lines = self.build_lines_data(co)
|
|
||||||
|
|
||||||
self.offset2inst_index = {}
|
|
||||||
for i, inst in enumerate(self.insts):
|
|
||||||
self.offset2inst_index[inst.offset] = i
|
|
||||||
|
|
||||||
free, names, varnames = self.unmangle_code_names(co, classname)
|
free, names, varnames = self.unmangle_code_names(co, classname)
|
||||||
self.names = names
|
self.names = names
|
||||||
@@ -186,8 +181,6 @@ class Scanner2(Scanner):
|
|||||||
self.load_asserts = set()
|
self.load_asserts = set()
|
||||||
for i in self.op_range(0, codelen):
|
for i in self.op_range(0, codelen):
|
||||||
|
|
||||||
self.offset2inst_index[inst.offset] = i
|
|
||||||
|
|
||||||
# We need to detect the difference between:
|
# We need to detect the difference between:
|
||||||
# raise AssertionError
|
# raise AssertionError
|
||||||
# and
|
# and
|
||||||
@@ -358,7 +351,7 @@ class Scanner2(Scanner):
|
|||||||
if (offset in self.stmts and
|
if (offset in self.stmts and
|
||||||
self.code[offset+3] not in (self.opc.END_FINALLY,
|
self.code[offset+3] not in (self.opc.END_FINALLY,
|
||||||
self.opc.POP_BLOCK)):
|
self.opc.POP_BLOCK)):
|
||||||
if ((offset in self.linestart_offsets and
|
if ((offset in self.linestarts and
|
||||||
self.code[self.prev[offset]] == self.opc.JUMP_ABSOLUTE)
|
self.code[self.prev[offset]] == self.opc.JUMP_ABSOLUTE)
|
||||||
or self.code[target] == self.opc.FOR_ITER
|
or self.code[target] == self.opc.FOR_ITER
|
||||||
or offset not in self.not_continue):
|
or offset not in self.not_continue):
|
||||||
@@ -956,7 +949,7 @@ class Scanner2(Scanner):
|
|||||||
'end': pre_rtarget})
|
'end': pre_rtarget})
|
||||||
|
|
||||||
# FIXME: this is yet another case were we need dominators.
|
# FIXME: this is yet another case were we need dominators.
|
||||||
if (pre_rtarget not in self.linestart_offsets
|
if (pre_rtarget not in self.linestarts
|
||||||
or self.version < 2.7):
|
or self.version < 2.7):
|
||||||
self.not_continue.add(pre_rtarget)
|
self.not_continue.add(pre_rtarget)
|
||||||
|
|
||||||
|
@@ -84,13 +84,6 @@ class Scanner26(scan.Scanner2):
|
|||||||
|
|
||||||
codelen = len(self.code)
|
codelen = len(self.code)
|
||||||
|
|
||||||
self.lines = self.build_lines_data(co)
|
|
||||||
|
|
||||||
self.insts = list(bytecode)
|
|
||||||
self.offset2inst_index = {}
|
|
||||||
for i, inst in enumerate(self.insts):
|
|
||||||
self.offset2inst_index[inst.offset] = i
|
|
||||||
|
|
||||||
free, names, varnames = self.unmangle_code_names(co, classname)
|
free, names, varnames = self.unmangle_code_names(co, classname)
|
||||||
self.names = names
|
self.names = names
|
||||||
|
|
||||||
@@ -248,7 +241,7 @@ class Scanner26(scan.Scanner2):
|
|||||||
if (offset in self.stmts
|
if (offset in self.stmts
|
||||||
and self.code[offset+3] not in (self.opc.END_FINALLY,
|
and self.code[offset+3] not in (self.opc.END_FINALLY,
|
||||||
self.opc.POP_BLOCK)):
|
self.opc.POP_BLOCK)):
|
||||||
if ((offset in self.linestart_offsets and
|
if ((offset in self.linestarts and
|
||||||
tokens[-1].kind == 'JUMP_BACK')
|
tokens[-1].kind == 'JUMP_BACK')
|
||||||
or offset not in self.not_continue):
|
or offset not in self.not_continue):
|
||||||
op_name = 'CONTINUE'
|
op_name = 'CONTINUE'
|
||||||
|
@@ -187,19 +187,14 @@ class Scanner3(Scanner):
|
|||||||
if self.is_pypy:
|
if self.is_pypy:
|
||||||
customize['PyPy'] = 0
|
customize['PyPy'] = 0
|
||||||
|
|
||||||
self.lines = self.build_lines_data(co)
|
|
||||||
|
|
||||||
# Scan for assertions. Later we will
|
# Scan for assertions. Later we will
|
||||||
# turn 'LOAD_GLOBAL' to 'LOAD_ASSERT'.
|
# turn 'LOAD_GLOBAL' to 'LOAD_ASSERT'.
|
||||||
# 'LOAD_ASSERT' is used in assert statements.
|
# 'LOAD_ASSERT' is used in assert statements.
|
||||||
self.load_asserts = set()
|
self.load_asserts = set()
|
||||||
|
|
||||||
self.offset2inst_index = {}
|
|
||||||
n = len(self.insts)
|
n = len(self.insts)
|
||||||
for i, inst in enumerate(self.insts):
|
for i, inst in enumerate(self.insts):
|
||||||
|
|
||||||
self.offset2inst_index[inst.offset] = i
|
|
||||||
|
|
||||||
# We need to detect the difference between:
|
# We need to detect the difference between:
|
||||||
# raise AssertionError
|
# raise AssertionError
|
||||||
# and
|
# and
|
||||||
|
Reference in New Issue
Block a user