Compare commits

...

157 Commits

Author SHA1 Message Date
rocky
470d203b40 Merge branch 'master' of github.com:rocky/python-uncompyle6 2021-10-29 22:19:47 -04:00
rocky
4911d85237 Get ready for release 3.8.0 2021-10-29 22:17:17 -04:00
rocky
93a218a8b1 Get ready for release 3.8.0 2021-10-29 22:16:20 -04:00
rocky
32c4b84458 Better handling of bytecode errors 2021-10-28 18:37:54 -04:00
rocky
9cf345d446 Allow running test from 3.9 and 3.10
this does not mean we decompile either of those bytecode though.
2021-10-26 19:05:32 -04:00
rocky
c164df2795 Redo packaging. 2021-10-26 18:52:55 -04:00
rocky
3ad63071ac Admnistrivia: package info 2021-10-26 18:39:36 -04:00
rocky
d0ca7b0363 Loosen check to allow running from 2.4-3.10
We still only can *decompile* 2.4-3.8
2021-10-26 06:21:51 -04:00
rocky
ea26084e6d Modernize and sync with decompyle3 better 2021-10-25 09:13:47 -04:00
rocky
fa203af665 Better messages when xdis not handling Python x.y 2021-10-24 23:22:41 -04:00
rocky
51ac72ba1f Sync with decompile3 2021-10-24 01:52:23 -04:00
rocky
d5bf7626af Fix bug in fragment parser 2021-10-24 01:32:41 -04:00
rocky
7387e5094b More version tuple conversions 2021-10-23 15:54:14 -04:00
rocky
1bcd21a6f4 More version conversion bugs 2021-10-23 10:04:58 -04:00
rocky
71fe1e6c2c Fragment and other bugs
Part of the upgrade process
2021-10-23 09:47:30 -04:00
rocky
40a40b0bad Administrivia 2021-10-23 09:03:29 -04:00
rocky
528a2b0c22 Administrivia 2021-10-23 08:57:19 -04:00
rocky
e3369edaed DRY using version_info_to_str 2021-10-23 08:24:35 -04:00
rocky
0a9dc57cc9 Try 3.6 CI testing 2021-10-21 18:53:44 -04:00
rocky
48bd832e7c Adminsitrivia 2021-10-21 16:36:46 -04:00
rocky
29a91fc015 Version twiddling 2021-10-21 16:33:09 -04:00
rocky
3e5f963c64 Merge branch 'master' of github.com:rocky/python-uncompyle6 2021-10-21 15:54:08 -04:00
R. Bernstein
c7ebdb344b Merge pull request #360 from rocky/3.10-adjust
Try Travis with new xdis
2021-10-21 15:52:40 -04:00
rocky
438c3b8d1d Add Windows and OSX CI 2021-10-21 15:47:15 -04:00
rocky
aa1d7abfdc Worflows CI testing 2021-10-21 15:42:22 -04:00
rocky
d3e30cf0e0 Update Python version in appveyor 2021-10-21 14:23:14 -04:00
rocky
36efc1fc8a Try 1st workflows CI 2021-10-21 14:18:56 -04:00
rocky
f00080317b Add pyston-2.3 in testing 2021-10-21 14:15:26 -04:00
rocky
162423895e Administrivia 2021-10-21 02:31:59 -04:00
rocky
f2750cff50 Correct pytest/test_grammar.py for new regime 2021-10-21 02:28:48 -04:00
R. Bernstein
256aaf0ef9 Update HOW-TO-REPORT-A-BUG.md 2021-10-21 02:23:03 -04:00
rocky
41314f95bb More Python version comparison adjustments 2021-10-19 16:30:56 -04:00
rocky
0645738775 Revise Python version comparisions
And set scanner.show_asm for 3.6
2021-10-19 05:54:54 -04:00
rocky
ceb7c659bd Python version comparison adjustments 2021-10-18 12:23:53 -04:00
rocky
8ac7a75372 Use tuples not floats in Python release comparison 2021-10-18 11:59:02 -04:00
rocky
15efaffe8d More Python version tuple comparison conversion 2021-10-16 11:41:22 -04:00
rocky
e8e006bb8c More Python version comparison conversions 2021-10-16 11:33:03 -04:00
rocky
c68b74a9c6 new dis - Python compisons involving tuples 2021-10-15 23:39:59 -04:00
rocky
f4bb0c44fe Try Travis with new xdis 2021-10-12 17:24:19 -04:00
R. Bernstein
8d81f4ab27 Update HOW-TO-REPORT-A-BUG.md 2021-09-16 06:23:25 -04:00
R. Bernstein
e0a56d4739 Update HOW-TO-REPORT-A-BUG.md 2021-09-03 07:41:38 -04:00
R. Bernstein
054364cb22 Update HOW-TO-REPORT-A-BUG.md 2021-09-03 07:32:53 -04:00
R. Bernstein
83c8313a8e Update HOW-TO-REPORT-A-BUG.md 2021-09-03 07:31:03 -04:00
rocky
184bda1b03 Work around broken modularity in python_parser 2021-08-27 02:13:09 -04:00
rocky
f374485e93 Another fragment fix for 3.8 2021-07-29 14:23:17 -04:00
rocky
fe7df87288 Sync 3.8 and Makefile changes with decompyle3
Makefile: pyston 2.3 tolerance
fragments: 3.8 comprehension adjustments
2021-07-29 13:16:03 -04:00
rocky
cfbb25df3d Fix some small bugs 2021-07-08 05:40:43 -04:00
rocky
d4174832a1 Black shouldn't format version.py 2021-06-23 11:46:31 -04:00
rocky
345de81d06 Administriva: add some config files
.editoryconfig: tell editors how to format this
setup.cfg: general project setup outside of Python-specific stuff
2021-06-23 02:09:32 -04:00
R. Bernstein
dd8f22e698 Merge pull request #352 from rocky/lambda-bug
Fixes #360
2021-06-15 22:46:46 -04:00
rocky
96b1e435c2 Fixes #360 2021-06-15 22:42:55 -04:00
R. Bernstein
971757e997 Merge pull request #348 from IzeBerg/patch-1
'NoneType' object is not iterable with numproc > 1
2021-06-14 13:44:49 -04:00
Renat Iliev
2b154e0b88 'NoneType' object is not iterable with numproc > 1
main calls with source_paths=None, but it needs to be iterable
2021-06-14 19:50:18 +03:00
R. Bernstein
5d35a75743 Merge pull request #340 from timgates42/bugfix_typo_unnecessary
docs: fix simple typo, unecessary -> unnecessary
2020-12-31 03:22:09 -05:00
Tim Gates
fc38e23d8f docs: fix simple typo, unecessary -> unnecessary
There is a small typo in test/simple_source/looping/12_if_while_true_pass.py.

Should read `unnecessary` rather than `unecessary`.
2020-12-31 18:11:41 +11:00
rocky
5c16c73a6c Fix annotation transform for 3.7+
We were producing:

```
z: z: int = 5 on bytecode_3.7_run/02_var_annotate.pyc
```

because grammar went

     5. sstmt
        ann_assign (4) transformed by n_stmts: ('%|%[2]{attr}: %c\n', 0)
             0. ann_assign_init (3): ('%|%[2]{attr}: %c = %c\n', 0, 1)

The "ann_assign" added "z:". Instead we have now:

```
     5. sstmt
        ann_assign_init (3) transformed by n_stmts: ('%|%[2]{attr}: %c = %c\n', 0, 1)
```

Also, in the previous statement which appears in the listing (but is not
actually in the finaly tree) we had:

     4. sstmt
        assign (2): ('%|%c = %p\n', -1, (0, 200))
             0. expr
                L. L.   7        26  LOAD_CONST               5
             1. store

So we now preface the node type with "deleted", e.g.:

     4. deleted sstmt
        assign (2): ('%|%c = %p\n', -1, (0, 200))
             0. expr
                L. L.   7        26  LOAD_CONST               5
             1. store

to reduce confusion
2020-12-27 22:50:46 -05:00
R. Bernstein
3f665b939d Merge pull request #339 from bloerwald/parsers-fix_expr32_emitted_when_used_by_expr1024
parsers: parse2: fix: also emit expr32 if count perfectly divisible by 1024
2020-12-27 20:46:10 -05:00
Bernd Lörwald
f2f49104ea parsers: parse2: fix: also emit expr32 if count perfectly divisible by 1024
expr1024 requires expr32, but a build_count of 1024 would emit only the
expr1024 rule and rely on luck of it being emitted somewhere else.

Emit expr32 rule either if there is a expr32 use or a expr1024 use to avoid.
2020-12-28 01:42:42 +01:00
R. Bernstein
c2ee564e11 Update README.rst 2020-11-20 08:52:55 -05:00
rocky
f95db091bc Merge branch 'master' of github.com:rocky/python-uncompyle6 2020-11-03 18:09:40 -05:00
rocky
78dbc8ae0f Adjust ann_assign_init rule...
We've reduced spurious `sstmt` reductions. The `ann_assign_init` rule needs
to adjust accordingly.
2020-11-03 18:07:42 -05:00
rocky
70b7e51df6 VERSION -> version 2020-10-31 11:25:06 -04:00
rocky
1164cd90dc Merge branch 'master' of github.com:rocky/python-uncompyle6 2020-09-10 17:19:36 -04:00
rocky
4bbdbe3894 Remove bogus async_with rule 2020-09-10 17:19:13 -04:00
rocky
28855767fb Get ready for release 3.7.4 2020-09-05 06:06:40 -04:00
rocky
8eb4d6a576 Fix bit rot in fragments.py
build_ast() added a code argument
n_dict(): was out of sync with corresponding pysource routine
pysource.py: small doc typo
2020-09-04 19:30:48 -04:00
rocky
b4db22d525 Narrow precedence for call statement 2020-09-03 04:35:59 -04:00
rocky
8879708da7 del_stmt -> delete to match Python AST better 2020-09-02 07:14:56 -04:00
rocky
67c45467c3 little sync with decompyle3
Add another forelsestmt (found only in a loop)
Add precidence on walrus operator
2020-09-01 17:10:33 -04:00
rocky
33bff4dc47 Small int thing and sync with decompyle3 2020-09-01 16:18:10 -04:00
rocky
71c17c4e53 Fragment api changed...
sync with pysource.
Simplify pysource a little
2020-08-23 19:27:52 -04:00
rocky
a5cfd81805 Include 3.8 excludes from decompyle3 2020-07-28 07:59:39 -04:00
rocky
64f19bf188 Use newest versions for 3.6-3.8 2020-07-26 10:53:17 -04:00
rocky
ff08f8a977 Administrivia 2020-07-25 15:42:54 -04:00
rocky
3ae4fda292 Administrivia 2020-07-25 15:40:27 -04:00
rocky
6cb6e45789 Get ready for release 3.7.3 2020-07-25 15:34:37 -04:00
rocky
024a81c053 Fix condition sense in except_handler.py reduction 2020-07-23 11:03:43 -04:00
rocky
a0f93f7ad9 Comment last change 2020-07-22 06:44:34 -04:00
rocky
d3d67441d1 Add VERSION in a pydoc-friendly way 2020-07-22 06:38:47 -04:00
rocky
a215ee2f00 Use "co_consts" in docstring detection.
Note: this is an upheaval because we need to pass "code" or at least
"code.co_consts" to the docstring detection routine
2020-07-21 10:31:07 -04:00
rocky
f62512dd65 Clarify a warning message 2020-07-19 20:36:18 -04:00
rocky
0f80c38530 Better doc string detection
A bug in 2.7 test_descr.py revealed a problem with the way we were
detecting docstrings.

        __doc__ = DocDescr()

was getting confused with a docstring.

This program also reveals other bugs in 3.2+ but we'll deal with that
in another commit.
2020-07-19 20:31:50 -04:00
rocky
bd07de5172 Issue template tweaking again 2020-07-16 07:21:24 -04:00
rocky
e36945e2d9 Another tweak 2020-07-16 07:09:48 -04:00
rocky
25df0bdb76 Spelling typo 2020-07-16 07:04:25 -04:00
rocky
29ceb3fe05 Tweak again 2020-07-16 07:03:01 -04:00
rocky
fd7e04fa5d Small tweaks 2020-07-16 07:00:13 -04:00
rocky
5079164db2 Add reduce check for aug_assign1 2020-07-07 09:54:57 -04:00
rocky
815ae2c5cd for/else detection for older 2.x Pythons 2020-07-06 18:38:14 -04:00
rocky
54932d36fa Small tweaks...
add-test.py: wasn't handling optimize correctly. Handle python version better
parse27.py: dyslexia
01_for_else_try_else.py: bug in found in 1.4 anydbm.py which we will
address soon
2020-07-06 18:19:06 -04:00
rocky
fa1d7e4af4 Tweak. 2020-07-06 14:44:25 -04:00
rocky
bfd4b4cd68 Update bug-fixing expectations 2020-07-06 14:35:24 -04:00
rocky
430fd2fa85 Update README.rst status on early Pythons 2020-07-06 12:02:59 -04:00
rocky
ef59b9c304 Forelse reduction checks on 2.6 2020-07-06 10:09:42 -04:00
rocky
084e183577 Add reduce check for 2.7 except_handler range 2020-07-05 22:18:07 -04:00
rocky
7c14cf2d66 Add missing ref URLs 2020-07-05 09:55:43 -04:00
rocky
1d3fdbb4cd Update status 2020-07-05 00:59:16 -04:00
rocky
b21e8b8b57 Get ready for release 3.7.2 2020-06-27 23:08:46 -04:00
rocky
4007b8b702 Back off "or" check using instructions vs opcodes 2020-06-27 11:44:23 -04:00
rocky
598b58796d Back off buggy "or" check 2020-06-27 11:33:46 -04:00
rocky
f7bad891a4 Last commit fixed test_pep352.py 2020-06-27 11:22:53 -04:00
rocky
357f28dd89 Add "comp_if_not" for 2.6- 2020-06-27 11:16:47 -04:00
rocky
5cc572147a Handle more ifelse reduction rules patterns 2020-06-27 09:10:48 -04:00
rocky
11be90758f Workaround bug detecting MAKE_FUNCTION docstrings 2020-06-26 07:17:31 -04:00
rocky
e3720515ae Adjust for newer xdis 2020-06-21 20:20:25 -04:00
rocky
7dec354a47 Merge branch 'master' of github.com:rocky/python-uncompyle6 2020-06-17 10:15:07 -04:00
rocky
2a8daca25d Fix broken __doc__ transform yet again...
Hopefully by using first_child() we have something more robust now.
2020-06-17 10:12:56 -04:00
rocky
7799819cad Add another 3.7 stdlib exclusion test 2020-06-17 05:42:10 -04:00
rocky
c6c50b5dfb Disable compile-farm 3.8.3 checking 2020-06-17 05:29:04 -04:00
rocky
d357898bbf Towards fixing a 3.8 try except-as bug 2020-06-15 06:03:28 -04:00
rocky
c4e7ddf90a Administrivia 2020-06-12 21:29:32 -04:00
rocky
02f502c40a New grammar rule often imples expanded reduce rule 2020-06-12 21:12:02 -04:00
rocky
de4fbb08f2 Get ready for release 3.7.1 2020-06-12 20:20:58 -04:00
rocky
e14675c2dc Handle 3.7+ "else" branch removal...
As seen in _cmp() of python3.8/distutils/version.py with optimization -O2
2020-06-12 13:18:33 -04:00
rocky
3449be024b CI take 3. 2020-06-10 22:18:28 -04:00
rocky
8b50b15f0a CI update take 2 2020-06-10 22:17:13 -04:00
rocky
e2e925679d Update CI to use git xdis 2020-06-10 22:15:55 -04:00
rocky
7deeee8502 Push "with" grammar improvements back to 3.6 2020-06-04 05:53:21 -04:00
rocky
acdd025162 ast-check "for" is a loop; sync "withas" test ..
with decompyle3.
2020-06-04 05:34:19 -04:00
rocky
9acb3cf068 Fix bug in 3.8 with .. as 2020-06-04 05:24:22 -04:00
rocky
40a653cd3b Bump min xdis version...
it fixes a bug in stdlib testing
2020-05-31 03:17:09 -04:00
rocky
3ac3979535 With a newer xdis, some stdlib test work now 2020-05-31 03:10:52 -04:00
rocky
7eba933cfa More excludes 2020-05-24 21:25:07 -04:00
rocky
ad5d3333da A regression regarding "and"/"or" with "continue" 2020-05-19 10:20:08 -04:00
rocky
e046323b31 Some typos 2020-05-19 01:35:50 -04:00
rocky
e80c13170a Administrivia 2020-05-19 01:29:09 -04:00
rocky
889417caeb Get ready for release 3.7.0 2020-05-19 01:17:58 -04:00
rocky
5a83c7c643 Simplify imports again using xdis 4.6.0 2020-05-19 00:53:53 -04:00
rocky
31db2f3e04 Small typo 2020-05-18 23:29:33 -04:00
rocky
7fa851765d Regularize "or" so args are in 1..2 and ...
correct "return None" semantic action
2020-05-18 22:55:26 -04:00
rocky
d7c3b8454b 3.8 needs call_stmt -> call
Simplify/regularize how "return" works
2020-05-18 22:26:18 -04:00
rocky
3fb8d90407 Revise for xdis 3.6.0 ...
Simplify xdis imports where we can.
Blacken (most) of those buffers too
2020-05-18 21:49:16 -04:00
rocky
ff43565981 3.4-3.4 mixed "and"/"or" parsing ...
Fix by limiting more the bogus come from.
2020-05-18 05:33:57 -04:00
rocky
4365022f40 Adapt decompyle3's 3.8 try/return grammar rules 2020-05-17 10:18:10 -04:00
rocky
d343384db7 A runnable "async" and "async with" test 2020-05-16 07:55:51 -04:00
rocky
87a891ca54 Skip 2.6 test until I can get around to it. 2020-05-14 23:50:55 -04:00
rocky
b94c649776 3.7 change rule to match op "or" expr's 2020-05-14 21:32:45 -04:00
R. Bernstein
f34375ba99 Create FUNDING.yml 2020-05-14 12:12:18 -04:00
rocky
81b704f597 Simpify an import, blacken a file. 2020-05-09 09:32:44 -04:00
rocky
5233a0716b Correct wong class names in super() 2020-05-08 05:59:20 -04:00
rocky
a810ed1280 Merge branch 'master' of github.com:rocky/python-uncompyle6 2020-05-05 22:18:22 -04:00
rocky
ab54caae34 Runtest.sh improvements 2020-05-05 22:18:15 -04:00
rocky
d3cf87e2d9 Start marking test suite since this is going to be copied 2020-05-04 11:43:16 -04:00
rocky
c5228dbdc4 Small test doc typo 2020-05-01 23:19:31 -04:00
rocky
a72163f6f9 lint 2020-04-30 18:00:04 -04:00
rocky
3e1300eb23 Bugs in nested async for...
* Generalize asyc_for rule
 Fix bug in picking out comprehension iterator in async for
* fix bug in getting expression in such a comprehension
* Add %[n]{%x} pattern to template_engine()
2020-04-29 10:12:54 -04:00
rocky
a4eaeea5b2 See above. 2020-04-27 23:05:05 -04:00
rocky
1141dfefc2 Typo in appveyor config 2020-04-27 23:03:46 -04:00
rocky
302a5d53d4 Get ready for release 3.6.7 2020-04-27 22:52:39 -04:00
R. Bernstein
698a3073d0 Merge pull request #313 from rocky/task/separate-dis
Task/separate dis
2020-04-24 02:29:52 -04:00
rocky
e6adf822cc Bump xdis version now that this is released 2020-04-24 02:25:07 -04:00
rocky
8c5acef792 Appveyor needs to install xdis from github 2020-04-21 23:03:00 -04:00
rocky
7578253f7d CI from xdis *branch* 2020-04-21 22:49:14 -04:00
rocky
9e193fd7cb Track branch changes in xdis 2020-04-21 22:42:57 -04:00
rocky
ab6b12be56 Small fixes in fragment parser 2020-04-21 19:58:03 -04:00
rocky
5bd97aa756 lint 2020-04-21 13:49:05 -04:00
rocky
5237d704fa Remove stray debug stmt 2020-04-20 23:13:06 -04:00
178 changed files with 3216 additions and 1742 deletions

View File

@@ -1,4 +1,7 @@
version: 2
filters:
branches:
only: master
jobs:
build:
working_directory: ~/rocky/python-uncompyle6
@@ -36,10 +39,11 @@ jobs:
# 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 --user --upgrade setuptools
- run: pip install --user -e .
- run: pip install --user -r requirements-dev.txt
- run:
command: | # Use pip to install dependengcies
pip install --user --upgrade setuptools
pip install --user -e .
pip install --user -r requirements-dev.txt
# Save dependency cache
- save_cache:

28
.editorconfig Normal file
View File

@@ -0,0 +1,28 @@
# THis is an EditorConfig file
# https://EditorConfig.org
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = tab
indent_size = 4
insert_final_newline = true
[*.yml]
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
[*.py]
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
# Tab indentation (no size specified)
[Makefile]
indent_style = tab

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [rocky]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -4,28 +4,40 @@ about: Tell us about uncompyle6 bugs
---
<!-- __Note:__ Have you read https://github.com/rocky/python-uncompyle6/blob/master/HOW-TO-REPORT-A-BUG.md ?
<!-- __Note:__ Bugs are not for asking questions about a problem you
are trying to solve that involve the use of uncompyle6 along the way,
although I may be more tolerent of this if you sponsor the project.
Also, the unless you are a sponsor of the project, it may take a
while, maybe a week or so, before the bug report is noticed, let alone
acted upon.
To set expectations, some legitimate bugs can take years
to fix, but they eventually do get fixed. Funding the project was
added to address the problem that there are lots of people seeking
help and reporting bugs, but few people who are willing or capable of
providing help or fixing bugs.
Finally, have you read https://github.com/rocky/python-uncompyle6/blob/master/HOW-TO-REPORT-A-BUG.md
?
Please remove any of the optional sections if they are not applicable.
Prerequisites
Prerequisites/Caveats
* Make sure the bytecode you have can be disassembled with a
disassembler and produces valid results.
* Don't put bytecode and corresponding source code on any service that
requires registration to download.
* When you open a bug report there is no privacy. If the legitimacy of
the activity is deemed suspicous, I may flag it as suspicious,
* When you open a bug report there is no privacy. If you need privacy, then
contact me by email and explain who you are and the need for privacy.
But be mindful that you may be asked to sponsor the project for the
personal and private help that you are requesting.
* If the legitimacy of the activity is deemed suspicous, I may flag it as suspicious,
making the issue even more easy to detect.
Bug reports that violate a prerequisite may be discarded.
Note that there are way more bug-fix requestors than there are bug
fixers. If you want you need more immediate, confidential or urgent
assistance
http://www.crazy-compilers.com/decompyle/ offers a byte-code
decompiler service for versions of Python up to 2.6.
Bug reports that violate the above may be discarded.
-->

31
.github/workflows/osx.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: uncompyle6 (osx)
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: macos-latest
strategy:
matrix:
os: [macOS]
python-version: [3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# Until the next xdis release
pip install git+git://github.com/rocky/python-xdis.git#egg=xdis
pip install -e .
pip install -r requirements-dev.txt
- name: Test uncompyle6
run: |
make check

30
.github/workflows/ubuntu.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: uncompyle6 (ubuntu)
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# Until the next xdis release
pip install git+git://github.com/rocky/python-xdis.git#egg=xdis
pip install -e .
pip install -r requirements-dev.txt
- name: Test uncompyle6
run: |
make check

31
.github/workflows/windows.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: uncompyle6 (windows)
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: macos-latest
strategy:
matrix:
os: [windows]
python-version: [3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# Until the next xdis release
pip install git+git://github.com/rocky/python-xdis.git#egg=xdis
pip install -e .
pip install -r requirements-dev.txt
- name: Test uncompyle6
run: |
make check

1
.gitignore vendored
View File

@@ -10,6 +10,7 @@
/.pytest_cache
/.python-version
/.tox
.mypy_cache
/.venv*
/README
/__pkginfo__.pyc

View File

@@ -13,6 +13,8 @@ matrix:
dist: xenial # required for Python >= 3.7 (travis-ci/travis-ci#9069)
install:
# Remove the next line when xdis 6.0.0 is released
# - pip install git://github.com/rocky/python-xdis.git#egg=xdis
- pip install -e .
- pip install -r requirements-dev.txt

View File

@@ -20,41 +20,14 @@
This decompiler is a constant work in progress: Python keeps
changing, and so does its code generation.
There is no Python decompiler yet that I know about that will
decompile everything. Overall, I think this one probably does the best
job of *any* Python decompiler that handles such a wide range of
versions.
There is no Python decompiler yet that I know about that will decompile everything. Overall, I think this one probably does the best job of *any* Python decompiler that handles such a wide range of versions.
But at any given time, there are a number of valid Python bytecode
files that I know of that will cause problems. See, for example, the
list in
But at any given time, there are a number of valid Python bytecode files that I know of that will cause problems. See, for example, the list in
[`test/stdlib/runtests.sh`](https://github.com/rocky/python-uncompyle6/blob/master/test/stdlib/runtests.sh).
But I understand: you would the bugs _you_ encounter addressed before
all the other known bugs.
There are far more bug reporters than there are bug fixers.
From my standpoint, the good thing about the bugs listed in
`runtests.sh` is that each test case is small and isolated to a single
kind of problem. And I'll tend to fix easier, more isolated cases than
generic "something's wrong" kinds of bugs where I'd have to do a bit
of work to figure out what's up, if not use some sort of mind reading,
make some guesses, and perform some experiments to see if the guesses
are correct. I can't read minds, nor am I into guessing games; I'd
rather devote the effort spent instead towards fixing bugs that are
precisely defined.
And it often turns out that by just fixing the well-defined and
prescribed cases, the ill-defined amorphous cases as well will get
handled as well.
In sum, you may need to do some work to have the bug you have found
handled before the hundreds of other bugs, and other things I could be
doing.
No one is getting paid to work to work on this project, let alone the
bugs you may have an interest in. If you require decompiling bytecode
immediately, consider using a decompilation service, listed further
down in this document.
Unless you are a sponsor of this project, it may take a while, maybe a week or so, before the bug report is noticed, let alone acted upon. Things eventually get fixed, but it may take years.
# Is it really a bug?
@@ -62,7 +35,7 @@ down in this document.
## Do you have valid bytecode?
As mentioned in README.rst, this project doesn't handle obfuscated
code. See README.rst for suggestions for how to remove some kinds of
code or release candidates. See README.rst for suggestions for how to remove some kinds of
obfuscation.
Checking if bytecode is valid is pretty simple: disassemble the code.
@@ -144,8 +117,7 @@ if False:
Python will eliminate the entire "if" statement.
So just because the text isn't the same, does not
necessarily mean there's a bug.
So just because the text isn't the same, this does not necessarily mean there's a bug.
# What to send (minimum requirements)
@@ -176,30 +148,18 @@ provide the input command and the output from that, please give:
## But I don't *have* the source code!
Sure, I get it. No problem. There is Python assembly code on parse
errors, so simply by hand decompile that. To get a full disassembly,
use `pydisasm` from the [xdis](https://pypi.python.org/pypi/xdis)
package. Opcodes are described in the documentation for
the [dis](https://docs.python.org/3.6/library/dis.html) module.
There is Python assembly code on parse errors, so simply by hand decompile that. To get a full disassembly, use `pydisasm` from the [xdis](https://pypi.python.org/pypi/xdis) package. Opcodes are described in the documentation for the [dis](https://docs.python.org/3.6/library/dis.html) module.
### But I don't *have* the source code and am incapable of figuring how to do a hand disassembly!
Well, you could learn. No one is born into this world knowing how to
disassemble Python bytecode. And as Richard Feynman once said, "What
one fool can learn, so can another."
Well, you could learn. No one is born into this world knowing how to disassemble Python bytecode. And as Richard Feynman once said, "What one fool can learn, so can another."
If this is too difficult, or too time consuming, or not of interest to
you, then perhaps what require is a decompilation service. [Crazy
Compilers](http://www.crazy-compilers.com/decompyle/) offers a
byte-code decompiler service for versions of Python up to 2.6. (If
there are others around let me know and I'll list them here.)
If this is too difficult, or too time consuming, or not of interest to you, then you might consider [sponsoring](https://github.com/sponsors/rocky) the project. [Crazy
Compilers](http://www.crazy-compilers.com/decompyle/) offers a byte-code decompiler service for versions of Python up to 2.6. (If there are others around let me know and I'll list them here.)
# Narrowing the problem
I don't need or want the entire source code base for the file(s) or
module(s) can't be decompiled. I just need those file(s) or module(s).
If there are problems in several files, file a bug report for each
file.
I don't need or want the entire source code base for the file(s) or module(s) can't be decompiled. I just need those file(s) or module(s). If there are problems in several files, file a bug report for each file.
Python modules can get quite large, and usually decompilation problems
occur in a single function or maybe the main-line code but not any of
@@ -217,10 +177,7 @@ likely the problem will be fixed and fixed sooner.
# Karma
I realize that following the instructions given herein puts a bit of
burden on the bug reporter. In my opinion, this is justified as
attempts to balance somewhat the burden and effort needed to fix the
bug and the attempts to balance number of would-be bug reporters with
the number of bug fixers. Better bug reporters are more likely to move
burden on the bug reporter. This is justified as attempts to balance somewhat the burden and effort needed to fix the bug and the attempts to balance number of would-be bug reporters with the number of bug fixers. Better bug reporters are more likely to move
in the category of bug fixers.
The barrier to reporting a big is pretty small: all you really need is
@@ -228,22 +185,14 @@ a github account, and the ability to type something after clicking
some buttons. So the reality is that many people just don't bother to
read these instructions, let alone follow it to any simulacrum.
And the reality is also that bugs sometimes get fixed even though
these instructions are not followed.
That said, bugs sometimes get fixed even though these instructions are not followed.
So one factors I may take into consideration is the bug reporter's karma.
I may take into consideration is the bug reporter's karma.
* Have you demonstrably contributed to open source? I may look at your github profile to see what contributions you have made, how popular those contributions are, or how popular you are.
* How appreciative are you? Have you starred this project that you are seeking help from? Have you starred _any_ github project? And the above two kind of feed into ...
* Attitude. Some people feel that they are doing me and the world a great favor by just pointing out that there is a problem whose solution would greatly benefit them. (This might account partially those that have this attitude often don't read or follow instructions such as those given here.)
* Have you demonstrably contributed to open source? I may look at your
github profile to see what contributions you have made, how popular
those contributions are, or how popular you are.
* How appreciative are you? Have you starred this project that you are
seeking help from? Have you starred _any_ github project? And the above
two kind of feed into ...
* Attitude. Some people feel that they are doing me and the world a
great favor by just pointing out that there is a problem whose solution
would greatly benefit them. Perhaps this is why they feel that
instructions are not to be followed by them, nor any need for
showing evidence gratitude when help is offered them.
# Confidentiality of Bug Reports
@@ -255,6 +204,8 @@ remains would not be an issue.
However feel free to remove any comments, and modify variable names
or constants in the source code.
If there is some legitimate reason to keep confidentiality, you can contact me by email to explain the extenuating circumstances. However I tend to discard without reading anonymous email.
# Ethics
I do not condone using this program for unethical or illegal purposes.

66
NEWS.md
View File

@@ -1,3 +1,69 @@
3.8.0: 2020-10-29
=================
* Better handling of invalid bytecode magic
* Support running from 3.9 and 3.10 although we do not support those bytecodes
* Redo version comparisons using tuples instead of floats. This is needed for Python 3.10
* Split out into 3 branches so that the master branch can assume Python 3.6+ conventions, especially type annotations
* Source Fragment fixes
* Lambda-bug fixes #360
* Bug fixes
3.7.4: 2020-8-05
================
* Fragment parsing was borked. This means deparsing in trepan2/trepan3k was broken
* 3.7+: narrow precedence for call tatement
* del_stmt -> delete to better match Python AST
* 3.8+ Add another `forelsestmt` (found only in a loop)
* 3.8+ Add precedence on walrus operator
* More files blackened
* bump min xdis version
3.7.3: 2020-7-25
================
Mostly small miscellaneous bug fixes
* `__doc__ = DocDescr()` from `test_descr.py` was getting confused as a docstring.
* detect 2.7 exchandler range better
* Add for .. else reduction checks on 2.6 and before
* Add reduce check for 2.7 augmented assign
* Add VERSION in a pydoc-friendly way
3.7.2: 2020-6-27
================
* Use newer xdis
* Docstrings (again) which were broken again on earlier Python
* Fix 2.6 and 2.7 decompilation bug in handling "list if" comprehensions
3.7.1: 2020-6-12 Fleetwood66
====================================================
Released to pick up new xdis version which has fixes to read bytestings better on 3.x
* Handle 3.7+ "else" branch removal adAs seen in `_cmp()` of `python3.8/distutils/version.py` with optimization `-O2`
* 3.6+ "with" and "with .. as" grammar improvements
* ast-check for "for" loop was missing some grammar rules
3.7.0: 2020-5-19 Primidi 1st Prairial - Alfalfa - HF
====================================================
The main impetus for this release is to pull in the recent changes from xdis.
We simplify imports using xdis 4.6.0.
There were some bugfixes to Python 3.4-3.8. See the ChangeLog for details
3.6.7: 2020-4-27 xdis again
===========================
More upheaval in xdis which we need to track here.
3.6.6: 2020-4-20 Love in the time of Cholera
============================================

View File

@@ -68,10 +68,9 @@ are syntactically correct by running the Python interpreter for that
bytecode version. Finally, in cases where the program has a test for
itself, we can run the check on the decompiled code.
We are serious about testing, and use automated processes to find
bugs. In the issue trackers for other decompilers, you will find a
number of bugs we've found along the way. Very few to none of them are
fixed in the other decompilers.
We use an automated processes to find bugs. In the issue trackers for
other decompilers, you will find a number of bugs we've found along
the way. Very few to none of them are fixed in the other decompilers.
Requirements
------------
@@ -172,15 +171,11 @@ 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.
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
decompiler from that era has been preserved (and Python compilation in
that era was minimal)
Python support is pretty good for Python 2
There is some work to do on the lower end Python versions which is
more difficult for us to handle since we don't have a Python
interpreter for versions 1.6, and 2.0.
On the lower end of Python versions, decompilation seems pretty good although
we don't have any automated testing in place for Python's distributed tests.
Also, we don't have a Python interpreter for versions 1.6, and 2.0.
In the Python 3 series, Python support is is strongest around 3.4 or
3.3 and drops off as you move further away from those versions. Python
@@ -195,7 +190,7 @@ added. So in sum handling control flow by ad hoc means as is currently
done is worse.
Between Python 3.5, 3.6, 3.7 there have been major changes to the
:code:`MAKE_FUNCTION` and :code:`CALL_FUNCTION` instructions. Python
:code:`MAKE_FUNCTION` and :code:`CALL_FUNCTION` instructions.
Python 3.8 removes :code:`SETUP_LOOP`, :code:`SETUP_EXCEPT`,
:code:`BREAK_LOOP`, and :code:`CONTINUE_LOOP`, instructions which may
@@ -211,26 +206,52 @@ 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
which use their own magic and encrypt bytecode. With the exception of
the Dropbox's old Python 2.5 interpreter this kind of thing is not
handled.
We also don't handle PJOrion_ obfuscated code. For that try: PJOrion
Deobfuscator_ to unscramble the bytecode to get valid bytecode before
trying this tool. This program can't decompile Microsoft Windows EXE
files created by Py2EXE_, although we can probably decompile the code
after you extract the bytecode properly. For situations like this, you
might want to consider a decompilation service like `Crazy Compilers
<http://www.crazy-compilers.com/decompyle/>`_. Handling
pathologically long lists of expressions or statements is slow.
We also don't handle PJOrion_ or otherwise obfuscated code. For
PJOrion try: PJOrion Deobfuscator_ to unscramble the bytecode to get
valid bytecode before trying this tool. This program can't decompile
Microsoft Windows EXE files created by Py2EXE_, although we can
probably decompile the code after you extract the bytecode
properly. Handling pathologically long lists of expressions or
statements is slow. We don't handle Cython_ or MicroPython which don't
use bytecode.
There are numerous bugs in decompilation. And that's true for every
other CPython decompiler I have encountered, even the ones that
claimed to be "perfect" on some particular version like 2.4.
There is lots to do, so please dig in and help.
As Python progresses decompilation also gets harder because the
compilation is more sophisticated and the language itself is more
sophisticated. I suspect that attempts there will be fewer ad-hoc
attempts like unpyc37_ (which is based on a 3.3 decompiler) simply
because it is harder to do so. The good news, at least from my
standpoint, is that I think I understand what's needed to address the
problems in a more robust way. But right now until such time as
project is better funded, I do not intend to make any serious effort
to support Python versions 3.8 or 3.9, including bugs that might come
in. I imagine at some point I may be interested in it.
You can easily find bugs by running the tests against the standard
test suite that Python uses to check itself. At any given time, there are
dozens of known problems that are pretty well isolated and that could
be solved if one were to put in the time to do so. The problem is that
there aren't that many people who have been working on bug fixing.
Some of the bugs in 3.7 and 3.8 are simply a matter of back-porting
the fixes in decompyle3.
You may run across a bug, that you want to report. Please do so. But
be aware that it might not get my attention for a while. If you
sponsor or support the project in some way, I'll prioritize your
issues above the queue of other things I might be doing instead.
See Also
--------
* https://github.com/rocky/python-decompile3 : Much smaller and more modern code, focusing on 3.7+. Changes in that will get migrated back ehre.
* https://github.com/rocky/python-decompile3 : Much smaller and more modern code, focusing on 3.7+. Changes in that will get migrated back here.
* https://code.google.com/archive/p/unpyc3/ : supports Python 3.2 only. The above projects use a different decompiling technique than what is used here. 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 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
@@ -242,6 +263,7 @@ See Also
* https://github.com/zrax/pycdc : The README for this C++ code says it aims to support all versions of Python. It is best for Python versions around 2.7 and 3.3 when the code was initially developed. Accuracy for current versions of Python3 and early versions of Python is lacking. Without major effort, it is unlikely it can be made to support current Python 3. See its `issue tracker <https://github.com/zrax/pycdc/issues>`_ for details. Currently lightly maintained.
.. _Cython: https://en.wikipedia.org/wiki/Cython
.. _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

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2018, 2020 Rocky Bernstein <rocky@gnu.org>
# Copyright (C) 2018, 2020-2021 Rocky Bernstein <rocky@gnu.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -21,66 +21,88 @@
# less elegant than having it here with reduced code, albeit there
# still is some room for improvement.
# Python-version | package | last-version |
# -----------------------------------------
# 2.5 | pip | 1.1 |
# 2.6 | pip | 1.5.6 |
# 2.7 | pip | 19.2.3 |
# 2.7 | pip | 1.2.1 |
# 3.1 | pip | 1.5.6 |
# 3.2 | pip | 7.1.2 |
# 3.3 | pip | 10.0.1 |
# 3.4 | pip | 19.1.1 |
# Things that change more often go here.
copyright = """
Copyright (C) 2015-2020 Rocky Bernstein <rb@dustyfeet.com>.
copyright = """
Copyright (C) 2015-2021 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",
"Programming Language :: Python :: 2.4",
"Programming Language :: Python :: 2.5",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"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",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: Implementation :: PyPy",
"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 = {
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",
]}
ftp_url = None
install_requires = ["spark-parser >= 1.8.9, < 1.9.0",
"xdis >= 4.4.0, < 4.5.0"]
]
}
ftp_url = None
install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 6.0.2, < 6.1.0"]
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/"
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/"
# tracebacks in zip files are funky and not debuggable
zip_safe = True
import os.path
def get_srcdir():
filename = os.path.normcase(os.path.dirname(os.path.abspath(__file__)))
return os.path.realpath(filename)
srcdir = get_srcdir()
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" )
# Get info from files; set: long_description and __version__
long_description = read("README.rst") + "\n"
exec(read("uncompyle6/version.py"))

View File

@@ -6,7 +6,7 @@ owd=$(pwd)
trap finish EXIT
cd $(dirname ${BASH_SOURCE[0]})
if ! source ./pyenv-older-versions ; then
if ! source ./pyenv-2.4-2.7-versions ; then
exit $?
fi
if ! source ./setup-python-2.4.sh ; then

View File

@@ -8,7 +8,7 @@ owd=$(pwd)
trap finish EXIT
cd $(dirname ${BASH_SOURCE[0]})
if ! source ./pyenv-newer-versions ; then
if ! source ./pyenv-newest-versions ; then
exit $?
fi
if ! source ./setup-master.sh ; then

View File

@@ -2,17 +2,17 @@
**Table of Contents**
- [Get latest sources:](#get-latest-sources)
- [Change version in uncompyle6/version.py](#change-version-in-uncompyle6versionpy)
- [Change version in uncompyle6/version.py:](#change-version-in-uncompyle6versionpy)
- [Update ChangeLog:](#update-changelog)
- [Update NEWS from ChangeLog:](#update-news-from-changelog)
- [Update NEWS.md from ChangeLog:](#update-newsmd-from-changelog)
- [Make sure pyenv is running and check newer versions](#make-sure-pyenv-is-running-and-check-newer-versions)
- [Switch to python-2.4, sync that up and build that first since it creates a tarball which we don't want.](#switch-to-python-24-sync-that-up-and-build-that-first-since-it-creates-a-tarball-which-we-dont-want)
- [Update NEWS from master branch](#update-news-from-master-branch)
- [Check against all versions](#check-against-all-versions)
- [Check against older versions](#check-against-older-versions)
- [Make packages and tag](#make-packages-and-tag)
- [Upload single package and look at Rst Formating](#upload-single-package-and-look-at-rst-formating)
- [Upload rest of versions](#upload-rest-of-versions)
- [Push tags:](#push-tags)
- [Check package on github](#check-package-on-github)
- [Release on Github](#release-on-github)
- [Get onto PyPI](#get-onto-pypi)
- [Update tags:](#update-tags)
<!-- markdown-toc end -->
# Get latest sources:
@@ -39,7 +39,7 @@
# Make sure pyenv is running and check newer versions
$ pyenv local && source admin-tools/check-newer-versions.sh
$ admin-tools/check-newer-versions.sh
# Switch to python-2.4, sync that up and build that first since it creates a tarball which we don't want.
@@ -50,39 +50,51 @@
# Check against older versions
$ source admin-tools/check-older-versions.sh
$ admin-tools/check-older-versions.sh
# Make packages and tag
$ . ./admin-tools/make-dist-older.sh
$ pyenv local 3.8.2
$ pyenv local 3.8.5
$ twine check dist/uncompyle6-$VERSION*
$ git tag release-python-2.4-$VERSION
$ twine check dist/uncompyle6-$VERSION*
$ . ./admin-tools/make-dist-newer.sh
$ ./admin-tools/make-dist-newer.sh
$ twine check dist/uncompyle6-$VERSION*
# Upload single package and look at Rst Formating
# Check package on github
$ twine check dist/uncompyle6-${VERSION}*
$ twine upload dist/uncompyle6-${VERSION}-py3.3.egg
$ [[ ! -d /tmp/gittest ]] && mkdir /tmp/gittest; pushd /tmp/gittest
$ pyenv local 3.8.3
$ pip install -e git://github.com/rocky/python-uncompyle6.git#egg=uncompyle6
$ uncompyle6 --help
$ pip uninstall uncompyle6
$ popd
# Upload rest of versions
$ twine upload dist/uncompyle6-${VERSION}*
# Release on Github
Goto https://github.com/rocky/python-uncompyle6/releases
# Push tags:
Now check the *tagged* release. (Checking the untagged release was previously done).
Todo: turn this into a script in `admin-tools`
$ pushd /tmp/gittest
$ pip install -e git://github.com/rocky/python-uncompyle6.git@$VERSION#egg=uncompyle6
$ uncompyle6 --help
$ pip uninstall uncompyle6
$ popd
# Get onto PyPI
$ twine upload dist/uncompyle6-${VERSION}*
# Update tags:
$ git push --tags
$ git pull --tags
# Check on a VM
# Move dist files to uploaded
$ cd /virtual/vagrant/virtual/vagrant/ubuntu-zesty
$ vagrant up
$ vagrant ssh
$ pyenv local 3.5.2
$ pip install --upgrade uncompyle6
$ exit
$ vagrant halt
$ mv -v dist/uncompyle6-${VERSION}* dist/uploaded

View File

@@ -9,7 +9,7 @@ owd=$(pwd)
trap finish EXIT
cd $(dirname ${BASH_SOURCE[0]})
if ! source ./pyenv-older-versions ; then
if ! source ./pyenv-2.4-2.7-versions ; then
exit $?
fi
if ! source ./setup-python-2.4.sh ; then
@@ -18,7 +18,7 @@ fi
cd ..
source $PACKAGE/version.py
echo $VERSION
echo $__version__
for pyversion in $PYVERSIONS; do
if ! pyenv local $pyversion ; then
@@ -29,11 +29,15 @@ for pyversion in $PYVERSIONS; do
python setup.py bdist_egg
done
pyenv local 2.7.18
python setup.py bdist_wheel
mv -v dist/${PACKAGE}-$__version__-py2{.py3,}-none-any.whl
# Pypi can only have one source tarball.
# Tarballs can get created from the above setup, so make sure to remove them since we want
# the tarball from master.
tarball=dist/${PACKAGE}-$VERSION-tar.gz
tarball=dist/${PACKAGE}-${__version_}_-tar.gz
if [[ -f $tarball ]]; then
rm -v dist/${PACKAGE}-$VERSION-tar.gz
rm -v dist/${PACKAGE}-${__version__}-tar.gz
fi

View File

@@ -0,0 +1,38 @@
#!/bin/bash
PACKAGE=uncompyle6
# FIXME put some of the below in a common routine
function finish {
cd $owd
}
cd $(dirname ${BASH_SOURCE[0]})
owd=$(pwd)
trap finish EXIT
if ! source ./pyenv-3.3-3.5-versions ; then
exit $?
fi
if ! source ./setup-python-3.3.sh ; then
exit $?
fi
cd ..
source $PACKAGE/version.py
echo $__version__
for pyversion in $PYVERSIONS; do
if ! pyenv local $pyversion ; then
exit $?
fi
# pip bdist_egg create too-general wheels. So
# we narrow that by moving the generated wheel.
# Pick out first two number of version, e.g. 3.5.1 -> 35
first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//')
rm -fr build
python setup.py bdist_egg bdist_wheel
mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl
done
python ./setup.py sdist

View File

@@ -10,7 +10,7 @@ cd $(dirname ${BASH_SOURCE[0]})
owd=$(pwd)
trap finish EXIT
if ! source ./pyenv-newer-versions ; then
if ! source ./pyenv-newest-versions ; then
exit $?
fi
if ! source ./setup-master.sh ; then
@@ -19,7 +19,7 @@ fi
cd ..
source $PACKAGE/version.py
echo $VERSION
echo $__version__
for pyversion in $PYVERSIONS; do
if ! pyenv local $pyversion ; then
@@ -32,7 +32,7 @@ for pyversion in $PYVERSIONS; do
first_two=$(echo $pyversion | cut -d'.' -f 1-2 | sed -e 's/\.//')
rm -fr build
python setup.py bdist_egg bdist_wheel
mv -v dist/${PACKAGE}-$VERSION-{py2.py3,py$first_two}-none-any.whl
mv -v dist/${PACKAGE}-$__version__-{py2.py3,py$first_two}-none-any.whl
done
python ./setup.py sdist

View File

@@ -0,0 +1,9 @@
# -*- shell-script -*-
# Sets PYVERSIONS to be pyenv versions that
# we can use in the python-2.4-to-2.7 branch.
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 2.6.9 2.7.18'

View File

@@ -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 2.6.9'
export PYVERSIONS='3.1.5 3.2.6'

View File

@@ -0,0 +1,8 @@
# -*- shell-script -*-
# Sets PYVERSIONS to be pyenv versions that
# we can use in the python-3.3-to-3.5 branch.
if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
echo "This script should be *sourced* rather than run directly through bash"
exit 1
fi
export PYVERSIONS='3.5.10 3.3.7 3.4.10'

View File

@@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
echo "This script should be *sourced* rather than run directly through bash"
exit 1
fi
export PYVERSIONS='3.5.9 3.6.10 2.6.9 3.3.7 2.7.17 3.2.6 3.1.5 3.4.10 3.7.7 3.8.2'
export PYVERSIONS='3.6.15 3.7.12 pyston-2.3 3.8.11 3.9.7 3.10.0'

View File

@@ -0,0 +1,8 @@
# -*- shell-script -*-
# Sets PYVERSIONS to be pyenv versions that
# we can use in the master branch.
if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
echo "This script should be *sourced* rather than run directly through bash"
exit 1
fi
export PYVERSIONS='3.7.11 3.8.12 3.9.7 3.10.0'

View File

@@ -1,5 +1,5 @@
#!/bin/bash
PYTHON_VERSION=3.7.7
PYTHON_VERSION=3.7.12
# FIXME put some of the below in a common routine
function finish {
@@ -20,4 +20,4 @@ cd $fulldir/..
(cd ../python-xdis && git checkout master && pyenv local $PYTHON_VERSION) && git pull && \
git checkout master && pyenv local $PYTHON_VERSION && git pull
cd $owd
rm -v */.python-version || true
rm -v */.python-version >/dev/null 2>&1 || true

View File

@@ -11,7 +11,8 @@ mydir=$(dirname $bs)
fulldir=$(readlink -f $mydir)
cd $fulldir/..
(cd ../python-spark && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \
(cd ../python-xdis && git checkout python-2.4 && pyenv local $PYTHON_VERSION) && git pull && \
(cd ../python-xdis && . ./admin-tools/setup-python-2.4.sh) && \
git checkout python-2.4 && pyenv local $PYTHON_VERSION && git pull
cd $owd
rm -v */.python-version || true
pyenv local $PYTHON_VERSION

15
admin-tools/setup-python-3.3.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
PYTHON_VERSION=3.3.7
pyenv local $PYTHON_VERSION
owd=$(pwd)
bs=${BASH_SOURCE[0]}
mydir=$(dirname $bs)
fulldir=$(readlink -f $mydir)
cd $fulldir/..
(cd ../python-xdis && ./admin-tools/setup-python-3.3.sh)
cd $owd
rm -v */.python-version || true
git checkout python-3.3-to-3.5 && git pull && pyenv local $PYTHON_VERSION

View File

@@ -1,78 +0,0 @@
environment:
global:
# SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the
# /E:ON and /V:ON options are not enabled in the batch script intepreter
# See: http://stackoverflow.com/a/13751649/163740
CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_env.cmd"
matrix:
# Pre-installed Python versions, which Appveyor may upgrade to
# a later point release.
# See: http://www.appveyor.com/docs/installed-software#python
# - PYTHON: "C:\\Python27"
# PYTHON_VERSION: "2.7.x"
# PYTHON_ARCH: "32"
- PYTHON: "C:\\Python27-x64"
PYTHON_VERSION: "2.7.x"
PYTHON_ARCH: "64"
# - PYTHON: "C:\\Python26"
# PYTHON_VERSION: "2.6.x"
# PYTHON_ARCH: "32"
# - PYTHON: "C:\\Python26-x64"
# PYTHON_VERSION: "2.6.x"
# PYTHON_ARCH: "64"
install:
# We need wheel installed to build wheels
- "%PYTHON%\\python.exe -m pip install wheel"
# Install Python (from the official .msi of http://python.org) and pip when
# not already installed.
- ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 }
# Prepend newly installed Python to the PATH of this build (this cannot be
# done from inside the powershell script as it would require to restart
# the parent CMD process).
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
- "SET HOME=."
# Check that we have the expected version and architecture for Python
- "python --version"
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
# Upgrade to the latest version of pip to avoid it displaying warnings
# about it being out of date.
- "%PYTHON%\\python.exe -m pip install --disable-pip-version-check --user --upgrade pip"
# Install the build dependencies of the project. If some dependencies contain
# compiled extensions and are not provided as pre-built wheel packages,
# pip will build them from source using the MSVC compiler matching the
# target Python version and architecture
- "%CMD_IN_ENV% pip install -r requirements.txt"
build_script:
# Build the compiled extension
- "%CMD_IN_ENV% python setup.py build"
test_script:
# Run the project tests
- "%CMD_IN_ENV% python test/test_pyenvlib.py --native --syntax-verify"
after_test:
# If tests are successful, create binary packages for the project.
- "%CMD_IN_ENV% python setup.py bdist_wininst"
- "%CMD_IN_ENV% python setup.py bdist_msi"
- ps: "ls dist"
artifacts:
# Archive the generated packages in the ci.appveyor.com build report.
- path: dist\*
#on_success:
# - TODO: upload the content of dist/*.whl to a public wheelhouse
#

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python
from uncompyle6 import PYTHON_VERSION, IS_PYPY
from xdis.version_info import PYTHON_VERSION_TRIPLE, IS_PYPY, version_tuple_to_str
from uncompyle6.scanner import get_scanner
def bug(state, slotstate):
if state:
@@ -21,8 +21,8 @@ def bug_loop(disassemble, tb=None):
def test_if_in_for():
code = bug.__code__
scan = get_scanner(PYTHON_VERSION)
if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY:
scan = get_scanner(PYTHON_VERSION_TRIPLE)
if (2, 7) <= PYTHON_VERSION_TRIPLE < (3, 1) and not IS_PYPY:
scan.build_instructions(code)
fjt = scan.find_jump_targets(False)
@@ -51,7 +51,7 @@ def test_if_in_for():
# previous bug was not mistaking while-loop for if-then
{'start': 48, 'end': 67, 'type': 'while-loop'}]
elif 3.2 < PYTHON_VERSION <= 3.4:
elif (3, 2) < PYTHON_VERSION_TRIPLE <= (3, 4):
scan.build_instructions(code)
fjt = scan.find_jump_targets(False)
assert {69: [66], 63: [18]} == fjt
@@ -62,6 +62,6 @@ def test_if_in_for():
{'end': 59, 'type': 'for-loop', 'start': 31},
{'end': 63, 'type': 'for-else', 'start': 62}]
else:
print("FIXME: should fix for %s" % PYTHON_VERSION)
print("FIXME: should fix for %s" % version_tuple_to_str())
assert True
return

View File

@@ -1,7 +1,7 @@
import re
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY # , PYTHON_VERSION
from uncompyle6.parser import get_python_parser, python_parser
from uncompyle6.scanner import get_scanner
from xdis.version_info import PYTHON_VERSION_TRIPLE, PYTHON3, IS_PYPY
def test_grammar():
@@ -16,19 +16,19 @@ def test_grammar():
p.dump_grammar(),
)
p = get_python_parser(PYTHON_VERSION, is_pypy=IS_PYPY)
p = get_python_parser(PYTHON_VERSION_TRIPLE, is_pypy=IS_PYPY)
(lhs, rhs, tokens, right_recursive, dup_rhs) = p.check_sets()
# We have custom rules that create the below
expect_lhs = set(["pos_arg"])
if PYTHON_VERSION < 3.8:
if PYTHON_VERSION < 3.7:
if PYTHON_VERSION_TRIPLE < (3, 8):
if PYTHON_VERSION_TRIPLE < (3, 7):
expect_lhs.add("attribute")
expect_lhs.add("get_iter")
if PYTHON_VERSION > 3.7 or PYTHON_VERSION < 3.0:
if PYTHON_VERSION_TRIPLE >= (3, 8) or PYTHON_VERSION_TRIPLE < (3, 0):
expect_lhs.add("stmts_opt")
else:
expect_lhs.add("async_with_as_stmt")
@@ -38,15 +38,15 @@ def test_grammar():
expect_right_recursive = set([("designList", ("store", "DUP_TOP", "designList"))])
if PYTHON_VERSION <= 3.6:
if PYTHON_VERSION_TRIPLE[:2] <= (3, 6):
unused_rhs.add("call")
if PYTHON_VERSION > 2.6:
if PYTHON_VERSION_TRIPLE >= (2, 7):
expect_lhs.add("kvlist")
expect_lhs.add("kv3")
unused_rhs.add("dict")
if PYTHON_VERSION < 3.7 and PYTHON_VERSION != 2.7:
if PYTHON_VERSION_TRIPLE < (3, 7) and PYTHON_VERSION_TRIPLE[:2] != (2, 7):
# NOTE: this may disappear
expect_lhs.add("except_handler_else")
@@ -60,8 +60,8 @@ def test_grammar():
""".split()
)
)
if PYTHON_VERSION >= 3.0:
if PYTHON_VERSION < 3.7:
if PYTHON_VERSION_TRIPLE >= (3, 0):
if PYTHON_VERSION_TRIPLE < (3, 7):
expect_lhs.add("annotate_arg")
expect_lhs.add("annotate_tuple")
unused_rhs.add("mkfunc_annotate")
@@ -69,7 +69,7 @@ def test_grammar():
unused_rhs.add("dict_comp")
unused_rhs.add("classdefdeco1")
unused_rhs.add("tryelsestmtl")
if PYTHON_VERSION >= 3.5:
if PYTHON_VERSION_TRIPLE >= (3, 5):
expect_right_recursive.add(
(("l_stmts", ("lastl_stmt", "come_froms", "l_stmts")))
)
@@ -80,7 +80,7 @@ def test_grammar():
expect_lhs.add("kwarg")
# FIXME
if PYTHON_VERSION < 3.8:
if PYTHON_VERSION_TRIPLE < (3, 8):
assert expect_lhs == set(lhs)
assert unused_rhs == set(rhs)
@@ -103,7 +103,7 @@ def test_grammar():
print(k, reduced_dup_rhs[k])
# assert not reduced_dup_rhs, reduced_dup_rhs
s = get_scanner(PYTHON_VERSION, IS_PYPY)
s = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY)
ignore_set = set(
"""
JUMP_BACK CONTINUE
@@ -116,12 +116,13 @@ def test_grammar():
RETURN_END_IF RETURN_END_IF_LAMBDA RETURN_VALUE_LAMBDA RETURN_LAST
""".split()
)
if 2.6 <= PYTHON_VERSION <= 2.7:
if (2, 6) <= PYTHON_VERSION_TRIPLE <= (2, 7):
opcode_set = set(s.opc.opname).union(ignore_set)
if PYTHON_VERSION == 2.6:
if PYTHON_VERSION_TRIPLE[:2] == (2, 6):
opcode_set.add("THEN")
check_tokens(tokens, opcode_set)
elif PYTHON_VERSION == 3.4:
elif PYTHON_VERSION_TRIPLE[:2] == (3, 4):
ignore_set.add("LOAD_CLASSNAME")
ignore_set.add("STORE_LOCALS")
opcode_set = set(s.opc.opname).union(ignore_set)
@@ -132,7 +133,7 @@ def test_dup_rule():
import inspect
python_parser(
PYTHON_VERSION,
PYTHON_VERSION_TRIPLE,
inspect.currentframe().f_code,
is_pypy=IS_PYPY,
parser_debug={

View File

@@ -9,13 +9,13 @@ import tempfile
import functools
# uncompyle6 / xdis
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY, code_deparse
from uncompyle6 import code_deparse
from xdis.version_info import PYTHON_VERSION_TRIPLE, PYTHON3, IS_PYPY
# 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
from xdis import Bytecode, get_opcode
opc = get_opcode(PYTHON_VERSION, IS_PYPY)
opc = get_opcode(PYTHON_VERSION_TRIPLE, IS_PYPY)
Bytecode = functools.partial(Bytecode, opc=opc)
import six
@@ -128,7 +128,7 @@ def validate_uncompyle(text, mode="exec"):
original_text = text
deparsed = code_deparse(
original_code, out=six.StringIO(), version=PYTHON_VERSION, compile_mode=mode
original_code, out=six.StringIO(), version=PYTHON_VERSION_TRIPLE, compile_mode=mode
)
uncompyled_text = deparsed.text
uncompyled_code = compile(uncompyled_text, "<string>", "exec")

View File

@@ -1,11 +1,57 @@
[bdist_rpm]
release = 1
packager = rocky <rb@dustyfeet.com>
doc_files = README
release = 0
packager = rocky <rb@dustyfeet.com
doc_files = README.rst
ChangeLog
COPYING
DECOMPYLE-2.4-CHANGELOG.txt
HISTORY.md
HOW-TO_REPORT-A-BUG.md
NEWS.md
# doc/
# examples/
[bdist_wheel]
universal=1
[egg_info]
tag_build =
tag_date = 0
[metadata]
description_file = README.rst
[flake8]
# max-line-length setting: NO we do not want everyone writing 120-character lines!
# We are setting the maximum line length big here because there are longer
# lines allowed by black in some cases that are forbidden by flake8. Since
# black has the final say about code formatting issues, this setting is here to
# make sure that flake8 doesn't fail the build on longer lines allowed by
# black.
max-line-length = 120
max-complexity = 12
select = E,F,W,C,B,B9
ignore =
# E123 closing bracket does not match indentation of opening bracket's line
E123
# E203 whitespace before ':' (Not PEP8 compliant, Python Black)
E203
# E501 line too long (82 > 79 characters) (replaced by B950 from flake8-bugbear,
# https://github.com/PyCQA/flake8-bugbear)
E501
# W503 line break before binary operator (Not PEP8 compliant, Python Black)
W503
# W504 line break after binary operator (Not PEP8 compliant, Python Black)
W504
# C901 function too complex - since many of zz9 functions are too complex with a lot
# of if branching
C901
# module level import not at top of file. This is too restrictive. Can't even have a
# docstring higher.
E402
per-file-ignores =
# These are config files. The `c` variable them is injected not defined.
pow/ansible/roles/jupyterhub/templates/jupyterhub_config*.py:F821
# Ignore some errors in files that are stolen from other projects to avoid lots
# of merge problems later .
pow/ansible/roles/webtier/files/supervisor_httpgroupok.py:E126,E128,E222,E225,E226,E261,E301,E302,E305,F841,E201,E202
silhouette/src/silhouette/gprof2dot.py:E711,E713,E741,F401
# Ignore undefined name errors in "expectation" test Python code.
# These files get exec'd in an environment that defines the variables.
server/tests/files/expectations/*.py:F821

View File

@@ -4,40 +4,59 @@ import sys
"""Setup script for the 'uncompyle6' distribution."""
SYS_VERSION = sys.version_info[0:2]
if not ((2, 6) <= SYS_VERSION <= (3, 9)):
mess = "Python Release 2.6 .. 3.9 are supported in this code branch."
if ((2, 4) <= SYS_VERSION <= (2, 7)):
mess += ("\nFor your Python, version %s, use the python-2.4 code/branch." %
sys.version[0:3])
if not ((2, 4) <= SYS_VERSION < (3, 11)):
mess = "Python Release 2.6 .. 3.10 are supported in this code branch."
if (2, 4) <= SYS_VERSION <= (2, 7):
mess += (
"\nFor your Python, version %s, use the python-2.4 code/branch."
% sys.version[0:3]
)
if (3, 3) <= SYS_VERSION < (3, 6):
mess += (
"\nFor your Python, version %s, use the python-3.3-to-3.5 code/branch."
% sys.version[0:3]
)
elif SYS_VERSION < (2, 4):
mess += ("\nThis package is not supported for Python version %s."
% sys.version[0:3])
mess += (
"\nThis package is not supported for Python version %s." % sys.version[0:3]
)
print(mess)
raise Exception(mess)
from __pkginfo__ import \
author, author_email, install_requires, \
license, long_description, classifiers, \
entry_points, modname, py_modules, \
short_desc, VERSION, web, \
zip_safe
from __pkginfo__ import (
author,
author_email,
install_requires,
license,
long_description,
classifiers,
entry_points,
modname,
py_modules,
short_desc,
__version__,
web,
zip_safe,
)
from setuptools import setup, find_packages
setup(
author = author,
author_email = author_email,
classifiers = classifiers,
description = short_desc,
entry_points = entry_points,
install_requires = install_requires,
license = license,
long_description = long_description,
long_description_content_type = "text/x-rst",
name = modname,
packages = find_packages(),
py_modules = py_modules,
test_suite = 'nose.collector',
url = web,
tests_require = ['nose>=1.0'],
version = VERSION,
zip_safe = zip_safe)
author=author,
author_email=author_email,
classifiers=classifiers,
description=short_desc,
entry_points=entry_points,
install_requires=install_requires,
license=license,
long_description=long_description,
long_description_content_type="text/x-rst",
name=modname,
packages=find_packages(),
py_modules=py_modules,
test_suite="nose.collector",
url=web,
tests_require=["nose>=1.0"],
version=__version__,
zip_safe=zip_safe,
)

5
test/.gitignore vendored
View File

@@ -1,3 +1,8 @@
/.coverage
/.python-version
/nohup.out
/pycdc
/test_pycdc_tests.sh
/test_uncompyle2.py
/test_unpy33.py
/test_unpy37.py

View File

@@ -13,7 +13,7 @@ PHONY=check clean dist distclean test test-unit test-functional rmChangeLog clea
GIT2CL ?= git2cl
PYTHON ?= python
PYTHON_VERSION = $(shell $(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2)
PYTHON_VERSION = $(shell $(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2 | head -1)
NATIVE_CHECK = check-$(PYTHON_VERSION)
# Set COMPILE='--compile' to force compilation before check
@@ -22,8 +22,8 @@ COVER_DIR=../tmp/grammar-cover
# Run short tests
check-short:
@$(PYTHON) -V && PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2`; \
$(MAKE) check-bytecode-$${PYTHON_VERSION}
@$(PYTHON) -V && PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2` | head -1; \
$(MAKE) check-bytecode-${PYTHON_VERSION}
# Run all tests
check:
@@ -77,6 +77,12 @@ check-3.8: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.8-run --verify-run
$(PYTHON) test_pythonlib.py --bytecode-3.8 --syntax-verify $(COMPILE)
check-3.9: check-bytecode
@echo "Note that we do not support decompiling Python 3.9 bytecode - no 3.9 tests run"
check-3.10: check-bytecode
@echo "Note that we do not support decompiling Python 3.10 bytecode - no 3.10 tests run"
# FIXME
#: this is called when running under pypy3.5-5.8.0, pypy2-5.6.0, or pypy3.6-7.3.0
5.8 5.6:

View File

@@ -3,14 +3,22 @@
"""
import os, sys, py_compile
assert len(sys.argv) >= 2
assert (2 <= len(sys.argv) <= 4)
version = sys.version[0:3]
vers = sys.version_info[:2]
if sys.argv[1] in ("--run", "-r"):
suffix = "_run"
py_source = sys.argv[2:]
i = 2
else:
suffix = ""
py_source = sys.argv[1:]
i = 1
try:
optimize = int(sys.argv[-1])
py_source = sys.argv[i:-1]
except:
optimize = 2
for path in py_source:
short = os.path.basename(path)
@@ -19,6 +27,10 @@ for path in py_source:
else:
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):
optimize = optimize
if vers > (3, 1):
py_compile.compile(path, cfile, optimize=optimize)
else:
py_compile.compile(path, cfile)
if vers >= (2, 6):
os.system("../bin/uncompyle6 -a -T %s" % cfile)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -51,7 +51,7 @@ for VERSION in $PYVERSIONS ; do
LOGFILE=/tmp/${MAIN}-$VERSION-$$.log
case "$VERSION" in
3.7.7 | 3.8.2 | 3.1.5 | 3.0.1 )
3.7.8 | 3.8.5 | 3.1.5 | 3.0.1 )
continue
;;
3.5.9 )
@@ -66,7 +66,7 @@ for VERSION in $PYVERSIONS ; do
3.4.10 )
MAX_TESTS=800
;;
3.6.10 )
3.6.11 )
# MAX_TESTS=1300 # about 2139 exist
# fails on _pyio.cpython-36.opt-1.pyc
MAX_TESTS=34

View File

@@ -3,7 +3,7 @@
from __future__ import print_function
from uncompyle6.main import decompile
from xdis.magics import sysinfo2float
from xdis import sysinfo2float
import sys, inspect
def uncompyle_test():

View File

@@ -0,0 +1,17 @@
# Adapted from 1.4 anydbm
"""This program is self-checking!"""
def scan(items):
for i in items:
try:
5 / i
except:
continue
else:
break
else:
return 2
return i
assert scan((0, 1)) == 1
assert scan((0, 0)) == 2
assert scan((3, 2, 1)) == 3

View File

@@ -0,0 +1,4 @@
# From https://github.com/rocky/python-uncompyle6/issues/350
# This is RUNNABLE!
a = (lambda x: x)(abs)
assert a(-3) == 3

View File

@@ -0,0 +1,9 @@
# From 2.7.17 test_bdb.py
# The problem was detecting a docstring at the begining of the module
# It must be detected and change'd or else the "from __future__" below
# is invalid.
# Note that this has to be compiled with optimation < 2 or else optimization
# will remove the docstring
"""Rational, infinite-precision, real numbers."""
from __future__ import division

View File

@@ -0,0 +1,27 @@
# From 2.7 test_descr.py
# Testing __doc__ descriptor...
# The bug in decompilation was erroneously matching
# __doc__ = as a docstring
"""This program is self-checking!"""
def test_doc_descriptor():
# Testing __doc__ descriptor...
# Python SF bug 542984
class DocDescr(object):
def __get__(self, object, otype):
if object:
object = object.__class__.__name__ + ' instance'
if otype:
otype = otype.__name__
return 'object=%s; type=%s' % (object, otype)
class OldClass:
__doc__ = DocDescr()
class NewClass(object):
__doc__ = DocDescr()
assert OldClass.__doc__ == 'object=None; type=OldClass'
assert OldClass().__doc__ == 'object=OldClass instance; type=OldClass'
assert NewClass.__doc__ == 'object=None; type=NewClass'
assert NewClass().__doc__ == 'object=NewClass instance; type=NewClass'
test_doc_descriptor()

View File

@@ -1,6 +1,8 @@
# Python 3.3+
#
# From Python 3.3.6 hmac.py
# Problem was getting wrong placement of positional args.
# In 3.6+ paramter handling changes
# In 3.6+ parameter handling changes
# RUNNABLE!

View File

@@ -2,6 +2,7 @@
# Bug was code not knowing which Python versions
# have kwargs coming before positional args in code.
"""This program is self-checking!"""
# RUNNABLE!
def tometadata(self, metadata, schema, Table, args, name=None):

View File

@@ -1,6 +1,9 @@
# 3.6+ type annotations on variables
from typing import List
# This test program is part of the uncompyle6 test suite
# tests STORE_ANNOTATION and SETUP_ANOTATIONS
# RUNNABLE!
y = 2
x: bool

View File

@@ -0,0 +1,12 @@
# From python3.8/distutils/version.py with optimization -O2
# The bug was that the other "else" constant propagated removed.
# NOTE: this program needs to be compile with optimization
def _cmp (b, c):
if b:
if c:
return 0
else:
return 1
else:
assert False, "never get here"

View File

@@ -1,23 +0,0 @@
# from 3.7 test_contextlib_async.py
# Bugs were not adding "async" when a function is a decorator,
# and a misaligment when using "async with as".
@_async_test
async def test_enter(self):
self.assertIs(await manager.__aenter__(), manager)
async with manager as context:
async with woohoo() as x:
x = 1
y = 2
assert manager is context
# From 3.7.6 test_coroutines.py
# Bug was different form of code for "async with" below
class CoroutineTest():
def test_with_8(self):
CNT = 0
async def foo():
nonlocal CNT
async with CM():
CNT += 1
return

View File

@@ -0,0 +1,70 @@
# from 3.7 test_contextlib_async.py
# Bugs were not adding "async" when a function is a decorator,
# and a misaligment when using "async with ... as".
"""This program is self-checking!"""
import asyncio
from contextlib import asynccontextmanager, AbstractAsyncContextManager
import functools
def _async_test(func):
"""Decorator to turn an async function into a test case."""
@functools.wraps(func)
def wrapper(*args, **kwargs):
coro = func(*args, **kwargs)
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
return loop.run_until_complete(coro)
finally:
loop.close()
asyncio.set_event_loop(None)
return wrapper
state = []
@asynccontextmanager
async def woohoo():
state.append(1)
yield 42
state.append(999)
@_async_test
async def test_enter():
class DefaultEnter(AbstractAsyncContextManager):
async def __aexit__(*args):
return
# await super().__aexit__(*args)
manager = DefaultEnter()
got_manager = await manager.__aenter__()
# print(got_manager, manager)
assert got_manager is manager
async with manager as context:
async with woohoo() as x:
x = 1
y = 2
assert manager is context
# From 3.7.6 test_coroutines.py
# Bug was different form of code for "async with" below
class CoroutineTest:
def test_with_8(self):
CNT = 0
async def foo():
nonlocal CNT
async with CM():
CNT += 1
return
test_enter()

View File

@@ -1,5 +1,5 @@
# Python 3.3 pyclbr.py
# Note that Python 3 adds a lot of unecessary "continues"
# Note that Python 3 adds a lot of unnecessary "continues"
# and puts that in for "pass"
def _readmodule(g, token, path):
for tokentype in g:

View File

@@ -16,3 +16,25 @@ def withas_bug(self, nested, a, b):
with self.assertRaises(ZeroDivisionError):
with nested(a(), b()) as (x, y):
1 // 0
# From 3.7.7 test_functools.py
# Bug is a unreachable code after "return"
def test_invalid_registrations(x):
return
with x:
x = 1
# From 3.7.7 test_re.py
# Bug was hooking in c_with.
def test_re_tests(tests):
for t in tests:
with a:
continue
# Adapted from 3.8 distutils/command/config.py
# In 3.8 the problem was in handling "with .. as" code
def _gen_temp_sourcefile(x, a, headers, lang):
with x as y:
if a:
y = 2
return 5

View File

@@ -8,7 +8,7 @@ b = [4, 5, 6]
del b[1]
del b[:]
# del_stmt ::= expr expr DELETE_SLICE+1
# delete ::= expr expr DELETE_SLICE+1
l = [None] * 10
del l[-2:]

View File

@@ -1 +1,3 @@
/.python-version
/runun33.sh
/runun7.sh

View File

@@ -45,7 +45,6 @@ SKIP_TESTS=(
[test_grammar.py]=1 # Too many stmts. Handle large stmts
[test_grp.py]=1 # Long test - might work Control flow?
[test_pep247.py]=1 # Long test - might work? Control flow?
[test_pwd.py]=1 # Long test - might work? Control flow?
[test_socketserver.py]=1 # -- test takes too long to run: 40 seconds
[test_threading.py]=1 # test takes too long to run: 11 seconds
[test_thread.py]=1 # test takes too long to run: 36 seconds

View File

@@ -55,12 +55,9 @@ SKIP_TESTS=(
[test_ossaudiodev.py]=1 # it fails on its own
[test_pdb.py]=1 # Line-number specific
[test_pep277.py]=1 # it fails on its own
[test_pep352.py]=1 # Investigate
[test_plistlib.py]=1 # it fails on its own
[test_pwd.py]=1 # Long test - might work? Control flow?
[test_pyclbr.py]=1 # Investigate
[test_rgbimg.py]=1 # it fails on its own
[test_queue.py]=1 # Control flow?
[test_scriptpackages.py]=1 # it fails on its own
[test_socketserver.py]=1 # Too long to run - 42 seconds
[test_sqlite.py]=1 # it fails on its own

View File

@@ -1,4 +1,11 @@
SKIP_TESTS=(
# ifelsestmt is borked in:
# if filename == 'srcfile':
# return srcfile
# if filename == 'destfile':
# return destfile
# assert 0 # shouldn't reach here.
[test_shutil.py]=1
[test___all__.py]=1 # it fails on its own
[test___all__.py]=1 # it fails on its own
@@ -52,13 +59,12 @@ SKIP_TESTS=(
[test_ossaudiodev.py]=1 # it fails on its own
[test_pep277.py]=1 # it fails on its own
[test_pep352.py]=1 # Investigate
[test_pyclbr.py]=1 # Investigate
[test_pwd.py]=1 # Long test - might work? Control flow?
[test_py3kwarn.py]=1 # it fails on its own
[test_scriptpackages.py]=1 # it fails on its own
[test_select.py]=1 # test takes too long to run: 11 seconds
[test_socket.py]=1 # test takes too long to run: 12 seconds
[test_startfile.py]=1 # it fails on its own
[test_structmembers.py]=1 # it fails on its own

View File

@@ -19,7 +19,6 @@ SKIP_TESTS=(
[test_modulefinder.py]=1 # FIX
[test_multiprocessing.py]=1 # On uncompyle2, takes 24 secs
[test_poll.py]=1 # test takes too long to run: 11 seconds
[test_pwd.py]=1 # Takes too long
[test_regrtest.py]=1 #
[test_runpy.py]=1 # Long and fails on its own
[test_select.py]=1 # Runs okay but takes 11 seconds

View File

@@ -17,8 +17,6 @@ SKIP_TESTS=(
[test_peepholer.py]=1
[test_pep352.py]=1
[test_quopri.py]=1 # TypeError: Can't convert 'bytes' object to str implicitly
[test_runpy.py]=1
[test_ssl.py]=1 # too installation specific
@@ -35,5 +33,4 @@ if (( BATCH )) ; then
# Fails in crontab environment?
# Figure out what's up here
SKIP_TESTS[test_exception_variations.py]=1
SKIP_TESTS[test_quopri.py]=1
fi

View File

@@ -1,4 +1,15 @@
SKIP_TESTS=(
# FIXME: Did this work sometime in the past ?
# for elem in g(s):
# if not tgt and isOdd(elem): continue
# is erroneously:
# for elem in g(s):
# if tgt or isOdd(elem):
# pass
# else:
# tgt.append(elem)
[test_itertools.py]=1
[test_buffer.py]=1 # FIXME: Works on c90ff51
[test_cmath.py]=1 # FIXME: Works on c90ff51

View File

@@ -1,4 +1,15 @@
SKIP_TESTS=(
# FIXME: Did this work sometime in the past ?
# for elem in g(s):
# if not tgt and isOdd(elem): continue
# is erroneously:
# for elem in g(s):
# if tgt or isOdd(elem):
# pass
# else:
# tgt.append(elem)
[test_itertools.py]=1
[test_buffer.py]=1 # FIXME: Works on c90ff51
[test_cmath.py]=1 # FIXME: Works on c90ff51
[test_strftime.py]=1 # FIXME: Works on c90ff51
@@ -87,5 +98,4 @@ if (( batch )) ; then
# Figure out what's up here
SKIP_TESTS[test_exception_variations.py]=1
SKIP_TESTS[test_mailbox.py]=1 # Takes to long on POWER; over 15 secs
SKIP_TESTS[test_quopri.py]=1
fi

View File

@@ -138,7 +138,6 @@ if (( BATCH )) ; then
SKIP_TESTS[test_ioctl.py]=1 # it fails on its own
SKIP_TESTS[test_poplib.py]=1 # May be a result of POWER installation
SKIP_TESTS[test_quopri.py]=1
SKIP_TESTS[test_sysconfig.py]=1 # POWER extension fails
SKIP_TESTS[test_tarfile.py]=1 # too long to run on POWER 15 secs
SKIP_TESTS[test_venv.py]=1 # takes too long 11 seconds

View File

@@ -123,8 +123,6 @@ SKIP_TESTS=(
[test_pyclbr.py]=1 # it fails on its own
[test_pydoc.py]=1 # it fails on its own
[test_quopri.py]=1 # AssertionError: b'123=four' != '123=four'
[test_random.py]=1 # it fails on its own
[test_range.py]=1
[test_regrtest.py]=1 # test takes too long to run: 12 seconds

View File

@@ -1,4 +1,19 @@
SKIP_TESTS=(
# FIXME: Did this work sometime in the past ?
# for elem in g(s):
# if not tgt and isOdd(elem): continue
# is erroneously:
# for elem in g(s):
# if tgt or isOdd(elem):
# pass
# else:
# tgt.append(elem)
[test_itertools.py]=1
# Fails on decompyle3 as well.
# complicated control flow and "and/or" expressions
[test_pickle.py]=1
[test_builtin.py]=1 # FIXME works on decompyle6
[test_context.py]=1 # FIXME works on decompyle6
[test_doctest2.py]=1 # FIXME works on decompyle6
@@ -48,6 +63,7 @@ SKIP_TESTS=(
[test_faulthandler.py]=1 # test takes too long before decompiling
[test_fileinput.py]=1 # Test assertion failures
[test_finalization.py]=1 # if/else logic
[test_frame.py]=1 # test assertion errors
[test_ftplib.py]=1 # parse error
[test_fstring.py]=1 # need to disambiguate leading fstrings from docstrings

View File

@@ -8,6 +8,37 @@ SKIP_TESTS=(
[test_urllib2.py]=1 # FIXME: works on uncompyle6?
[test_zipimport.py]=1 # FIXME: works on uncompyle6
# From decompyle3 excludes
# Very Simple example. Compare with 3.7 Need 3.8 parse rules for exception handling return
# for proto in p:
# try:
# drop = 5
# except StopIteration:
# continue
[test_dict.py]=1 #
# Simple example. Compare with 3.7 Need 3.8 parse rules for exception handling return
# try:
# return 5
# except KeyError:
# return res
# except TypeError:
# return 10
# These and the above may be due to new code generation or tests
# between 3.8.3 and 3.8.5 ?
[test_decorators.py]=1 #
[test_dtrace.py]=1 #
[test_exceptions.py]=1 #
[test_ftplib.py]=1 #
[test_gc.py]=1 #
[test_gzip.py]=1 #
[test_hashlib.py]=1 #
[test_iter.py]=1 #
[test_itertools.py]=1 #
[test___all__.py]=1 # it fails on its own
[test_argparse.py]=1 #- it fails on its own
[test_array.py]=1 #- parse error

View File

@@ -52,7 +52,7 @@ for VERSION in $PYVERSIONS ; do
LOGFILE=/tmp/runtests-$VERSION-$$.log
case "$VERSION" in
3.0.1 | 3.1.5 | 3.2.6 | 3.8.1 )
3.0.1 | 3.1.5 | 3.2.6 | 3.8.5 )
continue
;;
esac

View File

@@ -78,7 +78,6 @@ case $PYVERSION in
# Fails in crontab environment?
# Figure out what's up here
SKIP_TESTS[test_exception_variations.py]=1
SKIP_TESTS[test_quopri.py]=1
fi
;;
3.1)
@@ -91,7 +90,6 @@ case $PYVERSION in
# Fails in crontab environment?
# Figure out what's up here
SKIP_TESTS[test_exception_variations.py]=1
SKIP_TESTS[test_quopri.py]=1
fi
;;
3.2)
@@ -131,6 +129,7 @@ fulldir=$(pwd)
# DECOMPILER=uncompyle2
DECOMPILER=${DECOMPILER:-"$fulldir/../../bin/uncompyle6"}
OPTS=${OPTS:-""}
TESTDIR=/tmp/test${PYVERSION}
if [[ -e $TESTDIR ]] ; then
rm -fr $TESTDIR
@@ -139,6 +138,8 @@ fi
PYENV_ROOT=${PYENV_ROOT:-$HOME/.pyenv}
pyenv_local=$(pyenv local)
echo Python version is $pyenv_local
# pyenv version update
for dir in ../ ../../ ; do
cp -v .python-version $dir
@@ -147,18 +148,25 @@ done
mkdir $TESTDIR || exit $?
cp -r ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test $TESTDIR
cd $TESTDIR/test
if [[ $PYVERSION == 3.2 ]] ; then
cp ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test/* $TESTDIR
cd $TESTDIR
else
cd $TESTDIR/test
fi
pyenv local $FULLVERSION
export PYTHONPATH=$TESTDIR
export PATH=${PYENV_ROOT}/shims:${PATH}
DONT_SKIP_TESTS=${DONT_SKIP_TESTS:-0}
# Run tests
typeset -i i=0
typeset -i allerrs=0
if [[ -n $1 ]] ; then
files=$1
typeset -a files_ary=( $(echo $1) )
if (( ${#files_ary[@]} == 1 )) ; then
files=$@
typeset -a files_ary=( $(echo $@) )
if (( ${#files_ary[@]} == 1 || DONT_SKIP_TESTS == 1 )) ; then
SKIP_TESTS=()
fi
else
@@ -190,7 +198,7 @@ for file in $files; do
typeset -i ENDTIME=$(date +%s)
typeset -i time_diff
(( time_diff = ENDTIME - STARTTIME))
if (( time_diff > 10 )) ; then
if (( time_diff > $timeout )) ; then
echo "Skipping test $file -- test takes too long to run: $time_diff seconds"
continue
fi
@@ -202,7 +210,7 @@ for file in $files; do
$fulldir/compile-file.py $file && \
mv $file{,.orig} && \
echo ========== $(date +%X) Decompiling $file ===========
$DECOMPILER $decompiled_file > $file
$DECOMPILER $OPTS $decompiled_file > $file
rc=$?
if (( rc == 0 )) ; then
echo ========== $(date +%X) Running $file ===========

View File

@@ -31,6 +31,8 @@ import xdis.magics as magics
# ----- configure this for your needs
python_versions = [v for v in magics.python_versions if re.match("^[0-9.]+$", v)]
print(python_versions)
sys.exit(0)
# FIXME: we should remove Python versions that we don't support.
# These include Jython, and Python bytecode changes pre release.

View File

@@ -3,7 +3,7 @@
[flake8]
exclude = .tox,./build,./trepan/processor/command/tmp
filename = *.py
ignore = C901,E113,E121,E122,E123,E124,E125,E126,E127,E128,E129,E201,E202,E203,E221,E222,E225,E226,E241,E242,E251,E261,E271,E272,E302,E401,E402,E501,F401,E701,E702
ignore = C901,E113,E121,E122,E123,E124,E125,E126,E127,E128,E129,E201,E202,E203,E221,E222,E225,E226,E241,E242,E251,E261,E271,E272,E302,E401,E402,E501,F401,E701,E702,W503
[tox]
envlist = py27, py34, pypy

View File

@@ -28,20 +28,22 @@
import sys
__docformat__ = 'restructuredtext'
__docformat__ = "restructuredtext"
PYTHON3 = (sys.version_info >= (3, 0))
from uncompyle6.version import __version__
PYTHON3 = sys.version_info >= (3, 0)
# We do this crazy way to support Python 2.6 which
# doesn't support version_major, and has a bug in
# floating point so we can't divide 26 by 10 and get
# 2.6
PYTHON_VERSION = sys.version_info[0] + (sys.version_info[1] / 10.0)
PYTHON_VERSION_STR = "%s.%s" % (sys.version_info[0], sys.version_info[1])
PYTHON_VERSION_STR = "%s.%s" % (sys.version_info[0], sys.version_info[1])
IS_PYPY = '__pypy__' in sys.builtin_module_names
IS_PYPY = "__pypy__" in sys.builtin_module_names
if hasattr(sys, 'setrecursionlimit'):
if hasattr(sys, "setrecursionlimit"):
# pyston doesn't have setrecursionlimit
sys.setrecursionlimit(5000)

View File

@@ -1,13 +1,13 @@
#!/usr/bin/env python
# Mode: -*- python -*-
#
# Copyright (c) 2015-2016, 2018 by Rocky Bernstein <rb@dustyfeet.com>
# Copyright (c) 2015-2016, 2018, 2020 by Rocky Bernstein <rb@dustyfeet.com>
#
from __future__ import print_function
import sys, os, getopt
from uncompyle6.disas import disassemble_file
from uncompyle6.version import VERSION
from uncompyle6.version import __version__
program, ext = os.path.splitext(os.path.basename(__file__))
@@ -58,7 +58,7 @@ Type -h for for full help.""" % program
print(__doc__)
sys.exit(1)
elif opt in ('-V', '--version'):
print("%s %s" % (program, VERSION))
print("%s %s" % (program, __version__))
sys.exit(0)
else:
print(opt)

View File

@@ -1,11 +1,12 @@
#!/usr/bin/env python
# Mode: -*- python -*-
#
# Copyright (c) 2015-2017, 2019 by Rocky Bernstein
# Copyright (c) 2015-2017, 2019-2020 by Rocky Bernstein
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
#
from __future__ import print_function
import sys, os, getopt, time
from xdis.version_info import version_tuple_to_str
program = 'uncompyle6'
@@ -63,7 +64,7 @@ program = 'uncompyle6'
from uncompyle6 import verify
from uncompyle6.main import main, status_msg
from uncompyle6.version import VERSION
from uncompyle6.version import __version__
def usage():
print(__doc__)
@@ -74,10 +75,12 @@ def main_bin():
if not (sys.version_info[0:2] in ((2, 6), (2, 7), (3, 0),
(3, 1), (3, 2), (3, 3),
(3, 4), (3, 5), (3, 6),
(3, 7), (3, 8)
(3, 7), (3, 8), (3, 9), (3, 10)
)):
print('Error: %s requires Python 2.6-3.8' % program,
file=sys.stderr)
print(
f"Error: {program} can decompile only bytecode from Python 3.7"
f""" to 3.8.\n\tYou have version: {version_tuple_to_str()}."""
)
sys.exit(-1)
do_verify = recurse_dirs = False
@@ -105,7 +108,7 @@ def main_bin():
print(__doc__)
sys.exit(0)
elif opt in ('-V', '--version'):
print("%s %s" % (program, VERSION))
print("%s %s" % (program, __version__))
sys.exit(0)
elif opt == '--verify':
options['do_verify'] = 'strong'
@@ -197,6 +200,9 @@ def main_bin():
mess = status_msg(do_verify, *result)
print('# ' + mess)
pass
except ImportError as e:
print(str(e))
sys.exit(2)
except (KeyboardInterrupt):
pass
except verify.VerifyCmpError:
@@ -225,7 +231,7 @@ def main_bin():
if f is None:
break
(t, o, f, v) = \
main(src_base, out_base, [f], None, outfile, **options)
main(src_base, out_base, [f], [], outfile, **options)
tot_files += t
okay_files += o
failed_files += f

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2015-2016, 2818-2020 by Rocky Bernstein
# Copyright (c) 2015-2016, 2818-2021 by Rocky Bernstein
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock
@@ -29,13 +29,11 @@ Second, we need structured instruction information for the
want to run on earlier Python versions.
"""
from __future__ import print_function
import sys
from collections import deque
from xdis import iscode
from xdis.load import check_object_path, load_module
from xdis import check_object_path, iscode, load_module
from xdis.version_info import version_tuple_to_str
from uncompyle6.scanner import get_scanner
@@ -48,7 +46,7 @@ def disco(version, co, out=None, is_pypy=False):
# store final output stream for case of error
real_out = out or sys.stdout
print("# Python %s" % version, file=real_out)
print("# Python %s" % version_tuple_to_str(version), file=real_out)
if co.co_filename:
print("# Embedded file name: %s" % co.co_filename, file=real_out)

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2015-2016, 2818 by Rocky Bernstein
# Copyright (c) 2015-2016, 2818, 2020 by Rocky Bernstein
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -15,14 +15,27 @@
from collections import deque
from xdis import iscode
from xdis.load import load_file, load_module
from xdis.main import get_opcode
from xdis.bytecode import Bytecode, findlinestarts, offset2line
from xdis import (
Bytecode,
iscode,
findlinestarts,
get_opcode,
offset2line,
load_file,
load_module,
)
def line_number_mapping(pyc_filename, src_filename):
(version, timestamp, magic_int, code1, is_pypy,
source_size, sip_hash) = load_module(pyc_filename)
(
version,
timestamp,
magic_int,
code1,
is_pypy,
source_size,
sip_hash,
) = load_module(pyc_filename)
try:
code2 = load_file(src_filename)
except SyntaxError as e:
@@ -44,7 +57,10 @@ def number_loop(queue, mappings, opc):
assert code1.co_name == code2.co_name
linestarts_orig = findlinestarts(code1)
linestarts_uncompiled = list(findlinestarts(code2))
mappings += [[line, offset2line(offset, linestarts_uncompiled)] for offset, line in linestarts_orig]
mappings += [
[line, offset2line(offset, linestarts_uncompiled)]
for offset, line in linestarts_orig
]
bytecode1 = Bytecode(code1, opc)
bytecode2 = Bytecode(code2, opc)
instr2s = bytecode2.get_instructions(code2)

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2018-2020 Rocky Bernstein <rocky@gnu.org>
# Copyright (C) 2018-2021 Rocky Bernstein <rocky@gnu.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -12,16 +12,17 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
from typing import Any, Tuple
import datetime, py_compile, os, subprocess, sys, tempfile
from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION
from uncompyle6 import verify
from xdis import iscode
from xdis.magics import sysinfo2float
from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE, version_tuple_to_str
from uncompyle6.disas import check_object_path
from uncompyle6.semantics import pysource
from uncompyle6.parser import ParserError
from uncompyle6.version import VERSION
from uncompyle6.version import __version__
# from uncompyle6.linenumbers import line_number_mapping
@@ -31,8 +32,7 @@ from uncompyle6.semantics.linemap import deparse_code_with_map
from xdis.load import load_module
def _get_outstream(outfile):
def _get_outstream(outfile: str) -> Any:
dir = os.path.dirname(outfile)
failed_file = outfile + "_failed"
if os.path.exists(failed_file):
@@ -41,14 +41,11 @@ def _get_outstream(outfile):
os.makedirs(dir)
except OSError:
pass
if PYTHON_VERSION < 3.0:
return open(outfile, mode="wb")
else:
return open(outfile, mode="w", encoding="utf-8")
return open(outfile, mode="w", encoding="utf-8")
def decompile(
bytecode_version,
bytecode_version: str,
co,
out=None,
showasm=None,
@@ -62,7 +59,7 @@ def decompile(
magic_int=None,
mapstream=None,
do_fragments=False,
):
) -> Any:
"""
ingests and deparses a given code block 'co'
@@ -72,7 +69,7 @@ def decompile(
Caller is responsible for closing `out` and `mapstream`
"""
if bytecode_version is None:
bytecode_version = sysinfo2float()
bytecode_version = PYTHON_VERSION_TRIPLE
# store final output stream for case of error
real_out = out or sys.stdout
@@ -81,7 +78,7 @@ def decompile(
s += "\n"
real_out.write(s)
assert iscode(co)
assert iscode(co), f"""{co} does not smell like code"""
co_pypy_str = "PyPy " if is_pypy else ""
run_pypy_str = "PyPy " if IS_PYPY else ""
@@ -92,21 +89,16 @@ def decompile(
"# uncompyle6 version %s\n"
"# %sPython bytecode %s%s\n# Decompiled from: %sPython %s"
% (
VERSION,
__version__,
co_pypy_str,
bytecode_version,
version_tuple_to_str(bytecode_version),
" (%s)" % str(magic_int) if magic_int else "",
run_pypy_str,
"\n# ".join(sys_version_lines),
)
)
if PYTHON_VERSION < 3.0 and bytecode_version >= 3.0:
write(
'# Warning: this version has problems handling the Python 3 "byte" type in constants properly.\n'
)
if co.co_filename:
write("# Embedded file name: %s" % co.co_filename,)
write("# Embedded file name: %s" % co.co_filename)
if timestamp:
write("# Compiled at: %s" % datetime.datetime.fromtimestamp(timestamp))
if source_size:
@@ -120,12 +112,10 @@ def decompile(
mapstream = _get_outstream(mapstream)
deparsed = deparse_code_with_map(
bytecode_version,
co,
out,
showasm,
showast,
showgrammar,
bytecode_version,
debug_opts,
code_objects=code_objects,
is_pypy=is_pypy,
)
@@ -150,16 +140,16 @@ def decompile(
raise pysource.SourceWalkerError(str(e))
def compile_file(source_path):
def compile_file(source_path: str) -> str:
if source_path.endswith(".py"):
basename = source_path[:-3]
else:
basename = source_path
if hasattr(sys, "pypy_version_info"):
bytecode_path = "%s-pypy%s.pyc" % (basename, PYTHON_VERSION)
bytecode_path = "%s-pypy%s.pyc" % (basename, version_tuple_to_str())
else:
bytecode_path = "%s-%s.pyc" % (basename, PYTHON_VERSION)
bytecode_path = "%s-%s.pyc" % (basename, version_tuple_to_str())
print("compiling %s to %s" % (source_path, bytecode_path))
py_compile.compile(source_path, bytecode_path, "exec")
@@ -175,7 +165,7 @@ def decompile_file(
source_encoding=None,
mapstream=None,
do_fragments=False,
):
) -> Any:
"""
decompile Python byte-code file (.pyc). Return objects to
all of the deparsed objects found in `filename`.
@@ -231,10 +221,10 @@ def decompile_file(
# FIXME: combine into an options parameter
def main(
in_base,
out_base,
compiled_files,
source_files,
in_base: str,
out_base: str,
compiled_files: list,
source_files: list,
outfile=None,
showasm=None,
showast=False,
@@ -244,7 +234,7 @@ def main(
raise_on_error=False,
do_linemaps=False,
do_fragments=False,
):
) -> Tuple[int, int, int, int]:
"""
in_base base directory for input files
out_base base directory for output files (ignored when
@@ -289,13 +279,8 @@ def main(
# Unbuffer output if possible
buffering = -1 if sys.stdout.isatty() else 0
if PYTHON_VERSION >= 3.5:
t = tempfile.NamedTemporaryFile(
mode="w+b", buffering=buffering, suffix=".py", prefix=prefix
)
else:
t = tempfile.NamedTemporaryFile(
mode="w+b", suffix=".py", prefix=prefix
t = tempfile.NamedTemporaryFile(
mode="w+b", buffering=buffering, suffix=".py", prefix=prefix
)
current_outfile = t.name
sys.stdout = os.fdopen(sys.stdout.fileno(), "w", buffering)

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2015-2020 Rocky Bernstein
# Copyright (c) 2015-2021 Rocky Bernstein
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock
@@ -19,18 +19,15 @@
Common uncompyle6 parser routines.
"""
from __future__ import print_function
import sys
from xdis import iscode
from xdis.magics import py_str2float
from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6.show import maybe_show_asm
from xdis import iscode
class ParserError(Exception):
def __init__(self, token, offset, debug):
def __init__(self, token, offset, debug=PARSER_DEFAULT_DEBUG):
self.token = token
self.offset = offset
self.debug = debug
@@ -355,10 +352,10 @@ class PythonParser(GenericASTBuilder):
stmt ::= with
stmt ::= withasstmt
stmt ::= del_stmt
del_stmt ::= DELETE_FAST
del_stmt ::= DELETE_NAME
del_stmt ::= DELETE_GLOBAL
stmt ::= delete
delete ::= DELETE_FAST
delete ::= DELETE_NAME
delete ::= DELETE_GLOBAL
stmt ::= return
@@ -624,7 +621,7 @@ class PythonParser(GenericASTBuilder):
"""
def parse(p, tokens, customize):
def parse(p, tokens, customize, code):
p.customize_grammar_rules(tokens, customize)
ast = p.parse(tokens)
# p.cleanup()
@@ -643,107 +640,109 @@ def get_python_parser(
# If version is a string, turn that into the corresponding float.
if isinstance(version, str):
version = py_str2float(version)
version = tuple([int(v) for v in version.split(".")[:2]])
version = version[:2]
# FIXME: there has to be a better way...
# We could do this as a table lookup, but that would force us
# in import all of the parsers all of the time. Perhaps there is
# a lazy way of doing the import?
if version < 3.0:
if version < 2.2:
if version == 1.0:
if version < (3, 0):
if version < (2, 2):
if version == (1, 0):
import uncompyle6.parsers.parse10 as parse10
if compile_mode == "exec":
p = parse10.Python10Parser(debug_parser)
else:
p = parse10.Python01ParserSingle(debug_parser)
elif version == 1.1:
elif version == (1, 1):
import uncompyle6.parsers.parse11 as parse11
if compile_mode == "exec":
p = parse11.Python11Parser(debug_parser)
else:
p = parse11.Python11ParserSingle(debug_parser)
if version == 1.2:
if version == (1, 2):
import uncompyle6.parsers.parse12 as parse12
if compile_mode == "exec":
p = parse12.Python12Parser(debug_parser)
else:
p = parse12.Python12ParserSingle(debug_parser)
if version == 1.3:
if version == (1, 3):
import uncompyle6.parsers.parse13 as parse13
if compile_mode == "exec":
p = parse13.Python13Parser(debug_parser)
else:
p = parse13.Python13ParserSingle(debug_parser)
elif version == 1.4:
elif version == (1, 4):
import uncompyle6.parsers.parse14 as parse14
if compile_mode == "exec":
p = parse14.Python14Parser(debug_parser)
else:
p = parse14.Python14ParserSingle(debug_parser)
elif version == 1.5:
elif version == (1, 5):
import uncompyle6.parsers.parse15 as parse15
if compile_mode == "exec":
p = parse15.Python15Parser(debug_parser)
else:
p = parse15.Python15ParserSingle(debug_parser)
elif version == 1.6:
elif version == (1, 6):
import uncompyle6.parsers.parse16 as parse16
if compile_mode == "exec":
p = parse16.Python16Parser(debug_parser)
else:
p = parse16.Python16ParserSingle(debug_parser)
elif version == 2.1:
elif version == (2, 1):
import uncompyle6.parsers.parse21 as parse21
if compile_mode == "exec":
p = parse21.Python21Parser(debug_parser)
else:
p = parse21.Python21ParserSingle(debug_parser)
elif version == 2.2:
elif version == (2, 2):
import uncompyle6.parsers.parse22 as parse22
if compile_mode == "exec":
p = parse22.Python22Parser(debug_parser)
else:
p = parse22.Python22ParserSingle(debug_parser)
elif version == 2.3:
elif version == (2, 3):
import uncompyle6.parsers.parse23 as parse23
if compile_mode == "exec":
p = parse23.Python23Parser(debug_parser)
else:
p = parse23.Python23ParserSingle(debug_parser)
elif version == 2.4:
elif version == (2, 4):
import uncompyle6.parsers.parse24 as parse24
if compile_mode == "exec":
p = parse24.Python24Parser(debug_parser)
else:
p = parse24.Python24ParserSingle(debug_parser)
elif version == 2.5:
elif version == (2, 5):
import uncompyle6.parsers.parse25 as parse25
if compile_mode == "exec":
p = parse25.Python25Parser(debug_parser)
else:
p = parse25.Python25ParserSingle(debug_parser)
elif version == 2.6:
elif version == (2, 6):
import uncompyle6.parsers.parse26 as parse26
if compile_mode == "exec":
p = parse26.Python26Parser(debug_parser)
else:
p = parse26.Python26ParserSingle(debug_parser)
elif version == 2.7:
elif version == (2, 7):
import uncompyle6.parsers.parse27 as parse27
if compile_mode == "exec":
@@ -763,63 +762,63 @@ def get_python_parser(
else:
import uncompyle6.parsers.parse3 as parse3
if version == 3.0:
if version == (3, 0):
import uncompyle6.parsers.parse30 as parse30
if compile_mode == "exec":
p = parse30.Python30Parser(debug_parser)
else:
p = parse30.Python30ParserSingle(debug_parser)
elif version == 3.1:
elif version == (3, 1):
import uncompyle6.parsers.parse31 as parse31
if compile_mode == "exec":
p = parse31.Python31Parser(debug_parser)
else:
p = parse31.Python31ParserSingle(debug_parser)
elif version == 3.2:
elif version == (3, 2):
import uncompyle6.parsers.parse32 as parse32
if compile_mode == "exec":
p = parse32.Python32Parser(debug_parser)
else:
p = parse32.Python32ParserSingle(debug_parser)
elif version == 3.3:
elif version == (3, 3):
import uncompyle6.parsers.parse33 as parse33
if compile_mode == "exec":
p = parse33.Python33Parser(debug_parser)
else:
p = parse33.Python33ParserSingle(debug_parser)
elif version == 3.4:
elif version == (3, 4):
import uncompyle6.parsers.parse34 as parse34
if compile_mode == "exec":
p = parse34.Python34Parser(debug_parser)
else:
p = parse34.Python34ParserSingle(debug_parser)
elif version == 3.5:
elif version == (3, 5):
import uncompyle6.parsers.parse35 as parse35
if compile_mode == "exec":
p = parse35.Python35Parser(debug_parser)
else:
p = parse35.Python35ParserSingle(debug_parser)
elif version == 3.6:
elif version == (3, 6):
import uncompyle6.parsers.parse36 as parse36
if compile_mode == "exec":
p = parse36.Python36Parser(debug_parser)
else:
p = parse36.Python36ParserSingle(debug_parser)
elif version == 3.7:
elif version == (3, 7):
import uncompyle6.parsers.parse37 as parse37
if compile_mode == "exec":
p = parse37.Python37Parser(debug_parser)
else:
p = parse37.Python37ParserSingle(debug_parser)
elif version == 3.8:
elif version == (3, 8):
import uncompyle6.parsers.parse38 as parse38
if compile_mode == "exec":
@@ -878,8 +877,15 @@ def python_parser(
# For heavy grammar debugging
# parser_debug = {'rules': True, 'transition': True, 'reduce' : True,
# 'showstack': 'full'}
p = get_python_parser(version, parser_debug)
return parse(p, tokens, customize)
# FIXME: have p.insts update in a better way
# modularity is broken here
p.insts = scanner.insts
p.offset2inst_index = scanner.offset2inst_index
return parse(p, tokens, customize, co)
if __name__ == "__main__":

View File

@@ -7,7 +7,7 @@ from uncompyle6.parsers.parse11 import Python11Parser
class Python10Parser(Python11Parser):
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
super(Python11Parser, self).__init__(debug_parser)
super(Python10Parser, self).__init__(debug_parser)
self.customized = {}

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2019 Rocky Bernstein
# Copyright (c) 2019-2020 Rocky Bernstein
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6.parser import PythonParserSingle
@@ -7,7 +7,7 @@ from uncompyle6.parsers.parse12 import Python12Parser
class Python11Parser(Python12Parser):
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
super(Python12Parser, self).__init__(debug_parser)
super(Python11Parser, self).__init__(debug_parser)
self.customized = {}

Some files were not shown because too many files have changed in this diff Show More