You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 08:49:51 +08:00
Compare commits
198 Commits
release-py
...
release-py
Author | SHA1 | Date | |
---|---|---|---|
|
1358d40aef | ||
|
c8c6f1a63d | ||
|
850500c7ad | ||
|
470d203b40 | ||
|
4911d85237 | ||
|
93a218a8b1 | ||
|
9ec8918c1f | ||
|
08ed185608 | ||
|
32c4b84458 | ||
|
9cf345d446 | ||
|
c164df2795 | ||
|
3ad63071ac | ||
|
25cd759dbe | ||
|
000c060093 | ||
|
39d79217ca | ||
|
5390e3b838 | ||
|
8aeb0aad8c | ||
|
d0ca7b0363 | ||
|
a2e34ab75c | ||
|
5c2af69925 | ||
|
8076c60eee | ||
|
ea26084e6d | ||
|
1b4b6b334e | ||
|
482dbb5c82 | ||
|
fa203af665 | ||
|
08e27a8b0f | ||
|
55ffaa1aff | ||
|
51ac72ba1f | ||
|
d5bf7626af | ||
|
91fa73bf01 | ||
|
9a1b77aff4 | ||
|
79d5790e3f | ||
|
381a470d90 | ||
|
64b75625a9 | ||
|
7387e5094b | ||
|
1bcd21a6f4 | ||
|
536d45deb1 | ||
|
dce7e809e2 | ||
|
5ddbea73f4 | ||
|
71fe1e6c2c | ||
|
8a9a4ca6cc | ||
|
b8e9ce8a7a | ||
|
40a40b0bad | ||
|
528a2b0c22 | ||
|
d75bf1c32a | ||
|
cef3203601 | ||
|
5b657ac7d8 | ||
|
1509bc4828 | ||
|
fad5089175 | ||
|
52262dc38a | ||
|
b61255535e | ||
|
e3369edaed | ||
|
ce58ed7434 | ||
|
01859ce820 | ||
|
0a9dc57cc9 | ||
|
ada786e08c | ||
|
48bd832e7c | ||
|
cfb5c442e2 | ||
|
29a91fc015 | ||
|
37f953c353 | ||
|
4d84a723f4 | ||
|
ddbfc168c5 | ||
|
a463220df2 | ||
|
3e5f963c64 | ||
|
c7ebdb344b | ||
|
438c3b8d1d | ||
|
aa1d7abfdc | ||
|
d3e30cf0e0 | ||
|
36efc1fc8a | ||
|
f00080317b | ||
|
162423895e | ||
|
f2750cff50 | ||
|
256aaf0ef9 | ||
|
41314f95bb | ||
|
0645738775 | ||
|
ceb7c659bd | ||
|
8ac7a75372 | ||
|
15efaffe8d | ||
|
e8e006bb8c | ||
|
c68b74a9c6 | ||
|
f4bb0c44fe | ||
|
8d81f4ab27 | ||
|
e0a56d4739 | ||
|
054364cb22 | ||
|
83c8313a8e | ||
|
184bda1b03 | ||
|
f374485e93 | ||
|
fe7df87288 | ||
|
cfbb25df3d | ||
|
d4174832a1 | ||
|
345de81d06 | ||
|
3684b38310 | ||
|
f472275196 | ||
|
2bca6753d3 | ||
|
dd8f22e698 | ||
|
96b1e435c2 | ||
|
971757e997 | ||
|
2b154e0b88 | ||
|
5d35a75743 | ||
|
fc38e23d8f | ||
|
5c16c73a6c | ||
|
3f665b939d | ||
|
f2f49104ea | ||
|
c2ee564e11 | ||
|
f95db091bc | ||
|
78dbc8ae0f | ||
|
a0cb9c5d6a | ||
|
3ca66d0184 | ||
|
70b7e51df6 | ||
|
1164cd90dc | ||
|
4bbdbe3894 | ||
|
28855767fb | ||
|
316adff2d4 | ||
|
1a3bd3cabe | ||
|
9bc9532c24 | ||
|
732e3331b8 | ||
|
8eb4d6a576 | ||
|
b4db22d525 | ||
|
8879708da7 | ||
|
67c45467c3 | ||
|
33bff4dc47 | ||
|
71c17c4e53 | ||
|
a5cfd81805 | ||
|
64f19bf188 | ||
|
ff08f8a977 | ||
|
fae5525514 | ||
|
3ae4fda292 | ||
|
6cb6e45789 | ||
|
730b739907 | ||
|
844144f90a | ||
|
024a81c053 | ||
|
a0f93f7ad9 | ||
|
d3d67441d1 | ||
|
c105edff47 | ||
|
a215ee2f00 | ||
|
f62512dd65 | ||
|
0f80c38530 | ||
|
bd07de5172 | ||
|
f65aac7b97 | ||
|
e36945e2d9 | ||
|
25df0bdb76 | ||
|
29ceb3fe05 | ||
|
fd7e04fa5d | ||
|
5079164db2 | ||
|
68a145d050 | ||
|
815ae2c5cd | ||
|
54932d36fa | ||
|
fa1d7e4af4 | ||
|
bfd4b4cd68 | ||
|
c2e3ff0f43 | ||
|
430fd2fa85 | ||
|
b49033d584 | ||
|
ef59b9c304 | ||
|
d822017520 | ||
|
084e183577 | ||
|
3dc6c31ae5 | ||
|
8de663ff52 | ||
|
7c14cf2d66 | ||
|
1d3fdbb4cd | ||
|
6e0b010cd3 | ||
|
b21e8b8b57 | ||
|
4b2f26ca70 | ||
|
4007b8b702 | ||
|
e91fe14612 | ||
|
598b58796d | ||
|
f7bad891a4 | ||
|
8ce921c5b7 | ||
|
5d609ae1aa | ||
|
357f28dd89 | ||
|
7042d00203 | ||
|
5cc572147a | ||
|
6c8b3bfbe9 | ||
|
11be90758f | ||
|
e3720515ae | ||
|
38cd854b81 | ||
|
7dec354a47 | ||
|
2a8daca25d | ||
|
33be603e3d | ||
|
7799819cad | ||
|
c6c50b5dfb | ||
|
d357898bbf | ||
|
c4e7ddf90a | ||
|
5753f8114c | ||
|
02f502c40a | ||
|
de4fbb08f2 | ||
|
e14675c2dc | ||
|
3449be024b | ||
|
8b50b15f0a | ||
|
e2e925679d | ||
|
7deeee8502 | ||
|
acdd025162 | ||
|
9acb3cf068 | ||
|
40a653cd3b | ||
|
3ac3979535 | ||
|
7eba933cfa | ||
|
ad5d3333da | ||
|
e046323b31 | ||
|
e80c13170a |
@@ -1,4 +1,7 @@
|
||||
version: 2
|
||||
filters:
|
||||
branches:
|
||||
only: python-2.4
|
||||
jobs:
|
||||
build:
|
||||
parallelism: 1
|
||||
@@ -32,7 +35,12 @@ jobs:
|
||||
- v2-dependencies-
|
||||
|
||||
- run:
|
||||
command: sudo easy_install xdis spark-parser && sudo pip install -e . && sudo pip install -r requirements-dev.txt
|
||||
command: | # Use pip to install dependengcies
|
||||
sudo easy_install click==7.1.2
|
||||
# Until next release use github xdis
|
||||
sudo pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis
|
||||
sudo pip install -e .
|
||||
sudo pip install -r requirements-dev.txt
|
||||
|
||||
# Save dependency cache
|
||||
- save_cache:
|
||||
|
28
.editorconfig
Normal file
28
.editorconfig
Normal 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
|
36
.github/ISSUE_TEMPLATE/bug-report.md
vendored
36
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@@ -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.
|
||||
|
||||
-->
|
||||
|
||||
|
30
.github/workflows/osx.yml
vendored
Normal file
30
.github/workflows/osx.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: uncompyle6 (osx)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ python-2.4 ]
|
||||
pull_request:
|
||||
branches: [ python-2.4 ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macOS]
|
||||
python-version: [2.7]
|
||||
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: |
|
||||
# Until the next xdis release
|
||||
pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#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
30
.github/workflows/ubuntu.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: uncompyle6 (ubuntu)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ python-2.4 ]
|
||||
pull_request:
|
||||
branches: [ python-2.4 ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [2.7]
|
||||
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@python-2.4-to-2.7#egg=xdis
|
||||
pip install -e .
|
||||
pip install -r requirements-dev.txt
|
||||
- name: Test uncompyle6
|
||||
run: |
|
||||
make check
|
30
.github/workflows/windows.yml
vendored
Normal file
30
.github/workflows/windows.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: uncompyle6 (windows)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ python-2.4 ]
|
||||
pull_request:
|
||||
branches: [ python-2.4 ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows]
|
||||
python-version: [2.7]
|
||||
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: |
|
||||
# Until the next xdis release
|
||||
pip install git+git://github.com/rocky/python-xdis.git@python-2.4-to-2.7#egg=xdis
|
||||
pip install -e .
|
||||
pip install -r requirements-dev.txt
|
||||
- name: Test uncompyle6
|
||||
run: |
|
||||
make check
|
@@ -4,6 +4,8 @@ python:
|
||||
- 2.7 # this is a cheat here because travis doesn't do 2.4-2.6
|
||||
|
||||
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
|
||||
|
||||
|
@@ -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.
|
||||
|
52
NEWS.md
52
NEWS.md
@@ -1,3 +1,55 @@
|
||||
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
|
||||
====================================================
|
||||
|
||||
|
70
README.rst
70
README.rst
@@ -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
|
||||
------------
|
||||
@@ -171,15 +170,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
|
||||
@@ -194,7 +189,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
|
||||
@@ -210,26 +205,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
|
||||
@@ -241,6 +262,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
|
||||
|
@@ -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
|
||||
@@ -33,65 +33,76 @@
|
||||
# 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.6.0, < 4.7.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"))
|
||||
|
2
admin-tools/check-older-versions.sh → admin-tools/check-2.4-2.7-versions.sh
Normal file → Executable file
2
admin-tools/check-older-versions.sh → admin-tools/check-2.4-2.7-versions.sh
Normal file → Executable 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
|
2
admin-tools/check-newer-versions.sh → admin-tools/check-newest-versions.sh
Normal file → Executable file
2
admin-tools/check-newer-versions.sh → admin-tools/check-newest-versions.sh
Normal file → Executable 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
|
@@ -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,38 +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.3
|
||||
$ pyenv local 3.8.5
|
||||
$ twine check dist/uncompyle6-$VERSION*
|
||||
$ git tag release-python-2.4-$VERSION
|
||||
$ ./admin-tools/make-dist-newer.sh
|
||||
$ twine check dist/uncompyle6-$VERSION*
|
||||
$ . ./admin-tools/make-dist-newer.sh
|
||||
|
||||
# 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
|
||||
|
@@ -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
|
38
admin-tools/make-dist-3.3-3.5.sh
Executable file
38
admin-tools/make-dist-3.3-3.5.sh
Executable 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
|
@@ -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
|
9
admin-tools/pyenv-2.4-2.7-versions
Normal file
9
admin-tools/pyenv-2.4-2.7-versions
Normal 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'
|
@@ -6,4 +6,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
|
||||
echo "This script should be *sourced* rather than run directly through bash"
|
||||
exit 1
|
||||
fi
|
||||
export PYVERSIONS='2.4.6 2.5.6'
|
||||
export PYVERSIONS='3.1.5 3.2.6'
|
8
admin-tools/pyenv-3.3-3.5-versions
Normal file
8
admin-tools/pyenv-3.3-3.5-versions
Normal 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.3.7 3.4.10 3.5.10 '
|
@@ -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.18 3.2.6 3.1.5 3.4.10 3.7.7 3.8.3'
|
||||
export PYVERSIONS='3.6.15 3.7.12 pyston-2.3 3.8.11 3.9.7 3.10.0'
|
8
admin-tools/pyenv-versions
Normal file
8
admin-tools/pyenv-versions
Normal 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'
|
@@ -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
|
||||
|
@@ -11,7 +11,7 @@ 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
|
||||
|
15
admin-tools/setup-python-3.3.sh
Normal file
15
admin-tools/setup-python-3.3.sh
Normal 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
|
79
appveyor.yml
79
appveyor.yml
@@ -1,79 +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 git+git://github.com/rocky/python-uncompyle6.git#egg=uncompyle6-3.6.6"
|
||||
- "%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
|
||||
#
|
@@ -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.func_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
|
||||
|
@@ -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,10 +38,10 @@ 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")
|
||||
@@ -49,7 +49,7 @@ def test_grammar():
|
||||
# NOTE: this may disappear
|
||||
expect_lhs.add("except_handler_else")
|
||||
|
||||
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")
|
||||
|
||||
@@ -63,8 +63,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")
|
||||
@@ -72,7 +72,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")))
|
||||
)
|
||||
@@ -83,7 +83,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)
|
||||
|
||||
@@ -106,7 +106,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
|
||||
@@ -119,12 +119,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)
|
||||
@@ -135,7 +136,7 @@ def test_dup_rule():
|
||||
import inspect
|
||||
|
||||
python_parser(
|
||||
PYTHON_VERSION,
|
||||
PYTHON_VERSION_TRIPLE,
|
||||
inspect.currentframe().f_code,
|
||||
is_pypy=IS_PYPY,
|
||||
parser_debug={
|
||||
|
@@ -1,6 +1,7 @@
|
||||
from uncompyle6 import PYTHON_VERSION, code_deparse
|
||||
from uncompyle6 import code_deparse
|
||||
from xdis.version_info import PYTHON_VERSION_TRIPLE
|
||||
|
||||
if PYTHON_VERSION > 2.6:
|
||||
if PYTHON_VERSION_TRIPLE >= (2, 7):
|
||||
def test_single_mode():
|
||||
single_expressions = (
|
||||
'i = 1',
|
||||
|
@@ -9,12 +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 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
|
||||
|
||||
@@ -127,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")
|
||||
|
58
setup.cfg
58
setup.cfg
@@ -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
|
||||
|
18
setup.py
18
setup.py
@@ -6,12 +6,18 @@ import sys
|
||||
SYS_VERSION = sys.version_info[0:2]
|
||||
if not ((2, 4) <= SYS_VERSION <= (2, 7)):
|
||||
mess = "Python Release 2.4 .. 2.7 are supported in this code branch."
|
||||
if ((3, 2) <= SYS_VERSION <= (3, 8)):
|
||||
if ((3, 6) <= SYS_VERSION < (3, 9)):
|
||||
mess += ("\nFor your Python, version %s, use the master code/branch." %
|
||||
sys.version[0:3])
|
||||
else:
|
||||
mess += ("\nThis package is not supported before Python 2.4. Your Python version is %s."
|
||||
% sys.version[0:3])
|
||||
elif (3, 3) <= SYS_VERSION <= (3, 6):
|
||||
mess += (
|
||||
"\nFor your Python, version %s, use the python-3.3-3.5 code/branch."
|
||||
% sys.version[0:3]
|
||||
)
|
||||
elif SYS_VERSION < (2, 4):
|
||||
mess += (
|
||||
"\nThis package is not supported for Python before Python 2.4 version %s." % sys.version[0:3]
|
||||
)
|
||||
print(mess)
|
||||
raise Exception(mess)
|
||||
|
||||
@@ -26,7 +32,7 @@ from __pkginfo__ import (
|
||||
modname,
|
||||
py_modules,
|
||||
short_desc,
|
||||
VERSION,
|
||||
__version__,
|
||||
web,
|
||||
zip_safe,
|
||||
)
|
||||
@@ -49,6 +55,6 @@ setup(
|
||||
test_suite="nose.collector",
|
||||
url=web,
|
||||
tests_require=["nose>=1.0"],
|
||||
version=VERSION,
|
||||
version=__version__,
|
||||
zip_safe=zip_safe,
|
||||
)
|
||||
|
@@ -44,7 +44,8 @@ class TestGrammar(unittest.TestCase):
|
||||
print(k, reduced_dup_rhs[k])
|
||||
# assert not reduced_dup_rhs, reduced_dup_rhs
|
||||
|
||||
def test_dup_rule(self):
|
||||
# FIXME: Something got borked here
|
||||
def no_test_dup_rule(self):
|
||||
import inspect
|
||||
python_parser(PYTHON_VERSION, inspect.currentframe().f_code,
|
||||
is_pypy=IS_PYPY,
|
||||
|
@@ -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.7: 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:
|
||||
|
@@ -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)
|
||||
|
BIN
test/bytecode_2.4_run/01_for_else_try_else.pyc
Normal file
BIN
test/bytecode_2.4_run/01_for_else_try_else.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.4_run/01_lambda_call.pyc
Normal file
BIN
test/bytecode_2.4_run/01_lambda_call.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.6_run/01_lambda_call.pyc
Normal file
BIN
test/bytecode_2.6_run/01_lambda_call.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.7/01_module_doc.pyc
Normal file
BIN
test/bytecode_2.7/01_module_doc.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_2.7_run/01_for_else_try_else.pyc
Normal file
BIN
test/bytecode_2.7_run/01_for_else_try_else.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.7_run/01_lambda_call.pyc
Normal file
BIN
test/bytecode_2.7_run/01_lambda_call.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_2.7_run/03_doc_assign.pyc
Normal file
BIN
test/bytecode_2.7_run/03_doc_assign.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.1_run/03_doc_assign.pyc
Normal file
BIN
test/bytecode_3.1_run/03_doc_assign.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.3_run/03_doc_assign.pyc-notyet
Normal file
BIN
test/bytecode_3.3_run/03_doc_assign.pyc-notyet
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.6_run/03_doc_assign.pyc-notyet
Normal file
BIN
test/bytecode_3.6_run/03_doc_assign.pyc-notyet
Normal file
Binary file not shown.
BIN
test/bytecode_3.7/03_else_removal.pyc
Normal file
BIN
test/bytecode_3.7/03_else_removal.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.7_run/01_for_else_try_else.pyc
Normal file
BIN
test/bytecode_3.7_run/01_for_else_try_else.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7_run/01_lambda_call.pyc
Normal file
BIN
test/bytecode_3.7_run/01_lambda_call.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.8/03_else_removal.pyc
Normal file
BIN
test/bytecode_3.8/03_else_removal.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.8_run/01_lambda_call.pyc
Normal file
BIN
test/bytecode_3.8_run/01_lambda_call.pyc
Normal file
Binary file not shown.
@@ -50,7 +50,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 )
|
||||
@@ -65,7 +65,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
|
||||
|
17
test/simple_source/bug14/01_for_else_try_else.py
Normal file
17
test/simple_source/bug14/01_for_else_try_else.py
Normal 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
|
4
test/simple_source/bug22/01_lambda_call.py
Normal file
4
test/simple_source/bug22/01_lambda_call.py
Normal 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
|
9
test/simple_source/bug27+/01_module_doc.py
Normal file
9
test/simple_source/bug27+/01_module_doc.py
Normal 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
|
27
test/simple_source/bug27+/03_doc_assign.py
Normal file
27
test/simple_source/bug27+/03_doc_assign.py
Normal 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()
|
@@ -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):
|
||||
|
12
test/simple_source/bug37/03_else_removal.py
Normal file
12
test/simple_source/bug37/03_else_removal.py
Normal 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"
|
@@ -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:
|
||||
|
@@ -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
|
||||
|
@@ -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:]
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -7,7 +7,6 @@ SKIP_TESTS=(
|
||||
# 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
|
||||
[test_aepack.py]=1 # Fails on its own
|
||||
@@ -60,9 +59,7 @@ 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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -124,8 +124,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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -30,6 +30,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.
|
||||
|
2
tox.ini
2
tox.ini
@@ -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
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -1,12 +1,12 @@
|
||||
#!/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>
|
||||
#
|
||||
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__))
|
||||
|
||||
@@ -57,7 +57,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)
|
||||
|
@@ -1,10 +1,11 @@
|
||||
#!/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>
|
||||
#
|
||||
import sys, os, getopt, time
|
||||
from xdis.version_info import version_tuple_to_str
|
||||
|
||||
program = 'uncompyle6'
|
||||
|
||||
@@ -62,7 +63,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__)
|
||||
@@ -70,9 +71,12 @@ def usage():
|
||||
|
||||
|
||||
def main_bin():
|
||||
if not (sys.version_info[0:2] in ((2, 4), (2, 5), (2, 6), (2, 7))):
|
||||
sys.stderr.write('Error: this branch of %s requires Python 2.4, 2.5, 2.6 or 2.7'
|
||||
% program)
|
||||
if not (sys.version_info[0:2] in ((2, 4), (2, 5), (2, 6), (2, 7), (3, 0),
|
||||
(3, 1), (3, 2), (3, 3),
|
||||
(3, 4), (3, 5), (3, 6),
|
||||
(3, 7), (3, 8), (3, 9), (3, 10)
|
||||
)):
|
||||
print('Error: %s requires Python 2.4-3.10' % program)
|
||||
sys.exit(-1)
|
||||
|
||||
do_verify = recurse_dirs = False
|
||||
@@ -101,7 +105,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'
|
||||
@@ -193,6 +197,9 @@ def main_bin():
|
||||
mess = status_msg(do_verify, *result)
|
||||
print('# ' + mess)
|
||||
pass
|
||||
except ImportError:
|
||||
print(str(sys.exc_info()[1]))
|
||||
sys.exit(2)
|
||||
except (KeyboardInterrupt):
|
||||
pass
|
||||
except verify.VerifyCmpError:
|
||||
@@ -221,7 +228,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
|
||||
|
@@ -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
|
||||
@@ -33,6 +33,7 @@ import sys
|
||||
from collections import deque
|
||||
|
||||
from xdis import check_object_path, iscode, load_module
|
||||
from xdis.version_info import version_tuple_to_str
|
||||
from uncompyle6.scanner import get_scanner
|
||||
|
||||
|
||||
@@ -45,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
|
||||
real_out.write("# Python %s\n" % version)
|
||||
real_out.write("# Python %s\n" % version_tuple_to_str(version))
|
||||
if co.co_filename:
|
||||
real_out.write("# Embedded file name: %s\n" % co.co_filename)
|
||||
|
||||
|
@@ -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
|
||||
@@ -14,12 +14,13 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import datetime, os, subprocess, sys
|
||||
|
||||
from uncompyle6 import verify, IS_PYPY, PYTHON_VERSION
|
||||
from xdis import iscode, sysinfo2float
|
||||
from uncompyle6 import verify
|
||||
from xdis import iscode
|
||||
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
|
||||
|
||||
@@ -29,7 +30,6 @@ from uncompyle6.semantics.linemap import deparse_code_with_map
|
||||
|
||||
from xdis.load import load_module
|
||||
|
||||
|
||||
def _get_outstream(outfile):
|
||||
dir = os.path.dirname(outfile)
|
||||
failed_file = outfile + "_failed"
|
||||
@@ -66,7 +66,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
|
||||
@@ -75,7 +75,7 @@ def decompile(
|
||||
s += "\n"
|
||||
real_out.write(s)
|
||||
|
||||
assert iscode(co)
|
||||
assert iscode(co), ("%s does not smell like code" % co)
|
||||
|
||||
if is_pypy:
|
||||
co_pypy_str = "PyPy "
|
||||
@@ -97,18 +97,21 @@ def decompile(
|
||||
write("# -*- coding: %s -*-" % source_encoding)
|
||||
write(
|
||||
"# uncompyle6 version %s\n"
|
||||
"# %sPython bytecode %s%s\n# Decompiled from: %sPython %s" %
|
||||
(VERSION,
|
||||
co_pypy_str,
|
||||
bytecode_version,
|
||||
"# %sPython bytecode %s%s\n# Decompiled from: %sPython %s"
|
||||
% (
|
||||
__version__,
|
||||
co_pypy_str,
|
||||
version_tuple_to_str(bytecode_version),
|
||||
" (%s)" % m, run_pypy_str,
|
||||
"\n# ".join(sys_version_lines),
|
||||
)
|
||||
"\n# ".join(sys_version_lines),
|
||||
)
|
||||
)
|
||||
if bytecode_version >= 3.0:
|
||||
write("# Warning: this version has problems handling the Python 3 byte type in constants properly.\n")
|
||||
write(
|
||||
"# Warning: this version of Python 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))
|
||||
@@ -124,12 +127,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,
|
||||
)
|
||||
@@ -161,9 +162,9 @@ def compile_file(source_path):
|
||||
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")
|
||||
@@ -297,7 +298,7 @@ def main(
|
||||
else:
|
||||
buffering = 0
|
||||
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering)
|
||||
if PYTHON_VERSION > 2.6:
|
||||
if PYTHON_VERSION_TRIPLE > (2, 6):
|
||||
tee = subprocess.Popen(["tee", current_outfile],
|
||||
stdin=subprocess.PIPE)
|
||||
os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
|
||||
|
@@ -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
|
||||
@@ -21,9 +21,9 @@ Common uncompyle6 parser routines.
|
||||
|
||||
import sys
|
||||
|
||||
from xdis import iscode, 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):
|
||||
@@ -352,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
|
||||
@@ -621,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()
|
||||
@@ -640,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":
|
||||
@@ -760,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":
|
||||
@@ -875,16 +877,23 @@ 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__":
|
||||
|
||||
def parse_test(co):
|
||||
from uncompyle6 import PYTHON_VERSION, IS_PYPY
|
||||
from xdis.version_info import PYTHON_VERSION_TRIPLE, IS_PYPY
|
||||
|
||||
ast = python_parser(PYTHON_VERSION, co, showasm=True, is_pypy=IS_PYPY)
|
||||
ast = python_parser(PYTHON_VERSION_TRIPLE[:2], co, showasm=True, is_pypy=IS_PYPY)
|
||||
print(ast)
|
||||
return
|
||||
parse_test(parse_test.func_code)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2020 Rocky Bernstein
|
||||
# Copyright (c) 2015-2021 Rocky Bernstein
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
# Copyright (c) 1999 John Aycock
|
||||
@@ -97,9 +97,9 @@ class Python2Parser(PythonParser):
|
||||
for ::= SETUP_LOOP expr for_iter store
|
||||
for_block POP_BLOCK _come_froms
|
||||
|
||||
del_stmt ::= delete_subscript
|
||||
delete ::= delete_subscript
|
||||
delete_subscript ::= expr expr DELETE_SUBSCR
|
||||
del_stmt ::= expr DELETE_ATTR
|
||||
delete ::= expr DELETE_ATTR
|
||||
|
||||
_mklambda ::= load_closure mklambda
|
||||
kwarg ::= LOAD_CONST expr
|
||||
@@ -317,7 +317,7 @@ class Python2Parser(PythonParser):
|
||||
build_count = token.attr
|
||||
thousands = build_count // 1024
|
||||
thirty32s = (build_count // 32) % 32
|
||||
if thirty32s > 0:
|
||||
if thirty32s > 0 or thousands > 0:
|
||||
rule = "expr32 ::=%s" % (" expr" * 32)
|
||||
self.add_unique_rule(rule, opname_base, build_count, customize)
|
||||
if thousands > 0:
|
||||
@@ -348,7 +348,7 @@ class Python2Parser(PythonParser):
|
||||
],
|
||||
customize,
|
||||
)
|
||||
if self.version >= 2.7:
|
||||
if self.version >= (2, 7):
|
||||
self.add_unique_rule(
|
||||
"dict_comp_func ::= BUILD_MAP_n LOAD_FAST FOR_ITER store "
|
||||
"comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST",
|
||||
@@ -421,17 +421,17 @@ class Python2Parser(PythonParser):
|
||||
custom_seen_ops.add(opname)
|
||||
continue
|
||||
elif opname == "DELETE_ATTR":
|
||||
self.addRule("del_stmt ::= expr DELETE_ATTR", nop_func)
|
||||
self.addRule("delete ::= expr DELETE_ATTR", nop_func)
|
||||
custom_seen_ops.add(opname)
|
||||
continue
|
||||
elif opname.startswith("DELETE_SLICE"):
|
||||
self.addRule(
|
||||
"""
|
||||
del_expr ::= expr
|
||||
del_stmt ::= del_expr DELETE_SLICE+0
|
||||
del_stmt ::= del_expr del_expr DELETE_SLICE+1
|
||||
del_stmt ::= del_expr del_expr DELETE_SLICE+2
|
||||
del_stmt ::= del_expr del_expr del_expr DELETE_SLICE+3
|
||||
delete ::= del_expr DELETE_SLICE+0
|
||||
delete ::= del_expr del_expr DELETE_SLICE+1
|
||||
delete ::= del_expr del_expr DELETE_SLICE+2
|
||||
delete ::= del_expr del_expr del_expr DELETE_SLICE+3
|
||||
""",
|
||||
nop_func,
|
||||
)
|
||||
@@ -451,7 +451,7 @@ class Python2Parser(PythonParser):
|
||||
elif opname == "DELETE_SUBSCR":
|
||||
self.addRule(
|
||||
"""
|
||||
del_stmt ::= delete_subscript
|
||||
delete ::= delete_subscript
|
||||
delete_subscript ::= expr expr DELETE_SUBSCR
|
||||
""",
|
||||
nop_func,
|
||||
@@ -575,7 +575,7 @@ class Python2Parser(PythonParser):
|
||||
customize,
|
||||
)
|
||||
|
||||
if self.version >= 2.7:
|
||||
if self.version >= (2, 7):
|
||||
if i > 0:
|
||||
prev_tok = tokens[i - 1]
|
||||
if prev_tok == "LOAD_DICTCOMP":
|
||||
@@ -713,7 +713,7 @@ class Python2Parser(PythonParser):
|
||||
elif lhs in ("raise_stmt1",):
|
||||
# We will assume 'LOAD_ASSERT' will be handled by an assert grammar rule
|
||||
return tokens[first] == "LOAD_ASSERT" and (last >= len(tokens))
|
||||
elif rule == ("or", ("expr_jit", "expr", "\\e_come_from_opt")):
|
||||
elif rule == ("or", ("expr", "jmp_true", "expr", "\\e_come_from_opt")):
|
||||
expr2 = ast[2]
|
||||
return expr2 == "expr" and expr2[0] == "LOAD_ASSERT"
|
||||
elif lhs in ("delete_subscript", "del_expr"):
|
||||
|
@@ -48,7 +48,7 @@ class Python23Parser(Python24Parser):
|
||||
while1stmt ::= _while1test l_stmts JUMP_BACK
|
||||
POP_TOP POP_BLOCK
|
||||
|
||||
list_comp ::= BUILD_LIST_0 DUP_TOP LOAD_ATTR store list_iter del_stmt
|
||||
list_comp ::= BUILD_LIST_0 DUP_TOP LOAD_ATTR store list_iter delete
|
||||
list_for ::= expr for_iter store list_iter JUMP_BACK come_froms POP_TOP JUMP_BACK
|
||||
|
||||
lc_body ::= LOAD_NAME expr CALL_FUNCTION_1 POP_TOP
|
||||
|
@@ -91,7 +91,7 @@ class Python24Parser(Python25Parser):
|
||||
""")
|
||||
super(Python24Parser, self).customize_grammar_rules(tokens, customize)
|
||||
self.remove_rules_24()
|
||||
if self.version == 2.4:
|
||||
if self.version[:2] == (2, 4):
|
||||
self.check_reduce['nop_stmt'] = 'tokens'
|
||||
|
||||
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
||||
|
@@ -97,7 +97,7 @@ class Python25Parser(Python26Parser):
|
||||
return_stmt_lambda LAMBDA_MARKER
|
||||
""")
|
||||
super(Python25Parser, self).customize_grammar_rules(tokens, customize)
|
||||
if self.version == 2.5:
|
||||
if self.version[:2] == (2, 5):
|
||||
self.check_reduce["try_except"] = "tokens"
|
||||
self.check_reduce["aug_assign1"] = "AST"
|
||||
self.check_reduce["ifelsestmt"] = "AST"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2019 Rocky Bernstein
|
||||
# Copyright (c) 2017-2021 Rocky Bernstein
|
||||
"""
|
||||
spark grammar differences over Python2 for Python 2.6.
|
||||
"""
|
||||
@@ -6,6 +6,7 @@ spark grammar differences over Python2 for Python 2.6.
|
||||
from uncompyle6.parser import PythonParserSingle
|
||||
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||
from uncompyle6.parsers.parse2 import Python2Parser
|
||||
from uncompyle6.parsers.reducecheck import (except_handler, tryelsestmt)
|
||||
|
||||
class Python26Parser(Python2Parser):
|
||||
|
||||
@@ -24,7 +25,11 @@ class Python26Parser(Python2Parser):
|
||||
except_handler ::= JUMP_FORWARD COME_FROM except_stmts
|
||||
come_froms_pop END_FINALLY come_froms
|
||||
|
||||
except_handler ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY
|
||||
except_handler ::= JUMP_FORWARD COME_FROM except_stmts
|
||||
END_FINALLY
|
||||
|
||||
except_handler ::= JUMP_FORWARD COME_FROM except_stmts
|
||||
POP_TOP END_FINALLY
|
||||
come_froms
|
||||
|
||||
except_handler ::= jmp_abs COME_FROM except_stmts
|
||||
@@ -33,6 +38,7 @@ class Python26Parser(Python2Parser):
|
||||
except_handler ::= jmp_abs COME_FROM except_stmts
|
||||
END_FINALLY JUMP_FORWARD
|
||||
|
||||
|
||||
# Sometimes we don't put in COME_FROM to the next statement
|
||||
# like we do in 2.7. Perhaps we should?
|
||||
try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||
@@ -87,8 +93,8 @@ class Python26Parser(Python2Parser):
|
||||
|
||||
cf_jb_cf_pop ::= _come_froms JUMP_BACK come_froms POP_TOP
|
||||
|
||||
bp_come_from ::= POP_BLOCK COME_FROM
|
||||
jb_pb_come_from ::= JUMP_BACK bp_come_from
|
||||
pb_come_from ::= POP_BLOCK COME_FROM
|
||||
jb_pb_come_from ::= JUMP_BACK pb_come_from
|
||||
|
||||
_ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM POP_TOP
|
||||
_ifstmts_jump ::= c_stmts_opt JUMP_FORWARD come_froms POP_TOP COME_FROM
|
||||
@@ -142,7 +148,7 @@ class Python26Parser(Python2Parser):
|
||||
while1stmt ::= SETUP_LOOP l_stmts_opt CONTINUE _come_froms
|
||||
|
||||
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_pop POP_BLOCK _come_froms
|
||||
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_cf_pop bp_come_from
|
||||
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_cf_pop pb_come_from
|
||||
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_cf_pop POP_BLOCK
|
||||
whilestmt ::= SETUP_LOOP testexpr returns POP_BLOCK COME_FROM
|
||||
|
||||
@@ -224,15 +230,18 @@ class Python26Parser(Python2Parser):
|
||||
list_iter ::= list_if JUMP_BACK
|
||||
list_iter ::= list_if JUMP_BACK COME_FROM POP_TOP
|
||||
list_comp ::= BUILD_LIST_0 DUP_TOP
|
||||
store list_iter del_stmt
|
||||
store list_iter delete
|
||||
list_comp ::= BUILD_LIST_0 DUP_TOP
|
||||
store list_iter JUMP_BACK del_stmt
|
||||
store list_iter JUMP_BACK delete
|
||||
lc_body ::= LOAD_NAME expr LIST_APPEND
|
||||
lc_body ::= LOAD_FAST expr LIST_APPEND
|
||||
|
||||
comp_for ::= SETUP_LOOP expr for_iter store comp_iter jb_pb_come_from
|
||||
|
||||
comp_body ::= gen_comp_body
|
||||
comp_iter ::= comp_if_not
|
||||
comp_if_not ::= expr jmp_true comp_iter
|
||||
|
||||
comp_body ::= gen_comp_body
|
||||
|
||||
for_block ::= l_stmts_opt _come_froms POP_TOP JUMP_BACK
|
||||
|
||||
@@ -342,18 +351,30 @@ class Python26Parser(Python2Parser):
|
||||
WITH_CLEANUP END_FINALLY
|
||||
""")
|
||||
super(Python26Parser, self).customize_grammar_rules(tokens, customize)
|
||||
self.reduce_check_table = {
|
||||
"except_handler": except_handler,
|
||||
"tryelsestmt": tryelsestmt,
|
||||
"tryelsestmtl": tryelsestmt,
|
||||
}
|
||||
|
||||
|
||||
self.check_reduce['and'] = 'AST'
|
||||
self.check_reduce['assert_expr_and'] = 'AST'
|
||||
self.check_reduce["except_handler"] = "tokens"
|
||||
self.check_reduce["ifstmt"] = "tokens"
|
||||
self.check_reduce["ifelsestmt"] = "AST"
|
||||
self.check_reduce["forelselaststmtl"] = "tokens"
|
||||
self.check_reduce["forelsestmt"] = "tokens"
|
||||
self.check_reduce['list_for'] = 'AST'
|
||||
self.check_reduce['try_except'] = 'tokens'
|
||||
self.check_reduce['tryelsestmt'] = 'AST'
|
||||
self.check_reduce['tryelsestmtl'] = 'AST'
|
||||
|
||||
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
||||
invalid = super(Python26Parser,
|
||||
self).reduce_is_invalid(rule, ast,
|
||||
tokens, first, last)
|
||||
lhs = rule[0]
|
||||
if invalid or tokens is None:
|
||||
return invalid
|
||||
if rule in (
|
||||
@@ -369,7 +390,7 @@ class Python26Parser(Python2Parser):
|
||||
# For now, we won't let the 2nd 'expr' be a "if_exp_not"
|
||||
# However in < 2.6 where we don't have if/else expression it *can*
|
||||
# be.
|
||||
if self.version >= 2.6 and ast[2][0] == "if_exp_not":
|
||||
if self.version >= (2, 6) and ast[2][0] == "if_exp_not":
|
||||
return True
|
||||
|
||||
test_index = last
|
||||
@@ -386,6 +407,26 @@ class Python26Parser(Python2Parser):
|
||||
return not (jmp_target == tokens[test_index].offset or
|
||||
tokens[last].pattr == jmp_false.pattr)
|
||||
|
||||
elif lhs in ("forelselaststmtl", "forelsestmt"):
|
||||
# print("XXX", first, last)
|
||||
# for t in range(first, last):
|
||||
# print(tokens[t])
|
||||
# print("=" * 30)
|
||||
# If the SETUP_LOOP jumps to the tokens[last] then
|
||||
# this is a "for" not a "for else".
|
||||
|
||||
# However, in Python 2.2 and before there is a SET_LINENO
|
||||
# instruction which might have gotten removed. So we need
|
||||
# to account for that. bytecode-1.4/anydbm.pyc exhibits
|
||||
# this behavior.
|
||||
|
||||
# Also we need to use the setup_loop instruction (not opcode)
|
||||
# since the operand can be a relative offset rather than
|
||||
# an absolute offset.
|
||||
setup_inst = self.insts[self.offset2inst_index[tokens[first].offset]]
|
||||
if self.version <= (2, 2) and tokens[last] == "COME_FROM":
|
||||
last += 1
|
||||
return tokens[last-1].off2int() > setup_inst.argval
|
||||
elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")):
|
||||
for i in range(last-1, last-4, -1):
|
||||
t = tokens[i]
|
||||
@@ -402,7 +443,7 @@ class Python26Parser(Python2Parser):
|
||||
# The JUMP_ABSOLUTE has to be to the last POP_TOP or this is invalid
|
||||
ja_attr = ast[4].attr
|
||||
return tokens[last].offset != ja_attr
|
||||
elif rule[0] == 'try_except':
|
||||
elif lhs == 'try_except':
|
||||
# We need to distingush try_except from tryelsestmt and we do that
|
||||
# by checking the jump before the END_FINALLY
|
||||
# If we have:
|
||||
@@ -419,12 +460,12 @@ class Python26Parser(Python2Parser):
|
||||
last -= 1
|
||||
if (tokens[last] == 'COME_FROM'
|
||||
and tokens[last-1] == 'END_FINALLY'
|
||||
and tokens[last-2] == 'POP_TOP'):
|
||||
and tokens[last-2] == 'POP_TOP'):
|
||||
# A jump of 2 is a jump around POP_TOP, END_FINALLY which
|
||||
# would indicate try/else rather than try
|
||||
return (tokens[last-3].kind not in frozenset(('JUMP_FORWARD', 'RETURN_VALUE'))
|
||||
or (tokens[last-3] == 'JUMP_FORWARD' and tokens[last-3].attr != 2))
|
||||
elif rule[0] == 'tryelsestmt':
|
||||
elif lhs == 'tryelsestmt':
|
||||
|
||||
# We need to distingush try_except from tryelsestmt and we do that
|
||||
# by making sure that the jump before the except handler jumps to
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2019 Rocky Bernstein
|
||||
# Copyright (c) 2016-2020 Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <hartmut@goebel.noris.de>
|
||||
|
||||
@@ -7,9 +7,10 @@ from xdis import next_offset
|
||||
from uncompyle6.parser import PythonParserSingle, nop_func
|
||||
from uncompyle6.parsers.parse2 import Python2Parser
|
||||
from uncompyle6.parsers.reducecheck import (
|
||||
aug_assign1_check,
|
||||
or_check,
|
||||
ifelsestmt,
|
||||
tryelsestmt,
|
||||
except_handler,
|
||||
)
|
||||
|
||||
class Python27Parser(Python2Parser):
|
||||
@@ -92,7 +93,7 @@ class Python27Parser(Python2Parser):
|
||||
iflaststmtl ::= testexpr c_stmts
|
||||
|
||||
_ifstmts_jump ::= c_stmts_opt JUMP_FORWARD come_froms
|
||||
bp_come_from ::= POP_BLOCK COME_FROM
|
||||
pb_come_from ::= POP_BLOCK COME_FROM
|
||||
|
||||
# FIXME: Common with 3.0+
|
||||
jmp_false ::= POP_JUMP_IF_FALSE
|
||||
@@ -164,7 +165,7 @@ class Python27Parser(Python2Parser):
|
||||
while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK
|
||||
else_suitel COME_FROM
|
||||
|
||||
while1stmt ::= SETUP_LOOP returns bp_come_from
|
||||
while1stmt ::= SETUP_LOOP returns pb_come_from
|
||||
while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK COME_FROM
|
||||
|
||||
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK _come_froms
|
||||
@@ -231,12 +232,15 @@ class Python27Parser(Python2Parser):
|
||||
# FIXME: Put more in this table
|
||||
self.reduce_check_table = {
|
||||
# "ifelsestmt": ifelsestmt,
|
||||
"aug_assign1": aug_assign1_check,
|
||||
"except_handler": except_handler,
|
||||
"or": or_check,
|
||||
"tryelsestmt": tryelsestmt,
|
||||
"tryelsestmtl": tryelsestmt,
|
||||
}
|
||||
|
||||
self.check_reduce["and"] = "AST"
|
||||
self.check_reduce["aug_assign1"] = "AST"
|
||||
self.check_reduce["if_exp"] = "AST"
|
||||
|
||||
self.check_reduce["except_handler"] = "tokens"
|
||||
|
@@ -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
|
||||
@@ -254,7 +254,7 @@ class Python3Parser(PythonParser):
|
||||
END_FINALLY _jump
|
||||
|
||||
except_var_finalize ::= POP_BLOCK POP_EXCEPT LOAD_CONST COME_FROM_FINALLY
|
||||
LOAD_CONST store del_stmt
|
||||
LOAD_CONST store delete
|
||||
|
||||
except_suite ::= returns
|
||||
|
||||
@@ -538,7 +538,7 @@ class Python3Parser(PythonParser):
|
||||
# FIXME: What's the deal with the two rules? Different Python versions?
|
||||
# Different situations? Note that the above rule is based on the CALL_FUNCTION
|
||||
# token found, while this one doesn't.
|
||||
if self.version < 3.6:
|
||||
if self.version < (3, 6):
|
||||
call_function = self.call_fn_name(call_fn_tok)
|
||||
args_pos, args_kw = self.get_pos_kw(call_fn_tok)
|
||||
rule = "build_class ::= LOAD_BUILD_CLASS mkfunc %s" "%s" % (
|
||||
@@ -593,7 +593,7 @@ class Python3Parser(PythonParser):
|
||||
|
||||
# Note: 3.5+ have subclassed this method; so we don't handle
|
||||
# 'CALL_FUNCTION_VAR' or 'CALL_FUNCTION_EX' here.
|
||||
if is_pypy and self.version >= 3.6:
|
||||
if is_pypy and self.version >= (3, 6):
|
||||
if token == "CALL_FUNCTION":
|
||||
token.kind = self.call_fn_name(token)
|
||||
rule = (
|
||||
@@ -627,7 +627,7 @@ class Python3Parser(PythonParser):
|
||||
"""Python 3.3 added a an addtional LOAD_STR before MAKE_FUNCTION and
|
||||
this has an effect on many rules.
|
||||
"""
|
||||
if self.version >= 3.3:
|
||||
if self.version >= (3, 3):
|
||||
if PYTHON3 or not self.is_pypy:
|
||||
load_op = "LOAD_STR "
|
||||
else:
|
||||
@@ -681,6 +681,7 @@ class Python3Parser(PythonParser):
|
||||
"RAISE",
|
||||
"SETUP",
|
||||
"UNPACK",
|
||||
"WITH",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -775,7 +776,7 @@ class Python3Parser(PythonParser):
|
||||
rule = "kvlist_n ::="
|
||||
self.add_unique_rule(rule, "kvlist_n", 1, customize)
|
||||
rule = "dict ::= BUILD_MAP_n kvlist_n"
|
||||
elif self.version >= 3.5:
|
||||
elif self.version >= (3, 5):
|
||||
if not opname.startswith("BUILD_MAP_WITH_CALL"):
|
||||
# FIXME: Use the attr
|
||||
# so this doesn't run into exponential parsing time.
|
||||
@@ -845,7 +846,7 @@ class Python3Parser(PythonParser):
|
||||
build_count = token.attr
|
||||
thousands = build_count // 1024
|
||||
thirty32s = (build_count // 32) % 32
|
||||
if thirty32s > 0:
|
||||
if thirty32s > 0 or thousands > 0:
|
||||
rule = "expr32 ::=%s" % (" expr" * 32)
|
||||
self.add_unique_rule(rule, opname_base, build_count, customize)
|
||||
pass
|
||||
@@ -934,7 +935,7 @@ class Python3Parser(PythonParser):
|
||||
self.addRule("continue ::= CONTINUE_LOOP", nop_func)
|
||||
custom_ops_processed.add(opname)
|
||||
elif opname == "DELETE_ATTR":
|
||||
self.addRule("del_stmt ::= expr DELETE_ATTR", nop_func)
|
||||
self.addRule("delete ::= expr DELETE_ATTR", nop_func)
|
||||
custom_ops_processed.add(opname)
|
||||
elif opname == "DELETE_DEREF":
|
||||
self.addRule(
|
||||
@@ -948,7 +949,7 @@ class Python3Parser(PythonParser):
|
||||
elif opname == "DELETE_SUBSCR":
|
||||
self.addRule(
|
||||
"""
|
||||
del_stmt ::= delete_subscript
|
||||
delete ::= delete_subscript
|
||||
delete_subscript ::= expr expr DELETE_SUBSCR
|
||||
""",
|
||||
nop_func,
|
||||
@@ -1060,7 +1061,7 @@ class Python3Parser(PythonParser):
|
||||
args_pos, args_kw, annotate_args = token.attr
|
||||
|
||||
# FIXME: Fold test into add_make_function_rule
|
||||
if self.version < 3.3:
|
||||
if self.version < (3, 3):
|
||||
j = 1
|
||||
else:
|
||||
j = 2
|
||||
@@ -1122,7 +1123,7 @@ class Python3Parser(PythonParser):
|
||||
kwargs_str = ""
|
||||
|
||||
# Note order of kwargs and pos args changed between 3.3-3.4
|
||||
if self.version <= 3.2:
|
||||
if self.version <= (3, 2):
|
||||
if annotate_args > 0:
|
||||
rule = (
|
||||
"mkfunc_annotate ::= %s%s%sannotate_tuple load_closure LOAD_CODE %s"
|
||||
@@ -1139,7 +1140,7 @@ class Python3Parser(PythonParser):
|
||||
"pos_arg " * args_pos,
|
||||
opname,
|
||||
)
|
||||
elif self.version == 3.3:
|
||||
elif self.version == (3, 3):
|
||||
if annotate_args > 0:
|
||||
rule = (
|
||||
"mkfunc_annotate ::= %s%s%sannotate_tuple load_closure LOAD_CODE LOAD_STR %s"
|
||||
@@ -1157,7 +1158,7 @@ class Python3Parser(PythonParser):
|
||||
opname,
|
||||
)
|
||||
|
||||
elif self.version >= 3.4:
|
||||
elif self.version >= (3, 4):
|
||||
if PYTHON3 or not self.is_pypy:
|
||||
load_op = "LOAD_STR"
|
||||
else:
|
||||
@@ -1191,7 +1192,7 @@ class Python3Parser(PythonParser):
|
||||
)
|
||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||
|
||||
if self.version < 3.4:
|
||||
if self.version < (3, 4):
|
||||
rule = "mkfunc ::= %sload_closure LOAD_CODE %s" % (
|
||||
"expr " * args_pos,
|
||||
opname,
|
||||
@@ -1201,7 +1202,7 @@ class Python3Parser(PythonParser):
|
||||
pass
|
||||
elif opname_base.startswith("MAKE_FUNCTION"):
|
||||
# DRY with MAKE_CLOSURE
|
||||
if self.version >= 3.6:
|
||||
if self.version >= (3, 6):
|
||||
# The semantics of MAKE_FUNCTION in 3.6 are totally different from
|
||||
# before.
|
||||
args_pos, args_kw, annotate_args, closure = token.attr
|
||||
@@ -1263,7 +1264,7 @@ class Python3Parser(PythonParser):
|
||||
if self.is_pypy or (
|
||||
i >= 2 and tokens[i - 2] == "LOAD_LISTCOMP"
|
||||
):
|
||||
if self.version >= 3.6:
|
||||
if self.version >= (3, 6):
|
||||
# 3.6+ sometimes bundles all of the
|
||||
# 'exprs' in the rule above into a
|
||||
# tuple.
|
||||
@@ -1294,12 +1295,12 @@ class Python3Parser(PythonParser):
|
||||
)
|
||||
continue
|
||||
|
||||
if self.version < 3.6:
|
||||
if self.version < (3, 6):
|
||||
args_pos, args_kw, annotate_args = token.attr
|
||||
else:
|
||||
args_pos, args_kw, annotate_args, closure = token.attr
|
||||
|
||||
if self.version < 3.3:
|
||||
if self.version < (3, 3):
|
||||
j = 1
|
||||
else:
|
||||
j = 2
|
||||
@@ -1340,7 +1341,7 @@ class Python3Parser(PythonParser):
|
||||
else:
|
||||
kwargs = "kwargs"
|
||||
|
||||
if self.version < 3.3:
|
||||
if self.version < (3, 3):
|
||||
# positional args after keyword args
|
||||
rule = "mkfunc ::= %s %s%s%s" % (
|
||||
kwargs,
|
||||
@@ -1354,7 +1355,7 @@ class Python3Parser(PythonParser):
|
||||
"LOAD_CODE ",
|
||||
opname,
|
||||
)
|
||||
elif self.version == 3.3:
|
||||
elif self.version == (3, 3):
|
||||
# positional args after keyword args
|
||||
rule = "mkfunc ::= %s %s%s%s" % (
|
||||
kwargs,
|
||||
@@ -1362,7 +1363,7 @@ class Python3Parser(PythonParser):
|
||||
"LOAD_CODE LOAD_STR ",
|
||||
opname,
|
||||
)
|
||||
elif self.version > 3.5:
|
||||
elif self.version >= (3, 6):
|
||||
# positional args before keyword args
|
||||
rule = "mkfunc ::= %s%s %s%s" % (
|
||||
"pos_arg " * args_pos,
|
||||
@@ -1370,7 +1371,7 @@ class Python3Parser(PythonParser):
|
||||
"LOAD_CODE LOAD_STR ",
|
||||
opname,
|
||||
)
|
||||
elif self.version > 3.3:
|
||||
elif self.version >= (3, 4):
|
||||
# positional args before keyword args
|
||||
rule = "mkfunc ::= %s%s %s%s" % (
|
||||
"pos_arg " * args_pos,
|
||||
@@ -1387,7 +1388,7 @@ class Python3Parser(PythonParser):
|
||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||
|
||||
if re.search("^MAKE_FUNCTION.*_A", opname):
|
||||
if self.version >= 3.6:
|
||||
if self.version >= (3, 6):
|
||||
rule = (
|
||||
"mkfunc_annotate ::= %s%sannotate_tuple LOAD_CODE LOAD_STR %s"
|
||||
% (
|
||||
@@ -1405,11 +1406,11 @@ class Python3Parser(PythonParser):
|
||||
opname,
|
||||
)
|
||||
)
|
||||
if self.version >= 3.3:
|
||||
if self.version >= (3, 3):
|
||||
# Normally we remove EXTENDED_ARG from the opcodes, but in the case of
|
||||
# annotated functions can use the EXTENDED_ARG tuple to signal we have an annotated function.
|
||||
# Yes this is a little hacky
|
||||
if self.version == 3.3:
|
||||
if self.version == (3, 3):
|
||||
# 3.3 puts kwargs before pos_arg
|
||||
pos_kw_tuple = (
|
||||
("kwargs " * args_kw),
|
||||
@@ -1549,7 +1550,7 @@ class Python3Parser(PythonParser):
|
||||
"try_except": tryexcept,
|
||||
}
|
||||
|
||||
if self.version == 3.6:
|
||||
if self.version == (3, 6):
|
||||
self.reduce_check_table["and"] = and_check
|
||||
self.check_reduce["and"] = "AST"
|
||||
|
||||
@@ -1561,7 +1562,7 @@ class Python3Parser(PythonParser):
|
||||
self.check_reduce["ifelsestmtc"] = "AST"
|
||||
self.check_reduce["ifstmt"] = "AST"
|
||||
self.check_reduce["ifstmtl"] = "AST"
|
||||
if self.version == 3.6:
|
||||
if self.version == (3, 6):
|
||||
self.reduce_check_table["iflaststmtl"] = iflaststmt
|
||||
self.check_reduce["iflaststmt"] = "AST"
|
||||
self.check_reduce["iflaststmtl"] = "AST"
|
||||
@@ -1569,7 +1570,7 @@ class Python3Parser(PythonParser):
|
||||
self.check_reduce["testtrue"] = "tokens"
|
||||
if not PYTHON3:
|
||||
self.check_reduce["kwarg"] = "noAST"
|
||||
if self.version < 3.6 and not self.is_pypy:
|
||||
if self.version < (3, 6) and not self.is_pypy:
|
||||
# 3.6+ can remove a JUMP_FORWARD which messes up our testing here
|
||||
# Pypy we need to go over in better detail
|
||||
self.check_reduce["try_except"] = "AST"
|
||||
@@ -1596,11 +1597,11 @@ class Python3Parser(PythonParser):
|
||||
elif lhs == "kwarg":
|
||||
arg = tokens[first].attr
|
||||
return not (isinstance(arg, str) or isinstance(arg, unicode))
|
||||
elif lhs in ("iflaststmt", "iflaststmtl") and self.version == 3.6:
|
||||
elif lhs in ("iflaststmt", "iflaststmtl") and self.version[:2] == (3, 6):
|
||||
return ifstmt(self, lhs, n, rule, ast, tokens, first, last)
|
||||
elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")):
|
||||
# FIXME: go over what's up with 3.0. Evetually I'd like to remove RETURN_END_IF
|
||||
if self.version <= 3.0 or tokens[last] == "RETURN_END_IF":
|
||||
if self.version <= (3, 0) or tokens[last] == "RETURN_END_IF":
|
||||
return False
|
||||
if ifstmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
return True
|
||||
@@ -1642,7 +1643,7 @@ class Python3Parser(PythonParser):
|
||||
if while1stmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
return True
|
||||
|
||||
if self.version == 3.0:
|
||||
if self.version == (3, 0):
|
||||
return False
|
||||
|
||||
if 0 <= last < len(tokens) and tokens[last] in (
|
||||
@@ -1684,7 +1685,7 @@ class Python3Parser(PythonParser):
|
||||
if last == n:
|
||||
return False
|
||||
# 3.8+ Doesn't have SETUP_LOOP
|
||||
return self.version < 3.8 and tokens[first].attr > tokens[last].offset
|
||||
return self.version < (3, 8) and tokens[first].attr > tokens[last].offset
|
||||
elif rule == (
|
||||
"ifelsestmt",
|
||||
(
|
||||
|
@@ -17,15 +17,15 @@ class Python31Parser(Python32Parser):
|
||||
with ::= expr setupwith SETUP_FINALLY
|
||||
suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_FINALLY
|
||||
load del_stmt WITH_CLEANUP END_FINALLY
|
||||
load delete WITH_CLEANUP END_FINALLY
|
||||
|
||||
# Keeps Python 3.1 withas desigator in the same position as it is in other version
|
||||
setupwithas31 ::= setupwithas SETUP_FINALLY load del_stmt
|
||||
setupwithas31 ::= setupwithas SETUP_FINALLY load delete
|
||||
|
||||
withasstmt ::= expr setupwithas31 store
|
||||
suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_FINALLY
|
||||
load del_stmt WITH_CLEANUP END_FINALLY
|
||||
load delete WITH_CLEANUP END_FINALLY
|
||||
|
||||
store ::= STORE_NAME
|
||||
load ::= LOAD_FAST
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2017, 2019 Rocky Bernstein
|
||||
# Copyright (c) 2016-2017, 2019, 2021 Rocky Bernstein
|
||||
"""
|
||||
spark grammar differences over Python 3.4 for Python 3.5.
|
||||
"""
|
||||
@@ -156,7 +156,7 @@ class Python35Parser(Python34Parser):
|
||||
# FIXME: I suspect this is wrong for 3.6 and 3.5, but
|
||||
# I haven't verified what the 3.7ish fix is
|
||||
elif opname == 'BUILD_MAP_UNPACK_WITH_CALL':
|
||||
if self.version < 3.7:
|
||||
if self.version < (3, 7):
|
||||
self.addRule("expr ::= unmapexpr", nop_func)
|
||||
nargs = token.attr % 256
|
||||
map_unpack_n = "map_unpack_%s" % nargs
|
||||
@@ -167,10 +167,9 @@ class Python35Parser(Python34Parser):
|
||||
call_token = tokens[i+1]
|
||||
rule = 'call ::= expr unmapexpr ' + call_token.kind
|
||||
self.addRule(rule, nop_func)
|
||||
elif opname == 'BEFORE_ASYNC_WITH' and self.version < 3.8:
|
||||
elif opname == 'BEFORE_ASYNC_WITH' and self.version < (3, 8):
|
||||
# Some Python 3.5+ async additions
|
||||
rules_str = """
|
||||
async_with_stmt ::= expr
|
||||
stmt ::= async_with_stmt
|
||||
async_with_pre ::= BEFORE_ASYNC_WITH GET_AWAITABLE LOAD_CONST YIELD_FROM SETUP_ASYNC_WITH
|
||||
async_with_post ::= COME_FROM_ASYNC_WITH
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2019 Rocky Bernstein
|
||||
# Copyright (c) 2016-2020 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
|
||||
@@ -304,28 +304,25 @@ class Python36Parser(Python35Parser):
|
||||
self.addRule(rule, nop_func)
|
||||
# Check to combine assignment + annotation into one statement
|
||||
self.check_reduce['assign'] = 'token'
|
||||
elif opname == "WITH_CLEANUP_START":
|
||||
rules_str = """
|
||||
stmt ::= with_null
|
||||
with_null ::= with_suffix
|
||||
with_suffix ::= WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
"""
|
||||
self.addRule(rules_str, nop_func)
|
||||
elif opname == 'SETUP_WITH':
|
||||
rules_str = """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
|
||||
with_suffix
|
||||
|
||||
# Removes POP_BLOCK LOAD_CONST from 3.6-
|
||||
withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
# Removes POP_BLOCK LOAD_CONST from 3.6-
|
||||
withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH
|
||||
with_suffix
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
BEGIN_FINALLY COME_FROM_WITH
|
||||
with_suffix
|
||||
"""
|
||||
if self.version < 3.8:
|
||||
rules_str += """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
LOAD_CONST
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
"""
|
||||
else:
|
||||
rules_str += """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
BEGIN_FINALLY COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH
|
||||
END_FINALLY
|
||||
"""
|
||||
self.addRule(rules_str, nop_func)
|
||||
pass
|
||||
pass
|
||||
@@ -398,7 +395,7 @@ class Python36Parser(Python35Parser):
|
||||
starred ::= expr
|
||||
call_ex ::= expr starred CALL_FUNCTION_EX
|
||||
""", nop_func)
|
||||
if self.version >= 3.6:
|
||||
if self.version >= (3, 6):
|
||||
if 'BUILD_MAP_UNPACK_WITH_CALL' in self.seen_ops:
|
||||
self.addRule("""
|
||||
expr ::= call_ex_kw
|
||||
|
@@ -93,6 +93,9 @@ class Python37Parser(Python37BaseParser):
|
||||
else_suitec ::= c_stmts
|
||||
else_suitec ::= returns
|
||||
|
||||
else_suite_opt ::= else_suite
|
||||
else_suite_opt ::= pass
|
||||
|
||||
stmt ::= classdef
|
||||
stmt ::= call_stmt
|
||||
|
||||
@@ -109,10 +112,10 @@ class Python37Parser(Python37BaseParser):
|
||||
stmt ::= tryelsestmt
|
||||
stmt ::= tryfinallystmt
|
||||
|
||||
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
|
||||
return ::= ret_expr RETURN_VALUE
|
||||
@@ -634,6 +637,12 @@ class Python37Parser(Python37BaseParser):
|
||||
if_exp37 ::= expr expr jf_cfs expr COME_FROM
|
||||
jf_cfs ::= JUMP_FORWARD _come_froms
|
||||
ifelsestmt ::= testexpr c_stmts_opt jf_cfs else_suite opt_come_from_except
|
||||
|
||||
# This is probably more realistically an "ifstmt" (with a null else)
|
||||
# see _cmp() of python3.8/distutils/__pycache__/version.cpython-38.opt-1.pyc
|
||||
ifelsestmt ::= testexpr stmts jf_cfs else_suite_opt opt_come_from_except
|
||||
|
||||
|
||||
expr_pjit ::= expr POP_JUMP_IF_TRUE
|
||||
expr_jit ::= expr JUMP_IF_TRUE
|
||||
expr_jt ::= expr jmp_true
|
||||
@@ -879,7 +888,7 @@ class Python37Parser(Python37BaseParser):
|
||||
END_FINALLY _jump
|
||||
|
||||
except_var_finalize ::= POP_BLOCK POP_EXCEPT LOAD_CONST COME_FROM_FINALLY
|
||||
LOAD_CONST store del_stmt
|
||||
LOAD_CONST store delete
|
||||
|
||||
except_suite ::= returns
|
||||
|
||||
@@ -1282,7 +1291,7 @@ class Python37Parser(Python37BaseParser):
|
||||
withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
"""
|
||||
if self.version < 3.8:
|
||||
if self.version < (3, 8):
|
||||
rules_str += """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
LOAD_CONST
|
||||
|
@@ -127,6 +127,7 @@ class Python37BaseParser(PythonParser):
|
||||
"RAISE",
|
||||
"SETUP",
|
||||
"UNPACK",
|
||||
"WITH",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -208,7 +209,7 @@ class Python37BaseParser(PythonParser):
|
||||
stmt ::= async_with_as_stmt
|
||||
"""
|
||||
|
||||
if self.version < 3.8:
|
||||
if self.version < (3, 8):
|
||||
rules_str += """
|
||||
stmt ::= async_with_stmt SETUP_ASYNC_WITH
|
||||
c_stmt ::= c_async_with_stmt SETUP_ASYNC_WITH
|
||||
@@ -540,7 +541,7 @@ class Python37BaseParser(PythonParser):
|
||||
self.addRule("continue ::= CONTINUE_LOOP", nop_func)
|
||||
custom_ops_processed.add(opname)
|
||||
elif opname == "DELETE_ATTR":
|
||||
self.addRule("del_stmt ::= expr DELETE_ATTR", nop_func)
|
||||
self.addRule("delete ::= expr DELETE_ATTR", nop_func)
|
||||
custom_ops_processed.add(opname)
|
||||
elif opname == "DELETE_DEREF":
|
||||
self.addRule(
|
||||
@@ -554,7 +555,7 @@ class Python37BaseParser(PythonParser):
|
||||
elif opname == "DELETE_SUBSCR":
|
||||
self.addRule(
|
||||
"""
|
||||
del_stmt ::= delete_subscript
|
||||
delete ::= delete_subscript
|
||||
delete_subscript ::= expr expr DELETE_SUBSCR
|
||||
""",
|
||||
nop_func,
|
||||
@@ -993,55 +994,70 @@ class Python37BaseParser(PythonParser):
|
||||
)
|
||||
custom_ops_processed.add(opname)
|
||||
|
||||
elif opname == "WITH_CLEANUP_START":
|
||||
rules_str = """
|
||||
stmt ::= with_null
|
||||
with_null ::= with_suffix
|
||||
with_suffix ::= WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
"""
|
||||
self.addRule(rules_str, nop_func)
|
||||
elif opname == "SETUP_WITH":
|
||||
rules_str = """
|
||||
stmt ::= with
|
||||
stmt ::= withasstmt
|
||||
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with ::= expr
|
||||
SETUP_WITH POP_TOP
|
||||
suite_stmts_opt
|
||||
COME_FROM_WITH
|
||||
with_suffix
|
||||
withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with_suffix
|
||||
|
||||
with ::= expr
|
||||
SETUP_WITH POP_TOP
|
||||
suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
with_suffix
|
||||
|
||||
withasstmt ::= expr
|
||||
SETUP_WITH store suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
with_suffix
|
||||
|
||||
with ::= expr
|
||||
SETUP_WITH POP_TOP suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with_suffix
|
||||
withasstmt ::= expr
|
||||
SETUP_WITH store suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
|
||||
with ::= expr
|
||||
SETUP_WITH POP_TOP suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
withasstmt ::= expr
|
||||
SETUP_WITH store suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with_suffix
|
||||
"""
|
||||
if self.version < 3.8:
|
||||
if self.version < (3, 8):
|
||||
rules_str += """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
LOAD_CONST
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with_suffix
|
||||
"""
|
||||
else:
|
||||
rules_str += """
|
||||
with ::= expr
|
||||
with ::= expr
|
||||
SETUP_WITH POP_TOP suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with_suffix
|
||||
|
||||
withasstmt ::= expr
|
||||
SETUP_WITH store suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
withasstmt ::= expr
|
||||
SETUP_WITH store suite_stmts
|
||||
POP_BLOCK BEGIN_FINALLY COME_FROM_WITH with_suffix
|
||||
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
BEGIN_FINALLY COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH
|
||||
END_FINALLY
|
||||
with_suffix
|
||||
"""
|
||||
self.addRule(rules_str, nop_func)
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user