You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 09:22:40 +08:00
Merge branch 'master' into python-2.4
This commit is contained in:
6
NEWS
6
NEWS
@@ -1,3 +1,9 @@
|
|||||||
|
uncompyle6 3.1.3 2018-04-16
|
||||||
|
|
||||||
|
- Add some Python 3.7 rules, such as for handling LOAD_METHOD (not complete)
|
||||||
|
- Fix some fragment bugs
|
||||||
|
- small doc changes
|
||||||
|
|
||||||
uncompyle6 3.1.2 2018-04-08 Eastern Orthodox Easter
|
uncompyle6 3.1.2 2018-04-08 Eastern Orthodox Easter
|
||||||
|
|
||||||
- Python 3.x subclass and call parsing fixes
|
- Python 3.x subclass and call parsing fixes
|
||||||
|
51
README.rst
51
README.rst
@@ -52,8 +52,17 @@ You get the idea. This code pulls all of these forks together and
|
|||||||
*moves forward*. There is some serious refactoring and cleanup in this
|
*moves forward*. There is some serious refactoring and cleanup in this
|
||||||
code base over those old forks.
|
code base over those old forks.
|
||||||
|
|
||||||
This project has the most complete support for Python 3.3 and above
|
This demonstrably does the best in decompiling Python across all
|
||||||
and the best all-around Python support.
|
Python versions. And even when there is another project that only
|
||||||
|
provides decompilation for subset of Python versions, we generally do
|
||||||
|
demonstrably better for those as well.
|
||||||
|
|
||||||
|
How can we tell? By taking Python bytecode that comes distributed with
|
||||||
|
that version of Python and decompiling these. Among htose that
|
||||||
|
successfully decompile, we can then make sure the resulting programs
|
||||||
|
are syntactically correct by running the Python interpreter for that
|
||||||
|
bytecode version. Finally, in cases where the program has a test for
|
||||||
|
itself, we can run the check on the decompiled code.
|
||||||
|
|
||||||
We are serious about testing, and use automated processes to find
|
We are serious about testing, and use automated processes to find
|
||||||
bugs. In the issue trackers for other decompilers, you will find a
|
bugs. In the issue trackers for other decompilers, you will find a
|
||||||
@@ -136,26 +145,26 @@ All of the Python decompilers that I have looked at have problems
|
|||||||
decompiling Python's control flow. In some cases we can detect an
|
decompiling Python's control flow. In some cases we can detect an
|
||||||
erroneous decompilation and report that.
|
erroneous decompilation and report that.
|
||||||
|
|
||||||
*Verification* is the process of decompiling bytecode, compiling with
|
In older versions of Python it was possible to verify bytecode by
|
||||||
a Python for that bytecode version, and then comparing the bytecode
|
decompiling bytecode, and then compiling using the Python interpreter
|
||||||
produced by the decompiled/compiled program. Some allowance is made
|
for that bytecode version. Having done this the bytecode produced
|
||||||
for inessential differences. But other semantically equivalent
|
could be compared with the original bytecode. However as Python's code
|
||||||
differences are not caught. For example ``1 and 0`` is decompiled to
|
generation got better, this is no longer feasible.
|
||||||
the equivalent ``0``; remnants of the first true evaluation (1) is
|
|
||||||
lost when Python compiles this. When Python next compiles ``0`` the
|
|
||||||
resulting code is simpler.
|
|
||||||
|
|
||||||
*Weak Verification*
|
There is a kind of *weak verification* that we use that doesn't check
|
||||||
on the other hand doesn't check bytecode for equivalence but does
|
bytecode for equivalence but does check to see if the resulting
|
||||||
check to see if the resulting decompiled source is a valid Python
|
decompiled source is a valid Python program by running the Python
|
||||||
program by running the Python interpreter. Because the Python language
|
interpreter. Because the Python language has changed so much, for best
|
||||||
has changed so much, for best results you should use the same Python
|
results you should use the same Python version in checking as was used
|
||||||
Version in checking as used in the bytecode.
|
in creating the bytecode.
|
||||||
|
|
||||||
Finally, we have automated running the standard Python tests after
|
There are however an interesting class of these programs that is
|
||||||
first compiling and decompiling the test program. Results here are a
|
readily available give stronger verification: those programs that
|
||||||
bit weak (if not better than most other Python decompilers). But over
|
when run check some computation, or even better themselves.
|
||||||
time this will probably get better.
|
|
||||||
|
And already Python has a set of programs like this: the test suite
|
||||||
|
for the standard library that comes with Python. We have some
|
||||||
|
code in `test/stdlib` to facilitate this kind of checking.
|
||||||
|
|
||||||
Python support is strongest in Python 2 for 2.7 and drops off as you
|
Python support is strongest in Python 2 for 2.7 and drops off as you
|
||||||
get further away from that. Support is also probably pretty good for
|
get further away from that. Support is also probably pretty good for
|
||||||
@@ -203,7 +212,7 @@ There is lots to do, so please dig in and help.
|
|||||||
See Also
|
See Also
|
||||||
--------
|
--------
|
||||||
|
|
||||||
* https://github.com/zrax/pycdc : supports all versions of Python and is written in C++. Support for later Python 3 versions is a bit lacking though.
|
* https://github.com/zrax/pycdc : supports all versions of Python and is written in C++. Support for Python 3 is a bit lacking though.
|
||||||
* https://code.google.com/archive/p/unpyc3/ : supports Python 3.2 only. The above projects use a different decompiling technique than what is used here.
|
* https://code.google.com/archive/p/unpyc3/ : supports Python 3.2 only. The above projects use a different decompiling technique than what is used here.
|
||||||
* https://github.com/figment/unpyc3/ : fork of above, but supports Python 3.3 only. Includes some fixes like supporting function annotations
|
* https://github.com/figment/unpyc3/ : fork of above, but supports Python 3.3 only. Includes some fixes like supporting function annotations
|
||||||
* The HISTORY_ file.
|
* The HISTORY_ file.
|
||||||
|
15
admin-tools/pycdc-runtests.sh
Executable file
15
admin-tools/pycdc-runtests.sh
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Use pycdc to run our test/bytecode* test suite
|
||||||
|
bs=${BASH_SOURCE[0]}
|
||||||
|
testdir=$(dirname $bs)/../test
|
||||||
|
fulldir=$(readlink -f $testdir)
|
||||||
|
cd $fulldir
|
||||||
|
for dir in bytecode_* ; do
|
||||||
|
echo ========= $dir ================
|
||||||
|
cd $fulldir/$dir
|
||||||
|
for file in *.pyc; do
|
||||||
|
if ! pycdc $file > /dev/null ; then
|
||||||
|
echo ----- $dir/$file ------
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
@@ -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.5.5 3.6.4 2.6.9 3.3.7 2.7.14 3.2.6 3.1.5 3.4.8'
|
export PYVERSIONS='3.5.5 3.6.5 2.6.9 3.3.7 2.7.14 3.2.6 3.1.5 3.4.8'
|
||||||
|
32
admin-tools/uncompyle2-runtests.sh
Executable file
32
admin-tools/uncompyle2-runtests.sh
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Use pycdc to run our test/bytecode_2.7* test suite
|
||||||
|
bs=${BASH_SOURCE[0]}
|
||||||
|
topdir=$(dirname $bs)/..
|
||||||
|
(cd $topdir && pyenv local 2.7.14)
|
||||||
|
testdir=$topdir/test
|
||||||
|
fulldir=$(readlink -f $testdir)
|
||||||
|
cd $fulldir
|
||||||
|
|
||||||
|
for bytecode in bytecode_2.7/*.pyc ; do
|
||||||
|
echo $bytecode
|
||||||
|
uncompyle2 $bytecode > /dev/null
|
||||||
|
echo ================ $bytecode rc: $? ==============
|
||||||
|
done
|
||||||
|
|
||||||
|
tmpdir=/tmp/test-2.7
|
||||||
|
( cd bytecode_2.7_run &&
|
||||||
|
mkdir $tmpdir || true
|
||||||
|
for bytecode in *.pyc ; do
|
||||||
|
shortname=$(basename $bytecode .pyc)
|
||||||
|
echo $bytecode
|
||||||
|
py_file=${tmpdir}/${shortname}.py
|
||||||
|
typeset -i rc=0
|
||||||
|
uncompyle2 $bytecode > $py_file
|
||||||
|
rc=$?
|
||||||
|
if (( rc == 0 )); then
|
||||||
|
python $py_file
|
||||||
|
rc=$?
|
||||||
|
fi
|
||||||
|
echo ================ $bytecode rc: $rc ==============
|
||||||
|
done
|
||||||
|
)
|
@@ -26,6 +26,9 @@ def test_grammar():
|
|||||||
expect_right_recursive = set([('designList',
|
expect_right_recursive = set([('designList',
|
||||||
('store', 'DUP_TOP', 'designList'))])
|
('store', 'DUP_TOP', 'designList'))])
|
||||||
|
|
||||||
|
if PYTHON_VERSION != 3.7:
|
||||||
|
unused_rhs.add('call')
|
||||||
|
|
||||||
if PYTHON_VERSION > 2.6:
|
if PYTHON_VERSION > 2.6:
|
||||||
expect_lhs.add('kvlist')
|
expect_lhs.add('kvlist')
|
||||||
expect_lhs.add('kv3')
|
expect_lhs.add('kv3')
|
||||||
@@ -41,14 +44,10 @@ def test_grammar():
|
|||||||
expect_lhs.add("annotate_arg")
|
expect_lhs.add("annotate_arg")
|
||||||
expect_lhs.add("annotate_tuple")
|
expect_lhs.add("annotate_tuple")
|
||||||
unused_rhs.add("mkfunc_annotate")
|
unused_rhs.add("mkfunc_annotate")
|
||||||
unused_rhs.add('call')
|
|
||||||
unused_rhs.add("dict_comp")
|
unused_rhs.add("dict_comp")
|
||||||
unused_rhs.add("classdefdeco1")
|
unused_rhs.add("classdefdeco1")
|
||||||
if PYTHON_VERSION < 3.6:
|
if PYTHON_VERSION != 3.6:
|
||||||
# 3.6 has at least one non-custom call rule
|
if PYTHON_VERSION in (3.5, 3.7):
|
||||||
# the others don't
|
|
||||||
unused_rhs.add('call')
|
|
||||||
if PYTHON_VERSION == 3.5:
|
|
||||||
expect_right_recursive.add((('l_stmts',
|
expect_right_recursive.add((('l_stmts',
|
||||||
('lastl_stmt', 'come_froms', 'l_stmts'))))
|
('lastl_stmt', 'come_froms', 'l_stmts'))))
|
||||||
pass
|
pass
|
||||||
@@ -61,7 +60,6 @@ def test_grammar():
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
expect_lhs.add('kwarg')
|
expect_lhs.add('kwarg')
|
||||||
unused_rhs.add('call')
|
|
||||||
|
|
||||||
assert expect_lhs == set(lhs)
|
assert expect_lhs == set(lhs)
|
||||||
assert unused_rhs == set(rhs)
|
assert unused_rhs == set(rhs)
|
||||||
|
@@ -2,11 +2,11 @@ PHONY=check clean dist distclean test test-unit test-functional rmChangeLog clea
|
|||||||
check-bytecode-1.5 check-bytecode-1 check-bytecode-2 check-bytecode-3 \
|
check-bytecode-1.5 check-bytecode-1 check-bytecode-2 check-bytecode-3 \
|
||||||
check-bytecode-2.2 check-byteocde-2.3 check-bytecode-2.4 \
|
check-bytecode-2.2 check-byteocde-2.3 check-bytecode-2.4 \
|
||||||
check-short check-2.6 check-2.7 check-3.0 check-3.1 check-3.2 check-3.3 \
|
check-short check-2.6 check-2.7 check-3.0 check-3.1 check-3.2 check-3.3 \
|
||||||
check-3.4 check-3.5 check-5.6 5.6 5.8 \
|
check-3.4 check-3.5 check-3.6 check-3.7 check-5.6 5.6 5.8 \
|
||||||
grammar-coverage-2.5 grammar-coverage-2.6 grammar-coverage-2.7 \
|
grammar-coverage-2.5 grammar-coverage-2.6 grammar-coverage-2.7 \
|
||||||
grammar-coverage-3.1 grammar-coverage-3.2 grammar-coverage-3.3 \
|
grammar-coverage-3.1 grammar-coverage-3.2 grammar-coverage-3.3 \
|
||||||
grammar-coverage-3.4 grammar-coverage-3.5 grammar-coverage-3.6
|
grammar-coverage-3.4 grammar-coverage-3.5 grammar-coverage-3.6 \
|
||||||
|
grammar-coverage-3.7
|
||||||
|
|
||||||
GIT2CL ?= git2cl
|
GIT2CL ?= git2cl
|
||||||
PYTHON ?= python
|
PYTHON ?= python
|
||||||
@@ -63,6 +63,10 @@ check-3.5: check-bytecode
|
|||||||
check-3.6: check-bytecode
|
check-3.6: check-bytecode
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-3.6 --weak-verify $(COMPILE)
|
$(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)
|
||||||
|
|
||||||
# FIXME
|
# FIXME
|
||||||
#: this is called when running under pypy3.5-5.8.0 or pypy2-5.6.0
|
#: this is called when running under pypy3.5-5.8.0 or pypy2-5.6.0
|
||||||
5.8 5.6:
|
5.8 5.6:
|
||||||
@@ -229,6 +233,10 @@ check-bytecode-3.6:
|
|||||||
$(PYTHON) test_pythonlib.py --bytecode-3.6 --weak-verify
|
$(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-run --verify-run
|
||||||
|
|
||||||
|
#: Check deparsing Python 3.7
|
||||||
|
check-bytecode-3.7:
|
||||||
|
$(PYTHON) test_pythonlib.py --bytecode-3.7 --weak-verify
|
||||||
|
|
||||||
#: short tests for bytecodes only for this version of Python
|
#: short tests for bytecodes only for this version of Python
|
||||||
check-native-short:
|
check-native-short:
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --weak-verify $(COMPILE)
|
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --weak-verify $(COMPILE)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
These are byte-compiled programs compiled by Python 2.4
|
These are byte-compiled programs compiled by Python 2.4
|
||||||
|
|
||||||
Furthrmore the programs here are self-checking: when decompiled and
|
Furthermore, the programs here are self-checking: when decompiled and
|
||||||
then run again in a 2.4 interpreter, they will give an error if they
|
then run again in a 2.4 interpreter, they are likely to give an error when they
|
||||||
are miscompiled.
|
are miscompiled.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
These are byte-compiled programs compiled by Python 2.5.
|
These are byte-compiled programs compiled by Python 2.5.
|
||||||
|
|
||||||
Furthrmore the programs here are self-checking: when decompiled and
|
Furthermore the programs here are self-checking: when decompiled and
|
||||||
then run again in a 2.5 interpreter, they will give an error if they
|
then run again in a 2.5 interpreter, they are likely to give an error
|
||||||
are miscompiled.
|
when they are miscompiled.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
These are byte-compiled programs compiled by Python 2.6.
|
These are byte-compiled programs compiled by Python 2.6.
|
||||||
|
|
||||||
Furthrmore the programs here are self-checking: when decompiled and
|
Furthermore the programs here are self-checking: when decompiled and
|
||||||
then run again in a 2.6 interpreter, they will give an error if they
|
then run again in a 2.6 interpreter, they are likely to give an error
|
||||||
are miscompiled.
|
when they are miscompiled.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
These are byte-compiled programs compiled by Python 2.7.
|
These are byte-compiled programs compiled by Python 2.7.
|
||||||
|
|
||||||
Furthrmore the programs here are self-checking: when decompiled and
|
Furthermore, the programs here are self-checking: when decompiled and
|
||||||
then run again in a 2.7 interpreter, they will give an error if they
|
then run again in a 2.7 interpreter, they are likely to give an error
|
||||||
are miscompiled.
|
when they are miscompiled.
|
||||||
|
BIN
test/bytecode_3.0/10_classdec.pyc
Normal file
BIN
test/bytecode_3.0/10_classdec.pyc
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
These are byte-compiled programs compiled by Python 3.0.
|
These are byte-compiled programs compiled by Python 3.0.
|
||||||
|
|
||||||
Furthrmore the programs here are self-checking: when decompiled and
|
Furthermore, the programs here are self-checking: when decompiled and
|
||||||
then run again in a 3.0 interpreter, they will give an error if they
|
then run again in a 3.0 interpreter, they are likely to give an error
|
||||||
are miscompiled.
|
when they are miscompiled.
|
||||||
|
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
These are byte-compiled programs compiled by Python 3.1.
|
These are byte-compiled programs compiled by Python 3.1.
|
||||||
|
|
||||||
Furthrmore the programs here are self-checking: when decompiled and
|
Furthrmore, the programs here are self-checking: when decompiled and
|
||||||
then run again in a 3.1 interpreter, they will give an error if they
|
then run again in a 3.1 interpreter, they are likely to give an error
|
||||||
are miscompiled.
|
when they are miscompiled.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
These are byte-compiled programs compiled by Python 3.2.
|
These are byte-compiled programs compiled by Python 3.2.
|
||||||
|
|
||||||
Furthrmore the programs here are self-checking: when decompiled and
|
Furthermore, the programs here are self-checking: when decompiled and
|
||||||
then run again in a 3.2 interpreter, they will give an error if they
|
then run again in a 3.2 interpreter, they are likely to give an error
|
||||||
are miscompiled.
|
when they are miscompiled.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
These are byte-compiled programs compiled by Python 3.3.
|
These are byte-compiled programs compiled by Python 3.3.
|
||||||
|
|
||||||
Furthrmore the programs here are self-checking: when decompiled and
|
Furthermore, the programs here are self-checking: when decompiled and
|
||||||
then run again in a 3.3 interpreter, they will give an error if they
|
then run again in a 3.3 interpreter, they are likely to give an error
|
||||||
are miscompiled.
|
when they are miscompiled.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
These are byte-compiled programs compiled by Python 3.4.
|
These are byte-compiled programs compiled by Python 3.4.
|
||||||
|
|
||||||
Furthrmore the programs here are self-checking: when decompiled and
|
Furthermore, the programs here are self-checking: when decompiled and
|
||||||
then run again in a 3.4 interpreter, they will give an error if they
|
then run again in a 3.4 interpreter, they are likely to give an error
|
||||||
are miscompiled.
|
when they are miscompiled.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
These are byte-compiled programs compiled by Python 3.5.
|
These are byte-compiled programs compiled by Python 3.5.
|
||||||
|
|
||||||
Furthrmore the programs here are self-checking: when decompiled and
|
Furthrmore, the programs here are self-checking: when decompiled and
|
||||||
then run again in a 3.5 interpreter, they will give an error if they
|
then run again in a 3.5 interpreter, they are likely to give an error
|
||||||
are miscompiled.
|
when they are miscompiled.
|
||||||
|
Binary file not shown.
5
test/bytecode_3.6_run/README
Normal file
5
test/bytecode_3.6_run/README
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
These are byte-compiled programs compiled by Python 3.6.
|
||||||
|
|
||||||
|
Furthrmore, the programs here are self-checking: when decompiled and
|
||||||
|
then run again in a 3.6 interpreter, they are likely to give an error
|
||||||
|
when they are miscompiled.
|
BIN
test/bytecode_3.7/00_assign.pyc
Normal file
BIN
test/bytecode_3.7/00_assign.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/00_docstring.pyc
Normal file
BIN
test/bytecode_3.7/00_docstring.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/00_import.pyc
Normal file
BIN
test/bytecode_3.7/00_import.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/01_augmented_assign.pyc
Normal file
BIN
test/bytecode_3.7/01_augmented_assign.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/01_boolean.pyc
Normal file
BIN
test/bytecode_3.7/01_boolean.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/01_call_function.pyc
Normal file
BIN
test/bytecode_3.7/01_call_function.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/01_class.pyc
Normal file
BIN
test/bytecode_3.7/01_class.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/01_extended_arg.pyc
Normal file
BIN
test/bytecode_3.7/01_extended_arg.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/01_map_unpack.pyc
Normal file
BIN
test/bytecode_3.7/01_map_unpack.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/01_matrix_multiply.pyc
Normal file
BIN
test/bytecode_3.7/01_matrix_multiply.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/01_named_and_kwargs.pyc
Normal file
BIN
test/bytecode_3.7/01_named_and_kwargs.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/01_while_if_then.pyc
Normal file
BIN
test/bytecode_3.7/01_while_if_then.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/02_build_map_unpack_with_call.pyc
Normal file
BIN
test/bytecode_3.7/02_build_map_unpack_with_call.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/02_genexpr.pyc
Normal file
BIN
test/bytecode_3.7/02_genexpr.pyc
Normal file
Binary file not shown.
@@ -25,3 +25,7 @@ class MyClass(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
x = MyClass()
|
x = MyClass()
|
||||||
|
|
||||||
|
# Try class without parens
|
||||||
|
class Feature:
|
||||||
|
pass
|
||||||
|
@@ -1,6 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
me=${BASH_SOURCE[0]}
|
me=${BASH_SOURCE[0]}
|
||||||
|
|
||||||
|
typeset -i batch=1
|
||||||
|
isatty=$(/usr/bin/tty 2>/dev/null)
|
||||||
|
if [[ -n $isatty ]] && [[ "$isatty" != 'not a tty' ]] ; then
|
||||||
|
batch=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
function displaytime {
|
function displaytime {
|
||||||
local T=$1
|
local T=$1
|
||||||
local D=$((T/60/60/24))
|
local D=$((T/60/60/24))
|
||||||
@@ -66,7 +73,13 @@ case $PYVERSION in
|
|||||||
# .pyenv/versions/2.6.9/lib/python2.6/sre_parse.pyc
|
# .pyenv/versions/2.6.9/lib/python2.6/sre_parse.pyc
|
||||||
# .pyenv/versions/2.6.9/lib/python2.6/tabnanny.pyc
|
# .pyenv/versions/2.6.9/lib/python2.6/tabnanny.pyc
|
||||||
# .pyenv/versions/2.6.9/lib/python2.6/tarfile.pyc
|
# .pyenv/versions/2.6.9/lib/python2.6/tarfile.pyc
|
||||||
)
|
)
|
||||||
|
if (( batch )) ; then
|
||||||
|
# Fails in crontab environment?
|
||||||
|
# Figure out what's up here
|
||||||
|
SKIP_TESTS[test_aifc.py]=1
|
||||||
|
SKIP_TESTS[test_array.py]=1
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
2.7)
|
2.7)
|
||||||
SKIP_TESTS=(
|
SKIP_TESTS=(
|
||||||
@@ -97,12 +110,22 @@ case $PYVERSION in
|
|||||||
[test_xpickle.py]=1 # Runs ok but takes 72 seconds
|
[test_xpickle.py]=1 # Runs ok but takes 72 seconds
|
||||||
[test_zipfile64.py]=1 # Runs ok but takes 204 seconds
|
[test_zipfile64.py]=1 # Runs ok but takes 204 seconds
|
||||||
)
|
)
|
||||||
|
if (( batch )) ; then
|
||||||
|
# Fails in crontab environment?
|
||||||
|
# Figure out what's up here
|
||||||
|
SKIP_TESTS[test_array.py]=1
|
||||||
|
SKIP_TESTS[test_ast.py]=1
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
3.5)
|
3.5)
|
||||||
SKIP_TESTS=(
|
SKIP_TESTS=(
|
||||||
[test_decorators.py]=1 # Control flow wrt "if elif"
|
[test_decorators.py]=1 # Control flow wrt "if elif"
|
||||||
[test_quopri.py]=1 # Fails in crontab environment?
|
|
||||||
)
|
)
|
||||||
|
if (( batch )) ; then
|
||||||
|
# Fails in crontab environment?
|
||||||
|
# Figure out what's up here
|
||||||
|
SKIP_TESTS[test_quopri.py]=1
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
3.6)
|
3.6)
|
||||||
@@ -148,7 +171,7 @@ if [[ -n $1 ]] ; then
|
|||||||
SKIP_TESTS=()
|
SKIP_TESTS=()
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
files=test_*.py
|
files=test_a*.py
|
||||||
fi
|
fi
|
||||||
|
|
||||||
typeset -i ALL_FILES_STARTTIME=$(date +%s)
|
typeset -i ALL_FILES_STARTTIME=$(date +%s)
|
||||||
|
@@ -79,7 +79,7 @@ for vers in (2.7, 3.4, 3.5, 3.6):
|
|||||||
for vers in (1.5,
|
for vers in (1.5,
|
||||||
2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7,
|
2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7,
|
||||||
3.0, 3.1, 3.2, 3.3,
|
3.0, 3.1, 3.2, 3.3,
|
||||||
3.4, 3.5, 3.6, 'pypy3.2', 'pypy2.7'):
|
3.4, 3.5, 3.6, 3.7, 'pypy3.2', 'pypy2.7'):
|
||||||
bytecode = "bytecode_%s" % vers
|
bytecode = "bytecode_%s" % vers
|
||||||
key = "bytecode-%s" % vers
|
key = "bytecode-%s" % vers
|
||||||
test_options[key] = (bytecode, PYC, bytecode, vers)
|
test_options[key] = (bytecode, PYC, bytecode, vers)
|
||||||
|
@@ -69,7 +69,7 @@ def usage():
|
|||||||
def main_bin():
|
def main_bin():
|
||||||
if not (sys.version_info[0:2] in ((2, 4), (2, 5), (2, 6), (2, 7),
|
if not (sys.version_info[0:2] in ((2, 4), (2, 5), (2, 6), (2, 7),
|
||||||
(3, 2), (3, 3),
|
(3, 2), (3, 3),
|
||||||
(3, 4), (3, 5), (3, 6))):
|
(3, 4), (3, 5), (3, 6), (3, 7))):
|
||||||
sys.stderr.write('Error: %s requires Python 2.4 2.5 2.6, 2.7, '
|
sys.stderr.write('Error: %s requires Python 2.4 2.5 2.6, 2.7, '
|
||||||
'3.2, 3.3, 3.4, 3.5, or 3.6' % program)
|
'3.2, 3.3, 3.4, 3.5, or 3.6' % program)
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
@@ -719,6 +719,12 @@ def get_python_parser(
|
|||||||
p = parse36.Python36Parser(debug_parser)
|
p = parse36.Python36Parser(debug_parser)
|
||||||
else:
|
else:
|
||||||
p = parse36.Python36ParserSingle(debug_parser)
|
p = parse36.Python36ParserSingle(debug_parser)
|
||||||
|
elif version == 3.7:
|
||||||
|
import uncompyle6.parsers.parse37 as parse37
|
||||||
|
if compile_mode == 'exec':
|
||||||
|
p = parse37.Python37Parser(debug_parser)
|
||||||
|
else:
|
||||||
|
p = parse37.Python37ParserSingle(debug_parser)
|
||||||
else:
|
else:
|
||||||
if compile_mode == 'exec':
|
if compile_mode == 'exec':
|
||||||
p = parse3.Python3Parser(debug_parser)
|
p = parse3.Python3Parser(debug_parser)
|
||||||
|
@@ -176,6 +176,8 @@ class Python36Parser(Python35Parser):
|
|||||||
'expr32 ' * int((v//32) % 32) +
|
'expr32 ' * int((v//32) % 32) +
|
||||||
'expr ' * (v % 32) + opname)
|
'expr ' * (v % 32) + opname)
|
||||||
self.addRule(rule, nop_func)
|
self.addRule(rule, nop_func)
|
||||||
|
rule = ('starred ::= %s %s' % ('expr ' * v, opname))
|
||||||
|
self.addRule(rule, nop_func)
|
||||||
elif opname == 'SETUP_WITH':
|
elif opname == 'SETUP_WITH':
|
||||||
rules_str = """
|
rules_str = """
|
||||||
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST
|
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST
|
||||||
@@ -245,6 +247,17 @@ class Python36Parser(Python35Parser):
|
|||||||
starred ::= expr
|
starred ::= expr
|
||||||
call_ex ::= expr starred CALL_FUNCTION_EX
|
call_ex ::= expr starred CALL_FUNCTION_EX
|
||||||
""", nop_func)
|
""", nop_func)
|
||||||
|
if self.version > 3.6:
|
||||||
|
self.addRule("""
|
||||||
|
expr ::= call_ex_kw3
|
||||||
|
expr ::= call_ex_kw
|
||||||
|
call_ex_kw3 ::= expr
|
||||||
|
build_tuple_unpack_with_call
|
||||||
|
expr
|
||||||
|
CALL_FUNCTION_EX
|
||||||
|
call_ex_kw ::= expr expr
|
||||||
|
build_map_unpack_with_call CALL_FUNCTION_EX
|
||||||
|
""", nop_func)
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
super(Python36Parser, self).custom_classfunc_rule(opname, token,
|
super(Python36Parser, self).custom_classfunc_rule(opname, token,
|
||||||
|
@@ -26,6 +26,26 @@ class Python37Parser(Python36Parser):
|
|||||||
super(Python37Parser, self).__init__(debug_parser)
|
super(Python37Parser, self).__init__(debug_parser)
|
||||||
self.customized = {}
|
self.customized = {}
|
||||||
|
|
||||||
|
def p_37misc(self, args):
|
||||||
|
"""
|
||||||
|
# Where does the POP_TOP really belong?
|
||||||
|
stmt ::= import37
|
||||||
|
import37 ::= import POP_TOP
|
||||||
|
|
||||||
|
# Is there a pattern here?
|
||||||
|
attributes ::= IMPORT_FROM ROT_TWO POP_TOP IMPORT_FROM
|
||||||
|
|
||||||
|
# FIXME: generalize and specialize
|
||||||
|
attribute37 ::= LOAD_FAST LOAD_METHOD
|
||||||
|
attribute37 ::= LOAD_NAME LOAD_METHOD
|
||||||
|
expr ::= attribute37
|
||||||
|
|
||||||
|
# FIXME: generalize and specialize
|
||||||
|
call ::= expr CALL_METHOD_0
|
||||||
|
"""
|
||||||
|
|
||||||
|
def customize_grammar_rules(self, tokens, customize):
|
||||||
|
super(Python37Parser, self).customize_grammar_rules(tokens, customize)
|
||||||
|
|
||||||
class Python37ParserSingle(Python37Parser, PythonParserSingle):
|
class Python37ParserSingle(Python37Parser, PythonParserSingle):
|
||||||
pass
|
pass
|
||||||
|
@@ -145,7 +145,7 @@ class Scanner3(Scanner):
|
|||||||
self.opc.BUILD_MAP, self.opc.UNPACK_SEQUENCE,
|
self.opc.BUILD_MAP, self.opc.UNPACK_SEQUENCE,
|
||||||
self.opc.RAISE_VARARGS])
|
self.opc.RAISE_VARARGS])
|
||||||
|
|
||||||
if is_pypy:
|
if is_pypy or self.version >= 3.7:
|
||||||
varargs_ops.add(self.opc.CALL_METHOD)
|
varargs_ops.add(self.opc.CALL_METHOD)
|
||||||
if self.version >= 3.5:
|
if self.version >= 3.5:
|
||||||
varargs_ops |= set([self.opc.BUILD_SET_UNPACK,
|
varargs_ops |= set([self.opc.BUILD_SET_UNPACK,
|
||||||
@@ -187,7 +187,7 @@ class Scanner3(Scanner):
|
|||||||
|
|
||||||
bytecode = self.build_instructions(co)
|
bytecode = self.build_instructions(co)
|
||||||
|
|
||||||
# show_asm = 'after'
|
# show_asm = 'both'
|
||||||
if show_asm in ('both', 'before'):
|
if show_asm in ('both', 'before'):
|
||||||
for instr in bytecode.get_instructions(co):
|
for instr in bytecode.get_instructions(co):
|
||||||
print(instr.disassemble())
|
print(instr.disassemble())
|
||||||
@@ -355,9 +355,9 @@ class Scanner3(Scanner):
|
|||||||
else:
|
else:
|
||||||
opname = '%s_%d' % (opname, pos_args)
|
opname = '%s_%d' % (opname, pos_args)
|
||||||
|
|
||||||
elif self.is_pypy and opname in ('CALL_METHOD', 'JUMP_IF_NOT_DEBUG'):
|
elif self.is_pypy and opname == 'JUMP_IF_NOT_DEBUG':
|
||||||
# The value in the dict is in special cases in semantic actions, such
|
# The value in the dict is in special cases in semantic actions, such
|
||||||
# as CALL_FUNCTION. The value is not used in these cases, so we put
|
# as JUMP_IF_NOT_DEBUG. The value is not used in these cases, so we put
|
||||||
# in arbitrary value 0.
|
# in arbitrary value 0.
|
||||||
customize[opname] = 0
|
customize[opname] = 0
|
||||||
elif opname == 'UNPACK_EX':
|
elif opname == 'UNPACK_EX':
|
||||||
|
@@ -32,6 +32,131 @@ def customize_for_version3(self, version):
|
|||||||
'store_locals': ( '%|# inspect.currentframe().f_locals = __locals__\n', ),
|
'store_locals': ( '%|# inspect.currentframe().f_locals = __locals__\n', ),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
assert version >= 3.0
|
||||||
|
|
||||||
|
def n_classdef3(node):
|
||||||
|
# class definition ('class X(A,B,C):')
|
||||||
|
cclass = self.currentclass
|
||||||
|
|
||||||
|
# Pick out various needed bits of information
|
||||||
|
# * class_name - the name of the class
|
||||||
|
# * subclass_info - the parameters to the class e.g.
|
||||||
|
# class Foo(bar, baz)
|
||||||
|
# ----------
|
||||||
|
# * subclass_code - the code for the subclass body
|
||||||
|
subclass_info = None
|
||||||
|
if node == 'classdefdeco2':
|
||||||
|
if self.version >= 3.6:
|
||||||
|
class_name = node[1][1].pattr
|
||||||
|
elif self.version <= 3.3:
|
||||||
|
class_name = node[2][0].pattr
|
||||||
|
else:
|
||||||
|
class_name = node[1][2].pattr
|
||||||
|
build_class = node
|
||||||
|
else:
|
||||||
|
build_class = node[0]
|
||||||
|
if self.version >= 3.6:
|
||||||
|
if build_class == 'build_class_kw':
|
||||||
|
mkfunc = build_class[1]
|
||||||
|
assert mkfunc == 'mkfunc'
|
||||||
|
subclass_info = build_class
|
||||||
|
if hasattr(mkfunc[0], 'attr') and iscode(mkfunc[0].attr):
|
||||||
|
subclass_code = mkfunc[0].attr
|
||||||
|
else:
|
||||||
|
assert mkfunc[0] == 'load_closure'
|
||||||
|
subclass_code = mkfunc[1].attr
|
||||||
|
assert iscode(subclass_code)
|
||||||
|
if build_class[1][0] == 'load_closure':
|
||||||
|
code_node = build_class[1][1]
|
||||||
|
else:
|
||||||
|
code_node = build_class[1][0]
|
||||||
|
class_name = code_node.attr.co_name
|
||||||
|
else:
|
||||||
|
class_name = node[1][0].pattr
|
||||||
|
build_class = node[0]
|
||||||
|
|
||||||
|
assert 'mkfunc' == build_class[1]
|
||||||
|
mkfunc = build_class[1]
|
||||||
|
if mkfunc[0] in ('kwargs', 'no_kwargs'):
|
||||||
|
if 3.0 <= self.version <= 3.2:
|
||||||
|
for n in mkfunc:
|
||||||
|
if hasattr(n, 'attr') and iscode(n.attr):
|
||||||
|
subclass_code = n.attr
|
||||||
|
break
|
||||||
|
elif n == 'expr':
|
||||||
|
subclass_code = n[0].attr
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
for n in mkfunc:
|
||||||
|
if hasattr(n, 'attr') and iscode(n.attr):
|
||||||
|
subclass_code = n.attr
|
||||||
|
break
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
if node == 'classdefdeco2':
|
||||||
|
subclass_info = node
|
||||||
|
else:
|
||||||
|
subclass_info = node[0]
|
||||||
|
elif build_class[1][0] == 'load_closure':
|
||||||
|
# Python 3 with closures not functions
|
||||||
|
load_closure = build_class[1]
|
||||||
|
if hasattr(load_closure[-3], 'attr'):
|
||||||
|
# Python 3.3 classes with closures work like this.
|
||||||
|
# Note have to test before 3.2 case because
|
||||||
|
# index -2 also has an attr.
|
||||||
|
subclass_code = load_closure[-3].attr
|
||||||
|
elif hasattr(load_closure[-2], 'attr'):
|
||||||
|
# Python 3.2 works like this
|
||||||
|
subclass_code = load_closure[-2].attr
|
||||||
|
else:
|
||||||
|
raise 'Internal Error n_classdef: cannot find class body'
|
||||||
|
if hasattr(build_class[3], '__len__'):
|
||||||
|
if not subclass_info:
|
||||||
|
subclass_info = build_class[3]
|
||||||
|
elif hasattr(build_class[2], '__len__'):
|
||||||
|
subclass_info = build_class[2]
|
||||||
|
else:
|
||||||
|
raise 'Internal Error n_classdef: cannot superclass name'
|
||||||
|
elif self.version >= 3.6 and node == 'classdefdeco2':
|
||||||
|
subclass_info = node
|
||||||
|
subclass_code = build_class[1][0].attr
|
||||||
|
elif not subclass_info:
|
||||||
|
if mkfunc[0] in ('no_kwargs', 'kwargs'):
|
||||||
|
subclass_code = mkfunc[1].attr
|
||||||
|
else:
|
||||||
|
subclass_code = mkfunc[0].attr
|
||||||
|
if node == 'classdefdeco2':
|
||||||
|
subclass_info = node
|
||||||
|
else:
|
||||||
|
subclass_info = node[0]
|
||||||
|
|
||||||
|
if (node == 'classdefdeco2'):
|
||||||
|
self.write('\n')
|
||||||
|
else:
|
||||||
|
self.write('\n\n')
|
||||||
|
|
||||||
|
self.currentclass = str(class_name)
|
||||||
|
self.write(self.indent, 'class ', self.currentclass)
|
||||||
|
|
||||||
|
self.print_super_classes3(subclass_info)
|
||||||
|
self.println(':')
|
||||||
|
|
||||||
|
# class body
|
||||||
|
self.indent_more()
|
||||||
|
self.build_class(subclass_code)
|
||||||
|
self.indent_less()
|
||||||
|
|
||||||
|
self.currentclass = cclass
|
||||||
|
if len(self.param_stack) > 1:
|
||||||
|
self.write('\n\n')
|
||||||
|
else:
|
||||||
|
self.write('\n\n\n')
|
||||||
|
|
||||||
|
self.prune()
|
||||||
|
self.n_classdef3 = n_classdef3
|
||||||
|
|
||||||
|
|
||||||
if version >= 3.3:
|
if version >= 3.3:
|
||||||
def n_yield_from(node):
|
def n_yield_from(node):
|
||||||
self.write('yield from')
|
self.write('yield from')
|
||||||
@@ -112,7 +237,7 @@ def customize_for_version3(self, version):
|
|||||||
|
|
||||||
# FIXME: handle and pass full annotate args
|
# FIXME: handle and pass full annotate args
|
||||||
make_function3_annotate(self, node, is_lambda=False,
|
make_function3_annotate(self, node, is_lambda=False,
|
||||||
codeNode=code, annotate_last=annotate_last)
|
code_node=code, annotate_last=annotate_last)
|
||||||
|
|
||||||
if len(self.param_stack) > 1:
|
if len(self.param_stack) > 1:
|
||||||
self.write('\n\n')
|
self.write('\n\n')
|
||||||
@@ -754,6 +879,13 @@ def customize_for_version3(self, version):
|
|||||||
self.prune()
|
self.prune()
|
||||||
return
|
return
|
||||||
self.n_return_closure = return_closure
|
self.n_return_closure = return_closure
|
||||||
|
|
||||||
|
if version >= 3.7:
|
||||||
|
PRECEDENCE['attribute37'] = 2
|
||||||
|
TABLE_DIRECT.update({
|
||||||
|
'attribute37': ( '%c.%[1]{pattr}', 0 ),
|
||||||
|
})
|
||||||
|
pass
|
||||||
pass # version >= 3.6
|
pass # version >= 3.6
|
||||||
pass # version >= 3.4
|
pass # version >= 3.4
|
||||||
return
|
return
|
||||||
|
@@ -564,7 +564,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
|
|
||||||
self.indent_more()
|
self.indent_more()
|
||||||
start = len(self.f.getvalue())
|
start = len(self.f.getvalue())
|
||||||
self.make_function(node, is_lambda=False, codeNode=code_node)
|
self.make_function(node, is_lambda=False, code_node=code_node)
|
||||||
|
|
||||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||||
|
|
||||||
@@ -1433,16 +1433,21 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
self.write('{')
|
self.write('{')
|
||||||
self.set_pos_info(node[0], start, start+1)
|
self.set_pos_info(node[0], start, start+1)
|
||||||
|
|
||||||
if self.version > 3.0:
|
if self.version >= 3.0 and not self.is_pypy:
|
||||||
if node[0].kind.startswith('kvlist'):
|
if node[0].kind.startswith('kvlist'):
|
||||||
# Python 3.5+ style key/value list in dict
|
# Python 3.5+ style key/value list in dict
|
||||||
kv_node = node[0]
|
kv_node = node[0]
|
||||||
l = list(kv_node)
|
l = list(kv_node)
|
||||||
|
length = len(l)
|
||||||
|
if kv_node[-1].kind.startswith("BUILD_MAP"):
|
||||||
|
length -= 1
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(l):
|
while i < length:
|
||||||
|
self.write(sep)
|
||||||
|
name = self.traverse(l[i], indent='')
|
||||||
l[i].parent = kv_node
|
l[i].parent = kv_node
|
||||||
l[i+1].parent = kv_node
|
l[i+1].parent = kv_node
|
||||||
name = self.traverse(l[i], indent='')
|
self.write(name, ': ')
|
||||||
value = self.traverse(l[i+1], indent=self.indent+(len(name)+2)*' ')
|
value = self.traverse(l[i+1], indent=self.indent+(len(name)+2)*' ')
|
||||||
self.write(sep, name, ': ', value)
|
self.write(sep, name, ': ', value)
|
||||||
sep = line_seperator
|
sep = line_seperator
|
||||||
|
@@ -30,7 +30,7 @@ from uncompyle6.show import maybe_show_tree_param_default
|
|||||||
# FIXME: DRY the below code...
|
# FIXME: DRY the below code...
|
||||||
|
|
||||||
def make_function3_annotate(self, node, is_lambda, nested=1,
|
def make_function3_annotate(self, node, is_lambda, nested=1,
|
||||||
codeNode=None, annotate_last=-1):
|
code_node=None, annotate_last=-1):
|
||||||
"""
|
"""
|
||||||
Dump function defintion, doc string, and function
|
Dump function defintion, doc string, and function
|
||||||
body. This code is specialized for Python 3"""
|
body. This code is specialized for Python 3"""
|
||||||
@@ -96,7 +96,7 @@ def make_function3_annotate(self, node, is_lambda, nested=1,
|
|||||||
assert node[lambda_index].kind == 'LOAD_LAMBDA'
|
assert node[lambda_index].kind == 'LOAD_LAMBDA'
|
||||||
code = node[lambda_index].attr
|
code = node[lambda_index].attr
|
||||||
else:
|
else:
|
||||||
code = codeNode.attr
|
code = code_node.attr
|
||||||
|
|
||||||
assert iscode(code)
|
assert iscode(code)
|
||||||
code = Code(code, self.scanner, self.currentclass)
|
code = Code(code, self.scanner, self.currentclass)
|
||||||
@@ -278,7 +278,7 @@ def make_function3_annotate(self, node, is_lambda, nested=1,
|
|||||||
returnNone=rn)
|
returnNone=rn)
|
||||||
code._tokens = code._customize = None # save memory
|
code._tokens = code._customize = None # save memory
|
||||||
|
|
||||||
def make_function2(self, node, is_lambda, nested=1, codeNode=None):
|
def make_function2(self, node, is_lambda, nested=1, code_node=None):
|
||||||
"""
|
"""
|
||||||
Dump function defintion, doc string, and function body.
|
Dump function defintion, doc string, and function body.
|
||||||
This code is specialied for Python 2.
|
This code is specialied for Python 2.
|
||||||
@@ -328,7 +328,7 @@ def make_function2(self, node, is_lambda, nested=1, codeNode=None):
|
|||||||
assert node[lambda_index].kind == 'LOAD_LAMBDA'
|
assert node[lambda_index].kind == 'LOAD_LAMBDA'
|
||||||
code = node[lambda_index].attr
|
code = node[lambda_index].attr
|
||||||
else:
|
else:
|
||||||
code = codeNode.attr
|
code = code_node.attr
|
||||||
|
|
||||||
assert iscode(code)
|
assert iscode(code)
|
||||||
code = Code(code, self.scanner, self.currentclass)
|
code = Code(code, self.scanner, self.currentclass)
|
||||||
@@ -440,7 +440,7 @@ def make_function2(self, node, is_lambda, nested=1, codeNode=None):
|
|||||||
code._tokens = None; code._customize = None # save memory
|
code._tokens = None; code._customize = None # save memory
|
||||||
|
|
||||||
|
|
||||||
def make_function3(self, node, is_lambda, nested=1, codeNode=None):
|
def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
||||||
"""Dump function definition, doc string, and function body in
|
"""Dump function definition, doc string, and function body in
|
||||||
Python version 3.0 and above
|
Python version 3.0 and above
|
||||||
"""
|
"""
|
||||||
@@ -585,7 +585,7 @@ def make_function3(self, node, is_lambda, nested=1, codeNode=None):
|
|||||||
assert node[lambda_index].kind == 'LOAD_LAMBDA'
|
assert node[lambda_index].kind == 'LOAD_LAMBDA'
|
||||||
code = node[lambda_index].attr
|
code = node[lambda_index].attr
|
||||||
else:
|
else:
|
||||||
code = codeNode.attr
|
code = code_node.attr
|
||||||
|
|
||||||
assert iscode(code)
|
assert iscode(code)
|
||||||
scanner_code = Code(code, self.scanner, self.currentclass)
|
scanner_code = Code(code, self.scanner, self.currentclass)
|
||||||
|
@@ -1224,6 +1224,10 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
self.prec = p
|
self.prec = p
|
||||||
|
|
||||||
def n_classdef(self, node):
|
def n_classdef(self, node):
|
||||||
|
|
||||||
|
if self.version >= 3.0:
|
||||||
|
self.n_classdef3(node)
|
||||||
|
|
||||||
# class definition ('class X(A,B,C):')
|
# class definition ('class X(A,B,C):')
|
||||||
cclass = self.currentclass
|
cclass = self.currentclass
|
||||||
|
|
||||||
@@ -1233,113 +1237,25 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
# class Foo(bar, baz)
|
# class Foo(bar, baz)
|
||||||
# -----------
|
# -----------
|
||||||
# * subclass_code - the code for the subclass body
|
# * subclass_code - the code for the subclass body
|
||||||
subclass_info = None
|
|
||||||
if self.version > 3.0:
|
|
||||||
if node == 'classdefdeco2':
|
|
||||||
if self.version >= 3.6:
|
|
||||||
class_name = node[1][1].pattr
|
|
||||||
elif self.version <= 3.3:
|
|
||||||
class_name = node[2][0].pattr
|
|
||||||
else:
|
|
||||||
class_name = node[1][2].pattr
|
|
||||||
build_class = node
|
|
||||||
else:
|
|
||||||
build_class = node[0]
|
|
||||||
if self.version >= 3.6:
|
|
||||||
if build_class == 'build_class_kw':
|
|
||||||
mkfunc = build_class[1]
|
|
||||||
assert mkfunc == 'mkfunc'
|
|
||||||
subclass_info = build_class
|
|
||||||
if hasattr(mkfunc[0], 'attr') and iscode(mkfunc[0].attr):
|
|
||||||
subclass_code = mkfunc[0].attr
|
|
||||||
else:
|
|
||||||
assert mkfunc[0] == 'load_closure'
|
|
||||||
subclass_code = mkfunc[1].attr
|
|
||||||
assert iscode(subclass_code)
|
|
||||||
if build_class[1][0] == 'load_closure':
|
|
||||||
code_node = build_class[1][1]
|
|
||||||
else:
|
|
||||||
code_node = build_class[1][0]
|
|
||||||
class_name = code_node.attr.co_name
|
|
||||||
else:
|
|
||||||
class_name = node[1][0].pattr
|
|
||||||
build_class = node[0]
|
|
||||||
|
|
||||||
assert 'mkfunc' == build_class[1]
|
|
||||||
mkfunc = build_class[1]
|
|
||||||
if mkfunc[0] in ('kwargs', 'no_kwargs'):
|
|
||||||
if 3.0 <= self.version <= 3.2:
|
|
||||||
for n in mkfunc:
|
|
||||||
if hasattr(n, 'attr') and iscode(n.attr):
|
|
||||||
subclass_code = n.attr
|
|
||||||
break
|
|
||||||
elif n == 'expr':
|
|
||||||
subclass_code = n[0].attr
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
for n in mkfunc:
|
|
||||||
if hasattr(n, 'attr') and iscode(n.attr):
|
|
||||||
subclass_code = n.attr
|
|
||||||
break
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
if node == 'classdefdeco2':
|
|
||||||
subclass_info = node
|
|
||||||
else:
|
|
||||||
subclass_info = node[0]
|
|
||||||
elif build_class[1][0] == 'load_closure':
|
|
||||||
# Python 3 with closures not functions
|
|
||||||
load_closure = build_class[1]
|
|
||||||
if hasattr(load_closure[-3], 'attr'):
|
|
||||||
# Python 3.3 classes with closures work like this.
|
|
||||||
# Note have to test before 3.2 case because
|
|
||||||
# index -2 also has an attr.
|
|
||||||
subclass_code = load_closure[-3].attr
|
|
||||||
elif hasattr(load_closure[-2], 'attr'):
|
|
||||||
# Python 3.2 works like this
|
|
||||||
subclass_code = load_closure[-2].attr
|
|
||||||
else:
|
|
||||||
raise 'Internal Error n_classdef: cannot find class body'
|
|
||||||
if hasattr(build_class[3], '__len__'):
|
|
||||||
if not subclass_info:
|
|
||||||
subclass_info = build_class[3]
|
|
||||||
elif hasattr(build_class[2], '__len__'):
|
|
||||||
subclass_info = build_class[2]
|
|
||||||
else:
|
|
||||||
raise 'Internal Error n_classdef: cannot superclass name'
|
|
||||||
elif self.version >= 3.6 and node == 'classdefdeco2':
|
|
||||||
subclass_info = node
|
|
||||||
subclass_code = build_class[1][0].attr
|
|
||||||
elif not subclass_info:
|
|
||||||
if mkfunc[0] in ('no_kwargs', 'kwargs'):
|
|
||||||
subclass_code = mkfunc[1].attr
|
|
||||||
else:
|
|
||||||
subclass_code = mkfunc[0].attr
|
|
||||||
if node == 'classdefdeco2':
|
|
||||||
subclass_info = node
|
|
||||||
else:
|
|
||||||
subclass_info = node[0]
|
|
||||||
|
|
||||||
|
if node == 'classdefdeco2':
|
||||||
|
build_class = node
|
||||||
else:
|
else:
|
||||||
if node == 'classdefdeco2':
|
build_class = node[0]
|
||||||
build_class = node
|
build_list = build_class[1][0]
|
||||||
else:
|
if hasattr(build_class[-3][0], 'attr'):
|
||||||
build_class = node[0]
|
subclass_code = build_class[-3][0].attr
|
||||||
build_list = build_class[1][0]
|
class_name = build_class[0].pattr
|
||||||
if hasattr(build_class[-3][0], 'attr'):
|
elif (build_class[-3] == 'mkfunc' and
|
||||||
subclass_code = build_class[-3][0].attr
|
node == 'classdefdeco2' and
|
||||||
class_name = build_class[0].pattr
|
build_class[-3][0] == 'load_closure'):
|
||||||
elif (build_class[-3] == 'mkfunc' and
|
subclass_code = build_class[-3][1].attr
|
||||||
node == 'classdefdeco2' and
|
class_name = build_class[-3][0][0].pattr
|
||||||
build_class[-3][0] == 'load_closure'):
|
elif hasattr(node[0][0], 'pattr'):
|
||||||
subclass_code = build_class[-3][1].attr
|
subclass_code = build_class[-3][1].attr
|
||||||
class_name = build_class[-3][0][0].pattr
|
class_name = node[0][0].pattr
|
||||||
elif hasattr(node[0][0], 'pattr'):
|
else:
|
||||||
subclass_code = build_class[-3][1].attr
|
raise 'Internal Error n_classdef: cannot find class name'
|
||||||
class_name = node[0][0].pattr
|
|
||||||
else:
|
|
||||||
raise 'Internal Error n_classdef: cannot find class name'
|
|
||||||
|
|
||||||
if (node == 'classdefdeco2'):
|
if (node == 'classdefdeco2'):
|
||||||
self.write('\n')
|
self.write('\n')
|
||||||
@@ -1349,10 +1265,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
self.currentclass = str(class_name)
|
self.currentclass = str(class_name)
|
||||||
self.write(self.indent, 'class ', self.currentclass)
|
self.write(self.indent, 'class ', self.currentclass)
|
||||||
|
|
||||||
if self.version > 3.0:
|
self.print_super_classes(build_list)
|
||||||
self.print_super_classes3(subclass_info)
|
|
||||||
else:
|
|
||||||
self.print_super_classes(build_list)
|
|
||||||
self.println(':')
|
self.println(':')
|
||||||
|
|
||||||
# class body
|
# class body
|
||||||
|
@@ -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.1.2'
|
VERSION='3.1.3'
|
||||||
|
Reference in New Issue
Block a user