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
283 Commits
release-2.
...
release-2.
Author | SHA1 | Date | |
---|---|---|---|
|
300d387349 | ||
|
27ab6fe2f5 | ||
|
2e164763eb | ||
|
d332bde104 | ||
|
0893652943 | ||
|
6efd7afda3 | ||
|
ee3202779a | ||
|
9c072a6a42 | ||
|
277ad36566 | ||
|
af3d46b35c | ||
|
e1bc0c5cd6 | ||
|
5a519ed36a | ||
|
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 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -16,3 +16,5 @@
|
|||||||
/unpyc
|
/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:
|
||||||
|
53
HISTORY.md
53
HISTORY.md
@@ -30,7 +30,7 @@ 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. As
|
The last mention of a release of SPARK from John is around 2002. As
|
||||||
released, although the Early Algorithm parser was in good shape, this
|
released, although the Earley Algorithm parser was in good shape, this
|
||||||
code was woefully lacking as serious Python deparser.
|
code was woefully lacking as serious Python deparser.
|
||||||
|
|
||||||
In the fall of 2000, Hartmut Goebel
|
In the fall of 2000, Hartmut Goebel
|
||||||
@@ -44,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
|
||||||
@@ -65,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
|
||||||
@@ -95,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
|
||||||
@@ -115,9 +118,12 @@ 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+. In doing so, it has been expedient to separate this into three
|
3.2+. In doing so, it has been expedient to separate this into three
|
||||||
projects: load loading and disassembly (xdis), parsing and tree
|
projects:
|
||||||
building (spark_parser), and grammar and semantic actions for
|
|
||||||
decompiling (uncompyle6).
|
* 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
|
||||||
@@ -135,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
|
||||||
|
* Python 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 or want 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,6 +1,7 @@
|
|||||||
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 Makefile
|
||||||
include requirements.txt
|
include requirements.txt
|
||||||
|
115
NEWS
115
NEWS
@@ -1,3 +1,98 @@
|
|||||||
|
uncompyle6 2.11.2 2017-07-09
|
||||||
|
|
||||||
|
- Start supporting Pypy 3.5 (5.7.1-beta)
|
||||||
|
- use xdis 3.5.0's opcode sets and require xdis 3.5.0
|
||||||
|
- Correct some Python 2.4-2.6 loop detection
|
||||||
|
- guard against badly formatted bytecode
|
||||||
|
|
||||||
|
uncompyle6 2.11.1 2017-06-25
|
||||||
|
|
||||||
|
- Python 3.x annotation and function signature fixes
|
||||||
|
- Bump xdis version
|
||||||
|
- Small pysource bug fixes
|
||||||
|
|
||||||
|
uncompyle6 2.11.0 2017-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 2017-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 2017-05-30 Elaine Gordon
|
||||||
|
|
||||||
|
- Add fuzzy offset deparse look up
|
||||||
|
- 3.6 bug fixes
|
||||||
|
- 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 (grkov90)
|
||||||
|
- 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 2017-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 2017-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
|
uncompyle6 2.9.6 2016-12-04
|
||||||
|
|
||||||
- Shorten Python3 grammars with + and *
|
- Shorten Python3 grammars with + and *
|
||||||
@@ -26,7 +121,7 @@ uncompyle6 2.9.6 2016-11-20
|
|||||||
uncompyle6 2.9.5 2016-11-13
|
uncompyle6 2.9.5 2016-11-13
|
||||||
|
|
||||||
- Fix Python 3 bugs:
|
- Fix Python 3 bugs:
|
||||||
* improprer while 1 else
|
* improper while 1 else
|
||||||
* docstring indent
|
* docstring indent
|
||||||
* 3.3 default values in lambda expressions
|
* 3.3 default values in lambda expressions
|
||||||
* start 3.0 decompilation (needs newer xdis)
|
* start 3.0 decompilation (needs newer xdis)
|
||||||
@@ -36,12 +131,12 @@ uncompyle6 2.9.5 2016-11-13
|
|||||||
uncompyle6 2.9.4 2016-11-02
|
uncompyle6 2.9.4 2016-11-02
|
||||||
|
|
||||||
- Handle Python 3.x function annotations
|
- Handle Python 3.x function annotations
|
||||||
- track def keywoard-parameter line-splitting in source code better
|
- track def keyword-parameter line-splitting in source code better
|
||||||
- bump min xdis version to mask previous xdis bug
|
- bump min xdis version to mask previous xdis bug
|
||||||
|
|
||||||
uncompyle6 2.9.3 2016-10-26
|
uncompyle6 2.9.3 2016-10-26
|
||||||
|
|
||||||
Release forced by incompatiblity change in xdis 3.2.0.
|
Release forced by incompatibility change in xdis 3.2.0.
|
||||||
|
|
||||||
- Python 3.1 bugs:
|
- Python 3.1 bugs:
|
||||||
* handle "with ... as"
|
* handle "with ... as"
|
||||||
@@ -73,7 +168,7 @@ uncompyle6 2.9.0 2016-10-09
|
|||||||
this Forces change in requirements.txt and _pkg_info_.py
|
this Forces change in requirements.txt and _pkg_info_.py
|
||||||
- Start Python 1.5 decompiling; another round of work is needed to
|
- Start Python 1.5 decompiling; another round of work is needed to
|
||||||
remove bugs
|
remove bugs
|
||||||
- Simpify python 2.1 grammar
|
- Simplify python 2.1 grammar
|
||||||
- Fix bug with -t ... Wasn't showing source text when -t option was given
|
- Fix bug with -t ... Wasn't showing source text when -t option was given
|
||||||
- Fix 2.1-2.6 bug in list comprehension
|
- Fix 2.1-2.6 bug in list comprehension
|
||||||
|
|
||||||
@@ -96,7 +191,7 @@ control-flow structure detection is done.
|
|||||||
. 3.0 .. 3.2 *args processing
|
. 3.0 .. 3.2 *args processing
|
||||||
. 3.0 .. 3.2 call name and kwargs bug
|
. 3.0 .. 3.2 call name and kwargs bug
|
||||||
. 3.0 .. getting parameter of *
|
. 3.0 .. getting parameter of *
|
||||||
. 3.0 .. handling varible number of args
|
. 3.0 .. handling variable number of args
|
||||||
. 3.0 .. "if" structure bugs
|
. 3.0 .. "if" structure bugs
|
||||||
* 3.5+ if/else bugs
|
* 3.5+ if/else bugs
|
||||||
* 2.2-2.6 bugs
|
* 2.2-2.6 bugs
|
||||||
@@ -147,7 +242,7 @@ uncompyle6 2.7.1 2016-07-26
|
|||||||
|
|
||||||
uncompyle6 2.7.0 2016-07-15
|
uncompyle6 2.7.0 2016-07-15
|
||||||
|
|
||||||
- Many Syntax and verifification bugs removed
|
- Many Syntax and verification bugs removed
|
||||||
tested on standard libraries from 2.3.7 to 3.5.1
|
tested on standard libraries from 2.3.7 to 3.5.1
|
||||||
and they all decompile and verify fine.
|
and they all decompile and verify fine.
|
||||||
I'm sure there are more bugs though.
|
I'm sure there are more bugs though.
|
||||||
@@ -174,9 +269,9 @@ uncompyle6 2.6.0 2016-07-07
|
|||||||
- Better <2.6 vs. 2.7 grammar separation
|
- Better <2.6 vs. 2.7 grammar separation
|
||||||
- Fix some 2.7 deparsing bugs
|
- Fix some 2.7 deparsing bugs
|
||||||
- Fix bug in installing uncompyle6 script
|
- Fix bug in installing uncompyle6 script
|
||||||
- Doc improvments
|
- Doc improvements
|
||||||
|
|
||||||
uncompyle6 2.5.0 2016-06-22 Summer Solstace
|
uncompyle6 2.5.0 2016-06-22 Summer Solstice
|
||||||
|
|
||||||
- Much better Python 3.2-3.5 coverage.
|
- Much better Python 3.2-3.5 coverage.
|
||||||
3.4.6 is probably the best;3.2 and 3.5 are weaker
|
3.4.6 is probably the best;3.2 and 3.5 are weaker
|
||||||
@@ -188,7 +283,7 @@ uncompyle6 2.5.0 2016-06-22 Summer Solstace
|
|||||||
uncompyle6 2.4.0 2016-05-18 (in memory of Lewis Bernstein)
|
uncompyle6 2.4.0 2016-05-18 (in memory of Lewis Bernstein)
|
||||||
|
|
||||||
- Many Python 3 bugs fixed:
|
- Many Python 3 bugs fixed:
|
||||||
* Python 3.2 to 3.5 libaries largely
|
* Python 3.2 to 3.5 libraries largely
|
||||||
uncompyle and most verify
|
uncompyle and most verify
|
||||||
- pydisassembler:
|
- pydisassembler:
|
||||||
* disassembles all code objects in a file
|
* disassembles all code objects in a file
|
||||||
@@ -246,7 +341,7 @@ uncompyle6 2.2.0 2016-04-30
|
|||||||
|
|
||||||
uncompyle6 2.2.0 2016-04-02
|
uncompyle6 2.2.0 2016-04-02
|
||||||
|
|
||||||
- Support single-mode (in addtion to exec-mode) compilation
|
- Support single-mode (in addition to exec-mode) compilation
|
||||||
- Start to DRY Python 2 and Python 3 grammars
|
- Start to DRY Python 2 and Python 3 grammars
|
||||||
- Fix bug in if else ternary construct
|
- Fix bug in if else ternary construct
|
||||||
- Fix bug in uncomplye6 -d and -r options (via lelicopter)
|
- Fix bug in uncomplye6 -d and -r options (via lelicopter)
|
||||||
|
46
README.rst
46
README.rst
@@ -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.1 to 3.6 or
|
source code. It accepts bytecodes from Python version 1.5, and 2.1 to
|
||||||
so, including PyPy bytecode and Dropbox's Python 2.5 bytecode.
|
3.6 or so, including PyPy bytecode and Dropbox's Python 2.5 bytecode.
|
||||||
|
|
||||||
Why this?
|
Why this?
|
||||||
---------
|
---------
|
||||||
@@ -21,7 +21,8 @@ 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 or 3.3 depending on which
|
handled Python 3, and even there, only 3.2 or 3.3 depending on which
|
||||||
code is used. This code pulls these together and moves forward. It
|
code is used. This code pulls these together and moves forward. This
|
||||||
|
project has the most complete support for Python 3.3 and above. It
|
||||||
also addresses a number of open issues in the previous forks.
|
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
|
||||||
@@ -43,10 +44,10 @@ information.
|
|||||||
Requirements
|
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.3-2.7 are supported in the python-2.4 branch.
|
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.1-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
|
||||||
------------
|
------------
|
||||||
@@ -55,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:
|
||||||
@@ -93,6 +94,16 @@ 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
|
||||||
-----------------------
|
-----------------------
|
||||||
@@ -102,7 +113,7 @@ 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
|
at have the same problem. In some cases we can detect an erroneous
|
||||||
decompilation and report that.
|
decompilation and report that.
|
||||||
|
|
||||||
About 90% of the decompilation of Python standard library packages in
|
Over 98% of the decompilation of Python standard library packages in
|
||||||
Python 2.7.12 verifies correctly. Over 99% of Python 2.7 and 3.3-3.5
|
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.
|
"weakly" verify. Python 2.6 drops down to 96% weakly verifying.
|
||||||
Other versions drop off in quality too.
|
Other versions drop off in quality too.
|
||||||
@@ -128,10 +139,12 @@ 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,
|
handle since we don't have a Python interpreter for versions 1.5, 1.6,
|
||||||
and 2.0.
|
and 2.0.
|
||||||
|
|
||||||
Python 3.0 support is weak; Python 3.5 largely works, but still has
|
In the Python 3 series, Python support is is strongest around 3.4 or
|
||||||
some bugs in it. Python 3.6 changes things drastically by using word
|
3.3 and drops off as you move further away from those versions. Python
|
||||||
codes rather than byte codes. That has been addressed, but then it also
|
3.6 changes things drastically by using word codes rather than byte
|
||||||
changes function call opcodes and its semantics.
|
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
|
Currently not all Python magic numbers are supported. Specifically in
|
||||||
some versions of Python, notably Python 3.6, the magic number has
|
some versions of Python, notably Python 3.6, the magic number has
|
||||||
@@ -145,17 +158,20 @@ We also don't handle PJOrion_ obfuscated code. For that try: PJOrion
|
|||||||
Deobfuscator_ to unscramble the bytecode to get valid bytecode before
|
Deobfuscator_ to unscramble the bytecode to get valid bytecode before
|
||||||
trying this tool.
|
trying this tool.
|
||||||
|
|
||||||
|
Handling pathologically long lists of expressions or statements is
|
||||||
|
slow.
|
||||||
|
|
||||||
|
|
||||||
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
|
* 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
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
# 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 :: 5 - Production/Stable',
|
classifiers = ['Development Status :: 5 - Production/Stable',
|
||||||
@@ -20,6 +20,8 @@ classifiers = ['Development Status :: 5 - Production/Stable',
|
|||||||
'Programming Language :: Python :: 2.5',
|
'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.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 :: 5 - Production/Stable',
|
|||||||
# 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.5.1, < 1.6.0',
|
install_requires = ['spark-parser >= 1.6.1, < 1.7.0',
|
||||||
'xdis >= 3.2.3, < 3.3.0']
|
'xdis >= 3.5.0, < 3.6.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
|
||||||
|
)
|
@@ -6,7 +6,7 @@ machine:
|
|||||||
|
|
||||||
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)
|
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)
|
@@ -40,8 +40,10 @@ def test_grammar():
|
|||||||
ignore_set = set(
|
ignore_set = set(
|
||||||
"""
|
"""
|
||||||
JUMP_BACK CONTINUE RETURN_END_IF
|
JUMP_BACK CONTINUE RETURN_END_IF
|
||||||
COME_FROM COME_FROM_EXCEPT COME_FROM_LOOP COME_FROM_WITH
|
COME_FROM COME_FROM_EXCEPT
|
||||||
COME_FROM_FINALLY
|
COME_FROM_EXCEPT_CLAUSE
|
||||||
|
COME_FROM_LOOP COME_FROM_WITH
|
||||||
|
COME_FROM_FINALLY ELSE
|
||||||
LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP
|
LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP
|
||||||
LAMBDA_MARKER RETURN_LAST
|
LAMBDA_MARKER RETURN_LAST
|
||||||
""".split())
|
""".split())
|
||||||
|
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
|
||||||
|
@@ -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,14 @@ 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-bytecode-1 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.1
|
#: Run working tests from Python 3.0
|
||||||
check-3.0: check-bytecode
|
check-3.0: check-bytecode
|
||||||
@echo Python 3.0 testing not done yet
|
$(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
|
||||||
@@ -40,7 +39,7 @@ check-3.3: check-bytecode
|
|||||||
|
|
||||||
#: 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
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-3.4 --weak-verify $(COMPILE)
|
$(PYTHON) test_pythonlib.py --bytecode-3.4 --verify $(COMPILE)
|
||||||
|
|
||||||
#: Run working tests from Python 3.5
|
#: Run working tests from Python 3.5
|
||||||
check-3.5: check-bytecode
|
check-3.5: check-bytecode
|
||||||
@@ -98,9 +97,24 @@ 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:
|
||||||
|
BIN
test/bytecode_2.3/03_if1.pyc
Normal file
BIN
test/bytecode_2.3/03_if1.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.5/02_try_else.pyc
Normal file
BIN
test/bytecode_2.5/02_try_else.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6/01_ops.pyc
Normal file
BIN
test/bytecode_2.6/01_ops.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6/03_double_equals.pyc
Normal file
BIN
test/bytecode_2.6/03_double_equals.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6/03_if_for.pyc
Normal file
BIN
test/bytecode_2.6/03_if_for.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6/03_loop_if_cf.pyc
Normal file
BIN
test/bytecode_2.6/03_loop_if_cf.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6/04_if_and_bug.pyc
Normal file
BIN
test/bytecode_2.6/04_if_and_bug.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.7/01_ops.pyc
Normal file
BIN
test/bytecode_2.7/01_ops.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.7/02_complex.pyc
Normal file
BIN
test/bytecode_2.7/02_complex.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.7/02_while1else.pyc
Normal file
BIN
test/bytecode_2.7/02_while1else.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.7/03_double_equals.pyc
Normal file
BIN
test/bytecode_2.7/03_double_equals.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.7/03_if_1_else.pyc
Normal file
BIN
test/bytecode_2.7/03_if_1_else.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.1/02_ifelse_comprehension.pyc
Normal file
BIN
test/bytecode_3.1/02_ifelse_comprehension.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.1/03_if_1_else.pyc
Normal file
BIN
test/bytecode_3.1/03_if_1_else.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.1/12_if_while_true_pass.pyc
Normal file
BIN
test/bytecode_3.1/12_if_while_true_pass.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.2/01_delete_deref.pyc
Normal file
BIN
test/bytecode_3.2/01_delete_deref.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.2/01_named_and_kwargs.pyc
Normal file
BIN
test/bytecode_3.2/01_named_and_kwargs.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.2/01_try_except_raise.pyc
Normal file
BIN
test/bytecode_3.2/01_try_except_raise.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.2/03_if.pyc
Normal file
BIN
test/bytecode_3.2/03_if.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.3/02_while1else.pyc
Normal file
BIN
test/bytecode_3.3/02_while1else.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.3/12_if_while_true_pass.pyc
Normal file
BIN
test/bytecode_3.3/12_if_while_true_pass.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.4/05_while_true_break.pyc
Normal file
BIN
test/bytecode_3.4/05_while_true_break.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/01_map_unpack.pyc
Normal file
BIN
test/bytecode_3.5/01_map_unpack.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/01_named_and_kwargs.pyc
Normal file
BIN
test/bytecode_3.5/01_named_and_kwargs.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/02_async_for.pyc
Normal file
BIN
test/bytecode_3.5/02_async_for.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/02_build_map_unpack_with_call.pyc-notyet
Normal file
BIN
test/bytecode_3.5/02_build_map_unpack_with_call.pyc-notyet
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/02_try_finally.pyc
Normal file
BIN
test/bytecode_3.5/02_try_finally.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/02_while1else.pyc
Normal file
BIN
test/bytecode_3.5/02_while1else.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/03_async_await.pyc
Normal file
BIN
test/bytecode_3.5/03_async_await.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/03_double_star_unpack.pyc-notyet
Normal file
BIN
test/bytecode_3.5/03_double_star_unpack.pyc-notyet
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/03_while-if-break.pyc-notyet
Normal file
BIN
test/bytecode_3.5/03_while-if-break.pyc-notyet
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/04_CALL_FUNCTION_VAR_KW.pyc
Normal file
BIN
test/bytecode_3.5/04_CALL_FUNCTION_VAR_KW.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/04_def_annotate.pyc
Normal file
BIN
test/bytecode_3.5/04_def_annotate.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.5/10_kw+pos_args-bug.pyc
Normal file
BIN
test/bytecode_3.5/10_kw+pos_args-bug.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/00_assign.pyc
Normal file
BIN
test/bytecode_3.6/00_assign.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/00_docstring.pyc
Normal file
BIN
test/bytecode_3.6/00_docstring.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/00_import.pyc
Normal file
BIN
test/bytecode_3.6/00_import.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/01_call_function.pyc
Normal file
BIN
test/bytecode_3.6/01_call_function.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/01_extended_arg.pyc-notyet
Normal file
BIN
test/bytecode_3.6/01_extended_arg.pyc-notyet
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/01_matrix_multiply.pyc
Normal file
BIN
test/bytecode_3.6/01_matrix_multiply.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/02_build_map_unpack_with_call.pyc-notyet
Normal file
BIN
test/bytecode_3.6/02_build_map_unpack_with_call.pyc-notyet
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/03_async_await.pyc
Normal file
BIN
test/bytecode_3.6/03_async_await.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/03_while-if-break.pyc
Normal file
BIN
test/bytecode_3.6/03_while-if-break.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/03_while_else.pyc
Normal file
BIN
test/bytecode_3.6/03_while_else.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/04_CALL_FUNCTION_VAR_KW.pyc-notyet
Normal file
BIN
test/bytecode_3.6/04_CALL_FUNCTION_VAR_KW.pyc-notyet
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/04_raise.pyc
Normal file
BIN
test/bytecode_3.6/04_raise.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/05_try_finally_pass.pyc
Normal file
BIN
test/bytecode_3.6/05_try_finally_pass.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/10_if_break_finally.pyc
Normal file
BIN
test/bytecode_3.6/10_if_break_finally.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6/11_classbug.pyc
Normal file
BIN
test/bytecode_3.6/11_classbug.pyc
Normal file
Binary file not shown.
18
test/simple_source/bug22/01_ops.py
Normal file
18
test/simple_source/bug22/01_ops.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Statements to beef up grammar coverage rules
|
||||||
|
# Force "inplace" ops
|
||||||
|
y = +10 # UNARY_POSITIVE
|
||||||
|
y /= 1 # INPLACE_DIVIDE
|
||||||
|
y %= 4 # INPLACE_MODULO
|
||||||
|
y **= 1 # INPLACE POWER
|
||||||
|
y >>= 2 # INPLACE_RSHIFT
|
||||||
|
y <<= 2 # INPLACE_LSHIFT
|
||||||
|
y //= 1 # INPLACE_TRUE_DIVIDE
|
||||||
|
y &= 1 # INPLACE_AND
|
||||||
|
y ^= 1 # INPLACE_XOR
|
||||||
|
|
||||||
|
`y` # UNARY_CONVERT - No in Python 3.x
|
||||||
|
|
||||||
|
# Beef up augassign and STORE_SLICE+3
|
||||||
|
x = [1,2,3,4,5]
|
||||||
|
x[0:1] = 1
|
||||||
|
x[0:3] += 1, 2, 3
|
7
test/simple_source/bug22/03_if1.py
Normal file
7
test/simple_source/bug22/03_if1.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# From https://github.com/ToontownInfinite /src/otp/avatar/LocalAvatar.py#L364
|
||||||
|
if 1:
|
||||||
|
def jumpLandAnimFix(self, jumpTime):
|
||||||
|
return 5
|
||||||
|
|
||||||
|
def jumpLand(self):
|
||||||
|
return 6
|
27
test/simple_source/bug25/02_try_else.py
Normal file
27
test/simple_source/bug25/02_try_else.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Python 2.5 bug
|
||||||
|
# Was turning into tryelse when there in fact is no else.
|
||||||
|
def options(self, section):
|
||||||
|
try:
|
||||||
|
opts = self._sections[section].copy()
|
||||||
|
except KeyError:
|
||||||
|
raise NoSectionError(section)
|
||||||
|
opts.update(self._defaults)
|
||||||
|
if '__name__' in opts:
|
||||||
|
del opts['__name__']
|
||||||
|
return opts.keys()
|
||||||
|
|
||||||
|
# From python2.5/distutils/command/register.py
|
||||||
|
def post_to_server(self, urllib2):
|
||||||
|
try:
|
||||||
|
result = 5
|
||||||
|
except urllib2.HTTPError, e:
|
||||||
|
result = e.code, e.msg
|
||||||
|
except urllib2.URLError, e:
|
||||||
|
result = 500
|
||||||
|
else:
|
||||||
|
if self.show_response:
|
||||||
|
result = 10
|
||||||
|
result = 200
|
||||||
|
if self.show_response:
|
||||||
|
result = 8
|
||||||
|
return result
|
7
test/simple_source/bug25/03_if_for.py
Normal file
7
test/simple_source/bug25/03_if_for.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# From Python 2.6. distutils/sysconfig.py
|
||||||
|
def get_config_vars(_config_vars, args):
|
||||||
|
if _config_vars:
|
||||||
|
if args == 1:
|
||||||
|
if args < 8:
|
||||||
|
for key in ('LDFLAGS', 'BASECFLAGS'):
|
||||||
|
_config_vars[key] = 4
|
6
test/simple_source/bug26/03_double_equals.py
Normal file
6
test/simple_source/bug26/03_double_equals.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# From Python 2.7 parse_starttag HTMLParser.pyc
|
||||||
|
attrvalue = [1,2]
|
||||||
|
while attrvalue:
|
||||||
|
if attrvalue[:1] == 5 or \
|
||||||
|
attrvalue[:1] == 2 == attrvalue[-1:]:
|
||||||
|
attrvalue = 10
|
19
test/simple_source/bug26/03_loop_if_cf.py
Normal file
19
test/simple_source/bug26/03_loop_if_cf.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Bug in < 2.6 is having a COME_FROM_LOOP (but we
|
||||||
|
# don't tag that so it is just COME_FROM *before*
|
||||||
|
# a jump back to the loop.
|
||||||
|
def pickup(self, open_players, open_buf, wrap_buf):
|
||||||
|
for aplayer in self._game.active_players:
|
||||||
|
|
||||||
|
if aplayer in open_players:
|
||||||
|
aplayer.send(open_players)
|
||||||
|
|
||||||
|
if self == aplayer:
|
||||||
|
for awatcher in self._watchers:
|
||||||
|
if awatcher._can_see_detail:
|
||||||
|
awatcher.send(open_buf)
|
||||||
|
else:
|
||||||
|
awatcher.send(wrap_buf)
|
||||||
|
else:
|
||||||
|
self._game.send(aplayer.side)
|
||||||
|
else:
|
||||||
|
self._game.send(aplayer.side, wrap_buf)
|
1
test/simple_source/bug27+/03_if_1_else.py
Normal file
1
test/simple_source/bug27+/03_if_1_else.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1 if 1 else __file__
|
12
test/simple_source/bug31/02_ifelse_comprehension.py
Normal file
12
test/simple_source/bug31/02_ifelse_comprehension.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Python 2.7 sqlalchemy-1.013/sql/crud.py
|
||||||
|
def _extend_values_for_multiparams(compiler, stmt, c):
|
||||||
|
c(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
(compiler() if compiler()
|
||||||
|
else compiler())
|
||||||
|
if c in stmt else compiler(),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
for i in enumerate(stmt)
|
||||||
|
)
|
@@ -8,3 +8,23 @@ def open(file, mode = "r", buffering = None,
|
|||||||
encoding = None, errors = None,
|
encoding = None, errors = None,
|
||||||
newline = None, closefd = True) -> "IOBase":
|
newline = None, closefd = True) -> "IOBase":
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
def foo1(x: 'an argument that defaults to 5' = 5):
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
def div(a: dict(type=float, help='the dividend'),
|
||||||
|
b: dict(type=float, help='the divisor (must be different than 0)')
|
||||||
|
) -> dict(type=float, help='the result of dividing a by b'):
|
||||||
|
"""Divide a by b"""
|
||||||
|
return a / b
|
||||||
|
|
||||||
|
class TestSignatureObject(unittest.TestCase):
|
||||||
|
def test_signature_on_wkwonly(self):
|
||||||
|
def test(*, a:float, b:str) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class SupportsInt(_Protocol):
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def __int__(self) -> int:
|
||||||
|
pass
|
||||||
|
@@ -18,3 +18,12 @@ def __init__(self, defaults=None, dict_type=_default_dict,
|
|||||||
default_section=DEFAULTSECT,
|
default_section=DEFAULTSECT,
|
||||||
interpolation=_UNSET):
|
interpolation=_UNSET):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Bug found by hypothesis in creating function calls
|
||||||
|
# thanks to moagstar
|
||||||
|
def fn(a, b, d):
|
||||||
|
return (a, b, d)
|
||||||
|
|
||||||
|
b = {'b': 1,
|
||||||
|
'd': 2}
|
||||||
|
fn(a=0, **b)
|
||||||
|
9
test/simple_source/bug32/01_try_except_raise.py
Normal file
9
test/simple_source/bug32/01_try_except_raise.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# From 3.2 _abcoll.py
|
||||||
|
def pop(self):
|
||||||
|
it = iter(self)
|
||||||
|
try:
|
||||||
|
value = next(it)
|
||||||
|
except StopIteration:
|
||||||
|
raise KeyError
|
||||||
|
self.discard(value)
|
||||||
|
return value
|
11
test/simple_source/bug32/03_if.py
Normal file
11
test/simple_source/bug32/03_if.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# From 3.2 shlex.py
|
||||||
|
def _samefile(os, src, dst):
|
||||||
|
if hasattr(os.path, 'samefile'):
|
||||||
|
try:
|
||||||
|
return os.path.samefile(src, dst)
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# All other platforms: check for same pathname.
|
||||||
|
return (os.path.normcase(os.path.abspath(src)) ==
|
||||||
|
os.path.normcase(os.path.abspath(dst)))
|
4
test/simple_source/bug33/01_delete_deref.py
Normal file
4
test/simple_source/bug33/01_delete_deref.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
def a():
|
||||||
|
del y
|
||||||
|
def b():
|
||||||
|
return y
|
16
test/simple_source/bug33/01_if_try_except.py
Normal file
16
test/simple_source/bug33/01_if_try_except.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# From 3.3.5 _osx_support.py
|
||||||
|
def _get_system_version():
|
||||||
|
if __file__ is None:
|
||||||
|
try:
|
||||||
|
m = 5
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
m = 10
|
||||||
|
finally:
|
||||||
|
m = 15
|
||||||
|
if m is not None:
|
||||||
|
m = 20
|
||||||
|
|
||||||
|
return m
|
16
test/simple_source/bug33/01_try_except.py
Normal file
16
test/simple_source/bug33/01_try_except.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# From 3.3.5 _osx_support.py
|
||||||
|
def _get_system_version():
|
||||||
|
if __file__ is None:
|
||||||
|
try:
|
||||||
|
m = 5
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
m = 10
|
||||||
|
finally:
|
||||||
|
m = 15
|
||||||
|
if m is not None:
|
||||||
|
m = 20
|
||||||
|
|
||||||
|
return m
|
@@ -1,3 +1,6 @@
|
|||||||
# From Python 3.3.6 hmac.py
|
# From Python 3.3.6 hmac.py
|
||||||
# Problem was getting wrong placement of positional args
|
# Problem was getting wrong placement of positional args
|
||||||
digest_cons = lambda d=b'': 5
|
digest_cons = lambda d=b'': 5
|
||||||
|
|
||||||
|
# Handle single kwarg
|
||||||
|
lambda *, d=0: None
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user