You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Compare commits
268 Commits
release-3.
...
release-py
Author | SHA1 | Date | |
---|---|---|---|
|
0b24eca8d7 | ||
|
3116ac8323 | ||
|
19bb16270d | ||
|
35c41f8065 | ||
|
9d36e7742e | ||
|
75f3624f31 | ||
|
2e78c007ee | ||
|
f5a10ed5d0 | ||
|
de75849ae3 | ||
|
30d6dcdd69 | ||
|
c48345a5c0 | ||
|
a1cdc5e40c | ||
|
661bfd4e52 | ||
|
6ac48bb0e1 | ||
|
a18b4b1505 | ||
|
b2c832e19f | ||
|
1462a8beb0 | ||
|
f877e65919 | ||
|
78898ed187 | ||
|
ef03d78c4d | ||
|
48b251273a | ||
|
c91b5e1164 | ||
|
f8fd474b55 | ||
|
bc5f43ab05 | ||
|
1da2118e13 | ||
|
67e8f5d1a7 | ||
|
2a76013ed5 | ||
|
681bbd616b | ||
|
46390a161e | ||
|
28d0ec7a2a | ||
|
8a842c57d3 | ||
|
fb333f1505 | ||
|
ab257dc7ce | ||
|
e3d8751338 | ||
|
a1532bbfea | ||
|
128963d2e9 | ||
|
1cb9fc8b43 | ||
|
b9147b7872 | ||
|
5496271000 | ||
|
16b5df4ba4 | ||
|
fee6114d74 | ||
|
b14655dd43 | ||
|
3de2890050 | ||
|
90ae3e42f6 | ||
|
158a1886fe | ||
|
d2285f0d61 | ||
|
2e44ac25a1 | ||
|
9d425039a2 | ||
|
832f04a486 | ||
|
657d5ef024 | ||
|
e92c2503d1 | ||
|
b74662cf3d | ||
|
ed3b0e81b9 | ||
|
75755c8cfc | ||
|
4ce769399f | ||
|
d0dfdcfcde | ||
|
4e949a798d | ||
|
4fb379afb4 | ||
|
eb7484c671 | ||
|
79470ffff7 | ||
|
44af6c42a2 | ||
|
d7380dc549 | ||
|
b2f6e1cf1a | ||
|
7c9437f0a9 | ||
|
162bb0a85f | ||
|
e44ccd5787 | ||
|
c4612b7484 | ||
|
731c5a2092 | ||
|
7efbd55b69 | ||
|
5dbec5b383 | ||
|
f28ad69c38 | ||
|
49a71819a1 | ||
|
ed7d11525a | ||
|
5b1dcccddc | ||
|
992a08f5ce | ||
|
49ef408699 | ||
|
0487f2fb7a | ||
|
e43c8acd30 | ||
|
97604a93dd | ||
|
d266e9e123 | ||
|
7ac8bf91df | ||
|
772d36015c | ||
|
f381211291 | ||
|
aca4cb233d | ||
|
01ef3b774f | ||
|
9041dead7f | ||
|
4ea308f75a | ||
|
e5f06eb551 | ||
|
c68030e9fa | ||
|
fd95839701 | ||
|
6305023219 | ||
|
c7dda72a84 | ||
|
7caedcb50d | ||
|
1856e09a0c | ||
|
e47568e147 | ||
|
c702ce3802 | ||
|
a37f403410 | ||
|
9248a954bd | ||
|
89a7ad6f81 | ||
|
f432f4f698 | ||
|
5ef2d5cd9f | ||
|
204612ca85 | ||
|
df8c092212 | ||
|
55d2e598db | ||
|
3c67c7b32c | ||
|
5264ffc0e5 | ||
|
27b217a4ed | ||
|
d756548ac3 | ||
|
0171e4d899 | ||
|
a2054fb7dd | ||
|
f07c9c6dcf | ||
|
c677c946ea | ||
|
87063851be | ||
|
516c1a7910 | ||
|
2293f77841 | ||
|
212771244a | ||
|
5fc33aeef5 | ||
|
fff0d1c988 | ||
|
987b5a2290 | ||
|
910d210e52 | ||
|
b719a0ee35 | ||
|
25329d2752 | ||
|
df4d80ff26 | ||
|
13ab06ecb1 | ||
|
72e2d1a2bf | ||
|
c90210c063 | ||
|
21a8726a47 | ||
|
ca7f267103 | ||
|
7b15e54b7d | ||
|
ccd007355c | ||
|
36aba02093 | ||
|
a5dd330218 | ||
|
fc0eb87620 | ||
|
0b9fca2263 | ||
|
0d9464bb92 | ||
|
ff435227e9 | ||
|
fcdc3f67af | ||
|
299936e554 | ||
|
2e192f0467 | ||
|
9062f19a97 | ||
|
f51e40a1de | ||
|
e411024696 | ||
|
01a27e22b4 | ||
|
7553c4aed9 | ||
|
593304bc43 | ||
|
a9ca30fe34 | ||
|
6030730870 | ||
|
b9436e4851 | ||
|
b0a7452d48 | ||
|
5e05e521d9 | ||
|
7a052c349a | ||
|
35aca37557 | ||
|
57fe56d72e | ||
|
218e73540a | ||
|
0965e2cc96 | ||
|
5cf4f0a82f | ||
|
9b0225db60 | ||
|
8c0959de42 | ||
|
ccd71c857f | ||
|
b89dbb0ee7 | ||
|
a5bdc1acd0 | ||
|
a279784d8d | ||
|
3a9f4f2984 | ||
|
51ae8313cf | ||
|
38f04f0073 | ||
|
f3da5d770d | ||
|
24fb13cf23 | ||
|
524e8c8410 | ||
|
52d1e44560 | ||
|
6055c5e165 | ||
|
e0ed187ea6 | ||
|
eafe048c7e | ||
|
c0e553dbb5 | ||
|
7e59987af7 | ||
|
1f012f7c46 | ||
|
d1a3d42ab8 | ||
|
05fd992c48 | ||
|
47f1d888eb | ||
|
ca9c227837 | ||
|
5df384bb71 | ||
|
e80b36347a | ||
|
9e37495493 | ||
|
77b93c5f21 | ||
|
0b198ee881 | ||
|
9e0c65881d | ||
|
c796d6a799 | ||
|
3892fb533a | ||
|
2ea7487ca7 | ||
|
d4f6cec3d0 | ||
|
b1705e283d | ||
|
eee751e22a | ||
|
2b0fefb95f | ||
|
1a627ba207 | ||
|
ea75bcf47e | ||
|
6c6dcab857 | ||
|
0654aed6c8 | ||
|
3447ca0767 | ||
|
1e858efafd | ||
|
ce88a72ea1 | ||
|
7725b8e7de | ||
|
62ddbe320d | ||
|
a694601264 | ||
|
e06f88043f | ||
|
8fc3fd146f | ||
|
ce5066bddb | ||
|
93f18e2449 | ||
|
783e62f3ca | ||
|
c38dc61021 | ||
|
45782bbb39 | ||
|
4c9cd5657e | ||
|
dc627d13b8 | ||
|
ddc3489991 | ||
|
5b24c20331 | ||
|
8bb01143d8 | ||
|
a9635da96a | ||
|
e790cb75fd | ||
|
348afeebbf | ||
|
6888553773 | ||
|
0f489672b9 | ||
|
b7d8cbfaf5 | ||
|
df8d253f78 | ||
|
89b42e3696 | ||
|
22e5a4a283 | ||
|
61810172d1 | ||
|
658c8b4be7 | ||
|
d4dab54c7b | ||
|
5566b9ba6c | ||
|
e56ab2dcd5 | ||
|
d6c45979ba | ||
|
a06e9bf32e | ||
|
7e8f7ba674 | ||
|
09eb7f7f78 | ||
|
f7a910ec66 | ||
|
6d6a73eea7 | ||
|
e4a7641927 | ||
|
b24b46d48c | ||
|
a65d7dce5b | ||
|
718a0a5d34 | ||
|
ea9e3ab3f5 | ||
|
770e988ff8 | ||
|
0fa0641974 | ||
|
c13e23cdae | ||
|
fab4ebb768 | ||
|
89429339fa | ||
|
6ed129bd7a | ||
|
c4fde6b53e | ||
|
a7d93e88b4 | ||
|
9891494142 | ||
|
f8544dfbbe | ||
|
b00651d428 | ||
|
da8dccbaca | ||
|
37272ae827 | ||
|
7f2bee46b7 | ||
|
c8a4dcf72b | ||
|
012ff91cfb | ||
|
e690ddd50a | ||
|
45b7c1948c | ||
|
e2fb7ca3d2 | ||
|
b3bda76582 | ||
|
ab6d322eca | ||
|
1a8a0df107 | ||
|
0a37709b0a | ||
|
98cd1417df | ||
|
460069ceaa | ||
|
316aa44f23 | ||
|
7133540c23 | ||
|
590231741d | ||
|
a9349b8f3d |
@@ -3,13 +3,7 @@ language: python
|
||||
sudo: false
|
||||
|
||||
python:
|
||||
- '3.5'
|
||||
- '2.7'
|
||||
- '2.6'
|
||||
- '3.3'
|
||||
- '3.4'
|
||||
- '3.2'
|
||||
- '3.6'
|
||||
- '2.7' # this is a cheat here because travis doesn't do 2.4-2.6
|
||||
|
||||
install:
|
||||
- pip install -e .
|
||||
|
5
Makefile
5
Makefile
@@ -38,7 +38,10 @@ check-3.0 check-3.1 check-3.2 check-3.6:
|
||||
$(MAKE) -C test $@
|
||||
|
||||
check-3.7: pytest
|
||||
$(MAKE) -C test check
|
||||
|
||||
#:Tests for Python 2.4-2.5 (don't have pytest)
|
||||
check-2.4 check-2.5:
|
||||
$(MAKE) -C test $@
|
||||
|
||||
#:PyPy 2.6.1 PyPy 5.0.1, or PyPy 5.8.0-beta0
|
||||
# Skip for now
|
||||
|
26
NEWS
26
NEWS
@@ -1,29 +1,3 @@
|
||||
uncompyle6 3.2.3 2018-06-04 Michael Cohen flips and Fleetwood Redux
|
||||
|
||||
- Python 1.3 support 3.0 bug and
|
||||
- fix botched parameter ordering of 3.x in last release
|
||||
|
||||
uncompyle6 3.2.2 2018-06-04 When I'm 64
|
||||
|
||||
- Python 3.0 support and bug fixes
|
||||
|
||||
uncompyle6 3.2.1 2018-06-04 MF
|
||||
|
||||
- Python 1.4 and 1.5 bug fixes
|
||||
|
||||
uncompyle6 3.2.0 2018-05-19 Rocket Scientist
|
||||
|
||||
- Add rudimentary 1.4 support (still a bit buggy)
|
||||
- add --tree+ option to show formatting rule, when it is constant
|
||||
- Python 2.7.15candidate1 support (via xdis)
|
||||
- bug fixes, especially for 3.7 (but 2.7 and 3.6 and others as well)
|
||||
|
||||
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
|
||||
|
||||
- Python 3.x subclass and call parsing fixes
|
||||
|
100
README.rst
100
README.rst
@@ -1,4 +1,4 @@
|
||||
|buildstatus| |Latest Version| |Supported Python Versions|
|
||||
|buildstatus|
|
||||
|
||||
uncompyle6
|
||||
==========
|
||||
@@ -11,9 +11,8 @@ 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
|
||||
Python 2.5 bytecode and some PyPy bytecode.
|
||||
source code. It accepts bytecodes from Python version 1.5, and 2.1 to
|
||||
3.7 or so, including PyPy bytecode and Dropbox's Python 2.5 bytecode.
|
||||
|
||||
Why this?
|
||||
---------
|
||||
@@ -30,11 +29,11 @@ CPython bytecode decompilers is the ability to deparse just
|
||||
*fragments* of source code and give source-code information around a
|
||||
given bytecode offset.
|
||||
|
||||
I use the tree fragments to deparse fragments of code *at run time*
|
||||
inside my trepan_ debuggers_. For that, bytecode offsets are recorded
|
||||
and associated with fragments of the source code. This purpose,
|
||||
although compatible with the original intention, is yet a little bit
|
||||
different. See this_ for more information.
|
||||
I use the tree fragments to deparse fragments of code inside my
|
||||
trepan_ debuggers_. For that, bytecode offsets are recorded and
|
||||
associated with fragments of the source code. This purpose, although
|
||||
compatible with the original intention, is yet a little bit different.
|
||||
See this_ for more information.
|
||||
|
||||
Python fragment deparsing given an instruction offset is useful in
|
||||
showing stack traces and can be encorporated into any program that
|
||||
@@ -53,17 +52,8 @@ You get the idea. This code pulls all of these forks together and
|
||||
*moves forward*. There is some serious refactoring and cleanup in this
|
||||
code base over those old forks.
|
||||
|
||||
This demonstrably does the best in decompiling Python across all
|
||||
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 those 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.
|
||||
This project has the most complete support for Python 3.3 and above
|
||||
and the best all-around Python support.
|
||||
|
||||
We are serious about testing, and use automated processes to find
|
||||
bugs. In the issue trackers for other decompilers, you will find a
|
||||
@@ -76,7 +66,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.5, 2.1-2.7, and 3.0-3.6 and the
|
||||
above-mentioned PyPy versions.
|
||||
|
||||
Installation
|
||||
@@ -146,26 +136,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
|
||||
erroneous decompilation and report that.
|
||||
|
||||
In older versions of Python it was possible to verify bytecode by
|
||||
decompiling bytecode, and then compiling using the Python interpreter
|
||||
for that bytecode version. Having done this the bytecode produced
|
||||
could be compared with the original bytecode. However as Python's code
|
||||
generation got better, this is no longer feasible.
|
||||
*Verification* is the process of decompiling bytecode, compiling with
|
||||
a Python for that bytecode version, and then comparing the bytecode
|
||||
produced by the decompiled/compiled program. Some allowance is made
|
||||
for inessential differences. But other semantically equivalent
|
||||
differences are not caught. For example ``1 and 0`` is decompiled to
|
||||
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.
|
||||
|
||||
There verification that we use that doesn't check bytecode for
|
||||
equivalence but does check to see if the resulting decompiled source
|
||||
is a valid Python program by running the Python interpreter. Because
|
||||
the Python language has changed so much, for best results you should
|
||||
use the same Python version in checking as was used in creating the
|
||||
bytecode.
|
||||
*Weak Verification*
|
||||
on the other hand doesn't check bytecode for equivalence but does
|
||||
check to see if the resulting decompiled source is a valid Python
|
||||
program by running the Python interpreter. Because the Python language
|
||||
has changed so much, for best results you should use the same Python
|
||||
Version in checking as used in the bytecode.
|
||||
|
||||
There are however an interesting class of these programs that is
|
||||
readily available give stronger verification: those programs that
|
||||
when run check some computation, or even better themselves.
|
||||
|
||||
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.
|
||||
Finally, we have automated running the standard Python tests after
|
||||
first compiling and decompiling the test program. Results here are a
|
||||
bit weak (if not better than most other Python decompilers). But over
|
||||
time this will probably get better.
|
||||
|
||||
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
|
||||
@@ -175,21 +165,19 @@ that era was minimal)
|
||||
|
||||
There is some work to do on the lower end Python versions which is
|
||||
more difficult for us to handle since we don't have a Python
|
||||
interpreter for versions 1.6, and 2.0.
|
||||
interpreter for versions 1.5, 1.6, and 2.0.
|
||||
|
||||
In the Python 3 series, Python support is is strongest around 3.4 or
|
||||
3.3 and drops off as you move further away from those versions. Python
|
||||
3.0 is weird in that it in some ways resembles 2.6 more than it does
|
||||
3.1 or 2.7. Python 3.6 changes things drastically by using word codes
|
||||
rather than byte codes. As a result, the jump offset field in a jump
|
||||
instruction argument has been reduced. This makes the `EXTENDED_ARG`
|
||||
instructions are now more prevalent in jump instruction; previously
|
||||
they had been rare. Perhaps to compensate for the additional
|
||||
`EXTENDED_ARG` instructions, additional jump optimization has been
|
||||
added. So in sum handling control flow by ad hoc means as is currently
|
||||
done is worse.
|
||||
3.6 changes things drastically by using word codes rather than byte
|
||||
codes. As a result, the jump offset field in a jump instruction
|
||||
argument has been reduced. This makes the `EXTENDED_ARG` instructions
|
||||
are now more prevalent in jump instruction; previously they had been
|
||||
rare. Perhaps to compensate for the additional `EXTENDED_ARG`
|
||||
instructions, additional jump optimization has been added. So in sum
|
||||
handling control flow by ad hoc means as is currently done is worse.
|
||||
|
||||
Between Python 3.5, 3.6 and 3.7 there have been major changes to the
|
||||
Also, between Python 3.5, 3.6 and 3.7 there have been major changes to the
|
||||
`MAKE_FUNCTION` and `CALL_FUNCTION` instructions.
|
||||
|
||||
Currently not all Python magic numbers are supported. Specifically in
|
||||
@@ -215,12 +203,11 @@ There is lots to do, so please dig in and help.
|
||||
See Also
|
||||
--------
|
||||
|
||||
* https://github.com/zrax/pycdc : purports to support all versions of Python. It is written in C++ and is most accurate for Python versions around 2.7 and 3.3 when the code was more actively developed. Accuracy for more recent versions of Python 3 and early versions of Python are especially lacking. See its `issue tracker <https://github.com/zrax/pycdc/issues>`_ for details. Currently lightly maintained.
|
||||
* 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. Currently unmaintained.
|
||||
* https://github.com/figment/unpyc3/ : fork of above, but supports Python 3.3 only. Includes some fixes like supporting function annotations. Currently unmaintained.
|
||||
* https://github.com/wibiti/uncompyle2 : supports Python 2.7 only, but does that fairly well. There are situtations where `uncompyle6` results are incorrect while `uncompyle2` results are not, but more often uncompyle6 is correct when uncompyle2 is not. Because `uncompyle6` adheres to accuracy over idiomatic Python, `uncompyle2` can produce more natural-looking code when it is correct. Currently `uncompyle2` is lightly maintained. See its issue `tracker <https://github.com/wibiti/uncompyle2/issues>`_ for more details
|
||||
* `How to report a bug <https://github.com/rocky/python-uncompyle6/blob/master/HOW-TO-REPORT-A-BUG.md>`_
|
||||
* 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://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
|
||||
* The HISTORY_ file.
|
||||
* `How to report a bug <https://github.com/rocky/python-uncompyle6/blob/master/HOW-TO-REPORT-A-BUG.md>`_
|
||||
* https://github.com/rocky/python-xdis : Cross Python version disassembler
|
||||
* https://github.com/rocky/python-xasm : Cross Python version assembler
|
||||
* https://github.com/rocky/python-uncompyle6/wiki : Wiki Documents which describe the code and aspects of it in more detail
|
||||
@@ -238,6 +225,3 @@ See Also
|
||||
.. _PJOrion: http://www.koreanrandom.com/forum/topic/15280-pjorion-%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%B4%D0%B5%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%BE%D0%B1%D1%84
|
||||
.. _Deobfuscator: https://github.com/extremecoders-re/PjOrion-Deobfuscator
|
||||
.. _Py2EXE: https://en.wikipedia.org/wiki/Py2exe
|
||||
.. |Supported Python Versions| image:: https://img.shields.io/pypi/pyversions/uncompyle6.svg
|
||||
.. |Latest Version| image:: https://badge.fury.io/py/uncompyle6.svg
|
||||
:target: https://badge.fury.io/py/uncompyle6
|
||||
|
@@ -35,7 +35,6 @@ classifiers = ['Development Status :: 5 - Production/Stable',
|
||||
'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',
|
||||
@@ -57,8 +56,7 @@ entry_points = {
|
||||
]}
|
||||
ftp_url = None
|
||||
install_requires = ['spark-parser >= 1.8.5, < 1.9.0',
|
||||
'xdis >= 3.8.4, < 3.9.0']
|
||||
|
||||
'xdis >= 3.7.0, < 3.8.0']
|
||||
license = 'GPL3'
|
||||
mailing_list = 'python-debugger@googlegroups.com'
|
||||
modname = 'uncompyle6'
|
||||
|
2
admin-tools/check-newer-versions.sh
Executable file → Normal file
2
admin-tools/check-newer-versions.sh
Executable file → Normal file
@@ -16,7 +16,6 @@ if ! source ./setup-master.sh ; then
|
||||
fi
|
||||
cd ..
|
||||
for version in $PYVERSIONS; do
|
||||
echo --- $version ---
|
||||
if ! pyenv local $version ; then
|
||||
exit $?
|
||||
fi
|
||||
@@ -24,5 +23,4 @@ for version in $PYVERSIONS; do
|
||||
if ! make check; then
|
||||
exit $?
|
||||
fi
|
||||
echo === $version ===
|
||||
done
|
||||
|
2
admin-tools/check-older-versions.sh
Executable file → Normal file
2
admin-tools/check-older-versions.sh
Executable file → Normal file
@@ -15,7 +15,6 @@ fi
|
||||
|
||||
cd ..
|
||||
for version in $PYVERSIONS; do
|
||||
echo --- $version ---
|
||||
if ! pyenv local $version ; then
|
||||
exit $?
|
||||
fi
|
||||
@@ -23,5 +22,4 @@ for version in $PYVERSIONS; do
|
||||
if ! make check ; then
|
||||
exit $?
|
||||
fi
|
||||
echo === $version ===
|
||||
done
|
||||
|
46
admin-tools/how-to-make-a-release.txt
Normal file
46
admin-tools/how-to-make-a-release.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
git pull
|
||||
|
||||
Change version in uncompyle6/version.py
|
||||
source uncompyle6/version.py
|
||||
echo $VERSION
|
||||
git commit -m"Get ready for release $VERSION" .
|
||||
|
||||
Update ChangeLog:
|
||||
make ChangeLog
|
||||
|
||||
Update NEWS from ChangeLog
|
||||
make check
|
||||
|
||||
git commit --amend .
|
||||
|
||||
git push
|
||||
|
||||
Make sure pyenv is running
|
||||
# Pyenv
|
||||
|
||||
source admin-tools/check-newer-versions.sh
|
||||
|
||||
|
||||
# Switch to python-2.4 and build that first...
|
||||
source admin-tools/setup-python-2.4
|
||||
|
||||
rm ChangeLog
|
||||
git merge master
|
||||
|
||||
Update NEWS from master branch
|
||||
|
||||
git commit -m"Get ready for release $VERSION" .
|
||||
|
||||
source admin-tools/check-older-versions.sh
|
||||
source admin-tools/check-newer-versions.sh
|
||||
|
||||
make-dist-older.sh
|
||||
|
||||
git tag release-python-2.4-$VERSION
|
||||
|
||||
./make-dist-newer.sh
|
||||
|
||||
git tag release-$VERSION
|
||||
|
||||
|
||||
twine upload dist/uncompyle6-${VERSION}*
|
@@ -1,15 +0,0 @@
|
||||
#!/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"
|
||||
exit 1
|
||||
fi
|
||||
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'
|
||||
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'
|
||||
|
2
admin-tools/setup-master.sh
Executable file → Normal file
2
admin-tools/setup-master.sh
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PYTHON_VERSION=3.6.5
|
||||
PYTHON_VERSION=3.6.4
|
||||
|
||||
# FIXME put some of the below in a common routine
|
||||
function finish {
|
||||
|
0
admin-tools/setup-python-2.4.sh
Executable file → Normal file
0
admin-tools/setup-python-2.4.sh
Executable file → Normal file
@@ -1,32 +0,0 @@
|
||||
#!/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
|
||||
)
|
3
admin-tools/update-sources.sh
Executable file
3
admin-tools/update-sources.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cd $(dirname ${BASH_SOURCE[0]})/..
|
||||
git pull
|
@@ -47,7 +47,7 @@ install:
|
||||
|
||||
# Upgrade to the latest version of pip to avoid it displaying warnings
|
||||
# about it being out of date.
|
||||
- "%PYTHON%\\python.exe -m pip install --disable-pip-version-check --user --upgrade pip"
|
||||
- "pip install --disable-pip-version-check --user --upgrade pip"
|
||||
|
||||
# Install the build dependencies of the project. If some dependencies contain
|
||||
# compiled extensions and are not provided as pre-built wheel packages,
|
||||
|
@@ -6,10 +6,9 @@ machine:
|
||||
|
||||
dependencies:
|
||||
override:
|
||||
- pip install --upgrade setuptools
|
||||
- pip install -e .
|
||||
- pip install pytest==3.2.5 hypothesis
|
||||
test:
|
||||
override:
|
||||
- python ./setup.py develop && make check-2.7
|
||||
- cd ./test/stdlib && pyenv local 2.7.10 && bash ./runtests.sh 'test_[p-z]*.py'
|
||||
- cd ./test/stdlib && pyenv local 2.7.10 && bash ./runtests.sh 'test_[f-i]*.py'
|
||||
|
@@ -30,7 +30,7 @@ def list_comp():
|
||||
[y for y in range(3)]
|
||||
|
||||
def get_parsed_for_fn(fn):
|
||||
code = fn.__code__ if PYTHON3 else fn.func_code
|
||||
code = fn.func_code
|
||||
return deparse(code, version=PYTHON_VERSION)
|
||||
|
||||
def check_expect(expect, parsed, fn_name):
|
||||
|
@@ -10,7 +10,7 @@ else:
|
||||
maxint = sys.maxint
|
||||
from uncompyle6.semantics.helper import print_docstring
|
||||
|
||||
class PrintFake():
|
||||
class PrintFake:
|
||||
def __init__(self):
|
||||
self.pending_newlines = 0
|
||||
self.f = StringIO()
|
||||
|
@@ -20,7 +20,7 @@ def bug_loop(disassemble, tb=None):
|
||||
disassemble(tb)
|
||||
|
||||
def test_if_in_for():
|
||||
code = bug.__code__
|
||||
code = bug.func_code
|
||||
scan = get_scanner(PYTHON_VERSION)
|
||||
if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY:
|
||||
scan.build_instructions(code)
|
||||
|
@@ -1,154 +0,0 @@
|
||||
# std
|
||||
# test
|
||||
from uncompyle6 import PYTHON_VERSION, deparse_code
|
||||
import pytest
|
||||
pytestmark = pytest.mark.skipif(PYTHON_VERSION <= 2.6,
|
||||
reason='hypothesis needs 2.7 or later')
|
||||
if PYTHON_VERSION > 2.6:
|
||||
|
||||
import hypothesis
|
||||
from hypothesis import strategies as st
|
||||
|
||||
# uncompyle6
|
||||
|
||||
|
||||
@st.composite
|
||||
def expressions(draw):
|
||||
# todo : would be nice to generate expressions using hypothesis however
|
||||
# this is pretty involved so for now just use a corpus of expressions
|
||||
# from which to select.
|
||||
return draw(st.sampled_from((
|
||||
'abc',
|
||||
'len(items)',
|
||||
'x + 1',
|
||||
'lineno',
|
||||
'container',
|
||||
'self.attribute',
|
||||
'self.method()',
|
||||
# These expressions are failing, I think these are control
|
||||
# flow problems rather than problems with FORMAT_VALUE,
|
||||
# however I need to confirm this...
|
||||
#'sorted(items, key=lambda x: x.name)',
|
||||
#'func(*args, **kwargs)',
|
||||
#'text or default',
|
||||
#'43 if life_the_universe and everything else None'
|
||||
)))
|
||||
|
||||
|
||||
@st.composite
|
||||
def format_specifiers(draw):
|
||||
"""
|
||||
Generate a valid format specifier using the rules:
|
||||
|
||||
format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]
|
||||
fill ::= <any character>
|
||||
align ::= "<" | ">" | "=" | "^"
|
||||
sign ::= "+" | "-" | " "
|
||||
width ::= integer
|
||||
precision ::= integer
|
||||
type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"
|
||||
|
||||
See https://docs.python.org/2/library/string.html
|
||||
|
||||
:param draw: Let hypothesis draw from other strategies.
|
||||
|
||||
:return: An example format_specifier.
|
||||
"""
|
||||
alphabet_strategy = st.characters(min_codepoint=ord('a'), max_codepoint=ord('z'))
|
||||
fill = draw(st.one_of(alphabet_strategy, st.none()))
|
||||
align = draw(st.sampled_from(list('<>=^')))
|
||||
fill_align = (fill + align or '') if fill else ''
|
||||
|
||||
type_ = draw(st.sampled_from('bcdeEfFgGnosxX%'))
|
||||
can_have_sign = type_ in 'deEfFgGnoxX%'
|
||||
can_have_comma = type_ in 'deEfFgG%'
|
||||
can_have_precision = type_ in 'fFgG'
|
||||
can_have_pound = type_ in 'boxX%'
|
||||
can_have_zero = type_ in 'oxX'
|
||||
|
||||
sign = draw(st.sampled_from(list('+- ') + [''])) if can_have_sign else ''
|
||||
pound = draw(st.sampled_from(('#', '',))) if can_have_pound else ''
|
||||
zero = draw(st.sampled_from(('0', '',))) if can_have_zero else ''
|
||||
|
||||
int_strategy = st.integers(min_value=1, max_value=1000)
|
||||
|
||||
width = draw(st.one_of(int_strategy, st.none()))
|
||||
width = str(width) if width is not None else ''
|
||||
|
||||
comma = draw(st.sampled_from((',', '',))) if can_have_comma else ''
|
||||
if can_have_precision:
|
||||
precision = draw(st.one_of(int_strategy, st.none()))
|
||||
precision = '.' + str(precision) if precision else ''
|
||||
else:
|
||||
precision = ''
|
||||
|
||||
return ''.join((fill_align, sign, pound, zero, width, comma, precision, type_,))
|
||||
|
||||
|
||||
@st.composite
|
||||
def fstrings(draw):
|
||||
"""
|
||||
Generate a valid f-string.
|
||||
See https://www.python.org/dev/peps/pep-0498/#specification
|
||||
|
||||
:param draw: Let hypothsis draw from other strategies.
|
||||
|
||||
:return: A valid f-string.
|
||||
"""
|
||||
character_strategy = st.characters(
|
||||
blacklist_characters='\r\n\'\\s{}',
|
||||
min_codepoint=1,
|
||||
max_codepoint=1000,
|
||||
)
|
||||
is_raw = draw(st.booleans())
|
||||
integer_strategy = st.integers(min_value=0, max_value=3)
|
||||
expression_count = draw(integer_strategy)
|
||||
content = []
|
||||
for _ in range(expression_count):
|
||||
expression = draw(expressions())
|
||||
conversion = draw(st.sampled_from(('', '!s', '!r', '!a',)))
|
||||
has_specifier = draw(st.booleans())
|
||||
specifier = ':' + draw(format_specifiers()) if has_specifier else ''
|
||||
content.append('{{{}{}}}'.format(expression, conversion, specifier))
|
||||
content.append(draw(st.text(character_strategy)))
|
||||
content = ''.join(content)
|
||||
return "f{}'{}'".format('r' if is_raw else '', content)
|
||||
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6')
|
||||
@hypothesis.given(format_specifiers())
|
||||
def test_format_specifiers(format_specifier):
|
||||
"""Verify that format_specifiers generates valid specifiers"""
|
||||
try:
|
||||
exec('"{:' + format_specifier + '}".format(0)')
|
||||
except ValueError as e:
|
||||
if 'Unknown format code' not in str(e):
|
||||
raise
|
||||
|
||||
|
||||
def run_test(text):
|
||||
hypothesis.assume(len(text))
|
||||
hypothesis.assume("f'{" in text)
|
||||
expr = text + '\n'
|
||||
code = compile(expr, '<string>', 'single')
|
||||
deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single')
|
||||
recompiled = compile(deparsed.text, '<string>', 'single')
|
||||
if recompiled != code:
|
||||
assert 'dis(' + deparsed.text.strip('\n') + ')' == 'dis(' + expr.strip('\n') + ')'
|
||||
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6')
|
||||
@hypothesis.given(fstrings())
|
||||
def test_uncompyle_fstring(fstring):
|
||||
"""Verify uncompyling fstring bytecode"""
|
||||
run_test(fstring)
|
||||
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6')
|
||||
@pytest.mark.parametrize('fstring', [
|
||||
"f'{abc}{abc!s}'",
|
||||
"f'{abc}0'",
|
||||
])
|
||||
def test_uncompyle_direct(fstring):
|
||||
"""useful for debugging"""
|
||||
run_test(fstring)
|
@@ -1,185 +0,0 @@
|
||||
import string
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
import pytest
|
||||
pytestmark = pytest.mark.skip(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
|
||||
if PYTHON_VERSION > 2.6:
|
||||
from hypothesis import given, assume, example, settings, strategies as st
|
||||
from validate import validate_uncompyle
|
||||
from test_fstring import expressions
|
||||
|
||||
alpha = st.sampled_from(string.ascii_lowercase)
|
||||
numbers = st.sampled_from(string.digits)
|
||||
alphanum = st.sampled_from(string.ascii_lowercase + string.digits)
|
||||
|
||||
|
||||
@st.composite
|
||||
def function_calls(draw,
|
||||
min_keyword_args=0, max_keyword_args=5,
|
||||
min_positional_args=0, max_positional_args=5,
|
||||
min_star_args=0, max_star_args=1,
|
||||
min_double_star_args=0, max_double_star_args=1):
|
||||
"""
|
||||
Strategy factory for generating function calls.
|
||||
|
||||
:param draw: Callable which draws examples from other strategies.
|
||||
|
||||
:return: The function call text.
|
||||
"""
|
||||
st_positional_args = st.lists(
|
||||
alpha,
|
||||
min_size=min_positional_args,
|
||||
max_size=max_positional_args
|
||||
)
|
||||
st_keyword_args = st.lists(
|
||||
alpha,
|
||||
min_size=min_keyword_args,
|
||||
max_size=max_keyword_args
|
||||
)
|
||||
st_star_args = st.lists(
|
||||
alpha,
|
||||
min_size=min_star_args,
|
||||
max_size=max_star_args
|
||||
)
|
||||
st_double_star_args = st.lists(
|
||||
alpha,
|
||||
min_size=min_double_star_args,
|
||||
max_size=max_double_star_args
|
||||
)
|
||||
|
||||
positional_args = draw(st_positional_args)
|
||||
keyword_args = draw(st_keyword_args)
|
||||
st_values = st.lists(
|
||||
expressions(),
|
||||
min_size=len(keyword_args),
|
||||
max_size=len(keyword_args)
|
||||
)
|
||||
keyword_args = [
|
||||
x + '=' + e
|
||||
for x, e in
|
||||
zip(keyword_args, draw(st_values))
|
||||
]
|
||||
star_args = ['*' + x for x in draw(st_star_args)]
|
||||
double_star_args = ['**' + x for x in draw(st_double_star_args)]
|
||||
|
||||
arguments = positional_args + keyword_args + star_args + double_star_args
|
||||
draw(st.randoms()).shuffle(arguments)
|
||||
arguments = ','.join(arguments)
|
||||
|
||||
function_call = 'fn({arguments})'.format(arguments=arguments)
|
||||
try:
|
||||
# TODO: Figure out the exact rules for ordering of positional, keyword,
|
||||
# star args, double star args and in which versions the various
|
||||
# types of arguments are supported so we don't need to check that the
|
||||
# expression compiles like this.
|
||||
compile(function_call, '<string>', 'single')
|
||||
except:
|
||||
assume(False)
|
||||
return function_call
|
||||
|
||||
|
||||
def test_function_no_args():
|
||||
validate_uncompyle("fn()")
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
def isolated_function_calls(which):
|
||||
"""
|
||||
Returns a strategy for generating function calls, but isolated to
|
||||
particular types of arguments, for example only positional arguments.
|
||||
|
||||
This can help reason about debugging errors in specific types of function
|
||||
calls.
|
||||
|
||||
:param which: One of 'keyword', 'positional', 'star', 'double_star'
|
||||
|
||||
:return: Strategy for generating an function call isolated to specific
|
||||
argument types.
|
||||
"""
|
||||
kwargs = dict(
|
||||
max_keyword_args=0,
|
||||
max_positional_args=0,
|
||||
max_star_args=0,
|
||||
max_double_star_args=0,
|
||||
)
|
||||
kwargs['_'.join(('min', which, 'args'))] = 1
|
||||
kwargs['_'.join(('max', which, 'args'))] = 5 if 'star' not in which else 1
|
||||
return function_calls(**kwargs)
|
||||
|
||||
|
||||
with settings(max_examples=25):
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
@given(isolated_function_calls('positional'))
|
||||
@example("fn(0)")
|
||||
def test_function_positional_only(expr):
|
||||
validate_uncompyle(expr)
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
@given(isolated_function_calls('keyword'))
|
||||
@example("fn(a=0)")
|
||||
def test_function_call_keyword_only(expr):
|
||||
validate_uncompyle(expr)
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
@given(isolated_function_calls('star'))
|
||||
@example("fn(*items)")
|
||||
def test_function_call_star_only(expr):
|
||||
validate_uncompyle(expr)
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
@given(isolated_function_calls('double_star'))
|
||||
@example("fn(**{})")
|
||||
def test_function_call_double_star_only(expr):
|
||||
validate_uncompyle(expr)
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_CONST_KEY_MAP_BUILD_MAP_UNPACK_WITH_CALL_BUILD_TUPLE_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(w=0,m=0,**v)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_MAP_BUILD_MAP_UNPACK_WITH_CALL_BUILD_TUPLE_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(a=0,**g)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(*g,**j)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_MAP_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(*z,u=0)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_TUPLE_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(**a)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_MAP_BUILD_TUPLE_BUILD_TUPLE_UNPACK_WITH_CALL_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(b,b,b=0,*a)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_TUPLE_BUILD_TUPLE_UNPACK_WITH_CALL_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(*c,v)")
|
||||
|
||||
|
||||
@pytest.mark.xfail()
|
||||
def test_BUILD_CONST_KEY_MAP_CALL_FUNCTION_EX():
|
||||
validate_uncompyle("fn(i=0,y=0,*p)")
|
||||
|
||||
|
||||
@pytest.mark.skip(reason='skipping property based test until all individual tests are passing')
|
||||
@given(function_calls())
|
||||
def test_function_call(function_call):
|
||||
validate_uncompyle(function_call)
|
@@ -26,9 +26,6 @@ def test_grammar():
|
||||
expect_right_recursive = set([('designList',
|
||||
('store', 'DUP_TOP', 'designList'))])
|
||||
|
||||
if PYTHON_VERSION != 3.7:
|
||||
unused_rhs.add('call')
|
||||
|
||||
if PYTHON_VERSION > 2.6:
|
||||
expect_lhs.add('kvlist')
|
||||
expect_lhs.add('kv3')
|
||||
@@ -44,10 +41,14 @@ def test_grammar():
|
||||
expect_lhs.add("annotate_arg")
|
||||
expect_lhs.add("annotate_tuple")
|
||||
unused_rhs.add("mkfunc_annotate")
|
||||
unused_rhs.add('call')
|
||||
unused_rhs.add("dict_comp")
|
||||
unused_rhs.add("classdefdeco1")
|
||||
if PYTHON_VERSION != 3.6:
|
||||
if PYTHON_VERSION in (3.5, 3.7):
|
||||
if PYTHON_VERSION < 3.6:
|
||||
# 3.6 has at least one non-custom call rule
|
||||
# the others don't
|
||||
unused_rhs.add('call')
|
||||
if PYTHON_VERSION == 3.5:
|
||||
expect_right_recursive.add((('l_stmts',
|
||||
('lastl_stmt', 'come_froms', 'l_stmts'))))
|
||||
pass
|
||||
@@ -60,6 +61,7 @@ def test_grammar():
|
||||
pass
|
||||
else:
|
||||
expect_lhs.add('kwarg')
|
||||
unused_rhs.add('call')
|
||||
|
||||
assert expect_lhs == set(lhs)
|
||||
assert unused_rhs == set(rhs)
|
||||
|
@@ -8,12 +8,8 @@ from uncompyle6.semantics.consts import (
|
||||
|
||||
if PYTHON3:
|
||||
from io import StringIO
|
||||
def iteritems(d):
|
||||
return d.items()
|
||||
else:
|
||||
from StringIO import StringIO
|
||||
def iteritems(d):
|
||||
return d.iteritems()
|
||||
|
||||
from uncompyle6.semantics.pysource import SourceWalker as SourceWalker
|
||||
|
||||
@@ -30,7 +26,7 @@ def test_template_engine():
|
||||
# FIXME: and so on...
|
||||
|
||||
from uncompyle6.semantics.consts import (
|
||||
TABLE_DIRECT, TABLE_R,
|
||||
TABLE_R, TABLE_DIRECT,
|
||||
)
|
||||
|
||||
from uncompyle6.semantics.fragments import (
|
||||
@@ -44,7 +40,7 @@ def test_tables():
|
||||
(TABLE_DIRECT, 'TABLE_DIRECT', False),
|
||||
(TABLE_R, 'TABLE_R', False),
|
||||
(TABLE_DIRECT_FRAGMENT, 'TABLE_DIRECT_FRAGMENT', True)):
|
||||
for k, entry in iteritems(t):
|
||||
for k, entry in t.iteritems():
|
||||
if k in skip_for_now:
|
||||
continue
|
||||
fmt = entry[0]
|
||||
|
@@ -1,9 +1,6 @@
|
||||
import pytest
|
||||
from uncompyle6 import PYTHON_VERSION, deparse_code
|
||||
pytestmark = pytest.mark.skip(PYTHON_VERSION < 2.7,
|
||||
reason="need at least Python 2.7")
|
||||
|
||||
if PYTHON_VERSION > 2.6:
|
||||
if PYTHON_VERSION >= 2.6:
|
||||
def test_single_mode():
|
||||
single_expressions = (
|
||||
'i = 1',
|
||||
|
2
pytest/testdata/if-2.7.right
vendored
2
pytest/testdata/if-2.7.right
vendored
@@ -9,4 +9,4 @@
|
||||
12 JUMP_FORWARD 0 'to 15'
|
||||
15_0 COME_FROM 12 '12'
|
||||
15 LOAD_CONST 0 None
|
||||
18 RETURN_VALUE
|
||||
18 RETURN_VALUE
|
||||
|
2
pytest/testdata/ifelse-2.7.right
vendored
2
pytest/testdata/ifelse-2.7.right
vendored
@@ -12,4 +12,4 @@
|
||||
18 STORE_NAME 2 'd'
|
||||
21_0 COME_FROM 12 '12'
|
||||
21 LOAD_CONST 2 None
|
||||
24 RETURN_VALUE
|
||||
24 RETURN_VALUE
|
||||
|
@@ -1,26 +1,25 @@
|
||||
# future
|
||||
from __future__ import print_function
|
||||
# std
|
||||
import os
|
||||
import difflib
|
||||
import subprocess
|
||||
import tempfile
|
||||
import functools
|
||||
|
||||
from StringIO import StringIO
|
||||
# uncompyle6 / xdis
|
||||
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY, deparse_code
|
||||
from uncompyle6 import PYTHON_VERSION, IS_PYPY, deparse_code
|
||||
# TODO : I think we can get xdis to support the dis api (python 3 version) by doing something like this there
|
||||
from xdis.bytecode import Bytecode
|
||||
from xdis.main import get_opcode
|
||||
opc = get_opcode(PYTHON_VERSION, IS_PYPY)
|
||||
Bytecode = functools.partial(Bytecode, opc=opc)
|
||||
|
||||
if PYTHON3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from StringIO import StringIO
|
||||
try:
|
||||
import functools
|
||||
Bytecode = functools.partial(Bytecode, opc=opc)
|
||||
def _dis_to_text(co):
|
||||
return Bytecode(co).dis()
|
||||
except:
|
||||
pass
|
||||
|
||||
def _dis_to_text(co):
|
||||
return Bytecode(co).dis()
|
||||
|
||||
|
||||
def print_diff(original, uncompyled):
|
||||
@@ -44,8 +43,11 @@ def print_diff(original, uncompyled):
|
||||
print('\nTo display diff highlighting run:\n pip install BeautifulSoup4')
|
||||
diff = difflib.HtmlDiff().make_table(*args)
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
f = tempfile.NamedTemporaryFile(delete=False)
|
||||
try:
|
||||
f.write(str(diff).encode('utf-8'))
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
try:
|
||||
print()
|
||||
@@ -62,8 +64,7 @@ def print_diff(original, uncompyled):
|
||||
print('\nFor side by side diff install elinks')
|
||||
diff = difflib.Differ().compare(original_lines, uncompyled_lines)
|
||||
print('\n'.join(diff))
|
||||
finally:
|
||||
os.unlink(f.name)
|
||||
os.unlink(f.name)
|
||||
|
||||
|
||||
def are_instructions_equal(i1, i2):
|
||||
@@ -125,8 +126,9 @@ def validate_uncompyle(text, mode='exec'):
|
||||
original_text = text
|
||||
|
||||
deparsed = deparse_code(PYTHON_VERSION, original_code,
|
||||
|
||||
compile_mode=mode,
|
||||
out=six.StringIO(),
|
||||
out=StringIO(),
|
||||
is_pypy=IS_PYPY)
|
||||
uncompyled_text = deparsed.text
|
||||
uncompyled_code = compile(uncompyled_text, '<string>', 'exec')
|
||||
|
@@ -1,4 +1,2 @@
|
||||
# Pick up stuff from setup.py
|
||||
hypothesis==2.0.0
|
||||
pytest
|
||||
-e .
|
||||
|
16
setup.py
16
setup.py
@@ -1,16 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
|
||||
"""Setup script for the 'uncompyle6' distribution."""
|
||||
|
||||
import sys
|
||||
|
||||
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 ((2, 4) <= SYS_VERSION <= (2, 7)):
|
||||
mess += ("\nFor your Python, version %s, use the python-2.4 code/branch." %
|
||||
if not ((2, 4) <= SYS_VERSION <= (2, 7)):
|
||||
mess = "Python Release 2.4 .. 2.7 are supported in this code branch."
|
||||
if ((3, 2) <= SYS_VERSION <= (3, 7)):
|
||||
mess += ("\nFor your Python, version %s, use the master code/branch." %
|
||||
sys.version[0:3])
|
||||
elif SYS_VERSION < (2, 4):
|
||||
mess += ("\nThis package is not supported for Python version %s."
|
||||
else:
|
||||
mess += ("\nThis package is not supported before Python 2.4. Your Python version is %s."
|
||||
% sys.version[0:3])
|
||||
print(mess)
|
||||
raise Exception(mess)
|
||||
|
55
test-unit/test_grammar.py
Normal file
55
test-unit/test_grammar.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import re
|
||||
import unittest
|
||||
from uncompyle6 import PYTHON_VERSION, IS_PYPY # , PYTHON_VERSION
|
||||
from uncompyle6.parser import get_python_parser, python_parser
|
||||
|
||||
class TestGrammar(unittest.TestCase):
|
||||
def test_grammar(self):
|
||||
|
||||
def check_tokens(tokens, opcode_set):
|
||||
remain_tokens = set(tokens) - opcode_set
|
||||
remain_tokens = set([re.sub('_\d+$','', t) for t in remain_tokens])
|
||||
remain_tokens = set([re.sub('_CONT$','', t) for t in remain_tokens])
|
||||
remain_tokens = set(remain_tokens) - opcode_set
|
||||
self.assertEqual(remain_tokens, set([]),
|
||||
"Remaining tokens %s\n====\n%s" % (remain_tokens, p.dump_grammar()))
|
||||
|
||||
p = get_python_parser(PYTHON_VERSION, is_pypy=IS_PYPY)
|
||||
(lhs, rhs, tokens,
|
||||
right_recursive, dup_rhs) = p.check_sets()
|
||||
expect_lhs = set(['expr1024', 'pos_arg'])
|
||||
unused_rhs = set(['list', 'call', 'mkfunc',
|
||||
'mklambda',
|
||||
'unpack',])
|
||||
|
||||
expect_right_recursive = frozenset([('designList',
|
||||
('store', 'DUP_TOP', 'designList'))])
|
||||
expect_lhs.add('kwarg')
|
||||
|
||||
self.assertEqual(expect_lhs, set(lhs))
|
||||
self.assertEqual(unused_rhs, set(rhs))
|
||||
self.assertEqual(expect_right_recursive, right_recursive)
|
||||
|
||||
expect_dup_rhs = frozenset([('COME_FROM',), ('CONTINUE',), ('JUMP_ABSOLUTE',),
|
||||
('LOAD_CONST',),
|
||||
('JUMP_BACK',), ('JUMP_FORWARD',)])
|
||||
|
||||
reduced_dup_rhs = {}
|
||||
for k in dup_rhs:
|
||||
if k not in expect_dup_rhs:
|
||||
reduced_dup_rhs[k] = dup_rhs[k]
|
||||
pass
|
||||
pass
|
||||
for k in reduced_dup_rhs:
|
||||
print(k, reduced_dup_rhs[k])
|
||||
# assert not reduced_dup_rhs, reduced_dup_rhs
|
||||
|
||||
def test_dup_rule(self):
|
||||
import inspect
|
||||
python_parser(PYTHON_VERSION, inspect.currentframe().f_code,
|
||||
is_pypy=IS_PYPY,
|
||||
parser_debug={
|
||||
'dups': True, 'transition': False, 'reduce': False,
|
||||
'rules': False, 'errorstack': None, 'context': True})
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@@ -1,13 +1,12 @@
|
||||
PHONY=check clean dist distclean test test-unit test-functional rmChangeLog clean_pyc nosetests \
|
||||
check-bytecode-1 check-bytecode-1.4 check-bytecode-1.5 \
|
||||
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-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-3.6 check-3.7 check-5.6 5.6 5.8 \
|
||||
check-3.4 check-3.5 check-5.6 5.6 5.8 \
|
||||
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.4 grammar-coverage-3.5 grammar-coverage-3.6 \
|
||||
grammar-coverage-3.7
|
||||
grammar-coverage-3.4 grammar-coverage-3.5 grammar-coverage-3.6
|
||||
|
||||
|
||||
GIT2CL ?= git2cl
|
||||
PYTHON ?= python
|
||||
@@ -22,14 +21,14 @@ COVER_DIR=../tmp/grammar-cover
|
||||
# Run short tests
|
||||
check-short:
|
||||
@$(PYTHON) -V && PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2`; \
|
||||
$(MAKE) check-bytecode-short
|
||||
$(MAKE) check-bytecode
|
||||
|
||||
# Run all tests
|
||||
check:
|
||||
$(MAKE) check-$(PYTHON_VERSION)
|
||||
|
||||
#: Run working tests from Python 2.6 or 2.7
|
||||
check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-native-short
|
||||
check-2.4 check-2.5 check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-native-short
|
||||
|
||||
#: Run working tests from Python 3.0
|
||||
check-3.0: check-bytecode
|
||||
@@ -64,10 +63,6 @@ check-3.5: check-bytecode
|
||||
check-3.6: check-bytecode
|
||||
$(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
|
||||
#: this is called when running under pypy3.5-5.8.0 or pypy2-5.6.0
|
||||
5.8 5.6:
|
||||
@@ -77,7 +72,7 @@ check-disasm:
|
||||
$(PYTHON) dis-compare.py
|
||||
|
||||
#: Check deparsing bytecode 1.x only
|
||||
check-bytecode-1: check-bytecode-1.4 check-bytecode-1.5
|
||||
check-bytecode-1: check-bytecode-1.5
|
||||
|
||||
#: Check deparsing bytecode 2.x only
|
||||
check-bytecode-2:
|
||||
@@ -91,35 +86,14 @@ check-bytecode-3:
|
||||
--bytecode-3.1 --bytecode-3.2 --bytecode-3.3 \
|
||||
--bytecode-3.4 --bytecode-3.5 --bytecode-3.6 --bytecode-pypy3.2
|
||||
|
||||
#: Check deparsing on selected bytecode 3.x
|
||||
check-bytecode-3-short:
|
||||
$(PYTHON) test_pythonlib.py \
|
||||
--bytecode-3.4 --bytecode-3.5 --bytecode-3.6
|
||||
|
||||
#: Check deparsing bytecode on all Python 2 and Python 3 versions
|
||||
#: Check deparsing bytecode that works running Python 2 and Python 3
|
||||
check-bytecode: check-bytecode-3
|
||||
$(PYTHON) test_pythonlib.py \
|
||||
--bytecode-1.3 --bytecode-1.4 --bytecode-1.5 \
|
||||
--bytecode-2.2 --bytecode-2.3 --bytecode-2.4 \
|
||||
--bytecode-2.1 --bytecode-2.2 --bytecode-2.3 --bytecode-2.4 \
|
||||
--bytecode-2.5 --bytecode-2.6 --bytecode-2.7 \
|
||||
--bytecode-pypy2.7
|
||||
|
||||
|
||||
#: Check deparsing bytecode on selected Python 2 and Python 3 versions
|
||||
check-bytecode-short: check-bytecode-3-short
|
||||
$(PYTHON) test_pythonlib.py \
|
||||
--bytecode-2.6 --bytecode-2.7 --bytecode-pypy2.7
|
||||
|
||||
|
||||
#: Check deparsing bytecode 1.3 only
|
||||
check-bytecode-1.3:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-1.3
|
||||
|
||||
#: Check deparsing bytecode 1.4 only
|
||||
check-bytecode-1.4:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-1.4
|
||||
|
||||
#: Check deparsing bytecode 1.5 only
|
||||
check-bytecode-1.5:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-1.5
|
||||
@@ -225,11 +199,6 @@ check-bytecode-2.7:
|
||||
check-bytecode-3.0:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.0 --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
|
||||
|
||||
#: Check deparsing Python 3.1
|
||||
check-bytecode-3.1:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.1 --weak-verify
|
||||
@@ -260,15 +229,15 @@ check-bytecode-3.6:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.6 --weak-verify
|
||||
$(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
|
||||
check-native-short:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION)-run --verify-run $(COMPILE)
|
||||
|
||||
#: Run longer Python 2.6's lib files known to be okay
|
||||
check-2.4-ok:
|
||||
$(PYTHON) test_pythonlib.py --ok-2.4 --verify $(COMPILE)
|
||||
|
||||
#: Run longer Python 2.6's lib files known to be okay
|
||||
check-2.6-ok:
|
||||
$(PYTHON) test_pythonlib.py --ok-2.6 --weak-verify $(COMPILE)
|
||||
@@ -290,7 +259,7 @@ check-3.4-ok:
|
||||
2.6:
|
||||
|
||||
#: PyPy 5.0.x with Python 2.7 ...
|
||||
pypy-2.7 5.0 5.3 6.0:
|
||||
pypy-2.7 5.0 5.3:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-pypy2.7 --verify
|
||||
|
||||
#: PyPy 2.4.x with Python 3.2 ...
|
||||
|
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.
BIN
test/bytecode_1.5/exec.pyc
Normal file
BIN
test/bytecode_1.5/exec.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.2/10_del.pyc
Normal file
BIN
test/bytecode_2.2/10_del.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/01_ops.pyc
Normal file
BIN
test/bytecode_2.4/01_ops.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/01_triple_compare.pyc
Normal file
BIN
test/bytecode_2.4/01_triple_compare.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/02_except_as.pyc
Normal file
BIN
test/bytecode_2.4/02_except_as.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/02_unary_convert.pyc
Normal file
BIN
test/bytecode_2.4/02_unary_convert.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4/02_yield_bug.pyc
Normal file
BIN
test/bytecode_2.4/02_yield_bug.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.4_run/04_try_else_confuse.pyc
Normal file
BIN
test/bytecode_2.4_run/04_try_else_confuse.pyc
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
These are byte-compiled programs compiled by Python 2.4
|
||||
|
||||
Furthermore, the programs here are self-checking: when decompiled and
|
||||
then run again in a 2.4 interpreter, they are likely to give an error when they
|
||||
Furthrmore the programs here are self-checking: when decompiled and
|
||||
then run again in a 2.4 interpreter, they will give an error if they
|
||||
are miscompiled.
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.5/06_setif_comprehension.pyc
Normal file
BIN
test/bytecode_2.5/06_setif_comprehension.pyc
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
These are byte-compiled programs compiled by Python 2.5.
|
||||
|
||||
Furthermore the programs here are self-checking: when decompiled and
|
||||
then run again in a 2.5 interpreter, they are likely to give an error
|
||||
when they are miscompiled.
|
||||
Furthrmore the programs here are self-checking: when decompiled and
|
||||
then run again in a 2.5 interpreter, they will give an error if they
|
||||
are miscompiled.
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.6/02_ifelse_lambda.pyc
Normal file
BIN
test/bytecode_2.6/02_ifelse_lambda.pyc
Normal file
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.
@@ -1,5 +1,5 @@
|
||||
These are byte-compiled programs compiled by Python 2.6.
|
||||
|
||||
Furthermore the programs here are self-checking: when decompiled and
|
||||
then run again in a 2.6 interpreter, they are likely to give an error
|
||||
when they are miscompiled.
|
||||
Furthrmore the programs here are self-checking: when decompiled and
|
||||
then run again in a 2.6 interpreter, they will give an error if they
|
||||
are miscompiled.
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.7/02_ifelse_lambda.pyc
Normal file
BIN
test/bytecode_2.7/02_ifelse_lambda.pyc
Normal file
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.
@@ -1,5 +1,5 @@
|
||||
These are byte-compiled programs compiled by Python 2.7.
|
||||
|
||||
Furthermore, the programs here are self-checking: when decompiled and
|
||||
then run again in a 2.7 interpreter, they are likely to give an error
|
||||
when they are miscompiled.
|
||||
Furthrmore the programs here are self-checking: when decompiled and
|
||||
then run again in a 2.7 interpreter, they will give an error if they
|
||||
are miscompiled.
|
||||
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user