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
420 Commits
release-2.
...
release-2.
Author | SHA1 | Date | |
---|---|---|---|
|
af10f99776 | ||
|
0cbafa6e3a | ||
|
4afaee2a36 | ||
|
daea3c348c | ||
|
bf45260588 | ||
|
34a356d237 | ||
|
d9c1374a59 | ||
|
2e05137f2b | ||
|
267ecda070 | ||
|
7e89839777 | ||
|
c7f8edd5ef | ||
|
6a991833a3 | ||
|
28ee3f1257 | ||
|
e9588e56e2 | ||
|
7b2217fda4 | ||
|
5ca219f3d3 | ||
|
b733a1b036 | ||
|
4615cda03f | ||
|
eb92418224 | ||
|
844221cd43 | ||
|
7c299fbf37 | ||
|
da695115b5 | ||
|
f1d9e194fe | ||
|
e727a437ea | ||
|
9a3e11a957 | ||
|
966a4bc7dc | ||
|
ad98fae3d4 | ||
|
cbbf64ccd0 | ||
|
394120bb1a | ||
|
7257ba41c5 | ||
|
9eee4eccd7 | ||
|
cf3c07e047 | ||
|
d93b7a9eae | ||
|
5ebb731c04 | ||
|
d3794ec9af | ||
|
2ab7aa2f48 | ||
|
49fd430505 | ||
|
2a47f0309f | ||
|
3084ac20e9 | ||
|
9c846c309e | ||
|
b4efa62fad | ||
|
94d1c6dfd3 | ||
|
6991a637a2 | ||
|
52b1f4d2b6 | ||
|
0ce804ae16 | ||
|
d2502f205e | ||
|
2ad40a5648 | ||
|
d1a695b2bd | ||
|
47b6a35abc | ||
|
b1e32c7cc5 | ||
|
47977b3372 | ||
|
2a7a166696 | ||
|
ea732acf49 | ||
|
da884487d5 | ||
|
ff73efcf8e | ||
|
a32c0e68ef | ||
|
73857c831b | ||
|
4c2ca44818 | ||
|
3e7add1138 | ||
|
69fd1b3371 | ||
|
d540146d5a | ||
|
e9a17010c7 | ||
|
038692dbf9 | ||
|
93437152a2 | ||
|
b952f56c44 | ||
|
ca1679e636 | ||
|
8d084ed358 | ||
|
a10914a645 | ||
|
9c0ef9fa63 | ||
|
449d74af51 | ||
|
f8a40c1949 | ||
|
e10e184eda | ||
|
605721c995 | ||
|
50d875f6a6 | ||
|
26e8de8532 | ||
|
89d8a70778 | ||
|
1093ef5c5b | ||
|
dcaca27821 | ||
|
4a47822904 | ||
|
4e9555a7f6 | ||
|
d1c0413b79 | ||
|
93ec81673b | ||
|
0cf5f41fda | ||
|
246495febd | ||
|
91b86ac156 | ||
|
26cd91046e | ||
|
b42c66e091 | ||
|
364827a2f2 | ||
|
819458564c | ||
|
486f313532 | ||
|
84fd71b73b | ||
|
50687e6317 | ||
|
b35546157f | ||
|
7755dddd94 | ||
|
ce1e841255 | ||
|
68f0f79030 | ||
|
bf195a234f | ||
|
87db833f62 | ||
|
8081decf7c | ||
|
e5008693a1 | ||
|
810649799c | ||
|
d4be647bce | ||
|
4a898ff4c1 | ||
|
cb6925beec | ||
|
2665f292c5 | ||
|
33be34c6fb | ||
|
3bbc94847d | ||
|
3a8d4e1a12 | ||
|
87e005a7ba | ||
|
5477ca294d | ||
|
31c28d0220 | ||
|
659e28d686 | ||
|
8a33a583cd | ||
|
8a776176e2 | ||
|
03498963d4 | ||
|
47dbc57f3d | ||
|
39b9810587 | ||
|
8cdaac93ab | ||
|
a9f7a3c6d0 | ||
|
495bdd7b64 | ||
|
b4ded92822 | ||
|
be9194c223 | ||
|
45bd8e4058 | ||
|
bb24df596d | ||
|
6acec471e3 | ||
|
41343c27b7 | ||
|
9e34654b38 | ||
|
b9703cf6b4 | ||
|
792df2a7a7 | ||
|
b4a6c3c319 | ||
|
4199bc7f61 | ||
|
91e1d2538f | ||
|
6773a66b99 | ||
|
ed6cb9af79 | ||
|
a91cd71667 | ||
|
6f82ae3642 | ||
|
4e05c741e3 | ||
|
fdcb90f661 | ||
|
f416473562 | ||
|
5856802902 | ||
|
4f2ae2f603 | ||
|
ea1651d8ca | ||
|
be769da401 | ||
|
cb3c5e7119 | ||
|
39e3582e72 | ||
|
a0c090932e | ||
|
d1e118afa3 | ||
|
f7da8fd8ab | ||
|
3b1dd9d1c4 | ||
|
91fd1ce732 | ||
|
a46e7cbfa4 | ||
|
d46873c44d | ||
|
54e50771ab | ||
|
160ec0d9cc | ||
|
e1111e3f50 | ||
|
65913778a5 | ||
|
cf21fff38b | ||
|
29122340e6 | ||
|
1e3ea60055 | ||
|
2fbbc728b1 | ||
|
0a6c8ba909 | ||
|
d3904527e6 | ||
|
b043f6bafc | ||
|
aa207a3c77 | ||
|
747212c62c | ||
|
493e4b14a1 | ||
|
9491c67779 | ||
|
8ef5e5d12b | ||
|
222986640e | ||
|
f9d47abb2b | ||
|
31ed869a6f | ||
|
19d2569515 | ||
|
9348411056 | ||
|
e71dd010d7 | ||
|
dadd1c5c45 | ||
|
99af1c9ffe | ||
|
3dc766d0a9 | ||
|
357005c814 | ||
|
41d63a0261 | ||
|
1cb2cd7a82 | ||
|
9ec312ba5e | ||
|
597d51951e | ||
|
cc2321f49e | ||
|
476a1c8ab5 | ||
|
545a46dffa | ||
|
8333e4ae93 | ||
|
e9057f378a | ||
|
36b75abd90 | ||
|
1528537ca4 | ||
|
6b8ae29267 | ||
|
33ec66a82f | ||
|
b0493d1984 | ||
|
7f37c60c42 | ||
|
e2fd308928 | ||
|
6d7cec002a | ||
|
9c49b5d54b | ||
|
8dc23e2cdc | ||
|
a01b8be054 | ||
|
114fe11e66 | ||
|
b131c20e99 | ||
|
5db1178b3e | ||
|
7ece296f76 | ||
|
5035d5433b | ||
|
78a5b620a7 | ||
|
e851c0d46a | ||
|
a760188724 | ||
|
ad345ef94a | ||
|
d050dd3adb | ||
|
9392103998 | ||
|
707770049f | ||
|
ec0669367f | ||
|
3f40c16587 | ||
|
66518baed0 | ||
|
21023fea74 | ||
|
66741d16ba | ||
|
e02ebef45d | ||
|
99fce6dfd7 | ||
|
7b8c5e091c | ||
|
77caf515ea | ||
|
e4c0d56947 | ||
|
4827b1e994 | ||
|
2b46e71264 | ||
|
84c2932bc5 | ||
|
874b3c9d31 | ||
|
f6a997befc | ||
|
136f42a610 | ||
|
c43e734f37 | ||
|
2327f0fdfa | ||
|
0afcd31bd5 | ||
|
6f097ff1ca | ||
|
8eb1a16f5b | ||
|
ed9fb64e72 | ||
|
d002c667ae | ||
|
e56743cc14 | ||
|
39814fab8b | ||
|
970774ab95 | ||
|
723fa5dfed | ||
|
4d4e59c40b | ||
|
a92e6c9688 | ||
|
6c546fe6e1 | ||
|
9b1dd0f26c | ||
|
0ff0c97a95 | ||
|
3e988be075 | ||
|
eb64a03dfa | ||
|
9aa4e2b9ae | ||
|
c147514e9e | ||
|
813229ac45 | ||
|
f1a947f106 | ||
|
2f51067a9d | ||
|
e3f4beeb74 | ||
|
7d58dcf6dd | ||
|
bfff1b4e9f | ||
|
e6761e13bb | ||
|
c7c0a98982 | ||
|
eebec48308 | ||
|
da50394841 | ||
|
13d5cd1a58 | ||
|
08dcc7d820 | ||
|
7755563b65 | ||
|
b43cbc050d | ||
|
db7a26d47d | ||
|
92166452c1 | ||
|
96fa3ef381 | ||
|
755415c7d8 | ||
|
b168e1de55 | ||
|
38eed14b41 | ||
|
2c993f8c32 | ||
|
65858a4c74 | ||
|
263c63e009 | ||
|
813bce4697 | ||
|
a5d2237435 | ||
|
d22931cb49 | ||
|
9cc2700160 | ||
|
a5a0f45dde | ||
|
3c02fa7e36 | ||
|
0d0f836f76 | ||
|
69c93cc665 | ||
|
97576e473d | ||
|
1e324e0e8d | ||
|
7ab4e1fbdb | ||
|
abecb21671 | ||
|
8be6369bdf | ||
|
8941417a54 | ||
|
cbcfd53dae | ||
|
df2ca51f4a | ||
|
4f4069c6b5 | ||
|
6aa1531972 | ||
|
4fcb385dc0 | ||
|
260ddedbfd | ||
|
f8917aaf88 | ||
|
c8550d5c9e | ||
|
1aeb09cb8b | ||
|
f575234fc8 | ||
|
abcd10628a | ||
|
eb2b63ce9c | ||
|
805e17988e | ||
|
80df5dcc95 | ||
|
2bc316d6f0 | ||
|
195bbc746b | ||
|
0f56b4f476 | ||
|
94719918d4 | ||
|
f2a3721d7d | ||
|
79863ae122 | ||
|
d7f898b4fb | ||
|
fe36c9e9f6 | ||
|
76ae1592d0 | ||
|
31d387749b | ||
|
9e3026bd78 | ||
|
bfe7e7777d | ||
|
81b4941fda | ||
|
0f719d41fd | ||
|
766451cbb9 | ||
|
1e4dc52197 | ||
|
6073c77921 | ||
|
b6e53205dd | ||
|
ee6dddd25a | ||
|
968a54512b | ||
|
a81ffe8963 | ||
|
3b9e48a3b6 | ||
|
80a4ad4f1b | ||
|
50c2e1bda9 | ||
|
f4999f6300 | ||
|
0f536b18fa | ||
|
6fb879d0d8 | ||
|
411eaaeafb | ||
|
36874c72e2 | ||
|
7343575e55 | ||
|
fef0567746 | ||
|
41f360e3dc | ||
|
5d10f7a0b0 | ||
|
2a5eda631a | ||
|
a685c60606 | ||
|
d2ac293cf6 | ||
|
cd3cf5ec29 | ||
|
2eaea447eb | ||
|
287e98b4b1 | ||
|
63e4c9343f | ||
|
eab653afdd | ||
|
7700446bb1 | ||
|
bfd2f77fbc | ||
|
1574bf4e1e | ||
|
2328ca7a55 | ||
|
ccdd37611c | ||
|
2e355b6245 | ||
|
9849f06ff6 | ||
|
0e7da031b2 | ||
|
25dd67a135 | ||
|
1a38d3d9aa | ||
|
de65a2c250 | ||
|
7daec3352c | ||
|
8feb472d51 | ||
|
7a10917857 | ||
|
334f6935b6 | ||
|
aff920d87b | ||
|
6319d33fa0 | ||
|
abb61a4d7d | ||
|
b54a19c6ff | ||
|
a4c943fe0d | ||
|
0480455ae1 | ||
|
9b7d978944 | ||
|
a6befdee09 | ||
|
d6f7ef4e17 | ||
|
cec80e696c | ||
|
0826129112 | ||
|
7beaa9f36c | ||
|
78ef16e4d7 | ||
|
59b597ea5d | ||
|
cb8ffa51d7 | ||
|
a7ef513849 | ||
|
8e62a48c96 | ||
|
6d3b934bf2 | ||
|
27fb5758bd | ||
|
5703ccd8b8 | ||
|
20ba165e4a | ||
|
7eb9210b0c | ||
|
fe072d8b57 | ||
|
f430b0dbe4 | ||
|
9ef670c872 | ||
|
c04fe00e50 | ||
|
52691c4e8a | ||
|
f067148b6c | ||
|
bb8d0a6389 | ||
|
97ce330b00 | ||
|
8b240a80e7 | ||
|
e888a87d15 | ||
|
f41426e94b | ||
|
22dee55ff7 | ||
|
8916447adb | ||
|
478602bfa5 | ||
|
056f600da1 | ||
|
2e1bd2dc13 | ||
|
346d8678d2 | ||
|
4411ecceba | ||
|
a4dd6e9805 | ||
|
b52f341d46 | ||
|
2ada29618f | ||
|
649e4518fe | ||
|
0df2c8b4bb | ||
|
d2b477ae7d | ||
|
a8f9f2170f | ||
|
fe46015b78 | ||
|
051efb80f5 | ||
|
1fc8ac4700 | ||
|
c87710dd4b | ||
|
ccd129b377 | ||
|
c03a8186b5 | ||
|
8bc76f19b9 | ||
|
6908898b90 | ||
|
fa1a6347e9 | ||
|
760532b218 | ||
|
88f2ad1f5a | ||
|
d271e886d9 | ||
|
c0b4a5e703 | ||
|
b6dee24289 | ||
|
0e9ebca1a5 | ||
|
f3b9a5936e | ||
|
bae3d2e361 | ||
|
4f83a87a00 | ||
|
d8b7c3d813 | ||
|
c119965d96 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,7 +1,7 @@
|
|||||||
|
*.pyo
|
||||||
*.pyc
|
*.pyc
|
||||||
*_dis
|
*_dis
|
||||||
*~
|
*~
|
||||||
*.pyc
|
|
||||||
/.cache
|
/.cache
|
||||||
/.eggs
|
/.eggs
|
||||||
/.python-version
|
/.python-version
|
||||||
@@ -13,5 +13,8 @@
|
|||||||
/nose-*.egg
|
/nose-*.egg
|
||||||
/tmp
|
/tmp
|
||||||
/uncompyle6.egg-info
|
/uncompyle6.egg-info
|
||||||
|
/unpyc
|
||||||
__pycache__
|
__pycache__
|
||||||
build
|
build
|
||||||
|
/.venv*
|
||||||
|
/.idea
|
@@ -8,9 +8,11 @@ python:
|
|||||||
- '2.6'
|
- '2.6'
|
||||||
- '3.3'
|
- '3.3'
|
||||||
- '3.4'
|
- '3.4'
|
||||||
|
- '3.2'
|
||||||
|
- '3.6'
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- pip install -r requirements.txt
|
- pip install -e .
|
||||||
- pip install -r requirements-dev.txt
|
- pip install -r requirements-dev.txt
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
59
HISTORY.md
59
HISTORY.md
@@ -29,7 +29,9 @@ augmented with pseudo instruction COME_FROM. This code introduced
|
|||||||
another clever idea: using table-driven semantics routines, using
|
another clever idea: using table-driven semantics routines, using
|
||||||
format specifiers.
|
format specifiers.
|
||||||
|
|
||||||
The last mention of a release of SPARK from John is around 2002.
|
The last mention of a release of SPARK from John is around 2002. As
|
||||||
|
released, although the Earley Algorithm parser was in good shape, this
|
||||||
|
code was woefully lacking as serious Python deparser.
|
||||||
|
|
||||||
In the fall of 2000, Hartmut Goebel
|
In the fall of 2000, Hartmut Goebel
|
||||||
[took over maintaining the code](https://groups.google.com/forum/#!searchin/comp.lang.python/hartmut$20goebel/comp.lang.python/35s3mp4-nuY/UZALti6ujnQJ). The
|
[took over maintaining the code](https://groups.google.com/forum/#!searchin/comp.lang.python/hartmut$20goebel/comp.lang.python/35s3mp4-nuY/UZALti6ujnQJ). The
|
||||||
@@ -42,7 +44,8 @@ it appears that Hartmut did most of the work to get this code to
|
|||||||
accept the full Python language. He added precedence to the table
|
accept the full Python language. He added precedence to the table
|
||||||
specifiers, support for multiple versions of Python, the
|
specifiers, support for multiple versions of Python, the
|
||||||
pretty-printing of docstrings, lists, and hashes. He also wrote test and verification routines of
|
pretty-printing of docstrings, lists, and hashes. He also wrote test and verification routines of
|
||||||
deparsed bytecode, and used this in an extensive set of tests that he also wrote. He could verify against the entire Python library.
|
deparsed bytecode, and used this in an extensive set of tests that he also wrote. He says he could verify against the
|
||||||
|
entire Python library. However I have subsequently found small and relatively obscure bugs in the decompilation code.
|
||||||
|
|
||||||
decompyle2.2 was packaged for Debian (sarge) by
|
decompyle2.2 was packaged for Debian (sarge) by
|
||||||
[Ben Burton around 2002](https://packages.qa.debian.org/d/decompyle.html). As
|
[Ben Burton around 2002](https://packages.qa.debian.org/d/decompyle.html). As
|
||||||
@@ -63,10 +66,12 @@ code to handle first Python 2.3 and then 2.4 bytecodes. Because of
|
|||||||
jump optimization introduced in the CPython bytecode compiler at that
|
jump optimization introduced in the CPython bytecode compiler at that
|
||||||
time, various JUMP instructions were classifed as going backwards, and
|
time, various JUMP instructions were classifed as going backwards, and
|
||||||
COME FROM instructions were reintroduced. See
|
COME FROM instructions were reintroduced. See
|
||||||
RELEASE-2.4-CHANGELOG.txt for more details here. There wasn't a public
|
[RELEASE-2.4-CHANGELOG.txt](https://github.com/rocky/python-uncompyle6/blob/master/DECOMPYLE-2.4-CHANGELOG.txt)
|
||||||
|
for more details here. There wasn't a public
|
||||||
release of RELEASE-2.4 and bytecodes other than Python 2.4 weren't
|
release of RELEASE-2.4 and bytecodes other than Python 2.4 weren't
|
||||||
supported. Dan says the Python 2.3 version could verify the entire
|
supported. Dan says the Python 2.3 version could verify the entire
|
||||||
python library.
|
Python library. But given subsequent bugs found like simply
|
||||||
|
recognizing complex-number constants in bytecode, decompilation wasn't perfect.
|
||||||
|
|
||||||
Next we get to ["uncompyle" and
|
Next we get to ["uncompyle" and
|
||||||
PyPI](https://pypi.python.org/pypi/uncompyle/1.1) and the era of
|
PyPI](https://pypi.python.org/pypi/uncompyle/1.1) and the era of
|
||||||
@@ -93,17 +98,17 @@ so. Then hamled made a few commits earler on, while Eike Siewertsen
|
|||||||
made a few commits later on. But mostly wibiti, and Guenther
|
made a few commits later on. But mostly wibiti, and Guenther
|
||||||
Starnberger got the code to where uncompyle2 was around 2012.
|
Starnberger got the code to where uncompyle2 was around 2012.
|
||||||
|
|
||||||
In uncompyle2 decompilation of python bytecode 2.5 & 2.6 is done by
|
In `uncompyle`, decompilation of python bytecode 2.5 & 2.6 is done by
|
||||||
transforming the byte code into a a pseudo 2.7 python bytecode and is
|
transforming the byte code into a a pseudo 2.7 python bytecode and is
|
||||||
based on code from Eloi Vanderbeken.
|
based on code from Eloi Vanderbeken.
|
||||||
|
|
||||||
This project, uncompyle6, abandons that approach for various
|
This project, `uncompyle6`, abandons that approach for various
|
||||||
reasons. However the main reason is that we need offsets in fragment
|
reasons. However the main reason is that we need offsets in fragment
|
||||||
deparsing to be exactly the same, and the transformation process can
|
deparsing to be exactly the same, and the transformation process can
|
||||||
remove instructions. Adding instructions with psuedo_offsets is
|
remove instructions. _Adding_ instructions with psuedo offsets is
|
||||||
however okay.
|
however okay.
|
||||||
|
|
||||||
Uncompyle6, however owes its existence to the fork of uncompyle2 by
|
`Uncompyle6` however owes its existence to the fork of `uncompyle2` by
|
||||||
Myst herie (Mysterie) whose first commit picks up at
|
Myst herie (Mysterie) whose first commit picks up at
|
||||||
2012. I chose this since it seemed to have been at that time the most
|
2012. I chose this since it seemed to have been at that time the most
|
||||||
actively, if briefly, worked on. Also starting around 2012 is Dark
|
actively, if briefly, worked on. Also starting around 2012 is Dark
|
||||||
@@ -112,12 +117,21 @@ Fenx's uncompyle3 which I used for inspiration for Python3 support.
|
|||||||
I started working on this late 2015, mostly to add fragment support.
|
I started working on this late 2015, mostly to add fragment support.
|
||||||
In that, I decided to make this runnable on Python 3.2+ and Python 2.6+
|
In that, I decided to make this runnable on Python 3.2+ and Python 2.6+
|
||||||
while, handling Python bytecodes from Python versions 2.5+ and
|
while, handling Python bytecodes from Python versions 2.5+ and
|
||||||
3.2+.
|
3.2+. In doing so, it has been expedient to separate this into three
|
||||||
|
projects:
|
||||||
|
|
||||||
|
* bytecode loading and disassembly ([xdis](https://pypi.python.org/pypi/xdis)),
|
||||||
|
* parsing and tree building ([spark_parser](https://pypi.python.org/pypi/spark_parser)),
|
||||||
|
* this project - grammar and semantic actions for decompiling
|
||||||
|
([uncompyle6](https://pypi.python.org/pypi/spark_parser)).
|
||||||
|
|
||||||
|
|
||||||
Over the many years, code styles and Python features have
|
Over the many years, code styles and Python features have
|
||||||
changed. However brilliant the code was and still is, it hasn't really
|
changed. However brilliant the code was and still is, it hasn't really
|
||||||
had a single public active maintainer. And there have been many forks
|
had a single public active maintainer. And there have been many forks
|
||||||
of the code.
|
of the code. I have spent a great deal of time trying to organize and
|
||||||
|
modularize the code so that it can handle more Python versions more
|
||||||
|
gracefully (with still only moderate success).
|
||||||
|
|
||||||
That it has been in need of an overhaul has been recognized by the
|
That it has been in need of an overhaul has been recognized by the
|
||||||
Hartmut a decade an a half ago:
|
Hartmut a decade an a half ago:
|
||||||
@@ -127,23 +141,26 @@ Hartmut a decade an a half ago:
|
|||||||
NB. This is not a masterpiece of software, but became more like a hack.
|
NB. This is not a masterpiece of software, but became more like a hack.
|
||||||
Probably a complete rewrite would be sensefull. hG/2000-12-27
|
Probably a complete rewrite would be sensefull. hG/2000-12-27
|
||||||
|
|
||||||
This project deparses using an Early-algorithm parse with lots of
|
This project deparses using an Earley-algorithm parse with lots of
|
||||||
massaging of tokens and the grammar in the scanner
|
massaging of tokens and the grammar in the scanner
|
||||||
phase. Early-algorithm parsers are context free and tend to be linear
|
phase. Earley-algorithm parsers are context free and tend to be linear
|
||||||
if the grammar is LR or left recursive.
|
if the grammar is LR or left recursive.
|
||||||
|
|
||||||
Another approach that doesn't use grammars is to do something like
|
Another approach that doesn't use grammars is to do something like
|
||||||
simulate execution symbolically and build expression trees off of
|
simulate execution symbolically and build expression trees off of
|
||||||
stack results. The two important projects that work this way are
|
stack results. Control flow in that apprproach still needs to be
|
||||||
[unpyc3](https://code.google.com/p/unpyc3/) and most especially
|
handled somewhat ad hoc. The two important projects that work this
|
||||||
[pycdc](https://github.com/zrax/pycdc) The latter project is largely
|
way are [unpyc3](https://code.google.com/p/unpyc3/) and most
|
||||||
by Michael Hansen and Darryl Pogue. If they supported getting
|
especially [pycdc](https://github.com/zrax/pycdc) The latter project
|
||||||
source-code fragments and I could call it from Python, I'd probably
|
is largely by Michael Hansen and Darryl Pogue. If they supported
|
||||||
ditch this and use that. From what I've seen, the code runs blindingly
|
getting source-code fragments, did a better job in supporting Python
|
||||||
fast and spans all versions of Python.
|
more fully, and had a way I could call it from Python, I'd probably
|
||||||
|
would have ditched this and used that. The code runs blindingly fast
|
||||||
|
and spans all versions of Python, although more recently Python 3
|
||||||
|
support has been lagging.
|
||||||
|
|
||||||
Tests for the project have been, or are being, culled from all of the
|
Tests for the project have been, or are being, culled from all of the
|
||||||
projects mentioned.
|
projects mentioned.
|
||||||
|
|
||||||
NB. If you find mistakes, want corrections, or want your name added (or removed),
|
NB. If you find mistakes, want corrections, or want your name added
|
||||||
please contact me.
|
(or removed), please contact me.
|
||||||
|
68
HOW-TO-REPORT-A-BUG.md
Normal file
68
HOW-TO-REPORT-A-BUG.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# How to report a Bug
|
||||||
|
|
||||||
|
## The difficulty of the problem
|
||||||
|
|
||||||
|
There is no Python decompiler yet, that I know about that will
|
||||||
|
decompyle everything. This one probably does the
|
||||||
|
best job of *any* Python decompiler. But it is a constant work in progress: Python keeps changing, and so does its code generation.
|
||||||
|
|
||||||
|
I have found bugs in *every* Python decompiler I have tried. Even
|
||||||
|
those where authors/maintainers claim that they have used it on
|
||||||
|
the entire Python standard library. And I don't mean that
|
||||||
|
the program doesn't come out with the same Python source instructions,
|
||||||
|
but that the program is *semantically* not equivalent.
|
||||||
|
|
||||||
|
So it is likely you'll find a mistranslation in decompiling.
|
||||||
|
|
||||||
|
## What to send (minimum requirements)
|
||||||
|
|
||||||
|
The basic requirement is pretty simple:
|
||||||
|
|
||||||
|
* Python bytecode
|
||||||
|
* Source text
|
||||||
|
|
||||||
|
## What to send (additional helpful information)
|
||||||
|
|
||||||
|
Some kind folks also give the invocation they used and the output
|
||||||
|
which usually includes an error message produced. This is helpful. I
|
||||||
|
can figure out what OS you are running this on and what version of
|
||||||
|
*uncomplye6* was used. Therefore, if you don't provide the input
|
||||||
|
command and the output from that, please give:
|
||||||
|
|
||||||
|
* _uncompyle6_ version used
|
||||||
|
* OS that you used this on
|
||||||
|
* Python interpreter version used
|
||||||
|
|
||||||
|
|
||||||
|
### But I don't *have* the source code!
|
||||||
|
|
||||||
|
Sure, I get it. No problem. There is Python assembly code on parse
|
||||||
|
errors, so simply by hand decompile that. To get a full disassembly,
|
||||||
|
use pydisasm from the [xdis](https://pypi.python.org/pypi/xdis)
|
||||||
|
package. Opcodes are described in the documentation for
|
||||||
|
the [dis](https://docs.python.org/3.6/library/dis.html) module.
|
||||||
|
|
||||||
|
### But I don't *have* the source code and am incapable of figuring how how to do a hand disassembly!
|
||||||
|
|
||||||
|
Well, you could learn. No one is born into this world knowing how to
|
||||||
|
disassemble Python bytecode. And as Richard Feynman once said, "What
|
||||||
|
one fool can learn, so can another."
|
||||||
|
|
||||||
|
## Narrowing the problem
|
||||||
|
|
||||||
|
I don't need the entire source code base for which one file or module
|
||||||
|
can't be decompiled. I just need that one file or module only. If
|
||||||
|
there are several files, file a bug report for each file.
|
||||||
|
|
||||||
|
Python modules can get quite large, and usually decompilation problems
|
||||||
|
occur in a single function or maybe the main-line code but not any of
|
||||||
|
the functions or classes. So please chop down the source code by
|
||||||
|
removing those parts that do to decompile properly.
|
||||||
|
|
||||||
|
By doing this, you'll probably have a better sense of what exactly is
|
||||||
|
the problem. Perhaps you can find the boundary of what decompiles, and
|
||||||
|
what doesn't. That is useful. Or maybe the same file will decompile
|
||||||
|
properly on a neighboring version of Python. That is helpful too.
|
||||||
|
|
||||||
|
In sum, the more you can isolate or narrow the problem, the more
|
||||||
|
likley the problem will be fixed and fixed sooner.
|
@@ -1,11 +1,18 @@
|
|||||||
include README.rst
|
include README.rst
|
||||||
include ChangeLog
|
include ChangeLog
|
||||||
include HISTORY.md
|
include HISTORY.md
|
||||||
|
include HOW-TO-REPORT-A-BUG.md
|
||||||
include LICENSE
|
include LICENSE
|
||||||
|
include Makefile
|
||||||
|
include requirements.txt
|
||||||
|
include requirements-dev.txt
|
||||||
include DECOMPYLE-2.4-CHANGELOG.txt
|
include DECOMPYLE-2.4-CHANGELOG.txt
|
||||||
include __pkginfo__.py
|
include __pkginfo__.py
|
||||||
recursive-include uncompyle6 *.py
|
recursive-include uncompyle6 *.py
|
||||||
include bin/uncompyle6
|
include bin/uncompyle6
|
||||||
include bin/pydisassemble
|
include bin/pydisassemble
|
||||||
|
include pytest/Makefile
|
||||||
|
include test/Makefile
|
||||||
recursive-include test *.py *.pyc
|
recursive-include test *.py *.pyc
|
||||||
recursive-include pytest *.py
|
recursive-include pytest *.py
|
||||||
|
recursive-include pytest/testdata *
|
||||||
|
2
Makefile
2
Makefile
@@ -33,7 +33,7 @@ check-2.7 check-3.3 check-3.4: pytest
|
|||||||
|
|
||||||
#: Tests for Python 3.2 and 3.5 - pytest doesn't work here
|
#: Tests for Python 3.2 and 3.5 - pytest doesn't work here
|
||||||
# Or rather 3.5 doesn't work not on Travis
|
# Or rather 3.5 doesn't work not on Travis
|
||||||
check-3.1 check-3.2 check-3.5 check-3.6:
|
check-3.0 check-3.1 check-3.2 check-3.5 check-3.6:
|
||||||
$(MAKE) -C test $@
|
$(MAKE) -C test $@
|
||||||
|
|
||||||
#:Tests for Python 2.6 (doesn't have pytest)
|
#:Tests for Python 2.6 (doesn't have pytest)
|
||||||
|
173
NEWS
173
NEWS
@@ -1,9 +1,178 @@
|
|||||||
uncompyle6 2.832 2016-09-11 live from NYC!
|
uncompyle6 2.11.1 2016-06-18 Fleetwood
|
||||||
|
- Major improvements in fragment tracking
|
||||||
|
* Add nonterminal node in extractInfo
|
||||||
|
* tag more offsets in expressions
|
||||||
|
* tag array subscripts
|
||||||
|
* set YIELD value offset in a <yield> expr
|
||||||
|
* fix a long-standing bug in not adjusting final AST when melding other deparse ASTs
|
||||||
|
- Fixes yet again for make_function node handling; document what's up here
|
||||||
|
- Fix bug in snowflake Python 3.5 *args kwargs
|
||||||
|
|
||||||
|
uncompyle6 2.10.1 2016-06-3 Marylin Frankel
|
||||||
|
|
||||||
|
- fix some fragments parsing bugs
|
||||||
|
- was returning the wrong type sometimes in deparse_code_around_offset()
|
||||||
|
- capture function name in offsets
|
||||||
|
- track changes to ifelstrmtr node from pysource into fragments
|
||||||
|
|
||||||
|
uncompyle6 2.10.0 2016-05-30 Elaine Gordon
|
||||||
|
|
||||||
|
- Add fuzzy offset deparse lookup
|
||||||
|
- 3.6 bugfixes
|
||||||
|
- fix EXTENDED_ARGS handling (and in 2.6 and others)
|
||||||
|
- semantic routine make_function fragments.py
|
||||||
|
- MAKE_FUNCTION handling
|
||||||
|
- CALL_FUNCTION_EX handling
|
||||||
|
- async property on defs
|
||||||
|
- support for CALL_FUNCTION_KW (moagstar)
|
||||||
|
- 3.5+ UNMAP_PACK and BUILD_UNMAP_PACK handling
|
||||||
|
- 3.5 FUNCTION_VAR bug
|
||||||
|
- 3.x pass statement insdie while True
|
||||||
|
- Improve 3.2 decompilation
|
||||||
|
- Fixed -o argument processing (Gregrory)
|
||||||
|
- Reduce scope of LOAD_ASSERT as expr to 3.4+
|
||||||
|
- "await" statement fixes
|
||||||
|
- 2.3, 2.4 "if 1 .." fixes
|
||||||
|
- 3.x annotation fixes
|
||||||
|
|
||||||
|
uncompyle6 2.9.11 2016-04-06
|
||||||
|
|
||||||
|
- Better support for Python 3.5+ BUILD_MAP_UNPACK
|
||||||
|
- Start 3.6 CALL_FUNCTION_EX support
|
||||||
|
- Many decompilation bug fixes. (Many more remain). See ChangeLog
|
||||||
|
|
||||||
|
uncompyle6 2.9.10 2016-02-25
|
||||||
|
|
||||||
|
- Python grammar rule fixes
|
||||||
|
- Add ability to get grammar coverage on runs
|
||||||
|
- Handle Python 3.6 opcode BUILD_CONST_KEYMAP
|
||||||
|
|
||||||
|
uncompyle6 2.9.9 2016-12-16
|
||||||
|
|
||||||
|
- Remaining Python 3.5 ops handled
|
||||||
|
(this also means more Python 3.6 ops are handled)
|
||||||
|
- Python 3.5 and 3.6 async and await handled
|
||||||
|
- Python 3.0 decompilation improved
|
||||||
|
- Python 3 annotations fixed
|
||||||
|
- Better control-flow detection
|
||||||
|
- Code cleanups and misc bug fixes
|
||||||
|
|
||||||
|
uncompyle6 2.9.8 2016-12-16
|
||||||
|
|
||||||
|
- Better control-flow detection
|
||||||
|
- pseudo instruction THEN in 2.x
|
||||||
|
to disambiguate if from and
|
||||||
|
- fix bug in --verify option
|
||||||
|
- DRY (a little) control-flow detection
|
||||||
|
- fix syntax in tuples with one element
|
||||||
|
- if AST rule inheritence in Python 2.5
|
||||||
|
- NAME_MODULE removal for Python <= 2.4
|
||||||
|
- verifycall fixes for Python <= 2.4
|
||||||
|
- more Python lint
|
||||||
|
|
||||||
|
uncompyle6 2.9.7 2016-12-16
|
||||||
|
|
||||||
|
- Start to handle 3.5/3.6 build_map_unpack_with_call
|
||||||
|
- Some Python 3.6 bytecode to wordcode conversion fixes
|
||||||
|
- option -g: show start-end range when possible
|
||||||
|
- track print_docstring move to help (used in python 3.1)
|
||||||
|
- verify: allow RETURN_VALUE to match RETURN_END_IF
|
||||||
|
- some 3.2 compatibility
|
||||||
|
- Better Python 3 control flow detection by adding Pseudo ELSE opcodes
|
||||||
|
|
||||||
|
uncompyle6 2.9.6 2016-12-04
|
||||||
|
|
||||||
|
- Shorten Python3 grammars with + and *
|
||||||
|
this requires spark parser 1.5.1
|
||||||
|
- Add some AST reduction checks to improve
|
||||||
|
decompile accuracy. This too requires
|
||||||
|
spark parser 1.5.1
|
||||||
|
|
||||||
|
uncompyle6 2.9.6 2016-11-20
|
||||||
|
|
||||||
|
- Correct MANIFEST.in
|
||||||
|
- More AST grammar checking
|
||||||
|
- --linemapping option or linenumbers.line_number_mapping()
|
||||||
|
Shows correspondence of lines between source
|
||||||
|
and decompiled source
|
||||||
|
- Some control flow adjustments in code for 2.x.
|
||||||
|
This is probably an improvement in 2.6 and before.
|
||||||
|
For 2.7 things are just shuffled around a little. Sigh.
|
||||||
|
Overall I think we are getting more precise in
|
||||||
|
or analysis even if it is not always reflected
|
||||||
|
in the results.
|
||||||
|
- better control flow debugging output
|
||||||
|
- Python 2 and 3 detect structure code is more similar
|
||||||
|
- Handle Docstrings with embedded tiple quotes (""")
|
||||||
|
|
||||||
|
uncompyle6 2.9.5 2016-11-13
|
||||||
|
|
||||||
|
- Fix Python 3 bugs:
|
||||||
|
* improprer while 1 else
|
||||||
|
* docstring indent
|
||||||
|
* 3.3 default values in lambda expressions
|
||||||
|
* start 3.0 decompilation (needs newer xdis)
|
||||||
|
- Start grammar misparse checking
|
||||||
|
|
||||||
|
|
||||||
|
uncompyle6 2.9.4 2016-11-02
|
||||||
|
|
||||||
|
- Handle Python 3.x function annotations
|
||||||
|
- track def keywoard-parameter line-splitting in source code better
|
||||||
|
- bump min xdis version to mask previous xdis bug
|
||||||
|
|
||||||
|
uncompyle6 2.9.3 2016-10-26
|
||||||
|
|
||||||
|
Release forced by incompatiblity change in xdis 3.2.0.
|
||||||
|
|
||||||
|
- Python 3.1 bugs:
|
||||||
|
* handle "with ... as"
|
||||||
|
* handle "with"
|
||||||
|
* Start handling def (...) -> yy (has bugs still)
|
||||||
|
|
||||||
|
- DRY Python 3.x via inheritance
|
||||||
|
- Python 3.6 work (from Daniel Bradburn)
|
||||||
|
* Handle 3.6 buildstring
|
||||||
|
* Handle 3.6 handle single and multiple fstring better
|
||||||
|
|
||||||
|
|
||||||
|
uncompyle6 2.9.2 2016-10-15
|
||||||
|
|
||||||
|
- use source-code line breaks to assist in where to break
|
||||||
|
in tuples and maps
|
||||||
|
- Fix Python 1.5 decompyle bugs
|
||||||
|
- Fix some Python 2.6 and below bugs
|
||||||
|
- DRY fragments.py code a little
|
||||||
|
|
||||||
|
uncompyle6 2.9.1 2016-10-09
|
||||||
|
|
||||||
|
- Improved Python 1.5 decompiling
|
||||||
|
- Handle old-style pre Python 2.2 classes
|
||||||
|
|
||||||
|
uncompyle6 2.9.0 2016-10-09
|
||||||
|
|
||||||
|
- Use xdis 3.0.0 protocol load_module.
|
||||||
|
this Forces change in requirements.txt and _pkg_info_.py
|
||||||
|
- Start Python 1.5 decompiling; another round of work is needed to
|
||||||
|
remove bugs
|
||||||
|
- Simpify python 2.1 grammar
|
||||||
|
- Fix bug with -t ... Wasn't showing source text when -t option was given
|
||||||
|
- Fix 2.1-2.6 bug in list comprehension
|
||||||
|
|
||||||
|
uncompyle6 2.8.4 2016-10-08
|
||||||
|
|
||||||
|
- Python 3 disassembly bug fixes
|
||||||
|
- Python 3.6 fstring bug fixes (from moagstar)
|
||||||
|
- Python 2.1 disassembly
|
||||||
|
- COME_FROM suffixes added in Python3
|
||||||
|
- use .py extension in verification disassembly
|
||||||
|
|
||||||
|
uncompyle6 2.8.3 2016-09-11 live from NYC!
|
||||||
|
|
||||||
NOTE: this is possibly the last release before a major reworking of
|
NOTE: this is possibly the last release before a major reworking of
|
||||||
control-flow structure detection is done.
|
control-flow structure detection is done.
|
||||||
|
|
||||||
- Lots of bug fixes decompilations:
|
- Lots of bug fixes in decompilation:
|
||||||
* 3.0 .. 3.4 whileTrue bug
|
* 3.0 .. 3.4 whileTrue bug
|
||||||
* 3.x function declaration deparsing:
|
* 3.x function declaration deparsing:
|
||||||
. 3.0 .. 3.2 *args processing
|
. 3.0 .. 3.2 *args processing
|
||||||
|
99
README.rst
99
README.rst
@@ -1,4 +1,4 @@
|
|||||||
|buildstatus|
|
|buildstatus| |Supported Python Versions|
|
||||||
|
|
||||||
uncompyle6
|
uncompyle6
|
||||||
==========
|
==========
|
||||||
@@ -11,8 +11,8 @@ Introduction
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
*uncompyle6* translates Python bytecode back into equivalent Python
|
*uncompyle6* translates Python bytecode back into equivalent Python
|
||||||
source code. It accepts bytecodes from Python version 2.2 to 3.6 or
|
source code. It accepts bytecodes from Python version 1.5, and 2.1 to
|
||||||
so, including PyPy bytecode.
|
3.6 or so, including PyPy bytecode and Dropbox's Python 2.5 bytecode.
|
||||||
|
|
||||||
Why this?
|
Why this?
|
||||||
---------
|
---------
|
||||||
@@ -20,9 +20,10 @@ Why this?
|
|||||||
There were a number of decompyle, uncompile, uncompyle2, uncompyle3
|
There were a number of decompyle, uncompile, uncompyle2, uncompyle3
|
||||||
forks around. All of them came basically from the same code base, and
|
forks around. All of them came basically from the same code base, and
|
||||||
almost all of them no were no longer actively maintained. Only one
|
almost all of them no were no longer actively maintained. Only one
|
||||||
handled Python 3, and even there, only 3.2. This code pulls these
|
handled Python 3, and even there, only 3.2 or 3.3 depending on which
|
||||||
together and moves forward. It also addresses a number of open issues
|
code is used. This code pulls these together and moves forward. This
|
||||||
in the previous forks.
|
project has the most complete support for Python 3.3 and above. It
|
||||||
|
also addresses a number of open issues in the previous forks.
|
||||||
|
|
||||||
What makes this different from other CPython bytecode decompilers?: its
|
What makes this different from other CPython bytecode decompilers?: its
|
||||||
ability to deparse just fragments and give source-code information
|
ability to deparse just fragments and give source-code information
|
||||||
@@ -44,8 +45,9 @@ Requirements
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
This project requires Python 2.6 or later, PyPy 3-2.4, or PyPy-5.0.1.
|
This project requires Python 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 has been tested on Python bytecodes from
|
The bytecode files it can read has been tested on Python bytecodes from
|
||||||
versions 2.2-2.7, and 3.2-3.6 and the above-mentioned PyPy versions.
|
versions 1.5, 2.1-2.7, and 3.0-3.6 and the above-mentioned PyPy versions.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
@@ -54,7 +56,7 @@ This uses setup.py, so it follows the standard Python routine:
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
pip install -r requirements.txt
|
pip install -e .
|
||||||
pip install -r requirements-dev.txt
|
pip install -r requirements-dev.txt
|
||||||
python setup.py install # may need sudo
|
python setup.py install # may need sudo
|
||||||
# or if you have pyenv:
|
# or if you have pyenv:
|
||||||
@@ -92,35 +94,84 @@ For usage help:
|
|||||||
|
|
||||||
$ uncompyle6 -h
|
$ uncompyle6 -h
|
||||||
|
|
||||||
|
If you want strong verification of the correctness of the
|
||||||
|
decompilation process, add the `--verify` option. But there are
|
||||||
|
situations where this will indicate a failure, although the generated
|
||||||
|
program is semantically equivalent. Using option `--weak-verify` will
|
||||||
|
tell you if there is something definitely wrong. Generally, large
|
||||||
|
swaths of code are decompiled correctly, if not the entire program.
|
||||||
|
|
||||||
|
You can also cross compare the results with pycdc_ . Since they work
|
||||||
|
differently, bugs here often aren't in that, and vice versa.
|
||||||
|
|
||||||
|
|
||||||
Known Bugs/Restrictions
|
Known Bugs/Restrictions
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
Python 2 deparsing decompiles and about 90% verifies from Python 2.3.7 to Python
|
The biggest known and possibly fixable (but hard) problem has to do
|
||||||
3.4.2 on the standard library packages I have on my system.
|
with handling control flow. All of the Python decompilers I have looked
|
||||||
|
at have the same problem. In some cases we can detect an erroneous
|
||||||
|
decompilation and report that.
|
||||||
|
|
||||||
(Verification is the process of decompiling bytecode, compiling with a
|
Over 98% of the decompilation of Python standard library packages in
|
||||||
Python for that byecode version, and then comparing the byetcode
|
Python 2.7.12 verifies correctly. Over 99% of Python 2.7 and 3.3-3.5
|
||||||
|
"weakly" verify. Python 2.6 drops down to 96% weakly verifying.
|
||||||
|
Other versions drop off in quality too.
|
||||||
|
|
||||||
|
*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
|
produced by the decompiled/compiled program. Some allowance is made
|
||||||
for inessential differences.)
|
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.
|
||||||
|
|
||||||
Later distributions average about 200 files. At this point, 2.7
|
*Weak Verification*
|
||||||
decompilation is better than uncompyle2. A number of bugs have been
|
on the other hand doesn't check bytecode for equivalence but does
|
||||||
fixed.
|
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.
|
||||||
|
|
||||||
|
Later distributions average about 200 files. 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.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.6 changes things drastically by using word codes rather than byte
|
||||||
|
codes. That has been addressed, but then it also changes function call
|
||||||
|
opcodes and its semantics and has more problems with control flow than
|
||||||
|
3.5 has.
|
||||||
|
|
||||||
|
Currently not all Python magic numbers are supported. Specifically in
|
||||||
|
some versions of Python, notably Python 3.6, the magic number has
|
||||||
|
changes several times within a version. We support only the released
|
||||||
|
magic. There are also customized Python interpreters, notably Dropbox,
|
||||||
|
which use their own magic and encrypt bytcode. With the exception of
|
||||||
|
the Dropbox's old Python 2.5 interpreter this kind of thing is not
|
||||||
|
handled.
|
||||||
|
|
||||||
|
We also don't handle PJOrion_ obfuscated code. For that try: PJOrion
|
||||||
|
Deobfuscator_ to unscramble the bytecode to get valid bytecode before
|
||||||
|
trying this tool.
|
||||||
|
|
||||||
|
Handling pathologically long lists of expressions or statements is
|
||||||
|
slow.
|
||||||
|
|
||||||
Python 3.5 largely works, but still has some bugs in it.
|
|
||||||
Python 3.6 changes things drastically by using word codes rather than
|
|
||||||
byte codes, and that needs to be addressed.
|
|
||||||
|
|
||||||
There is lots to do, so please dig in and help.
|
There is lots to do, so please dig in and help.
|
||||||
|
|
||||||
See Also
|
See Also
|
||||||
--------
|
--------
|
||||||
|
|
||||||
* https://github.com/zrax/pycdc : supports all versions of Python and is written in C++
|
* 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 what is used here.
|
* https://code.google.com/archive/p/unpyc3/ : supports Python 3.2 only. The above projects use a different decompiling technique than what is used here.
|
||||||
|
* https://github.com/figment/unpyc3/ : fork of above, but supports Python 3.3 only. Include some fixes like supporting function annotations
|
||||||
* The HISTORY_ file.
|
* The HISTORY_ file.
|
||||||
|
* `How to report a bug <https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md>`_
|
||||||
.. |downloads| image:: https://img.shields.io/pypi/dd/uncompyle6.svg
|
.. |downloads| image:: https://img.shields.io/pypi/dd/uncompyle6.svg
|
||||||
.. _trepan: https://pypi.python.org/pypi/trepan
|
.. _trepan: https://pypi.python.org/pypi/trepan
|
||||||
.. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md
|
.. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md
|
||||||
@@ -130,3 +181,7 @@ See Also
|
|||||||
.. _this: https://github.com/rocky/python-uncompyle6/wiki/Deparsing-technology-and-its-use-in-exact-location-reporting
|
.. _this: https://github.com/rocky/python-uncompyle6/wiki/Deparsing-technology-and-its-use-in-exact-location-reporting
|
||||||
.. |buildstatus| image:: https://travis-ci.org/rocky/python-uncompyle6.svg
|
.. |buildstatus| image:: https://travis-ci.org/rocky/python-uncompyle6.svg
|
||||||
:target: https://travis-ci.org/rocky/python-uncompyle6
|
:target: https://travis-ci.org/rocky/python-uncompyle6
|
||||||
|
.. |Supported Python Versions| image:: https://img.shields.io/pypi/pyversions/uncompyle6.svg
|
||||||
|
:target: https://pypi.python.org/pypi/uncompyle6/
|
||||||
|
.. _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
|
||||||
|
@@ -9,17 +9,19 @@
|
|||||||
|
|
||||||
# Things that change more often go here.
|
# Things that change more often go here.
|
||||||
copyright = """
|
copyright = """
|
||||||
Copyright (C) 2015, 2016 Rocky Bernstein <rb@dustyfeet.com>.
|
Copyright (C) 2015-2017 Rocky Bernstein <rb@dustyfeet.com>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
classifiers = ['Development Status :: 4 - Beta',
|
classifiers = ['Development Status :: 5 - Production/Stable',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'Operating System :: OS Independent',
|
'Operating System :: OS Independent',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
'Programming Language :: Python :: 2',
|
'Programming Language :: Python :: 2.4',
|
||||||
|
'Programming Language :: Python :: 2.5',
|
||||||
'Programming Language :: Python :: 2.6',
|
'Programming Language :: Python :: 2.6',
|
||||||
'Programming Language :: Python :: 2.7',
|
'Programming Language :: Python :: 2.7',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3.1',
|
||||||
|
'Programming Language :: Python :: 3.2',
|
||||||
'Programming Language :: Python :: 3.3',
|
'Programming Language :: Python :: 3.3',
|
||||||
'Programming Language :: Python :: 3.4',
|
'Programming Language :: Python :: 3.4',
|
||||||
'Programming Language :: Python :: 3.5',
|
'Programming Language :: Python :: 3.5',
|
||||||
@@ -31,14 +33,14 @@ classifiers = ['Development Status :: 4 - Beta',
|
|||||||
# The rest in alphabetic order
|
# The rest in alphabetic order
|
||||||
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
|
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
|
||||||
author_email = "rb@dustyfeet.com"
|
author_email = "rb@dustyfeet.com"
|
||||||
entry_points={
|
entry_points = {
|
||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
'uncompyle6=uncompyle6.bin.uncompile:main_bin',
|
'uncompyle6=uncompyle6.bin.uncompile:main_bin',
|
||||||
'pydisassemble=uncompyle6.bin.pydisassemble:main',
|
'pydisassemble=uncompyle6.bin.pydisassemble:main',
|
||||||
]}
|
]}
|
||||||
ftp_url = None
|
ftp_url = None
|
||||||
install_requires = ['spark-parser >= 1.4.0',
|
install_requires = ['spark-parser >= 1.6.1, < 1.7.0',
|
||||||
'xdis >= 2.3.0']
|
'xdis >= 3.3.1, < 3.4.0', 'six']
|
||||||
license = 'MIT'
|
license = 'MIT'
|
||||||
mailing_list = 'python-debugger@googlegroups.com'
|
mailing_list = 'python-debugger@googlegroups.com'
|
||||||
modname = 'uncompyle6'
|
modname = 'uncompyle6'
|
||||||
|
78
appveyor.yml
Normal file
78
appveyor.yml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
environment:
|
||||||
|
global:
|
||||||
|
# SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the
|
||||||
|
# /E:ON and /V:ON options are not enabled in the batch script intepreter
|
||||||
|
# See: http://stackoverflow.com/a/13751649/163740
|
||||||
|
CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_env.cmd"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
|
||||||
|
# Pre-installed Python versions, which Appveyor may upgrade to
|
||||||
|
# a later point release.
|
||||||
|
# See: http://www.appveyor.com/docs/installed-software#python
|
||||||
|
|
||||||
|
# - PYTHON: "C:\\Python27"
|
||||||
|
# PYTHON_VERSION: "2.7.x"
|
||||||
|
# PYTHON_ARCH: "32"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python27-x64"
|
||||||
|
PYTHON_VERSION: "2.7.x"
|
||||||
|
PYTHON_ARCH: "64"
|
||||||
|
|
||||||
|
# - PYTHON: "C:\\Python26"
|
||||||
|
# PYTHON_VERSION: "2.6.x"
|
||||||
|
# PYTHON_ARCH: "32"
|
||||||
|
|
||||||
|
# - PYTHON: "C:\\Python26-x64"
|
||||||
|
# PYTHON_VERSION: "2.6.x"
|
||||||
|
# PYTHON_ARCH: "64"
|
||||||
|
|
||||||
|
install:
|
||||||
|
# We need wheel installed to build wheels
|
||||||
|
- "%PYTHON%\\python.exe -m pip install wheel"
|
||||||
|
|
||||||
|
# Install Python (from the official .msi of http://python.org) and pip when
|
||||||
|
# not already installed.
|
||||||
|
- ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 }
|
||||||
|
|
||||||
|
# Prepend newly installed Python to the PATH of this build (this cannot be
|
||||||
|
# done from inside the powershell script as it would require to restart
|
||||||
|
# the parent CMD process).
|
||||||
|
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||||
|
- "SET HOME=."
|
||||||
|
|
||||||
|
# Check that we have the expected version and architecture for Python
|
||||||
|
- "python --version"
|
||||||
|
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
|
||||||
|
|
||||||
|
# Upgrade to the latest version of pip to avoid it displaying warnings
|
||||||
|
# about it being out of date.
|
||||||
|
- "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,
|
||||||
|
# pip will build them from source using the MSVC compiler matching the
|
||||||
|
# target Python version and architecture
|
||||||
|
- "%CMD_IN_ENV% pip install -r requirements.txt"
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
# Build the compiled extension
|
||||||
|
- "%CMD_IN_ENV% python setup.py build"
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
# Run the project tests
|
||||||
|
- "%CMD_IN_ENV% python test/test_pyenvlib.py --native --weak-verify"
|
||||||
|
|
||||||
|
after_test:
|
||||||
|
# If tests are successful, create binary packages for the project.
|
||||||
|
- "%CMD_IN_ENV% python setup.py bdist_wininst"
|
||||||
|
- "%CMD_IN_ENV% python setup.py bdist_msi"
|
||||||
|
- ps: "ls dist"
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
# Archive the generated packages in the ci.appveyor.com build report.
|
||||||
|
- path: dist\*
|
||||||
|
|
||||||
|
#on_success:
|
||||||
|
# - TODO: upload the content of dist/*.whl to a public wheelhouse
|
||||||
|
#
|
229
appveyor/install.ps1
Normal file
229
appveyor/install.ps1
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
# Sample script to install Python and pip under Windows
|
||||||
|
# Authors: Olivier Grisel, Jonathan Helmus, Kyle Kastner, and Alex Willmer
|
||||||
|
# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
|
||||||
|
$MINICONDA_URL = "http://repo.continuum.io/miniconda/"
|
||||||
|
$BASE_URL = "https://www.python.org/ftp/python/"
|
||||||
|
$GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
|
||||||
|
$GET_PIP_PATH = "C:\get-pip.py"
|
||||||
|
|
||||||
|
$PYTHON_PRERELEASE_REGEX = @"
|
||||||
|
(?x)
|
||||||
|
(?<major>\d+)
|
||||||
|
\.
|
||||||
|
(?<minor>\d+)
|
||||||
|
\.
|
||||||
|
(?<micro>\d+)
|
||||||
|
(?<prerelease>[a-z]{1,2}\d+)
|
||||||
|
"@
|
||||||
|
|
||||||
|
|
||||||
|
function Download ($filename, $url) {
|
||||||
|
$webclient = New-Object System.Net.WebClient
|
||||||
|
|
||||||
|
$basedir = $pwd.Path + "\"
|
||||||
|
$filepath = $basedir + $filename
|
||||||
|
if (Test-Path $filename) {
|
||||||
|
Write-Host "Reusing" $filepath
|
||||||
|
return $filepath
|
||||||
|
}
|
||||||
|
|
||||||
|
# Download and retry up to 3 times in case of network transient errors.
|
||||||
|
Write-Host "Downloading" $filename "from" $url
|
||||||
|
$retry_attempts = 2
|
||||||
|
for ($i = 0; $i -lt $retry_attempts; $i++) {
|
||||||
|
try {
|
||||||
|
$webclient.DownloadFile($url, $filepath)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Catch [Exception]{
|
||||||
|
Start-Sleep 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Test-Path $filepath) {
|
||||||
|
Write-Host "File saved at" $filepath
|
||||||
|
} else {
|
||||||
|
# Retry once to get the error message if any at the last try
|
||||||
|
$webclient.DownloadFile($url, $filepath)
|
||||||
|
}
|
||||||
|
return $filepath
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ParsePythonVersion ($python_version) {
|
||||||
|
if ($python_version -match $PYTHON_PRERELEASE_REGEX) {
|
||||||
|
return ([int]$matches.major, [int]$matches.minor, [int]$matches.micro,
|
||||||
|
$matches.prerelease)
|
||||||
|
}
|
||||||
|
$version_obj = [version]$python_version
|
||||||
|
return ($version_obj.major, $version_obj.minor, $version_obj.build, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function DownloadPython ($python_version, $platform_suffix) {
|
||||||
|
$major, $minor, $micro, $prerelease = ParsePythonVersion $python_version
|
||||||
|
|
||||||
|
if (($major -le 2 -and $micro -eq 0) `
|
||||||
|
-or ($major -eq 3 -and $minor -le 2 -and $micro -eq 0) `
|
||||||
|
) {
|
||||||
|
$dir = "$major.$minor"
|
||||||
|
$python_version = "$major.$minor$prerelease"
|
||||||
|
} else {
|
||||||
|
$dir = "$major.$minor.$micro"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prerelease) {
|
||||||
|
if (($major -le 2) `
|
||||||
|
-or ($major -eq 3 -and $minor -eq 1) `
|
||||||
|
-or ($major -eq 3 -and $minor -eq 2) `
|
||||||
|
-or ($major -eq 3 -and $minor -eq 3) `
|
||||||
|
) {
|
||||||
|
$dir = "$dir/prev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($major -le 2) -or ($major -le 3 -and $minor -le 4)) {
|
||||||
|
$ext = "msi"
|
||||||
|
if ($platform_suffix) {
|
||||||
|
$platform_suffix = ".$platform_suffix"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$ext = "exe"
|
||||||
|
if ($platform_suffix) {
|
||||||
|
$platform_suffix = "-$platform_suffix"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = "python-$python_version$platform_suffix.$ext"
|
||||||
|
$url = "$BASE_URL$dir/$filename"
|
||||||
|
$filepath = Download $filename $url
|
||||||
|
return $filepath
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallPython ($python_version, $architecture, $python_home) {
|
||||||
|
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
|
||||||
|
if (Test-Path $python_home) {
|
||||||
|
Write-Host $python_home "already exists, skipping."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if ($architecture -eq "32") {
|
||||||
|
$platform_suffix = ""
|
||||||
|
} else {
|
||||||
|
$platform_suffix = "amd64"
|
||||||
|
}
|
||||||
|
$installer_path = DownloadPython $python_version $platform_suffix
|
||||||
|
$installer_ext = [System.IO.Path]::GetExtension($installer_path)
|
||||||
|
Write-Host "Installing $installer_path to $python_home"
|
||||||
|
$install_log = $python_home + ".log"
|
||||||
|
if ($installer_ext -eq '.msi') {
|
||||||
|
InstallPythonMSI $installer_path $python_home $install_log
|
||||||
|
} else {
|
||||||
|
InstallPythonEXE $installer_path $python_home $install_log
|
||||||
|
}
|
||||||
|
if (Test-Path $python_home) {
|
||||||
|
Write-Host "Python $python_version ($architecture) installation complete"
|
||||||
|
} else {
|
||||||
|
Write-Host "Failed to install Python in $python_home"
|
||||||
|
Get-Content -Path $install_log
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallPythonEXE ($exepath, $python_home, $install_log) {
|
||||||
|
$install_args = "/quiet InstallAllUsers=1 TargetDir=$python_home"
|
||||||
|
RunCommand $exepath $install_args
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallPythonMSI ($msipath, $python_home, $install_log) {
|
||||||
|
$install_args = "/qn /log $install_log /i $msipath TARGETDIR=$python_home"
|
||||||
|
$uninstall_args = "/qn /x $msipath"
|
||||||
|
RunCommand "msiexec.exe" $install_args
|
||||||
|
if (-not(Test-Path $python_home)) {
|
||||||
|
Write-Host "Python seems to be installed else-where, reinstalling."
|
||||||
|
RunCommand "msiexec.exe" $uninstall_args
|
||||||
|
RunCommand "msiexec.exe" $install_args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function RunCommand ($command, $command_args) {
|
||||||
|
Write-Host $command $command_args
|
||||||
|
Start-Process -FilePath $command -ArgumentList $command_args -Wait -Passthru
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallPip ($python_home) {
|
||||||
|
$pip_path = $python_home + "\Scripts\pip.exe"
|
||||||
|
$python_path = $python_home + "\python.exe"
|
||||||
|
if (-not(Test-Path $pip_path)) {
|
||||||
|
Write-Host "Installing pip..."
|
||||||
|
$webclient = New-Object System.Net.WebClient
|
||||||
|
$webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH)
|
||||||
|
Write-Host "Executing:" $python_path $GET_PIP_PATH
|
||||||
|
& $python_path $GET_PIP_PATH
|
||||||
|
} else {
|
||||||
|
Write-Host "pip already installed."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function DownloadMiniconda ($python_version, $platform_suffix) {
|
||||||
|
if ($python_version -eq "3.4") {
|
||||||
|
$filename = "Miniconda3-3.5.5-Windows-" + $platform_suffix + ".exe"
|
||||||
|
} else {
|
||||||
|
$filename = "Miniconda-3.5.5-Windows-" + $platform_suffix + ".exe"
|
||||||
|
}
|
||||||
|
$url = $MINICONDA_URL + $filename
|
||||||
|
$filepath = Download $filename $url
|
||||||
|
return $filepath
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallMiniconda ($python_version, $architecture, $python_home) {
|
||||||
|
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
|
||||||
|
if (Test-Path $python_home) {
|
||||||
|
Write-Host $python_home "already exists, skipping."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if ($architecture -eq "32") {
|
||||||
|
$platform_suffix = "x86"
|
||||||
|
} else {
|
||||||
|
$platform_suffix = "x86_64"
|
||||||
|
}
|
||||||
|
$filepath = DownloadMiniconda $python_version $platform_suffix
|
||||||
|
Write-Host "Installing" $filepath "to" $python_home
|
||||||
|
$install_log = $python_home + ".log"
|
||||||
|
$args = "/S /D=$python_home"
|
||||||
|
Write-Host $filepath $args
|
||||||
|
Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru
|
||||||
|
if (Test-Path $python_home) {
|
||||||
|
Write-Host "Python $python_version ($architecture) installation complete"
|
||||||
|
} else {
|
||||||
|
Write-Host "Failed to install Python in $python_home"
|
||||||
|
Get-Content -Path $install_log
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallMinicondaPip ($python_home) {
|
||||||
|
$pip_path = $python_home + "\Scripts\pip.exe"
|
||||||
|
$conda_path = $python_home + "\Scripts\conda.exe"
|
||||||
|
if (-not(Test-Path $pip_path)) {
|
||||||
|
Write-Host "Installing pip..."
|
||||||
|
$args = "install --yes pip"
|
||||||
|
Write-Host $conda_path $args
|
||||||
|
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
|
||||||
|
} else {
|
||||||
|
Write-Host "pip already installed."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function main () {
|
||||||
|
InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON
|
||||||
|
InstallPip $env:PYTHON
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
87
appveyor/run_with_env.cmd
Normal file
87
appveyor/run_with_env.cmd
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
:: To build extensions for 64 bit Python 3, we need to configure environment
|
||||||
|
:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of:
|
||||||
|
:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1)
|
||||||
|
::
|
||||||
|
:: To build extensions for 64 bit Python 2, we need to configure environment
|
||||||
|
:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of:
|
||||||
|
:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0)
|
||||||
|
::
|
||||||
|
:: 32 bit builds, and 64-bit builds for 3.5 and beyond, do not require specific
|
||||||
|
:: environment configurations.
|
||||||
|
::
|
||||||
|
:: Note: this script needs to be run with the /E:ON and /V:ON flags for the
|
||||||
|
:: cmd interpreter, at least for (SDK v7.0)
|
||||||
|
::
|
||||||
|
:: More details at:
|
||||||
|
:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows
|
||||||
|
:: http://stackoverflow.com/a/13751649/163740
|
||||||
|
::
|
||||||
|
:: Author: Olivier Grisel
|
||||||
|
:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
::
|
||||||
|
:: Notes about batch files for Python people:
|
||||||
|
::
|
||||||
|
:: Quotes in values are literally part of the values:
|
||||||
|
:: SET FOO="bar"
|
||||||
|
:: FOO is now five characters long: " b a r "
|
||||||
|
:: If you don't want quotes, don't include them on the right-hand side.
|
||||||
|
::
|
||||||
|
:: The CALL lines at the end of this file look redundant, but if you move them
|
||||||
|
:: outside of the IF clauses, they do not run properly in the SET_SDK_64==Y
|
||||||
|
:: case, I don't know why.
|
||||||
|
@ECHO OFF
|
||||||
|
SET COMMAND_TO_RUN=%*
|
||||||
|
SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows
|
||||||
|
SET WIN_WDK=c:\Program Files (x86)\Windows Kits\10\Include\wdf
|
||||||
|
|
||||||
|
:: Extract the major and minor versions, and allow for the minor version to be
|
||||||
|
:: more than 9. This requires the version number to have two dots in it.
|
||||||
|
SET MAJOR_PYTHON_VERSION=%PYTHON_VERSION:~0,1%
|
||||||
|
IF "%PYTHON_VERSION:~3,1%" == "." (
|
||||||
|
SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,1%
|
||||||
|
) ELSE (
|
||||||
|
SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,2%
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Based on the Python version, determine what SDK version to use, and whether
|
||||||
|
:: to set the SDK for 64-bit.
|
||||||
|
IF %MAJOR_PYTHON_VERSION% == 2 (
|
||||||
|
SET WINDOWS_SDK_VERSION="v7.0"
|
||||||
|
SET SET_SDK_64=Y
|
||||||
|
) ELSE (
|
||||||
|
IF %MAJOR_PYTHON_VERSION% == 3 (
|
||||||
|
SET WINDOWS_SDK_VERSION="v7.1"
|
||||||
|
IF %MINOR_PYTHON_VERSION% LEQ 4 (
|
||||||
|
SET SET_SDK_64=Y
|
||||||
|
) ELSE (
|
||||||
|
SET SET_SDK_64=N
|
||||||
|
IF EXIST "%WIN_WDK%" (
|
||||||
|
:: See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/
|
||||||
|
REN "%WIN_WDK%" 0wdf
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) ELSE (
|
||||||
|
ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%"
|
||||||
|
EXIT 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
IF %PYTHON_ARCH% == 64 (
|
||||||
|
IF %SET_SDK_64% == Y (
|
||||||
|
ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture
|
||||||
|
SET DISTUTILS_USE_SDK=1
|
||||||
|
SET MSSdk=1
|
||||||
|
"%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION%
|
||||||
|
"%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release
|
||||||
|
ECHO Executing: %COMMAND_TO_RUN%
|
||||||
|
call %COMMAND_TO_RUN% || EXIT 1
|
||||||
|
) ELSE (
|
||||||
|
ECHO Using default MSVC build environment for 64 bit architecture
|
||||||
|
ECHO Executing: %COMMAND_TO_RUN%
|
||||||
|
call %COMMAND_TO_RUN% || EXIT 1
|
||||||
|
)
|
||||||
|
) ELSE (
|
||||||
|
ECHO Using default MSVC build environment for 32 bit architecture
|
||||||
|
ECHO Executing: %COMMAND_TO_RUN%
|
||||||
|
call %COMMAND_TO_RUN% || EXIT 1
|
||||||
|
)
|
@@ -1,12 +1,12 @@
|
|||||||
machine:
|
machine:
|
||||||
python:
|
python:
|
||||||
version: 2.7.8
|
version: 2.7.10
|
||||||
environment:
|
environment:
|
||||||
COMPILE: --compile
|
COMPILE: --compile
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
override:
|
override:
|
||||||
- pip install -r requirements.txt
|
- pip install -e .
|
||||||
- pip install -r requirements-dev.txt
|
- pip install -r requirements-dev.txt
|
||||||
test:
|
test:
|
||||||
override:
|
override:
|
||||||
|
1
pytest/.gitignore
vendored
1
pytest/.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
|
/.hypothesis
|
||||||
/__pycache__
|
/__pycache__
|
||||||
|
6
pytest/test_CALL_FUNCTION_KW.sh
Normal file
6
pytest/test_CALL_FUNCTION_KW.sh
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
source ../.venv.3.6/bin/activate
|
||||||
|
py.test -k test_CALL_FUNCTION_KW
|
||||||
|
source ../.venv.3.5/bin/activate
|
||||||
|
py.test -k test_CALL_FUNCTION_KW
|
||||||
|
source ../.venv.2.7/bin/activate
|
||||||
|
py.test -k test_CALL_FUNCTION_KW
|
21
pytest/test_build_const_key_map.py
Normal file
21
pytest/test_build_const_key_map.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import pytest
|
||||||
|
# uncompyle6
|
||||||
|
from uncompyle6 import PYTHON_VERSION
|
||||||
|
from validate import validate_uncompyle
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6')
|
||||||
|
@pytest.mark.parametrize('text', (
|
||||||
|
"{0.: 'a', -1: 'b'}", # BUILD_MAP
|
||||||
|
"{'a':'b'}", # BUILD_MAP
|
||||||
|
"{0: 1}", # BUILD_MAP
|
||||||
|
"{b'0':1, b'2':3}", # BUILD_CONST_KEY_MAP
|
||||||
|
"{0: 1, 2: 3}", # BUILD_CONST_KEY_MAP
|
||||||
|
"{'a':'b','c':'d'}", # BUILD_CONST_KEY_MAP
|
||||||
|
"{0: 1, 2: 3}", # BUILD_CONST_KEY_MAP
|
||||||
|
"{'a': 1, 'b': 2}", # BUILD_CONST_KEY_MAP
|
||||||
|
"{'a':'b','c':'d'}", # BUILD_CONST_KEY_MAP
|
||||||
|
"{0.0:'b',0.1:'d'}", # BUILD_CONST_KEY_MAP
|
||||||
|
))
|
||||||
|
def test_build_const_key_map(text):
|
||||||
|
validate_uncompyle(text)
|
78
pytest/test_docstring.py
Normal file
78
pytest/test_docstring.py
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import sys
|
||||||
|
from uncompyle6 import PYTHON3
|
||||||
|
if PYTHON3:
|
||||||
|
from io import StringIO
|
||||||
|
minint = -sys.maxsize-1
|
||||||
|
maxint = sys.maxsize
|
||||||
|
else:
|
||||||
|
from StringIO import StringIO
|
||||||
|
minint = -sys.maxint-1
|
||||||
|
maxint = sys.maxint
|
||||||
|
from uncompyle6.semantics.helper import print_docstring
|
||||||
|
|
||||||
|
class PrintFake():
|
||||||
|
def __init__(self):
|
||||||
|
self.pending_newlines = 0
|
||||||
|
self.f = StringIO()
|
||||||
|
|
||||||
|
def write(self, *data):
|
||||||
|
if (len(data) == 0) or (len(data) == 1 and data[0] == ''):
|
||||||
|
return
|
||||||
|
out = ''.join((str(j) for j in data))
|
||||||
|
n = 0
|
||||||
|
for i in out:
|
||||||
|
if i == '\n':
|
||||||
|
n += 1
|
||||||
|
if n == len(out):
|
||||||
|
self.pending_newlines = max(self.pending_newlines, n)
|
||||||
|
return
|
||||||
|
elif n:
|
||||||
|
self.pending_newlines = max(self.pending_newlines, n)
|
||||||
|
out = out[n:]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if self.pending_newlines > 0:
|
||||||
|
self.f.write('\n'*self.pending_newlines)
|
||||||
|
self.pending_newlines = 0
|
||||||
|
|
||||||
|
for i in out[::-1]:
|
||||||
|
if i == '\n':
|
||||||
|
self.pending_newlines += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if self.pending_newlines:
|
||||||
|
out = out[:-self.pending_newlines]
|
||||||
|
self.f.write(out)
|
||||||
|
def println(self, *data):
|
||||||
|
if data and not(len(data) == 1 and data[0] ==''):
|
||||||
|
self.write(*data)
|
||||||
|
self.pending_newlines = max(self.pending_newlines, 1)
|
||||||
|
return
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_docstring():
|
||||||
|
|
||||||
|
for doc, expect in (
|
||||||
|
("Now is the time",
|
||||||
|
' """Now is the time"""'),
|
||||||
|
("""
|
||||||
|
Now is the time
|
||||||
|
""",
|
||||||
|
''' """
|
||||||
|
Now is the time
|
||||||
|
"""''')
|
||||||
|
|
||||||
|
# (r'''func placeholder - ' and with ("""\nstring\n """)''',
|
||||||
|
# """ r'''func placeholder - ' and with (\"\"\"\nstring\n\"\"\")'''"""),
|
||||||
|
# (r"""func placeholder - ' and with ('''\nstring\n''') and \"\"\"\nstring\n\"\"\" """,
|
||||||
|
# """ r\"\"\"func placeholder - ' and with ('''\nstring\n''') and \"\"\"\nstring\n\"\"\" \"\"\"""")
|
||||||
|
):
|
||||||
|
|
||||||
|
o = PrintFake()
|
||||||
|
# print(doc)
|
||||||
|
# print(expect)
|
||||||
|
print_docstring(o, ' ', doc)
|
||||||
|
assert expect == o.f.getvalue()
|
@@ -8,6 +8,18 @@ def bug(state, slotstate):
|
|||||||
for key, value in slotstate.items():
|
for key, value in slotstate.items():
|
||||||
setattr(state, key, 2)
|
setattr(state, key, 2)
|
||||||
|
|
||||||
|
# From 2.7 disassemble
|
||||||
|
# Problem is not getting while, because
|
||||||
|
# COME_FROM not added
|
||||||
|
def bug_loop(disassemble, tb=None):
|
||||||
|
if tb:
|
||||||
|
try:
|
||||||
|
tb = 5
|
||||||
|
except AttributeError:
|
||||||
|
raise RuntimeError
|
||||||
|
while tb: tb = tb.tb_next
|
||||||
|
disassemble(tb)
|
||||||
|
|
||||||
def test_if_in_for():
|
def test_if_in_for():
|
||||||
code = bug.__code__
|
code = bug.__code__
|
||||||
scan = get_scanner(PYTHON_VERSION)
|
scan = get_scanner(PYTHON_VERSION)
|
||||||
@@ -16,18 +28,35 @@ def test_if_in_for():
|
|||||||
n = scan.setup_code(code)
|
n = scan.setup_code(code)
|
||||||
scan.build_lines_data(code, n)
|
scan.build_lines_data(code, n)
|
||||||
scan.build_prev_op(n)
|
scan.build_prev_op(n)
|
||||||
fjt = scan.find_jump_targets()
|
fjt = scan.find_jump_targets(False)
|
||||||
assert {15: [3], 69: [66], 63: [18]} == fjt
|
assert {15: [3], 69: [66], 63: [18]} == fjt
|
||||||
assert scan.structs == \
|
assert scan.structs == \
|
||||||
[{'start': 0, 'end': 72, 'type': 'root'},
|
[{'start': 0, 'end': 72, 'type': 'root'},
|
||||||
{'start': 18, 'end': 66, 'type': 'if-then'},
|
{'start': 15, 'end': 66, 'type': 'if-then'},
|
||||||
{'start': 31, 'end': 59, 'type': 'for-loop'},
|
{'start': 31, 'end': 59, 'type': 'for-loop'},
|
||||||
{'start': 62, 'end': 63, 'type': 'for-else'}]
|
{'start': 62, 'end': 63, 'type': 'for-else'}]
|
||||||
|
|
||||||
|
code = bug_loop.__code__
|
||||||
|
n = scan.setup_code(code)
|
||||||
|
scan.build_lines_data(code, n)
|
||||||
|
scan.build_prev_op(n)
|
||||||
|
fjt = scan.find_jump_targets(False)
|
||||||
|
assert{64: [42], 67: [42, 42], 42: [16, 41], 19: [6]} == fjt
|
||||||
|
assert scan.structs == [
|
||||||
|
{'start': 0, 'end': 80, 'type': 'root'},
|
||||||
|
{'start': 3, 'end': 64, 'type': 'if-then'},
|
||||||
|
{'start': 6, 'end': 15, 'type': 'try'},
|
||||||
|
{'start': 19, 'end': 38, 'type': 'except'},
|
||||||
|
{'start': 45, 'end': 67, 'type': 'while-loop'},
|
||||||
|
{'start': 70, 'end': 64, 'type': 'while-else'},
|
||||||
|
# previous bug was not mistaking while-loop for if-then
|
||||||
|
{'start': 48, 'end': 67, 'type': 'while-loop'}]
|
||||||
|
|
||||||
elif 3.2 < PYTHON_VERSION <= 3.4:
|
elif 3.2 < PYTHON_VERSION <= 3.4:
|
||||||
scan.code = array('B', code.co_code)
|
scan.code = array('B', code.co_code)
|
||||||
scan.build_lines_data(code)
|
scan.build_lines_data(code)
|
||||||
scan.build_prev_op()
|
scan.build_prev_op()
|
||||||
fjt = scan.find_jump_targets()
|
fjt = scan.find_jump_targets(False)
|
||||||
assert {69: [66], 63: [18]} == fjt
|
assert {69: [66], 63: [18]} == fjt
|
||||||
assert scan.structs == \
|
assert scan.structs == \
|
||||||
[{'end': 72, 'type': 'root', 'start': 0},
|
[{'end': 72, 'type': 'root', 'start': 0},
|
||||||
|
@@ -21,9 +21,13 @@ def expressions(draw):
|
|||||||
'container',
|
'container',
|
||||||
'self.attribute',
|
'self.attribute',
|
||||||
'self.method()',
|
'self.method()',
|
||||||
'sorted(items, key=lambda x: x.name)',
|
# These expressions are failing, I think these are control
|
||||||
'func(*args, **kwargs)',
|
# flow problems rather than problems with FORMAT_VALUE,
|
||||||
'text or default',
|
# 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'
|
||||||
)))
|
)))
|
||||||
|
|
||||||
|
|
||||||
@@ -87,19 +91,23 @@ def fstrings(draw):
|
|||||||
|
|
||||||
:return: A valid f-string.
|
: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())
|
is_raw = draw(st.booleans())
|
||||||
integer_strategy = st.integers(min_value=0, max_value=3)
|
integer_strategy = st.integers(min_value=0, max_value=3)
|
||||||
expression_count = draw(integer_strategy)
|
expression_count = draw(integer_strategy)
|
||||||
content = []
|
content = []
|
||||||
for _ in range(expression_count):
|
for _ in range(expression_count):
|
||||||
expression = draw(expressions())
|
expression = draw(expressions())
|
||||||
# not yet : conversion not supported
|
conversion = draw(st.sampled_from(('', '!s', '!r', '!a',)))
|
||||||
conversion = ''#draw(st.sampled_from(('', '!s', '!r', '!a',)))
|
|
||||||
has_specifier = draw(st.booleans())
|
has_specifier = draw(st.booleans())
|
||||||
specifier = ':' + draw(format_specifiers()) if has_specifier else ''
|
specifier = ':' + draw(format_specifiers()) if has_specifier else ''
|
||||||
content.append('{{{}{}}}'.format(expression, conversion, specifier))
|
content.append('{{{}{}}}'.format(expression, conversion, specifier))
|
||||||
|
content.append(draw(st.text(character_strategy)))
|
||||||
content = ''.join(content)
|
content = ''.join(content)
|
||||||
|
|
||||||
return "f{}'{}'".format('r' if is_raw else '', content)
|
return "f{}'{}'".format('r' if is_raw else '', content)
|
||||||
|
|
||||||
|
|
||||||
@@ -114,23 +122,29 @@ def test_format_specifiers(format_specifier):
|
|||||||
raise
|
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')
|
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6')
|
||||||
@hypothesis.given(fstrings())
|
@hypothesis.given(fstrings())
|
||||||
def test_uncompyle_fstring(fstring):
|
def test_uncompyle_fstring(fstring):
|
||||||
"""Verify uncompyling fstring bytecode"""
|
"""Verify uncompyling fstring bytecode"""
|
||||||
|
run_test(fstring)
|
||||||
|
|
||||||
# ignore fstring with no expressions an fsring with
|
|
||||||
# no expressions just gets compiled to a normal string.
|
|
||||||
hypothesis.assume('{' in fstring)
|
|
||||||
|
|
||||||
# BUG : At the moment a single expression is not supported
|
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6')
|
||||||
# for example f'{abc}'.
|
@pytest.mark.parametrize('fstring', [
|
||||||
hypothesis.assume(fstring.count('{') > 1)
|
"f'{abc}{abc!s}'",
|
||||||
|
"f'{abc}0'",
|
||||||
expr = fstring + '\n'
|
])
|
||||||
code = compile(expr, '<string>', 'single')
|
def test_uncompyle_direct(fstring):
|
||||||
deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single')
|
"""useful for debugging"""
|
||||||
recompiled = compile(deparsed.text, '<string>', 'single')
|
run_test(fstring)
|
||||||
|
|
||||||
if recompiled != code:
|
|
||||||
assert deparsed.text == expr
|
|
||||||
|
175
pytest/test_function_call.py
Normal file
175
pytest/test_function_call.py
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
# std
|
||||||
|
import string
|
||||||
|
# 3rd party
|
||||||
|
from hypothesis import given, assume, example, settings, strategies as st
|
||||||
|
import pytest
|
||||||
|
# uncompyle
|
||||||
|
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()")
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
|
||||||
|
@given(isolated_function_calls('positional'))
|
||||||
|
@example("fn(0)")
|
||||||
|
def test_function_positional_only(expr):
|
||||||
|
validate_uncompyle(expr)
|
||||||
|
|
||||||
|
@given(isolated_function_calls('keyword'))
|
||||||
|
@example("fn(a=0)")
|
||||||
|
def test_function_call_keyword_only(expr):
|
||||||
|
validate_uncompyle(expr)
|
||||||
|
|
||||||
|
@given(isolated_function_calls('star'))
|
||||||
|
@example("fn(*items)")
|
||||||
|
def test_function_call_star_only(expr):
|
||||||
|
validate_uncompyle(expr)
|
||||||
|
|
||||||
|
@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)
|
@@ -1,6 +1,6 @@
|
|||||||
import pytest, re
|
import re
|
||||||
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY # , PYTHON_VERSION
|
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY # , PYTHON_VERSION
|
||||||
from uncompyle6.parser import get_python_parser
|
from uncompyle6.parser import get_python_parser, python_parser
|
||||||
from uncompyle6.scanner import get_scanner
|
from uncompyle6.scanner import get_scanner
|
||||||
|
|
||||||
def test_grammar():
|
def test_grammar():
|
||||||
@@ -16,14 +16,21 @@ def test_grammar():
|
|||||||
p = get_python_parser(PYTHON_VERSION, is_pypy=IS_PYPY)
|
p = get_python_parser(PYTHON_VERSION, is_pypy=IS_PYPY)
|
||||||
lhs, rhs, tokens, right_recursive = p.checkSets()
|
lhs, rhs, tokens, right_recursive = p.checkSets()
|
||||||
expect_lhs = set(['expr1024', 'pos_arg'])
|
expect_lhs = set(['expr1024', 'pos_arg'])
|
||||||
unused_rhs = set(['build_list', 'call_function', 'mkfunc', 'mklambda',
|
unused_rhs = set(['build_list', 'call_function', 'mkfunc',
|
||||||
|
'mklambda',
|
||||||
'unpack', 'unpack_list'])
|
'unpack', 'unpack_list'])
|
||||||
expect_right_recursive = [['designList', ('designator', 'DUP_TOP', 'designList')]]
|
expect_right_recursive = [['designList', ('designator', 'DUP_TOP', 'designList')]]
|
||||||
if PYTHON3:
|
if PYTHON3:
|
||||||
expect_lhs.add('load_genexpr')
|
expect_lhs.add('load_genexpr')
|
||||||
|
|
||||||
unused_rhs = unused_rhs.union(set("""
|
unused_rhs = unused_rhs.union(set("""
|
||||||
except_pop_except genexpr classdefdeco2 listcomp
|
except_pop_except genexpr classdefdeco2 listcomp
|
||||||
""".split()))
|
""".split()))
|
||||||
|
if 3.0 <= PYTHON_VERSION:
|
||||||
|
expect_lhs.add("annotate_arg")
|
||||||
|
expect_lhs.add("annotate_tuple")
|
||||||
|
unused_rhs.add("mkfunc_annotate")
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
expect_lhs.add('kwarg')
|
expect_lhs.add('kwarg')
|
||||||
assert expect_lhs == set(lhs)
|
assert expect_lhs == set(lhs)
|
||||||
@@ -31,14 +38,28 @@ def test_grammar():
|
|||||||
assert expect_right_recursive == right_recursive
|
assert expect_right_recursive == right_recursive
|
||||||
s = get_scanner(PYTHON_VERSION, IS_PYPY)
|
s = get_scanner(PYTHON_VERSION, IS_PYPY)
|
||||||
ignore_set = set(
|
ignore_set = set(
|
||||||
"""JUMP_BACK CONTINUE RETURN_END_IF COME_FROM
|
"""
|
||||||
LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP
|
JUMP_BACK CONTINUE RETURN_END_IF
|
||||||
LAMBDA_MARKER RETURN_LAST
|
COME_FROM COME_FROM_EXCEPT
|
||||||
|
COME_FROM_EXCEPT_CLAUSE
|
||||||
|
COME_FROM_LOOP COME_FROM_WITH
|
||||||
|
COME_FROM_FINALLY ELSE
|
||||||
|
LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP
|
||||||
|
LAMBDA_MARKER RETURN_LAST
|
||||||
""".split())
|
""".split())
|
||||||
if 2.6 <= PYTHON_VERSION <= 2.7:
|
if 2.6 <= PYTHON_VERSION <= 2.7:
|
||||||
opcode_set = set(s.opc.opname).union(ignore_set)
|
opcode_set = set(s.opc.opname).union(ignore_set)
|
||||||
check_tokens(tokens, opcode_set)
|
check_tokens(tokens, opcode_set)
|
||||||
elif PYTHON_VERSION == 3.4:
|
elif PYTHON_VERSION == 3.4:
|
||||||
ignore_set.add('LOAD_CLASSNAME')
|
ignore_set.add('LOAD_CLASSNAME')
|
||||||
|
ignore_set.add('STORE_LOCALS')
|
||||||
opcode_set = set(s.opc.opname).union(ignore_set)
|
opcode_set = set(s.opc.opname).union(ignore_set)
|
||||||
check_tokens(tokens, opcode_set)
|
check_tokens(tokens, opcode_set)
|
||||||
|
|
||||||
|
def test_dup_rule():
|
||||||
|
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})
|
||||||
|
@@ -9,8 +9,6 @@ def test_single_mode():
|
|||||||
'i = j % 4',
|
'i = j % 4',
|
||||||
'i = {}',
|
'i = {}',
|
||||||
'i = []',
|
'i = []',
|
||||||
'while i < 1 or stop:\n i\n',
|
|
||||||
'while i < 1 or stop:\n print%s\n' % ('(i)' if PYTHON3 else ' i'),
|
|
||||||
'for i in range(10):\n i\n',
|
'for i in range(10):\n i\n',
|
||||||
'for i in range(10):\n for j in range(10):\n i + j\n',
|
'for i in range(10):\n for j in range(10):\n i + j\n',
|
||||||
'try:\n i\nexcept Exception:\n j\nelse:\n k\n'
|
'try:\n i\nexcept Exception:\n j\nelse:\n k\n'
|
||||||
|
147
pytest/validate.py
Normal file
147
pytest/validate.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
# future
|
||||||
|
from __future__ import print_function
|
||||||
|
# std
|
||||||
|
import os
|
||||||
|
import difflib
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import functools
|
||||||
|
# compatability
|
||||||
|
import six
|
||||||
|
# uncompyle6 / xdis
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
def _dis_to_text(co):
|
||||||
|
return Bytecode(co).dis()
|
||||||
|
|
||||||
|
|
||||||
|
def print_diff(original, uncompyled):
|
||||||
|
"""
|
||||||
|
Try and display a pretty html line difference between the original and
|
||||||
|
uncompyled code and bytecode if elinks and BeautifulSoup are installed
|
||||||
|
otherwise just show the diff.
|
||||||
|
|
||||||
|
:param original: Text describing the original code object.
|
||||||
|
:param uncompyled: Text describing the uncompyled code object.
|
||||||
|
"""
|
||||||
|
original_lines = original.split('\n')
|
||||||
|
uncompyled_lines = uncompyled.split('\n')
|
||||||
|
args = original_lines, uncompyled_lines, 'original', 'uncompyled'
|
||||||
|
try:
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
diff = difflib.HtmlDiff().make_file(*args)
|
||||||
|
diff = BeautifulSoup(diff, "html.parser")
|
||||||
|
diff.select_one('table[summary="Legends"]').extract()
|
||||||
|
except ImportError:
|
||||||
|
print('\nTo display diff highlighting run:\n pip install BeautifulSoup4')
|
||||||
|
diff = difflib.HtmlDiff().make_table(*args)
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||||
|
f.write(str(diff).encode('utf-8'))
|
||||||
|
|
||||||
|
try:
|
||||||
|
print()
|
||||||
|
html = subprocess.check_output([
|
||||||
|
'elinks',
|
||||||
|
'-dump',
|
||||||
|
'-no-references',
|
||||||
|
'-dump-color-mode',
|
||||||
|
'1',
|
||||||
|
f.name,
|
||||||
|
]).decode('utf-8')
|
||||||
|
print(html)
|
||||||
|
except:
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
def are_instructions_equal(i1, i2):
|
||||||
|
"""
|
||||||
|
Determine if two instructions are approximately equal,
|
||||||
|
ignoring certain fields which we allow to differ, namely:
|
||||||
|
|
||||||
|
* code objects are ignore (should probaby be checked) due to address
|
||||||
|
* line numbers
|
||||||
|
|
||||||
|
:param i1: left instruction to compare
|
||||||
|
:param i2: right instruction to compare
|
||||||
|
|
||||||
|
:return: True if the two instructions are approximately equal, otherwise False.
|
||||||
|
"""
|
||||||
|
result = (1==1
|
||||||
|
and i1.opname == i2.opname
|
||||||
|
and i1.opcode == i2.opcode
|
||||||
|
and i1.arg == i2.arg
|
||||||
|
# ignore differences due to code objects
|
||||||
|
# TODO : Better way of ignoring address
|
||||||
|
and (i1.argval == i2.argval or '<code object' in str(i1.argval))
|
||||||
|
# TODO : Should probably recurse to check code objects
|
||||||
|
and (i1.argrepr == i2.argrepr or '<code object' in i1.argrepr)
|
||||||
|
and i1.offset == i2.offset
|
||||||
|
# ignore differences in line numbers
|
||||||
|
#and i1.starts_line
|
||||||
|
and i1.is_jump_target == i2.is_jump_target
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def are_code_objects_equal(co1, co2):
|
||||||
|
"""
|
||||||
|
Determine if two code objects are approximately equal,
|
||||||
|
see are_instructions_equal for more information.
|
||||||
|
|
||||||
|
:param i1: left code object to compare
|
||||||
|
:param i2: right code object to compare
|
||||||
|
|
||||||
|
:return: True if the two code objects are approximately equal, otherwise False.
|
||||||
|
"""
|
||||||
|
instructions1 = Bytecode(co1)
|
||||||
|
instructions2 = Bytecode(co2)
|
||||||
|
for opcode1, opcode2 in zip(instructions1, instructions2):
|
||||||
|
if not are_instructions_equal(opcode1, opcode2):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def validate_uncompyle(text, mode='exec'):
|
||||||
|
"""
|
||||||
|
Validate decompilation of the given source code.
|
||||||
|
|
||||||
|
:param text: Source to validate decompilation of.
|
||||||
|
"""
|
||||||
|
original_code = compile(text, '<string>', mode)
|
||||||
|
original_dis = _dis_to_text(original_code)
|
||||||
|
original_text = text
|
||||||
|
|
||||||
|
deparsed = deparse_code(PYTHON_VERSION, original_code,
|
||||||
|
compile_mode=mode, out=six.StringIO())
|
||||||
|
uncompyled_text = deparsed.text
|
||||||
|
uncompyled_code = compile(uncompyled_text, '<string>', 'exec')
|
||||||
|
|
||||||
|
if not are_code_objects_equal(uncompyled_code, original_code):
|
||||||
|
|
||||||
|
uncompyled_dis = _dis_to_text(uncompyled_text)
|
||||||
|
|
||||||
|
def output(text, dis):
|
||||||
|
width = 60
|
||||||
|
return '\n\n'.join([
|
||||||
|
' SOURCE CODE '.center(width, '#'),
|
||||||
|
text.strip(),
|
||||||
|
' BYTECODE '.center(width, '#'),
|
||||||
|
dis
|
||||||
|
])
|
||||||
|
|
||||||
|
original = output(original_text, original_dis)
|
||||||
|
uncompyled = output(uncompyled_text, uncompyled_dis)
|
||||||
|
print_diff(original, uncompyled)
|
||||||
|
|
||||||
|
assert 'original' == 'uncompyled'
|
@@ -1,3 +1,3 @@
|
|||||||
pytest
|
pytest>=3.0.0
|
||||||
flake8
|
flake8
|
||||||
hypothesis
|
hypothesis
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
spark-parser >= 1.4.0
|
# Pick up stuff from setup.py
|
||||||
xdis >= 2.2.2
|
-e .
|
||||||
|
2
setup.py
2
setup.py
@@ -24,6 +24,6 @@ setup(
|
|||||||
py_modules = py_modules,
|
py_modules = py_modules,
|
||||||
test_suite = 'nose.collector',
|
test_suite = 'nose.collector',
|
||||||
url = web,
|
url = web,
|
||||||
setup_requires = ['nose>=1.0'],
|
tests_require = ['nose>=1.0'],
|
||||||
version = VERSION,
|
version = VERSION,
|
||||||
zip_safe = zip_safe)
|
zip_safe = zip_safe)
|
||||||
|
@@ -3,7 +3,7 @@ PHONY=check clean dist distclean test test-unit test-functional rmChangeLog clea
|
|||||||
GIT2CL ?= git2cl
|
GIT2CL ?= git2cl
|
||||||
PYTHON ?= python
|
PYTHON ?= python
|
||||||
|
|
||||||
PYTHON_VERSION = $(shell $(PYTHON) -V | cut -d ' ' -f 2 | cut -d'.' -f1,2)
|
PYTHON_VERSION = $(shell $(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2)
|
||||||
NATIVE_CHECK = check-$(PYTHON_VERSION)
|
NATIVE_CHECK = check-$(PYTHON_VERSION)
|
||||||
|
|
||||||
# Set COMPILE='--compile' to force compilation before check
|
# Set COMPILE='--compile' to force compilation before check
|
||||||
@@ -16,15 +16,18 @@ check-short:
|
|||||||
|
|
||||||
# Run all tests
|
# Run all tests
|
||||||
check:
|
check:
|
||||||
@$(PYTHON) -V && PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2`; \
|
$(MAKE) check-$(PYTHON_VERSION)
|
||||||
$(MAKE) check-$$PYTHON_VERSION
|
|
||||||
|
|
||||||
#: Run working tests from Python 2.6 or 2.7
|
#: Run working tests from Python 2.6 or 2.7
|
||||||
check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-2.7-ok
|
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
|
||||||
|
$(PYTHON) test_pythonlib.py --bytecode-3.0 --weak-verify $(COMPILE)
|
||||||
|
|
||||||
#: Run working tests from Python 3.1
|
#: Run working tests from Python 3.1
|
||||||
check-3.1: check-bytecode
|
check-3.1: check-bytecode
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-3.1 --verify $(COMPILE)
|
$(PYTHON) test_pythonlib.py --bytecode-3.1 --weak-verify $(COMPILE)
|
||||||
|
|
||||||
#: Run working tests from Python 3.2
|
#: Run working tests from Python 3.2
|
||||||
check-3.2: check-bytecode
|
check-3.2: check-bytecode
|
||||||
@@ -32,7 +35,7 @@ check-3.2: check-bytecode
|
|||||||
|
|
||||||
#: Run working tests from Python 3.3
|
#: Run working tests from Python 3.3
|
||||||
check-3.3: check-bytecode
|
check-3.3: check-bytecode
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-3.3 --verify $(COMPILE)
|
$(PYTHON) test_pythonlib.py --bytecode-3.3 --weak-verify $(COMPILE)
|
||||||
|
|
||||||
#: Run working tests from Python 3.4
|
#: Run working tests from Python 3.4
|
||||||
check-3.4: check-bytecode check-3.4-ok check-2.7-ok
|
check-3.4: check-bytecode check-3.4-ok check-2.7-ok
|
||||||
@@ -50,25 +53,36 @@ check-3.6: check-bytecode
|
|||||||
check-disasm:
|
check-disasm:
|
||||||
$(PYTHON) dis-compare.py
|
$(PYTHON) dis-compare.py
|
||||||
|
|
||||||
|
#: Check deparsing bytecode 1.x only
|
||||||
|
check-bytecode-1:
|
||||||
|
$(PYTHON) test_pythonlib.py --bytecode-1.5
|
||||||
|
|
||||||
#: Check deparsing bytecode 2.x only
|
#: Check deparsing bytecode 2.x only
|
||||||
check-bytecode-2:
|
check-bytecode-2:
|
||||||
$(PYTHON) test_pythonlib.py \
|
$(PYTHON) test_pythonlib.py \
|
||||||
--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
|
--bytecode-2.5 --bytecode-2.6 --bytecode-2.7 --bytecode-pypy2.7
|
||||||
|
|
||||||
#: Check deparsing bytecode 3.x only
|
#: Check deparsing bytecode 3.x only
|
||||||
check-bytecode-3:
|
check-bytecode-3:
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-3.2 --bytecode-3.3 \
|
$(PYTHON) test_pythonlib.py --bytecode-3.0 \
|
||||||
|
--bytecode-3.1 --bytecode-3.2 --bytecode-3.3 \
|
||||||
--bytecode-3.4 --bytecode-3.5 --bytecode-pypy3.2
|
--bytecode-3.4 --bytecode-3.5 --bytecode-pypy3.2
|
||||||
|
|
||||||
#: Check deparsing bytecode that works running Python 2 and Python 3
|
#: Check deparsing bytecode that works running Python 2 and Python 3
|
||||||
check-bytecode: check-bytecode-3
|
check-bytecode: check-bytecode-3
|
||||||
$(PYTHON) test_pythonlib.py \
|
$(PYTHON) test_pythonlib.py \
|
||||||
--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
|
--bytecode-2.5 --bytecode-2.6 --bytecode-2.7 \
|
||||||
|
--bytecode-pypy2.7 --bytecode-1
|
||||||
|
|
||||||
|
|
||||||
|
#: Check deparsing Python 2.1
|
||||||
|
check-bytecode-2.1:
|
||||||
|
$(PYTHON) test_pythonlib.py --bytecode-2.1
|
||||||
|
|
||||||
#: Check deparsing Python 2.2
|
#: Check deparsing Python 2.2
|
||||||
check-bytecode-2.3:
|
check-bytecode-2.2:
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-2.2
|
$(PYTHON) test_pythonlib.py --bytecode-2.2
|
||||||
|
|
||||||
#: Check deparsing Python 2.3
|
#: Check deparsing Python 2.3
|
||||||
@@ -83,13 +97,32 @@ check-bytecode-2.4:
|
|||||||
check-bytecode-2.5:
|
check-bytecode-2.5:
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-2.5
|
$(PYTHON) test_pythonlib.py --bytecode-2.5
|
||||||
|
|
||||||
|
#: Get grammar coverage for Python 2.5
|
||||||
|
grammar-coverage-2.5:
|
||||||
|
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5
|
||||||
|
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6
|
||||||
|
|
||||||
|
#: Get grammar coverage for Python 2.6
|
||||||
|
grammar-coverage-2.6:
|
||||||
|
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6
|
||||||
|
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9
|
||||||
|
|
||||||
|
#: Get grammar coverage for Python 2.7
|
||||||
|
grammar-coverage-2.7:
|
||||||
|
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7
|
||||||
|
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13
|
||||||
|
|
||||||
#: Check deparsing Python 2.6
|
#: Check deparsing Python 2.6
|
||||||
check-bytecode-2.6:
|
check-bytecode-2.6:
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-2.6
|
$(PYTHON) test_pythonlib.py --bytecode-2.6 --weak-verify
|
||||||
|
|
||||||
#: Check deparsing Python 2.7
|
#: Check deparsing Python 2.7
|
||||||
check-bytecode-2.7:
|
check-bytecode-2.7:
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-2.7
|
$(PYTHON) test_pythonlib.py --bytecode-2.7 --verify
|
||||||
|
|
||||||
|
#: Check deparsing Python 3.0
|
||||||
|
check-bytecode-3.0:
|
||||||
|
$(PYTHON) test_pythonlib.py --bytecode-3.0
|
||||||
|
|
||||||
#: Check deparsing Python 3.1
|
#: Check deparsing Python 3.1
|
||||||
check-bytecode-3.1:
|
check-bytecode-3.1:
|
||||||
|
BIN
test/bytecode_1.5/docstring.pyc
Normal file
BIN
test/bytecode_1.5/docstring.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/exceptions.pyc
Normal file
BIN
test/bytecode_1.5/exceptions.pyc
Normal file
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.
BIN
test/bytecode_1.5/expressions.pyc
Normal file
BIN
test/bytecode_1.5/expressions.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/globals.pyc
Normal file
BIN
test/bytecode_1.5/globals.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/import.pyc
Normal file
BIN
test/bytecode_1.5/import.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/lambda.pyc
Normal file
BIN
test/bytecode_1.5/lambda.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/misc.pyc
Normal file
BIN
test/bytecode_1.5/misc.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/nested_elif.pyc
Normal file
BIN
test/bytecode_1.5/nested_elif.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/print.pyc
Normal file
BIN
test/bytecode_1.5/print.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/slices.pyc
Normal file
BIN
test/bytecode_1.5/slices.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_class.pyc
Normal file
BIN
test/bytecode_1.5/test_class.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_class.pyo
Normal file
BIN
test/bytecode_1.5/test_class.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_del.pyc
Normal file
BIN
test/bytecode_1.5/test_del.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_del.pyo
Normal file
BIN
test/bytecode_1.5/test_del.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_docstring.pyc
Normal file
BIN
test/bytecode_1.5/test_docstring.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_docstring.pyo
Normal file
BIN
test/bytecode_1.5/test_docstring.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_empty.pyc
Normal file
BIN
test/bytecode_1.5/test_empty.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_empty.pyo
Normal file
BIN
test/bytecode_1.5/test_empty.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_exceptions.pyc
Normal file
BIN
test/bytecode_1.5/test_exceptions.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_exceptions.pyo
Normal file
BIN
test/bytecode_1.5/test_exceptions.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_exec.pyc
Normal file
BIN
test/bytecode_1.5/test_exec.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_exec.pyo
Normal file
BIN
test/bytecode_1.5/test_exec.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_expressions.pyc
Normal file
BIN
test/bytecode_1.5/test_expressions.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_expressions.pyo
Normal file
BIN
test/bytecode_1.5/test_expressions.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_functions.pyc
Normal file
BIN
test/bytecode_1.5/test_functions.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_functions.pyo
Normal file
BIN
test/bytecode_1.5/test_functions.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_global.pyc
Normal file
BIN
test/bytecode_1.5/test_global.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_global.pyo
Normal file
BIN
test/bytecode_1.5/test_global.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_globals.pyc
Normal file
BIN
test/bytecode_1.5/test_globals.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_globals.pyo
Normal file
BIN
test/bytecode_1.5/test_globals.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_import.pyc
Normal file
BIN
test/bytecode_1.5/test_import.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_import.pyo
Normal file
BIN
test/bytecode_1.5/test_import.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_integers.pyc
Normal file
BIN
test/bytecode_1.5/test_integers.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_integers.pyo
Normal file
BIN
test/bytecode_1.5/test_integers.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_lambda.pyc
Normal file
BIN
test/bytecode_1.5/test_lambda.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_lambda.pyo
Normal file
BIN
test/bytecode_1.5/test_lambda.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_loops.pyc
Normal file
BIN
test/bytecode_1.5/test_loops.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_loops.pyo
Normal file
BIN
test/bytecode_1.5/test_loops.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_misc.pyc
Normal file
BIN
test/bytecode_1.5/test_misc.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_misc.pyo
Normal file
BIN
test/bytecode_1.5/test_misc.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_nested_elif.pyc
Normal file
BIN
test/bytecode_1.5/test_nested_elif.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_nested_elif.pyo
Normal file
BIN
test/bytecode_1.5/test_nested_elif.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_prettyprint.pyc
Normal file
BIN
test/bytecode_1.5/test_prettyprint.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_prettyprint.pyo
Normal file
BIN
test/bytecode_1.5/test_prettyprint.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_print.pyc
Normal file
BIN
test/bytecode_1.5/test_print.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_print.pyo
Normal file
BIN
test/bytecode_1.5/test_print.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_single_stmt.pyc
Normal file
BIN
test/bytecode_1.5/test_single_stmt.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_single_stmt.pyo
Normal file
BIN
test/bytecode_1.5/test_single_stmt.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_slices.pyc
Normal file
BIN
test/bytecode_1.5/test_slices.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_slices.pyo
Normal file
BIN
test/bytecode_1.5/test_slices.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_tuple_params.pyc
Normal file
BIN
test/bytecode_1.5/test_tuple_params.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_tuple_params.pyo
Normal file
BIN
test/bytecode_1.5/test_tuple_params.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_tuples.pyc
Normal file
BIN
test/bytecode_1.5/test_tuples.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/test_tuples.pyo
Normal file
BIN
test/bytecode_1.5/test_tuples.pyo
Normal file
Binary file not shown.
BIN
test/bytecode_1.5/tuple_params.pyc
Normal file
BIN
test/bytecode_1.5/tuple_params.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/applyEquiv.pyc
Normal file
BIN
test/bytecode_2.1/applyEquiv.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/augmentedAssign.pyc
Normal file
BIN
test/bytecode_2.1/augmentedAssign.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/docstring.pyc
Normal file
BIN
test/bytecode_2.1/docstring.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/exceptions.pyc
Normal file
BIN
test/bytecode_2.1/exceptions.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/exec.pyc
Normal file
BIN
test/bytecode_2.1/exec.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/expressions.pyc
Normal file
BIN
test/bytecode_2.1/expressions.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/extendedImport.pyc
Normal file
BIN
test/bytecode_2.1/extendedImport.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/extendedPrint.pyc
Normal file
BIN
test/bytecode_2.1/extendedPrint.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/globals.pyc
Normal file
BIN
test/bytecode_2.1/globals.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/import.pyc
Normal file
BIN
test/bytecode_2.1/import.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/lambda.pyc
Normal file
BIN
test/bytecode_2.1/lambda.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/listComprehensions.pyc
Normal file
BIN
test/bytecode_2.1/listComprehensions.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/misc.pyc
Normal file
BIN
test/bytecode_2.1/misc.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/nested_elif.pyc
Normal file
BIN
test/bytecode_2.1/nested_elif.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/print.pyc
Normal file
BIN
test/bytecode_2.1/print.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.1/slices.pyc
Normal file
BIN
test/bytecode_2.1/slices.pyc
Normal file
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