You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 09:22:40 +08:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f0f9676f52 | ||
|
be610aa6b3 | ||
|
1494bb2049 | ||
|
d62dc3daac | ||
|
5ad51707e3 | ||
|
f28c255804 | ||
|
315965300f | ||
|
9bd85fe5a0 |
10
NEWS.md
10
NEWS.md
@@ -1,3 +1,13 @@
|
|||||||
|
3.4.1 2019-10-02
|
||||||
|
================
|
||||||
|
|
||||||
|
- Correct assert{,2} transforms Fixes #289
|
||||||
|
- Fragment parsing fixes:
|
||||||
|
* Wasn't handling 3-arg %p
|
||||||
|
* fielding error in code_deparse()
|
||||||
|
- Use newer xdis to better track Python 3.8.0
|
||||||
|
|
||||||
|
|
||||||
3.4.0 2019-08-24 Totoro
|
3.4.0 2019-08-24 Totoro
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
|buildstatus| |Latest Version| |Supported Python Versions|
|
|buildstatus| |Pypi Installs| |Latest Version| |Supported Python Versions|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|packagestatus|
|
|packagestatus|
|
||||||
|
|
||||||
@@ -244,3 +246,4 @@ See Also
|
|||||||
.. |Supported Python Versions| image:: https://img.shields.io/pypi/pyversions/uncompyle6.svg
|
.. |Supported Python Versions| image:: https://img.shields.io/pypi/pyversions/uncompyle6.svg
|
||||||
.. |Latest Version| image:: https://badge.fury.io/py/uncompyle6.svg
|
.. |Latest Version| image:: https://badge.fury.io/py/uncompyle6.svg
|
||||||
:target: https://badge.fury.io/py/uncompyle6
|
:target: https://badge.fury.io/py/uncompyle6
|
||||||
|
.. |Pypi Installs| image:: https://pepy.tech/badge/uncompyle6/month
|
||||||
|
@@ -58,7 +58,7 @@ entry_points = {
|
|||||||
]}
|
]}
|
||||||
ftp_url = None
|
ftp_url = None
|
||||||
install_requires = ["spark-parser >= 1.8.9, < 1.9.0",
|
install_requires = ["spark-parser >= 1.8.9, < 1.9.0",
|
||||||
"xdis >= 4.0.3, < 4.1.0"]
|
"xdis >= 4.0.4, < 4.1.0"]
|
||||||
|
|
||||||
license = "GPL3"
|
license = "GPL3"
|
||||||
mailing_list = "python-debugger@googlegroups.com"
|
mailing_list = "python-debugger@googlegroups.com"
|
||||||
|
@@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
|
|||||||
echo "This script should be *sourced* rather than run directly through bash"
|
echo "This script should be *sourced* rather than run directly through bash"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
export PYVERSIONS='3.6.8 3.7.3 2.6.9 3.3.7 2.7.16 3.2.6 3.1.5 3.4.8'
|
export PYVERSIONS='3.6.9 3.7.4 2.6.9 3.3.7 2.7.16 3.2.6 3.1.5 3.4.10 3.5.7'
|
||||||
|
@@ -2,22 +2,23 @@
|
|||||||
""" Trivial helper program to bytecompile and run an uncompile
|
""" Trivial helper program to bytecompile and run an uncompile
|
||||||
"""
|
"""
|
||||||
import os, sys, py_compile
|
import os, sys, py_compile
|
||||||
|
|
||||||
assert len(sys.argv) >= 2
|
assert len(sys.argv) >= 2
|
||||||
version = sys.version[0:3]
|
version = sys.version[0:3]
|
||||||
if sys.argv[1] == '--run':
|
if sys.argv[1] in ("--run", "-r"):
|
||||||
suffix = '_run'
|
suffix = "_run"
|
||||||
py_source = sys.argv[2:]
|
py_source = sys.argv[2:]
|
||||||
else:
|
else:
|
||||||
suffix = ''
|
suffix = ""
|
||||||
py_source = sys.argv[1:]
|
py_source = sys.argv[1:]
|
||||||
|
|
||||||
for path in py_source:
|
for path in py_source:
|
||||||
short = os.path.basename(path)
|
short = os.path.basename(path)
|
||||||
if hasattr(sys, 'pypy_version_info'):
|
if hasattr(sys, "pypy_version_info"):
|
||||||
cfile = "bytecode_pypy%s%s/%s" % (version, suffix, short) + 'c'
|
cfile = "bytecode_pypy%s%s/%s" % (version, suffix, short) + "c"
|
||||||
else:
|
else:
|
||||||
cfile = "bytecode_%s%s/%s" % (version, suffix, short) + 'c'
|
cfile = "bytecode_%s%s/%s" % (version, suffix, short) + "c"
|
||||||
print("byte-compiling %s to %s" % (path, cfile))
|
print("byte-compiling %s to %s" % (path, cfile))
|
||||||
py_compile.compile(path, cfile)
|
py_compile.compile(path, cfile)
|
||||||
if isinstance(version, str) or version >= (2, 6, 0):
|
if isinstance(version, str) or version >= (2, 6, 0):
|
||||||
os.system("../bin/uncompyle6 -a -t %s" % cfile)
|
os.system("../bin/uncompyle6 -a -T %s" % cfile)
|
||||||
|
BIN
test/bytecode_3.7_run/01_assert2.pyc
Normal file
BIN
test/bytecode_3.7_run/01_assert2.pyc
Normal file
Binary file not shown.
8
test/simple_source/bug37/01_assert2.py
Normal file
8
test/simple_source/bug37/01_assert2.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Self-checking test.
|
||||||
|
# Bug was in if transform not inverting expression
|
||||||
|
# This file is RUNNABLE!
|
||||||
|
def test_assert2(c):
|
||||||
|
if c < 2:
|
||||||
|
raise SyntaxError('Oops')
|
||||||
|
|
||||||
|
test_assert2(5)
|
@@ -16,7 +16,7 @@
|
|||||||
"""Isolate Python version-specific semantic actions here.
|
"""Isolate Python version-specific semantic actions here.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from uncompyle6.semantics.consts import TABLE_R, TABLE_DIRECT
|
from uncompyle6.semantics.consts import PRECEDENCE, TABLE_R, TABLE_DIRECT
|
||||||
|
|
||||||
from uncompyle6.parsers.treenode import SyntaxTree
|
from uncompyle6.parsers.treenode import SyntaxTree
|
||||||
from uncompyle6.scanners.tok import Token
|
from uncompyle6.scanners.tok import Token
|
||||||
@@ -27,29 +27,31 @@ def customize_for_version(self, is_pypy, version):
|
|||||||
########################
|
########################
|
||||||
# PyPy changes
|
# PyPy changes
|
||||||
#######################
|
#######################
|
||||||
TABLE_DIRECT.update(
|
TABLE_DIRECT.update({
|
||||||
{
|
'assert_pypy': ( '%|assert %c\n' , 1 ),
|
||||||
"assert2_pypy": ("%|assert %c, %c\n", (1, "assert_expr"), 4),
|
'assert2_pypy': ( '%|assert %c, %c\n' , 1, 4 ),
|
||||||
"assert_pypy": ("%|assert %c\n", (1, "assert_expr")),
|
'try_except_pypy': ( '%|try:\n%+%c%-%c\n\n', 1, 2 ),
|
||||||
"assign2_pypy": ("%|%c, %c = %c, %c\n", 3, 2, 0, 1),
|
'tryfinallystmt_pypy': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 3 ),
|
||||||
"assign3_pypy": ("%|%c, %c, %c = %c, %c, %c\n", 5, 4, 3, 0, 1, 2),
|
'assign3_pypy': ( '%|%c, %c, %c = %c, %c, %c\n', 5, 4, 3, 0, 1, 2 ),
|
||||||
"try_except_pypy": ("%|try:\n%+%c%-%c\n\n", 1, 2),
|
'assign2_pypy': ( '%|%c, %c = %c, %c\n', 3, 2, 0, 1),
|
||||||
"tryfinallystmt_pypy": ("%|try:\n%+%c%-%|finally:\n%+%c%-\n\n", 1, 3),
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
########################
|
########################
|
||||||
# Without PyPy
|
# Without PyPy
|
||||||
#######################
|
#######################
|
||||||
TABLE_DIRECT.update(
|
TABLE_DIRECT.update({
|
||||||
{
|
"assert": ("%|assert %c\n", (0, "assert_expr")),
|
||||||
"assert": ("%|assert %c\n", (0, "assert_expr")),
|
"assert2": ("%|assert %c, %c\n", (0, "assert_expr"), 3),
|
||||||
"assert2": ("%|assert %c, %c\n", (0, "assert_expr"), 3),
|
|
||||||
"assign2": ("%|%c, %c = %c, %c\n", 3, 4, 0, 1),
|
# Created only via transformation
|
||||||
"assign3": ("%|%c, %c, %c = %c, %c, %c\n", 5, 6, 7, 0, 1, 2),
|
"assertnot": ("%|assert not %p\n", (0, PRECEDENCE['unary_not'])),
|
||||||
"try_except": ("%|try:\n%+%c%-%c\n\n", 1, 3),
|
"assert2not": ( "%|assert not %p, %c\n" ,
|
||||||
}
|
(0, PRECEDENCE['unary_not']), 3 ),
|
||||||
)
|
|
||||||
|
"assign2": ("%|%c, %c = %c, %c\n", 3, 4, 0, 1),
|
||||||
|
"assign3": ("%|%c, %c, %c = %c, %c, %c\n", 5, 6, 7, 0, 1, 2),
|
||||||
|
"try_except": ("%|try:\n%+%c%-%c\n\n", 1, 3),
|
||||||
|
})
|
||||||
if version >= 3.0:
|
if version >= 3.0:
|
||||||
if version >= 3.2:
|
if version >= 3.2:
|
||||||
TABLE_DIRECT.update(
|
TABLE_DIRECT.update(
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015-2018 by Rocky Bernstein
|
# Copyright (c) 2015-2019 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
|
||||||
@@ -1636,16 +1636,27 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
finish = len(self.f.getvalue())
|
finish = len(self.f.getvalue())
|
||||||
self.set_pos_info(node, start, finish)
|
self.set_pos_info(node, start, finish)
|
||||||
arg += 1
|
arg += 1
|
||||||
elif typ == 'p':
|
elif typ == "p":
|
||||||
p = self.prec
|
p = self.prec
|
||||||
(index, self.prec) = entry[arg]
|
tup = entry[arg]
|
||||||
|
assert isinstance(tup, tuple)
|
||||||
|
if len(tup) == 3:
|
||||||
|
(index, nonterm_name, self.prec) = tup
|
||||||
|
assert node[index] == nonterm_name, (
|
||||||
|
"at %s[%d], expected '%s' node; got '%s'"
|
||||||
|
% (node.kind, arg, nonterm_name, node[index].kind)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
assert len(tup) == 2
|
||||||
|
(index, self.prec) = entry[arg]
|
||||||
|
|
||||||
node[index].parent = node
|
node[index].parent = node
|
||||||
start = len(self.f.getvalue())
|
start = len(self.f.getvalue())
|
||||||
self.preorder(node[index])
|
self.preorder(node[index])
|
||||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||||
self.prec = p
|
self.prec = p
|
||||||
arg += 1
|
arg += 1
|
||||||
elif typ == 'C':
|
elif typ == "C":
|
||||||
low, high, sep = entry[arg]
|
low, high, sep = entry[arg]
|
||||||
lastC = remaining = len(node[low:high])
|
lastC = remaining = len(node[low:high])
|
||||||
start = len(self.f.getvalue())
|
start = len(self.f.getvalue())
|
||||||
@@ -1657,7 +1668,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
|
|
||||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||||
arg += 1
|
arg += 1
|
||||||
elif typ == 'D':
|
elif typ == "D":
|
||||||
low, high, sep = entry[arg]
|
low, high, sep = entry[arg]
|
||||||
lastC = remaining = len(node[low:high])
|
lastC = remaining = len(node[low:high])
|
||||||
for subnode in node[low:high]:
|
for subnode in node[low:high]:
|
||||||
@@ -1670,13 +1681,13 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
arg += 1
|
arg += 1
|
||||||
elif typ == 'x':
|
elif typ == "x":
|
||||||
src, dest = entry[arg]
|
src, dest = entry[arg]
|
||||||
for d in dest:
|
for d in dest:
|
||||||
self.set_pos_info_recurse(node[d], node[src].start, node[src].finish)
|
self.set_pos_info_recurse(node[d], node[src].start, node[src].finish)
|
||||||
pass
|
pass
|
||||||
arg += 1
|
arg += 1
|
||||||
elif typ == 'P':
|
elif typ == "P":
|
||||||
p = self.prec
|
p = self.prec
|
||||||
low, high, sep, self.prec = entry[arg]
|
low, high, sep, self.prec = entry[arg]
|
||||||
lastC = remaining = len(node[low:high])
|
lastC = remaining = len(node[low:high])
|
||||||
@@ -1689,13 +1700,13 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.prec = p
|
self.prec = p
|
||||||
arg += 1
|
arg += 1
|
||||||
|
|
||||||
elif typ == '{':
|
elif typ == "{":
|
||||||
d = node.__dict__
|
d = node.__dict__
|
||||||
expr = m.group('expr')
|
expr = m.group("expr")
|
||||||
|
|
||||||
# Line mapping stuff
|
# Line mapping stuff
|
||||||
if (hasattr(node, 'linestart') and node.linestart
|
if (hasattr(node, "linestart") and node.linestart
|
||||||
and hasattr(node, 'current_line_number')):
|
and hasattr(node, "current_line_number")):
|
||||||
self.source_linemap[self.current_line_number] = node.linestart
|
self.source_linemap[self.current_line_number] = node.linestart
|
||||||
# Additional fragment-position stuff
|
# Additional fragment-position stuff
|
||||||
try:
|
try:
|
||||||
@@ -1766,7 +1777,7 @@ def code_deparse(co, out=StringIO(), version=None, is_pypy=None,
|
|||||||
:param out: File like object to write the output to.
|
:param out: File like object to write the output to.
|
||||||
:param debug_opts: A dictionary with keys
|
:param debug_opts: A dictionary with keys
|
||||||
'asm': value determines whether to show
|
'asm': value determines whether to show
|
||||||
mangled bytecode disdassembly
|
mangled bytecode disassembly
|
||||||
'ast': value determines whether to show
|
'ast': value determines whether to show
|
||||||
'grammar': boolean determining whether to show
|
'grammar': boolean determining whether to show
|
||||||
grammar reduction rules.
|
grammar reduction rules.
|
||||||
@@ -1918,6 +1929,8 @@ def deparsed_find(tup, deparsed, code):
|
|||||||
"""
|
"""
|
||||||
nodeInfo = None
|
nodeInfo = None
|
||||||
name, last_i = tup
|
name, last_i = tup
|
||||||
|
if not hasattr(deparsed, "offsets"):
|
||||||
|
return None
|
||||||
if (name, last_i) in deparsed.offsets.keys():
|
if (name, last_i) in deparsed.offsets.keys():
|
||||||
nodeInfo = deparsed.offsets[name, last_i]
|
nodeInfo = deparsed.offsets[name, last_i]
|
||||||
else:
|
else:
|
||||||
|
@@ -88,7 +88,7 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
if raise_stmt == "raise_stmt1" and len(testexpr[0]) == 2:
|
if raise_stmt == "raise_stmt1" and len(testexpr[0]) == 2:
|
||||||
assert_expr = testexpr[0][0]
|
assert_expr = testexpr[0][0]
|
||||||
assert_expr.kind = "assert_expr"
|
assert_expr.kind = "assert_expr"
|
||||||
jmp_true = testexpr[0][1]
|
jump_cond = testexpr[0][1]
|
||||||
expr = raise_stmt[0]
|
expr = raise_stmt[0]
|
||||||
RAISE_VARARGS_1 = raise_stmt[1]
|
RAISE_VARARGS_1 = raise_stmt[1]
|
||||||
if expr[0] == "call":
|
if expr[0] == "call":
|
||||||
@@ -105,15 +105,19 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
# 1. RAISE_VARARGS_1
|
# 1. RAISE_VARARGS_1
|
||||||
# becomes:
|
# becomes:
|
||||||
# assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_1 COME_FROM
|
# assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_1 COME_FROM
|
||||||
|
if jump_cond == "jmp_true":
|
||||||
|
kind = "assert2"
|
||||||
|
else:
|
||||||
|
assert jump_cond == "jmp_false"
|
||||||
|
kind = "assert2not"
|
||||||
|
|
||||||
call = expr[0]
|
call = expr[0]
|
||||||
LOAD_ASSERT = call[0]
|
LOAD_ASSERT = call[0]
|
||||||
expr = call[1][0]
|
expr = call[1][0]
|
||||||
node = SyntaxTree(
|
node = SyntaxTree(
|
||||||
"assert2",
|
kind,
|
||||||
[assert_expr, jmp_true, LOAD_ASSERT, expr, RAISE_VARARGS_1]
|
[assert_expr, jump_cond, LOAD_ASSERT, expr, RAISE_VARARGS_1]
|
||||||
)
|
)
|
||||||
node.transformed_by="n_ifstmt",
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# ifstmt
|
# ifstmt
|
||||||
# 0. testexpr (2)
|
# 0. testexpr (2)
|
||||||
@@ -128,12 +132,18 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
# 1. RAISE_VARARGS_1
|
# 1. RAISE_VARARGS_1
|
||||||
# becomes:
|
# becomes:
|
||||||
# assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1 COME_FROM
|
# assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1 COME_FROM
|
||||||
|
if jump_cond == "jmp_true":
|
||||||
|
kind = "assert"
|
||||||
|
else:
|
||||||
|
assert jump_cond == "jmp_false"
|
||||||
|
kind = "assertnot"
|
||||||
|
|
||||||
LOAD_ASSERT = expr[0]
|
LOAD_ASSERT = expr[0]
|
||||||
node = SyntaxTree(
|
node = SyntaxTree(
|
||||||
"assert",
|
kind,
|
||||||
[assert_expr, jmp_true, LOAD_ASSERT, RAISE_VARARGS_1]
|
[assert_expr, jump_cond, LOAD_ASSERT, RAISE_VARARGS_1]
|
||||||
)
|
)
|
||||||
node.transformed_by="n_ifstmt",
|
node.transformed_by="n_ifstmt",
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
return node
|
return node
|
||||||
|
@@ -12,4 +12,4 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
# This file is suitable for sourcing inside bash as
|
# This file is suitable for sourcing inside bash as
|
||||||
# well as importing into Python
|
# well as importing into Python
|
||||||
VERSION="3.4.0" # noqa
|
VERSION="3.4.1" # noqa
|
||||||
|
Reference in New Issue
Block a user