Compare commits

...

64 Commits

Author SHA1 Message Date
rocky
ce5066bddb Merge branch 'master' into python-2.4 2017-08-15 11:12:20 -04:00
rocky
93f18e2449 Allow version to be string...
in get_python_parser and get_scanner
2017-08-13 09:23:27 -04:00
rocky
783e62f3ca Merge branch 'python-2.4' of github.com:rocky/python-uncompyle6 into python-2.4 2017-08-10 09:45:11 -04:00
rocky
c38dc61021 xdis "is not" is now "is-not" 2017-08-09 22:07:32 -04:00
rocky
45782bbb39 Get ready for release 2.11.3 2017-08-09 21:46:27 -04:00
rocky
4c9cd5657e Merge branch 'master' into python-2.4 2017-08-09 21:45:50 -04:00
rocky
dc627d13b8 Get ready for release 2.11.3 2017-08-09 21:33:01 -04:00
rocky
ddc3489991 Python 2.4 comptiability and ...
exception match -> exception-match
2017-08-03 03:48:57 -04:00
rocky
5b24c20331 Bump xdis 2017-08-02 08:37:50 -04:00
rocky
8bb01143d8 Remove six from python 2.4/2.5 2017-08-02 08:28:08 -04:00
rocky
a9635da96a in xdis "exception match" is now "exception-match" 2017-08-02 06:36:40 -04:00
rocky
e790cb75fd Python 2.4 doesn't do six 2017-08-02 06:20:07 -04:00
rocky
348afeebbf Python 2.4 compatibility 2017-08-01 22:32:43 -04:00
rocky
6888553773 Merge branch 'master' into python-2.4 2017-06-25 18:56:31 -04:00
rocky
0f489672b9 More merge fixups from master 2017-06-18 16:05:22 -04:00
rocky
b7d8cbfaf5 Merge branch 'master' into python-2.4 2017-06-18 15:40:40 -04:00
rocky
df8d253f78 2.4 doesn't do six 2017-06-03 06:00:47 -04:00
rocky
89b42e3696 Nope it (appveyor) doesn't. 2017-06-03 05:55:21 -04:00
rocky
22e5a4a283 Administrivia
See if appveyor will handle 2.5
2017-06-03 05:53:41 -04:00
rocky
61810172d1 Merge branch 'master' into python-2.4 2017-06-03 05:50:42 -04:00
rocky
658c8b4be7 No decorators in Python < 2.6 2017-05-30 02:30:56 -04:00
rocky
d4dab54c7b Merge branch 'master' into python-2.4 2017-05-30 02:18:57 -04:00
rocky
5566b9ba6c Get ready for release 2.9.11 2017-05-06 07:49:09 -04:00
rocky
e56ab2dcd5 Sync with master 2017-05-06 07:17:04 -04:00
rocky
d6c45979ba Merge branch 'master' into python-2.4 2017-05-06 07:16:39 -04:00
rocky
a06e9bf32e Merge branch 'master' into python-2.4 2017-04-14 05:45:53 -04:00
rocky
7e8f7ba674 namedtuple25 -> namedtuple24 2017-04-14 05:42:44 -04:00
rocky
09eb7f7f78 Merge branch 'master' into python-2.4 2017-04-10 00:48:04 -04:00
rocky
f7a910ec66 Merge branch 'master' into python-2.4 2017-03-01 05:55:26 -05:00
rocky
6d6a73eea7 Merge branch 'master' into python-2.4 2017-02-25 21:02:12 -05:00
rocky
e4a7641927 Python <= 2.6 grammar fixes 2017-02-25 05:13:19 -05:00
rocky
b24b46d48c Merge branch 'master' into python-2.4 2017-02-25 04:48:06 -05:00
rocky
a65d7dce5b Python 2.5 was missing try else stmt 2017-02-22 05:30:07 -05:00
rocky
718a0a5d34 Merge branch 'master' into python-2.4 2017-02-22 05:29:49 -05:00
rocky
ea9e3ab3f5 Group coverage Makefile targets 2017-02-10 01:00:26 -05:00
rocky
770e988ff8 Changes based on coverage information 2017-01-29 22:54:30 -05:00
rocky
0fa0641974 Merge branch 'master' into python-2.4 2017-01-29 22:05:55 -05:00
rocky
c13e23cdae Get ready for release 2.9.9 2017-01-11 21:52:20 -05:00
rocky
fab4ebb768 Merge changes ...
* str() in Python 2.4 doesn't detect unicode.
* index() doesn't work on tuples
* ifelse change
2017-01-11 19:34:28 -05:00
rocky
89429339fa Merge branch 'master' into python-2.4 2017-01-11 19:25:44 -05:00
rocky
6ed129bd7a 2.4 verify hacks 2017-01-02 07:15:46 -05:00
rocky
c4fde6b53e Merge branch 'master' into python-2.4 2017-01-02 05:39:50 -05:00
rocky
a7d93e88b4 Merge branch 'master' into python-2.4 2017-01-02 05:39:13 -05:00
rocky
9891494142 We are version 2.9.9 2016-12-31 18:16:23 -05:00
rocky
f8544dfbbe 2.7->2.4 conversion 2016-12-31 10:56:43 -05:00
rocky
b00651d428 Merge master branche
Handle 2.2 list_if
2016-12-31 05:19:21 -05:00
rocky
da8dccbaca Merge branch 'master' into python-2.4 2016-12-29 02:08:12 -05:00
rocky
37272ae827 Merge commit '9b1dd0f' into python-2.4 2016-12-27 10:32:25 -05:00
rocky
7f2bee46b7 Bug in using python2 ast checking in python 2.5 2016-12-26 01:55:16 -05:00
rocky
c8a4dcf72b Removing NAME_MODULE, lint and bug fixes
scanner*.py: show_asm param is optional
verify.py: call correct scanners
main.py, verify.py: Use older Python print statements
2016-12-25 09:16:04 -05:00
rocky
012ff91cfb Merge branch 'master' into python-2.4 2016-12-25 07:57:17 -05:00
rocky
e690ddd50a Merge branch 'master' into python-2.4 2016-12-18 07:43:15 -05:00
rocky
45b7c1948c show-asm on python2.5 is optional
Make scanner2 a little more like scanner3.
2016-12-17 07:57:31 -05:00
rocky
e2fb7ca3d2 Python 2.6/2.7 tolerance in Python 2.4 branch 2016-12-17 06:51:47 -05:00
rocky
b3bda76582 Merge branch 'master' into python-2.4 2016-12-16 22:56:07 -05:00
rocky
ab6d322eca Get ready for release 2.9.7 2016-12-04 14:09:53 -05:00
rocky
1a8a0df107 Merge branch 'master' into python-2.4 2016-12-04 13:40:06 -05:00
rocky
0a37709b0a CircleCI build 2016-11-24 05:41:31 -05:00
rocky
98cd1417df Remove dup Python 3 grammar rule 2016-11-24 05:36:43 -05:00
rocky
460069ceaa Bug in 2.4 "if" dectection and...
Wrong language used in old-style exceptions: use "except Error,e" not
"except Error(e)""
2016-11-24 05:15:35 -05:00
rocky
316aa44f23 Python 2.6 grammary bug and..
__pkginfo.py__: Bump spark_parser version for parse_flags 'dups'
2016-11-24 04:09:32 -05:00
rocky
7133540c23 Make work on 2.4 2016-11-23 08:26:12 -05:00
rocky
590231741d Merge branch 'come-from-type' into python-2.4 2016-11-23 07:54:18 -05:00
rocky
a9349b8f3d Making it run on Python 2.4 and 2.5 2016-11-23 07:53:51 -05:00
57 changed files with 617 additions and 706 deletions

View File

@@ -3,13 +3,7 @@ language: python
sudo: false sudo: false
python: python:
- '3.5' - '2.7' # this is a cheat here because travis doesn't do 2.4-2.6
- '2.7.12'
- '2.6'
- '3.3'
- '3.4'
- '3.2'
- '3.6'
install: install:
- pip install -e . - pip install -e .

323
ChangeLog
View File

@@ -1,29 +1,37 @@
2017-08-15 rocky <rb@dustyfeet.com>
* uncompyle6/version.py: Get ready for release 2.11.4
2017-08-15 rocky <rb@dustyfeet.com>
* __pkginfo__.py, pytest/validate.py, uncompyle6/parser.py,
uncompyle6/scanner.py: Misc cleanups... remove code now in xdis require at least xdis 3.5.4 PyPy tolerance
in validate testing
2017-08-13 rocky <rb@dustyfeet.com> 2017-08-13 rocky <rb@dustyfeet.com>
* pytest/test_basic.py, uncompyle6/parser.py, uncompyle6/scanner.py: * ChangeLog, README.rst, __pkginfo__.py, pytest/test_basic.py,
Allow 3-part version string lookups, e.g 2.7.1 We allow a float here, but if passed a string like '2.7'. or uncompyle6/parser.py, uncompyle6/scanner.py: Allow version to be
'2.7.13', accept that in looking up either a scanner or a parser. string... in get_python_parser and get_scanner
2017-08-10 rocky <rb@dustyfeet.com> 2017-08-10 rocky <rb@dustyfeet.com>
* README.rst: Link typo Name is trepan2 now not trepan * : commit c38dc61021368f11e95cef70ee77e4a43dba1598 Author: rocky
<rb@dustyfeet.com> Date: Wed Aug 9 22:01:59 2017 -0400
2017-08-09 rocky <rb@dustyfeet.com> 2017-08-09 rocky <rb@dustyfeet.com>
* ChangeLog, NEWS, README.rst, __pkginfo__.py, * ChangeLog: Get ready for release 2.11.3
uncompyle6/semantics/consts.py, uncompyle6/version.py: Get ready for
release 2.11.3 need xdis 3.5.1 for now. Adjust for xdis "is-not" which we need as 2017-08-09 rocky <rb@dustyfeet.com>
"is not"
* : commit dc627d13b8455ded4bf708a596bb466f9df9bf7b Author: rocky
<rb@dustyfeet.com> Date: Wed Aug 9 21:19:30 2017 -0400
2017-08-03 rocky <rb@dustyfeet.com>
* pytest/test_deparse.py, pytest/test_docstring.py,
pytest/test_fjt.py, pytest/test_single_compile.py,
pytest/validate.py, uncompyle6/scanners/scanner3.py,
uncompyle6/scanners/scanner30.py: Python 2.4 comptiability and ... exception match -> exception-match
2017-08-02 rocky <rb@dustyfeet.com>
* __pkginfo__.py: Bump xdis
2017-08-02 rocky <rb@dustyfeet.com>
* __pkginfo__.py: Remove six from python 2.4/2.5
2017-08-02 rocky <rb@dustyfeet.com> 2017-08-02 rocky <rb@dustyfeet.com>
@@ -33,6 +41,20 @@
* __pkginfo__.py: Remove six from Python-2.4/2.5 package * __pkginfo__.py: Remove six from Python-2.4/2.5 package
2017-08-02 rocky <rb@dustyfeet.com>
* uncompyle6/scanners/scanner3.py: in xdis "exception match" is now
"exception-match"
2017-08-02 rocky <rb@dustyfeet.com>
* __pkginfo__.py: Python 2.4 doesn't do six
2017-08-01 rocky <rb@dustyfeet.com>
* pytest/validate.py, test/dis-compare.py,
test/simple-uncompyle-code-test.py: Python 2.4 compatibility
2017-07-17 rocky <rb@dustyfeet.com> 2017-07-17 rocky <rb@dustyfeet.com>
* __pkginfo__.py, uncompyle6/scanners/scanner2.py, * __pkginfo__.py, uncompyle6/scanners/scanner2.py,
@@ -97,10 +119,8 @@
2017-06-25 rocky <rb@dustyfeet.com> 2017-06-25 rocky <rb@dustyfeet.com>
* ChangeLog, NEWS, test/simple_source/bug31/04_def_annotate.py, * : commit 9c072a6a423d8379712296dbcd499c772ba7ef59 Author: rocky
uncompyle6/semantics/make_function.py, <rb@dustyfeet.com> Date: Sun Jun 25 18:44:50 2017 -0400
uncompyle6/semantics/pysource.py: 3.x funciton and annotation bug
fixes
2017-06-25 rocky <rb@dustyfeet.com> 2017-06-25 rocky <rb@dustyfeet.com>
@@ -125,8 +145,14 @@
2017-06-18 rocky <rb@dustyfeet.com> 2017-06-18 rocky <rb@dustyfeet.com>
* ChangeLog, NEWS, uncompyle6/version.py: Get ready for release * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py,
2.11.0 uncompyle6/semantics/fragments.py,
uncompyle6/semantics/make_function.py: More merge fixups from master
2017-06-18 rocky <rb@dustyfeet.com>
* : commit af10f99776b142c44fb4507033fb3220b5f57910 Author: rocky
<rb@dustyfeet.com> Date: Sun Jun 18 15:22:27 2017 -0400
2017-06-13 rocky <rb@dustyfeet.com> 2017-06-13 rocky <rb@dustyfeet.com>
@@ -221,7 +247,20 @@
2017-06-03 rocky <rb@dustyfeet.com> 2017-06-03 rocky <rb@dustyfeet.com>
* .travis.yml: Streamline .travis.yml a little bit * pytest/validate.py: 2.4 doesn't do six
2017-06-03 rocky <rb@dustyfeet.com>
* appveyor.yml: Nope it (appveyor) doesn't.
2017-06-03 rocky <rb@dustyfeet.com>
* __pkginfo__.py, appveyor.yml: Administrivia See if appveyor will handle 2.5
2017-06-03 rocky <rb@dustyfeet.com>
* : commit 7c299fbf3777c452d6a10075964961783f510699 Author: rocky
<rb@dustyfeet.com> Date: Sat Jun 3 05:38:05 2017 -0400
2017-06-03 rocky <rb@dustyfeet.com> 2017-06-03 rocky <rb@dustyfeet.com>
@@ -248,8 +287,12 @@
2017-05-30 rocky <rb@dustyfeet.com> 2017-05-30 rocky <rb@dustyfeet.com>
* ChangeLog, NEWS, uncompyle6/version.py: Get ready for release * pytest/test_function_call.py: No decorators in Python < 2.6
2.10.0
2017-05-30 rocky <rb@dustyfeet.com>
* : commit ad98fae3d4b0b83f65b15da8201e33c0ee6dab17 Author: rocky
<rb@dustyfeet.com> Date: Tue May 30 01:26:52 2017 -0400
2017-05-30 rocky <rb@dustyfeet.com> 2017-05-30 rocky <rb@dustyfeet.com>
@@ -488,15 +531,25 @@
* ChangeLog, NEWS, uncompyle6/version.py: Get ready for release * ChangeLog, NEWS, uncompyle6/version.py: Get ready for release
2.9.11 2.9.11
2017-05-06 rocky <rb@dustyfeet.com>
* ChangeLog, NEWS, uncompyle6/version.py: Get ready for release
2.9.11
2017-05-06 rocky <rb@dustyfeet.com> 2017-05-06 rocky <rb@dustyfeet.com>
* test/Makefile: fix PYTHON variable setting in test/Makefile * test/Makefile: fix PYTHON variable setting in test/Makefile
2017-05-06 rocky <rb@dustyfeet.com> 2017-05-06 rocky <rb@dustyfeet.com>
* test/simple_source/bug32/01_try_except_raise.py, * test/Makefile, uncompyle6/scanners/scanner2.py,
test/simple_source/bug32/03_if.py, uncompyle6/parsers/parse32.py, uncompyle6/scanners/scanner3.py, uncompyle6/semantics/fragments.py:
uncompyle6/parsers/parse33.py: Fix more Python3.2 parser errors Sync with master
2017-05-06 rocky <rb@dustyfeet.com>
* : commit 4a4782290490187ac2fcaaecd3ca808f933722b2 Author: rocky
<rb@dustyfeet.com> Date: Sat May 6 05:25:56 2017 -0400
2017-05-05 rocky <rb@dustyfeet.com> 2017-05-05 rocky <rb@dustyfeet.com>
@@ -684,6 +737,11 @@
haphazard way using real flow-control analysis. Hopefully that's on haphazard way using real flow-control analysis. Hopefully that's on
the way. In the meantime we have this hack. the way. In the meantime we have this hack.
2017-04-14 rocky <rb@dustyfeet.com>
* : commit 7e8f7ba67431725fceec08344934c929a517efc5 Author: rocky
<rb@dustyfeet.com> Date: Fri Apr 14 05:42:44 2017 -0400
2017-04-14 rocky <rb@dustyfeet.com> 2017-04-14 rocky <rb@dustyfeet.com>
* test/simple_source/bug27+/03_if_1_else.py, * test/simple_source/bug27+/03_if_1_else.py,
@@ -748,9 +806,10 @@
uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py, uncompyle6/parsers/parse2.py, uncompyle6/parsers/parse3.py,
uncompyle6/parsers/parse35.py: Add more while1else grammar rules Towards addressing issue #93 uncompyle6/parsers/parse35.py: Add more while1else grammar rules Towards addressing issue #93
2017-04-09 rocky <rb@dustyfeet.com> 2017-04-10 rocky <rb@dustyfeet.com>
* : One more FUNCTION_VAR test for 3.3 * : commit b9703cf6b41138b717c282fc791c08d807692b07 Author: rocky
<rb@dustyfeet.com> Date: Sun Apr 9 06:58:41 2017 -0400
2017-04-09 rocky <rb@dustyfeet.com> 2017-04-09 rocky <rb@dustyfeet.com>
@@ -861,11 +920,8 @@
2017-03-01 rocky <rb@dustyfeet.com> 2017-03-01 rocky <rb@dustyfeet.com>
* uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py, * : commit 160ec0d9cc5fe347f6e8bdb69515a28c76cfb368 Author: rocky
uncompyle6/scanners/scanner3.py, uncompyle6/verify.py: COME_FROM for <rb@dustyfeet.com> Date: Wed Mar 1 05:50:31 2017 -0500
3.x POP_EXCEPT, DRY with op_name() ... Start adding COME_FROMs for POP_EXCEPT in preparation for getting
tryelse blocks correct. Simpler opname access functions: - self.op_name(op) is self.opc.opname[op] - self.op_name_from_offset(offset) is
self.opc.opname[self.code[offset]] verify.py: not all offsets are ints
2017-02-28 rocky <rb@dustyfeet.com> 2017-02-28 rocky <rb@dustyfeet.com>
@@ -889,13 +945,17 @@
2017-02-25 rocky <rb@dustyfeet.com> 2017-02-25 rocky <rb@dustyfeet.com>
* ChangeLog, NEWS, __pkginfo__.py, uncompyle6/version.py: Get ready * : commit 1e3ea60055027dfd3f098661ac4f5979c5c48f7e Author: rocky
for release 2.9.10 <rb@dustyfeet.com> Date: Sat Feb 25 20:18:03 2017 -0500
2017-02-25 rocky <rb@dustyfeet.com> 2017-02-25 rocky <rb@dustyfeet.com>
* uncompyle6/parser.py, uncompyle6/parsers/parse26.py: Python 2.6 * uncompyle6/parser.py: Python <= 2.6 grammar fixes
parsing bugs .. and some parser list nonterminal cleanup
2017-02-25 rocky <rb@dustyfeet.com>
* : commit 2fbbc728b10f0d3a754165708584bd80d33bc7f9 Author: rocky
<rb@dustyfeet.com> Date: Sat Feb 25 04:45:10 2017 -0500
2017-02-24 rocky <rb@dustyfeet.com> 2017-02-24 rocky <rb@dustyfeet.com>
@@ -909,9 +969,15 @@
uncompyle6/parsers/parse25.py: Python 2.5 wasn't handling tryelse uncompyle6/parsers/parse25.py: Python 2.5 wasn't handling tryelse
properly properly
2017-02-20 rocky <rb@dustyfeet.com> 2017-02-22 rocky <rb@dustyfeet.com>
* : New test doesn't --verify correctly. Sigh. * test/Makefile, test/simple_source/bug25/02_try_else.py,
uncompyle6/parsers/parse25.py: Python 2.5 was missing try else stmt
2017-02-22 rocky <rb@dustyfeet.com>
* : commit b043f6bafc9b9ae26e64dc0f1441d7abae894c37 Author: rocky
<rb@dustyfeet.com> Date: Mon Feb 20 09:22:01 2017 -0500
2017-02-20 rocky <rb@dustyfeet.com> 2017-02-20 rocky <rb@dustyfeet.com>
@@ -950,6 +1016,10 @@
* test/simple_source/bug22/01_ops.py, test/test_pythonlib.py: Beef * test/simple_source/bug22/01_ops.py, test/test_pythonlib.py: Beef
up grammar coverage up grammar coverage
2017-02-10 rocky <rb@dustyfeet.com>
* test/Makefile: Group coverage Makefile targets
2017-01-29 rocky <rb@dustyfeet.com> 2017-01-29 rocky <rb@dustyfeet.com>
* test/Makefile, test/simple_source/bug22/01_ops.py, * test/Makefile, test/simple_source/bug22/01_ops.py,
@@ -957,9 +1027,24 @@
uncompyle6/semantics/pysource.py: Changes based on grammar coverage uncompyle6/semantics/pysource.py: Changes based on grammar coverage
info info
2017-01-29 R. Bernstein <rocky@users.noreply.github.com> 2017-01-29 rocky <rb@dustyfeet.com>
* : Merge pull request #83 from rocky/coverage Coverage * test/Makefile, test/simple_source/bug22/01_ops.py,
uncompyle6/parsers/parse25.py, uncompyle6/semantics/consts.py,
uncompyle6/semantics/pysource.py: Changes based on coverage
information
2017-01-29 rocky <rb@dustyfeet.com>
* : commit 9348411056cbe809e07c4ef341effa17bca90e2f Merge: 3dc766d
e71dd01 Author: R. Bernstein <rocky@users.noreply.github.com> Date:
Sun Jan 29 21:54:45 2017 -0500
2017-01-29 rocky <rb@dustyfeet.com>
* test/Makefile, test/simple_source/bug22/01_ops.py,
test/test_pyenvlib.py, test/test_pythonlib.py,
uncompyle6/semantics/consts.py: Simplfy getting coverage consts.py: notes on versions use which ops
2017-01-29 rocky <rb@dustyfeet.com> 2017-01-29 rocky <rb@dustyfeet.com>
@@ -1063,6 +1148,10 @@
* uncompyle6/__init__.py: sys.recursionlimit is optional, not * uncompyle6/__init__.py: sys.recursionlimit is optional, not
essential essential
2017-01-11 rocky <rb@dustyfeet.com>
* NEWS, uncompyle6/version.py: Get ready for release 2.9.9
2017-01-11 rocky <rb@dustyfeet.com> 2017-01-11 rocky <rb@dustyfeet.com>
* : commit b131c20e99514d3a969a51e841d3a823017f1beb Author: rocky * : commit b131c20e99514d3a969a51e841d3a823017f1beb Author: rocky
@@ -1072,9 +1161,22 @@
* ChangeLog, NEWS: Get ready for release 2.10.9 * ChangeLog, NEWS: Get ready for release 2.10.9
2017-01-11 rocky <rb@dustyfeet.com>
* uncompyle6/parsers/parse3.py, uncompyle6/scanner.py,
uncompyle6/semantics/make_function.py, uncompyle6/version.py: Merge
changes ... * str() in Python 2.4 doesn't detect unicode. * index() doesn't work on tuples * ifelse change
2017-01-11 rocky <rb@dustyfeet.com>
* : commit 7ece296f7638e71fad1117b940f7ffddbe095b1f Merge: 78a5b62
5035d54 Author: R. Bernstein <rocky@users.noreply.github.com> Date:
Wed Jan 11 07:10:23 2017 -0500
2017-01-11 R. Bernstein <rocky@users.noreply.github.com> 2017-01-11 R. Bernstein <rocky@users.noreply.github.com>
* : Merge pull request #79 from rocky/revert-78-patch-1 Revert "fix bug : not generate all files when use "-ro"" * uncompyle6/main.py: Revert "fix bug : not generate all files when
use "-ro""
2017-01-11 R. Bernstein <rocky@users.noreply.github.com> 2017-01-11 R. Bernstein <rocky@users.noreply.github.com>
@@ -1173,6 +1275,16 @@
* uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py: * uncompyle6/parsers/parse35.py, uncompyle6/scanners/scanner3.py:
Python 3.5 continue detection bug Python 3.5 continue detection bug
2017-01-02 rocky <rb@dustyfeet.com>
* uncompyle6/verify.py: 2.4 verify hacks
2017-01-02 rocky <rb@dustyfeet.com>
* : commit a7d93e88b4e0dfd6876a7a31bd201a0e40f24bea Merge: 9891494
136f42a Author: rocky <rb@dustyfeet.com> Date: Mon Jan 2 05:39:13
2017 -0500
2017-01-01 rocky <rb@dustyfeet.com> 2017-01-01 rocky <rb@dustyfeet.com>
* uncompyle6/scanners/scanner3.py: add come_from for setup_finally * uncompyle6/scanners/scanner3.py: add come_from for setup_finally
@@ -1187,6 +1299,14 @@
* README.rst: Note how to verify correctness ... with --verify, --weak-verify and cross checking with pycdc * README.rst: Note how to verify correctness ... with --verify, --weak-verify and cross checking with pycdc
2016-12-31 rocky <rb@dustyfeet.com>
* uncompyle6/version.py: We are version 2.9.9
2016-12-31 rocky <rb@dustyfeet.com>
* uncompyle6/main.py: 2.7->2.4 conversion
2016-12-31 rocky <rb@dustyfeet.com> 2016-12-31 rocky <rb@dustyfeet.com>
* ChangeLog, NEWS, uncompyle6/version.py: Get ready for release * ChangeLog, NEWS, uncompyle6/version.py: Get ready for release
@@ -1196,6 +1316,13 @@
* uncompyle6/parsers/parse26.py: 2.x list_if may have a THEN in it * uncompyle6/parsers/parse26.py: 2.x list_if may have a THEN in it
2016-12-31 rocky <rb@dustyfeet.com>
* test/Makefile, uncompyle6/main.py, uncompyle6/parsers/parse26.py,
uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner26.py,
uncompyle6/scanners/scanner3.py, uncompyle6/semantics/pysource.py,
uncompyle6/verify.py: Merge master branche Handle 2.2 list_if
2016-12-31 rocky <rb@dustyfeet.com> 2016-12-31 rocky <rb@dustyfeet.com>
* uncompyle6/scanners/scanner3.py: Towards fixing a Python 3.3 * uncompyle6/scanners/scanner3.py: Towards fixing a Python 3.3
@@ -1224,10 +1351,9 @@
* : Merge pull request #73 from rocky/then-crap Add THEN token to improve Python 2.2-2.6 control flow detection * : Merge pull request #73 from rocky/then-crap Add THEN token to improve Python 2.2-2.6 control flow detection
2016-12-28 rocky <rb@dustyfeet.com> 2016-12-29 R. Bernstein <rocky@users.noreply.github.com>
* uncompyle6/parsers/parse3.py, uncompyle6/scanners/tok.py: Misc * : Merge pull request #72 from rocky/master THEN psuedo-ops for Python 2.x
bugs
2016-12-28 rocky <rb@dustyfeet.com> 2016-12-28 rocky <rb@dustyfeet.com>
@@ -1254,8 +1380,7 @@
2016-12-27 rocky <rb@dustyfeet.com> 2016-12-27 rocky <rb@dustyfeet.com>
* uncompyle6/scanners/scanner2.py: Make 2.6 and 2.7 ingest more * : Merge commit '9b1dd0f' into python-2.4
alike
2016-12-26 rocky <rb@dustyfeet.com> 2016-12-26 rocky <rb@dustyfeet.com>
@@ -1275,6 +1400,11 @@
* uncompyle6/parsers/parse25.py: fix bug in using python2 AST rules * uncompyle6/parsers/parse25.py: fix bug in using python2 AST rules
in python 2.5 in python 2.5
2016-12-26 rocky <rb@dustyfeet.com>
* uncompyle6/parsers/parse25.py: Bug in using python2 ast checking
in python 2.5
2016-12-26 rocky <rb@dustyfeet.com> 2016-12-26 rocky <rb@dustyfeet.com>
* : commit f1a947f106b231fb1480ba301b15e3ceaf78c94f Author: rocky * : commit f1a947f106b231fb1480ba301b15e3ceaf78c94f Author: rocky
@@ -1287,15 +1417,19 @@
uncompyle6/verify.py: Scanner call fixes. NAME_MODULE removal for uncompyle6/verify.py: Scanner call fixes. NAME_MODULE removal for
<=2.4 <=2.4
2016-12-24 rocky <rb@dustyfeet.com> 2016-12-25 rocky <rb@dustyfeet.com>
* uncompyle6/parsers/astnode.py, uncompyle6/parsers/parse2.py, * uncompyle6/main.py, uncompyle6/scanners/scanner15.py,
uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner21.py, uncompyle6/scanners/scanner22.py,
uncompyle6/parsers/parse36.py, uncompyle6/scanners/scanner15.py, uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner24.py,
uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner21.py, uncompyle6/semantics/pysource.py, uncompyle6/verify.py: Removing
uncompyle6/scanners/scanner22.py, NAME_MODULE, lint and bug fixes scanner*.py: show_asm param is optional verify.py: call correct
uncompyle6/semantics/fragments.py, uncompyle6/semantics/pysource.py: scanners main.py, verify.py: Use older Python print statements
Lint
2016-12-25 rocky <rb@dustyfeet.com>
* : commit e3f4beeb74e33d5b404094765cc63040f62a0b41 Author: rocky
<rb@dustyfeet.com> Date: Sat Dec 24 07:45:02 2016 -0500
2016-12-24 rocky <rb@dustyfeet.com> 2016-12-24 rocky <rb@dustyfeet.com>
@@ -1316,22 +1450,34 @@
2016-12-18 rocky <rb@dustyfeet.com> 2016-12-18 rocky <rb@dustyfeet.com>
* pytest/.gitignore, test/simple_source/bug25/02_try_else.py, * : commit c7c0a989829a9a625333665516387c1177c611c2 Author: rocky
uncompyle6/parsers/parse25.py, uncompyle6/parsers/parse26.py: Python <rb@dustyfeet.com> Date: Sun Dec 18 00:56:07 2016 -0500
2.5 mistaken try/else
2016-12-17 rocky <rb@dustyfeet.com> 2016-12-17 rocky <rb@dustyfeet.com>
* uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py: * uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py:
show-asm on python2.5 is optional make scanner2 look a little more like scanner3 show-asm on python2.5 is optional make scanner2 look a little more like scanner3
2016-12-17 rocky <rb@dustyfeet.com>
* uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner25.py:
show-asm on python2.5 is optional Make scanner2 a little more like scanner3.
2016-12-17 rocky <rb@dustyfeet.com>
* uncompyle6/parser.py, uncompyle6/scanner.py,
uncompyle6/scanners/scanner2.py, uncompyle6/scanners/scanner3.py,
uncompyle6/semantics/fragments.py: Python 2.6/2.7 tolerance in
Python 2.4 branch
2016-12-16 rocky <rb@dustyfeet.com> 2016-12-16 rocky <rb@dustyfeet.com>
* NEWS: Release 2.9.8 news * NEWS: Release 2.9.8 news
2016-12-16 rocky <rb@dustyfeet.com> 2016-12-16 rocky <rb@dustyfeet.com>
* __pkginfo__.py, uncompyle6/version.py: Get ready for release 2.9.8 * : commit 13d5cd1a588b7f4f2c233c436ce6b0b39db9950e Author: rocky
<rb@dustyfeet.com> Date: Fri Dec 16 22:42:46 2016 -0500
2016-12-16 rocky <rb@dustyfeet.com> 2016-12-16 rocky <rb@dustyfeet.com>
@@ -1399,15 +1545,12 @@
2016-12-04 rocky <rb@dustyfeet.com> 2016-12-04 rocky <rb@dustyfeet.com>
* ChangeLog, NEWS, uncompyle6/main.py, uncompyle6/parser.py, * ChangeLog: Get ready for release 2.9.7
uncompyle6/parsers/parse26.py, uncompyle6/parsers/parse3.py,
uncompyle6/parsers/parse34.py, uncompyle6/parsers/parse35.py, 2016-12-04 rocky <rb@dustyfeet.com>
uncompyle6/scanner.py, uncompyle6/scanners/scanner2.py,
uncompyle6/scanners/scanner23.py, uncompyle6/scanners/scanner24.py, * : commit d22931cb49f0e28a0fbe48a7c1526b1f170a5b52 Author: rocky
uncompyle6/scanners/scanner3.py, uncompyle6/scanners/tok.py, <rb@dustyfeet.com> Date: Sun Dec 4 07:31:34 2016 -0500
uncompyle6/semantics/make_function.py,
uncompyle6/semantics/pysource.py, uncompyle6/verify.py,
uncompyle6/version.py: Get ready for release 2.9.7 Some of the many lint things. Linting is kind of stupid though.
2016-11-28 rocky <rb@dustyfeet.com> 2016-11-28 rocky <rb@dustyfeet.com>
@@ -1458,11 +1601,34 @@
* uncompyle6/semantics/pysource.py: Better line number tracking Indent Python 2 list comprehensions, albeit badly. DRY code a * uncompyle6/semantics/pysource.py: Better line number tracking Indent Python 2 list comprehensions, albeit badly. DRY code a
little via indent_if_source_nl little via indent_if_source_nl
2016-11-24 rocky <rb@dustyfeet.com>
* circle.yml: CircleCI build
2016-11-24 rocky <rb@dustyfeet.com>
* uncompyle6/parsers/parse3.py: Remove dup Python 3 grammar rule
2016-11-24 rocky <rb@dustyfeet.com> 2016-11-24 rocky <rb@dustyfeet.com>
* uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py: * uncompyle6/parsers/parse3.py, uncompyle6/scanners/scanner2.py:
<2.7 "if" detection and dup Python 3 grammar rule <2.7 "if" detection and dup Python 3 grammar rule
2016-11-24 rocky <rb@dustyfeet.com>
* test/test_pyenvlib.py, uncompyle6/linenumbers.py,
uncompyle6/main.py, uncompyle6/scanners/scanner2.py,
uncompyle6/semantics/make_function.py,
uncompyle6/semantics/pysource.py, uncompyle6/verify.py: Bug in 2.4
"if" dectection and... Wrong language used in old-style exceptions: use "except Error,e"
not "except Error(e)""
2016-11-24 rocky <rb@dustyfeet.com>
* __pkginfo__.py, pytest/test_grammar.py, uncompyle6/parser.py,
uncompyle6/parsers/parse26.py: Python 2.6 grammary bug and.. __pkginfo.py__: Bump spark_parser
version for parse_flags 'dups'
2016-11-23 rocky <rb@dustyfeet.com> 2016-11-23 rocky <rb@dustyfeet.com>
* __pkginfo__.py, pytest/test_grammar.py, uncompyle6/parser.py, * __pkginfo__.py, pytest/test_grammar.py, uncompyle6/parser.py,
@@ -1474,8 +1640,17 @@
2016-11-23 rocky <rb@dustyfeet.com> 2016-11-23 rocky <rb@dustyfeet.com>
* : commit 6aa1531972de83ecab15b4c96b89c873ea5a7458 Author: rocky * : commit 7133540c235e16f02d2db62cb903b70aa311de20 Author: rocky
<rb@dustyfeet.com> Date: Wed Nov 23 00:48:38 2016 -0500 <rb@dustyfeet.com> Date: Wed Nov 23 08:26:12 2016 -0500
2016-11-23 rocky <rb@dustyfeet.com>
* : commit a9349b8f3d12b2aa0cd88286617c1af9cccad018 Author: rocky
<rb@dustyfeet.com> Date: Tue Nov 22 17:49:47 2016 -0500
2016-11-23 rocky <rb@dustyfeet.com>
* circle.yml: Circle CI uses 2.7.10 and 2.7.12 is not available
2016-11-22 rocky <rb@dustyfeet.com> 2016-11-22 rocky <rb@dustyfeet.com>

View File

@@ -37,7 +37,7 @@ check-3.0 check-3.1 check-3.2 check-3.5 check-3.6:
$(MAKE) -C test $@ $(MAKE) -C test $@
#:Tests for Python 2.6 (doesn't have pytest) #:Tests for Python 2.6 (doesn't have pytest)
check-2.6: check-2.4 check-2.5 check-2.6:
$(MAKE) -C test $@ $(MAKE) -C test $@
#:PyPy 2.6.1 or PyPy 5.0.1 #:PyPy 2.6.1 or PyPy 5.0.1
@@ -59,7 +59,7 @@ clean: clean_pyc
#: Create source (tarball) and wheel distribution #: Create source (tarball) and wheel distribution
dist: dist:
$(PYTHON) ./setup.py sdist bdist_wheel $(PYTHON) ./setup.py sdist bdist_egg
#: Remove .pyc files #: Remove .pyc files
clean_pyc: clean_pyc:

View File

@@ -40,7 +40,7 @@ entry_points = {
]} ]}
ftp_url = None ftp_url = None
install_requires = ['spark-parser >= 1.6.1, < 1.7.0', install_requires = ['spark-parser >= 1.6.1, < 1.7.0',
'xdis >= 3.5.4, < 3.6.0', 'six'] 'xdis >= 3.5.4, < 3.6.0']
license = 'MIT' license = 'MIT'
mailing_list = 'python-debugger@googlegroups.com' mailing_list = 'python-debugger@googlegroups.com'
modname = 'uncompyle6' modname = 'uncompyle6'

View File

@@ -10,4 +10,4 @@ dependencies:
- pip install -r requirements-dev.txt - pip install -r requirements-dev.txt
test: test:
override: override:
- python ./setup.py develop && make check-2.7 - python ./setup.py develop && make check-2.6

View File

@@ -29,7 +29,7 @@ def list_comp():
[y for y in range(3)] [y for y in range(3)]
def get_parsed_for_fn(fn): def get_parsed_for_fn(fn):
code = fn.__code__ if PYTHON3 else fn.func_code code = fn.func_code
return deparse(PYTHON_VERSION, code) return deparse(PYTHON_VERSION, code)
def check_expect(expect, parsed): def check_expect(expect, parsed):

View File

@@ -10,7 +10,7 @@ else:
maxint = sys.maxint maxint = sys.maxint
from uncompyle6.semantics.helper import print_docstring from uncompyle6.semantics.helper import print_docstring
class PrintFake(): class PrintFake:
def __init__(self): def __init__(self):
self.pending_newlines = 0 self.pending_newlines = 0
self.f = StringIO() self.f = StringIO()

View File

@@ -21,9 +21,8 @@ def bug_loop(disassemble, tb=None):
disassemble(tb) disassemble(tb)
def test_if_in_for(): def test_if_in_for():
code = bug.__code__ code = bug.func_code
scan = get_scanner(PYTHON_VERSION) scan = get_scanner(PYTHON_VERSION)
print(PYTHON_VERSION)
if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY: if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY:
n = scan.setup_code(code) n = scan.setup_code(code)
scan.build_lines_data(code, n) scan.build_lines_data(code, n)

View File

@@ -1,150 +0,0 @@
# std
import os
# test
import pytest
import hypothesis
from hypothesis import strategies as st
# uncompyle6
from uncompyle6 import PYTHON_VERSION, deparse_code
@st.composite
def expressions(draw):
# todo : would be nice to generate expressions using hypothesis however
# this is pretty involved so for now just use a corpus of expressions
# from which to select.
return draw(st.sampled_from((
'abc',
'len(items)',
'x + 1',
'lineno',
'container',
'self.attribute',
'self.method()',
# These expressions are failing, I think these are control
# flow problems rather than problems with FORMAT_VALUE,
# however I need to confirm this...
#'sorted(items, key=lambda x: x.name)',
#'func(*args, **kwargs)',
#'text or default',
#'43 if life_the_universe and everything else None'
)))
@st.composite
def format_specifiers(draw):
"""
Generate a valid format specifier using the rules:
format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]
fill ::= <any character>
align ::= "<" | ">" | "=" | "^"
sign ::= "+" | "-" | " "
width ::= integer
precision ::= integer
type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"
See https://docs.python.org/2/library/string.html
:param draw: Let hypothesis draw from other strategies.
:return: An example format_specifier.
"""
alphabet_strategy = st.characters(min_codepoint=ord('a'), max_codepoint=ord('z'))
fill = draw(st.one_of(alphabet_strategy, st.none()))
align = draw(st.sampled_from(list('<>=^')))
fill_align = (fill + align or '') if fill else ''
type_ = draw(st.sampled_from('bcdeEfFgGnosxX%'))
can_have_sign = type_ in 'deEfFgGnoxX%'
can_have_comma = type_ in 'deEfFgG%'
can_have_precision = type_ in 'fFgG'
can_have_pound = type_ in 'boxX%'
can_have_zero = type_ in 'oxX'
sign = draw(st.sampled_from(list('+- ') + [''])) if can_have_sign else ''
pound = draw(st.sampled_from(('#', '',))) if can_have_pound else ''
zero = draw(st.sampled_from(('0', '',))) if can_have_zero else ''
int_strategy = st.integers(min_value=1, max_value=1000)
width = draw(st.one_of(int_strategy, st.none()))
width = str(width) if width is not None else ''
comma = draw(st.sampled_from((',', '',))) if can_have_comma else ''
if can_have_precision:
precision = draw(st.one_of(int_strategy, st.none()))
precision = '.' + str(precision) if precision else ''
else:
precision = ''
return ''.join((fill_align, sign, pound, zero, width, comma, precision, type_,))
@st.composite
def fstrings(draw):
"""
Generate a valid f-string.
See https://www.python.org/dev/peps/pep-0498/#specification
:param draw: Let hypothsis draw from other strategies.
:return: A valid f-string.
"""
character_strategy = st.characters(
blacklist_characters='\r\n\'\\s{}',
min_codepoint=1,
max_codepoint=1000,
)
is_raw = draw(st.booleans())
integer_strategy = st.integers(min_value=0, max_value=3)
expression_count = draw(integer_strategy)
content = []
for _ in range(expression_count):
expression = draw(expressions())
conversion = draw(st.sampled_from(('', '!s', '!r', '!a',)))
has_specifier = draw(st.booleans())
specifier = ':' + draw(format_specifiers()) if has_specifier else ''
content.append('{{{}{}}}'.format(expression, conversion, specifier))
content.append(draw(st.text(character_strategy)))
content = ''.join(content)
return "f{}'{}'".format('r' if is_raw else '', content)
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6')
@hypothesis.given(format_specifiers())
def test_format_specifiers(format_specifier):
"""Verify that format_specifiers generates valid specifiers"""
try:
exec('"{:' + format_specifier + '}".format(0)')
except ValueError as e:
if 'Unknown format code' not in str(e):
raise
def run_test(text):
hypothesis.assume(len(text))
hypothesis.assume("f'{" in text)
expr = text + '\n'
code = compile(expr, '<string>', 'single')
deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single')
recompiled = compile(deparsed.text, '<string>', 'single')
if recompiled != code:
assert 'dis(' + deparsed.text.strip('\n') + ')' == 'dis(' + expr.strip('\n') + ')'
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6')
@hypothesis.given(fstrings())
def test_uncompyle_fstring(fstring):
"""Verify uncompyling fstring bytecode"""
run_test(fstring)
@pytest.mark.skipif(PYTHON_VERSION < 3.6, reason='need at least python 3.6')
@pytest.mark.parametrize('fstring', [
"f'{abc}{abc!s}'",
"f'{abc}0'",
])
def test_uncompyle_direct(fstring):
"""useful for debugging"""
run_test(fstring)

View File

@@ -1,175 +0,0 @@
# std
import string
# 3rd party
from hypothesis import given, assume, example, settings, strategies as st
import pytest
# uncompyle
from validate import validate_uncompyle
from test_fstring import expressions
alpha = st.sampled_from(string.ascii_lowercase)
numbers = st.sampled_from(string.digits)
alphanum = st.sampled_from(string.ascii_lowercase + string.digits)
@st.composite
def function_calls(draw,
min_keyword_args=0, max_keyword_args=5,
min_positional_args=0, max_positional_args=5,
min_star_args=0, max_star_args=1,
min_double_star_args=0, max_double_star_args=1):
"""
Strategy factory for generating function calls.
:param draw: Callable which draws examples from other strategies.
:return: The function call text.
"""
st_positional_args = st.lists(
alpha,
min_size=min_positional_args,
max_size=max_positional_args
)
st_keyword_args = st.lists(
alpha,
min_size=min_keyword_args,
max_size=max_keyword_args
)
st_star_args = st.lists(
alpha,
min_size=min_star_args,
max_size=max_star_args
)
st_double_star_args = st.lists(
alpha,
min_size=min_double_star_args,
max_size=max_double_star_args
)
positional_args = draw(st_positional_args)
keyword_args = draw(st_keyword_args)
st_values = st.lists(
expressions(),
min_size=len(keyword_args),
max_size=len(keyword_args)
)
keyword_args = [
x + '=' + e
for x, e in
zip(keyword_args, draw(st_values))
]
star_args = ['*' + x for x in draw(st_star_args)]
double_star_args = ['**' + x for x in draw(st_double_star_args)]
arguments = positional_args + keyword_args + star_args + double_star_args
draw(st.randoms()).shuffle(arguments)
arguments = ','.join(arguments)
function_call = 'fn({arguments})'.format(arguments=arguments)
try:
# TODO: Figure out the exact rules for ordering of positional, keyword,
# star args, double star args and in which versions the various
# types of arguments are supported so we don't need to check that the
# expression compiles like this.
compile(function_call, '<string>', 'single')
except:
assume(False)
return function_call
def test_function_no_args():
validate_uncompyle("fn()")
def isolated_function_calls(which):
"""
Returns a strategy for generating function calls, but isolated to
particular types of arguments, for example only positional arguments.
This can help reason about debugging errors in specific types of function
calls.
:param which: One of 'keyword', 'positional', 'star', 'double_star'
:return: Strategy for generating an function call isolated to specific
argument types.
"""
kwargs = dict(
max_keyword_args=0,
max_positional_args=0,
max_star_args=0,
max_double_star_args=0,
)
kwargs['_'.join(('min', which, 'args'))] = 1
kwargs['_'.join(('max', which, 'args'))] = 5 if 'star' not in which else 1
return function_calls(**kwargs)
with settings(max_examples=25):
@given(isolated_function_calls('positional'))
@example("fn(0)")
def test_function_positional_only(expr):
validate_uncompyle(expr)
@given(isolated_function_calls('keyword'))
@example("fn(a=0)")
def test_function_call_keyword_only(expr):
validate_uncompyle(expr)
@given(isolated_function_calls('star'))
@example("fn(*items)")
def test_function_call_star_only(expr):
validate_uncompyle(expr)
@given(isolated_function_calls('double_star'))
@example("fn(**{})")
def test_function_call_double_star_only(expr):
validate_uncompyle(expr)
@pytest.mark.xfail()
def test_BUILD_CONST_KEY_MAP_BUILD_MAP_UNPACK_WITH_CALL_BUILD_TUPLE_CALL_FUNCTION_EX():
validate_uncompyle("fn(w=0,m=0,**v)")
@pytest.mark.xfail()
def test_BUILD_MAP_BUILD_MAP_UNPACK_WITH_CALL_BUILD_TUPLE_CALL_FUNCTION_EX():
validate_uncompyle("fn(a=0,**g)")
@pytest.mark.xfail()
def test_CALL_FUNCTION_EX():
validate_uncompyle("fn(*g,**j)")
@pytest.mark.xfail()
def test_BUILD_MAP_CALL_FUNCTION_EX():
validate_uncompyle("fn(*z,u=0)")
@pytest.mark.xfail()
def test_BUILD_TUPLE_CALL_FUNCTION_EX():
validate_uncompyle("fn(**a)")
@pytest.mark.xfail()
def test_BUILD_MAP_BUILD_TUPLE_BUILD_TUPLE_UNPACK_WITH_CALL_CALL_FUNCTION_EX():
validate_uncompyle("fn(b,b,b=0,*a)")
@pytest.mark.xfail()
def test_BUILD_TUPLE_BUILD_TUPLE_UNPACK_WITH_CALL_CALL_FUNCTION_EX():
validate_uncompyle("fn(*c,v)")
@pytest.mark.xfail()
def test_BUILD_CONST_KEY_MAP_CALL_FUNCTION_EX():
validate_uncompyle("fn(i=0,y=0,*p)")
@pytest.mark.skip(reason='skipping property based test until all individual tests are passing')
@given(function_calls())
def test_function_call(function_call):
validate_uncompyle(function_call)

View File

@@ -1,19 +1,19 @@
import pytest from uncompyle6 import PYTHON_VERSION, deparse_code
from uncompyle6 import PYTHON_VERSION, PYTHON3, deparse_code
def test_single_mode(): if PYTHON_VERSION >= 2.5:
single_expressions = ( def test_single_mode():
'i = 1', single_expressions = (
'i and (j or k)', 'i = 1',
'i += 1', 'i and (j or k)',
'i = j % 4', 'i += 1',
'i = {}', 'i = j % 4',
'i = []', 'i = {}',
'for i in range(10):\n i\n', 'i = []',
'for i in range(10):\n for j in range(10):\n i + j\n', 'for i in range(10):\n i\n',
'try:\n i\nexcept Exception:\n j\nelse:\n k\n' 'for i in range(10):\n for j in range(10):\n i + j\n',
) 'try:\n i\nexcept Exception:\n j\nelse:\n k\n'
)
for expr in single_expressions: for expr in single_expressions:
code = compile(expr + '\n', '<string>', 'single') code = compile(expr + '\n', '<string>', 'single')
assert deparse_code(PYTHON_VERSION, code, compile_mode='single').text == expr + '\n' assert deparse_code(PYTHON_VERSION, code, compile_mode='single').text == expr + '\n'

View File

@@ -1,24 +1,25 @@
# future
from __future__ import print_function
# std # std
import os import os
import difflib import difflib
import subprocess import subprocess
import tempfile import tempfile
import functools
# compatability from StringIO import StringIO
import six
# uncompyle6 / xdis # uncompyle6 / xdis
from uncompyle6 import PYTHON_VERSION, IS_PYPY, deparse_code from uncompyle6 import PYTHON_VERSION, IS_PYPY, deparse_code
# TODO : I think we can get xdis to support the dis api (python 3 version) by doing something like this there # TODO : I think we can get xdis to support the dis api (python 3 version) by doing something like this there
from xdis.bytecode import Bytecode from xdis.bytecode import Bytecode
from xdis.main import get_opcode from xdis.main import get_opcode
opc = get_opcode(PYTHON_VERSION, IS_PYPY) opc = get_opcode(PYTHON_VERSION, IS_PYPY)
Bytecode = functools.partial(Bytecode, opc=opc)
try:
import functools
Bytecode = functools.partial(Bytecode, opc=opc)
def _dis_to_text(co):
return Bytecode(co).dis()
except:
pass
def _dis_to_text(co):
return Bytecode(co).dis()
def print_diff(original, uncompyled): def print_diff(original, uncompyled):
@@ -42,8 +43,11 @@ def print_diff(original, uncompyled):
print('\nTo display diff highlighting run:\n pip install BeautifulSoup4') print('\nTo display diff highlighting run:\n pip install BeautifulSoup4')
diff = difflib.HtmlDiff().make_table(*args) diff = difflib.HtmlDiff().make_table(*args)
with tempfile.NamedTemporaryFile(delete=False) as f: f = tempfile.NamedTemporaryFile(delete=False)
try:
f.write(str(diff).encode('utf-8')) f.write(str(diff).encode('utf-8'))
finally:
f.close()
try: try:
print() print()
@@ -60,8 +64,7 @@ def print_diff(original, uncompyled):
print('\nFor side by side diff install elinks') print('\nFor side by side diff install elinks')
diff = difflib.Differ().compare(original_lines, uncompyled_lines) diff = difflib.Differ().compare(original_lines, uncompyled_lines)
print('\n'.join(diff)) print('\n'.join(diff))
finally: os.unlink(f.name)
os.unlink(f.name)
def are_instructions_equal(i1, i2): def are_instructions_equal(i1, i2):
@@ -123,8 +126,9 @@ def validate_uncompyle(text, mode='exec'):
original_text = text original_text = text
deparsed = deparse_code(PYTHON_VERSION, original_code, deparsed = deparse_code(PYTHON_VERSION, original_code,
compile_mode=mode, compile_mode=mode,
out=six.StringIO(), out=StringIO(),
is_pypy=IS_PYPY) is_pypy=IS_PYPY)
uncompyled_text = deparsed.text uncompyled_text = deparsed.text
uncompyled_code = compile(uncompyled_text, '<string>', 'exec') uncompyled_code = compile(uncompyled_text, '<string>', 'exec')

View File

@@ -19,7 +19,7 @@ check:
$(MAKE) check-$(PYTHON_VERSION) $(MAKE) check-$(PYTHON_VERSION)
#: Run working tests from Python 2.6 or 2.7 #: Run working tests from Python 2.6 or 2.7
check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-native-short check-2.4 check-2.5 check-2.6 check-2.7: check-bytecode-2 check-bytecode-3 check-bytecode-1 check-native-short
#: Run working tests from Python 3.0 #: Run working tests from Python 3.0
check-3.0: check-bytecode check-3.0: check-bytecode
@@ -67,7 +67,7 @@ check-bytecode-2:
check-bytecode-3: check-bytecode-3:
$(PYTHON) test_pythonlib.py --bytecode-3.0 \ $(PYTHON) test_pythonlib.py --bytecode-3.0 \
--bytecode-3.1 --bytecode-3.2 --bytecode-3.3 \ --bytecode-3.1 --bytecode-3.2 --bytecode-3.3 \
--bytecode-3.4 --bytecode-3.5 --bytecode-pypy3.2 --bytecode-3.4 --bytecode-3.5 --bytecode-3.6 --bytecode-pypy3.2
#: Check deparsing bytecode that works running Python 2 and Python 3 #: Check deparsing bytecode that works running Python 2 and Python 3
check-bytecode: check-bytecode-3 check-bytecode: check-bytecode-3
@@ -97,29 +97,6 @@ check-bytecode-2.4:
check-bytecode-2.5: check-bytecode-2.5:
$(PYTHON) test_pythonlib.py --bytecode-2.5 $(PYTHON) test_pythonlib.py --bytecode-2.5
#: Get grammar coverage for Python 2.5
grammar-coverage-2.5:
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6
#: Get grammar coverage for Python 2.6
grammar-coverage-2.6:
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9
#: Get grammar coverage for Python 2.7
grammar-coverage-2.7:
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13
#: Check deparsing Python 2.6
check-bytecode-2.6:
$(PYTHON) test_pythonlib.py --bytecode-2.6 --weak-verify
#: Check deparsing Python 2.7
check-bytecode-2.7:
$(PYTHON) test_pythonlib.py --bytecode-2.7 --verify
#: Check deparsing Python 3.0 #: Check deparsing Python 3.0
check-bytecode-3.0: check-bytecode-3.0:
$(PYTHON) test_pythonlib.py --bytecode-3.0 $(PYTHON) test_pythonlib.py --bytecode-3.0
@@ -148,9 +125,33 @@ check-bytecode-3.5:
check-bytecode-3.6: check-bytecode-3.6:
$(PYTHON) test_pythonlib.py --bytecode-3.6 $(PYTHON) test_pythonlib.py --bytecode-3.6
#: Get grammar coverage for Python 2.4
grammar-coverage-2.4:
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-24.cover $(PYTHON) test_pythonlib.py --bytecode-2.4
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-24.cover $(PYTHON) test_pyenvlib.py --2.4.6
#: Get grammar coverage for Python 2.5
grammar-coverage-2.5:
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6
#: Get grammar coverage for Python 2.6
grammar-coverage-2.6:
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9
#: Get grammar coverage for Python 2.7
grammar-coverage-2.7:
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7
SPARK_PARSER_COVERAGE=/tmp/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13
#: short tests for bytecodes only for this version of Python #: short tests for bytecodes only for this version of Python
check-native-short: check-native-short:
$(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --verify $(COMPILE) $(PYTHON) test_pythonlib.py --bytecode-$(PYTHON_VERSION) --weak-verify $(COMPILE)
#: Run longer Python 2.6's lib files known to be okay
check-2.4-ok:
$(PYTHON) test_pythonlib.py --ok-2.4 --verify $(COMPILE)
#: Run longer Python 2.6's lib files known to be okay #: Run longer Python 2.6's lib files known to be okay
check-2.6-ok: check-2.6-ok:

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,9 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
# Mode: -*- python -*- # Mode: -*- python -*-
# #
# Copyright (c) 2015 by Rocky Bernstein <rb@dustyfeet.com> # Copyright (c) 2015, 2017 by Rocky Bernstein <rb@dustyfeet.com>
# #
from __future__ import print_function
import dis, os.path import dis, os.path

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import print_function
from uncompyle6 import uncompyle from uncompyle6 import uncompyle
import sys, inspect import sys, inspect

View File

@@ -19,8 +19,6 @@ Step 2: Run the test:
test_pyenvlib --mylib --verify # decompile verify 'mylib' test_pyenvlib --mylib --verify # decompile verify 'mylib'
""" """
from __future__ import print_function
from uncompyle6 import main, PYTHON3 from uncompyle6 import main, PYTHON3
import os, time, shutil, sys import os, time, shutil, sys
from fnmatch import fnmatch from fnmatch import fnmatch

View File

@@ -27,8 +27,6 @@ Step 2: Run the test:
test_pythonlib.py --mylib --verify # decompile verify 'mylib' test_pythonlib.py --mylib --verify # decompile verify 'mylib'
""" """
from __future__ import print_function
import getopt, os, py_compile, sys, shutil, tempfile, time import getopt, os, py_compile, sys, shutil, tempfile, time
from uncompyle6 import PYTHON_VERSION from uncompyle6 import PYTHON_VERSION
@@ -127,8 +125,10 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
if opts['do_compile']: if opts['do_compile']:
compiled_version = opts['compiled_version'] compiled_version = opts['compiled_version']
if compiled_version and PYTHON_VERSION != compiled_version: if compiled_version and PYTHON_VERSION != compiled_version:
print("Not compiling: desired Python version is %s but we are running %s" % sys.stderr.write("Not compiling: "
(compiled_version, PYTHON_VERSION), file=sys.stderr) "desired Python version is %s "
"but we are running %s" %
(compiled_version, PYTHON_VERSION))
else: else:
for root, dirs, basenames in os.walk(src_dir): for root, dirs, basenames in os.walk(src_dir):
file_matches(files, root, basenames, PY) file_matches(files, root, basenames, PY)
@@ -146,8 +146,8 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
file_matches(files, dirname, basenames, obj_patterns) file_matches(files, dirname, basenames, obj_patterns)
if not files: if not files:
print("Didn't come up with any files to test! Try with --compile?", sys.stderr.write("Didn't come up with any files to test! "
file=sys.stderr) "Try with --compile?")
exit(1) exit(1)
os.chdir(cwd) os.chdir(cwd)
@@ -161,9 +161,9 @@ def do_tests(src_dir, obj_patterns, target_dir, opts):
except ValueError: except ValueError:
pass pass
print(time.ctime()) print time.ctime()
print('Source directory: ', src_dir) print 'Source directory: ', src_dir
print('Output directory: ', target_dir) print 'Output directory: ', target_dir
try: try:
_, _, failed_files, failed_verify = \ _, _, failed_files, failed_verify = \
main(src_dir, target_dir, files, [], main(src_dir, target_dir, files, [],
@@ -236,14 +236,13 @@ if __name__ == '__main__':
if os.path.isdir(src_dir): if os.path.isdir(src_dir):
checked_dirs.append([src_dir, pattern, target_dir]) checked_dirs.append([src_dir, pattern, target_dir])
else: else:
print("Can't find directory %s. Skipping" % src_dir, sys.stderr.write("Can't find directory %s. Skipping" % src_dir)
file=sys.stderr)
continue continue
last_compile_version = compiled_version last_compile_version = compiled_version
pass pass
if not checked_dirs: if not checked_dirs:
print("No directories found to check", file=sys.stderr) sys.stderr.write("No directories found to check\n")
sys.exit(1) sys.exit(1)
test_opts['compiled_version'] = last_compile_version test_opts['compiled_version'] = last_compile_version

View File

@@ -3,7 +3,6 @@
# #
# Copyright (c) 2015-2016 by Rocky Bernstein <rb@dustyfeet.com> # Copyright (c) 2015-2016 by Rocky Bernstein <rb@dustyfeet.com>
# #
from __future__ import print_function
import sys, os, getopt import sys, os, getopt
from uncompyle6.disas import disassemble_file from uncompyle6.disas import disassemble_file
@@ -26,7 +25,7 @@ Options:
-V | --version show version and stop -V | --version show version and stop
-h | --help show this message -h | --help show this message
""".format(program) """ % (program, program)
PATTERNS = ('*.pyc', '*.pyo') PATTERNS = ('*.pyc', '*.pyo')
@@ -37,15 +36,15 @@ Type -h for for full help.""" % program
native = True native = True
if len(sys.argv) == 1: if len(sys.argv) == 1:
print("No file(s) given", file=sys.stderr) sys.stderr.write("No file(s) given\n")
print(Usage_short, file=sys.stderr) sys.stderr.write(Usage_short)
sys.exit(1) sys.exit(1)
try: try:
opts, files = getopt.getopt(sys.argv[1:], 'hVU', opts, files = getopt.getopt(sys.argv[1:], 'hVU',
['help', 'version', 'uncompyle6']) ['help', 'version', 'uncompyle6'])
except getopt.GetoptError as e: except getopt.GetoptError(e):
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr) sys.stderr.write('%s: %s' % (os.path.basename(sys.argv[0]), e))
sys.exit(-1) sys.exit(-1)
for opt, val in opts: for opt, val in opts:
@@ -59,15 +58,14 @@ Type -h for for full help.""" % program
native = False native = False
else: else:
print(opt) print(opt)
print(Usage_short, file=sys.stderr) sys.stderr.write(Usage_short)
sys.exit(1) sys.exit(1)
for file in files: for file in files:
if os.path.exists(files[0]): if os.path.exists(files[0]):
disassemble_file(file, sys.stdout, native) disassemble_file(file, sys.stdout, native)
else: else:
print("Can't read %s - skipping" % files[0], sys.stderr.write("Can't read %s - skipping\n" % files[0])
file=sys.stderr)
pass pass
pass pass
return return

View File

@@ -4,7 +4,6 @@
# Copyright (c) 2015-2016 by Rocky Bernstein # Copyright (c) 2015-2016 by Rocky Bernstein
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com> # Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# #
from __future__ import print_function
import sys, os, getopt, time import sys, os, getopt, time
program, ext = os.path.splitext(os.path.basename(__file__)) program, ext = os.path.splitext(os.path.basename(__file__))
@@ -65,11 +64,11 @@ def usage():
def main_bin(): def main_bin():
if not (sys.version_info[0:2] in ((2, 6), (2, 7), if not (sys.version_info[0:2] in ((2, 4), (2, 5), (2, 6), (2, 7),
(3, 1), (3, 2), (3, 3), (3, 2), (3, 3),
(3, 4), (3, 5), (3, 6))): (3, 4), (3, 5), (3, 6))):
print('Error: %s requires Python 2.6-2.7, or 3.1-3.6' % program, sys.stderr.write('Error: %s requires Python 2.4 2.5 2.6, 2.7, '
file=sys.stderr) '3.2, 3.3, 3.4, 3.5, or 3.6' % program)
sys.exit(-1) sys.exit(-1)
do_verify = recurse_dirs = False do_verify = recurse_dirs = False
@@ -84,8 +83,8 @@ def main_bin():
opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:', opts, files = getopt.getopt(sys.argv[1:], 'hagtdrVo:c:p:',
'help asm grammar linemaps recurse timestamp tree ' 'help asm grammar linemaps recurse timestamp tree '
'verify version showgrammar'.split(' ')) 'verify version showgrammar'.split(' '))
except getopt.GetoptError as e: except getopt.GetoptError(e):
print('%s: %s' % (os.path.basename(sys.argv[0]), e), file=sys.stderr) sys.stderr.write('%s: %s\n' % (os.path.basename(sys.argv[0]), e))
sys.exit(-1) sys.exit(-1)
options = {} options = {}
@@ -119,7 +118,7 @@ def main_bin():
elif opt in ('--recurse', '-r'): elif opt in ('--recurse', '-r'):
recurse_dirs = True recurse_dirs = True
else: else:
print(opt, file=sys.stderr) sys.stderr.write(opt)
usage() usage()
# expand directory if specified # expand directory if specified
@@ -144,7 +143,7 @@ def main_bin():
files = [f[sb_len:] for f in files] files = [f[sb_len:] for f in files]
if not files: if not files:
print("No files given", file=sys.stderr) sys.stderr.write("No files given\n")
usage() usage()
if outfile == '-': if outfile == '-':

View File

@@ -16,8 +16,6 @@ Second, we need structured instruction information for the
want to run on Python 2.7. want to run on Python 2.7.
""" """
from __future__ import print_function
import sys import sys
from collections import deque from collections import deque
@@ -37,10 +35,9 @@ def disco(version, co, out=None, is_pypy=False):
# store final output stream for case of error # store final output stream for case of error
real_out = out or sys.stdout real_out = out or sys.stdout
print('# Python %s' % version, file=real_out) real_out.write('# Python %s\n' % version)
if co.co_filename: if co.co_filename:
print('# Embedded file name: %s' % co.co_filename, real_out.write('# Embedded file name: %s\n' % co.co_filename)
file=real_out)
scanner = get_scanner(version, is_pypy=is_pypy) scanner = get_scanner(version, is_pypy=is_pypy)
@@ -52,16 +49,15 @@ def disco_loop(disasm, queue, real_out):
while len(queue) > 0: while len(queue) > 0:
co = queue.popleft() co = queue.popleft()
if co.co_name != '<module>': if co.co_name != '<module>':
print('\n# %s line %d of %s' % real_out.write('\n# %s line %d of %s\n' %
(co.co_name, co.co_firstlineno, co.co_filename), (co.co_name, co.co_firstlineno, co.co_filename))
file=real_out)
tokens, customize = disasm(co) tokens, customize = disasm(co)
for t in tokens: for t in tokens:
if iscode(t.pattr): if iscode(t.pattr):
queue.append(t.pattr) queue.append(t.pattr)
elif iscode(t.attr): elif iscode(t.attr):
queue.append(t.attr) queue.append(t.attr)
print(t, file=real_out) real_out.write(t)
pass pass
pass pass

View File

@@ -10,7 +10,7 @@ def line_number_mapping(pyc_filename, src_filename):
source_size) = load_module(pyc_filename) source_size) = load_module(pyc_filename)
try: try:
code2 = load_file(src_filename) code2 = load_file(src_filename)
except SyntaxError as e: except SyntaxError, e:
return str(e) return str(e)
queue = deque([code1, code2]) queue = deque([code1, code2])

View File

@@ -1,4 +1,3 @@
from __future__ import print_function
import datetime, os, subprocess, sys, tempfile import datetime, os, subprocess, sys, tempfile
from uncompyle6 import verify, IS_PYPY from uncompyle6 import verify, IS_PYPY
@@ -22,31 +21,36 @@ def decompile(
# store final output stream for case of error # store final output stream for case of error
real_out = out or sys.stdout real_out = out or sys.stdout
co_pypy_str = 'PyPy ' if is_pypy else '' if is_pypy:
run_pypy_str = 'PyPy ' if IS_PYPY else '' co_pypy_str = 'PyPy '
print('# uncompyle6 version %s\n' else:
'# %sPython bytecode %s%s\n# Decompiled from: %sPython %s' % co_pypy_str = ''
(VERSION, co_pypy_str, bytecode_version,
" (%d)" % magic_int if magic_int else "",
run_pypy_str, '\n# '.join(sys.version.split('\n'))),
file=real_out)
if co.co_filename:
print('# Embedded file name: %s' % co.co_filename,
file=real_out)
if timestamp:
print('# Compiled at: %s' % datetime.datetime.fromtimestamp(timestamp),
file=real_out)
if source_size:
print('# Size of source mod 2**32: %d bytes' % source_size,
file=real_out)
try: if IS_PYPY:
pysource.deparse_code(bytecode_version, co, out, showasm, showast, run_pypy_str = 'PyPy '
showgrammar, code_objects=code_objects, else:
is_pypy=is_pypy) run_pypy_str = ''
except pysource.SourceWalkerError as e:
# deparsing failed if magic_int:
raise pysource.SourceWalkerError(str(e)) m = str(magic_int)
else:
m = ""
real_out.write('# uncompyle6 version %s\n'
'# %sPython bytecode %s%s\n# Decompiled from: %sPython %s\n' %
(VERSION, co_pypy_str, bytecode_version,
" (%s)" % m, run_pypy_str,
'\n# '.join(sys.version.split('\n'))))
if co.co_filename:
real_out.write('# Embedded file name: %s\n' % co.co_filename)
if timestamp:
real_out.write('# Compiled at: %s\n' %
datetime.datetime.fromtimestamp(timestamp))
if source_size:
real_out.write('# Size of source mod 2**32: %d bytes\n' % source_size)
pysource.deparse_code(bytecode_version, co, out, showasm, showast,
showgrammar, code_objects=code_objects,
is_pypy=is_pypy)
# For compatiblity # For compatiblity
uncompyle = decompile uncompyle = decompile
@@ -128,7 +132,10 @@ def main(in_base, out_base, files, codes, outfile=None,
junk, outfile = tempfile.mkstemp(suffix=".py", junk, outfile = tempfile.mkstemp(suffix=".py",
prefix=prefix) prefix=prefix)
# Unbuffer output if possible # Unbuffer output if possible
buffering = -1 if sys.stdout.isatty() else 0 if sys.stdout.isatty():
buffering = -1
else:
buffering = 0
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering) sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', buffering)
tee = subprocess.Popen(["tee", outfile], stdin=subprocess.PIPE) tee = subprocess.Popen(["tee", outfile], stdin=subprocess.PIPE)
os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
@@ -145,9 +152,9 @@ def main(in_base, out_base, files, codes, outfile=None,
try: try:
decompile_file(infile, outstream, showasm, showast, showgrammar) decompile_file(infile, outstream, showasm, showast, showgrammar)
tot_files += 1 tot_files += 1
except (ValueError, SyntaxError, ParserError, pysource.SourceWalkerError) as e: except (ValueError, SyntaxError, ParserError, pysource.SourceWalkerError):
sys.stdout.write("\n") sys.stdout.write("\n")
sys.stderr.write("\n# file %s\n# %s\n" % (infile, e)) sys.stderr.write("# file %s\n" % (infile))
failed_files += 1 failed_files += 1
except KeyboardInterrupt: except KeyboardInterrupt:
if outfile: if outfile:
@@ -181,24 +188,28 @@ def main(in_base, out_base, files, codes, outfile=None,
msg = verify.compare_code_with_srcfile(infile, current_outfile, weak_verify=weak_verify) msg = verify.compare_code_with_srcfile(infile, current_outfile, weak_verify=weak_verify)
if not current_outfile: if not current_outfile:
if not msg: if not msg:
print('\n# okay decompiling %s' % infile) print '\n# okay decompiling %s' % infile
okay_files += 1 okay_files += 1
else: else:
print('\n# %s\n\t%s', infile, msg) print '\n# %s\n\t%s', infile, msg
except verify.VerifyCmpError as e: except verify.VerifyCmpError, e:
print(e) print(e)
verify_failed_files += 1 verify_failed_files += 1
os.rename(current_outfile, current_outfile + '_unverified') os.rename(current_outfile, current_outfile + '_unverified')
sys.stderr.write("### Error Verifying %s\n" % filename) sys.stderr.write("### Error Verifying %s\n" % filename)
sys.stderr.write(str(e) + "\n") sys.stderr.write(str(e) + "\n")
if not outfile: if not outfile:
sys.stder.write("### Error Verifiying %s" %
filename)
sys.stderr.write(e)
if raise_on_error: if raise_on_error:
raise raise
pass pass
pass pass
pass pass
elif do_verify: elif do_verify:
sys.stderr.write("\n### uncompile successful, but no file to compare against\n") sys.stderr.write("\n### uncompile successful, "
"but no file to compare against")
pass pass
else: else:
okay_files += 1 okay_files += 1

View File

@@ -6,8 +6,6 @@
Common uncompyle parser routines. Common uncompyle parser routines.
""" """
from __future__ import print_function
import sys import sys
from xdis.code import iscode from xdis.code import iscode
@@ -30,13 +28,13 @@ class PythonParser(GenericASTBuilder):
def __init__(self, AST, start, debug): def __init__(self, AST, start, debug):
super(PythonParser, self).__init__(AST, start, debug) super(PythonParser, self).__init__(AST, start, debug)
self.collect = frozenset( self.collect = [
['stmts', 'except_stmts', '_stmts', 'load_attrs', 'stmts', 'except_stmts', '_stmts', 'load_attrs',
'exprlist', 'kvlist', 'kwargs', 'come_froms', '_come_from', 'exprlist', 'kvlist', 'kwargs', 'come_froms', '_come_from',
# Python < 3 # Python < 3
'print_items', 'print_items',
# PyPy: # PyPy:
'kvlist_n']) 'kvlist_n']
def ast_first_offset(self, ast): def ast_first_offset(self, ast):
if hasattr(ast, 'offset'): if hasattr(ast, 'offset'):
@@ -92,7 +90,10 @@ class PythonParser(GenericASTBuilder):
def fix(c): def fix(c):
s = str(c) s = str(c)
i = s.find('_') i = s.find('_')
return s if i == -1 else s[:i] if i == -1:
return s
else:
return s[:i]
prefix = '' prefix = ''
if parent and tokens: if parent and tokens:
@@ -123,7 +124,10 @@ class PythonParser(GenericASTBuilder):
err_token = instructions[index] err_token = instructions[index]
print("Instruction context:") print("Instruction context:")
for i in range(start, finish): for i in range(start, finish):
indent = ' ' if i != index else '-> ' if i != index:
indent = ' '
else:
indent = '-> '
print("%s%s" % (indent, instructions[i])) print("%s%s" % (indent, instructions[i]))
raise ParserError(err_token, err_token.offset) raise ParserError(err_token, err_token.offset)

View File

@@ -12,8 +12,6 @@ If we succeed in creating a parse tree, then we have a Python program
that a later phase can turn into a sequence of ASCII text. that a later phase can turn into a sequence of ASCII text.
""" """
from __future__ import print_function
from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func
from uncompyle6.parsers.astnode import AST from uncompyle6.parsers.astnode import AST
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG

View File

@@ -15,8 +15,6 @@ If we succeed in creating a parse tree, then we have a Python program
that a later phase can turn into a sequence of ASCII text. that a later phase can turn into a sequence of ASCII text.
""" """
from __future__ import print_function
from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func
from uncompyle6.parsers.astnode import AST from uncompyle6.parsers.astnode import AST
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
@@ -537,7 +535,10 @@ class Python3Parser(PythonParser):
"""Python 3.3 added a an addtional LOAD_CONST before MAKE_FUNCTION and """Python 3.3 added a an addtional LOAD_CONST before MAKE_FUNCTION and
this has an effect on many rules. this has an effect on many rules.
""" """
new_rule = rule % (('LOAD_CONST ') * (1 if self.version >= 3.3 else 0)) if self.version >= 3.3:
new_rule = rule % (('LOAD_CONST ') * 1)
else:
new_rule = rule % (('LOAD_CONST ') * 0)
self.add_unique_rule(new_rule, opname, attr, customize) self.add_unique_rule(new_rule, opname, attr, customize)
def add_custom_rules(self, tokens, customize): def add_custom_rules(self, tokens, customize):
@@ -889,7 +890,8 @@ class Python3Parser(PythonParser):
elif lhs == 'annotate_tuple': elif lhs == 'annotate_tuple':
return not isinstance(tokens[first].attr, tuple) return not isinstance(tokens[first].attr, tuple)
elif lhs == 'kwarg': elif lhs == 'kwarg':
return not isinstance(tokens[first].attr, str) return not (isinstance(tokens[first].attr, unicode) or
isinstance(tokens[first].attr, str))
elif lhs == 'while1elsestmt': elif lhs == 'while1elsestmt':
# if SETUP_LOOP target spans the else part, then this is # if SETUP_LOOP target spans the else part, then this is
# not while1else. Also do for whileTrue? # not while1else. Also do for whileTrue?

View File

@@ -2,7 +2,6 @@
""" """
spark grammar differences over Python 3.1 for Python 3.0. spark grammar differences over Python 3.1 for Python 3.0.
""" """
from __future__ import print_function
from uncompyle6.parser import PythonParserSingle from uncompyle6.parser import PythonParserSingle
from uncompyle6.parsers.parse31 import Python31Parser from uncompyle6.parsers.parse31 import Python31Parser

View File

@@ -2,7 +2,6 @@
""" """
spark grammar differences over Python 3.2 for Python 3.1. spark grammar differences over Python 3.2 for Python 3.1.
""" """
from __future__ import print_function
from uncompyle6.parser import PythonParserSingle from uncompyle6.parser import PythonParserSingle
from uncompyle6.parsers.parse32 import Python32Parser from uncompyle6.parsers.parse32 import Python32Parser

View File

@@ -2,8 +2,6 @@
""" """
spark grammar differences over Python 3 for Python 3.2. spark grammar differences over Python 3 for Python 3.2.
""" """
from __future__ import print_function
from uncompyle6.parser import PythonParserSingle from uncompyle6.parser import PythonParserSingle
from uncompyle6.parsers.parse3 import Python3Parser from uncompyle6.parsers.parse3 import Python3Parser

View File

@@ -2,7 +2,6 @@
""" """
spark grammar differences over Python 3.2 for Python 3.3. spark grammar differences over Python 3.2 for Python 3.3.
""" """
from __future__ import print_function
from uncompyle6.parser import PythonParserSingle from uncompyle6.parser import PythonParserSingle
from uncompyle6.parsers.parse32 import Python32Parser from uncompyle6.parsers.parse32 import Python32Parser

View File

@@ -2,7 +2,6 @@
""" """
spark grammar differences over Python 3.4 for Python 3.5. spark grammar differences over Python 3.4 for Python 3.5.
""" """
from __future__ import print_function
from uncompyle6.parser import PythonParserSingle from uncompyle6.parser import PythonParserSingle
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG

View File

@@ -2,7 +2,6 @@
""" """
spark grammar differences over Python 3.5 for Python 3.6. spark grammar differences over Python 3.5 for Python 3.6.
""" """
from __future__ import print_function
from uncompyle6.parser import PythonParserSingle from uncompyle6.parser import PythonParserSingle
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2016 by Rocky Bernstein # Copyright (c) 2016-2017 by Rocky Bernstein
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org> # Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com> # Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock # Copyright (c) 1999 John Aycock
@@ -10,8 +10,6 @@ scanner/ingestion module. From here we call various version-specific
scanners, e.g. for Python 2.7 or 3.4. scanners, e.g. for Python 2.7 or 3.4.
""" """
from __future__ import print_function
import sys import sys
from uncompyle6 import PYTHON3, IS_PYPY from uncompyle6 import PYTHON3, IS_PYPY

View File

@@ -13,13 +13,13 @@ import uncompyle6.scanners.scanner21 as scan
from xdis.opcodes import opcode_15 from xdis.opcodes import opcode_15
JUMP_OPs = opcode_15.JUMP_OPs JUMP_OPs = opcode_15.JUMP_OPs
# We base this off of 2.2 instead of the other way around # We base this off of 2.1 instead of the other way around
# because we cleaned things up this way. # because we cleaned things up this way.
# The history is that 2.7 support is the cleanest, # The history is that 2.7 support is the cleanest,
# then from that we got 2.6 and so on. # then from that we got 2.6 and so on.
class Scanner15(scan.Scanner21): class Scanner15(scan.Scanner21):
def __init__(self, show_asm=False): def __init__(self, show_asm=False):
scan.Scanner21.__init__(self, show_asm) scan.Scanner21.__init__(self, show_asm=False)
self.opc = opcode_15 self.opc = opcode_15
self.opname = opcode_15.opname self.opname = opcode_15.opname
self.version = 1.5 self.version = 1.5

View File

@@ -20,9 +20,13 @@ For example:
Finally we save token information. Finally we save token information.
""" """
from __future__ import print_function from uncompyle6 import PYTHON_VERSION
if PYTHON_VERSION < 2.6:
from xdis.namedtuple24 import namedtuple
else:
from collections import namedtuple
from collections import namedtuple
from array import array from array import array
from uncompyle6.scanner import L65536 from uncompyle6.scanner import L65536
@@ -85,7 +89,9 @@ class Scanner2(Scanner):
cause specific rules for the specific number of arguments they take. cause specific rules for the specific number of arguments they take.
""" """
show_asm = self.show_asm if not show_asm else show_asm if not show_asm:
show_asm = self.show_asm
# show_asm = 'after' # show_asm = 'after'
if show_asm in ('both', 'before'): if show_asm in ('both', 'before'):
from xdis.bytecode import Bytecode from xdis.bytecode import Bytecode
@@ -1026,8 +1032,10 @@ class Scanner2(Scanner):
# FIXME: rocky: I think we need something like this... # FIXME: rocky: I think we need something like this...
if offset not in set(self.ignore_if) or self.version == 2.7: if offset not in set(self.ignore_if) or self.version == 2.7:
source = (self.setup_loops[label] if label in self.setup_loops:
if label in self.setup_loops else offset) source = self.setup_loops[label]
else:
source = offset
targets[label] = targets.get(label, []) + [source] targets[label] = targets.get(label, []) + [source]
pass pass

View File

@@ -19,7 +19,7 @@ JUMP_OPs = opcode_21.JUMP_OPs
# then from that we got 2.6 and so on. # then from that we got 2.6 and so on.
class Scanner21(scan.Scanner22): class Scanner21(scan.Scanner22):
def __init__(self, show_asm=False): def __init__(self, show_asm=False):
scan.Scanner22.__init__(self, show_asm) scan.Scanner22.__init__(self, show_asm=False)
self.opc = opcode_21 self.opc = opcode_21
self.opname = opcode_21.opname self.opname = opcode_21.opname
self.version = 2.1 self.version = 2.1

View File

@@ -19,7 +19,7 @@ JUMP_OPs = opcode_22.JUMP_OPs
# then from that we got 2.6 and so on. # then from that we got 2.6 and so on.
class Scanner22(scan.Scanner23): class Scanner22(scan.Scanner23):
def __init__(self, show_asm=False): def __init__(self, show_asm=False):
scan.Scanner23.__init__(self, show_asm) scan.Scanner23.__init__(self, show_asm=False)
self.opc = opcode_22 self.opc = opcode_22
self.opname = opcode_22.opname self.opname = opcode_22.opname
self.version = 2.2 self.version = 2.2

View File

@@ -87,7 +87,9 @@ class Scanner26(scan.Scanner2):
cause specific rules for the specific number of arguments they take. cause specific rules for the specific number of arguments they take.
""" """
show_asm = self.show_asm if not show_asm else show_asm if not show_asm:
show_asm = self.show_asm
# show_asm = 'after' # show_asm = 'after'
if show_asm in ('both', 'before'): if show_asm in ('both', 'before'):
from xdis.bytecode import Bytecode from xdis.bytecode import Bytecode

View File

@@ -7,8 +7,6 @@ grammar parsing.
""" """
from __future__ import print_function
from uncompyle6.scanners.scanner2 import Scanner2 from uncompyle6.scanners.scanner2 import Scanner2
from uncompyle6 import PYTHON3 from uncompyle6 import PYTHON3

View File

@@ -20,9 +20,13 @@ For example:
Finally we save token information. Finally we save token information.
""" """
from __future__ import print_function from uncompyle6 import PYTHON_VERSION
if PYTHON_VERSION < 2.6:
from xdis.namedtuple24 import namedtuple
else:
from collections import namedtuple
from collections import namedtuple
from array import array from array import array
from uncompyle6.scanner import Scanner from uncompyle6.scanner import Scanner
@@ -162,8 +166,10 @@ class Scanner3(Scanner):
cause specific rules for the specific number of arguments they take. cause specific rules for the specific number of arguments they take.
""" """
show_asm = self.show_asm if not show_asm else show_asm if not show_asm:
# show_asm = 'both' show_asm = self.show_asm
# show_asm = 'after'
if show_asm in ('both', 'before'): if show_asm in ('both', 'before'):
bytecode = Bytecode(co, self.opc) bytecode = Bytecode(co, self.opc)
for instr in bytecode.get_instructions(co): for instr in bytecode.get_instructions(co):

View File

@@ -6,8 +6,6 @@ This sets up opcodes Python's 3.0 and calls a generalized
scanner routine for Python 3. scanner routine for Python 3.
""" """
from __future__ import print_function
# bytecode verification, verify(), uses JUMP_OPs from here # bytecode verification, verify(), uses JUMP_OPs from here
from xdis.opcodes import opcode_30 as opc from xdis.opcodes import opcode_30 as opc
from xdis.bytecode import op_size from xdis.bytecode import op_size

View File

@@ -6,8 +6,6 @@ This sets up opcodes Python's 3.1 and calls a generalized
scanner routine for Python 3. scanner routine for Python 3.
""" """
from __future__ import print_function
# bytecode verification, verify(), uses JUMP_OPs from here # bytecode verification, verify(), uses JUMP_OPs from here
from xdis.opcodes import opcode_31 as opc from xdis.opcodes import opcode_31 as opc
JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs)

View File

@@ -9,8 +9,6 @@ This sets up opcodes Python's 3.2 and calls a generalized
scanner routine for Python 3. scanner routine for Python 3.
""" """
from __future__ import print_function
# bytecode verification, verify(), uses JUMP_OPs from here # bytecode verification, verify(), uses JUMP_OPs from here
from xdis.opcodes import opcode_32 as opc from xdis.opcodes import opcode_32 as opc
JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs)

View File

@@ -6,8 +6,6 @@ This sets up opcodes Python's 3.3 and calls a generalized
scanner routine for Python 3. scanner routine for Python 3.
""" """
from __future__ import print_function
# bytecode verification, verify(), uses JUMP_OPs from here # bytecode verification, verify(), uses JUMP_OPs from here
from xdis.opcodes import opcode_33 as opc from xdis.opcodes import opcode_33 as opc
JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs) JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs)

View File

@@ -9,8 +9,6 @@ This sets up opcodes Python's 3.4 and calls a generalized
scanner routine for Python 3. scanner routine for Python 3.
""" """
from __future__ import print_function
from xdis.opcodes import opcode_34 as opc from xdis.opcodes import opcode_34 as opc
# bytecode verification, verify(), uses JUMP_OPs from here # bytecode verification, verify(), uses JUMP_OPs from here

View File

@@ -9,8 +9,6 @@ This sets up opcodes Python's 3.5 and calls a generalized
scanner routine for Python 3. scanner routine for Python 3.
""" """
from __future__ import print_function
from uncompyle6.scanners.scanner3 import Scanner3 from uncompyle6.scanners.scanner3 import Scanner3
# bytecode verification, verify(), uses JUMP_OPs from here # bytecode verification, verify(), uses JUMP_OPs from here

View File

@@ -9,8 +9,6 @@ This sets up opcodes Python's 3.6 and calls a generalized
scanner routine for Python 3. scanner routine for Python 3.
""" """
from __future__ import print_function
from uncompyle6.scanners.scanner3 import Scanner3 from uncompyle6.scanners.scanner3 import Scanner3
# bytecode verification, verify(), uses JUMP_OPs from here # bytecode verification, verify(), uses JUMP_OPs from here

View File

@@ -56,12 +56,18 @@ class Token:
return self.format(line_prefix='') return self.format(line_prefix='')
def format(self, line_prefix=''): def format(self, line_prefix=''):
prefix = ('\n%s%4d ' % (line_prefix, self.linestart) if self.linestart:
if self.linestart else (' ' * (6 + len(line_prefix)))) prefix = '\n%s%4d ' % (line_prefix, self.linestart)
else:
prefix = ' ' * (6 + len(line_prefix))
offset_opname = '%6s %-17s' % (self.offset, self.type) offset_opname = '%6s %-17s' % (self.offset, self.type)
if not self.has_arg: if not self.has_arg:
return "%s%s" % (prefix, offset_opname) return "%s%s" % (prefix, offset_opname)
argstr = "%6d " % self.attr if isinstance(self.attr, int) else (' '*7)
if isinstance(self.attr, int):
argstr = "%6d " % self.attr
else:
argstr = ' '*7
if self.pattr: if self.pattr:
pattr = self.pattr pattr = self.pattr
if self.opc: if self.opc:

View File

@@ -51,8 +51,6 @@ The node position 0 will be associated with "import".
# FIXME: DRY code with pysource # FIXME: DRY code with pysource
from __future__ import print_function
import re, sys import re, sys
from xdis.code import iscode from xdis.code import iscode
@@ -79,7 +77,12 @@ from uncompyle6.semantics.consts import (
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from spark_parser.ast import GenericASTTraversalPruningException from spark_parser.ast import GenericASTTraversalPruningException
from collections import namedtuple from uncompyle6 import PYTHON_VERSION
if PYTHON_VERSION < 2.6:
from xdis.namedtuple24 import namedtuple
else:
from collections import namedtuple
NodeInfo = namedtuple("NodeInfo", "node start finish") NodeInfo = namedtuple("NodeInfo", "node start finish")
ExtractInfo = namedtuple("ExtractInfo", ExtractInfo = namedtuple("ExtractInfo",
"lineNo lineStartOffset markerLine selectedLine selectedText nonterminal") "lineNo lineStartOffset markerLine selectedLine selectedText nonterminal")
@@ -772,7 +775,10 @@ class FragmentsWalker(pysource.SourceWalker, object):
def n_genexpr(self, node): def n_genexpr(self, node):
start = len(self.f.getvalue()) start = len(self.f.getvalue())
self.write('(') self.write('(')
code_index = -6 if self.version > 3.2 else -5 if self.version > 3.2:
code_index = -6
else:
code_index = -5
self.comprehension_walk(node, iter_index=3, code_index=code_index) self.comprehension_walk(node, iter_index=3, code_index=code_index)
self.write(')') self.write(')')
self.set_pos_info(node, start, len(self.f.getvalue())) self.set_pos_info(node, start, len(self.f.getvalue()))
@@ -926,7 +932,10 @@ class FragmentsWalker(pysource.SourceWalker, object):
subclass = n.attr subclass = n.attr
break break
pass pass
subclass_info = node if node == 'classdefdeco2' else node[0] if node == 'classdefdeco2':
subclass_info = node
else:
subclass_info = node[0]
elif buildclass[1][0] == 'load_closure': elif buildclass[1][0] == 'load_closure':
# Python 3 with closures not functions # Python 3 with closures not functions
load_closure = buildclass[1] load_closure = buildclass[1]
@@ -950,7 +959,10 @@ class FragmentsWalker(pysource.SourceWalker, object):
subclass = buildclass[1][0].attr subclass = buildclass[1][0].attr
subclass_info = node[0] subclass_info = node[0]
else: else:
buildclass = node if (node == 'classdefdeco2') else node[0] if node == 'classdefdeco2':
buildclass = node
else:
buildclass = node[0]
build_list = buildclass[1][0] build_list = buildclass[1][0]
if hasattr(buildclass[-3][0], 'attr'): if hasattr(buildclass[-3][0], 'attr'):
subclass = buildclass[-3][0].attr subclass = buildclass[-3][0].attr
@@ -1016,7 +1028,9 @@ class FragmentsWalker(pysource.SourceWalker, object):
tokens.append(Token('LAMBDA_MARKER')) tokens.append(Token('LAMBDA_MARKER'))
try: try:
ast = parser.parse(self.p, tokens, customize) ast = parser.parse(self.p, tokens, customize)
except (parser.ParserError, AssertionError) as e: except parser.ParserError(e):
raise ParserError(e, tokens)
except AssertionError(e):
raise ParserError(e, tokens) raise ParserError(e, tokens)
maybe_show_ast(self.showast, ast) maybe_show_ast(self.showast, ast)
return ast return ast
@@ -1041,7 +1055,9 @@ class FragmentsWalker(pysource.SourceWalker, object):
# Build AST from disassembly. # Build AST from disassembly.
try: try:
ast = parser.parse(self.p, tokens, customize) ast = parser.parse(self.p, tokens, customize)
except (parser.ParserError, AssertionError) as e: except parser.ParserError(e):
raise ParserError(e, tokens)
except AssertionError(e):
raise ParserError(e, tokens) raise ParserError(e, tokens)
maybe_show_ast(self.showast, ast) maybe_show_ast(self.showast, ast)

View File

@@ -6,14 +6,9 @@ All the crazy things we have to do to handle Python functions
from xdis.code import iscode from xdis.code import iscode
from uncompyle6.scanner import Code from uncompyle6.scanner import Code
from uncompyle6.parsers.astnode import AST from uncompyle6.parsers.astnode import AST
from uncompyle6 import PYTHON3
from uncompyle6.semantics.parser_error import ParserError from uncompyle6.semantics.parser_error import ParserError
from uncompyle6.semantics.helper import print_docstring from uncompyle6.semantics.helper import print_docstring
if PYTHON3:
from itertools import zip_longest
else:
from itertools import izip_longest as zip_longest
from uncompyle6.show import maybe_show_ast_param_default from uncompyle6.show import maybe_show_ast_param_default
@@ -139,7 +134,7 @@ def make_function3_annotate(self, node, isLambda, nested=1,
code._customize, code._customize,
isLambda = isLambda, isLambda = isLambda,
noneInNames = ('None' in code.co_names)) noneInNames = ('None' in code.co_names))
except ParserError as p: except ParserError, p:
self.write(str(p)) self.write(str(p))
self.ERROR = p self.ERROR = p
return return
@@ -170,7 +165,7 @@ def make_function3_annotate(self, node, isLambda, nested=1,
self.write(suffix, param) self.write(suffix, param)
suffix = ', ' suffix = ', '
if param in annotate_tuple[0].attr: if param in annotate_tuple[0].attr:
p = annotate_tuple[0].attr.index(param) p = [x for x in annotate_tuple[0].attr].index(param)
self.write(': ') self.write(': ')
self.preorder(node[p]) self.preorder(node[p])
if (line_number != self.line_number): if (line_number != self.line_number):
@@ -182,7 +177,10 @@ def make_function3_annotate(self, node, isLambda, nested=1,
# else: # else:
# self.write(': %s' % value) # self.write(': %s' % value)
suffix = ', ' if i > 0 else '' if i > 0:
suffix = ', '
else:
suffix = ''
for n in node: for n in node:
if n == 'pos_arg': if n == 'pos_arg':
no_paramnames = False no_paramnames = False
@@ -367,17 +365,21 @@ def make_function2(self, node, isLambda, nested=1, codeNode=None):
code._customize, code._customize,
isLambda = isLambda, isLambda = isLambda,
noneInNames = ('None' in code.co_names)) noneInNames = ('None' in code.co_names))
except ParserError as p: except ParserError, p:
self.write(str(p)) self.write(str(p))
self.ERROR = p self.ERROR = p
return return
kw_pairs = args_node.attr[1] if self.version >= 3.0 else 0 if self.version >= 3.0:
kw_pairs = args_node.attr[1]
else:
kw_pairs = 0
indent = self.indent indent = self.indent
# build parameters # build parameters
tup = [paramnames, defparams]
params = [build_param(ast, name, default) for params = [build_param(ast, name, default) for
name, default in zip_longest(paramnames, defparams, fillvalue=None)] name, default in map(lambda *tup:tup, *tup)]
params.reverse() # back to correct order params.reverse() # back to correct order
if code_has_star_arg(code): if code_has_star_arg(code):
@@ -438,34 +440,10 @@ def make_function2(self, node, isLambda, nested=1, codeNode=None):
def make_function3(self, node, isLambda, nested=1, codeNode=None): def make_function3(self, node, isLambda, nested=1, codeNode=None):
"""Dump function definition, doc string, and function body in """Dump function definition, doc string, and function body."""
Python version 3.0 and above
"""
# For Python 3.3, the evaluation stack in MAKE_FUNCTION is: # FIXME: call make_function3 if we are self.version >= 3.0
# and then simplify the below.
# * default argument objects in positional order
# * pairs of name and default argument, with the name just below
# the object on the stack, for keyword-only parameters
# * parameter annotation objects
# * a tuple listing the parameter names for the annotations
# (only if there are ony annotation objects)
# * the code associated with the function (at TOS1)
# * the qualified name of the function (at TOS)
# For Python 3.0 .. 3.2 the evaluation stack is:
# The function object is defined to have argc default parameters,
# which are found below TOS.
# * first come positional args in the order they are given in the source,
# * next come the keyword args in the order they given in the source,
# * finally is the code associated with the function (at TOS)
#
# Note: There is no qualified name at TOS
# MAKE_CLOSURE adds an additional closure slot
# Thank you, Python, for a such a well-thought out system that has
# changed 4 or so times.
def build_param(ast, name, default): def build_param(ast, name, default):
"""build parameters: """build parameters:
@@ -485,31 +463,21 @@ def make_function3(self, node, isLambda, nested=1, codeNode=None):
# MAKE_FUNCTION_... or MAKE_CLOSURE_... # MAKE_FUNCTION_... or MAKE_CLOSURE_...
assert node[-1].type.startswith('MAKE_') assert node[-1].type.startswith('MAKE_')
# Python 3.3+ adds a qualified name at TOS (-1)
# moving down the LOAD_LAMBDA instruction
if 3.0 <= self.version <= 3.2:
lambda_index = -2
elif 3.03 <= self.version:
lambda_index = -3
else:
lambda_index = None
args_node = node[-1] args_node = node[-1]
if isinstance(args_node.attr, tuple): if isinstance(args_node.attr, tuple):
pos_args, kw_args, annotate_argc = args_node.attr if self.version <= 3.3 and len(node) > 2 and node[-3] != 'LOAD_LAMBDA':
if self.version <= 3.3 and len(node) > 2 and node[lambda_index] != 'LOAD_LAMBDA': # positional args are after kwargs
# args are after kwargs; kwargs are bundled as one node
defparams = node[1:args_node.attr[0]+1] defparams = node[1:args_node.attr[0]+1]
else: else:
# args are before kwargs; kwags as bundled as one node # positional args are before kwargs
defparams = node[:args_node.attr[0]] defparams = node[:args_node.attr[0]]
pos_args, kw_args, annotate_argc = args_node.attr
else: else:
if self.version < 3.6: if self.version < 3.6:
defparams = node[:args_node.attr] defparams = node[:args_node.attr]
else: else:
default, kw, annotate, closure = args_node.attr default, kw, annotate, closure = args_node.attr
# FIXME: start here for Python 3.6 and above: # FIXME: start here.
defparams = [] defparams = []
# if default: # if default:
# defparams = node[-(2 + kw + annotate + closure)] # defparams = node[-(2 + kw + annotate + closure)]
@@ -519,6 +487,12 @@ def make_function3(self, node, isLambda, nested=1, codeNode=None):
kw_args = 0 kw_args = 0
pass pass
if 3.0 <= self.version <= 3.2:
lambda_index = -2
elif 3.03 <= self.version:
lambda_index = -3
else:
lambda_index = None
if lambda_index and isLambda and iscode(node[lambda_index].attr): if lambda_index and isLambda and iscode(node[lambda_index].attr):
assert node[lambda_index].type == 'LOAD_LAMBDA' assert node[lambda_index].type == 'LOAD_LAMBDA'
@@ -534,7 +508,7 @@ def make_function3(self, node, isLambda, nested=1, codeNode=None):
paramnames = list(code.co_varnames[:argc]) paramnames = list(code.co_varnames[:argc])
# defaults are for last n parameters, thus reverse # defaults are for last n parameters, thus reverse
if not 3.0 <= self.version <= 3.1: if not 3.0 <= self.version <= 3.2:
paramnames.reverse(); defparams.reverse() paramnames.reverse(); defparams.reverse()
try: try:
@@ -542,33 +516,71 @@ def make_function3(self, node, isLambda, nested=1, codeNode=None):
code._customize, code._customize,
isLambda = isLambda, isLambda = isLambda,
noneInNames = ('None' in code.co_names)) noneInNames = ('None' in code.co_names))
except ParserError as p: except ParserError, p:
self.write(str(p)) self.write(str(p))
self.ERROR = p self.ERROR = p
return return
kw_pairs = args_node.attr[1] if self.version >= 3.0 else 0 if self.version >= 3.0:
kw_pairs = args_node.attr[1]
else:
kw_pairs = 0
indent = self.indent
# build parameters # build parameters
params = [build_param(ast, name, d) for if self.version != 3.2:
name, d in zip_longest(paramnames, defparams, fillvalue=None)] tup = [paramnames, defparams]
params = [build_param(ast, name, default) for
if not 3.0 <= self.version <= 3.1: name, default in map(lambda *tup:tup, *tup)]
params.reverse() # back to correct order params.reverse() # back to correct order
if code_has_star_arg(code): if code_has_star_arg(code):
if self.version > 3.0: if self.version > 3.0:
params.append('*%s' % code.co_varnames[argc + kw_pairs]) params.append('*%s' % code.co_varnames[argc + kw_pairs])
else: else:
params.append('*%s' % code.co_varnames[argc]) params.append('*%s' % code.co_varnames[argc])
argc += 1 argc += 1
# dump parameter list (with default values)
if isLambda:
self.write("lambda ", ", ".join(params))
else:
self.write("(", ", ".join(params))
# self.println(indent, '#flags:\t', int(code.co_flags))
# dump parameter list (with default values)
if isLambda:
self.write("lambda ", ", ".join(params))
else: else:
self.write("(", ", ".join(params)) if isLambda:
# self.println(indent, '#flags:\t', int(code.co_flags)) self.write("lambda ")
else:
self.write("(")
pass
last_line = self.f.getvalue().split("\n")[-1]
l = len(last_line)
indent = ' ' * l
line_number = self.line_number
if code_has_star_arg(code):
self.write('*%s' % code.co_varnames[argc + kw_pairs])
argc += 1
i = len(paramnames) - len(defparams)
self.write(", ".join(paramnames[:i]))
if i > 0:
suffix = ', '
else:
suffix = ''
for n in node:
if n == 'pos_arg':
self.write(suffix)
self.write(paramnames[i] + '=')
i += 1
self.preorder(n)
if (line_number != self.line_number):
suffix = ",\n" + indent
line_number = self.line_number
else:
suffix = ', '
if kw_args > 0: if kw_args > 0:
if not (4 & code.co_flags): if not (4 & code.co_flags):

View File

@@ -67,8 +67,6 @@ methods implement most of the below.
The '%' may optionally be followed by a number (C) in square brackets, which The '%' may optionally be followed by a number (C) in square brackets, which
makes the engine walk down to N[C] before evaluating the escape code. makes the engine walk down to N[C] before evaluating the escape code.
""" """
from __future__ import print_function
import sys import sys
from uncompyle6 import PYTHON3 from uncompyle6 import PYTHON3
@@ -956,7 +954,10 @@ class SourceWalker(GenericASTTraversal, object):
return return
n = node[-1] n = node[-1]
elif node[-1] == 'del_stmt': elif node[-1] == 'del_stmt':
n = node[-3] if node[-2] == 'JUMP_BACK' else node[-2] if node[-2] == 'JUMP_BACK':
n = node[-3]
else:
n = node[-2]
assert n == 'list_iter' assert n == 'list_iter'
@@ -974,7 +975,10 @@ class SourceWalker(GenericASTTraversal, object):
list_iter = node[-1] list_iter = node[-1]
else: else:
expr = n[1] expr = n[1]
list_iter = node[-3] if node[-2] == 'JUMP_BACK' else node[-2] if node[-2] == 'JUMP_BACK':
list_iter = node[-3]
else:
list_iter = node[-2]
assert expr == 'expr' assert expr == 'expr'
assert list_iter == 'list_iter' assert list_iter == 'list_iter'
@@ -1026,7 +1030,10 @@ class SourceWalker(GenericASTTraversal, object):
self.write( '[ ') self.write( '[ ')
expr = n[0] expr = n[0]
list_iter = node[-2] if self.is_pypy and node[-1] == 'JUMP_BACK' else node[-1] if self.is_pypy and node[-1] == 'JUMP_BACK':
list_iter = node[-2]
else:
list_iter = node[-1]
assert expr == 'expr' assert expr == 'expr'
assert list_iter == 'list_iter' assert list_iter == 'list_iter'
@@ -1100,7 +1107,10 @@ class SourceWalker(GenericASTTraversal, object):
self.write(' for ') self.write(' for ')
self.preorder(ast[iter_index-1]) self.preorder(ast[iter_index-1])
self.write(' in ') self.write(' in ')
iter_expr = node[2] if node[2] == 'expr' else node[-3] if node[2] == 'expr':
iter_expr = node[2]
else:
iter_expr = node[-3]
assert iter_expr == 'expr' assert iter_expr == 'expr'
self.preorder(iter_expr) self.preorder(iter_expr)
self.preorder(ast[iter_index]) self.preorder(ast[iter_index])
@@ -1108,7 +1118,10 @@ class SourceWalker(GenericASTTraversal, object):
def n_genexpr(self, node): def n_genexpr(self, node):
self.write('(') self.write('(')
code_index = -6 if self.version > 3.2 else -5 if self.version > 3.2:
code_index = -6
else:
code_index = -5
self.comprehension_walk(node, iter_index=3, code_index=code_index) self.comprehension_walk(node, iter_index=3, code_index=code_index)
self.write(')') self.write(')')
self.prune() self.prune()
@@ -1349,7 +1362,10 @@ class SourceWalker(GenericASTTraversal, object):
break break
pass pass
pass pass
subclass_info = node if node == 'classdefdeco2' else node[0] if node == 'classdefdeco2':
subclass_info = node
else:
subclass_info = node[0]
elif buildclass[1][0] == 'load_closure': elif buildclass[1][0] == 'load_closure':
# Python 3 with closures not functions # Python 3 with closures not functions
load_closure = buildclass[1] load_closure = buildclass[1]
@@ -1376,7 +1392,10 @@ class SourceWalker(GenericASTTraversal, object):
subclass_code = buildclass[1][0].attr subclass_code = buildclass[1][0].attr
subclass_info = node[0] subclass_info = node[0]
else: else:
buildclass = node if (node == 'classdefdeco2') else node[0] if node == 'classdefdeco2':
buildclass = node
else:
buildclass = node[0]
build_list = buildclass[1][0] build_list = buildclass[1][0]
if hasattr(buildclass[-3][0], 'attr'): if hasattr(buildclass[-3][0], 'attr'):
subclass_code = buildclass[-3][0].attr subclass_code = buildclass[-3][0].attr
@@ -2069,7 +2088,9 @@ class SourceWalker(GenericASTTraversal, object):
tokens.append(Token('LAMBDA_MARKER')) tokens.append(Token('LAMBDA_MARKER'))
try: try:
ast = python_parser.parse(self.p, tokens, customize) ast = python_parser.parse(self.p, tokens, customize)
except (python_parser.ParserError, AssertionError) as e: except python_parser.ParserError, e:
raise ParserError(e, tokens)
except AssertionError, e:
raise ParserError(e, tokens) raise ParserError(e, tokens)
maybe_show_ast(self.showast, ast) maybe_show_ast(self.showast, ast)
return ast return ast
@@ -2096,7 +2117,9 @@ class SourceWalker(GenericASTTraversal, object):
# Build AST from disassembly. # Build AST from disassembly.
try: try:
ast = python_parser.parse(self.p, tokens, customize) ast = python_parser.parse(self.p, tokens, customize)
except (python_parser.ParserError, AssertionError) as e: except python_parser.ParserError, e:
raise ParserError(e, tokens)
except AssertionError, e:
raise ParserError(e, tokens) raise ParserError(e, tokens)
maybe_show_ast(self.showast, ast) maybe_show_ast(self.showast, ast)
@@ -2174,10 +2197,10 @@ def deparse_code(version, co, out=sys.stdout, showasm=None, showast=False,
if __name__ == '__main__': if __name__ == '__main__':
def deparse_test(co): def deparse_test(co):
"This is a docstring" "This is a docstring"
sys_version = sys.version_info.major + (sys.version_info.minor / 10.0) sys_version = float(sys.version[0:3])
deparsed = deparse_code(sys_version, co, showasm='after', showast=True) deparsed = deparse_code(sys_version, co, showasm='after', showast=True)
# deparsed = deparse_code(sys_version, co, showasm=None, showast=False, # deparsed = deparse_code(sys_version, co, showasm=None, showast=False,
# showgrammar=True) # showgrammar=True)
print(deparsed.text) print(deparsed.text)
return return
deparse_test(deparse_test.__code__) deparse_test(deparse_test.func_code)

View File

@@ -12,7 +12,10 @@ def maybe_show_asm(showasm, tokens):
:param tokens: The asm tokens to show. :param tokens: The asm tokens to show.
""" """
if showasm: if showasm:
stream = showasm if hasattr(showasm, 'write') else sys.stdout if hasattr(showasm, 'write'):
stream = showasm
else:
stream = sys.stdout
for t in tokens: for t in tokens:
stream.write(str(t)) stream.write(str(t))
stream.write('\n') stream.write('\n')
@@ -29,7 +32,10 @@ def maybe_show_ast(showast, ast):
:param ast: The ast to show. :param ast: The ast to show.
""" """
if showast: if showast:
stream = showast if hasattr(showast, 'write') else sys.stdout if hasattr(showast, 'write'):
stream = showast
else:
stream = sys.stdout
stream.write(str(ast)) stream.write(str(ast))
stream.write('\n') stream.write('\n')
@@ -48,7 +54,10 @@ def maybe_show_ast_param_default(showast, name, default):
:param default: The function parameter default. :param default: The function parameter default.
""" """
if showast: if showast:
stream = showast if hasattr(showast, 'write') else sys.stdout if hasattr(showast, 'write'):
stream = showast
else:
stream = sys.stdout
stream.write('\n') stream.write('\n')
stream.write('--' + name) stream.write('--' + name)
stream.write('\n') stream.write('\n')

View File

@@ -6,8 +6,6 @@
byte-code verification byte-code verification
""" """
from __future__ import print_function
import dis, operator import dis, operator
import uncompyle6 import uncompyle6
@@ -365,8 +363,10 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2,
elif member == 'co_flags': elif member == 'co_flags':
flags1 = code_obj1.co_flags flags1 = code_obj1.co_flags
flags2 = code_obj2.co_flags flags2 = code_obj2.co_flags
if is_pypy: if is_pypy or version == 2.4:
# For PYPY for now we don't care about PYPY_SOURCE_IS_UTF8: # For PYPY for now we don't care about PYPY_SOURCE_IS_UTF8:
# Python 2.4 also sets this flag and I am not sure
# where or why
flags2 &= ~0x0100 # PYPY_SOURCE_IS_UTF8 flags2 &= ~0x0100 # PYPY_SOURCE_IS_UTF8
# We also don't care about COROUTINE or GENERATOR for now # We also don't care about COROUTINE or GENERATOR for now
flags1 &= ~0x000000a0 flags1 &= ~0x000000a0
@@ -375,6 +375,8 @@ def cmp_code_objects(version, is_pypy, code_obj1, code_obj2,
raise CmpErrorMember(name, 'co_flags', raise CmpErrorMember(name, 'co_flags',
pretty_flags(flags1), pretty_flags(flags1),
pretty_flags(flags2)) pretty_flags(flags2))
else: else:
# all other members must be equal # all other members must be equal
if getattr(code_obj1, member) != getattr(code_obj2, member): if getattr(code_obj1, member) != getattr(code_obj2, member):
@@ -418,8 +420,10 @@ def compare_code_with_srcfile(pyc_filename, src_filename, weak_verify=False):
return msg return msg
try: try:
code_obj2 = load_file(src_filename) code_obj2 = load_file(src_filename)
except SyntaxError as e: except SyntaxError, e:
# src_filename can be the first of a group sometimes # src_filename can be the first of a group sometimes
if version == 2.4:
print(pyc_filename)
return str(e).replace(src_filename, pyc_filename) return str(e).replace(src_filename, pyc_filename)
cmp_code_objects(version, is_pypy, code_obj1, code_obj2, ignore_code=weak_verify) cmp_code_objects(version, is_pypy, code_obj1, code_obj2, ignore_code=weak_verify)
return None return None