Merge branch 'master' of github.com:rocky/python-uncompyle6

This commit is contained in:
rocky
2020-09-10 17:19:36 -04:00
9 changed files with 160 additions and 76 deletions

11
NEWS.md
View File

@@ -1,3 +1,14 @@
3.7.4: 2020-8-05
================
* Fragment parsing was borked. This means deparsing in trepan2/trepan3k was broken
* 3.7+: narrow precedence for call tatement
* del_stmt -> delete to better match Python AST
* 3.8+ Add another `forelsestmt` (found only in a loop)
* 3.8+ Add precedence on walrus operator
* More files blackened
* bump min xdis version
3.7.3: 2020-7-25
================

View File

@@ -33,65 +33,71 @@
# 3.4 | pip | 19.1.1 |
# Things that change more often go here.
copyright = """
copyright = """
Copyright (C) 2015-2020 Rocky Bernstein <rb@dustyfeet.com>.
"""
classifiers = ["Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2.4",
"Programming Language :: Python :: 2.5",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.0",
"Programming Language :: Python :: 3.1",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Topic :: Software Development :: Debuggers",
"Topic :: Software Development :: Libraries :: Python Modules",
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2.4",
"Programming Language :: Python :: 2.5",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.0",
"Programming Language :: Python :: 3.1",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Topic :: Software Development :: Debuggers",
"Topic :: Software Development :: Libraries :: Python Modules",
]
# The rest in alphabetic order
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
author_email = "rb@dustyfeet.com"
entry_points = {
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
author_email = "rb@dustyfeet.com"
entry_points = {
"console_scripts": [
"uncompyle6=uncompyle6.bin.uncompile:main_bin",
"pydisassemble=uncompyle6.bin.pydisassemble:main",
]}
ftp_url = None
install_requires = ["spark-parser >= 1.8.9, < 1.9.0",
"xdis >= 4.7.0, <5.1.0"]
]
}
ftp_url = None
install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 5.0.4, <5.1.0"]
license = "GPL3"
mailing_list = "python-debugger@googlegroups.com"
modname = "uncompyle6"
py_modules = None
short_desc = "Python cross-version byte-code decompiler"
web = "https://github.com/rocky/python-uncompyle6/"
license = "GPL3"
mailing_list = "python-debugger@googlegroups.com"
modname = "uncompyle6"
py_modules = None
short_desc = "Python cross-version byte-code decompiler"
web = "https://github.com/rocky/python-uncompyle6/"
# tracebacks in zip files are funky and not debuggable
zip_safe = True
import os.path
def get_srcdir():
filename = os.path.normcase(os.path.dirname(os.path.abspath(__file__)))
return os.path.realpath(filename)
srcdir = get_srcdir()
def read(*rnames):
return open(os.path.join(srcdir, *rnames)).read()
# Get info from files; set: long_description and VERSION
long_description = ( read("README.rst") + "\n" )
long_description = read("README.rst") + "\n"
exec(read("uncompyle6/version.py"))

View File

@@ -55,11 +55,11 @@
# Make packages and tag
$ . ./admin-tools/make-dist-older.sh
$ pyenv local 3.8.4
$ twine check dist/uncompyle6-$VERSION*
$ ./admin-tools/make-dist-newer.sh
$ pyenv local 3.8.5
$ twine check dist/uncompyle6-$VERSION*
$ git tag release-python-2.4-$VERSION
$ ./admin-tools/make-dist-newer.sh
$ twine check dist/uncompyle6-$VERSION*
# Check package on github

View File

@@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
echo "This script should be *sourced* rather than run directly through bash"
exit 1
fi
export PYVERSIONS='3.5.9 3.6.11 2.6.9 3.3.7 2.7.18 3.2.6 3.1.5 3.4.10 3.7.8 3.8.5'
export PYVERSIONS='3.5.9 3.6.12 2.6.9 3.3.7 2.7.18 3.2.6 3.1.5 3.4.10 3.7.9 3.8.5'

View File

@@ -1200,7 +1200,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
p_insts = self.p.insts
self.p.insts = self.scanner.insts
self.p.offset2inst_index = self.scanner.offset2inst_index
ast = parser.parse(self.p, tokens, customize)
ast = parser.parse(self.p, tokens, customize, code)
self.p.insts = p_insts
except (parser.ParserError, AssertionError) as e:
raise ParserError(e, tokens, {})
@@ -1544,7 +1544,8 @@ class FragmentsWalker(pysource.SourceWalker, object):
line_seperator = ",\n" + self.indent
sep = INDENT_PER_LEVEL[:-1]
start = len(self.f.getvalue())
self.write("{")
if node[0] != "dict_entry":
self.write("{")
self.set_pos_info(node[0], start, start + 1)
if self.version >= 3.0 and not self.is_pypy:
@@ -1570,7 +1571,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
i += 2
pass
pass
elif node[1].kind.startswith("kvlist"):
elif len(node) > 1 and node[1].kind.startswith("kvlist"):
# Python 3.0..3.4 style key/value list in dict
kv_node = node[1]
l = list(kv_node)
@@ -1596,37 +1597,98 @@ class FragmentsWalker(pysource.SourceWalker, object):
i += 3
pass
pass
elif node[-1].kind.startswith("BUILD_CONST_KEY_MAP"):
# Python 3.6+ style const map
keys = node[-2].pattr
values = node[:-2]
# FIXME: Line numbers?
for key, value in zip(keys, values):
self.write(sep)
self.write(repr(key))
line_number = self.line_number
self.write(":")
self.write(self.traverse(value[0]))
sep = ", "
if line_number != self.line_number:
sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
line_number = self.line_number
else:
sep += " "
pass
pass
if sep.startswith(",\n"):
self.write(sep[1:])
pass
elif node[0].kind.startswith("dict_entry"):
assert self.version >= 3.5
template = ("%C", (0, len(node[0]), ", **"))
self.template_engine(template, node[0])
sep = ""
elif node[-1].kind.startswith("BUILD_MAP_UNPACK") or node[
-1
].kind.startswith("dict_entry"):
assert self.version >= 3.5
# FIXME: I think we can intermingle dict_comp's with other
# dictionary kinds of things. The most common though is
# a sequence of dict_comp's
kwargs = node[-1].attr
template = ("**%C", (0, kwargs, ", **"))
self.template_engine(template, node)
sep = ""
pass
else:
# Python 2 style kvlist
assert node[-1].kind.startswith("kvlist")
kv_node = node[-1] # goto kvlist
# Python 2 style kvlist. Find beginning of kvlist.
indent = self.indent + " "
line_number = self.line_number
if node[0].kind.startswith("BUILD_MAP"):
if len(node) > 1 and node[1].kind in ("kvlist", "kvlist_n"):
kv_node = node[1]
else:
kv_node = node[1:]
self.kv_map(kv_node, sep, line_number, indent)
for kv in kv_node:
assert kv in ("kv", "kv2", "kv3")
# kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR
# kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR
# kv3 ::= expr expr STORE_MAP
if kv == "kv":
name = self.traverse(kv[-2], indent="")
kv[1].parent = kv_node
value = self.traverse(
kv[1], indent=self.indent + (len(name) + 2) * " "
)
elif kv == "kv2":
name = self.traverse(kv[1], indent="")
kv[-3].parent = kv_node
value = self.traverse(
kv[-3], indent=self.indent + (len(name) + 2) * " "
)
elif kv == "kv3":
name = self.traverse(kv[-2], indent="")
kv[0].parent = kv_node
value = self.traverse(
kv[0], indent=self.indent + (len(name) + 2) * " "
)
self.write(sep, name, ": ", value)
sep = line_seperator
else:
sep = ""
opname = node[-1].kind
if self.is_pypy and self.version >= 3.5:
if opname.startswith("BUILD_CONST_KEY_MAP"):
keys = node[-2].attr
# FIXME: DRY this and the above
for i in range(len(keys)):
key = keys[i]
value = self.traverse(node[i], indent="")
self.write(sep, key, ": ", value)
sep = ", "
if line_number != self.line_number:
sep += "\n" + self.indent + " "
line_number = self.line_number
pass
pass
pass
else:
if opname.startswith("kvlist"):
list_node = node[0]
else:
list_node = node
assert list_node[-1].kind.startswith("BUILD_MAP")
for i in range(0, len(list_node) - 1, 2):
key = self.traverse(list_node[i], indent="")
value = self.traverse(list_node[i + 1], indent="")
self.write(sep, key, ": ", value)
sep = ", "
if line_number != self.line_number:
sep += "\n" + self.indent + " "
line_number = self.line_number
pass
pass
pass
elif opname.startswith("kvlist"):
kv_node = node[-1]
self.kv_map(node[-1], sep, line_number, indent)
pass
self.write("}")
finish = len(self.f.getvalue())
self.set_pos_info(node, start, finish)

View File

@@ -1660,7 +1660,7 @@ class SourceWalker(GenericASTTraversal, object):
"""
prettyprint a dict
'dict' is something like k = {'a': 1, 'b': 42}"
We will source-code use line breaks to guide us when to break.
We will use source-code line breaks to guide us when to break.
"""
p = self.prec
self.prec = 100

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2018 Rocky Bernstein <rocky@gnu.org>
# Copyright (C) 2018, 2020 Rocky Bernstein <rocky@gnu.org>
#
# 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
@@ -47,8 +47,11 @@ def maybe_show_tree(walker, ast):
stream = walker.showast
else:
stream = sys.stdout
if (isinstance(walker.showast, dict) and walker.showast.get("Full", False)
and hasattr(walker, "str_with_template")):
if (
isinstance(walker.showast, dict)
and walker.showast.get("Full", False)
and hasattr(walker, "str_with_template")
):
walker.str_with_template(ast)
else:
stream.write(str(ast))

View File

@@ -5,10 +5,12 @@
from math import copysign
from uncompyle6 import PYTHON_VERSION
def is_negative_zero(n):
"""Returns true if n is -0.0"""
return n == 0.0 and copysign(1, n) == -1
def better_repr(v, version):
"""Work around Python's unorthogonal and unhelpful repr() for primitive float
and complex."""

View File

@@ -12,4 +12,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This file is suitable for sourcing inside POSIX shell as
# well as importing into Python
VERSION="3.7.3" # noqa
VERSION="3.7.4" # noqa