Compare commits

...

20 Commits

Author SHA1 Message Date
rocky
84e8542248 Get ready for release 3.2.5 2018-12-30 12:15:57 -05:00
rocky
fe9beb2fd1 Use raw string in regexp with "\d"...
Bump python versions used in testing
2018-12-26 19:06:21 -05:00
rocky
7de893730d main.main parameter "codes" is not used. Note that. 2018-12-25 12:55:40 -05:00
rocky
a7ceedb62c Python 3.6+ control flow 2018-12-15 09:17:54 -05:00
rocky
49999b2633 Merge branch 'master' of github.com:rocky/python-uncompyle6 2018-12-15 09:12:35 -05:00
rocky
ffad6ae6d5 Some more typos 2018-12-15 09:11:41 -05:00
rocky
d250d38b39 Typo 2018-12-15 05:15:37 -05:00
rocky
4a76a4f591 Add karma section 2018-12-15 05:11:50 -05:00
rocky
f5448b371c More complete fragment parsing for imports 2018-12-10 06:40:14 -05:00
rocky
55a73d5a29 CI runtest skips 2018-11-12 11:03:15 -05:00
rocky
dc0b243938 CI runtest skips 2018-11-12 10:51:17 -05:00
rocky
99fc7f9873 runtests on CI again 2018-11-12 10:34:30 -05:00
rocky
3b7c8cf092 runtests on CI again 2018-11-12 10:29:22 -05:00
rocky
5abfe7c85a Typo in last test name 2018-11-12 09:50:46 -05:00
rocky
7fa21d0db4 More stdlib test removal 2018-11-12 09:19:46 -05:00
rocky
d422f28d2e Another test bites the dust due to control flow complexity 2018-11-12 07:32:33 -05:00
rocky
f3cd1ee3f3 Add FIXME not for attribute parenthesis 2018-11-12 03:48:44 -05:00
rocky
de6dec6ecd Control flow bits again 2018-11-11 14:11:23 -05:00
rocky
fbcf91954e Correct the last release date 2018-10-27 13:03:59 -04:00
rocky
350a16cfa2 Administrivia 2018-10-27 12:54:25 -04:00
15 changed files with 106 additions and 30 deletions

View File

@@ -1,6 +1,21 @@
# How to report a Bug
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
**Table of Contents**
## The difficulty of the problem
- [The difficulty of the problem](#the-difficulty-of-the-problem)
- [Is it really a bug?](#is-it-really-a-bug)
- [Do you have valid bytecode?](#do-you-have-valid-bytecode)
- [Semantic equivalence vs. exact source code](#semantic-equivalence-vs-exact-source-code)
- [What to send (minimum requirements)](#what-to-send-minimum-requirements)
- [What to send (additional helpful information)](#what-to-send-additional-helpful-information)
- [But I don't *have* the source code!](#but-i-dont-have-the-source-code)
- [But I don't *have* the source code and am incapable of figuring how how to do a hand disassembly!](#but-i-dont-have-the-source-code-and-am-incapable-of-figuring-how-how-to-do-a-hand-disassembly)
- [Narrowing the problem](#narrowing-the-problem)
- [Karma](#karma)
- [Confidentiality of Bug Reports](#confidentiality-of-bug-reports)
- [Ethics](#ethics)
<!-- markdown-toc end -->
# The difficulty of the problem
This decompiler is a constant work in progress: Python keeps
changing, and so does its code generation.
@@ -41,10 +56,10 @@ bugs you may have an interest in. If you require decompiling bytecode
immediately, consider using a decompilation service, listed further
down in this document.
## Is it really a bug?
# Is it really a bug?
### Do you have valid bytecode?
## 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
@@ -55,11 +70,11 @@ Python comes with a disassembly module called `dis`. A prerequisite
module for this package, `xdis` has a cross-python version
disassembler called `pydisasm`.
### Semantic equivalence vs. exact source code
## Semantic equivalence vs. exact source code
Consider how Python compiles something like "(x*y) + 5". Early on
Python creates an "abstract syntax tree" (AST) for this. And this is
"abstract" in the sense that unimportant, redundant or unnecceary
"abstract" in the sense that unimportant, redundant or unnecessary
items have been removed. Here, this means that any notion that you
wrote "x+y" in parenthesis is lost, since in this context they are
unneeded. Also lost is the fact that the multiplication didn't have
@@ -132,7 +147,7 @@ Python will eliminate the entire "if" statement.
So just because the text isn't the same, does not
necessarily mean there's a bug.
## What to send (minimum requirements)
# What to send (minimum requirements)
The basic requirement is pretty simple:
@@ -146,7 +161,7 @@ sending is too large.
Also try to narrow the bug. See below.
## What to send (additional helpful information)
# What to send (additional helpful information)
Some kind folks also give the invocation they used and the output
which usually includes an error message produced. This is
@@ -159,7 +174,7 @@ provide the input command and the output from that, please give:
* Python interpreter version used
### But I don't *have* the source code!
## 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,
@@ -167,7 +182,7 @@ use `pydisasm` from the [xdis](https://pypi.python.org/pypi/xdis)
package. Opcodes are described in the documentation for
the [dis](https://docs.python.org/3.6/library/dis.html) module.
### But I don't *have* the source code and am incapable of figuring how how to do a hand disassembly!
### 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
@@ -179,7 +194,7 @@ 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
# 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).
@@ -197,22 +212,53 @@ what doesn't. That is useful. Or maybe the same file will decompile
properly on a neighboring version of Python. That is helpful too.
In sum, the more you can isolate or narrow the problem, the more
likley the problem will be fixed and fixed sooner.
likely the problem will be fixed and fixed sooner.
## Confidentiality of Bug Reports
# 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
in the category of bug fixers.
The barrier to reporting a big is pretty small: all you really need is
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.
So one factors 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. 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
When you report a bug, you are giving up confidentiality to the source
code and the byte code. However, I would imagine that if you have
narrowed the problem sufficiently, confidentiality of the little that
remains would not be an issue.
However feel free to remove any commments, and modify variable names
However feel free to remove any comments, and modify variable names
or constants in the source code.
## Ethics
# Ethics
I do not condone using this program for unethical or illegal purposes.
More detestful, at least to me, is asking for help to assist you in
More detestable, at least to me, is asking for help to assist you in
something that might not legitimate.
Don't use the issue tracker for such solicitations. To try to stave

9
NEWS
View File

@@ -1,4 +1,11 @@
uncompyle6 3.2.4 2018-06-04 7x9 release
uncompyle6 3.2.5 2019-12-30 Clearout sale
- 3.7.2 Remove deprecation warning on regexp string that isn't raw
- main.main() parameter `codes` is not used - note that
- Improve Python 3.6+ control flow detection
- More complete fragment instruction annotation for `imports`
uncompyle6 3.2.4 2018-10-27 7x9 release
- Bug fixes #180, #182, #187, #192
- Enhancements #189

View File

@@ -57,7 +57,7 @@ entry_points = {
]}
ftp_url = None
install_requires = ['spark-parser >= 1.8.7, < 1.9.0',
'xdis >= 3.8.8, < 3.9.0']
'xdis >= 3.8.9, < 3.9.0']
license = 'GPL3'
mailing_list = 'python-debugger@googlegroups.com'

View File

@@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
echo "This script should be *sourced* rather than run directly through bash"
exit 1
fi
export PYVERSIONS='3.5.5 3.6.6 3.7.1 2.6.9 3.3.7 2.7.14 3.2.6 3.1.5 3.4.8'
export PYVERSIONS='3.5.5 3.6.8 3.7.2 2.6.9 3.3.7 2.7.15 3.2.6 3.1.5 3.4.8'

Binary file not shown.

View File

@@ -115,13 +115,20 @@ case $PYVERSION in
# See test/simple_source/bug27+/05_not_unconditional.py
[test_memoryio.py]=1 # FIX
[test_multiprocessing.py]=1 # On uncompyle2, taks 24 secs
[test_pep352.py]=1 # ?
[test_pep352.py]=1 # ?
[test_posix.py]=1 # Bug in try-else detection inside test_initgroups()
# Deal with when we have better flow-control detection
[test_pwd.py]=1 # Takes too long
[test_pty.py]=1
[test_queue.py]=1 # Control flow?
[test_re.py]=1 # Probably Control flow?
[test_select.py]=1 # Runs okay but takes 11 seconds
[test_socket.py]=1 # Runs ok but takes 22 seconds
[test_subprocess.py]=1 # Runs ok but takes 22 seconds
[test_sys_settrace.py]=1 # Line numbers are expected to be different
[test_strtod.py]=1 # FIX
[test_traceback.py]=1 # Line numbers change - duh.
[test_types.py]=1 # try/else confusions
[test_unicode.py]=1 # Too long to run 11 seconds
[test_xpickle.py]=1 # Runs ok but takes 72 seconds
[test_zipfile64.py]=1 # Runs ok but takes 204 seconds

View File

@@ -177,7 +177,7 @@ def main_bin():
if numproc <= 1:
try:
result = main(src_base, out_base, files, codes, outfile,
result = main(src_base, out_base, files, None, outfile,
**options)
result = list(result) + [options.get('do_verify', None)]
if len(files) > 1:
@@ -212,7 +212,7 @@ def main_bin():
if f is None:
break
(t, o, f, v) = \
main(src_base, out_base, [f], codes, outfile, **options)
main(src_base, out_base, [f], None, outfile, **options)
tot_files += t
okay_files += o
failed_files += f

View File

@@ -158,9 +158,11 @@ def main(in_base, out_base, files, codes, outfile=None,
"""
in_base base directory for input files
out_base base directory for output files (ignored when
files list of filenames to be uncompyled (relative to src_base)
files list of filenames to be uncompyled (relative to in_base)
outfile write output to this filename (overwrites out_base)
Note: `codes` is not use. Historical compatability?
For redirecting output to
- <filename> outfile=<filename> (out_base is ignored)
- files below out_base out_base=...

View File

@@ -158,8 +158,10 @@ class Python2Parser(PythonParser):
try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
except_handler COME_FROM
# Note: except_stmts may have many jumps after END_FINALLY
except_handler ::= JUMP_FORWARD COME_FROM except_stmts
END_FINALLY COME_FROM
END_FINALLY come_froms
except_handler ::= jmp_abs COME_FROM except_stmts
END_FINALLY

View File

@@ -263,7 +263,7 @@ if __name__ == '__main__':
""".split()))
remain_tokens = set(tokens) - opcode_set
import re
remain_tokens = set([re.sub('_\d+$', '', t)
remain_tokens = set([re.sub(r'_\d+$', '', t)
for t in remain_tokens])
remain_tokens = set([re.sub('_CONT$', '', t)
for t in remain_tokens])

View File

@@ -42,6 +42,11 @@ class Python36Parser(Python35Parser):
whilestmt ::= SETUP_LOOP testexpr l_stmts_opt
JUMP_BACK come_froms POP_BLOCK COME_FROM_LOOP
# 3.6 due to jump optimization, we sometimes add RETURN_END_IF where
# RETURN_VALUE is meant. Specifcally this can happen in
# ifelsestmt -> ...else_suite _. suite_stmts... (last) stmt
return ::= ret_expr RETURN_END_IF
# A COME_FROM is dropped off because of JUMP-to-JUMP optimization
and ::= expr jmp_false expr
and ::= expr jmp_false expr jmp_false

View File

@@ -957,8 +957,6 @@ class Scanner3(Scanner):
elif op == self.opc.POP_EXCEPT:
next_offset = xdis.next_offset(op, self.opc, offset)
target = self.get_target(next_offset)
if target is None:
from trepan.api import debug; debug()
if target > next_offset:
next_op = code[next_offset]
if (self.opc.JUMP_ABSOLUTE == next_op and
@@ -986,8 +984,9 @@ class Scanner3(Scanner):
# In RETURN_VALUE, JUMP_ABSOLUTE, RETURN_VALUE is never RETURN_END_IF
if op == self.opc.RETURN_VALUE:
next_offset = xdis.next_offset(op, self.opc, offset)
if (next_offset < len(code) and code[next_offset] == self.opc.JUMP_ABSOLUTE and
offset in self.return_end_ifs):
if ( next_offset < len(code) and
(code[next_offset] == self.opc.JUMP_ABSOLUTE and
offset in self.return_end_ifs) ):
self.return_end_ifs.remove(offset)
pass
pass

View File

@@ -105,6 +105,9 @@ TABLE_DIRECT_FRAGMENT = {
'pass': ( '%|%rpass\n', ),
'raise_stmt0': ( '%|%rraise\n', ),
'import': ( '%|import %c%x\n', 2, (2, (0, 1)), ),
'import_cont': ( ', %c%x', (2, 'alias'), (2, (0, 1)), ),
'import_from': ( '%|from %[2]{pattr}%x import %c\n',
(2, (0, 1)), (3, 'importlist'), ),
'importfrom': ( '%|from %[2]{pattr}%x import %c\n', (2, (0, 1)), 3),
# FIXME only in <= 2.4

View File

@@ -1779,6 +1779,11 @@ class SourceWalker(GenericASTTraversal, object):
def n_attribute(self, node):
if (node[0] == 'LOAD_CONST' or
node[0] == 'expr' and node[0][0] == 'LOAD_CONST'):
# FIXME: I didn't record which constants parenthesis is
# necessary. However, I suspect that we could further
# refine this by looking at operator precedence and
# eval'ing the constant value (pattr) and comparing with
# the type of the constant.
node.kind = 'attribute_w_parens'
self.default(node)

View File

@@ -12,4 +12,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This file is suitable for sourcing inside bash as
# well as importing into Python
VERSION='3.2.4'
VERSION='3.2.5'