You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Compare commits
200 Commits
release-py
...
3.4.1
Author | SHA1 | Date | |
---|---|---|---|
|
f0f9676f52 | ||
|
be610aa6b3 | ||
|
1494bb2049 | ||
|
d62dc3daac | ||
|
5ad51707e3 | ||
|
f28c255804 | ||
|
315965300f | ||
|
9bd85fe5a0 | ||
|
c6e3168c31 | ||
|
7969b19c2b | ||
|
f8bfde4a8e | ||
|
e2b309fa30 | ||
|
1ebfde6927 | ||
|
73619de3f5 | ||
|
600cd0b8ee | ||
|
90a2ed2c9e | ||
|
8728cb6a99 | ||
|
8daedaf063 | ||
|
4a4a20995e | ||
|
c923ce9afe | ||
|
88901c6901 | ||
|
31f7d14eab | ||
|
388d1da970 | ||
|
66294d54f7 | ||
|
55783c2712 | ||
|
fd580f3c60 | ||
|
a781006ff1 | ||
|
0be3d5a530 | ||
|
bc3cd0102b | ||
|
6e6d590268 | ||
|
71bdc8dc6a | ||
|
71735ca7ef | ||
|
9f121ef00c | ||
|
2e01f42f65 | ||
|
3f9a862277 | ||
|
cc531cf90a | ||
|
c7124ad9ca | ||
|
44a4aab0a7 | ||
|
2a52982d52 | ||
|
56e5e8dcef | ||
|
ecab7d7b09 | ||
|
e39a902e56 | ||
|
e2914ed552 | ||
|
f425db33b7 | ||
|
68c5b2338f | ||
|
e55a0410c9 | ||
|
0fe8961418 | ||
|
8cd331a32b | ||
|
4c76931807 | ||
|
7b7f794913 | ||
|
50e46531ce | ||
|
67ef34977f | ||
|
32c7b8f23d | ||
|
2f06d1eeb0 | ||
|
999f1fb0f9 | ||
|
76eef9a149 | ||
|
c8b945fb56 | ||
|
a1e7c16dbe | ||
|
35f14e4357 | ||
|
49d1a50354 | ||
|
0dc19a8fdd | ||
|
f6aa8b2baf | ||
|
887a006849 | ||
|
e26c7407a0 | ||
|
69823af553 | ||
|
e96498eaf0 | ||
|
9d6d6a355d | ||
|
04c53c1086 | ||
|
96866f94a7 | ||
|
d371839c99 | ||
|
24afe072b7 | ||
|
e2d7f01298 | ||
|
b39112b601 | ||
|
20b513fc81 | ||
|
d369017122 | ||
|
6675ea2cd0 | ||
|
4b82806d6c | ||
|
3c06b82931 | ||
|
c680416f92 | ||
|
58c8fe5a66 | ||
|
aea1adeb85 | ||
|
c871a4ecc5 | ||
|
cd9eca7bff | ||
|
002720988c | ||
|
08f23567a6 | ||
|
43348d7d24 | ||
|
164e9d4b5c | ||
|
37e4754268 | ||
|
c3257a9b79 | ||
|
70b0704967 | ||
|
76dcaf9bf0 | ||
|
21fd506fbb | ||
|
efe0914814 | ||
|
5981c7eae9 | ||
|
36ef1607af | ||
|
b2d97f9847 | ||
|
24ba5d7f40 | ||
|
eae3f0d77b | ||
|
a54fba7993 | ||
|
719d2d7232 | ||
|
e82cabc278 | ||
|
9ab086b207 | ||
|
4022e80d6d | ||
|
9811c5bc42 | ||
|
354796fffd | ||
|
ab696b316a | ||
|
2f99da8199 | ||
|
fd5f4fa5b8 | ||
|
8e4168674d | ||
|
c8fc6a704c | ||
|
622d6f849c | ||
|
10d8aed4c0 | ||
|
86fd5dbf7a | ||
|
9fe1752359 | ||
|
48ae7a6964 | ||
|
117b4ff4f1 | ||
|
e9002038f8 | ||
|
9d47b99932 | ||
|
59b012df6f | ||
|
44d7cbcf6f | ||
|
9bae73679f | ||
|
ceebe9ab60 | ||
|
b7e22b4530 | ||
|
c7b20edba0 | ||
|
64e35b09db | ||
|
a0d4daf5ff | ||
|
afa6a00db8 | ||
|
d8f0d31475 | ||
|
dd76a6f253 | ||
|
cb40caa73c | ||
|
fd59879510 | ||
|
c9cae2d09e | ||
|
af209dc142 | ||
|
ad419e0ed9 | ||
|
ee5c7da790 | ||
|
39c12704a8 | ||
|
3b3fc09b60 | ||
|
f7697ccd7b | ||
|
e364499bb9 | ||
|
9db59f1b80 | ||
|
a5cdb50154 | ||
|
792ef5b5b8 | ||
|
47ed0795b2 | ||
|
cccf33573b | ||
|
3c3e5c82fc | ||
|
436260dc9a | ||
|
8f0674706b | ||
|
01cc184716 | ||
|
2771cb46ab | ||
|
9ed4326f7e | ||
|
e3b10b62d7 | ||
|
59b8f18486 | ||
|
bcf6939312 | ||
|
3b7f49c01d | ||
|
ae976e991a | ||
|
8fe6309650 | ||
|
4c4aa393df | ||
|
a8b8c2908c | ||
|
cb406e2581 | ||
|
20b16c44ff | ||
|
3abe8d11d3 | ||
|
26140934da | ||
|
b62752eca1 | ||
|
9db446d928 | ||
|
46acb74745 | ||
|
44e1288e2f | ||
|
ce9270dda0 | ||
|
3d732db3cc | ||
|
009a74da7d | ||
|
251eb6da1b | ||
|
8b5e0f49f8 | ||
|
1cc08d9598 | ||
|
d99e78d46d | ||
|
b94cce7b12 | ||
|
fe786b2b95 | ||
|
bf56fbeeec | ||
|
6d8d9fd83b | ||
|
78ca6a0c1f | ||
|
86dd321256 | ||
|
4db364f701 | ||
|
c03b039714 | ||
|
d97509495e | ||
|
4d793ba1b2 | ||
|
590d2f44f1 | ||
|
e875b79a75 | ||
|
b57ca392a2 | ||
|
a132e2ace6 | ||
|
b05500dd49 | ||
|
65307f257c | ||
|
8909fe8d37 | ||
|
733a44e22f | ||
|
f2f17740ee | ||
|
393e5c9303 | ||
|
8c611476fe | ||
|
6df65a87bc | ||
|
bb94c7f5bc | ||
|
8e9ce0be31 | ||
|
bc49469704 | ||
|
5905cce1de | ||
|
af816c9e60 |
@@ -27,9 +27,9 @@ jobs:
|
||||
# VM instead of a container) see https://circleci.com/docs/2.0/executor-types/
|
||||
# To see the list of pre-built images that CircleCI provides for most common languages see
|
||||
# https://circleci.com/docs/2.0/circleci-images/
|
||||
docker:
|
||||
- image: circleci/build-image:ubuntu-14.04-XXL-upstart-1189-5614f37
|
||||
command: /sbin/init
|
||||
machine:
|
||||
python:
|
||||
version: 2.7.14
|
||||
steps:
|
||||
# Machine Setup
|
||||
# If you break your build into multiple jobs with workflows, you will probably want to do the parts of this that are relevant in each
|
||||
@@ -42,25 +42,24 @@ jobs:
|
||||
# This is based on your 1.0 configuration file or project settings
|
||||
- run:
|
||||
working_directory: ~/rocky/python-uncompyle6
|
||||
command: pyenv local 2.7.11 && pyenv rehash && pip install virtualenv && pip install nose && pip install pep8 && pip install six && pyenv rehash
|
||||
command: pip install virtualenv && pip install nose && pip install pep8 && pyenv rehash
|
||||
# Dependencies
|
||||
# This would typically go in either a build or a build-and-test job when using workflows
|
||||
# Restore the dependency cache
|
||||
- restore_cache:
|
||||
keys:
|
||||
# This branch if available
|
||||
- v1-dep-{{ .Branch }}-
|
||||
# Default branch if not
|
||||
- v1-dep-master-
|
||||
# Any branch if there are none on the default branch - this should be unnecessary if you have your default branch configured correctly
|
||||
- v1-dep-
|
||||
- v2-dependencies-{{ .Branch }}-
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- v2-dependencies-
|
||||
|
||||
# This is based on your 1.0 configuration file or project settings
|
||||
- run: pip install --upgrade setuptools
|
||||
- run: pip install -e .
|
||||
- run: pip install pytest==3.2.5 hypothesis==3.0.0
|
||||
- run: pip install -r requirements-dev.txt
|
||||
|
||||
# Save dependency cache
|
||||
- save_cache:
|
||||
key: v1-dep-{{ .Branch }}-{{ epoch }}
|
||||
key: v2-dependencies-{{ .Branch }}-{{ epoch }}
|
||||
paths:
|
||||
# This is a broad list of cache paths to include many possible development environments
|
||||
# You can probably delete some of these entries
|
||||
@@ -69,14 +68,13 @@ jobs:
|
||||
- ~/.m2
|
||||
- ~/.ivy2
|
||||
- ~/.bundle
|
||||
- ~/.go_workspace
|
||||
- ~/.gradle
|
||||
- ~/.cache/bower
|
||||
|
||||
# Test
|
||||
# This would typically be a build job when using workflows, possibly combined with build
|
||||
# This is based on your 1.0 configuration file or project settings
|
||||
- run: python ./setup.py develop && make check-2.7
|
||||
- run: cd ./test/stdlib && pyenv local 2.7.11 && bash ./runtests.sh 'test_[p-z]*.py'
|
||||
- run: cd ./test/stdlib && bash ./runtests.sh 'test_[p-z]*.py'
|
||||
# Teardown
|
||||
# If you break your build into multiple jobs with workflows, you will probably want to do the parts of this that are relevant in each
|
||||
# Save test results
|
||||
|
@@ -3,7 +3,6 @@ language: python
|
||||
python:
|
||||
- '3.5'
|
||||
- '2.7'
|
||||
- '2.6'
|
||||
- '3.4'
|
||||
- '3.6'
|
||||
|
||||
|
@@ -115,7 +115,7 @@ mechanisms and addressed problems and extensions by some other means.
|
||||
Specifically, in `uncompyle`, decompilation of python bytecode 2.5 &
|
||||
2.6 is done by transforming the byte code into a pseudo-2.7 Python
|
||||
bytecode and is based on code from Eloi Vanderbeken. A bit of this
|
||||
could have bene easily added by modifying grammar rules.
|
||||
could have been easily added by modifying grammar rules.
|
||||
|
||||
This project, `uncompyle6`, abandons that approach for various
|
||||
reasons. Having a grammar per Python version is much cleaner and it
|
||||
|
267
NEWS.md
267
NEWS.md
@@ -1,3 +1,89 @@
|
||||
3.4.1 2019-10-02
|
||||
================
|
||||
|
||||
- Correct assert{,2} transforms Fixes #289
|
||||
- Fragment parsing fixes:
|
||||
* Wasn't handling 3-arg %p
|
||||
* fielding error in code_deparse()
|
||||
- Use newer xdis to better track Python 3.8.0
|
||||
|
||||
|
||||
3.4.0 2019-08-24 Totoro
|
||||
=======================
|
||||
|
||||
The main change is to add a tree-transformation phase. This simplifies the
|
||||
code a little and allows us to turn `if ...: raise AssertionError` into
|
||||
`assert`, and many `if ..: else if ...` into `if ... elif ..`
|
||||
|
||||
Use options `--show=before` and `--show=after` to see the before the tree transformation phase and after the tree transformation phase.
|
||||
|
||||
Most of the heavy lifting for this was done by x0ret.
|
||||
|
||||
Other changes:
|
||||
|
||||
- Fix issue #275, #283 (process to fix this bug is documented on wiki), #284
|
||||
- blacken more code
|
||||
- CircleCI adjustments for a changing CircleCi
|
||||
- Require more recent `xdis` for Python 3.8
|
||||
- Fix bugs in code using `BUILD_LIST_UNPACK` and variants
|
||||
|
||||
3.3.5 2019-07-03 Pre Independence Day
|
||||
=====================================
|
||||
|
||||
Again, most of the work in this is release is thanks to x0ret.
|
||||
|
||||
- Handle annotation arguments in Python 3.x
|
||||
- Fix _vararg_ and function signatures in 3.x
|
||||
- Some 3.x < 3.6 `while` (1)/`if` fixes — others remain
|
||||
- Start reinstating `else if` -> `elif`
|
||||
- `LOAD_CONST` -> `LOAD_CODE` where appropriate
|
||||
- option `--weak-verify` is now `--syntax-verify`
|
||||
- code cleanups, start using [black](https://github.com/python/black) to reformat text
|
||||
|
||||
|
||||
3.3.4 2019-06-19 Fleetwood at 65
|
||||
================================
|
||||
|
||||
Most of the work in this is release is thanks to x0ret.
|
||||
|
||||
- Major work was done by x0ret to correct function signatures and include annotation types
|
||||
- Handle Python 3.6 `STORE_ANNOTATION` [#58](https://github.com/rocky/python-uncompyle6/issues/58)
|
||||
- Friendlier assembly output
|
||||
- `LOAD_CONST` replaced by `LOAD_STR` where appropriate to simplify parsing and improve clarity
|
||||
- remove unneeded parenthesis in a generator expression when it is the single argument to the function [#247](https://github.com/rocky/python-uncompyle6/issues/246)
|
||||
- Bug in noting an async function [#246](https://github.com/rocky/python-uncompyle6/issues/246)
|
||||
- Handle Unicode docstrings and fix docstring bugs [#241](https://github.com/rocky/python-uncompyle6/issues/241)
|
||||
- Add short option -T as an alternate for --tree+
|
||||
- Some grammar cleanup
|
||||
|
||||
3.3.3 2019-05-19 Henry and Lewis
|
||||
================================
|
||||
|
||||
As before, decomplation bugs fixed. The focus has primarily been on
|
||||
Python 3.7. But with this release, releases will be put on hold,as a
|
||||
better control-flow detection is worked on . This has been needed for a
|
||||
while, and is long overdue. It will probably also take a while to get
|
||||
done as good as what we have now.
|
||||
|
||||
However this work will be done in a new project
|
||||
[decompyle3](https://github.com/rocky/python-decompile3). In contrast
|
||||
to _uncompyle6_ the code will be written assuming a modern Python 3,
|
||||
e.g. 3.7. It is originally intended to decompile Python version 3.7
|
||||
and greater.
|
||||
|
||||
* A number of Python 3.7+ chained comparisons were fixed
|
||||
* Revise Python 3.6ish format string handling
|
||||
* Go over operator precedence, e.g. for AST `IfExp`
|
||||
|
||||
Reported Bug Fixes
|
||||
------------------
|
||||
|
||||
* [#239: 3.7 handling of 4-level attribute import](https://github.com/rocky/python-uncompyle6/issues/239),
|
||||
* [#229: Inconsistent if block in python3.6](https://github.com/rocky/python-uncompyle6/issues/229),
|
||||
* [#227: Args not appearing in decompiled src when kwargs is specified explicitly (call_ex_kw)](https://github.com/rocky/python-uncompyle6/issues/227)
|
||||
2.7 confusion around "and" versus comprehension "if"
|
||||
* [#225: 2.7 confusion around "and" vs comprehension "if"](https://github.com/rocky/python-uncompyle6/issues/225)
|
||||
|
||||
3.3.2 2019-05-03 Better Friday
|
||||
==============================
|
||||
|
||||
@@ -10,8 +96,7 @@ some span back as far as 2.x
|
||||
But as before, many more remain in the 3.7 and 3.8 range which will
|
||||
get addressed in future releases
|
||||
|
||||
Pypy 3.6 support was started. Pypy 3.x detection fixed (via xdis)
|
||||
|
||||
Pypy 3.6 support was started. Pypy 3.x detection fixed (via `xdis`)
|
||||
|
||||
3.3.1 2019-04-19 Good Friday
|
||||
==========================
|
||||
@@ -20,14 +105,14 @@ Lots of decomplation bugs, especially in the 3.x series fixed. Don't worry thoug
|
||||
|
||||
* Add annotation return values in 3.6+
|
||||
* Fix 3.6+ lambda parameter handling decompilation
|
||||
* Fix 3.7+ chained comparision decompilation
|
||||
* Fix 3.7+ chained comparison decompilation
|
||||
* split out semantic-action customization into more separate files
|
||||
* Add 3.8 try/else
|
||||
* Fix 2.7 generator decompilation
|
||||
* Fix some parser failures fixes in 3.4+ using test_pyenvlib
|
||||
* Add more run tests
|
||||
|
||||
3.3.0 2019-43-14 Holy Week
|
||||
3.3.0 2019-04-14 Holy Week
|
||||
==========================
|
||||
|
||||
* First cut at Python 3.8 (many bugs remain)
|
||||
@@ -42,23 +127,25 @@ Mostly more of the same: bug fixes and pull requests.
|
||||
Bug Fixes
|
||||
-----------
|
||||
|
||||
* [#155: Python 3.x bytecode confusing "try/else" with "try" in a loop](https://github.com/rocky/python-uncompyle6/issues/155),
|
||||
* [#200: Python 3 bug in not detecting end bounds of an "if" ... "elif"](https://github.com/rocky/python-uncompyle6/issues/200),
|
||||
* [#208: Comma placement in 3.6 and 3.7 **kwargs](https://github.com/rocky/python-uncompyle6/issues/208),
|
||||
* [#209: Fix "if" return boundary in 3.6+](https://github.com/rocky/python-uncompyle6/issues/209),
|
||||
* [#221: Wrong grammar for nested ifelsestmt (in Python 3.7 at least)](https://github.com/rocky/python-uncompyle6/issues/221)
|
||||
* [#215: 2.7 can have two JUMP_BACKs at the end of a while loop](https://github.com/rocky/python-uncompyle6/issues/215)
|
||||
* [#209: Fix "if" return boundary in 3.6+](https://github.com/rocky/python-uncompyle6/issues/209),
|
||||
* [#208: Comma placement in 3.6 and 3.7 **kwargs](https://github.com/rocky/python-uncompyle6/issues/208),
|
||||
* [#200: Python 3 bug in not detecting end bounds of an "if" ... "elif"](https://github.com/rocky/python-uncompyle6/issues/200),
|
||||
* [#155: Python 3.x bytecode confusing "try/else" with "try" in a loop](https://github.com/rocky/python-uncompyle6/issues/155),
|
||||
|
||||
|
||||
Pull Requests
|
||||
----------------
|
||||
|
||||
* [#202: Better "assert" statement detemination in Python 2.7](https://github.com/rocky/python-uncompyle6/pull/211)
|
||||
* [#202: Better "assert" statement determination in Python 2.7](https://github.com/rocky/python-uncompyle6/pull/211)
|
||||
* [#204: Python 3.7 testing](https://github.com/rocky/python-uncompyle6/pull/204)
|
||||
* [#205: Run more f-string tests on Python 3.7](https://github.com/rocky/python-uncompyle6/pull/205)
|
||||
* [#211: support utf-8 chars in Python 3 sourcecode](https://github.com/rocky/python-uncompyle6/pull/202)
|
||||
|
||||
|
||||
|
||||
3.2.5 2018-12-30 Clearout sale
|
||||
3.2.5 2018-12-30 Clear-out sale
|
||||
======================================
|
||||
|
||||
- 3.7.2 Remove deprecation warning on regexp string that isn't raw
|
||||
@@ -93,7 +180,7 @@ Pull Requests
|
||||
|
||||
- Add rudimentary 1.4 support (still a bit buggy)
|
||||
- add --tree+ option to show formatting rule, when it is constant
|
||||
- Python 2.7.15candidate1 support (via xdis)
|
||||
- Python 2.7.15candidate1 support (via `xdis`)
|
||||
- bug fixes, especially for 3.7 (but 2.7 and 3.6 and others as well)
|
||||
|
||||
3.1.3 2018-04-16
|
||||
@@ -123,14 +210,14 @@ Jesus on Friday's New York Times puzzle: "I'm stuck on 2A"
|
||||
- reduce 3.5, 3.6 control-flow bugs
|
||||
- reduce ambiguity in rules that lead to long (exponential?) parses
|
||||
- limit/isolate some 2.6/2.7,3.x grammar rules
|
||||
- more runtime testing of decompiled code
|
||||
- more removal of parenthesis around calls via setting precidence
|
||||
- more run-time testing of decompiled code
|
||||
- more removal of parenthesis around calls via setting precedence
|
||||
|
||||
3.1.0 2018-03-21 Equinox
|
||||
==============================
|
||||
|
||||
- Add code_deparse_with_offset() fragment function.
|
||||
- Correct paramenter call fragment deparse_code()
|
||||
- Correct parameter call fragment deparse_code()
|
||||
- Lots of 3.6, 3.x, and 2.7 bug fixes
|
||||
About 5% of 3.6 fail parsing now. But
|
||||
semantics still needs much to be desired.
|
||||
@@ -198,24 +285,24 @@ function calls and definitions.
|
||||
2.15.1 2018-01-27
|
||||
=====================
|
||||
|
||||
- Add --linemap option to give line correspondences
|
||||
- Add `--linemap` option to give line correspondences
|
||||
between original source lines and reconstructed line sources.
|
||||
It is far from perfect, but it is a start
|
||||
- Add a new class of tests: tests which when decompiled check themselves
|
||||
- Split off Python version semantic action customizations into its own file
|
||||
- Fix 2.7 bug in ifelse loop statement
|
||||
- Handle 3.6+ EXTENDED_ARGs for POP_JUMP_IF... instructions
|
||||
- Correct 3.6+ calls with kwargs
|
||||
- Fix 2.7 bug in `if`/`else` loop statement
|
||||
- Handle 3.6+ `EXTENDED_ARG`s for `POP_JUMP_IF..` instructions
|
||||
- Correct 3.6+ calls with `kwargs`
|
||||
- Describe the difficulty of 3.6 in README
|
||||
|
||||
2.14.3 2018-01-19
|
||||
=====================
|
||||
|
||||
- Fix bug in 3.5+ await stmt
|
||||
- Fix bug in 3.5+ `await` statement
|
||||
- Better version to magic handling; handle 3.5.2 .. 3.5.4 versions
|
||||
- Improve/correct test_pyenvlib.py status messages
|
||||
- Fix some 2.7 and 2.6 parser bugs
|
||||
- Fix whilelse parsing bugs
|
||||
- Fix `whilelse` parsing bugs
|
||||
- Correct 2.5- decorator parsing
|
||||
- grammar for decorators matches AST a little more
|
||||
- better tests in setup.py for running the right version of Python
|
||||
@@ -226,15 +313,15 @@ function calls and definitions.
|
||||
|
||||
Decompilation bug fixes, mostly 3.6 and pre 2.7
|
||||
|
||||
- 3.6 FUNCTION_EX (somewhat)
|
||||
- 3.6 FUNCTION_EX_KW fixes
|
||||
- 3.6 MAKE_FUNCTION fixes
|
||||
- correct 3.5 CALL_FUNCTION_VAR
|
||||
- 3.6 `FUNCTION_EX` (somewhat)
|
||||
- 3.6 `FUNCTION_EX_KW` fixes
|
||||
- 3.6 `MAKE_FUNCTION` fixes
|
||||
- correct 3.5 `CALL_FUNCTION_VAR`
|
||||
- stronger 3.x "while 1" testing
|
||||
- Fix bug in if's with "pass" bodies. Fixes #104
|
||||
- try/else and try/finally fixes on 2.6-
|
||||
- limit pypy customization to pypy
|
||||
- Add addr fields in COME_FROMS
|
||||
- Add addr fields in `COME_FROM`S
|
||||
- Allow use of full instructions in parser reduction routines
|
||||
- Reduce grammar in Python 3 by specialization more to specific
|
||||
Python versions
|
||||
@@ -243,11 +330,11 @@ Decompilation bug fixes, mostly 3.6 and pre 2.7
|
||||
2.14.1 2017-12-10 Dr. Gecko
|
||||
===================================
|
||||
|
||||
- Many decompilation bugfixes
|
||||
- Many decompilation bug fixes
|
||||
- Grammar rule reduction and version isolation
|
||||
- Match higher-level nonterminal names more closely
|
||||
with Python AST
|
||||
- Start automated Python stdlib testing - full round trip
|
||||
- Start automated Python _stdlib_ testing — full round trip
|
||||
|
||||
2.14.0 2017-11-26 johnnybamazing
|
||||
=========================================
|
||||
@@ -256,7 +343,7 @@ Decompilation bug fixes, mostly 3.6 and pre 2.7
|
||||
and remove used grammar rules
|
||||
- Fix a number of bytecode decompile problems
|
||||
(many more remain)
|
||||
- Add stdlib/runtests.sh for even more rigorous testing
|
||||
- Add `stdlib/runtests.sh` for even more rigorous testing
|
||||
|
||||
2.13.3 2017-11-13
|
||||
=====================
|
||||
@@ -272,16 +359,16 @@ Overall: better 3.6 decompiling and some much needed code refactoring and cleanu
|
||||
rather trying to parse the bytecode array. This largely been done in for versions 3.x;
|
||||
3.0 custom mangling code has been reduced;
|
||||
some 2.x conversion has been done, but more is desired. This make it possible to...
|
||||
- Handle EXTENDED_ARGS better. While relevant to all Python versions it is most noticeable in
|
||||
version 3.6+ where in switching to wordcodes the size of operands has been reduced from 2**16
|
||||
to 2**8. JUMP instruction then often need EXTENDED_ARGS.
|
||||
- Handle `EXTENDED_ARGS` better. While relevant to all Python versions it is most noticeable in
|
||||
version 3.6+ where in switching to wordcodes the size of operands has been reduced from 2^16
|
||||
to 2^8. `JUMP` instruction then often need EXTENDED_ARGS.
|
||||
- Refactor find_jump_targets() with via working of of instructions rather the bytecode array.
|
||||
- use --weak-verify more and additional fuzzing on verify()
|
||||
- use `--weak-verify` more and additional fuzzing on verify()
|
||||
- fragment parser now ignores errors in nested function definitions; an parameter was
|
||||
added to assist here. Ignoring errors may be okay because the fragment parser often just needs,
|
||||
well, *fragments*.
|
||||
- Distinguish RETURN_VALUE from RETURN_END_IF in exception bodies better in 3.6
|
||||
- bug in 3.x language changes: import queue via import Queue
|
||||
- Distinguish `RETURN_VALUE` from `RETURN_END_IF` in exception bodies better in 3.6
|
||||
- bug in 3.x language changes: import queue via `import Queue`
|
||||
- reinstate some bytecode tests since decompiling has gotten better
|
||||
- Revise how to report a bug
|
||||
|
||||
@@ -301,12 +388,12 @@ Overall: better 3.6 decompiling and some much needed code refactoring and cleanu
|
||||
- Fixes in deparsing lambda expressions
|
||||
- Improve table-semantics descriptions
|
||||
- Document hacky customize arg count better (until we can remove it)
|
||||
- Update to use xdis 3.7.0 or greater
|
||||
- Update to use `xdis` 3.7.0 or greater
|
||||
|
||||
2.12.0 2017-09-26
|
||||
=====================
|
||||
|
||||
- Use xdis 3.6.0 or greater now
|
||||
- Use `xdis` 3.6.0 or greater now
|
||||
- Small semantic table cleanups
|
||||
- Python 3.4's terms a little names better
|
||||
- Slightly more Python 3.7, but still failing a lot
|
||||
@@ -320,13 +407,13 @@ Overall: better 3.6 decompiling and some much needed code refactoring and cleanu
|
||||
2.11.4 2017-08-15
|
||||
=====================
|
||||
|
||||
* scanner and parser now allow 3-part version string lookups,
|
||||
* scanner and parser now allow 3-part version string look ups,
|
||||
e.g. 2.7.1 We allow a float here, but if passed a string like '2.7'. or
|
||||
* unpin 3.5.1. xdis 3.5.4 has been release and fixes the problems we had. Use that.
|
||||
* some routines here moved to xdis. Use the xdis version
|
||||
* README.rst: Link typo Name is trepan2 now not trepan
|
||||
* xdis-forced change adjust for COMPARE_OP "is-not" in
|
||||
semanatic routines. We need "is not".
|
||||
* unpin 3.5.1. `xdis` 3.5.4 has been release and fixes the problems we had. Use that.
|
||||
* some routines here moved to `xdis`. Use the `xdis` version
|
||||
* `README.rst`: Link typo Name is _trepan2_ now not _trepan_
|
||||
* xdis-forced change adjust for `COMPARE_OP` "is-not" in
|
||||
semantic routines. We need "is not".
|
||||
* Some PyPy tolerance in validate testing.
|
||||
* Some pyston tolerance
|
||||
|
||||
@@ -336,15 +423,15 @@ Overall: better 3.6 decompiling and some much needed code refactoring and cleanu
|
||||
Very minor changes
|
||||
|
||||
- RsT doc fixes and updates
|
||||
- use newer xdis, but not too new; 3.5.2 breaks uncompyle6
|
||||
- use xdis opcode sets
|
||||
- xdis "exception match" is now "exception-match"
|
||||
- use newer `xdis`, but not too new; 3.5.2 breaks uncompyle6
|
||||
- use `xdis` opcode sets
|
||||
- `xdis` "exception match" is now "exception-match"
|
||||
|
||||
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
|
||||
- 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
|
||||
|
||||
@@ -352,55 +439,55 @@ Very minor changes
|
||||
=====================
|
||||
|
||||
- Python 3.x annotation and function signature fixes
|
||||
- Bump xdis version
|
||||
- Small pysource bug fixes
|
||||
- Bump `xdis` version
|
||||
- Small `pysource.py` bug fixes
|
||||
|
||||
2.11.0 2017-06-18 Fleetwood
|
||||
==================================
|
||||
|
||||
- Major improvements in fragment tracking
|
||||
* Add nonterminal node in extractInfo
|
||||
* Add nonterminal node in `extractInfo()`
|
||||
* tag more offsets in expressions
|
||||
* tag array subscripts
|
||||
* set YIELD value offset in a <yield> expr
|
||||
* 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
|
||||
- Fix bug in snowflake Python 3.5 `*args`, `kwargs`
|
||||
|
||||
2.10.1 2017-06-3 Marylin Frankel
|
||||
========================================
|
||||
|
||||
- fix some fragments parsing bugs
|
||||
- was returning the wrong type sometimes in deparse_code_around_offset()
|
||||
- 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
|
||||
- track changes to `ifelstrmtr` node from `pysource.py` into fragments
|
||||
|
||||
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)
|
||||
- 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
|
||||
- `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
|
||||
- 3.x pass statement inside `while True`
|
||||
- Improve 3.2 decompilation
|
||||
- Fixed -o argument processing (grkov90)
|
||||
- Fixed `-o` argument processing (grkov90)
|
||||
- Reduce scope of LOAD_ASSERT as expr to 3.4+
|
||||
- "await" statement fixes
|
||||
- `await` statement fixes
|
||||
- 2.3, 2.4 "if 1 .." fixes
|
||||
- 3.x annotation fixes
|
||||
|
||||
2.9.11 2017-04-06
|
||||
=====================
|
||||
|
||||
- Better support for Python 3.5+ BUILD_MAP_UNPACK
|
||||
- Start 3.6 CALL_FUNCTION_EX support
|
||||
- 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
|
||||
|
||||
2.9.10 2017-02-25
|
||||
@@ -408,7 +495,7 @@ Very minor changes
|
||||
|
||||
- Python grammar rule fixes
|
||||
- Add ability to get grammar coverage on runs
|
||||
- Handle Python 3.6 opcode BUILD_CONST_KEYMAP
|
||||
- Handle Python 3.6 opcode `BUILD_CONST_KEYMAP`
|
||||
|
||||
2.9.9 2016-12-16
|
||||
|
||||
@@ -424,13 +511,13 @@ Very minor changes
|
||||
====================
|
||||
|
||||
- Better control-flow detection
|
||||
- pseudo instruction THEN in 2.x
|
||||
- pseudo instruction `THEN` in 2.x
|
||||
to disambiguate if from and
|
||||
- fix bug in --verify option
|
||||
- fix bug in `--verify` option
|
||||
- DRY (a little) control-flow detection
|
||||
- fix syntax in tuples with one element
|
||||
- if AST rule inheritance in Python 2.5
|
||||
- NAME_MODULE removal for Python <= 2.4
|
||||
- `NAME_MODULE` removal for Python <= 2.4
|
||||
- verify call fixes for Python <= 2.4
|
||||
- more Python lint
|
||||
|
||||
@@ -441,9 +528,9 @@ Very minor changes
|
||||
- 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
|
||||
- verify: allow `RETURN_VALUE` to match `RETURN_END_IF`
|
||||
- some 3.2 compatibility
|
||||
- Better Python 3 control flow detection by adding Pseudo ELSE opcodes
|
||||
- Better Python 3 control flow detection by adding Pseudo `ELSE` opcodes
|
||||
|
||||
2.9.6 2016-12-04
|
||||
====================
|
||||
@@ -459,7 +546,7 @@ Very minor changes
|
||||
|
||||
- Correct MANIFEST.in
|
||||
- More AST grammar checking
|
||||
- --linemapping option or linenumbers.line_number_mapping()
|
||||
- `--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.
|
||||
@@ -479,7 +566,7 @@ Very minor changes
|
||||
* improper while 1 else
|
||||
* docstring indent
|
||||
* 3.3 default values in lambda expressions
|
||||
* start 3.0 decompilation (needs newer xdis)
|
||||
* start 3.0 decompilation (needs newer `xdis`)
|
||||
- Start grammar misparse checking
|
||||
|
||||
|
||||
@@ -493,12 +580,12 @@ Very minor changes
|
||||
2.9.3 2016-10-26
|
||||
====================
|
||||
|
||||
Release forced by incompatibility change in xdis 3.2.0.
|
||||
Release forced by incompatibility change in` xdis` 3.2.0.
|
||||
|
||||
- Python 3.1 bugs:
|
||||
* handle "with ... as"
|
||||
* handle "with"
|
||||
* Start handling def (...) -> yy (has bugs still)
|
||||
* 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)
|
||||
@@ -524,12 +611,12 @@ Release forced by incompatibility change in xdis 3.2.0.
|
||||
2.9.0 2016-10-09
|
||||
====================
|
||||
|
||||
- Use xdis 3.0.0 protocol load_module.
|
||||
- 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
|
||||
- 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
|
||||
|
||||
2.8.4 2016-10-08
|
||||
@@ -538,8 +625,8 @@ Release forced by incompatibility change in xdis 3.2.0.
|
||||
- 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
|
||||
- `COME_FROM` suffixes added in Python3
|
||||
- use `.py` extension in verification disassembly
|
||||
|
||||
2.8.3 2016-09-11 live from NYC!
|
||||
=======================================
|
||||
@@ -584,8 +671,8 @@ control-flow structure detection is done.
|
||||
- Add Python 2.2 decompilation
|
||||
|
||||
- Fix bugs
|
||||
* PyPy LOOKUP_METHOD bug
|
||||
* Python 3.6 FORMAT_VALUE handles expressions now
|
||||
* PyPy `LOOKUP_METHOD` bug
|
||||
* Python 3.6 `FORMAT_VALUE` handles expressions now
|
||||
|
||||
2.8.0 2016-08-03
|
||||
====================
|
||||
@@ -635,7 +722,7 @@ control-flow structure detection is done.
|
||||
====================
|
||||
|
||||
- Improve Python 2.6 bytecode deparsing:
|
||||
stdlib now will deparse something
|
||||
_stdlib_ now will deparse something
|
||||
- Better <2.6 vs. 2.7 grammar separation
|
||||
- Fix some 2.7 deparsing bugs
|
||||
- Fix bug in installing uncompyle6 script
|
||||
@@ -698,9 +785,9 @@ control-flow structure detection is done.
|
||||
2.3.2 2016-05-1
|
||||
===================
|
||||
|
||||
- Add --version option standalone scripts
|
||||
- Add `--version` option standalone scripts
|
||||
- Correct License information in package
|
||||
- expose fns uncompyle_file, load_file, and load_module
|
||||
- expose functions `uncompyle_file()`, `load_file()`, and `load_module()`
|
||||
- Start to DRY Python2 and Python3 grammars Separate out 3.2, and 3.5+
|
||||
specific grammar code
|
||||
- Fix bug in 3.5+ constant map parsing
|
||||
@@ -708,12 +795,12 @@ control-flow structure detection is done.
|
||||
2.3.0, 2.3.1 2016-04-30
|
||||
=============================
|
||||
|
||||
- Require spark_parser >= 1.1.0
|
||||
- Require `spark_parser` >= 1.1.0
|
||||
|
||||
2.2.0 2016-04-30
|
||||
====================
|
||||
|
||||
- Spark is no longer here but pulled separate package spark_parse
|
||||
- Spark is no longer here but pulled separate package [spark_parser](https://pypi.org/project/spark_parser/)
|
||||
- Python 3 parsing fixes
|
||||
- More tests
|
||||
|
||||
@@ -723,7 +810,7 @@ control-flow structure detection is done.
|
||||
- Support single-mode (in addition to exec-mode) compilation
|
||||
- Start to DRY Python 2 and Python 3 grammars
|
||||
- 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)
|
||||
|
||||
|
||||
2.1.3 2016-01-02
|
||||
@@ -731,7 +818,7 @@ control-flow structure detection is done.
|
||||
|
||||
- Limited support for decompiling Python 3.5
|
||||
- Improve Python 3 class deparsing
|
||||
- Handle MAKE_CLOSURE opcode
|
||||
- Handle `MAKE_CLOSURE` opcode
|
||||
- Start to DRY opcode code.
|
||||
- increase test coverage
|
||||
- fix misc small bugs and some improvements
|
||||
@@ -773,5 +860,5 @@ Changes from uncompyle2
|
||||
|
||||
SPARK:
|
||||
add option to show grammar rules applied
|
||||
allow Python-style # comments in grammar
|
||||
allow Python-style `#` comments in grammar
|
||||
Runs on Python 3 and Python 2
|
||||
|
84
README.rst
84
README.rst
@@ -1,4 +1,8 @@
|
||||
|buildstatus| |Latest Version| |Supported Python Versions|
|
||||
|buildstatus| |Pypi Installs| |Latest Version| |Supported Python Versions|
|
||||
|
||||
|
||||
|
||||
|packagestatus|
|
||||
|
||||
uncompyle6
|
||||
==========
|
||||
@@ -93,8 +97,8 @@ This uses setup.py, so it follows the standard Python routine:
|
||||
A GNU makefile is also provided so :code:`make install` (possibly as root or
|
||||
sudo) will do the steps above.
|
||||
|
||||
Testing
|
||||
-------
|
||||
Running Tests
|
||||
-------------
|
||||
|
||||
::
|
||||
|
||||
@@ -122,16 +126,32 @@ For usage help:
|
||||
|
||||
$ 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.
|
||||
Verification
|
||||
------------
|
||||
|
||||
You can also cross compare the results with pycdc_ . Since they work
|
||||
differently, bugs here often aren't in that, and vice versa.
|
||||
In older versions of Python it was possible to verify bytecode by
|
||||
decompiling bytecode, and then compiling using the Python interpreter
|
||||
for that bytecode version. Having done this the bytecode produced
|
||||
could be compared with the original bytecode. However as Python's code
|
||||
generation got better, this no longer was feasible.
|
||||
|
||||
If you want Python syntax verification of the correctness of the
|
||||
decompilation process, add the :code:`--syntax-verify` option. However since
|
||||
Python syntax changes, you should use this option if the bytecode is
|
||||
the right bytecode for the Python interpreter that will be checking
|
||||
the syntax.
|
||||
|
||||
You can also cross compare the results with another python decompiler
|
||||
like pycdc_ . Since they work differently, bugs here often aren't in
|
||||
that, and vice versa.
|
||||
|
||||
There is an interesting class of these programs that is readily
|
||||
available give stronger verification: those programs that when run
|
||||
test themselves. Our test suite includes these.
|
||||
|
||||
And Python comes with another a set of programs like this: its test
|
||||
suite for the standard library. We have some code in :code:`test/stdlib` to
|
||||
facilitate this kind of checking too.
|
||||
|
||||
Known Bugs/Restrictions
|
||||
-----------------------
|
||||
@@ -146,27 +166,6 @@ All of the Python decompilers that I have looked at have problems
|
||||
decompiling Python's control flow. In some cases we can detect an
|
||||
erroneous decompilation and report that.
|
||||
|
||||
In older versions of Python it was possible to verify bytecode by
|
||||
decompiling bytecode, and then compiling using the Python interpreter
|
||||
for that bytecode version. Having done this the bytecode produced
|
||||
could be compared with the original bytecode. However as Python's code
|
||||
generation got better, this is no longer feasible.
|
||||
|
||||
There verification that we use that doesn't check bytecode for
|
||||
equivalence but does check to see if the resulting decompiled source
|
||||
is a valid Python program by running the Python interpreter. Because
|
||||
the Python language has changed so much, for best results you should
|
||||
use the same Python version in checking as was used in creating the
|
||||
bytecode.
|
||||
|
||||
There are however an interesting class of these programs that is
|
||||
readily available give stronger verification: those programs that
|
||||
when run check some computation, or even better themselves.
|
||||
|
||||
And already Python has a set of programs like this: the test suite
|
||||
for the standard library that comes with Python. We have some
|
||||
code in `test/stdlib` to facilitate this kind of checking.
|
||||
|
||||
Python support is strongest in Python 2 for 2.7 and drops off as you
|
||||
get further away from that. Support is also probably pretty good for
|
||||
python 2.3-2.4 since a lot of the goodness of early the version of the
|
||||
@@ -182,20 +181,24 @@ In the Python 3 series, Python support is is strongest around 3.4 or
|
||||
3.0 is weird in that it in some ways resembles 2.6 more than it does
|
||||
3.1 or 2.7. Python 3.6 changes things drastically by using word codes
|
||||
rather than byte codes. As a result, the jump offset field in a jump
|
||||
instruction argument has been reduced. This makes the `EXTENDED_ARG`
|
||||
instruction argument has been reduced. This makes the :code:`EXTENDED_ARG`
|
||||
instructions are now more prevalent in jump instruction; previously
|
||||
they had been rare. Perhaps to compensate for the additional
|
||||
`EXTENDED_ARG` instructions, additional jump optimization has been
|
||||
:code:`EXTENDED_ARG` instructions, additional jump optimization has been
|
||||
added. So in sum handling control flow by ad hoc means as is currently
|
||||
done is worse.
|
||||
|
||||
Between Python 3.5, 3.6 and 3.7 there have been major changes to the
|
||||
`MAKE_FUNCTION` and `CALL_FUNCTION` instructions.
|
||||
:code:`MAKE_FUNCTION` and :code:`CALL_FUNCTION` instructions.
|
||||
|
||||
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,
|
||||
changes several times within a version.
|
||||
|
||||
**We support only released versions, not candidate versions.** Note however
|
||||
that the magic of a released version is usually the same as the *last* candidate version prior to release.
|
||||
|
||||
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.
|
||||
@@ -218,7 +221,7 @@ See Also
|
||||
* https://github.com/zrax/pycdc : purports to support all versions of Python. It is written in C++ and is most accurate for Python versions around 2.7 and 3.3 when the code was more actively developed. Accuracy for more recent versions of Python 3 and early versions of Python are especially lacking. See its `issue tracker <https://github.com/zrax/pycdc/issues>`_ for details. Currently lightly maintained.
|
||||
* https://code.google.com/archive/p/unpyc3/ : supports Python 3.2 only. The above projects use a different decompiling technique than what is used here. Currently unmaintained.
|
||||
* https://github.com/figment/unpyc3/ : fork of above, but supports Python 3.3 only. Includes some fixes like supporting function annotations. Currently unmaintained.
|
||||
* https://github.com/wibiti/uncompyle2 : supports Python 2.7 only, but does that fairly well. There are situtations where `uncompyle6` results are incorrect while `uncompyle2` results are not, but more often uncompyle6 is correct when uncompyle2 is not. Because `uncompyle6` adheres to accuracy over idiomatic Python, `uncompyle2` can produce more natural-looking code when it is correct. Currently `uncompyle2` is lightly maintained. See its issue `tracker <https://github.com/wibiti/uncompyle2/issues>`_ for more details
|
||||
* https://github.com/wibiti/uncompyle2 : supports Python 2.7 only, but does that fairly well. There are situations where :code:`uncompyle6` results are incorrect while :code:`uncompyle2` results are not, but more often uncompyle6 is correct when uncompyle2 is not. Because :code:`uncompyle6` adheres to accuracy over idiomatic Python, :code:`uncompyle2` can produce more natural-looking code when it is correct. Currently :code:`uncompyle2` is lightly maintained. See its issue `tracker <https://github.com/wibiti/uncompyle2/issues>`_ for more details
|
||||
* `How to report a bug <https://github.com/rocky/python-uncompyle6/blob/master/HOW-TO-REPORT-A-BUG.md>`_
|
||||
* The HISTORY_ file.
|
||||
* https://github.com/rocky/python-xdis : Cross Python version disassembler
|
||||
@@ -226,7 +229,7 @@ See Also
|
||||
* https://github.com/rocky/python-uncompyle6/wiki : Wiki Documents which describe the code and aspects of it in more detail
|
||||
|
||||
|
||||
.. _trepan: https://pypi.python.org/pypi/trepan2
|
||||
.. _trepan: https://pypi.python.org/pypi/trepan2g
|
||||
.. _compiler: https://pypi.python.org/pypi/spark_parser
|
||||
.. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md
|
||||
.. _debuggers: https://pypi.python.org/pypi/trepan3k
|
||||
@@ -235,9 +238,12 @@ See Also
|
||||
.. _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
|
||||
:target: https://travis-ci.org/rocky/python-uncompyle6
|
||||
.. |packagestatus| image:: https://repology.org/badge/vertical-allrepos/python:uncompyle6.svg
|
||||
:target: https://repology.org/project/python:uncompyle6/versions
|
||||
.. _PJOrion: http://www.koreanrandom.com/forum/topic/15280-pjorion-%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%B4%D0%B5%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%BE%D0%B1%D1%84
|
||||
.. _Deobfuscator: https://github.com/extremecoders-re/PjOrion-Deobfuscator
|
||||
.. _Py2EXE: https://en.wikipedia.org/wiki/Py2exe
|
||||
.. |Supported Python Versions| image:: https://img.shields.io/pypi/pyversions/uncompyle6.svg
|
||||
.. |Latest Version| image:: https://badge.fury.io/py/uncompyle6.svg
|
||||
:target: https://badge.fury.io/py/uncompyle6
|
||||
.. |Pypi Installs| image:: https://pepy.tech/badge/uncompyle6/month
|
||||
|
@@ -26,46 +26,46 @@ copyright = """
|
||||
Copyright (C) 2015-2019 Rocky Bernstein <rb@dustyfeet.com>.
|
||||
"""
|
||||
|
||||
classifiers = ['Development Status :: 5 - Production/Stable',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2.4',
|
||||
'Programming Language :: Python :: 2.5',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3.0',
|
||||
'Programming Language :: Python :: 3.1',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Software Development :: Debuggers',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
classifiers = ["Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 2.4",
|
||||
"Programming Language :: Python :: 2.5",
|
||||
"Programming Language :: Python :: 2.6",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3.0",
|
||||
"Programming Language :: Python :: 3.1",
|
||||
"Programming Language :: Python :: 3.2",
|
||||
"Programming Language :: Python :: 3.3",
|
||||
"Programming Language :: Python :: 3.4",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Topic :: Software Development :: Debuggers",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
]
|
||||
|
||||
# The rest in alphabetic order
|
||||
author = "Rocky Bernstein, Hartmut Goebel, John Aycock, and others"
|
||||
author_email = "rb@dustyfeet.com"
|
||||
entry_points = {
|
||||
'console_scripts': [
|
||||
'uncompyle6=uncompyle6.bin.uncompile:main_bin',
|
||||
'pydisassemble=uncompyle6.bin.pydisassemble:main',
|
||||
"console_scripts": [
|
||||
"uncompyle6=uncompyle6.bin.uncompile:main_bin",
|
||||
"pydisassemble=uncompyle6.bin.pydisassemble:main",
|
||||
]}
|
||||
ftp_url = None
|
||||
install_requires = ['spark-parser >= 1.8.7, < 1.9.0',
|
||||
'xdis >= 4.0.1, < 4.1.0']
|
||||
install_requires = ["spark-parser >= 1.8.9, < 1.9.0",
|
||||
"xdis >= 4.0.4, < 4.1.0"]
|
||||
|
||||
license = 'GPL3'
|
||||
mailing_list = 'python-debugger@googlegroups.com'
|
||||
modname = 'uncompyle6'
|
||||
license = "GPL3"
|
||||
mailing_list = "python-debugger@googlegroups.com"
|
||||
modname = "uncompyle6"
|
||||
py_modules = None
|
||||
short_desc = 'Python cross-version byte-code decompiler'
|
||||
web = 'https://github.com/rocky/python-uncompyle6/'
|
||||
short_desc = "Python cross-version byte-code decompiler"
|
||||
web = "https://github.com/rocky/python-uncompyle6/"
|
||||
|
||||
# tracebacks in zip files are funky and not debuggable
|
||||
zip_safe = True
|
||||
@@ -82,5 +82,5 @@ def read(*rnames):
|
||||
return open(os.path.join(srcdir, *rnames)).read()
|
||||
|
||||
# Get info from files; set: long_description and VERSION
|
||||
long_description = ( read("README.rst") + '\n' )
|
||||
exec(read('uncompyle6/version.py'))
|
||||
long_description = ( read("README.rst") + "\n" )
|
||||
exec(read("uncompyle6/version.py"))
|
||||
|
@@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
|
||||
echo "This script should be *sourced* rather than run directly through bash"
|
||||
exit 1
|
||||
fi
|
||||
export PYVERSIONS='3.6.8 3.7.3 2.6.9 3.3.7 2.7.16 3.2.6 3.1.5 3.4.8'
|
||||
export PYVERSIONS='3.6.9 3.7.4 2.6.9 3.3.7 2.7.16 3.2.6 3.1.5 3.4.10 3.5.7'
|
||||
|
@@ -6,4 +6,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
|
||||
echo "This script should be *sourced* rather than run directly through bash"
|
||||
exit 1
|
||||
fi
|
||||
export PYVERSIONS='2.4.6 2.5.6'
|
||||
export PYVERSIONS='2.4.6 2.5.6 2.6.9'
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PYTHON_VERSION=3.6.5
|
||||
PYTHON_VERSION=3.6.8
|
||||
|
||||
# FIXME put some of the below in a common routine
|
||||
function finish {
|
||||
|
@@ -61,7 +61,7 @@ build_script:
|
||||
|
||||
test_script:
|
||||
# Run the project tests
|
||||
- "%CMD_IN_ENV% python test/test_pyenvlib.py --native --weak-verify"
|
||||
- "%CMD_IN_ENV% python test/test_pyenvlib.py --native --syntax-verify"
|
||||
|
||||
after_test:
|
||||
# If tests are successful, create binary packages for the project.
|
||||
|
@@ -1,78 +0,0 @@
|
||||
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()
|
@@ -1,9 +1,12 @@
|
||||
# std
|
||||
# test
|
||||
from uncompyle6 import PYTHON_VERSION, deparse_code
|
||||
import sys
|
||||
from uncompyle6 import PYTHON_VERSION, code_deparse
|
||||
import pytest
|
||||
pytestmark = pytest.mark.skipif(PYTHON_VERSION <= 2.6,
|
||||
reason='hypothesis needs 2.7 or later')
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
PYTHON_VERSION <= 2.6, reason="hypothesis needs 2.7 or later"
|
||||
)
|
||||
if PYTHON_VERSION > 2.6:
|
||||
|
||||
import hypothesis
|
||||
@@ -11,29 +14,31 @@ if PYTHON_VERSION > 2.6:
|
||||
|
||||
# uncompyle6
|
||||
|
||||
|
||||
@st.composite
|
||||
def expressions(draw):
|
||||
# todo : would be nice to generate expressions using hypothesis however
|
||||
# this is pretty involved so for now just use a corpus of expressions
|
||||
# from which to select.
|
||||
return draw(st.sampled_from((
|
||||
'abc',
|
||||
'len(items)',
|
||||
'x + 1',
|
||||
'lineno',
|
||||
'container',
|
||||
'self.attribute',
|
||||
'self.method()',
|
||||
# These expressions are failing, I think these are control
|
||||
# flow problems rather than problems with FORMAT_VALUE,
|
||||
# however I need to confirm this...
|
||||
#'sorted(items, key=lambda x: x.name)',
|
||||
#'func(*args, **kwargs)',
|
||||
#'text or default',
|
||||
#'43 if life_the_universe and everything else None'
|
||||
)))
|
||||
|
||||
return draw(
|
||||
st.sampled_from(
|
||||
(
|
||||
"abc",
|
||||
"len(items)",
|
||||
"x + 1",
|
||||
"lineno",
|
||||
"container",
|
||||
"self.attribute",
|
||||
"self.method()",
|
||||
# These expressions are failing, I think these are control
|
||||
# flow problems rather than problems with FORMAT_VALUE,
|
||||
# however I need to confirm this...
|
||||
#'sorted(items, key=lambda x: x.name)',
|
||||
#'func(*args, **kwargs)',
|
||||
#'text or default',
|
||||
#'43 if life_the_universe and everything else None'
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@st.composite
|
||||
def format_specifiers(draw):
|
||||
@@ -54,36 +59,37 @@ if PYTHON_VERSION > 2.6:
|
||||
|
||||
:return: An example format_specifier.
|
||||
"""
|
||||
alphabet_strategy = st.characters(min_codepoint=ord('a'), max_codepoint=ord('z'))
|
||||
alphabet_strategy = st.characters(
|
||||
min_codepoint=ord("a"), max_codepoint=ord("z")
|
||||
)
|
||||
fill = draw(st.one_of(alphabet_strategy, st.none()))
|
||||
align = draw(st.sampled_from(list('<>=^')))
|
||||
fill_align = (fill + align or '') if fill else ''
|
||||
align = draw(st.sampled_from(list("<>=^")))
|
||||
fill_align = (fill + align or "") if fill else ""
|
||||
|
||||
type_ = draw(st.sampled_from('bcdeEfFgGnosxX%'))
|
||||
can_have_sign = type_ in 'deEfFgGnoxX%'
|
||||
can_have_comma = type_ in 'deEfFgG%'
|
||||
can_have_precision = type_ in 'fFgG'
|
||||
can_have_pound = type_ in 'boxX%'
|
||||
can_have_zero = type_ in 'oxX'
|
||||
type_ = draw(st.sampled_from("bcdeEfFgGnosxX%"))
|
||||
can_have_sign = type_ in "deEfFgGnoxX%"
|
||||
can_have_comma = type_ in "deEfFgG%"
|
||||
can_have_precision = type_ in "fFgG"
|
||||
can_have_pound = type_ in "boxX%"
|
||||
can_have_zero = type_ in "oxX"
|
||||
|
||||
sign = draw(st.sampled_from(list('+- ') + [''])) if can_have_sign else ''
|
||||
pound = draw(st.sampled_from(('#', '',))) if can_have_pound else ''
|
||||
zero = draw(st.sampled_from(('0', '',))) if can_have_zero else ''
|
||||
sign = draw(st.sampled_from(list("+- ") + [""])) if can_have_sign else ""
|
||||
pound = draw(st.sampled_from(("#", ""))) if can_have_pound else ""
|
||||
zero = draw(st.sampled_from(("0", ""))) if can_have_zero else ""
|
||||
|
||||
int_strategy = st.integers(min_value=1, max_value=1000)
|
||||
|
||||
width = draw(st.one_of(int_strategy, st.none()))
|
||||
width = str(width) if width is not None else ''
|
||||
width = str(width) if width is not None else ""
|
||||
|
||||
comma = draw(st.sampled_from((',', '',))) if can_have_comma else ''
|
||||
comma = draw(st.sampled_from((",", ""))) if can_have_comma else ""
|
||||
if can_have_precision:
|
||||
precision = draw(st.one_of(int_strategy, st.none()))
|
||||
precision = '.' + str(precision) if precision else ''
|
||||
precision = "." + str(precision) if precision else ""
|
||||
else:
|
||||
precision = ''
|
||||
|
||||
return ''.join((fill_align, sign, pound, zero, width, comma, precision, type_,))
|
||||
precision = ""
|
||||
|
||||
return "".join((fill_align, sign, pound, zero, width, comma, precision, type_))
|
||||
|
||||
@st.composite
|
||||
def fstrings(draw):
|
||||
@@ -96,9 +102,7 @@ if PYTHON_VERSION > 2.6:
|
||||
:return: A valid f-string.
|
||||
"""
|
||||
character_strategy = st.characters(
|
||||
blacklist_characters='\r\n\'\\s{}',
|
||||
min_codepoint=1,
|
||||
max_codepoint=1000,
|
||||
blacklist_characters="\r\n'\\s{}", min_codepoint=1, max_codepoint=1000
|
||||
)
|
||||
is_raw = draw(st.booleans())
|
||||
integer_strategy = st.integers(min_value=0, max_value=3)
|
||||
@@ -106,53 +110,49 @@ if PYTHON_VERSION > 2.6:
|
||||
content = []
|
||||
for _ in range(expression_count):
|
||||
expression = draw(expressions())
|
||||
conversion = draw(st.sampled_from(('', '!s', '!r', '!a',)))
|
||||
conversion = draw(st.sampled_from(("", "!s", "!r", "!a")))
|
||||
has_specifier = draw(st.booleans())
|
||||
specifier = ':' + draw(format_specifiers()) if has_specifier else ''
|
||||
content.append('{{{}{}}}'.format(expression, conversion, specifier))
|
||||
specifier = ":" + draw(format_specifiers()) if has_specifier else ""
|
||||
content.append("{{{}{}}}".format(expression, conversion, specifier))
|
||||
content.append(draw(st.text(character_strategy)))
|
||||
content = ''.join(content)
|
||||
return "f{}'{}'".format('r' if is_raw else '', content)
|
||||
content = "".join(content)
|
||||
return "f{}'{}'".format("r" if is_raw else "", content)
|
||||
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION != 3.6, reason='need Python 3.6')
|
||||
@pytest.mark.skipif(PYTHON_VERSION != 3.6, reason="need Python 3.6")
|
||||
@hypothesis.given(format_specifiers())
|
||||
def test_format_specifiers(format_specifier):
|
||||
"""Verify that format_specifiers generates valid specifiers"""
|
||||
try:
|
||||
exec('"{:' + format_specifier + '}".format(0)')
|
||||
except ValueError as e:
|
||||
if 'Unknown format code' not in str(e):
|
||||
if "Unknown format code" not in str(e):
|
||||
raise
|
||||
|
||||
|
||||
def run_test(text):
|
||||
hypothesis.assume(len(text))
|
||||
hypothesis.assume("f'{" in text)
|
||||
expr = text + '\n'
|
||||
code = compile(expr, '<string>', 'single')
|
||||
deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single')
|
||||
recompiled = compile(deparsed.text, '<string>', 'single')
|
||||
expr = text + "\n"
|
||||
code = compile(expr, "<string>", "single")
|
||||
deparsed = code_deparse(code, sys.stdout, PYTHON_VERSION, compile_mode="single")
|
||||
recompiled = compile(deparsed.text, "<string>", "single")
|
||||
if recompiled != code:
|
||||
print(recompiled)
|
||||
print('================')
|
||||
print("================")
|
||||
print(code)
|
||||
print('----------------')
|
||||
assert 'dis(' + deparsed.text.strip('\n') + ')' == 'dis(' + expr.strip('\n') + ')'
|
||||
print("----------------")
|
||||
assert (
|
||||
"dis(" + deparsed.text.strip("\n") + ")"
|
||||
== "dis(" + expr.strip("\n") + ")"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION != 3.6, reason='need Python 3.6')
|
||||
@pytest.mark.skipif(PYTHON_VERSION != 3.6, reason="need Python 3.6")
|
||||
@hypothesis.given(fstrings())
|
||||
def test_uncompyle_fstring(fstring):
|
||||
"""Verify uncompyling fstring bytecode"""
|
||||
run_test(fstring)
|
||||
|
||||
|
||||
@pytest.mark.skipif(PYTHON_VERSION != 3.6, reason='need Python 3.6+')
|
||||
@pytest.mark.parametrize('fstring', [
|
||||
"f'{abc}{abc!s}'",
|
||||
"f'{abc}0'",
|
||||
])
|
||||
@pytest.mark.skipif(PYTHON_VERSION != 3.6, reason="need Python 3.6+")
|
||||
@pytest.mark.parametrize("fstring", ["f'{abc}{abc!s}'", "f'{abc}0'"])
|
||||
def test_uncompyle_direct(fstring):
|
||||
"""useful for debugging"""
|
||||
run_test(fstring)
|
||||
|
@@ -9,6 +9,7 @@ def test_grammar():
|
||||
remain_tokens = set(tokens) - opcode_set
|
||||
remain_tokens = set([re.sub(r'_\d+$','', t) for t in remain_tokens])
|
||||
remain_tokens = set([re.sub('_CONT$','', t) for t in remain_tokens])
|
||||
remain_tokens = set([re.sub('LOAD_CODE$','', t) for t in remain_tokens])
|
||||
remain_tokens = set(remain_tokens) - opcode_set
|
||||
assert remain_tokens == set([]), \
|
||||
"Remaining tokens %s\n====\n%s" % (remain_tokens, p.dump_grammar())
|
||||
@@ -88,7 +89,7 @@ def test_grammar():
|
||||
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 LOAD_STR LOAD_CODE
|
||||
LAMBDA_MARKER
|
||||
RETURN_END_IF RETURN_END_IF_LAMBDA RETURN_VALUE_LAMBDA RETURN_LAST
|
||||
""".split())
|
||||
|
@@ -15,7 +15,7 @@ else:
|
||||
def iteritems(d):
|
||||
return d.iteritems()
|
||||
|
||||
from uncompyle6.semantics.pysource import SourceWalker as SourceWalker
|
||||
from uncompyle6.semantics.pysource import (SourceWalker, deparse_code2str)
|
||||
|
||||
def test_template_engine():
|
||||
s = StringIO()
|
||||
@@ -185,3 +185,11 @@ def test_tables():
|
||||
assert arg == len(entry), (
|
||||
"%s[%s] arg %d should be length of entry %d. Full entry: %s" %
|
||||
(name, k, arg, len(entry), entry))
|
||||
|
||||
def test_deparse_code2str():
|
||||
def deparse_test(co):
|
||||
"This is a docstring"
|
||||
s = deparse_code2str(co, debug_opts={"asm": "after", "tree": True})
|
||||
assert s
|
||||
return
|
||||
deparse_test(deparse_test.__code__)
|
||||
|
@@ -1,3 +1,4 @@
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
from uncompyle6.scanners.tok import Token
|
||||
|
||||
def test_token():
|
||||
@@ -16,7 +17,7 @@ def test_token():
|
||||
# Make sure formatting of: LOAD_CONST False. We assume False is the 0th index
|
||||
# of co_consts.
|
||||
t = Token('LOAD_CONST', offset=1, attr=False, pattr=False, has_arg=True)
|
||||
expect = ' 1 LOAD_CONST 0 False'
|
||||
expect = ' 1 LOAD_CONST False'
|
||||
assert t.format() == expect
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
2
pytest/testdata/if-2.7.right
vendored
2
pytest/testdata/if-2.7.right
vendored
@@ -8,5 +8,5 @@
|
||||
9 STORE_NAME 2 'b'
|
||||
12 JUMP_FORWARD 0 'to 15'
|
||||
15_0 COME_FROM 12 '12'
|
||||
15 LOAD_CONST 0 None
|
||||
15 LOAD_CONST None
|
||||
18 RETURN_VALUE
|
||||
|
6
pytest/testdata/ifelse-2.7.right
vendored
6
pytest/testdata/ifelse-2.7.right
vendored
@@ -4,12 +4,12 @@
|
||||
3 0 LOAD_NAME 0 'True'
|
||||
3 POP_JUMP_IF_FALSE 15 'to 15'
|
||||
|
||||
4 6 LOAD_CONST 0 1
|
||||
4 6 LOAD_CONST 1
|
||||
9 STORE_NAME 1 'b'
|
||||
12 JUMP_FORWARD 6 'to 21'
|
||||
|
||||
6 15 LOAD_CONST 1 2
|
||||
6 15 LOAD_CONST 2
|
||||
18 STORE_NAME 2 'd'
|
||||
21_0 COME_FROM 12 '12'
|
||||
21 LOAD_CONST 2 None
|
||||
21 LOAD_CONST None
|
||||
24 RETURN_VALUE
|
||||
|
@@ -1,16 +1,20 @@
|
||||
# future
|
||||
from __future__ import print_function
|
||||
|
||||
# std
|
||||
import os
|
||||
import difflib
|
||||
import subprocess
|
||||
import tempfile
|
||||
import functools
|
||||
|
||||
# uncompyle6 / xdis
|
||||
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY, deparse_code
|
||||
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY, code_deparse
|
||||
|
||||
# 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)
|
||||
import six
|
||||
@@ -20,6 +24,7 @@ if PYTHON3:
|
||||
else:
|
||||
from StringIO import StringIO
|
||||
|
||||
|
||||
def _dis_to_text(co):
|
||||
return Bytecode(co).dis()
|
||||
|
||||
@@ -33,36 +38,32 @@ def print_diff(original, uncompyled):
|
||||
: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'
|
||||
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')
|
||||
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'))
|
||||
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')
|
||||
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')
|
||||
print("\nFor side by side diff install elinks")
|
||||
diff = difflib.Differ().compare(original_lines, uncompyled_lines)
|
||||
print('\n'.join(diff))
|
||||
print("\n".join(diff))
|
||||
finally:
|
||||
os.unlink(f.name)
|
||||
|
||||
@@ -80,18 +81,19 @@ def are_instructions_equal(i1, i2):
|
||||
|
||||
:return: True if the two instructions are approximately equal, otherwise False.
|
||||
"""
|
||||
result = (1 == 1
|
||||
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))
|
||||
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.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.starts_line
|
||||
and i1.is_jump_target == i2.is_jump_target
|
||||
)
|
||||
return result
|
||||
@@ -115,22 +117,21 @@ def are_code_objects_equal(co1, co2):
|
||||
return True
|
||||
|
||||
|
||||
def validate_uncompyle(text, mode='exec'):
|
||||
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_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(),
|
||||
is_pypy=IS_PYPY)
|
||||
deparsed = code_deparse(
|
||||
original_code, out=six.StringIO(), version=PYTHON_VERSION, compile_mode=mode
|
||||
)
|
||||
uncompyled_text = deparsed.text
|
||||
uncompyled_code = compile(uncompyled_text, '<string>', 'exec')
|
||||
uncompyled_code = compile(uncompyled_text, "<string>", "exec")
|
||||
|
||||
if not are_code_objects_equal(uncompyled_code, original_code):
|
||||
|
||||
@@ -138,15 +139,17 @@ def validate_uncompyle(text, mode='exec'):
|
||||
|
||||
def output(text, dis):
|
||||
width = 60
|
||||
return '\n\n'.join([
|
||||
' SOURCE CODE '.center(width, '#'),
|
||||
text.strip(),
|
||||
' BYTECODE '.center(width, '#'),
|
||||
dis
|
||||
])
|
||||
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'
|
||||
assert "original" == "uncompyled"
|
||||
|
@@ -1,2 +1,4 @@
|
||||
flake8
|
||||
hypothesis<=3.0.0
|
||||
six
|
||||
pytest==3.2.5
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[bdist_rpm]
|
||||
release = 1
|
||||
packager = Mysterie <kajusska@gmail.com>
|
||||
packager = rocky <rb@dustyfeet.com>
|
||||
doc_files = README
|
||||
# CHANGES.txt
|
||||
# USAGE.txt
|
||||
@@ -8,4 +8,4 @@ doc_files = README
|
||||
# examples/
|
||||
|
||||
[bdist_wheel]
|
||||
universal=1
|
||||
# universal=1
|
||||
|
@@ -34,47 +34,47 @@ check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-na
|
||||
#: Run working tests from Python 3.0
|
||||
check-3.0: check-bytecode
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.0-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.0 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.0 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run working tests from Python 3.1
|
||||
check-3.1: check-bytecode
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.1-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.1 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.1 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run working tests from Python 3.2
|
||||
check-3.2: check-bytecode
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.2-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.2 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.2 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run working tests from Python 3.3
|
||||
check-3.3: check-bytecode
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.3-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.3 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.3 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run working tests from Python 3.4
|
||||
check-3.4: check-bytecode check-3.4-ok check-2.7-ok
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.4-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.4 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.4 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run working tests from Python 3.5
|
||||
check-3.5: check-bytecode
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.5-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.5 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.5 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run working tests from Python 3.6
|
||||
check-3.6: check-bytecode
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.6-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.6 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.6 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run working tests from Python 3.7
|
||||
check-3.7: check-bytecode
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.7-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.7 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.7 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run working tests from Python 3.8
|
||||
check-3.8: check-bytecode
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.8 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.8 --syntax-verify $(COMPILE)
|
||||
|
||||
# FIXME
|
||||
#: this is called when running under pypy3.5-5.8.0 or pypy2-5.6.0
|
||||
@@ -176,7 +176,7 @@ grammar-coverage-2.6:
|
||||
grammar-coverage-2.7:
|
||||
-rm $(COVER_DIR)/spark-grammar-2.7.cover || true
|
||||
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.7.cover $(PYTHON) test_pythonlib.py --bytecode-2.7
|
||||
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.7.cover $(PYTHON) test_pyenvlib.py --2.7.14 --max=600
|
||||
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.7.cover $(PYTHON) test_pyenvlib.py --2.7.16 --max=600
|
||||
|
||||
#: Get grammar coverage for Python 3.0
|
||||
grammar-coverage-3.0:
|
||||
@@ -219,82 +219,88 @@ grammar-coverage-3.5:
|
||||
grammar-coverage-3.6:
|
||||
rm $(COVER_DIR)/spark-grammar-3.6.cover || /bin/true
|
||||
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.6.cover $(PYTHON) test_pythonlib.py --bytecode-3.6
|
||||
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.6.cover $(PYTHON) test_pyenvlib.py --3.6.4 --max=280
|
||||
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.6.cover $(PYTHON) test_pyenvlib.py --3.6.8 --max=280
|
||||
|
||||
#: Get grammar coverage for Python 3.7
|
||||
grammar-coverage-3.7:
|
||||
rm $(COVER_DIR)/spark-grammar-3.7.cover || /bin/true
|
||||
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.7.cover $(PYTHON) test_pyenvlib.py --3.7.3 --max=500
|
||||
|
||||
#: Check deparsing Python 2.6
|
||||
check-bytecode-2.6:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-2.6-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-2.6 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-2.6 --syntax-verify
|
||||
|
||||
#: Check deparsing Python 2.7
|
||||
check-bytecode-2.7:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-2.7-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-2.7 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-2.7 --syntax-verify
|
||||
|
||||
#: Check deparsing Python 3.0
|
||||
check-bytecode-3.0:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.0-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.0 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.0 --syntax-verify
|
||||
|
||||
#: Check deparsing Python 3.1
|
||||
check-bytecode-3.1:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.1-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.1 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.1 --syntax-verify
|
||||
|
||||
#: Check deparsing Python 3.2
|
||||
check-bytecode-3.2:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.2-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.2 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.2 --syntax-verify
|
||||
|
||||
#: Check deparsing Python 3.3
|
||||
check-bytecode-3.3:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.3-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.3 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.3 --syntax-verify
|
||||
|
||||
#: Check deparsing Python 3.4
|
||||
check-bytecode-3.4:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.4-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.4 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.4 --syntax-verify
|
||||
|
||||
#: Check deparsing Python 3.5
|
||||
check-bytecode-3.5:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.5-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.5 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.5 --syntax-verify
|
||||
|
||||
#: Check deparsing Python 3.6
|
||||
check-bytecode-3.6:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.6-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.6 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.6 --syntax-verify
|
||||
|
||||
#: Check deparsing Python 3.7
|
||||
check-bytecode-3.7:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.7 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.7-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.7 --syntax-verify
|
||||
|
||||
#: Check deparsing Python 3.8
|
||||
check-bytecode-3.8:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.8 --weak-verify
|
||||
$(PYTHON) test_pythonlib.py --bytecode-3.8 --syntax-verify
|
||||
|
||||
#: short tests for bytecodes only for this version of Python
|
||||
check-native-short:
|
||||
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --syntax-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION)-run --verify-run $(COMPILE)
|
||||
|
||||
#: Run longer Python 2.6's lib files known to be okay
|
||||
check-2.6-ok:
|
||||
$(PYTHON) test_pythonlib.py --ok-2.6 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --ok-2.6 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run longer Python 2.7's lib files known to be okay
|
||||
check-2.7-ok:
|
||||
$(PYTHON) test_pythonlib.py --ok-2.7 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --ok-2.7 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run longer Python 3.2's lib files known to be okay
|
||||
check-3.2-ok:
|
||||
$(PYTHON) test_pythonlib.py --ok-3.2 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --ok-3.2 --syntax-verify $(COMPILE)
|
||||
|
||||
#: Run longer Python 3.4's lib files known to be okay
|
||||
check-3.4-ok:
|
||||
$(PYTHON) test_pythonlib.py --ok-3.4 --weak-verify $(COMPILE)
|
||||
$(PYTHON) test_pythonlib.py --ok-3.4 --syntax-verify $(COMPILE)
|
||||
|
||||
#: PyPy of some sort. E.g. [PyPy 5.0.1 with GCC 4.8.4]
|
||||
# Skip for now
|
||||
|
@@ -2,22 +2,23 @@
|
||||
""" Trivial helper program to bytecompile and run an uncompile
|
||||
"""
|
||||
import os, sys, py_compile
|
||||
|
||||
assert len(sys.argv) >= 2
|
||||
version = sys.version[0:3]
|
||||
if sys.argv[1] == '--run':
|
||||
suffix = '_run'
|
||||
if sys.argv[1] in ("--run", "-r"):
|
||||
suffix = "_run"
|
||||
py_source = sys.argv[2:]
|
||||
else:
|
||||
suffix = ''
|
||||
suffix = ""
|
||||
py_source = sys.argv[1:]
|
||||
|
||||
for path in py_source:
|
||||
short = os.path.basename(path)
|
||||
if hasattr(sys, 'pypy_version_info'):
|
||||
cfile = "bytecode_pypy%s%s/%s" % (version, suffix, short) + 'c'
|
||||
if hasattr(sys, "pypy_version_info"):
|
||||
cfile = "bytecode_pypy%s%s/%s" % (version, suffix, short) + "c"
|
||||
else:
|
||||
cfile = "bytecode_%s%s/%s" % (version, suffix, short) + 'c'
|
||||
cfile = "bytecode_%s%s/%s" % (version, suffix, short) + "c"
|
||||
print("byte-compiling %s to %s" % (path, cfile))
|
||||
py_compile.compile(path, cfile)
|
||||
if isinstance(version, str) or version >= (2, 6, 0):
|
||||
os.system("../bin/uncompyle6 -a -t %s" % cfile)
|
||||
os.system("../bin/uncompyle6 -a -T %s" % cfile)
|
||||
|
BIN
test/bytecode_2.4/02_except_as.pyc
Normal file
BIN
test/bytecode_2.4/02_except_as.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4_run/00_docstring.pyc
Normal file
BIN
test/bytecode_2.4_run/00_docstring.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6_run/00_generator.pyc
Normal file
BIN
test/bytecode_2.6_run/00_generator.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.6_run/01_if_while_return.pyc
Normal file
BIN
test/bytecode_2.6_run/01_if_while_return.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.6_run/04_ifelse_parens.pyc
Normal file
BIN
test/bytecode_2.6_run/04_ifelse_parens.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.7_run/00_docstring.pyc
Normal file
BIN
test/bytecode_2.7_run/00_docstring.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.7_run/04_ifelse_parens.pyc
Normal file
BIN
test/bytecode_2.7_run/04_ifelse_parens.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.0_run/04_def_annotate.pyc
Normal file
BIN
test/bytecode_3.0_run/04_def_annotate.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.1_run/04_def_annotate.pyc
Normal file
BIN
test/bytecode_3.1_run/04_def_annotate.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.2_run/04_def_annotate.pyc
Normal file
BIN
test/bytecode_3.2_run/04_def_annotate.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.3/09_yield_from.pyc
Normal file
BIN
test/bytecode_3.3/09_yield_from.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.3_run/04_def_annotate.pyc
Normal file
BIN
test/bytecode_3.3_run/04_def_annotate.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.3_run/08_while_if.pyc
Normal file
BIN
test/bytecode_3.3_run/08_while_if.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.4/09_yield_from.pyc
Normal file
BIN
test/bytecode_3.4/09_yield_from.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.4_run/04_def_annotate.pyc
Normal file
BIN
test/bytecode_3.4_run/04_def_annotate.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.4_run/08_while_if.pyc
Normal file
BIN
test/bytecode_3.4_run/08_while_if.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/02_async.pyc
Normal file
BIN
test/bytecode_3.5/02_async.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.5_run/02_build_list_unpack.pyc
Normal file
BIN
test/bytecode_3.5_run/02_build_list_unpack.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5_run/04_def_annotate.pyc
Normal file
BIN
test/bytecode_3.5_run/04_def_annotate.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.6/05_ann_mopdule2.pyc
Normal file
BIN
test/bytecode_3.6/05_ann_mopdule2.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6_run/00_docstring.pyc
Normal file
BIN
test/bytecode_3.6_run/00_docstring.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.6_run/02_build_list_unpack.pyc
Normal file
BIN
test/bytecode_3.6_run/02_build_list_unpack.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6_run/02_call_ex_kw.pyc
Normal file
BIN
test/bytecode_3.6_run/02_call_ex_kw.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.6_run/04_def_annotate.pyc
Normal file
BIN
test/bytecode_3.6_run/04_def_annotate.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.7/01_chained_compare.pyc
Normal file
BIN
test/bytecode_3.7/01_chained_compare.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/02_async.pyc
Normal file
BIN
test/bytecode_3.7/02_async.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.7_run/00_docstring.pyc
Normal file
BIN
test/bytecode_3.7_run/00_docstring.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7_run/01_and_not_else.pyc
Normal file
BIN
test/bytecode_3.7_run/01_and_not_else.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7_run/01_assert2.pyc
Normal file
BIN
test/bytecode_3.7_run/01_assert2.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.7_run/02_build_list_unpack.pyc
Normal file
BIN
test/bytecode_3.7_run/02_build_list_unpack.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7_run/02_call_ex_kw.pyc
Normal file
BIN
test/bytecode_3.7_run/02_call_ex_kw.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7_run/04_def_annotate.pyc
Normal file
BIN
test/bytecode_3.7_run/04_def_annotate.pyc
Normal file
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
# Remake Python grammar statistics
|
||||
|
||||
typeset -A ALL_VERS=([2.4]=2.4.6 [2.5]=2.5.6 [2.6]=2.6.9 [2.7]=2.7.14 [3.2]=3.2.6 [3.3]=3.3.6 [3.4]=3.4.8 [3.5]=3.5.5 [3.6]=3.6.4)
|
||||
typeset -A ALL_VERS=([2.4]=2.4.6 [2.5]=2.5.6 [2.6]=2.6.9 [2.7]=2.7.16 [3.2]=3.2.6 [3.3]=3.3.6 [3.4]=3.4.8 [3.5]=3.5.6 [3.6]=3.6.8, [3.7]=3.7.3)
|
||||
|
||||
if (( $# == 0 )); then
|
||||
echo 1>&2 "usage: $0 two-digit-version"
|
||||
|
@@ -42,7 +42,7 @@ for VERSION in $PYVERSION ; do
|
||||
echo Python Version $(pyenv local) > $LOGFILE
|
||||
echo "" >> $LOGFILE
|
||||
typeset -i ALL_FILES_STARTTIME=$(date +%s)
|
||||
python ./test_pyenvlib.py --max ${MAX_TESTS} --weak-verify --$VERSION >>$LOGFILE 2>&1
|
||||
python ./test_pyenvlib.py --max ${MAX_TESTS} --syntax-verify --$VERSION >>$LOGFILE 2>&1
|
||||
rc=$?
|
||||
|
||||
echo Python Version $(pyenv local) >> $LOGFILE
|
||||
|
@@ -22,7 +22,7 @@ assert i[0]('a') == True
|
||||
assert i[0]('A') == False
|
||||
|
||||
# Issue #170. Bug is needing an "conditional_not_lambda" grammar rule
|
||||
# in addition the the "conditional_lambda" rule
|
||||
# in addition the the "if_expr_lambda" rule
|
||||
j = lambda a: False if not a else True
|
||||
assert j(True) == True
|
||||
assert j(False) == False
|
||||
|
19
test/simple_source/bug26/01_if_while_return.py
Normal file
19
test/simple_source/bug26/01_if_while_return.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Issue #284 in Python 2.6
|
||||
# See https://github.com/rocky/python-uncompyle6/issues/284
|
||||
# Decompilation failed when return was the last statetement
|
||||
# in the while loop inside the if block
|
||||
|
||||
# This code is RUNNABLE!
|
||||
|
||||
def f1():
|
||||
if True:
|
||||
while True:
|
||||
return 5
|
||||
|
||||
def f2():
|
||||
if True:
|
||||
while 1:
|
||||
return 6
|
||||
|
||||
|
||||
assert f1() == 5 and f2() == 6
|
@@ -2,3 +2,10 @@
|
||||
# This is RUNNABLE!
|
||||
assert [False, True, True, True, True] == [False if not a else True for a in range(5)]
|
||||
assert [True, False, False, False, False] == [False if a else True for a in range(5)]
|
||||
|
||||
# From bug #225
|
||||
m = ['hi', 'he', 'ih', 'who', 'ho']
|
||||
ms = {}
|
||||
for f in (f for f in m if f.startswith('h')):
|
||||
ms[f] = 5
|
||||
assert ms == {'hi': 5, 'he': 5, 'ho': 5}
|
||||
|
@@ -8,7 +8,7 @@ list(x for x in range(10) if x % 2 if x % 3)
|
||||
|
||||
# expresion which evaluates True unconditionally,
|
||||
# but leave dead code or junk around that we have to match on.
|
||||
# Tests "conditional_true" rule
|
||||
# Tests "if_expr_true" rule
|
||||
5 if 1 else 2
|
||||
|
||||
0 or max(5, 3) if 0 else 3
|
||||
|
9
test/simple_source/bug26/04_ifelse_parens.py
Normal file
9
test/simple_source/bug26/04_ifelse_parens.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# From 3.7.3 dataclasses.py
|
||||
# Bug was handling precedence. Need parenthesis before IfExp.
|
||||
#
|
||||
# RUNNABLE!
|
||||
def _hash_add(fields):
|
||||
flds = [f for f in fields if (4 if f is None else f)]
|
||||
return flds
|
||||
|
||||
assert _hash_add([None, True, False, 3]) == [None, True, 3]
|
@@ -1,6 +1,6 @@
|
||||
# Bug found in 2.7 test_itertools.py
|
||||
# Bug was erroneously using reduction to unconditional_true
|
||||
# A proper fix would be to use unconditional_true only when we
|
||||
# Bug was erroneously using reduction to if_expr_true
|
||||
# A proper fix would be to use if_expr_true only when we
|
||||
# can determine there is or was dead code.
|
||||
from itertools import izip_longest
|
||||
for args in [['abc', range(6)]]:
|
||||
|
@@ -1,13 +1,61 @@
|
||||
# Python 3 annotations
|
||||
# Python 3 positional, kwonly, varargs, and annotations. Ick.
|
||||
|
||||
def foo(a, b: 'annotating b', c: int) -> float:
|
||||
print(a + b + c)
|
||||
# RUNNABLE!
|
||||
def test1(args_1, c: int, w=4, *varargs: int, **kwargs: 'annotating kwargs') -> tuple:
|
||||
return (args_1, c, w, kwargs)
|
||||
|
||||
def test2(args_1, args_2, c: int, w=4, *varargs: int, **kwargs: 'annotating kwargs'):
|
||||
return (args_1, args_2, c, w, varargs, kwargs)
|
||||
|
||||
def test3(c: int, w=4, *varargs: int, **kwargs: 'annotating kwargs') -> float:
|
||||
return 5.4
|
||||
|
||||
def test4(a: float, c: int, *varargs: int, **kwargs: 'annotating kwargs') -> float:
|
||||
return 5.4
|
||||
|
||||
def test5(a: float, c: int = 5, *varargs: int, **kwargs: 'annotating kwargs') -> float:
|
||||
return 5.4
|
||||
|
||||
def test6(a: float, c: int, test=None):
|
||||
return (a, c, test)
|
||||
|
||||
def test7(*varargs: int, **kwargs):
|
||||
return (varargs, kwargs)
|
||||
|
||||
def test8(x=55, *varargs: int, **kwargs) -> list:
|
||||
return (x, varargs, kwargs)
|
||||
|
||||
def test9(arg_1=55, *varargs: int, y=5, **kwargs):
|
||||
return x, varargs, int, y, kwargs
|
||||
|
||||
def test10(args_1, b: 'annotating b', c: int) -> float:
|
||||
return 5.4
|
||||
|
||||
def test11(*, name):
|
||||
return args, name
|
||||
|
||||
def test12(a, *args, name):
|
||||
return a, args
|
||||
pass
|
||||
|
||||
def test13(*args, name):
|
||||
return args, name
|
||||
|
||||
def test14(*args, name: int=1, qname):
|
||||
return args, name, qname
|
||||
|
||||
def test15(*args, name='S', fname, qname=4):
|
||||
return args, name, fname, qname
|
||||
|
||||
# From 3.4 /asyncio/streams.py open_connection
|
||||
_DEFAULT_LIMIT = 5
|
||||
def test16(host=None, port=None, *,
|
||||
loop=None, limit=_DEFAULT_LIMIT, **kwds):
|
||||
return host, port, loop, limit, kwds
|
||||
|
||||
# Python 3.1 _pyio.py uses the -> "IOBase" annotation
|
||||
def open(file, mode = "r", buffering = None,
|
||||
encoding = None, errors = None,
|
||||
newline = None, closefd = True) -> "IOBase":
|
||||
return text
|
||||
def o(f, mode = "r", buffering = None) -> "IOBase":
|
||||
return (f, mode, buffering)
|
||||
|
||||
def foo1(x: 'an argument that defaults to 5' = 5):
|
||||
print(x)
|
||||
@@ -18,13 +66,87 @@ def div(a: dict(type=float, help='the dividend'),
|
||||
"""Divide a by b"""
|
||||
return a / b
|
||||
|
||||
class TestSignatureObject(unittest.TestCase):
|
||||
class TestSignatureObject1():
|
||||
def test_signature_on_wkwonly(self):
|
||||
def test(*, a:float, b:str) -> int:
|
||||
def test(*, a:float, b:str, c:str = 'test', **kwargs: int) -> int:
|
||||
pass
|
||||
|
||||
class SupportsInt(_Protocol):
|
||||
class TestSignatureObject2():
|
||||
def test_signature_on_wkwonly(self):
|
||||
def test(*, c='test', a:float, b:str="S", **kwargs: int) -> int:
|
||||
pass
|
||||
|
||||
class TestSignatureObject3():
|
||||
def test_signature_on_wkwonly(self):
|
||||
def test(*, c='test', a:float, kwargs:str="S", **b: int) -> int:
|
||||
pass
|
||||
|
||||
class TestSignatureObject4():
|
||||
def test_signature_on_wkwonly(self):
|
||||
def test(x=55, *args, c:str='test', a:float, kwargs:str="S", **b: int) -> int:
|
||||
pass
|
||||
|
||||
class TestSignatureObject5():
|
||||
def test_signature_on_wkwonly(self):
|
||||
def test(x=55, *args: int, c='test', a:float, kwargs:str="S", **b: int) -> int:
|
||||
pass
|
||||
|
||||
class TestSignatureObject5():
|
||||
def test_signature_on_wkwonly(self):
|
||||
def test(x:int=55, *args: (int, str), c='test', a:float, kwargs:str="S", **b: int) -> int:
|
||||
pass
|
||||
|
||||
class TestSignatureObject7():
|
||||
def test_signature_on_wkwonly(self):
|
||||
def test(c='test', kwargs:str="S", **b: int) -> int:
|
||||
pass
|
||||
|
||||
class TestSignatureObject8():
|
||||
def test_signature_on_wkwonly(self):
|
||||
def test(**b: int) -> int:
|
||||
pass
|
||||
|
||||
class TestSignatureObject9():
|
||||
def test_signature_on_wkwonly(self):
|
||||
def test(a, **b: int) -> int:
|
||||
pass
|
||||
|
||||
class SupportsInt():
|
||||
|
||||
@abstractmethod
|
||||
def __int__(self) -> int:
|
||||
pass
|
||||
|
||||
def ann1(args_1, b: 'annotating b', c: int, *varargs: str) -> float:
|
||||
assert ann1.__annotations__['b'] == 'annotating b'
|
||||
assert ann1.__annotations__['c'] == int
|
||||
assert ann1.__annotations__['varargs'] == str
|
||||
assert ann1.__annotations__['return'] == float
|
||||
|
||||
def ann2(args_1, b: int = 5, **kwargs: float) -> float:
|
||||
assert ann2.__annotations__['b'] == int
|
||||
assert ann2.__annotations__['kwargs'] == float
|
||||
assert ann2.__annotations__['return'] == float
|
||||
assert b == 5
|
||||
|
||||
class TestSignatureObject():
|
||||
def test_signature_on_wkwonly(self):
|
||||
def test(x:int=55, *args: (int, str), c='test', a:float, kwargs:str="S", **b: int) -> int:
|
||||
pass
|
||||
|
||||
assert test1(1, 5) == (1, 5, 4, {})
|
||||
assert test1(1, 5, 6, foo='bar') == (1, 5, 6, {'foo': 'bar'})
|
||||
assert test2(2, 3, 4) == (2, 3, 4, 4, (), {})
|
||||
assert test3(10, foo='bar') == 5.4
|
||||
assert test4(9.5, 7, 6, 4, bar='baz') == 5.4
|
||||
### FIXME: fill in...
|
||||
assert test6(1.2, 3) == (1.2, 3, None)
|
||||
assert test6(2.3, 4, 5) == (2.3, 4, 5)
|
||||
|
||||
ann1(1, 'test', 5)
|
||||
ann2(1)
|
||||
|
||||
### FIXME: fill in...
|
||||
|
||||
assert test12(1, 2, 3, name='hi') == (1, (2, 3)), "a, *args, name"
|
||||
assert test13(1, 2, 3, name='hi') == ((1, 2, 3), 'hi'), "*args, name"
|
||||
assert test16('localhost', loop=2, limit=3, a='b') == ('localhost', None, 2, 3, {'a': 'b'})
|
||||
|
34
test/simple_source/bug34/08_while_if.py
Normal file
34
test/simple_source/bug34/08_while_if.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# Testing "while 1" versus "while" handling with if/elif/else's
|
||||
|
||||
def while_test(a, b, c):
|
||||
while a != 2:
|
||||
if b:
|
||||
a += 1
|
||||
elif c:
|
||||
c = 0
|
||||
else:
|
||||
break
|
||||
return a, b, c
|
||||
|
||||
|
||||
def while1_test(a, b, c):
|
||||
while 1:
|
||||
if a != 2:
|
||||
if b:
|
||||
a = 3
|
||||
b = 0
|
||||
elif c:
|
||||
c = 0
|
||||
else:
|
||||
a += b + c
|
||||
break
|
||||
return a, b, c
|
||||
|
||||
|
||||
assert while_test(2, 0, 0) == (2, 0, 0), "no while loops"
|
||||
assert while_test(0, 1, 0) == (2, 1, 0), "two while loops of b branch"
|
||||
assert while_test(0, 0, 0) == (0, 0, 0), "0 while loops, else branch"
|
||||
|
||||
# FIXME: put this in a timer, and try with a=2
|
||||
assert while1_test(4, 1, 1) == (3, 0, 0), "three while1 loops"
|
||||
assert while1_test(4, 0, 0) == (4, 0, 0), " one while1 loop"
|
17
test/simple_source/bug35/02_async.py
Normal file
17
test/simple_source/bug35/02_async.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# From 3.7.3 asyncio/base_events.py
|
||||
# We had (still have) screwy logic. Python 3.5 code node detection was off too.
|
||||
|
||||
async def create_connection(self):
|
||||
infos = await self._ensure_resolved()
|
||||
|
||||
laddr_infos = await self._ensure_resolved()
|
||||
for family in infos:
|
||||
for laddr in laddr_infos:
|
||||
family = 1
|
||||
else:
|
||||
continue
|
||||
await self.sock_connect()
|
||||
else:
|
||||
raise OSError('Multiple exceptions: {}' for exc in family)
|
||||
|
||||
return
|
17
test/simple_source/bug35/02_build_list_unpack.py
Normal file
17
test/simple_source/bug35/02_build_list_unpack.py
Normal file
@@ -0,0 +1,17 @@
|
||||
a = 5
|
||||
x = [1, 2, 3]
|
||||
i = [(a,), x]
|
||||
j = [a, *x]
|
||||
|
||||
def f1(a):
|
||||
return a[0], a[1]
|
||||
|
||||
def f2(b):
|
||||
return len(b), b[0]+5, b[2]
|
||||
|
||||
def f3(x, y):
|
||||
return [1, *x, y]
|
||||
|
||||
assert f1(i) == ((5,), x)
|
||||
assert f2(j) == (4, 10, 2)
|
||||
assert f3(x, a) == [1, 1, 2, 3, 5]
|
@@ -1,5 +1,5 @@
|
||||
# Adapted from Python 3.6 trace.py
|
||||
# Bug was in handling BUID_TUPLE_UNPACK created via
|
||||
# Bug was in handling BUILD_TUPLE_UNPACK created via
|
||||
# *opts.arguments
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
@@ -7,4 +7,4 @@ parser.add_argument('filename', nargs='?')
|
||||
parser.add_argument('arguments', nargs=argparse.REMAINDER)
|
||||
opts = parser.parse_args(["foo", "a", "b"])
|
||||
argv = opts.filename, *opts.arguments
|
||||
assert argv == ('foo', 'a', 'b')
|
||||
assert argv == ('foo', 'a', 'b'), "Reconstruct tuple using '*' and BUILD_TUPLE_UNPACK"
|
||||
|
@@ -4,8 +4,8 @@
|
||||
var1 = 'x'
|
||||
var2 = 'y'
|
||||
abc = 'def'
|
||||
assert (f'interpolate {var1} strings {var2!r} {var2!s} py36' ==
|
||||
"interpolate x strings 'y' y py36")
|
||||
assert (f"interpolate {var1} strings {var2!r} {var2!s} 'py36" ==
|
||||
"interpolate x strings 'y' y 'py36")
|
||||
assert 'def0' == f'{abc}0'
|
||||
assert 'defdef' == f'{abc}{abc!s}'
|
||||
|
||||
@@ -38,4 +38,31 @@ filename = '.'
|
||||
source = 'foo'
|
||||
source = (f"__file__ = r'''{os.path.abspath(filename)}'''\n"
|
||||
+ source + "\ndel __file__")
|
||||
print(source)
|
||||
|
||||
# Note how { and } are *not* escaped here
|
||||
f = 'one'
|
||||
name = 'two'
|
||||
assert(f"{f}{'{{name}}'} {f}{'{name}'}") == 'one{{name}} one{name}'
|
||||
|
||||
# From 3.7.3 dataclasses.py
|
||||
log_rounds = 5
|
||||
assert "05$" == f'{log_rounds:02d}$'
|
||||
|
||||
|
||||
def testit(a, b, l):
|
||||
# print(l)
|
||||
return l
|
||||
|
||||
# The call below shows the need for BUILD_STRING to count expr arguments.
|
||||
# Also note that we use {{ }} to escape braces in contrast to the example
|
||||
# above.
|
||||
def _repr_fn(fields):
|
||||
return testit('__repr__',
|
||||
('self',),
|
||||
['return xx + f"(' +
|
||||
', '.join([f"{f}={{self.{f}!r}}"
|
||||
for f in fields]) +
|
||||
')"'])
|
||||
|
||||
fields = ['a', 'b', 'c']
|
||||
assert _repr_fn(fields) == ['return xx + f"(a={self.a!r}, b={self.b!r}, c={self.c!r})"']
|
||||
|
47
test/simple_source/bug36/02_call_ex_kw.py
Normal file
47
test/simple_source/bug36/02_call_ex_kw.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# From #227
|
||||
# Bug was not handling call_ex_kw correctly
|
||||
# This appears in
|
||||
# showparams(c, test="A", **extra_args)
|
||||
# below
|
||||
|
||||
def showparams(c, test, **extra_args):
|
||||
return {'c': c, **extra_args, 'test': test}
|
||||
|
||||
def f(c, **extra_args):
|
||||
return showparams(c, test="A", **extra_args)
|
||||
|
||||
def f1(c, d, **extra_args):
|
||||
return showparams(c, test="B", **extra_args)
|
||||
|
||||
def f2(**extra_args):
|
||||
return showparams(1, test="C", **extra_args)
|
||||
|
||||
def f3(c, *args, **extra_args):
|
||||
return showparams(c, *args, **extra_args)
|
||||
|
||||
assert f(1, a=2, b=3) == {'c': 1, 'a': 2, 'b': 3, 'test': 'A'}
|
||||
|
||||
a = {'param1': 2}
|
||||
assert f1('2', '{\'test\': "4"}', test2='a', **a) \
|
||||
== {'c': '2', 'test2': 'a', 'param1': 2, 'test': 'B'}
|
||||
assert f1(2, '"3"', test2='a', **a) \
|
||||
== {'c': 2, 'test2': 'a', 'param1': 2, 'test': 'B'}
|
||||
assert f1(False, '"3"', test2='a', **a) \
|
||||
== {'c': False, 'test2': 'a', 'param1': 2, 'test': 'B'}
|
||||
assert f(2, test2='A', **a) \
|
||||
== {'c': 2, 'test2': 'A', 'param1': 2, 'test': 'A'}
|
||||
assert f(str(2) + str(1), test2='a', **a) \
|
||||
== {'c': '21', 'test2': 'a', 'param1': 2, 'test': 'A'}
|
||||
assert f1((a.get('a'), a.get('b')), a, test3='A', **a) \
|
||||
== {'c': (None, None), 'test3': 'A', 'param1': 2, 'test': 'B'}
|
||||
|
||||
b = {'b1': 1, 'b2': 2}
|
||||
assert f2(**a, **b) == \
|
||||
{'c': 1, 'param1': 2, 'b1': 1, 'b2': 2, 'test': 'C'}
|
||||
|
||||
c = (2,)
|
||||
d = (2, 3)
|
||||
assert f(2, **a) == {'c': 2, 'param1': 2, 'test': 'A'}
|
||||
assert f3(2, *c, **a) == {'c': 2, 'param1': 2, 'test': 2}
|
||||
assert f3(*d, **a) == {'c': 2, 'param1': 2, 'test': 3}
|
||||
|
37
test/simple_source/bug36/05_ann_mopdule2.py
Normal file
37
test/simple_source/bug36/05_ann_mopdule2.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# This is from Python 3.6's test directory.
|
||||
"""
|
||||
Some correct syntax for variable annotation here.
|
||||
More examples are in test_grammar and test_parser.
|
||||
"""
|
||||
|
||||
from typing import no_type_check, ClassVar
|
||||
|
||||
i: int = 1
|
||||
j: int
|
||||
x: float = i/10
|
||||
|
||||
def f():
|
||||
class C: ...
|
||||
return C()
|
||||
|
||||
f().new_attr: object = object()
|
||||
|
||||
class C:
|
||||
def __init__(self, x: int) -> None:
|
||||
self.x = x
|
||||
|
||||
c = C(5)
|
||||
c.new_attr: int = 10
|
||||
|
||||
__annotations__ = {}
|
||||
|
||||
|
||||
@no_type_check
|
||||
class NTC:
|
||||
def meth(self, param: complex) -> None:
|
||||
...
|
||||
|
||||
class CV:
|
||||
var: ClassVar['CV']
|
||||
|
||||
CV.var = CV()
|
16
test/simple_source/bug37/01_and_not_else.py
Normal file
16
test/simple_source/bug37/01_and_not_else.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# From 3.7.3 base64.py
|
||||
# Bug was handling "and not" in an
|
||||
# if/else in the presence of better Python bytecode generatation
|
||||
|
||||
# RUNNABLE!
|
||||
def foo(foldnuls, word):
|
||||
x = 5 if foldnuls and not word else 6
|
||||
return x
|
||||
|
||||
for expect, foldnuls, word in (
|
||||
(6, True, True),
|
||||
(5, True, False),
|
||||
(6, False, True),
|
||||
(6, False, False)
|
||||
):
|
||||
assert foo(foldnuls, word) == expect
|
8
test/simple_source/bug37/01_assert2.py
Normal file
8
test/simple_source/bug37/01_assert2.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Self-checking test.
|
||||
# Bug was in if transform not inverting expression
|
||||
# This file is RUNNABLE!
|
||||
def test_assert2(c):
|
||||
if c < 2:
|
||||
raise SyntaxError('Oops')
|
||||
|
||||
test_assert2(5)
|
@@ -11,9 +11,16 @@ def chained_compare_b(a, obj):
|
||||
if -0x80000000 <= obj <= 0x7fffffff:
|
||||
return 5
|
||||
|
||||
def chained_compare_c(a, d):
|
||||
for i in len(d):
|
||||
if a == d[i] != 2:
|
||||
return 5
|
||||
|
||||
chained_compare_a(3)
|
||||
try:
|
||||
chained_compare_a(8)
|
||||
except ValueError:
|
||||
pass
|
||||
chained_compare_b(True, 0x0)
|
||||
|
||||
chained_compare_c(3, [3])
|
||||
|
@@ -8,4 +8,7 @@ def x(s):
|
||||
if not k.startswith('_')
|
||||
}
|
||||
|
||||
assert x((('_foo', None),)) == {}
|
||||
# Yes, the print() is funny. This is
|
||||
# to test though a 2-arg assert where
|
||||
# the 2nd argument is not a string.
|
||||
assert x((('_foo', None),)) == {}, print("See issue #162")
|
||||
|
@@ -11,6 +11,9 @@
|
||||
def _walk_dir(dir, dfile, ddir=None):
|
||||
yield from _walk_dir(dir, ddir=dfile)
|
||||
|
||||
def ybug(g):
|
||||
yield from g
|
||||
|
||||
# From 3.5.1 _wakrefset.py
|
||||
#
|
||||
# 3.5:
|
||||
|
@@ -1,10 +1,55 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# uncompyle2 bug was not escaping """ properly
|
||||
r'''func placeholder - with ("""\nstring\n""")'''
|
||||
def foo():
|
||||
r'''func placeholder - ' and with ("""\nstring\n""")'''
|
||||
|
||||
def bar():
|
||||
# RUNNABLE!
|
||||
r'''func placeholder - with ("""\nstring\n""")'''
|
||||
|
||||
def dq0():
|
||||
assert __doc__ == r'''func placeholder - with ("""\nstring\n""")'''
|
||||
|
||||
def dq1():
|
||||
"""assert that dedent() has no effect on 'text'"""
|
||||
assert dq1.__doc__ == """assert that dedent() has no effect on 'text'"""
|
||||
|
||||
def dq2():
|
||||
'''assert that dedent() has no effect on 'text\''''
|
||||
assert dq1.__doc__ == '''assert that dedent() has no effect on 'text\''''
|
||||
|
||||
def dq3():
|
||||
"""assert that dedent() has no effect on 'text\""""
|
||||
assert dq3.__doc__ == """assert that dedent() has no effect on 'text\""""
|
||||
|
||||
def dq4():
|
||||
"""assert that dedent() has no effect on 'text'"""
|
||||
assert dq4.__doc__ == """assert that dedent() has no effect on 'text'"""
|
||||
|
||||
def dq5():
|
||||
r'''func placeholder - ' and with ("""\nstring\n""")'''
|
||||
assert dq5.__doc__ == r'''func placeholder - ' and with ("""\nstring\n""")'''
|
||||
|
||||
def dq6():
|
||||
r"""func placeholder - ' and with ('''\nstring\n''') and \"\"\"\nstring\n\"\"\" """
|
||||
assert dq6.__doc__ == r"""func placeholder - ' and with ('''\nstring\n''') and \"\"\"\nstring\n\"\"\" """
|
||||
|
||||
def dq7():
|
||||
u""" <----- SEE 'u' HERE
|
||||
>>> mylen(u"áéíóú")
|
||||
5
|
||||
"""
|
||||
assert dq7.__doc__ == u""" <----- SEE 'u' HERE
|
||||
>>> mylen(u"áéíóú")
|
||||
5
|
||||
"""
|
||||
|
||||
def dq8():
|
||||
u""" <----- SEE 'u' HERE
|
||||
>>> mylen(u"تست")
|
||||
5
|
||||
"""
|
||||
assert dq8.__doc__ == u""" <----- SEE 'u' HERE
|
||||
>>> mylen(u"تست")
|
||||
5
|
||||
"""
|
||||
|
||||
def baz():
|
||||
"""
|
||||
@@ -20,3 +65,28 @@ def baz():
|
||||
>>> t.rundict(m1.__dict__, 'rundict_test_pvt') # None are skipped.
|
||||
TestResults(failed=0, attempted=8)
|
||||
"""
|
||||
assert baz.__doc__ == \
|
||||
"""
|
||||
... '''>>> assert 1 == 1
|
||||
... '''
|
||||
... \"""
|
||||
>>> exec test_data in m1.__dict__
|
||||
>>> exec test_data in m2.__dict__
|
||||
>>> m1.__dict__.update({"f2": m2._f, "g2": m2.g, "h2": m2.H})
|
||||
|
||||
Tests that objects outside m1 are excluded:
|
||||
\"""
|
||||
>>> t.rundict(m1.__dict__, 'rundict_test_pvt') # None are skipped.
|
||||
TestResults(failed=0, attempted=8)
|
||||
"""
|
||||
|
||||
dq0()
|
||||
dq1()
|
||||
dq2()
|
||||
dq3()
|
||||
dq4()
|
||||
dq5()
|
||||
dq6()
|
||||
dq7()
|
||||
dq8()
|
||||
baz()
|
||||
|
@@ -7,3 +7,4 @@ import http.client as httpclient
|
||||
if len(__file__) == 0:
|
||||
# a.b.c should force consecutive LOAD_ATTRs
|
||||
import a.b.c as d
|
||||
import stuff0.stuff1.stuff2.stuff3 as stuff3
|
||||
|
@@ -43,10 +43,10 @@ case $PYVERSION in
|
||||
2.5)
|
||||
SKIP_TESTS=(
|
||||
[test_contextlib.py]=1 # Syntax error - look at
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_pdb.py]=1 # Line-number specific
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_pdb.py]=1 # Line-number specific
|
||||
[test_pwd.py]=1 # Long test - might work? Control flow?
|
||||
[test_queue.py]=1 # Control flow?
|
||||
[test_re.py]=1 # Probably Control flow?
|
||||
@@ -56,18 +56,46 @@ case $PYVERSION in
|
||||
;;
|
||||
2.6)
|
||||
SKIP_TESTS=(
|
||||
[test_aepack.py]=1
|
||||
[test_aifc.py]=1
|
||||
[test_array.py]=1
|
||||
[test_audioop.py]=1
|
||||
[test_base64.py]=1
|
||||
[test_bigmem.py]=1
|
||||
[test_binascii.py]=1
|
||||
[test_builtin.py]=1
|
||||
[test_bytes.py]=1
|
||||
[test_class.py]=1
|
||||
[test_codeccallbacks.py]=1
|
||||
[test_codecencodings_cn.py]=1
|
||||
[test_codecencodings_hk.py]=1
|
||||
[test_codecencodings_jp.py]=1
|
||||
[test_codecencodings_kr.py]=1
|
||||
[test_codecencodings_tw.py]=1
|
||||
[test_codecencodings_cn.py]=1
|
||||
[test_codecmaps_hk.py]=1
|
||||
[test_codecmaps_jp.py]=1
|
||||
[test_codecmaps_kr.py]=1
|
||||
[test_codecmaps_tw.py]=1
|
||||
[test_codecs.py]=1
|
||||
[test_compile.py]=1 # Intermittent - sometimes works and sometimes doesn't
|
||||
[test_grammar.py]=1 # Need real flow control. "and" in side "or"
|
||||
# "and" inside ifelse need to simulatenously work
|
||||
[test_cookielib.py]=1
|
||||
[test_copy.py]=1
|
||||
[test_decimal.py]=1
|
||||
[test_descr.py]=1 # Problem in pickle.py?
|
||||
[test_exceptions.py]=1
|
||||
[test_extcall.py]=1
|
||||
[test_float.py]=1
|
||||
[test_future4.py]=1
|
||||
[test_generators.py]=1
|
||||
[test_grp.py]=1 # Long test - might work Control flow?
|
||||
[test_opcodes.py]=1
|
||||
[test_pwd.py]=1 # Long test - might work? Control flow?
|
||||
[test_re.py]=1 # Probably Control flow?
|
||||
[test_queue.py]=1 # Control flow?
|
||||
[test_strftime.py]=1
|
||||
[test_trace.py]=1 # Line numbers are expected to be different
|
||||
[test_zipfile64.py]=1 # Skip Long test
|
||||
[test_zlib.py]=1 # Look at
|
||||
[test_zlib.py]=1 # Takes too long to run (more than 3 minutes 39 seconds)
|
||||
# .pyenv/versions/2.6.9/lib/python2.6/lib2to3/refactor.pyc
|
||||
# .pyenv/versions/2.6.9/lib/python2.6/pyclbr.pyc
|
||||
# .pyenv/versions/2.6.9/lib/python2.6/quopri.pyc -- look at ishex, is short
|
||||
@@ -103,9 +131,11 @@ case $PYVERSION in
|
||||
[test_httplib.py]=1 # Ok, but POWER has problems with this
|
||||
[test_pdb.py]=1 # Ok, but POWER has problems with this
|
||||
|
||||
[test_capi.py]=1
|
||||
[test_curses.py]=1 # Possibly fails on its own but not detected
|
||||
[test_dis.py]=1 # We change line numbers - duh!
|
||||
[test_doctest.py]=1 # Fails on its own
|
||||
[test_exceptions.py]=1
|
||||
[test_format.py]=1 # control flow. uncompyle2 does not have problems here
|
||||
[test_generators.py]=1 # control flow. uncompyle2 has problem here too
|
||||
[test_grammar.py]=1 # Too many stmts. Handle large stmts
|
||||
@@ -113,6 +143,9 @@ case $PYVERSION in
|
||||
[test_ioctl.py]=1 # Test takes too long to run
|
||||
[test_itertools.py]=1 # Fix erroneous reduction to "conditional_true".
|
||||
# See test/simple_source/bug27+/05_not_unconditional.py
|
||||
[test_long.py]=1
|
||||
[test_long_future.py]=1
|
||||
[test_math.py]=1
|
||||
[test_memoryio.py]=1 # FIX
|
||||
[test_multiprocessing.py]=1 # On uncompyle2, taks 24 secs
|
||||
[test_pep352.py]=1 # ?
|
||||
@@ -122,9 +155,11 @@ case $PYVERSION in
|
||||
[test_pty.py]=1
|
||||
[test_queue.py]=1 # Control flow?
|
||||
[test_re.py]=1 # Probably Control flow?
|
||||
[test_runpy.py]=1 # Long and fails on its own
|
||||
[test_select.py]=1 # Runs okay but takes 11 seconds
|
||||
[test_socket.py]=1 # Runs ok but takes 22 seconds
|
||||
[test_subprocess.py]=1 # Runs ok but takes 22 seconds
|
||||
[test_sys_setprofile.py]=1
|
||||
[test_sys_settrace.py]=1 # Line numbers are expected to be different
|
||||
[test_strtod.py]=1 # FIX
|
||||
[test_traceback.py]=1 # Line numbers change - duh.
|
||||
@@ -188,6 +223,7 @@ fi
|
||||
mkdir $TESTDIR || exit $?
|
||||
cp -r ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test $TESTDIR
|
||||
cd $TESTDIR/test
|
||||
pyenv local $FULLVERSION
|
||||
export PYTHONPATH=$TESTDIR
|
||||
|
||||
# Run tests
|
||||
@@ -204,10 +240,14 @@ else
|
||||
fi
|
||||
|
||||
typeset -i ALL_FILES_STARTTIME=$(date +%s)
|
||||
typeset -i skipped=0
|
||||
|
||||
for file in $files; do
|
||||
# AIX bash doesn't grok [[ -v SKIP... ]]
|
||||
[[ ${SKIP_TESTS[$file]} == 1 ]] && continue
|
||||
if [[ ${SKIP_TESTS[$file]} == 1 ]] ; then
|
||||
((skipped++))
|
||||
continue
|
||||
fi
|
||||
|
||||
# If the fails *before* decompiling, skip it!
|
||||
typeset -i STARTTIME=$(date +%s)
|
||||
@@ -241,7 +281,7 @@ for file in $files; do
|
||||
fi
|
||||
(( rc != 0 && allerrs++ ))
|
||||
if (( STOP_ONERROR && rc )) ; then
|
||||
echo "** Ran $i tests before failure **"
|
||||
echo "** Ran $i tests before failure. Skipped $skipped test for known failures. **"
|
||||
exit $allerrs
|
||||
fi
|
||||
done
|
||||
@@ -251,5 +291,5 @@ typeset -i ALL_FILES_ENDTIME=$(date +%s)
|
||||
|
||||
printf "Ran $i unit-test files in "
|
||||
displaytime $time_diff
|
||||
|
||||
echo "Skipped $skipped test for known failures."
|
||||
exit $allerrs
|
||||
|
@@ -28,64 +28,77 @@ from fnmatch import fnmatch
|
||||
from uncompyle6 import main, PYTHON3
|
||||
import xdis.magics as magics
|
||||
|
||||
#----- configure this for your needs
|
||||
# ----- configure this for your needs
|
||||
|
||||
python_versions = [v for v in magics.python_versions if
|
||||
re.match('^[0-9.]+$', v)]
|
||||
python_versions = [v for v in magics.python_versions if re.match("^[0-9.]+$", v)]
|
||||
|
||||
# FIXME: we should remove Python versions that we don't support.
|
||||
# These include Jython, and Python bytecode changes pre release.
|
||||
|
||||
TEST_VERSIONS = (
|
||||
'pypy3-2.4.0', 'pypy-2.6.1',
|
||||
'pypy-5.0.1', 'pypy-5.3.1', 'pypy3.5-5.7.1-beta',
|
||||
'pypy3.5-5.9.0', 'pypy3.5-6.0.0',
|
||||
'native') + tuple(python_versions)
|
||||
"pypy3-2.4.0",
|
||||
"pypy-2.6.1",
|
||||
"pypy-5.0.1",
|
||||
"pypy-5.3.1",
|
||||
"pypy3.5-5.7.1-beta",
|
||||
"pypy3.5-5.9.0",
|
||||
"pypy3.5-6.0.0",
|
||||
"native",
|
||||
) + tuple(python_versions)
|
||||
|
||||
|
||||
target_base = '/tmp/py-dis/'
|
||||
lib_prefix = os.path.join(os.environ['HOME'], '.pyenv/versions')
|
||||
target_base = "/tmp/py-dis/"
|
||||
lib_prefix = os.path.join(os.environ["HOME"], ".pyenv/versions")
|
||||
|
||||
PYC = ('*.pyc', )
|
||||
PYO = ('*.pyo', )
|
||||
PYOC = ('*.pyc', '*.pyo')
|
||||
PYC = ("*.pyc",)
|
||||
PYO = ("*.pyo",)
|
||||
PYOC = ("*.pyc", "*.pyo")
|
||||
|
||||
#-----
|
||||
# -----
|
||||
|
||||
test_options = {
|
||||
# name: (src_basedir, pattern, output_base_suffix)
|
||||
'test': ('./test', PYOC, 'test'),
|
||||
'max=': 200,
|
||||
}
|
||||
"test": ("./test", PYOC, "test"),
|
||||
"max=": 200,
|
||||
}
|
||||
|
||||
for vers in TEST_VERSIONS:
|
||||
if vers.startswith('pypy'):
|
||||
if vers.startswith('pypy3.'):
|
||||
if vers.startswith("pypy"):
|
||||
if vers.startswith("pypy3."):
|
||||
short_vers = vers[4:6]
|
||||
else:
|
||||
short_vers = vers[0:-2]
|
||||
|
||||
test_options[vers] = (os.path.join(lib_prefix, vers, 'lib_pypy'),
|
||||
PYC, 'python-lib'+short_vers)
|
||||
test_options[vers] = (
|
||||
os.path.join(lib_prefix, vers, "lib_pypy"),
|
||||
PYC,
|
||||
"python-lib" + short_vers,
|
||||
)
|
||||
else:
|
||||
if vers == 'native':
|
||||
if vers == "native":
|
||||
short_vers = os.path.basename(sys.path[-1])
|
||||
test_options[vers] = (sys.path[-1],
|
||||
PYC, short_vers)
|
||||
test_options[vers] = (sys.path[-1], PYC, short_vers)
|
||||
else:
|
||||
short_vers = vers[:3]
|
||||
test_options[vers] = (os.path.join(lib_prefix, vers, 'lib', 'python'+short_vers),
|
||||
PYC, 'python-lib'+short_vers)
|
||||
test_options[vers] = (
|
||||
os.path.join(lib_prefix, vers, "lib", "python" + short_vers),
|
||||
PYC,
|
||||
"python-lib" + short_vers,
|
||||
)
|
||||
|
||||
def do_tests(src_dir, patterns, target_dir, start_with=None,
|
||||
do_verify=False, max_files=200):
|
||||
|
||||
def do_tests(
|
||||
src_dir, patterns, target_dir, start_with=None, do_verify=False, max_files=200
|
||||
):
|
||||
def visitor(files, dirname, names):
|
||||
files.extend(
|
||||
[os.path.normpath(os.path.join(dirname, n))
|
||||
for n in names
|
||||
for pat in patterns
|
||||
if fnmatch(n, pat)])
|
||||
[
|
||||
os.path.normpath(os.path.join(dirname, n))
|
||||
for n in names
|
||||
for pat in patterns
|
||||
if fnmatch(n, pat)
|
||||
]
|
||||
)
|
||||
|
||||
files = []
|
||||
cwd = os.getcwd()
|
||||
@@ -93,10 +106,13 @@ def do_tests(src_dir, patterns, target_dir, start_with=None,
|
||||
if PYTHON3:
|
||||
for root, dirname, names in os.walk(os.curdir):
|
||||
files.extend(
|
||||
[os.path.normpath(os.path.join(root, n))
|
||||
for n in names
|
||||
for pat in patterns
|
||||
if fnmatch(n, pat)])
|
||||
[
|
||||
os.path.normpath(os.path.join(root, n))
|
||||
for n in names
|
||||
for pat in patterns
|
||||
if fnmatch(n, pat)
|
||||
]
|
||||
)
|
||||
pass
|
||||
pass
|
||||
else:
|
||||
@@ -108,26 +124,29 @@ def do_tests(src_dir, patterns, target_dir, start_with=None,
|
||||
try:
|
||||
start_with = files.index(start_with)
|
||||
files = files[start_with:]
|
||||
print('>>> starting with file', files[0])
|
||||
print(">>> starting with file", files[0])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if len(files) > max_files:
|
||||
files = [file for file in files if not 'site-packages' in file]
|
||||
files = [file for file in files if not 'test' in file]
|
||||
files = [file for file in files if not "site-packages" in file]
|
||||
files = [file for file in files if not "test" in file]
|
||||
if len(files) > max_files:
|
||||
# print("Number of files %d - truncating to last 200" % len(files))
|
||||
print("Number of files %d - truncating to first %s" %
|
||||
(len(files), max_files))
|
||||
print(
|
||||
"Number of files %d - truncating to first %s" % (len(files), max_files)
|
||||
)
|
||||
files = files[:max_files]
|
||||
|
||||
print(time.ctime())
|
||||
(tot_files, okay_files, failed_files,
|
||||
verify_failed_files) = main.main(src_dir, target_dir, files, [], do_verify=do_verify)
|
||||
(tot_files, okay_files, failed_files, verify_failed_files) = main.main(
|
||||
src_dir, target_dir, files, [], do_verify=do_verify
|
||||
)
|
||||
print(time.ctime())
|
||||
return verify_failed_files + failed_files
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
import getopt, sys
|
||||
|
||||
do_coverage = do_verify = False
|
||||
@@ -136,38 +155,46 @@ if __name__ == '__main__':
|
||||
|
||||
test_options_keys = list(test_options.keys())
|
||||
test_options_keys.sort()
|
||||
opts, args = getopt.getopt(sys.argv[1:], '',
|
||||
['start-with=', 'verify', 'verify-run', 'weak-verify',
|
||||
'max=', 'coverage', 'all', ] \
|
||||
+ test_options_keys )
|
||||
vers = ''
|
||||
opts, args = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
"",
|
||||
[
|
||||
"start-with=",
|
||||
"verify",
|
||||
"verify-run",
|
||||
"syntax-verify",
|
||||
"max=",
|
||||
"coverage",
|
||||
"all",
|
||||
]
|
||||
+ test_options_keys,
|
||||
)
|
||||
vers = ""
|
||||
|
||||
for opt, val in opts:
|
||||
if opt == '--verify':
|
||||
do_verify = 'strong'
|
||||
elif opt == '--weak-verify':
|
||||
do_verify = 'weak'
|
||||
elif opt == '--verify-run':
|
||||
do_verify = 'verify-run'
|
||||
elif opt == '--coverage':
|
||||
if opt == "--verify":
|
||||
do_verify = "strong"
|
||||
elif opt == "--syntax-verify":
|
||||
do_verify = "weak"
|
||||
elif opt == "--verify-run":
|
||||
do_verify = "verify-run"
|
||||
elif opt == "--coverage":
|
||||
do_coverage = True
|
||||
elif opt == '--start-with':
|
||||
elif opt == "--start-with":
|
||||
start_with = val
|
||||
elif opt[2:] in test_options_keys:
|
||||
triple = test_options[opt[2:]]
|
||||
vers = triple[-1]
|
||||
test_dirs.append(triple)
|
||||
elif opt == '--max':
|
||||
test_options['max='] = int(val)
|
||||
elif opt == '--all':
|
||||
vers = 'all'
|
||||
elif opt == "--max":
|
||||
test_options["max="] = int(val)
|
||||
elif opt == "--all":
|
||||
vers = "all"
|
||||
for val in test_options_keys:
|
||||
test_dirs.append(test_options[val])
|
||||
|
||||
if do_coverage:
|
||||
os.environ['SPARK_PARSER_COVERAGE'] = (
|
||||
'/tmp/spark-grammar-%s.cover' % vers
|
||||
)
|
||||
os.environ["SPARK_PARSER_COVERAGE"] = "/tmp/spark-grammar-%s.cover" % vers
|
||||
|
||||
failed = 0
|
||||
for src_dir, pattern, target_dir in test_dirs:
|
||||
@@ -175,8 +202,14 @@ if __name__ == '__main__':
|
||||
target_dir = os.path.join(target_base, target_dir)
|
||||
if os.path.exists(target_dir):
|
||||
shutil.rmtree(target_dir, ignore_errors=1)
|
||||
failed += do_tests(src_dir, pattern, target_dir, start_with,
|
||||
do_verify, test_options['max='])
|
||||
failed += do_tests(
|
||||
src_dir,
|
||||
pattern,
|
||||
target_dir,
|
||||
start_with,
|
||||
do_verify,
|
||||
test_options["max="],
|
||||
)
|
||||
else:
|
||||
print("### Path %s doesn't exist; skipping" % src_dir)
|
||||
pass
|
||||
|
@@ -35,69 +35,89 @@ from uncompyle6 import PYTHON_VERSION
|
||||
from uncompyle6.main import main
|
||||
from fnmatch import fnmatch
|
||||
|
||||
|
||||
def get_srcdir():
|
||||
filename = os.path.normcase(os.path.dirname(__file__))
|
||||
return os.path.realpath(filename)
|
||||
|
||||
|
||||
src_dir = get_srcdir()
|
||||
|
||||
|
||||
#----- configure this for your needs
|
||||
# ----- configure this for your needs
|
||||
|
||||
lib_prefix = '/usr/lib'
|
||||
#lib_prefix = [src_dir, '/usr/lib/', '/usr/local/lib/']
|
||||
lib_prefix = "/usr/lib"
|
||||
# lib_prefix = [src_dir, '/usr/lib/', '/usr/local/lib/']
|
||||
|
||||
target_base = tempfile.mkdtemp(prefix='py-dis-')
|
||||
target_base = tempfile.mkdtemp(prefix="py-dis-")
|
||||
|
||||
PY = ('*.py', )
|
||||
PYC = ('*.pyc', )
|
||||
PYO = ('*.pyo', )
|
||||
PYOC = ('*.pyc', '*.pyo')
|
||||
PY = ("*.py",)
|
||||
PYC = ("*.pyc",)
|
||||
PYO = ("*.pyo",)
|
||||
PYOC = ("*.pyc", "*.pyo")
|
||||
|
||||
test_options = {
|
||||
# name: (src_basedir, pattern, output_base_suffix, python_version)
|
||||
'test':
|
||||
('test', PYC, 'test'),
|
||||
|
||||
'ok-2.6': (os.path.join(src_dir, 'ok_lib2.6'),
|
||||
PYOC, 'ok-2.6', 2.6),
|
||||
|
||||
'ok-2.7': (os.path.join(src_dir, 'ok_lib2.7'),
|
||||
PYOC, 'ok-2.7', 2.7),
|
||||
|
||||
'ok-3.2': (os.path.join(src_dir, 'ok_lib3.2'),
|
||||
PYOC, 'ok-3.2', 3.2),
|
||||
|
||||
'base-2.7': (os.path.join(src_dir, 'base_tests', 'python2.7'),
|
||||
PYOC, 'base_2.7', 2.7),
|
||||
"test": ("test", PYC, "test"),
|
||||
"ok-2.6": (os.path.join(src_dir, "ok_lib2.6"), PYOC, "ok-2.6", 2.6),
|
||||
"ok-2.7": (os.path.join(src_dir, "ok_lib2.7"), PYOC, "ok-2.7", 2.7),
|
||||
"ok-3.2": (os.path.join(src_dir, "ok_lib3.2"), PYOC, "ok-3.2", 3.2),
|
||||
"base-2.7": (
|
||||
os.path.join(src_dir, "base_tests", "python2.7"),
|
||||
PYOC,
|
||||
"base_2.7",
|
||||
2.7,
|
||||
),
|
||||
}
|
||||
|
||||
for vers in (2.7, 3.4, 3.5, 3.6):
|
||||
for vers in (2.7, 3.4, 3.5, 3.6):
|
||||
pythonlib = "ok_lib%s" % vers
|
||||
key = "ok-%s" % vers
|
||||
test_options[key] = (os.path.join(src_dir, pythonlib), PYOC, key, vers)
|
||||
pass
|
||||
|
||||
for vers in (1.3, 1.4, 1.5,
|
||||
2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7,
|
||||
3.0, 3.1, 3.2, 3.3,
|
||||
3.4, 3.5, 3.6, 3.7, 3.8, 'pypy3.2', 'pypy2.7', 'pypy3.6'):
|
||||
for vers in (
|
||||
1.3,
|
||||
1.4,
|
||||
1.5,
|
||||
2.1,
|
||||
2.2,
|
||||
2.3,
|
||||
2.4,
|
||||
2.5,
|
||||
2.6,
|
||||
2.7,
|
||||
3.0,
|
||||
3.1,
|
||||
3.2,
|
||||
3.3,
|
||||
3.4,
|
||||
3.5,
|
||||
3.6,
|
||||
3.7,
|
||||
3.8,
|
||||
"pypy3.2",
|
||||
"pypy2.7",
|
||||
"pypy3.6",
|
||||
):
|
||||
bytecode = "bytecode_%s" % vers
|
||||
key = "bytecode-%s" % vers
|
||||
test_options[key] = (bytecode, PYC, bytecode, vers)
|
||||
test_options[key] = (bytecode, PYC, bytecode, vers)
|
||||
bytecode = "bytecode_%s_run" % vers
|
||||
key = "bytecode-%s-run" % vers
|
||||
test_options[key] = (bytecode, PYC, bytecode, vers)
|
||||
test_options[key] = (bytecode, PYC, bytecode, vers)
|
||||
key = "%s" % vers
|
||||
pythonlib = "python%s" % vers
|
||||
if isinstance(vers, float) and vers >= 3.0:
|
||||
pythonlib = os.path.join(pythonlib, '__pycache__')
|
||||
test_options[key] = (os.path.join(lib_prefix, pythonlib), PYOC, pythonlib, vers)
|
||||
pythonlib = os.path.join(pythonlib, "__pycache__")
|
||||
test_options[key] = (os.path.join(lib_prefix, pythonlib), PYOC, pythonlib, vers)
|
||||
|
||||
# -----
|
||||
|
||||
#-----
|
||||
|
||||
def help():
|
||||
print("""Usage-Examples:
|
||||
print(
|
||||
"""Usage-Examples:
|
||||
|
||||
# compile, decompyle and verify short tests for Python 2.7:
|
||||
test_pythonlib.py --bytecode-2.7 --verify --compile
|
||||
@@ -107,18 +127,21 @@ def help():
|
||||
|
||||
# decompile and verify known good python 2.7
|
||||
test_pythonlib.py --ok-2.7 --verify
|
||||
""")
|
||||
"""
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def do_tests(src_dir, obj_patterns, target_dir, opts):
|
||||
|
||||
def file_matches(files, root, basenames, patterns):
|
||||
files.extend(
|
||||
[os.path.normpath(os.path.join(root, n))
|
||||
for n in basenames
|
||||
for pat in patterns
|
||||
if fnmatch(n, pat)])
|
||||
[
|
||||
os.path.normpath(os.path.join(root, n))
|
||||
for n in basenames
|
||||
for pat in patterns
|
||||
if fnmatch(n, pat)
|
||||
]
|
||||
)
|
||||
|
||||
files = []
|
||||
# Change directories so use relative rather than
|
||||
@@ -127,11 +150,14 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
|
||||
cwd = os.getcwd()
|
||||
os.chdir(src_dir)
|
||||
|
||||
if opts['do_compile']:
|
||||
compiled_version = opts['compiled_version']
|
||||
if opts["do_compile"]:
|
||||
compiled_version = opts["compiled_version"]
|
||||
if compiled_version and PYTHON_VERSION != compiled_version:
|
||||
print("Not compiling: desired Python version is %s but we are running %s" %
|
||||
(compiled_version, PYTHON_VERSION), file=sys.stderr)
|
||||
print(
|
||||
"Not compiling: desired Python version is %s but we are running %s"
|
||||
% (compiled_version, PYTHON_VERSION),
|
||||
file=sys.stderr,
|
||||
)
|
||||
else:
|
||||
for root, dirs, basenames in os.walk(src_dir):
|
||||
file_matches(files, root, basenames, PY)
|
||||
@@ -143,34 +169,36 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
|
||||
pass
|
||||
pass
|
||||
|
||||
for root, dirs, basenames in os.walk('.'):
|
||||
for root, dirs, basenames in os.walk("."):
|
||||
# Turn root into a relative path
|
||||
dirname = root[2:] # 2 = len('.') + 1
|
||||
file_matches(files, dirname, basenames, obj_patterns)
|
||||
|
||||
if not files:
|
||||
print("Didn't come up with any files to test! Try with --compile?",
|
||||
file=sys.stderr)
|
||||
print(
|
||||
"Didn't come up with any files to test! Try with --compile?",
|
||||
file=sys.stderr,
|
||||
)
|
||||
exit(1)
|
||||
|
||||
os.chdir(cwd)
|
||||
files.sort()
|
||||
|
||||
if opts['start_with']:
|
||||
if opts["start_with"]:
|
||||
try:
|
||||
start_with = files.index(opts['start_with'])
|
||||
start_with = files.index(opts["start_with"])
|
||||
files = files[start_with:]
|
||||
print('>>> starting with file', files[0])
|
||||
print(">>> starting with file", files[0])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
print(time.ctime())
|
||||
print('Source directory: ', src_dir)
|
||||
print('Output directory: ', target_dir)
|
||||
print("Source directory: ", src_dir)
|
||||
print("Output directory: ", target_dir)
|
||||
try:
|
||||
_, _, failed_files, failed_verify = \
|
||||
main(src_dir, target_dir, files, [],
|
||||
do_verify=opts['do_verify'])
|
||||
_, _, failed_files, failed_verify = main(
|
||||
src_dir, target_dir, files, [], do_verify=opts["do_verify"]
|
||||
)
|
||||
if failed_files != 0:
|
||||
sys.exit(2)
|
||||
elif failed_verify != 0:
|
||||
@@ -179,71 +207,81 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
|
||||
except (KeyboardInterrupt, OSError):
|
||||
print()
|
||||
sys.exit(1)
|
||||
if test_opts['rmtree']:
|
||||
if test_opts["rmtree"]:
|
||||
parent_dir = os.path.dirname(target_dir)
|
||||
print("Everything good, removing %s" % parent_dir)
|
||||
shutil.rmtree(parent_dir)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_dirs = []
|
||||
checked_dirs = []
|
||||
start_with = None
|
||||
|
||||
test_options_keys = list(test_options.keys())
|
||||
test_options_keys.sort()
|
||||
opts, args = getopt.getopt(sys.argv[1:], '',
|
||||
['start-with=', 'verify', 'verify-run',
|
||||
'weak-verify', 'all',
|
||||
'compile', 'coverage',
|
||||
'no-rm'] \
|
||||
+ test_options_keys )
|
||||
if not opts: help()
|
||||
opts, args = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
"",
|
||||
[
|
||||
"start-with=",
|
||||
"verify",
|
||||
"verify-run",
|
||||
"syntax-verify",
|
||||
"all",
|
||||
"compile",
|
||||
"coverage",
|
||||
"no-rm",
|
||||
]
|
||||
+ test_options_keys,
|
||||
)
|
||||
if not opts:
|
||||
help()
|
||||
|
||||
test_opts = {
|
||||
'do_compile': False,
|
||||
'do_verify': False,
|
||||
'start_with': None,
|
||||
'rmtree' : True,
|
||||
'coverage' : False
|
||||
}
|
||||
"do_compile": False,
|
||||
"do_verify": False,
|
||||
"start_with": None,
|
||||
"rmtree": True,
|
||||
"coverage": False,
|
||||
}
|
||||
|
||||
for opt, val in opts:
|
||||
if opt == '--verify':
|
||||
test_opts['do_verify'] = 'strong'
|
||||
elif opt == '--weak-verify':
|
||||
test_opts['do_verify'] = 'weak'
|
||||
elif opt == '--verify-run':
|
||||
test_opts['do_verify'] = 'verify-run'
|
||||
elif opt == '--compile':
|
||||
test_opts['do_compile'] = True
|
||||
elif opt == '--start-with':
|
||||
test_opts['start_with'] = val
|
||||
elif opt == '--no-rm':
|
||||
test_opts['rmtree'] = False
|
||||
if opt == "--verify":
|
||||
test_opts["do_verify"] = "strong"
|
||||
elif opt == "--syntax-verify":
|
||||
test_opts["do_verify"] = "weak"
|
||||
elif opt == "--verify-run":
|
||||
test_opts["do_verify"] = "verify-run"
|
||||
elif opt == "--compile":
|
||||
test_opts["do_compile"] = True
|
||||
elif opt == "--start-with":
|
||||
test_opts["start_with"] = val
|
||||
elif opt == "--no-rm":
|
||||
test_opts["rmtree"] = False
|
||||
elif opt[2:] in test_options_keys:
|
||||
test_dirs.append(test_options[opt[2:]])
|
||||
elif opt == '--all':
|
||||
elif opt == "--all":
|
||||
for val in test_options_keys:
|
||||
test_dirs.append(test_options[val])
|
||||
elif opt == '--coverage':
|
||||
test_opts['coverage'] = True
|
||||
elif opt == "--coverage":
|
||||
test_opts["coverage"] = True
|
||||
else:
|
||||
help()
|
||||
pass
|
||||
pass
|
||||
|
||||
if test_opts['coverage']:
|
||||
os.environ['SPARK_PARSER_COVERAGE'] = (
|
||||
'/tmp/spark-grammar-python-lib%s.cover' % test_dirs[0][-1]
|
||||
)
|
||||
if test_opts["coverage"]:
|
||||
os.environ["SPARK_PARSER_COVERAGE"] = (
|
||||
"/tmp/spark-grammar-python-lib%s.cover" % test_dirs[0][-1]
|
||||
)
|
||||
|
||||
last_compile_version = None
|
||||
for src_dir, pattern, target_dir, compiled_version in test_dirs:
|
||||
if os.path.isdir(src_dir):
|
||||
checked_dirs.append([src_dir, pattern, target_dir])
|
||||
else:
|
||||
print("Can't find directory %s. Skipping" % src_dir,
|
||||
file=sys.stderr)
|
||||
print("Can't find directory %s. Skipping" % src_dir, file=sys.stderr)
|
||||
continue
|
||||
last_compile_version = compiled_version
|
||||
pass
|
||||
@@ -252,7 +290,7 @@ if __name__ == '__main__':
|
||||
print("No directories found to check", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
test_opts['compiled_version'] = last_compile_version
|
||||
test_opts["compiled_version"] = last_compile_version
|
||||
|
||||
for src_dir, pattern, target_dir in checked_dirs:
|
||||
target_dir = os.path.join(target_base, target_dir)
|
||||
|
@@ -51,14 +51,8 @@ import uncompyle6.semantics.fragments
|
||||
# Export some functions
|
||||
from uncompyle6.main import decompile_file
|
||||
|
||||
# For compatibility
|
||||
uncompyle_file = decompile_file
|
||||
|
||||
# Convenience functions so you can say:
|
||||
# from uncompyle6 import (code_deparse, deparse_code2str)
|
||||
|
||||
code_deparse = uncompyle6.semantics.pysource.code_deparse
|
||||
deparse_code2str = uncompyle6.semantics.pysource.deparse_code2str
|
||||
|
||||
# This is deprecated:
|
||||
deparse_code = uncompyle6.semantics.pysource.deparse_code
|
||||
code_deparse = uncompyle6.semantics.pysource.code_deparse
|
||||
|
@@ -38,16 +38,20 @@ Options:
|
||||
--fragments use fragments deparser
|
||||
--verify compare generated source with input byte-code
|
||||
--verify-run compile generated source, run it and check exit code
|
||||
--weak-verify compile generated source
|
||||
--syntax-verify compile generated source
|
||||
--linemaps generated line number correspondencies between byte-code
|
||||
and generated source output
|
||||
--encoding <encoding>
|
||||
use <encoding> in generated source according to pep-0263
|
||||
--help show this message
|
||||
|
||||
Debugging Options:
|
||||
--asm | -a include byte-code (disables --verify)
|
||||
--grammar | -g show matching grammar
|
||||
--tree | -t include syntax tree (disables --verify)
|
||||
--tree++ add template rules to --tree when possible
|
||||
--asm | -a include byte-code (disables --verify)
|
||||
--grammar | -g show matching grammar
|
||||
--tree={before|after}
|
||||
-t {before|after} include syntax before (or after) tree transformation
|
||||
(disables --verify)
|
||||
--tree++ | -T add template rules to --tree=before when possible
|
||||
|
||||
Extensions of generated files:
|
||||
'.pyc_dis' '.pyo_dis' successfully decompiled (and verified if --verify)
|
||||
@@ -85,12 +89,12 @@ def main_bin():
|
||||
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
|
||||
|
||||
try:
|
||||
opts, pyc_paths = getopt.getopt(sys.argv[1:], 'hac:gtdrVo:p:',
|
||||
opts, pyc_paths = getopt.getopt(sys.argv[1:], 'hac:gtTdrVo:p:',
|
||||
'help asm compile= grammar linemaps recurse '
|
||||
'timestamp tree tree+ '
|
||||
'timestamp tree= tree+ '
|
||||
'fragments verify verify-run version '
|
||||
'weak-verify '
|
||||
'showgrammar'.split(' '))
|
||||
'syntax-verify '
|
||||
'showgrammar encoding='.split(' '))
|
||||
except getopt.GetoptError as e:
|
||||
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
@@ -105,7 +109,7 @@ def main_bin():
|
||||
sys.exit(0)
|
||||
elif opt == '--verify':
|
||||
options['do_verify'] = 'strong'
|
||||
elif opt == '--weak-verify':
|
||||
elif opt == '--syntax-verify':
|
||||
options['do_verify'] = 'weak'
|
||||
elif opt == '--fragments':
|
||||
options['do_fragments'] = True
|
||||
@@ -117,10 +121,19 @@ def main_bin():
|
||||
options['showasm'] = 'after'
|
||||
options['do_verify'] = None
|
||||
elif opt in ('--tree', '-t'):
|
||||
options['showast'] = True
|
||||
if 'showast' not in options:
|
||||
options['showast'] = {}
|
||||
if val == 'before':
|
||||
options['showast'][val] = True
|
||||
elif val == 'after':
|
||||
options['showast'][val] = True
|
||||
else:
|
||||
options['showast']['before'] = True
|
||||
options['do_verify'] = None
|
||||
elif opt in ('--tree+',):
|
||||
options['showast'] = 'Full'
|
||||
elif opt in ('--tree+', '-T'):
|
||||
if 'showast' not in options:
|
||||
options['showast'] = {}
|
||||
options['showast']['Full'] = True
|
||||
options['do_verify'] = None
|
||||
elif opt in ('--grammar', '-g'):
|
||||
options['showgrammar'] = True
|
||||
@@ -134,6 +147,8 @@ def main_bin():
|
||||
numproc = int(val)
|
||||
elif opt in ('--recurse', '-r'):
|
||||
recurse_dirs = True
|
||||
elif opt == '--encoding':
|
||||
options['source_encoding'] = val
|
||||
else:
|
||||
print(opt, file=sys.stderr)
|
||||
usage()
|
||||
|
@@ -45,10 +45,21 @@ def _get_outstream(outfile):
|
||||
return open(outfile, mode='w', encoding='utf-8')
|
||||
|
||||
def decompile(
|
||||
bytecode_version, co, out=None, showasm=None, showast=False,
|
||||
timestamp=None, showgrammar=False, code_objects={},
|
||||
source_size=None, is_pypy=None, magic_int=None,
|
||||
mapstream=None, do_fragments=False):
|
||||
bytecode_version,
|
||||
co,
|
||||
out=None,
|
||||
showasm=None,
|
||||
showast={},
|
||||
timestamp=None,
|
||||
showgrammar=False,
|
||||
source_encoding=None,
|
||||
code_objects={},
|
||||
source_size=None,
|
||||
is_pypy=None,
|
||||
magic_int=None,
|
||||
mapstream=None,
|
||||
do_fragments=False,
|
||||
):
|
||||
"""
|
||||
ingests and deparses a given code block 'co'
|
||||
|
||||
@@ -72,6 +83,8 @@ def decompile(
|
||||
co_pypy_str = 'PyPy ' if is_pypy else ''
|
||||
run_pypy_str = 'PyPy ' if IS_PYPY else ''
|
||||
sys_version_lines = sys.version.split('\n')
|
||||
if source_encoding:
|
||||
write('# -*- coding: %s -*-' % source_encoding)
|
||||
write('# uncompyle6 version %s\n'
|
||||
'# %sPython bytecode %s%s\n# Decompiled from: %sPython %s' %
|
||||
(VERSION, co_pypy_str, bytecode_version,
|
||||
@@ -136,7 +149,7 @@ def compile_file(source_path):
|
||||
|
||||
|
||||
def decompile_file(filename, outstream=None, showasm=None, showast=False,
|
||||
showgrammar=False, mapstream=None, do_fragments=False):
|
||||
showgrammar=False, source_encoding=None, mapstream=None, do_fragments=False):
|
||||
"""
|
||||
decompile Python byte-code file (.pyc). Return objects to
|
||||
all of the deparsed objects found in `filename`.
|
||||
@@ -152,12 +165,12 @@ def decompile_file(filename, outstream=None, showasm=None, showast=False,
|
||||
for con in co:
|
||||
deparsed.append(
|
||||
decompile(version, con, outstream, showasm, showast,
|
||||
timestamp, showgrammar, code_objects=code_objects,
|
||||
timestamp, showgrammar, source_encoding, code_objects=code_objects,
|
||||
is_pypy=is_pypy, magic_int=magic_int),
|
||||
mapstream=mapstream)
|
||||
else:
|
||||
deparsed = [decompile(version, co, outstream, showasm, showast,
|
||||
timestamp, showgrammar,
|
||||
timestamp, showgrammar, source_encoding,
|
||||
code_objects=code_objects, source_size=source_size,
|
||||
is_pypy=is_pypy, magic_int=magic_int,
|
||||
mapstream=mapstream, do_fragments=do_fragments)]
|
||||
@@ -168,7 +181,7 @@ def decompile_file(filename, outstream=None, showasm=None, showast=False,
|
||||
# FIXME: combine into an options parameter
|
||||
def main(in_base, out_base, compiled_files, source_files, outfile=None,
|
||||
showasm=None, showast=False, do_verify=False,
|
||||
showgrammar=False, raise_on_error=False,
|
||||
showgrammar=False, source_encoding=None, raise_on_error=False,
|
||||
do_linemaps=False, do_fragments=False):
|
||||
"""
|
||||
in_base base directory for input files
|
||||
@@ -245,7 +258,7 @@ def main(in_base, out_base, compiled_files, source_files, outfile=None,
|
||||
# Try to uncompile the input file
|
||||
try:
|
||||
deparsed = decompile_file(infile, outstream, showasm, showast, showgrammar,
|
||||
linemap_stream, do_fragments)
|
||||
source_encoding, linemap_stream, do_fragments)
|
||||
if do_fragments:
|
||||
for d in deparsed:
|
||||
last_mod = None
|
||||
@@ -275,11 +288,24 @@ def main(in_base, out_base, compiled_files, source_files, outfile=None,
|
||||
sys.stdout.write("\n")
|
||||
sys.stderr.write("\nLast file: %s " % (infile))
|
||||
raise
|
||||
except RuntimeError as e:
|
||||
sys.stdout.write("\n%s\n" % str(e))
|
||||
if str(e).startswith('Unsupported Python'):
|
||||
sys.stdout.write("\n")
|
||||
sys.stderr.write("\n# Unsupported bytecode in file %s\n# %s\n" % (infile, e))
|
||||
else:
|
||||
if outfile:
|
||||
outstream.close()
|
||||
os.remove(outfile)
|
||||
sys.stdout.write("\n")
|
||||
sys.stderr.write("\nLast file: %s " % (infile))
|
||||
raise
|
||||
|
||||
# except:
|
||||
# failed_files += 1
|
||||
# if current_outfile:
|
||||
# outstream.close()
|
||||
# os.rename(current_outfile, current_outfile + '_failed')
|
||||
# os.rename(current_outfile, current_outfile + "_failed")
|
||||
# else:
|
||||
# sys.stderr.write("\n# %s" % sys.exc_info()[1])
|
||||
# sys.stderr.write("\n# Can't uncompile %s\n" % infile)
|
||||
@@ -328,9 +354,9 @@ def main(in_base, out_base, compiled_files, source_files, outfile=None,
|
||||
# mem_usage = __memUsage()
|
||||
print(mess, infile)
|
||||
if current_outfile:
|
||||
sys.stdout.write("%s\r" %
|
||||
status_msg(do_verify, tot_files, okay_files, failed_files,
|
||||
verify_failed_files, do_verify))
|
||||
sys.stdout.write("%s -- %s\r" %
|
||||
(infile, status_msg(do_verify, tot_files, okay_files, failed_files,
|
||||
verify_failed_files, do_verify)))
|
||||
try:
|
||||
# FIXME: Something is weird with Pypy here
|
||||
sys.stdout.flush()
|
||||
|
@@ -61,7 +61,6 @@ class PythonParser(GenericASTBuilder):
|
||||
'imports_cont',
|
||||
'kvlist_n',
|
||||
# Python 3.6+
|
||||
'joined_str',
|
||||
'come_from_loops',
|
||||
]
|
||||
self.collect = frozenset(nt_list)
|
||||
@@ -83,7 +82,7 @@ class PythonParser(GenericASTBuilder):
|
||||
# FIXME: would love to do expr, sstmts, stmts and
|
||||
# so on but that would require major changes to the
|
||||
# semantic actions
|
||||
self.singleton = frozenset(('str', 'joined_str', 'store', '_stmts', 'suite_stmts_opt',
|
||||
self.singleton = frozenset(('str', 'store', '_stmts', 'suite_stmts_opt',
|
||||
'inplace_op'))
|
||||
# Instructions filled in from scanner
|
||||
self.insts = []
|
||||
@@ -499,6 +498,7 @@ class PythonParser(GenericASTBuilder):
|
||||
def p_expr(self, args):
|
||||
'''
|
||||
expr ::= _mklambda
|
||||
expr ::= LOAD_CODE
|
||||
expr ::= LOAD_FAST
|
||||
expr ::= LOAD_NAME
|
||||
expr ::= LOAD_CONST
|
||||
@@ -804,7 +804,6 @@ def python_parser(version, co, out=sys.stdout, showasm=False,
|
||||
if __name__ == '__main__':
|
||||
def parse_test(co):
|
||||
from uncompyle6 import PYTHON_VERSION, IS_PYPY
|
||||
ast = python_parser('2.7.13', co, showasm=True, is_pypy=True)
|
||||
ast = python_parser(PYTHON_VERSION, co, showasm=True, is_pypy=IS_PYPY)
|
||||
print(ast)
|
||||
return
|
||||
|
@@ -98,9 +98,9 @@ class Python2Parser(PythonParser):
|
||||
for ::= SETUP_LOOP expr for_iter store
|
||||
for_block POP_BLOCK _come_froms
|
||||
|
||||
del_stmt ::= delete_subscr
|
||||
delete_subscr ::= expr expr DELETE_SUBSCR
|
||||
del_stmt ::= expr DELETE_ATTR
|
||||
del_stmt ::= delete_subscript
|
||||
delete_subscript ::= expr expr DELETE_SUBSCR
|
||||
del_stmt ::= expr DELETE_ATTR
|
||||
|
||||
_mklambda ::= load_closure mklambda
|
||||
kwarg ::= LOAD_CONST expr
|
||||
@@ -390,10 +390,10 @@ class Python2Parser(PythonParser):
|
||||
continue
|
||||
elif opname == 'DELETE_SUBSCR':
|
||||
self.addRule("""
|
||||
del_stmt ::= delete_subscr
|
||||
delete_subscr ::= expr expr DELETE_SUBSCR
|
||||
del_stmt ::= delete_subscript
|
||||
delete_subscript ::= expr expr DELETE_SUBSCR
|
||||
""", nop_func)
|
||||
self.check_reduce['delete_subscr'] = 'AST'
|
||||
self.check_reduce['delete_subscript'] = 'AST'
|
||||
custom_seen_ops.add(opname)
|
||||
continue
|
||||
elif opname == 'GET_ITER':
|
||||
@@ -459,7 +459,7 @@ class Python2Parser(PythonParser):
|
||||
if i > 0 and tokens[i-1] == 'LOAD_LAMBDA':
|
||||
self.addRule('mklambda ::= %s LOAD_LAMBDA %s' %
|
||||
('pos_arg ' * token.attr, opname), nop_func)
|
||||
rule = 'mkfunc ::= %s LOAD_CONST %s' % ('expr ' * token.attr, opname)
|
||||
rule = 'mkfunc ::= %s LOAD_CODE %s' % ('expr ' * token.attr, opname)
|
||||
elif opname_base == 'MAKE_CLOSURE':
|
||||
# FIXME: use add_unique_rules to tidy this up.
|
||||
if i > 0 and tokens[i-1] == 'LOAD_LAMBDA':
|
||||
@@ -474,7 +474,7 @@ class Python2Parser(PythonParser):
|
||||
('expr ' * token.attr, opname))], customize)
|
||||
pass
|
||||
self.add_unique_rules([
|
||||
('mkfunc ::= %s load_closure LOAD_CONST %s' %
|
||||
('mkfunc ::= %s load_closure LOAD_CODE %s' %
|
||||
('expr ' * token.attr, opname))], customize)
|
||||
|
||||
if self.version >= 2.7:
|
||||
@@ -549,7 +549,7 @@ class Python2Parser(PythonParser):
|
||||
elif rule == ('or', ('expr', 'jmp_true', 'expr', '\\e_come_from_opt')):
|
||||
expr2 = ast[2]
|
||||
return expr2 == 'expr' and expr2[0] == 'LOAD_ASSERT'
|
||||
elif lhs in ('delete_subscr', 'del_expr'):
|
||||
elif lhs in ('delete_subscript', 'del_expr'):
|
||||
op = ast[0][0]
|
||||
return op.kind in ('and', 'or')
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user