Compare commits

...

50 Commits

Author SHA1 Message Date
rocky
0e5eb954b2 Adminstrivia 2019-04-19 06:01:06 -04:00
rocky
7d9286b353 Get ready for release 3.3.1 2019-04-19 05:51:05 -04:00
rocky
0de99e5d44 Scale back "try" vs. "tryelse" reduction test on 3.6+ 2019-04-18 16:45:44 -04:00
rocky
52af2ba32a 3.6+ lambda parameter handling 2019-04-18 14:21:52 -04:00
rocky
bd0db6c539 Extend annotate test to 3.7 2019-04-18 09:47:54 -04:00
rocky
8663b4ca52 Fix bugs caused by last commit 2019-04-18 07:31:16 -04:00
rocky
b2dd58a85e Hacky attemp to add more 3.x annotate information in 2019-04-18 02:26:50 -04:00
rocky
97cb193a71 3.7 chained comparison grammar 2019-04-17 23:41:41 -04:00
rocky
e6e60cb49d 3.6 Chained compare 2019-04-17 15:44:33 -04:00
rocky
2ea8c3b1b1 3.7 and 3.8 chained compare fixups 2019-04-16 10:19:16 -04:00
rocky
701d2af54e Improve Python 2.7 generator handling 2019-04-15 23:14:44 -04:00
rocky
8a4189bc0e Python 2.6-2.7ish generator handling 2019-04-15 20:32:15 -04:00
rocky
0c4ab699b5 3.4+ while handling with returns ...
these while loops don't have a JUMP_BACK in them
2019-04-15 12:03:11 -04:00
rocky
8e11c53064 More cleanup from recent refactoring 2019-04-15 08:18:31 -04:00
rocky
b4c66d4307 Was missing some 3.7 and 3.7 semantic actions...
Possibly some as a result of the last refactor?
2019-04-15 08:11:31 -04:00
rocky
53968e535f Split up version-specific semantic action code more 2019-04-14 21:47:16 -04:00
rocky
d2381fbe11 Update dates and version numbers 2019-04-14 19:54:53 -04:00
rocky
d413ebe0e1 Split out semantic actions per version ...
In version 3.5..3.8 there are quite hefty changes.
2019-04-14 19:25:56 -04:00
rocky
f96522e18e Add 3.8 try else 2019-04-14 19:01:33 -04:00
rocky
50d50af2ee Doc typo 2019-04-14 07:45:06 -04:00
rocky
4dc2897cdc One last new item update 2019-04-14 07:10:30 -04:00
rocky
47fb80494d Get ready for release 3.3.0 2019-04-14 07:03:07 -04:00
rocky
830e19e3e6 Get ready for release 3.3.0 2019-04-14 06:59:49 -04:00
rocky
c5cfd36a61 Start 3.8 async for/else 2019-04-14 06:54:08 -04:00
rocky
9b550b9dda PEP E225 with a nod to Deepcommit 2019-04-14 06:11:16 -04:00
rocky
400943bb6a 3.8 async for/with...
More is needed though.
2019-04-13 22:22:37 -04:00
rocky
f89ba40147 Adjust while True grammar rule 2019-04-13 20:46:13 -04:00
rocky
32c611a315 Adjust 3.8 while-stmt rules 2019-04-13 20:35:26 -04:00
rocky
5d91e96358 3.6-3.8 "async for" handling...
And add an if_stmt rule for 3.8. My want to extend it back to
other versions.
2019-04-13 18:31:40 -04:00
rocky
44edf1d7db 3.8 try/except handling - again (and more to come) 2019-04-12 03:20:13 -04:00
rocky
a891aa0706 More 3.8 try blocks 2019-04-11 16:42:28 -04:00
rocky
5e1340a2fc 3.8 exception handling 2019-04-11 12:09:24 -04:00
rocky
94eff282f8 3.8 try/except 2019-04-11 07:44:32 -04:00
rocky
7f65a8a6dd 3.8 SETUP_EXCEPT removal workaround; reinstate option -c | --compile 2019-04-11 07:19:35 -04:00
rocky
cfe7feed4d Fix 3.8 pytests 2019-04-10 22:58:15 -04:00
rocky
b3a20896b2 Remove dup pypy test 2019-04-10 12:35:26 -04:00
R. Bernstein
1425476018 Merge pull request #222 from rocky/python-3.8
Python 3.8
2019-04-10 12:00:03 -04:00
rocky
59c77f103d More self-checking run tests 2019-04-10 11:49:27 -04:00
rocky
726045a05e Basic 3.8+ "for" loop handling...
More Makefile mangling
2019-04-10 11:26:58 -04:00
rocky
49e354375e More run tests 2019-04-10 11:05:46 -04:00
rocky
f3d86e0708 Bang on Python 3.8 2019-04-10 07:22:43 -04:00
rocky
820283827f 3.8 "for" block ...
pysource: Tag older semantics for blocks with "expr" and "for_block"
2019-04-10 06:00:16 -04:00
rocky
8b65cc7275 Small changes - bump required xdis version 2019-04-09 21:45:28 -04:00
rocky
1e47f47527 Allow for newer xdis 2019-04-05 16:30:28 -04:00
rocky
19a95be3ef WIP - more 3.8 grammar stuff 2019-03-30 00:27:48 -04:00
rocky
5a6550b353 Administrivia: require xdis 3.9.1 or greater 2019-03-28 20:56:49 -04:00
rocky
82fb9426af [WIP] - move forward a tad on Python 3.8 2019-03-28 12:10:08 -04:00
rocky
98b91db8e6 Another 3.6->3.7 typo (in comment this time) 2019-03-28 11:22:07 -04:00
rocky
ce3f815b08 opcode import typo 2019-03-28 11:16:06 -04:00
rocky
c447b9cfa9 Note use of releases 2019-03-26 12:41:12 -04:00
127 changed files with 1889 additions and 987 deletions

View File

@@ -40,6 +40,9 @@ check-3.0 check-3.1 check-3.2 check-3.6:
check-3.7: pytest
$(MAKE) -C test check
check-3.8:
$(MAKE) -C test check
#:PyPy 2.6.1 PyPy 5.0.1, or PyPy 5.8.0-beta0
# Skip for now
2.6 5.0 5.3 5.6 5.8:

21
NEWS.md
View File

@@ -1,3 +1,24 @@
3.3.1 2019-04-19 Good Friday
==========================
Lots of decomplation bugs, especially in the 3.x series fixed. Don't worry though, many more remain.
* Add annotation return values in 3.6+
* Fix 3.6+ lambda parameter handling decompilation
* Fix 3.7+ chained comparision decompilation
* split out semantic-action customization into more separate files
* Add 3.8 try/else
* Fix 2.7 generator decompilation
* Fix some parser failures fixes in 3.4+ using test_pyenvlib
* Add more run tests
3.3.0 2019-43-14 Holy Week
==========================
* First cut at Python 3.8 (many bugs remain)
* Reinstate -c | --compile (compile before disassembly) option
* The usual smattering of bug and doc fixes
3.2.6 2019-03-23 Mueller Report
=======================================

View File

@@ -12,7 +12,7 @@ Introduction
*uncompyle6* translates Python bytecode back into equivalent Python
source code. It accepts bytecodes from Python version 1.3 to version
3.7, spanning over 22 years of Python releases. We include Dropbox's
3.8, spanning over 24 years of Python releases. We include Dropbox's
Python 2.5 bytecode and some PyPy bytecode.
Why this?
@@ -76,7 +76,7 @@ Requirements
The code here can be run on Python versions 2.6 or later, PyPy 3-2.4,
or PyPy-5.0.1. Python versions 2.4-2.7 are supported in the
python-2.4 branch. The bytecode files it can read have been tested on
Python bytecodes from versions 1.4, 2.1-2.7, and 3.0-3.6 and the
Python bytecodes from versions 1.4, 2.1-2.7, and 3.0-3.8 and the
above-mentioned PyPy versions.
Installation

View File

@@ -23,7 +23,7 @@
# Things that change more often go here.
copyright = """
Copyright (C) 2015-2018 Rocky Bernstein <rb@dustyfeet.com>.
Copyright (C) 2015-2019 Rocky Bernstein <rb@dustyfeet.com>.
"""
classifiers = ['Development Status :: 5 - Production/Stable',
@@ -43,6 +43,7 @@ classifiers = ['Development Status :: 5 - Production/Stable',
'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',
]
@@ -57,7 +58,7 @@ entry_points = {
]}
ftp_url = None
install_requires = ['spark-parser >= 1.8.7, < 1.9.0',
'xdis >= 3.9.0, < 3.10.0']
'xdis >= 4.0.0, < 4.1.0']
license = 'GPL3'
mailing_list = 'python-debugger@googlegroups.com'

View File

@@ -58,7 +58,8 @@
$ git tag release-python-2.4-$VERSION
$ . ./admin-tools/make-dist-newer.sh
$ git tag release-$VERSION
Goto https://github.com/rocky/python-uncompyle6/releases
# Upload single package and look at Rst Formating

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.2.6 3.6.8 3.7.2 2.6.9 3.3.7 2.7.15 3.2.6 3.1.5 3.4.8'
export PYVERSIONS='3.6.8 3.7.2 2.6.9 3.3.7 2.7.15 3.2.6 3.1.5 3.4.8'

View File

@@ -47,7 +47,7 @@ class PrintFake():
out = out[:-self.pending_newlines]
self.f.write(out)
def println(self, *data):
if data and not(len(data) == 1 and data[0] ==''):
if data and not(len(data) == 1 and data[0] == ''):
self.write(*data)
self.pending_newlines = max(self.pending_newlines, 1)
return

View File

@@ -18,15 +18,19 @@ def test_grammar():
right_recursive, dup_rhs) = p.check_sets()
# We have custom rules that create the below
expect_lhs = set(['pos_arg', 'get_iter', 'attribute'])
expect_lhs = set(['pos_arg', 'attribute'])
if PYTHON_VERSION < 3.8:
expect_lhs.add('get_iter')
unused_rhs = set(['list', 'mkfunc',
'mklambda',
'unpack',])
expect_right_recursive = set([('designList',
('store', 'DUP_TOP', 'designList'))])
if PYTHON_VERSION != 3.7:
if PYTHON_VERSION < 3.7:
unused_rhs.add('call')
if PYTHON_VERSION > 2.6:
@@ -61,7 +65,11 @@ def test_grammar():
expect_lhs.add('kwarg')
assert expect_lhs == set(lhs)
assert unused_rhs == set(rhs)
# FIXME
if PYTHON_VERSION != 3.8:
assert unused_rhs == set(rhs)
assert expect_right_recursive == right_recursive
expect_dup_rhs = frozenset([('COME_FROM',), ('CONTINUE',), ('JUMP_ABSOLUTE',),

View File

@@ -80,7 +80,7 @@ def are_instructions_equal(i1, i2):
:return: True if the two instructions are approximately equal, otherwise False.
"""
result = (1==1
result = (1 == 1
and i1.opname == i2.opname
and i1.opcode == i2.opcode
and i1.arg == i2.arg

View File

@@ -4,8 +4,8 @@ import sys
"""Setup script for the 'uncompyle6' distribution."""
SYS_VERSION = sys.version_info[0:2]
if not ((2, 6) <= SYS_VERSION <= (3, 7)):
mess = "Python Release 2.6 .. 3.7 are supported in this code branch."
if not ((2, 6) <= SYS_VERSION <= (3, 8)):
mess = "Python Release 2.6 .. 3.8 are supported in this code branch."
if ((2, 4) <= SYS_VERSION <= (2, 7)):
mess += ("\nFor your Python, version %s, use the python-2.4 code/branch." %
sys.version[0:3])

View File

@@ -33,43 +33,48 @@ check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-na
#: Run working tests from Python 3.0
check-3.0: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.0 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.0-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.0 --weak-verify $(COMPILE)
#: Run working tests from Python 3.1
check-3.1: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.1 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.1-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.1 --weak-verify $(COMPILE)
#: Run working tests from Python 3.2
check-3.2: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.2 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.2-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.2 --weak-verify $(COMPILE)
#: Run working tests from Python 3.3
check-3.3: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.3 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.3-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.3 --weak-verify $(COMPILE)
#: Run working tests from Python 3.4
check-3.4: check-bytecode check-3.4-ok check-2.7-ok
$(PYTHON) test_pythonlib.py --bytecode-3.4 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.4-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.4 --weak-verify $(COMPILE)
#: Run working tests from Python 3.5
check-3.5: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.5 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.5-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.5 --weak-verify $(COMPILE)
#: Run working tests from Python 3.6
check-3.6: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.6 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.6-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.6 --weak-verify $(COMPILE)
#: Run working tests from Python 3.7
check-3.7: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.7 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.7-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.7 --weak-verify $(COMPILE)
#: Run working tests from Python 3.8
check-3.8: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.8 --weak-verify $(COMPILE)
# FIXME
#: this is called when running under pypy3.5-5.8.0 or pypy2-5.6.0
@@ -92,7 +97,8 @@ check-bytecode-2:
check-bytecode-3:
$(PYTHON) test_pythonlib.py --bytecode-3.0 \
--bytecode-3.1 --bytecode-3.2 --bytecode-3.3 \
--bytecode-3.4 --bytecode-3.5 --bytecode-3.6 --bytecode-3.7 \
--bytecode-3.4 --bytecode-3.5 --bytecode-3.6 \
--bytecode-3.7 --bytecode-3.8 \
--bytecode-pypy3.2
#: Check deparsing on selected bytecode 3.x
@@ -217,53 +223,58 @@ grammar-coverage-3.6:
#: Check deparsing Python 2.6
check-bytecode-2.6:
$(PYTHON) test_pythonlib.py --bytecode-2.6 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-2.6-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-2.6 --weak-verify
#: Check deparsing Python 2.7
check-bytecode-2.7:
$(PYTHON) test_pythonlib.py --bytecode-2.7 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-2.7-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-2.7 --weak-verify
#: Check deparsing Python 3.0
check-bytecode-3.0:
$(PYTHON) test_pythonlib.py --bytecode-3.0 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-3.0-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.0 --weak-verify
#: Check deparsing Python 3.1
check-bytecode-3.1:
$(PYTHON) test_pythonlib.py --bytecode-3.1 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-3.1-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.1 --weak-verify
#: Check deparsing Python 3.2
check-bytecode-3.2:
$(PYTHON) test_pythonlib.py --bytecode-3.2 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-3.2-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.2 --weak-verify
#: Check deparsing Python 3.3
check-bytecode-3.3:
$(PYTHON) test_pythonlib.py --bytecode-3.3 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-3.3-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.3 --weak-verify
#: Check deparsing Python 3.4
check-bytecode-3.4:
$(PYTHON) test_pythonlib.py --bytecode-3.4 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-3.4-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.4 --weak-verify
#: Check deparsing Python 3.5
check-bytecode-3.5:
$(PYTHON) test_pythonlib.py --bytecode-3.5 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-3.5-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.5 --weak-verify
#: Check deparsing Python 3.6
check-bytecode-3.6:
$(PYTHON) test_pythonlib.py --bytecode-3.6 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-3.6-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.6 --weak-verify
#: Check deparsing Python 3.7
check-bytecode-3.7:
$(PYTHON) test_pythonlib.py --bytecode-3.7 --weak-verify
#: Check deparsing Python 3.8
check-bytecode-3.8:
$(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.8 --weak-verify
#: short tests for bytecodes only for this version of Python
check-native-short:
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --weak-verify $(COMPILE)

View File

@@ -4,12 +4,19 @@
import os, sys, py_compile
assert len(sys.argv) >= 2
version = sys.version[0:3]
for path in sys.argv[1:]:
if sys.argv[1] == '--run':
suffix = '_run'
py_source = sys.argv[2:]
else:
suffix = ''
py_source = sys.argv[1:]
for path in py_source:
short = os.path.basename(path)
if hasattr(sys, 'pypy_version_info'):
cfile = "bytecode_pypy%s/%s" % (version, short) + 'c'
cfile = "bytecode_pypy%s%s/%s" % (version, suffix, short) + 'c'
else:
cfile = "bytecode_%s/%s" % (version, short) + 'c'
cfile = "bytecode_%s%s/%s" % (version, suffix, short) + 'c'
print("byte-compiling %s to %s" % (path, cfile))
py_compile.compile(path, cfile)
if isinstance(version, str) or version >= (2, 6, 0):

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -18,7 +18,7 @@ a *= b; print a # a = a*b = 2
a -= a; print a # a = a-a = 0
a += 7*3; print a # == 21
l= [1,2,3]
l = [1,2,3]
l[1] *= 3; print l[1]; # 6
l[1][2][3] = 7
l[1][2][3] *= 3;

View File

@@ -76,7 +76,7 @@ def get_srcdir():
src_dir = get_srcdir()
os.chdir(src_dir)
files=[
files = [
'if',
'ifelse',
# 'keyword',

View File

@@ -1,7 +1,7 @@
# We have to do contortions here because
# lambda's have to be more or less on a line
f = lambda x: 1 if x<2 else 3
f = lambda x: 1 if x < 2 else 3
assert f(3) == 3
assert f(1) == 1

View File

@@ -3,7 +3,7 @@
# while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK COME_FROM
# while1stmt ::= SETUP_LOOP l_stmts_opt CONTINUE COME_FROM
# which is included in later code generation
ms=0
if ms==1:
ms = 0
if ms == 1:
while 1:
pass

View File

@@ -1,12 +1,18 @@
# Python 2.7 sqlalchemy-1.013/sql/crud.py
def _extend_values_for_multiparams(compiler, stmt, c):
c(
[
(
(compiler() if compiler()
else compiler())
if c in stmt else compiler(),
)
]
for i in enumerate(stmt)
# Adapted from Python 2.7 sqlalchemy-1.013/sql/crud.py
# Bug was in handling generator comprehension
# In 2.6, 2.7 JUMP_ABSOLUTEs rather than JUMP_BACKs are generated
# RUNNABLE!
def extend(stmt, a, c, c1, c2, c3):
return c(
([ (5 if c1 else c2)
if a else c3
] for i in enumerate(stmt))
)
def foo(gen):
return list(gen)
assert extend([0], 0, foo, True, 'c2', 'c3') == [['c3']]
assert extend([0, 1], 1, foo, False, 'c2', 'c3') == [['c2'], ['c2']]
assert extend([0, 1], False, foo, False, 'c2', 'c3') == [['c3'], ['c3']]

View File

@@ -1,8 +1,11 @@
# In Python 3.3+ this uses grammar rule
# compare_chained2 ::= expr COMPARE_OP RETURN_VALUE
# In Python 3.6 uses this uses grammar rule
# compare_chained2 ::= expr COMPARE_OP come_froms JUMP_FORWARD
# Seen in Python 3.3 ipaddress.py
# RUNNABLE!
def _is_valid_netmask(netmask):
return 0 <= netmask <= 10
@@ -10,4 +13,4 @@ def _is_valid_netmask(netmask):
# detections
# See in 2.6.9 quopri.py ishex():
'0' <= __file__ <= '9' or 'a' <= __file__ <= 'f' or 'A' <= __file__ <= 'F'
assert not '0' <= __file__ <= '9' or 'a' <= __file__ <= 'f' or 'A' <= __file__ <= 'F'

View File

@@ -1,6 +1,12 @@
# From Python 3.3.6 hmac.py
# Problem was getting wrong placement of positional args
# Problem was getting wrong placement of positional args.
# In 3.6+ paramter handling changes
# RUNNABLE!
digest_cons = lambda d=b'': 5
# Handle single kwarg
lambda *, d=0: None
x = lambda *, d=0: d
assert x(d=1) == 1
assert x() == 0

View File

@@ -1,28 +1,32 @@
# From Python 3.4 asynchat.py
# Tests presence or absense of
# SETUP_LOOP testexpr return_stmts POP_BLOCK COME_FROM_LOOP
# Note: that there is no JUMP_BACK because of the return_stmts.
def initiate_send(self, num_sent, first):
while self.producer_fifo and self.connected:
def initiate_send(a, b, c, num_sent):
while a and b:
try:
5
except OSError:
return
1 / (b - 1)
except ZeroDivisionError:
return 1
if num_sent:
if first:
self.producer_fifo = '6'
else:
del self.producer_fifo[0]
return
c = 2
return c
# FIXME: this causes a parse error:
# def initiate_send(self):
# while self.producer_fifo and self.connected:
# try:
# 6
# except OSError:
# return
def initiate_send2(a, b):
while a and b:
try:
1 / (b - 1)
except ZeroDivisionError:
return 1
# return
return 2
assert initiate_send(1, 1, 2, False) == 1
assert initiate_send(1, 2, 3, False) == 3
assert initiate_send(1, 2, 3, True) == 2
assert initiate_send2(1, 1) == 1
assert initiate_send2(1, 2) == 2

View File

@@ -1,3 +1,4 @@
# Self-checking test.
# Python 3 bug in not detecting the end bounds of if elif.
def testit(b):
if b == 1:

View File

@@ -2,7 +2,7 @@
#Not detecting 2nd return is outside of
# if/then. Fix was to ensure COME_FROM
def return_return_bug(foo):
if foo =='say_hello':
if foo == 'say_hello':
return "hello"
return "world"

View File

@@ -1,4 +1,5 @@
# Self-checking 3.6+ string interpolation tests
# Self-checking test.
# String interpolation tests
var1 = 'x'
var2 = 'y'

View File

@@ -0,0 +1,19 @@
# From 3.6 _collections.abc.py
# Bug was try/execpt parsing detection since 3.6 removes
# a JUMP_FORWARD from earlier 3.xs.
# This could also get confused with try/else.
# RUNNABLE!
def iter(self):
i = 0
try:
while True:
v = self[i]
yield v
i += 1
except IndexError:
return
A = [10, 20, 30]
assert list(iter(A)) == A

View File

@@ -1,8 +1,17 @@
# Self-checking test.
# Tests:
# forstmt ::= SETUP_LOOP expr _for store
# for_block POP_BLOCK COME_FROM
for a in [1]:
c = 2
# for ::= SETUP_LOOP expr for_iter store
# for_block POP_BLOCK COME_FROM
# In 3.8+
# for ::= expr for_iter store
# for_block POP_BLOCK COME_FROM
for a in range(2):
c = 2
c = 0
for a in [1]:
c += a
assert c == 1, c
for a in range(3):
c += a
assert c == 4, c

View File

@@ -1,12 +1,26 @@
# Self-checking test.
# Mixed boolean expresions
b = True
assert b, 'b = True'
c = False
assert not c, 'c = False'
d = True
a = b and c or d
assert a, 'b and c or d'
a = (b or c) and d
assert a, '(b or c) and d'
a = b or c or d
assert a, 'b or c or d'
a = b and c and d
assert not a, 'b and c and d'
a = b or c and d
assert a
a = b and (c or d)
assert a
a = b and c or d
assert a
a = (b or c and d) and b
assert a
a = (b or c and d or a) and b
assert a

View File

@@ -1,8 +1,15 @@
# Self-checking test.
# Tests of Python slice operators
ary = [1,2,3,4,5]
# Forces BUILD_SLICE 2 on 3.x
ary[:2]
ary[2:]
a = ary[:2]
assert a == [1, 2]
a = ary[2:]
assert a == [3, 4, 5]
# Forces BUILD_SLICE 3
ary[1:4:2]
a = ary[1:4:2]
assert a == [2, 4]

View File

@@ -20,7 +20,7 @@ a *= b; # print a # a = a*b = 2
a -= a; # print a # a = a-a = 0
a += 7*3; # print a # == 21
l= [1,2,3]
l = [1,2,3]
l[1] *= 3; # print l[1]; # 6
l[1][2][3] = 7
l[1][2][3] *= 3;

View File

@@ -28,7 +28,7 @@ def foo():
z = {}
def a():
b =1
b = 1
global z
del z
def b(y):

View File

@@ -36,7 +36,7 @@ python_versions = [v for v in magics.python_versions if
# FIXME: we should remove Python versions that we don't support.
# These include Jython, and Python bytecode changes pre release.
TEST_VERSIONS=(
TEST_VERSIONS = (
'pypy-2.4.0', 'pypy-2.6.1',
'pypy-5.0.1', 'pypy-5.3.1', 'pypy3.5-5.7.1-beta',
'native') + tuple(python_versions)

View File

@@ -81,7 +81,7 @@ for vers in (2.7, 3.4, 3.5, 3.6):
for vers in (1.3, 1.4, 1.5,
2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7,
3.0, 3.1, 3.2, 3.3,
3.4, 3.5, 3.6, 3.7, 'pypy3.2', 'pypy2.7'):
3.4, 3.5, 3.6, 3.7, 3.8, 'pypy3.2', 'pypy2.7'):
bytecode = "bytecode_%s" % vers
key = "bytecode-%s" % vers
test_options[key] = (bytecode, PYC, bytecode, vers)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# Mode: -*- python -*-
#
# Copyright (c) 2015-2017 by Rocky Bernstein
# Copyright (c) 2015-2017, 2019 by Rocky Bernstein
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
#
from __future__ import print_function
@@ -30,7 +30,8 @@ Options:
-> /tmp/bla/fasel.pyc_dis, /tmp/bar/foo.pyc_dis
uncompyle6 -o /tmp /usr/lib/python1.5
-> /tmp/smtplib.pyc_dis ... /tmp/lib-tk/FixTk.pyc_dis
-c <file> attempts a disassembly after compiling <file>
--compile | -c <python-file>
attempts a decompilation after compiling <python-file>
-d print timestamps
-p <integer> use <integer> number of processes
-r recurse directories looking for .pyc and .pyo files
@@ -43,10 +44,10 @@ Options:
--help show this message
Debugging Options:
--asm -a include byte-code (disables --verify)
--grammar -g show matching grammar
--tree -t include syntax tree (disables --verify)
--tree++ add template rules to --tree when possible
--asm | -a include byte-code (disables --verify)
--grammar | -g show matching grammar
--tree | -t include syntax tree (disables --verify)
--tree++ add template rules to --tree when possible
Extensions of generated files:
'.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify)
@@ -61,10 +62,7 @@ from uncompyle6.main import main, status_msg
from uncompyle6.version import VERSION
def usage():
print("""usage:
%s [--verify | --weak-verify ] [--asm] [--tree[+]] [--grammar] [-o <path>] FILE|DIR...
%s [--help | -h | --version | -V]
""" % (program, program))
print(__doc__)
sys.exit(1)
@@ -72,9 +70,9 @@ def main_bin():
if not (sys.version_info[0:2] in ((2, 6), (2, 7), (3, 0),
(3, 1), (3, 2), (3, 3),
(3, 4), (3, 5), (3, 6),
(3, 7)
(3, 7), (3, 8)
)):
print('Error: %s requires Python 2.6-3.7' % program,
print('Error: %s requires Python 2.6-3.8' % program,
file=sys.stderr)
sys.exit(-1)
@@ -82,13 +80,13 @@ def main_bin():
numproc = 0
outfile = '-'
out_base = None
codes = []
source_paths = []
timestamp = False
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
try:
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
'help asm grammar linemaps recurse '
opts, pyc_paths = getopt.getopt(sys.argv[1:], 'hac:gtdrVo:p:',
'help asm compile= grammar linemaps recurse '
'timestamp tree tree+ '
'fragments verify verify-run version '
'weak-verify '
@@ -130,8 +128,8 @@ def main_bin():
outfile = val
elif opt in ('--timestamp', '-d'):
timestamp = True
elif opt == '-c':
codes.append(val)
elif opt in ('--compile', '-c'):
source_paths.append(val)
elif opt == '-p':
numproc = int(val)
elif opt in ('--recurse', '-r'):
@@ -143,33 +141,33 @@ def main_bin():
# expand directory if specified
if recurse_dirs:
expanded_files = []
for f in files:
for f in pyc_paths:
if os.path.isdir(f):
for root, _, dir_files in os.walk(f):
for df in dir_files:
if df.endswith('.pyc') or df.endswith('.pyo'):
expanded_files.append(os.path.join(root, df))
files = expanded_files
pyc_paths = expanded_files
# argl, commonprefix works on strings, not on path parts,
# thus we must handle the case with files in 'some/classes'
# and 'some/cmds'
src_base = os.path.commonprefix(files)
src_base = os.path.commonprefix(pyc_paths)
if src_base[-1:] != os.sep:
src_base = os.path.dirname(src_base)
if src_base:
sb_len = len( os.path.join(src_base, '') )
files = [f[sb_len:] for f in files]
pyc_paths = [f[sb_len:] for f in pyc_paths]
if not files:
print("No files given", file=sys.stderr)
if not pyc_paths and not source_paths:
print("No input files given to decompile", file=sys.stderr)
usage()
if outfile == '-':
outfile = None # use stdout
elif outfile and os.path.isdir(outfile):
out_base = outfile; outfile = None
elif outfile and len(files) > 1:
elif outfile and len(pyc_paths) > 1:
out_base = outfile; outfile = None
if timestamp:
@@ -177,10 +175,10 @@ def main_bin():
if numproc <= 1:
try:
result = main(src_base, out_base, files, None, outfile,
result = main(src_base, out_base, pyc_paths, source_paths, outfile,
**options)
result = list(result) + [options.get('do_verify', None)]
if len(files) > 1:
if len(pyc_paths) > 1:
mess = status_msg(do_verify, *result)
print('# ' + mess)
pass
@@ -196,8 +194,8 @@ def main_bin():
except ImportError:
from queue import Empty
fqueue = Queue(len(files)+numproc)
for f in files:
fqueue = Queue(len(pyc_paths)+numproc)
for f in pyc_paths:
fqueue.put(f)
for i in range(numproc):
fqueue.put(None)

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2018 Rocky Bernstein <rocky@gnu.org>
# Copyright (C) 2018-2019 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
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import datetime, os, subprocess, sys, tempfile
import datetime, py_compile, os, subprocess, sys, tempfile
from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION
from xdis.code import iscode
@@ -119,6 +119,22 @@ def decompile(
# deparsing failed
raise pysource.SourceWalkerError(str(e))
def compile_file(source_path):
if source_path.endswith('.py'):
basename = source_path[:-3]
else:
basename = source_path
if hasattr(sys, 'pypy_version_info'):
bytecode_path = "%s-pypy%s.pyc" % (basename, PYTHON_VERSION)
else:
bytecode_path = "%s-%s.pyc" % (basename, PYTHON_VERSION)
print("compiling %s to %s" % (source_path, bytecode_path))
py_compile.compile(source_path, bytecode_path, 'exec')
return bytecode_path
def decompile_file(filename, outstream=None, showasm=None, showast=False,
showgrammar=False, mapstream=None, do_fragments=False):
"""
@@ -150,7 +166,7 @@ def decompile_file(filename, outstream=None, showasm=None, showast=False,
# FIXME: combine into an options parameter
def main(in_base, out_base, files, codes, outfile=None,
def main(in_base, out_base, compiled_files, source_files, outfile=None,
showasm=None, showast=False, do_verify=False,
showgrammar=False, raise_on_error=False,
do_linemaps=False, do_fragments=False):
@@ -160,8 +176,6 @@ def main(in_base, out_base, files, codes, outfile=None,
files list of filenames to be uncompyled (relative to in_base)
outfile write output to this filename (overwrites out_base)
Note: `codes` is not use. Historical compatability?
For redirecting output to
- <filename> outfile=<filename> (out_base is ignored)
- files below out_base out_base=...
@@ -171,7 +185,10 @@ def main(in_base, out_base, files, codes, outfile=None,
current_outfile = outfile
linemap_stream = None
for filename in files:
for source_path in source_files:
compiled_files.append(compile_file(source_path))
for filename in compiled_files:
infile = os.path.join(in_base, filename)
# print("XXX", infile)
if not os.path.exists(infile):

View File

@@ -747,6 +747,12 @@ def get_python_parser(
p = parse37.Python37Parser(debug_parser)
else:
p = parse37.Python37ParserSingle(debug_parser)
elif version == 3.8:
import uncompyle6.parsers.parse38 as parse38
if compile_mode == 'exec':
p = parse38.Python38Parser(debug_parser)
else:
p = parse38.Python38ParserSingle(debug_parser)
else:
if compile_mode == 'exec':
p = parse3.Python3Parser(debug_parser)

View File

@@ -467,7 +467,7 @@ class Python2Parser(PythonParser):
pass
self.add_unique_rules([
('mkfunc ::= %s load_closure LOAD_CONST %s' %
('expr '* token.attr, opname))], customize)
('expr ' * token.attr, opname))], customize)
if self.version >= 2.7:
if i > 0:

View File

@@ -267,6 +267,8 @@ class Python26Parser(Python2Parser):
# Note: preserve positions 0 2 and 4 for semantic actions
conditional_not ::= expr jmp_true expr jf_cf_pop expr COME_FROM
conditional ::= expr jmp_false expr jf_cf_pop expr come_from_opt
conditional ::= expr jmp_false expr ja_cf_pop expr
expr ::= conditional_not
and ::= expr JUMP_IF_FALSE POP_TOP expr JUMP_IF_FALSE POP_TOP

View File

@@ -41,7 +41,6 @@ class Python27Parser(Python2Parser):
comp_body ::= set_comp_body
comp_for ::= expr for_iter store comp_iter JUMP_BACK
comp_iter ::= comp_if
comp_iter ::= comp_body
dict_comp_body ::= expr expr MAP_ADD
@@ -123,6 +122,7 @@ class Python27Parser(Python2Parser):
conditional_true ::= expr JUMP_FORWARD expr COME_FROM
conditional ::= expr jmp_false expr JUMP_FORWARD expr COME_FROM
conditional ::= expr jmp_false expr JUMP_ABSOLUTE expr
"""
def p_stmt27(self, args):

View File

@@ -98,8 +98,9 @@ class Python3Parser(PythonParser):
sstmt ::= return RETURN_LAST
return_if_stmts ::= return_if_stmt come_from_opt
return_if_stmts ::= _stmts return_if_stmt
return_if_stmt ::= ret_expr RETURN_END_IF
return_if_stmts ::= _stmts return_if_stmt _come_froms
return_if_stmt ::= ret_expr RETURN_END_IF
returns ::= _stmts return_if_stmt
stmt ::= break
break ::= BREAK_LOOP
@@ -874,12 +875,12 @@ class Python3Parser(PythonParser):
j = 2
if is_pypy or (i >= j and tokens[i-j] == 'LOAD_LAMBDA'):
rule_pat = ('mklambda ::= %sload_closure LOAD_LAMBDA %%s%s' %
('pos_arg '* args_pos, opname))
('pos_arg ' * args_pos, opname))
self.add_make_function_rule(rule_pat, opname, token.attr, customize)
if has_get_iter_call_function1:
rule_pat = ("generator_exp ::= %sload_closure load_genexpr %%s%s expr "
"GET_ITER CALL_FUNCTION_1" % ('pos_arg '* args_pos, opname))
"GET_ITER CALL_FUNCTION_1" % ('pos_arg ' * args_pos, opname))
self.add_make_function_rule(rule_pat, opname, token.attr, customize)
if has_get_iter_call_function1:
@@ -899,7 +900,7 @@ class Python3Parser(PythonParser):
if (is_pypy or (i >= j and tokens[i-j] == 'LOAD_DICTCOMP')):
self.add_unique_rule('dict_comp ::= %sload_closure LOAD_DICTCOMP %s '
'expr GET_ITER CALL_FUNCTION_1' %
('pos_arg '* args_pos, opname),
('pos_arg ' * args_pos, opname),
opname, token.attr, customize)
if args_kw > 0:
@@ -952,19 +953,25 @@ class Python3Parser(PythonParser):
opname))
self.add_unique_rule(rule, opname, token.attr, customize)
else:
rule = ('mklambda ::= %sLOAD_LAMBDA LOAD_CONST %s' %
(('expr ' * stack_count), opname))
self.add_unique_rule(rule, opname, token.attr, customize)
rule = ('mkfunc ::= %s%s%s%s' %
('expr ' * stack_count,
'load_closure ' * closure,
'LOAD_CONST ' * 2,
opname))
('expr ' * stack_count,
'load_closure ' * closure,
'LOAD_CONST ' * 2,
opname))
self.add_unique_rule(rule, opname, token.attr, customize)
if has_get_iter_call_function1:
rule_pat = ("generator_exp ::= %sload_genexpr %%s%s expr "
"GET_ITER CALL_FUNCTION_1" % ('pos_arg '* args_pos, opname))
"GET_ITER CALL_FUNCTION_1" % ('pos_arg ' * args_pos, opname))
self.add_make_function_rule(rule_pat, opname, token.attr, customize)
rule_pat = ("generator_exp ::= %sload_closure load_genexpr %%s%s expr "
"GET_ITER CALL_FUNCTION_1" % ('pos_arg '* args_pos, opname))
"GET_ITER CALL_FUNCTION_1" % ('pos_arg ' * args_pos, opname))
self.add_make_function_rule(rule_pat, opname, token.attr, customize)
if is_pypy or (i >= 2 and tokens[i-2] == 'LOAD_LISTCOMP'):
if self.version >= 3.6:
@@ -980,8 +987,8 @@ class Python3Parser(PythonParser):
if is_pypy or (i >= 2 and tokens[i-2] == 'LOAD_LAMBDA'):
rule_pat = ('mklambda ::= %s%sLOAD_LAMBDA %%s%s' %
(('pos_arg '* args_pos),
('kwarg '* args_kw),
(('pos_arg ' * args_pos),
('kwarg ' * args_kw),
opname))
self.add_make_function_rule(rule_pat, opname, token.attr, customize)
continue
@@ -998,7 +1005,7 @@ class Python3Parser(PythonParser):
if has_get_iter_call_function1:
rule_pat = ("generator_exp ::= %sload_genexpr %%s%s expr "
"GET_ITER CALL_FUNCTION_1" % ('pos_arg '* args_pos, opname))
"GET_ITER CALL_FUNCTION_1" % ('pos_arg ' * args_pos, opname))
self.add_make_function_rule(rule_pat, opname, token.attr, customize)
if is_pypy or (i >= j and tokens[i-j] == 'LOAD_LISTCOMP'):
@@ -1014,8 +1021,8 @@ class Python3Parser(PythonParser):
# FIXME: Fold test into add_make_function_rule
if is_pypy or (i >= j and tokens[i-j] == 'LOAD_LAMBDA'):
rule_pat = ('mklambda ::= %s%sLOAD_LAMBDA %%s%s' %
(('pos_arg '* args_pos),
('kwarg '* args_kw),
(('pos_arg ' * args_pos),
('kwarg ' * args_kw),
opname))
self.add_make_function_rule(rule_pat, opname, token.attr, customize)
@@ -1148,7 +1155,9 @@ class Python3Parser(PythonParser):
self.check_reduce['ifelsestmt'] = 'AST'
self.check_reduce['annotate_tuple'] = 'noAST'
self.check_reduce['kwarg'] = 'noAST'
self.check_reduce['try_except'] = 'AST'
if self.version < 3.6:
# 3.6+ can remove a JUMP_FORWARD which messes up our testing here
self.check_reduce['try_except'] = 'AST'
# FIXME: remove parser errors caused by the below
# self.check_reduce['while1elsestmt'] = 'noAST'
@@ -1190,7 +1199,9 @@ class Python3Parser(PythonParser):
last += 1
if last == n:
return False
return tokens[first].attr > tokens[last].offset
# 3.8+ Doesn't have SETUP_LOOP
return self.version < 3.8 and tokens[first].attr > tokens[last].offset
elif rule == ('try_except',
('SETUP_EXCEPT', 'suite_stmts_opt', 'POP_BLOCK',
'except_handler', 'opt_come_from_except')):

View File

@@ -17,15 +17,10 @@ spark grammar differences over Python 3.3 for Python 3.4
"""
from uncompyle6.parser import PythonParserSingle
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6.parsers.parse33 import Python33Parser
class Python34Parser(Python33Parser):
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
super(Python34Parser, self).__init__(debug_parser)
self.customized = {}
def p_misc34(self, args):
"""
expr ::= LOAD_ASSERT
@@ -34,6 +29,8 @@ class Python34Parser(Python33Parser):
# passtmt is needed for semantic actions to add "pass"
suite_stmts_opt ::= pass
whilestmt ::= SETUP_LOOP testexpr returns come_froms POP_BLOCK COME_FROM_LOOP
# Seems to be needed starting 3.4.4 or so
while1stmt ::= SETUP_LOOP l_stmts
COME_FROM JUMP_BACK POP_BLOCK COME_FROM_LOOP

Some files were not shown because too many files have changed in this diff Show More