You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 16:59:52 +08:00
Compare commits
275 Commits
release-3.
...
release-py
Author | SHA1 | Date | |
---|---|---|---|
|
761eee7ae7 | ||
|
600cee26d9 | ||
|
61466808f5 | ||
|
de25c5f003 | ||
|
8880568045 | ||
|
3c7d460036 | ||
|
ee3f2446f9 | ||
|
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 .
|
||||
|
4
Makefile
4
Makefile
@@ -40,6 +40,10 @@ check-3.0 check-3.1 check-3.2 check-3.6:
|
||||
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
|
||||
2.6 5.0 5.3 5.6 5.8:
|
||||
|
8
NEWS
8
NEWS
@@ -1,11 +1,3 @@
|
||||
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)
|
||||
|
58
README.rst
58
README.rst
@@ -1,4 +1,4 @@
|
||||
|buildstatus| |Latest Version| |Supported Python Versions|
|
||||
|buildstatus|
|
||||
|
||||
uncompyle6
|
||||
==========
|
||||
@@ -29,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
|
||||
@@ -58,7 +58,7 @@ 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
|
||||
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
|
||||
@@ -151,12 +151,12 @@ 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.
|
||||
|
||||
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.
|
||||
There is a kind of *weak 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.
|
||||
|
||||
There are however an interesting class of these programs that is
|
||||
readily available give stronger verification: those programs that
|
||||
@@ -174,21 +174,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
|
||||
@@ -214,12 +212,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. Because of it specificity it can sometimes to better than uncompyle6 which we can't do withouth breaking other 2.7 cases. Currently 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 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://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
|
||||
@@ -237,6 +234,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.8.2, < 3.9.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}*
|
0
admin-tools/setup-master.sh
Executable file → Normal file
0
admin-tools/setup-master.sh
Executable file → Normal file
0
admin-tools/setup-python-2.4.sh
Executable file → Normal file
0
admin-tools/setup-python-2.4.sh
Executable file → Normal file
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,
|
||||
|
@@ -12,4 +12,4 @@ dependencies:
|
||||
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)
|
@@ -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()
|
@@ -29,7 +29,7 @@ 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
|
||||
@@ -249,6 +249,10 @@ 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)
|
||||
@@ -270,7 +274,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.
BIN
test/bytecode_1.4/test_empty-1.4.pyc
Normal file
BIN
test/bytecode_1.4/test_empty-1.4.pyc
Normal file
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.
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.
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.
@@ -1,9 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
# Mode: -*- python -*-
|
||||
#
|
||||
# Copyright (c) 2015 by Rocky Bernstein <rb@dustyfeet.com>
|
||||
# Copyright (c) 2015, 2017 by Rocky Bernstein <rb@dustyfeet.com>
|
||||
#
|
||||
from __future__ import print_function
|
||||
|
||||
|
||||
import dis, os.path
|
||||
|
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6 import uncompyle
|
||||
import sys, inspect
|
||||
|
||||
|
@@ -1,3 +0,0 @@
|
||||
# Python 1.4 tzparse.py, but also appears in 1.5
|
||||
|
||||
[tzname, delta] = __file__
|
@@ -1,6 +0,0 @@
|
||||
# Python 1.4 aifc.py
|
||||
# Something weird about the final "print" and PRINT_NL_CONT followed by PRINT_NL
|
||||
def _readmark(self, markers):
|
||||
if self._markers: print 'marker',
|
||||
else: print 'markers',
|
||||
print 'instead of', markers
|
@@ -1,11 +0,0 @@
|
||||
# Python 1.4 cgi.py
|
||||
# Bug was in "continue" detection.
|
||||
# 1.4 doesn't have lnotab and our CONTINUE detection is off.
|
||||
def parse_multipart(params, pdict):
|
||||
while params:
|
||||
if params.has_key('name'):
|
||||
params = None
|
||||
else:
|
||||
continue
|
||||
|
||||
return None
|
7
test/simple_source/bug25/02_yield_bug.py
Normal file
7
test/simple_source/bug25/02_yield_bug.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# From 2.4 test_array.py
|
||||
# In Python 2.4 and earlier "yield" is not valid and instead
|
||||
# we must use "yield None". Bug was not adding "None"
|
||||
|
||||
def yield_bug():
|
||||
yield None
|
||||
return
|
19
test/simple_source/bug25/04_try_else_confuse.py
Normal file
19
test/simple_source/bug25/04_try_else_confuse.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# From 2.4 test_sax.py
|
||||
# Bug was distinguishing try from try/else
|
||||
|
||||
def verify_empty_attrs():
|
||||
gvqk = 3
|
||||
try:
|
||||
gvk = 1/0
|
||||
except ZeroDivisionError:
|
||||
gvk = 1
|
||||
|
||||
try:
|
||||
gvqk = 0
|
||||
except KeyError:
|
||||
gvqk = 1
|
||||
|
||||
# If try/else was used above the return will be 4
|
||||
return gvk + gvqk
|
||||
|
||||
assert 1 == verify_empty_attrs()
|
@@ -1,20 +0,0 @@
|
||||
# From 3.0.1 __dummy_thread.py
|
||||
# bug was handling else:
|
||||
def interrupt_main():
|
||||
"""Set _interrupt flag to True to have start_new_thread raise
|
||||
KeyboardInterrupt upon exiting."""
|
||||
if _main:
|
||||
raise KeyboardInterrupt
|
||||
else:
|
||||
global _interrupt
|
||||
_interrupt = True
|
||||
|
||||
# From 3.0.1 ast.py bug was mangling prototype
|
||||
# def parse(expr, filename='<unknown>', mode='exec'):
|
||||
|
||||
# From 3.0.1 bisect
|
||||
def bisect_left(a, x, lo=0, hi=None):
|
||||
while lo:
|
||||
if a[mid] < x: lo = mid+1
|
||||
else: hi = mid
|
||||
return lo
|
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""byte compiles a Python 1.x program"""
|
||||
import sys
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: compile-file.py *python-file*")
|
||||
sys.exit(1)
|
||||
source = sys.argv[1]
|
||||
|
||||
# assert source.endswith('.py')
|
||||
basename = source[:-3]
|
||||
|
||||
# We do this crazy way to support Python 1.4 which
|
||||
# doesn't support version_info.
|
||||
PY_VERSION = sys.version[:3]
|
||||
|
||||
bytecode = "%s-%s.pyc" % (basename, PY_VERSION)
|
||||
|
||||
import py_compile
|
||||
print("# compiling %s to %s" % (source, bytecode))
|
||||
py_compile.compile(source, bytecode)
|
||||
# import os
|
||||
# os.system("../bin/uncompyle6 %s" % bytecode)
|
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
"""byte compiles a Python program after version 2.2 or so. Also see compile_file_1x.py"""
|
||||
import sys
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: compile-file.py *python-file*")
|
||||
|
@@ -42,10 +42,10 @@ case $PYVERSION in
|
||||
2.5)
|
||||
SKIP_TESTS=(
|
||||
[test_contextlib.py]=1 # Syntax error - look at
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_pdb.py]=1 # Line-number specific
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_pdb.py]=1 # Line-number specific
|
||||
[test_pwd.py]=1 # Long test - might work? Control flow?
|
||||
[test_queue.py]=1 # Control flow?
|
||||
[test_re.py]=1 # Probably Control flow?
|
||||
@@ -105,7 +105,6 @@ case $PYVERSION in
|
||||
[test_curses.py]=1 # Possibly fails on its own but not detected
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_doctest.py]=1 # Fails on its own
|
||||
[test_format.py]=1 # control flow. uncompyle2 does not have problems here
|
||||
[test_generators.py]=1 # control flow. uncompyle2 has problem here too
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
[test_io.py]=1 # Test takes too long to run
|
||||
|
@@ -20,8 +20,7 @@ Step 2: Run the test:
|
||||
test_pyenvlib --mylib --verify # decompile verify 'mylib'
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from uncompyle6 import main, PYTHON3
|
||||
import os, time, re, shutil, sys
|
||||
from fnmatch import fnmatch
|
||||
|
||||
|
@@ -27,8 +27,6 @@ Step 2: Run the test:
|
||||
test_pythonlib.py --mylib --verify # decompile verify 'mylib'
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import getopt, os, py_compile, sys, shutil, tempfile, time
|
||||
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
@@ -130,8 +128,10 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
|
||||
if opts['do_compile']:
|
||||
compiled_version = opts['compiled_version']
|
||||
if compiled_version and PYTHON_VERSION != compiled_version:
|
||||
print("Not compiling: desired Python version is %s but we are running %s" %
|
||||
(compiled_version, PYTHON_VERSION), file=sys.stderr)
|
||||
sys.stderr.write("Not compiling: "
|
||||
"desired Python version is %s "
|
||||
"but we are running %s" %
|
||||
(compiled_version, PYTHON_VERSION))
|
||||
else:
|
||||
for root, dirs, basenames in os.walk(src_dir):
|
||||
file_matches(files, root, basenames, PY)
|
||||
@@ -149,8 +149,8 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
|
||||
file_matches(files, dirname, basenames, obj_patterns)
|
||||
|
||||
if not files:
|
||||
print("Didn't come up with any files to test! Try with --compile?",
|
||||
file=sys.stderr)
|
||||
sys.stderr.write("Didn't come up with any files to test! "
|
||||
"Try with --compile?")
|
||||
exit(1)
|
||||
|
||||
os.chdir(cwd)
|
||||
@@ -164,9 +164,9 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
print(time.ctime())
|
||||
print('Source directory: ', src_dir)
|
||||
print('Output directory: ', target_dir)
|
||||
print time.ctime()
|
||||
print 'Source directory: ', src_dir
|
||||
print 'Output directory: ', target_dir
|
||||
try:
|
||||
_, _, failed_files, failed_verify = \
|
||||
main(src_dir, target_dir, files, [],
|
||||
@@ -242,14 +242,13 @@ if __name__ == '__main__':
|
||||
if os.path.isdir(src_dir):
|
||||
checked_dirs.append([src_dir, pattern, target_dir])
|
||||
else:
|
||||
print("Can't find directory %s. Skipping" % src_dir,
|
||||
file=sys.stderr)
|
||||
sys.stderr.write("Can't find directory %s. Skipping" % src_dir)
|
||||
continue
|
||||
last_compile_version = compiled_version
|
||||
pass
|
||||
|
||||
if not checked_dirs:
|
||||
print("No directories found to check", file=sys.stderr)
|
||||
sys.stderr.write("No directories found to check\n")
|
||||
sys.exit(1)
|
||||
|
||||
test_opts['compiled_version'] = last_compile_version
|
||||
|
@@ -3,7 +3,6 @@
|
||||
#
|
||||
# Copyright (c) 2015-2016, 2018 by Rocky Bernstein <rb@dustyfeet.com>
|
||||
#
|
||||
from __future__ import print_function
|
||||
import sys, os, getopt
|
||||
|
||||
from uncompyle6.disas import disassemble_file
|
||||
@@ -13,8 +12,8 @@ program, ext = os.path.splitext(os.path.basename(__file__))
|
||||
|
||||
__doc__ = """
|
||||
Usage:
|
||||
{0} [OPTIONS]... FILE
|
||||
{0} [--help | -h | -V | --version]
|
||||
%s [OPTIONS]... FILE
|
||||
%s [--help | -h | -V | --version]
|
||||
|
||||
Disassemble FILE with the instruction mangling that is done to
|
||||
assist uncompyle6 in parsing the instruction stream. For example
|
||||
@@ -23,9 +22,9 @@ BUILD_LIST have arguement counts appended to the instruction name, and
|
||||
COME_FROM instructions are inserted into the instruction stream.
|
||||
|
||||
Examples:
|
||||
{0} foo.pyc
|
||||
{0} foo.py # same thing as above but find the file
|
||||
{0} foo.pyc bar.pyc # disassemble foo.pyc and bar.pyc
|
||||
%s foo.pyc
|
||||
%s foo.py # same thing as above but find the file
|
||||
%s foo.pyc bar.pyc # disassemble foo.pyc and bar.pyc
|
||||
|
||||
See also `pydisasm' from the `xdis' package.
|
||||
|
||||
@@ -33,7 +32,7 @@ Options:
|
||||
-V | --version show version and stop
|
||||
-h | --help show this message
|
||||
|
||||
""".format(program)
|
||||
""" % ((program,) * 5)
|
||||
|
||||
PATTERNS = ('*.pyc', '*.pyo')
|
||||
|
||||
@@ -42,15 +41,15 @@ def main():
|
||||
Type -h for for full help.""" % program
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
print("No file(s) given", file=sys.stderr)
|
||||
print(Usage_short, file=sys.stderr)
|
||||
sys.stderr.write("No file(s) given\n")
|
||||
sys.stderr.write(Usage_short)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
opts, files = getopt.getopt(sys.argv[1:], 'hVU',
|
||||
['help', 'version', 'uncompyle6'])
|
||||
except getopt.GetoptError as e:
|
||||
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
||||
except getopt.GetoptError(e):
|
||||
sys.stderr.write('%s: %s' % (os.path.basename(sys.argv[0]), e))
|
||||
sys.exit(-1)
|
||||
|
||||
for opt, val in opts:
|
||||
@@ -62,15 +61,14 @@ Type -h for for full help.""" % program
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(opt)
|
||||
print(Usage_short, file=sys.stderr)
|
||||
sys.stderr.write(Usage_short)
|
||||
sys.exit(1)
|
||||
|
||||
for file in files:
|
||||
if os.path.exists(files[0]):
|
||||
disassemble_file(file, sys.stdout)
|
||||
else:
|
||||
print("Can't read %s - skipping" % files[0],
|
||||
file=sys.stderr)
|
||||
sys.stderr.write("Can't read %s - skipping\n" % files[0])
|
||||
pass
|
||||
pass
|
||||
return
|
||||
|
@@ -4,7 +4,6 @@
|
||||
# Copyright (c) 2015-2017 by Rocky Bernstein
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
from __future__ import print_function
|
||||
import sys, os, getopt, time
|
||||
|
||||
program = 'uncompyle6'
|
||||
@@ -69,13 +68,11 @@ def usage():
|
||||
|
||||
|
||||
def main_bin():
|
||||
if not (sys.version_info[0:2] in ((2, 6), (2, 7), (3, 0),
|
||||
(3, 1), (3, 2), (3, 3),
|
||||
(3, 4), (3, 5), (3, 6),
|
||||
(3, 7)
|
||||
)):
|
||||
print('Error: %s requires Python 2.6-3.7' % program,
|
||||
file=sys.stderr)
|
||||
if not (sys.version_info[0:2] in ((2, 4), (2, 5), (2, 6), (2, 7),
|
||||
(3, 2), (3, 3),
|
||||
(3, 4), (3, 5), (3, 6), (3, 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)
|
||||
sys.exit(-1)
|
||||
|
||||
do_verify = recurse_dirs = False
|
||||
@@ -93,8 +90,8 @@ def main_bin():
|
||||
'fragments verify verify-run version '
|
||||
'weak-verify '
|
||||
'showgrammar'.split(' '))
|
||||
except getopt.GetoptError as e:
|
||||
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
||||
except getopt.GetoptError(e):
|
||||
sys.stderr.write('%s: %s\n' % (os.path.basename(sys.argv[0]), e))
|
||||
sys.exit(-1)
|
||||
|
||||
options = {}
|
||||
@@ -137,7 +134,7 @@ def main_bin():
|
||||
elif opt in ('--recurse', '-r'):
|
||||
recurse_dirs = True
|
||||
else:
|
||||
print(opt, file=sys.stderr)
|
||||
sys.stderr.write(opt)
|
||||
usage()
|
||||
|
||||
# expand directory if specified
|
||||
@@ -162,7 +159,7 @@ def main_bin():
|
||||
files = [f[sb_len:] for f in files]
|
||||
|
||||
if not files:
|
||||
print("No files given", file=sys.stderr)
|
||||
sys.stderr.write("No files given\n")
|
||||
usage()
|
||||
|
||||
if outfile == '-':
|
||||
|
@@ -29,8 +29,6 @@ Second, we need structured instruction information for the
|
||||
want to run on earlier Python versions.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
from collections import deque
|
||||
|
||||
@@ -49,10 +47,9 @@ def disco(version, co, out=None, is_pypy=False):
|
||||
|
||||
# store final output stream for case of error
|
||||
real_out = out or sys.stdout
|
||||
print('# Python %s' % version, file=real_out)
|
||||
real_out.write('# Python %s\n' % version)
|
||||
if co.co_filename:
|
||||
print('# Embedded file name: %s' % co.co_filename,
|
||||
file=real_out)
|
||||
real_out.write('# Embedded file name: %s\n' % co.co_filename)
|
||||
|
||||
scanner = get_scanner(version, is_pypy=is_pypy)
|
||||
|
||||
@@ -64,32 +61,18 @@ def disco_loop(disasm, queue, real_out):
|
||||
while len(queue) > 0:
|
||||
co = queue.popleft()
|
||||
if co.co_name != '<module>':
|
||||
print('\n# %s line %d of %s' %
|
||||
(co.co_name, co.co_firstlineno, co.co_filename),
|
||||
file=real_out)
|
||||
real_out.write('\n# %s line %d of %s\n' %
|
||||
(co.co_name, co.co_firstlineno, co.co_filename))
|
||||
tokens, customize = disasm(co)
|
||||
for t in tokens:
|
||||
if iscode(t.pattr):
|
||||
queue.append(t.pattr)
|
||||
elif iscode(t.attr):
|
||||
queue.append(t.attr)
|
||||
print(t, file=real_out)
|
||||
real_out.write(t)
|
||||
pass
|
||||
pass
|
||||
|
||||
def disassemble_fp(fp, outstream=None):
|
||||
"""
|
||||
disassemble Python byte-code from an open file
|
||||
"""
|
||||
(version, timestamp, magic_int, co, is_pypy,
|
||||
source_size) = load_from_fp(fp)
|
||||
if type(co) == list:
|
||||
for con in co:
|
||||
disco(version, con, outstream)
|
||||
else:
|
||||
disco(version, co, outstream, is_pypy=is_pypy)
|
||||
co = None
|
||||
|
||||
def disassemble_file(filename, outstream=None):
|
||||
"""
|
||||
disassemble Python byte-code file (.pyc)
|
||||
|
@@ -25,7 +25,7 @@ def line_number_mapping(pyc_filename, src_filename):
|
||||
source_size) = load_module(pyc_filename)
|
||||
try:
|
||||
code2 = load_file(src_filename)
|
||||
except SyntaxError as e:
|
||||
except SyntaxError, e:
|
||||
return str(e)
|
||||
|
||||
queue = deque([code1, code2])
|
||||
|
@@ -12,10 +12,10 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from __future__ import print_function
|
||||
import datetime, os, subprocess, sys, tempfile
|
||||
|
||||
from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION
|
||||
import datetime, os, subprocess, sys
|
||||
|
||||
from uncompyle6 import verify, IS_PYPY
|
||||
from xdis.code import iscode
|
||||
from uncompyle6.disas import check_object_path
|
||||
from uncompyle6.semantics import pysource
|
||||
@@ -38,11 +38,7 @@ def _get_outstream(outfile):
|
||||
os.makedirs(dir)
|
||||
except OSError:
|
||||
pass
|
||||
if PYTHON_VERSION < 3.0:
|
||||
mode = 'wb'
|
||||
else:
|
||||
mode = 'w'
|
||||
return open(outfile, mode)
|
||||
return open(outfile, 'wb')
|
||||
|
||||
def decompile(
|
||||
bytecode_version, co, out=None, showasm=None, showast=False,
|
||||
@@ -63,20 +59,35 @@ def decompile(
|
||||
|
||||
assert iscode(co)
|
||||
|
||||
co_pypy_str = 'PyPy ' if is_pypy else ''
|
||||
run_pypy_str = 'PyPy ' if IS_PYPY else ''
|
||||
if is_pypy:
|
||||
co_pypy_str = 'PyPy '
|
||||
else:
|
||||
co_pypy_str = ''
|
||||
|
||||
if IS_PYPY:
|
||||
run_pypy_str = 'PyPy '
|
||||
else:
|
||||
run_pypy_str = ''
|
||||
|
||||
if magic_int:
|
||||
m = str(magic_int)
|
||||
else:
|
||||
m = ""
|
||||
|
||||
sys_version_lines = sys.version.split('\n')
|
||||
write('# uncompyle6 version %s\n'
|
||||
'# %sPython bytecode %s%s\n# Decompiled from: %sPython %s' %
|
||||
(VERSION, co_pypy_str, bytecode_version,
|
||||
" (%s)" % str(magic_int) if magic_int else "",
|
||||
run_pypy_str, '\n# '.join(sys_version_lines)))
|
||||
" (%s)" % m, run_pypy_str,
|
||||
'\n# '.join(sys_version_lines)))
|
||||
if co.co_filename:
|
||||
write('# Embedded file name: %s' % co.co_filename,)
|
||||
if timestamp:
|
||||
write('# Compiled at: %s' % datetime.datetime.fromtimestamp(timestamp))
|
||||
write('# Compiled at: %s' %
|
||||
datetime.datetime.fromtimestamp(timestamp))
|
||||
if source_size:
|
||||
write('# Size of source mod 2**32: %d bytes' % source_size)
|
||||
real_out.write('# Size of source mod 2**32: %d bytes\n' %
|
||||
source_size)
|
||||
|
||||
debug_opts = {
|
||||
'asm': showasm,
|
||||
@@ -109,7 +120,7 @@ def decompile(
|
||||
is_pypy=is_pypy)
|
||||
pass
|
||||
return deparsed
|
||||
except pysource.SourceWalkerError as e:
|
||||
except pysource.SourceWalkerError, e:
|
||||
# deparsing failed
|
||||
raise pysource.SourceWalkerError(str(e))
|
||||
|
||||
@@ -189,17 +200,10 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
prefix = prefix[:-len('.py')]
|
||||
|
||||
# Unbuffer output if possible
|
||||
buffering = -1 if sys.stdout.isatty() else 0
|
||||
if PYTHON_VERSION >= 3.5:
|
||||
t = tempfile.NamedTemporaryFile(mode='w+b',
|
||||
buffering=buffering,
|
||||
suffix='.py',
|
||||
prefix=prefix)
|
||||
if sys.stdout.isatty():
|
||||
buffering = -1
|
||||
else:
|
||||
t = tempfile.NamedTemporaryFile(mode='w+b',
|
||||
suffix='.py',
|
||||
prefix=prefix)
|
||||
current_outfile = t.name
|
||||
buffering = 0
|
||||
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering)
|
||||
tee = subprocess.Popen(["tee", current_outfile],
|
||||
stdin=subprocess.PIPE)
|
||||
@@ -238,9 +242,9 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
pass
|
||||
pass
|
||||
tot_files += 1
|
||||
except (ValueError, SyntaxError, ParserError, pysource.SourceWalkerError) as e:
|
||||
except (ValueError, SyntaxError, ParserError, pysource.SourceWalkerError):
|
||||
sys.stdout.write("\n")
|
||||
sys.stderr.write("\n# file %s\n# %s\n" % (infile, e))
|
||||
sys.stderr.write("# file %s\n" % (infile))
|
||||
failed_files += 1
|
||||
tot_files += 1
|
||||
except KeyboardInterrupt:
|
||||
@@ -278,13 +282,16 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
else:
|
||||
okay_files += 1
|
||||
pass
|
||||
except verify.VerifyCmpError as e:
|
||||
except verify.VerifyCmpError, e:
|
||||
print(e)
|
||||
verify_failed_files += 1
|
||||
os.rename(current_outfile, current_outfile + '_unverified')
|
||||
sys.stderr.write("### Error Verifying %s\n" % filename)
|
||||
sys.stderr.write(str(e) + "\n")
|
||||
if not outfile:
|
||||
sys.stderr.write("### Error Verifiying %s" %
|
||||
filename)
|
||||
sys.stderr.write(e)
|
||||
if raise_on_error:
|
||||
raise
|
||||
pass
|
||||
@@ -294,14 +301,15 @@ def main(in_base, out_base, files, codes, outfile=None,
|
||||
okay_files += 1
|
||||
pass
|
||||
elif do_verify:
|
||||
sys.stderr.write("\n### uncompile successful, but no file to compare against\n")
|
||||
sys.stderr.write("\n### uncompile successful, "
|
||||
"but no file to compare against")
|
||||
pass
|
||||
else:
|
||||
okay_files += 1
|
||||
if not current_outfile:
|
||||
mess = '\n# okay decompiling'
|
||||
# mem_usage = __memUsage()
|
||||
print(mess, infile)
|
||||
print mess, infile
|
||||
if current_outfile:
|
||||
sys.stdout.write("%s\r" %
|
||||
status_msg(do_verify, tot_files, okay_files, failed_files,
|
||||
|
@@ -19,8 +19,6 @@
|
||||
Common uncompyle6 parser routines.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
from xdis.code import iscode
|
||||
@@ -181,7 +179,7 @@ class PythonParser(GenericASTBuilder):
|
||||
indent = ' '
|
||||
else:
|
||||
indent = '-> '
|
||||
print("%s%s" % (indent, instructions[i]))
|
||||
print "%s%s" % (indent, instructions[i])
|
||||
raise ParserError(err_token, err_token.offset)
|
||||
else:
|
||||
raise ParserError(None, -1)
|
||||
@@ -620,25 +618,18 @@ def get_python_parser(
|
||||
# a lazy way of doing the import?
|
||||
|
||||
if version < 3.0:
|
||||
if version < 2.2:
|
||||
if version == 1.4:
|
||||
import uncompyle6.parsers.parse14 as parse14
|
||||
if compile_mode == 'exec':
|
||||
p = parse14.Python14Parser(debug_parser)
|
||||
else:
|
||||
p = parse14.Python14ParserSingle(debug_parser)
|
||||
elif version == 1.5:
|
||||
import uncompyle6.parsers.parse15 as parse15
|
||||
if compile_mode == 'exec':
|
||||
p = parse15.Python15Parser(debug_parser)
|
||||
else:
|
||||
p = parse15.Python15ParserSingle(debug_parser)
|
||||
elif version == 2.1:
|
||||
import uncompyle6.parsers.parse21 as parse21
|
||||
if compile_mode == 'exec':
|
||||
p = parse21.Python21Parser(debug_parser)
|
||||
else:
|
||||
p = parse21.Python21ParserSingle(debug_parser)
|
||||
if version == 1.5:
|
||||
import uncompyle6.parsers.parse15 as parse15
|
||||
if compile_mode == 'exec':
|
||||
p = parse15.Python15Parser(debug_parser)
|
||||
else:
|
||||
p = parse15.Python15ParserSingle(debug_parser)
|
||||
elif version == 2.1:
|
||||
import uncompyle6.parsers.parse21 as parse21
|
||||
if compile_mode == 'exec':
|
||||
p = parse21.Python21Parser(debug_parser)
|
||||
else:
|
||||
p = parse21.Python21ParserSingle(debug_parser)
|
||||
elif version == 2.2:
|
||||
import uncompyle6.parsers.parse22 as parse22
|
||||
if compile_mode == 'exec':
|
||||
@@ -788,4 +779,4 @@ if __name__ == '__main__':
|
||||
ast = python_parser(PYTHON_VERSION, co, showasm=True, is_pypy=IS_PYPY)
|
||||
print(ast)
|
||||
return
|
||||
parse_test(parse_test.__code__)
|
||||
# parse_test(parse_test.__code__)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user