Compare commits

..

144 Commits

Author SHA1 Message Date
rocky
ab414d3d9c Get ready for release 3.1.2 2018-04-08 05:34:25 -04:00
rocky
ede6eabc40 Slightly Python 3.x handing of subclasses...
which are created via a call to create a subclass.

Should be more general though.
2018-04-08 05:22:35 -04:00
rocky
61e2b3b635 Can run on 3.1. Fix some 3.1 function-call bugs 2018-04-08 04:11:01 -04:00
rocky
23fb07b1c9 Update test 2018-04-07 07:21:22 -04:00
rocky
1bbb72a6ce Handle class with one kwarg subclass 2018-04-07 07:13:49 -04:00
rocky
17361a9baa Administrivia 2018-04-06 22:11:30 -04:00
rocky
68821efdb0 Improve 3.5+ BUILD_MAP_UNPACK...
And add build_tuple_unpack runtime test from a previous commit.

We are far from out of the woods, as there is more to do and
we've uncovered more bugs in handling this.
2018-04-06 21:34:31 -04:00
rocky
e9ee671874 Testing administriva 2018-04-06 19:06:11 -04:00
rocky
9593043432 Add more stdlib run test coverage 2018-04-06 14:23:56 -04:00
rocky
1c95eb7b4e Make sure we call 'expr' go set precidence right 2018-04-06 14:04:58 -04:00
rocky
ff9ae4e792 Better handling of BUILD_TUPLE_UNPACK 2018-04-06 11:35:41 -04:00
rocky
d9eb5c5b09 Start folding in 3.5 vararg ops as varargs ops 2018-04-05 23:02:45 -04:00
rocky
e7b7de8842 Bump xdis version 2018-04-04 23:55:01 -04:00
rocky
3f26589bf1 More testing 2018-04-04 22:43:19 -04:00
rocky
30ce3a8bea Small tweaks 2018-04-04 22:36:26 -04:00
rocky
341e17f62c Split of Python 3 semantic-action customization...
And remove duplicate customization code in pysource.
2018-04-04 21:54:09 -04:00
rocky
b561b0090c Increase testing 2018-04-04 20:32:54 -04:00
rocky
ca41ea99f2 Fix 3.2 to 3.3 make_function more properly 2018-04-04 14:30:34 -04:00
rocky
e3040c78a9 3.2-3.4 Functions cals/defininitions yet again
And we're still not out of the woods.
2018-04-03 21:27:31 -04:00
rocky
a556e96c22 Merge branch 'master' of github.com:rocky/python-uncompyle6 2018-04-03 19:44:09 -04:00
rocky
e9c0d03b8b 3.2 mk_func tweak...
...more is needed though
2018-04-03 17:57:37 -04:00
rocky
155fd06372 More administrivia 2018-04-03 11:08:22 -04:00
rocky
acff1b6ee0 Administrivia
Adjust requirements-dev for 2.6.9
2018-04-03 11:00:16 -04:00
rocky
1cd2d1e915 DRY scanner code more...
Expand 2.6 testing
2018-04-03 10:35:02 -04:00
rocky
e2dec73a62 3.5 CALL_FUNCTION_VAR bug 2018-04-03 05:56:45 -04:00
rocky
fad43feb3d DRY instruction building code...
There is a little more that could be done with  self.offset2inst_index
2018-04-03 04:41:36 -04:00
rocky
96d8daeae9 More pyenv testing 2018-04-01 21:19:55 -04:00
rocky
8f6a1cb10b Add 3.2 to list of supported distributions 2018-04-01 16:54:10 -04:00
rocky
fc98bc972e Update NEWS 2018-04-01 14:53:45 -04:00
rocky
007ba4a8f3 Get ready for release 3.1.1 2018-04-01 14:17:50 -04:00
rocky
6b78677a74 Work on 3.5+ BUILD_MAP_UNPACK...
bugs still remain, just reduced.
2018-04-01 13:41:16 -04:00
rocky
ab1dba1536 Handle 3.5+ BUILD_MAP_UNPACK used in dictionaries
A number of weaknesses have been uncovered though
2018-04-01 12:56:58 -04:00
rocky
254d0519bb More 3.6 CALL_FUNCTION argument parsing 2018-04-01 11:26:46 -04:00
rocky
120412f5a8 Add Python 3.6 setcomp and another call bug 2018-04-01 07:09:24 -04:00
rocky
b54be24e14 3.6 argument parsing 2018-03-31 23:07:06 -04:00
rocky
535df1592e Another 3.6 control-flow bug...
and add source to some previous bytecode tests
2018-03-31 19:28:35 -04:00
rocky
64ffa5f6ab Add semantic action rule for except_return 2018-03-29 22:50:25 -04:00
rocky
9be4908c9c Python 3.6 MAKE_FUNCTION yet again...
And we'll eventually have to do more down the line
2018-03-29 22:04:46 -04:00
rocky
f18ce71e91 Replace all_instrs with inst_matches...
which works on 3.6+. Still should write a pytest for this.
2018-03-29 21:23:26 -04:00
rocky
362a353e03 Merge branch 'master' of github.com:rocky/python-uncompyle6 2018-03-29 17:21:51 -04:00
rocky
7d110f17bc 3.6 decompilation problems 2018-03-29 17:21:22 -04:00
R. Bernstein
04f4f3c25f Merge pull request #166 from rocky/grammer-reduce
Some 3.x grammar reduction...
2018-03-29 11:59:37 -04:00
rocky
1d5f4b0a05 Some 3.x grammar reduction...
Add 3.2 to grammar testing
2018-03-28 21:19:27 -04:00
rocky
dc3e6b31ca Limit coverage on 3.6 for now 2018-03-28 13:47:30 -04:00
rocky
94a81a36b7 3.5, 3.6 loop if/continue handling 2018-03-28 09:23:34 -04:00
rocky
e568d68baa Reinstate a test 2018-03-28 07:52:04 -04:00
R. Bernstein
8c22d57979 Merge pull request #165 from rocky/grammar-cleanup2
Grammar reduction for 2.6/2.7,3.x
2018-03-27 20:11:29 -04:00
rocky
bf0f5715a3 Adjust grammar-checking test 2018-03-27 19:47:08 -04:00
rocky
d90c44b454 3.5+ handle then before "if" jump going to loop 2018-03-27 19:24:29 -04:00
rocky
9d807501af Grammar reduction for 2.6/2.7,3.x 2018-03-27 17:02:03 -04:00
rocky
aa4416571b grammar-cover run-and-email fixup 2018-03-27 14:21:28 -04:00
rocky
d38395334c grammar-cover administrivia 2018-03-27 04:33:01 -04:00
rocky
516c7a0e9a Python 3.6 CALL_FUNCTION_EX fixes 2018-03-27 04:10:11 -04:00
rocky
681588f12d 3.5 CALL_FUNCTION_EX 2018-03-26 20:56:17 -04:00
rocky
3500c49daf More Python 3.4 CALL_FUNCTION_VAR 2018-03-26 19:40:33 -04:00
rocky
3d218c84b0 LOAD assert needs to be on 3.x...
Expand testing
2018-03-26 18:11:57 -04:00
rocky
1afe1fd943 Merge branch 'master' of github.com:rocky/python-uncompyle6 2018-03-26 14:50:54 -04:00
rocky
c5f8bbf32d Remove hacky 3.x offset address arithmetic 2018-03-26 14:50:17 -04:00
rocky
6b36d14859 Limit grammar coverage of 3.5.5 for now 2018-03-26 13:33:22 -04:00
rocky
ccbe8a8e2b cover all of 2.6.9 2018-03-26 12:55:43 -04:00
rocky
46c02bd352 There is no 2.8 2018-03-26 12:38:48 -04:00
rocky
30ba043000 Grammar coverage hacking 2018-03-26 11:12:56 -04:00
rocky
1f0e5f27d5 DRY grammar code 2018-03-26 11:08:27 -04:00
rocky
75245ba38c Back off full 2.7.14 testing for now 2018-03-26 09:47:18 -04:00
rocky
4889916304 Grammar coverage work 2018-03-26 09:26:24 -04:00
rocky
d1806edaad Administrivia: grammar coverage 2018-03-26 09:23:24 -04:00
rocky
c968e31be8 Administrivia: grammar coverage 2018-03-26 09:16:15 -04:00
rocky
c8870c6ed8 Grammar coverage hacking 2018-03-26 08:41:40 -04:00
rocky
23180806b4 More grammar coverage hacking 2018-03-26 08:19:03 -04:00
rocky
1f835d6237 Start grammar coverage testing 2018-03-26 08:03:54 -04:00
rocky
3d072e29a6 3.5 CALL_FUNCTION_VAR runnable test 2018-03-26 07:45:34 -04:00
rocky
74f01fbe33 Python 3.5 CALL_FUNCTION_VAR handling 2018-03-26 07:42:15 -04:00
rocky
710c950965 Bang on 3.4 CALL_FUNCTION_VAR 2018-03-26 00:19:39 -04:00
rocky
7aa6ff1d9b 3.6.4 runtests.sh futzing 2018-03-25 22:48:33 -04:00
rocky
421c358f9d Put 3.5.5 back into testing 2018-03-25 22:30:36 -04:00
rocky
cfb4ad625f 3.5 *() arg without further args 2018-03-25 22:24:32 -04:00
R. Bernstein
0b622a0ad8 Merge pull request #163 from rocky/grammar-cleanup
Grammar cleanup
2018-03-25 21:30:50 -04:00
rocky
8b7d5d3270 Merge branch 'master' into grammar-cleanup 2018-03-25 20:57:51 -04:00
rocky
5c7fdf6e8f Adjust stdlib tests 2018-03-25 20:55:04 -04:00
rocky
d2c8e4e12c Adjust test_grammar for recent changes 2018-03-25 20:52:28 -04:00
rocky
626f690a5a More grammar specialization by instruction 2018-03-25 20:38:21 -04:00
rocky
39cef6a41b More raise vs. assert hacky distinctions 2018-03-25 17:56:35 -04:00
rocky
116fbb33e0 Merge branch 'master' of github.com:rocky/python-uncompyle6 2018-03-25 17:36:46 -04:00
rocky
631940887f Additional Python 2.x assert vs raise testing 2018-03-25 17:35:18 -04:00
rocky
47beff57b2 Increase testing 2018-03-25 14:56:48 -04:00
rocky
7fb94176b1 Less ambigouus 2.x grammar rule for BUILD_MAP 2018-03-25 12:09:42 -04:00
rocky
2ae9cd7d08 bang on CALL_FUNCTION_EX_KW 2018-03-24 10:52:55 -04:00
rocky
1f663013ab 3.5 CALL_FUNCTION_VAR semantic handling 2018-03-24 10:24:16 -04:00
rocky
e3c7afb94d Towards handling 3.x' CALL_FUNCTION_VAR correctly 2018-03-24 08:26:45 -04:00
rocky
0d327ab0ce Fix bug introduced in last commit 2018-03-24 06:29:35 -04:00
rocky
35a60e0274 Fix parser slowness in decompiling 3.x locale.py..
And remove grammar inefficiency in adding extraneous kwargs in <= 3.2
kwargs was nullable so it might not have been wasn't wrong, just inefficient.
2018-03-23 11:59:04 -04:00
rocky
1b2b45642b 3.6 try except-as bug 2018-03-22 23:54:12 -04:00
rocky
28bfb453f5 Localize call_kw precedence to 3.6 2018-03-22 14:21:36 -04:00
rocky
df55ce3212 Isolate some 3.x dictcomp grammar rules 2018-03-22 13:34:39 -04:00
rocky
fcb4409e50 Omit 2.7 test_generators.py 2018-03-21 21:01:01 -04:00
rocky
155031a7c4 Get ready for release 3.1.0 2018-03-21 20:11:06 -04:00
rocky
c81b40b43b Comment out test/demo code 2018-03-21 20:00:25 -04:00
rocky
7fc7e083c3 A couple of 3.6 bugs...
remove parens around decorators by adjusting precidence
Partial handling of quotes within 3.6 format strings
2018-03-21 19:54:28 -04:00
rocky
d41a858f80 Messed up API compatibility 2018-03-21 17:38:38 -04:00
rocky
6dd0ad0810 Merge branch 'master' of github.com:rocky/python-uncompyle6 2018-03-21 17:01:21 -04:00
rocky
9368b63a2f Add 3.5 and 3.6 exclusions for runtests.sh...
All 3.x unit-test-type tests can be run via runtests.sh
2018-03-21 17:00:40 -04:00
rocky
da06d83a87 3.6 subclass extraction bug 2018-03-21 15:14:23 -04:00
rocky
6fb5808ff0 Merge branch 'master' of github.com:rocky/python-uncompyle6 2018-03-21 13:18:50 -04:00
rocky
0c3db340fa 2.7 bug confusing "or" with "if" and "assert" 2018-03-21 13:18:18 -04:00
rocky
925b6667d7 3.6 CALL_FUNCTION_KW handling 2018-03-21 08:01:45 -04:00
rocky
b8547346b7 Back off write "mode" setting to < 3.0 2018-03-21 00:25:41 -04:00
rocky
0aa7a7c223 Python code output should be binary...
as it may contain weird characters in strings. in 3.6 or so

r
2018-03-21 00:17:42 -04:00
rocky
cf5445c202 Test administrivia 2018-03-20 21:59:50 -04:00
rocky
bc8c38ee58 Another 2.7 runtests.sh ignore. 2018-03-20 21:01:05 -04:00
rocky
4cd81dab61 ignore 2.6.9 test in runtests.sh
It seems to fail intermittently
2018-03-20 19:29:47 -04:00
rocky
4f4b628842 Merge branch 'master' of github.com:rocky/python-uncompyle6 2018-03-20 16:15:28 -04:00
rocky
ff50a7f37b In 2.7: raise <expr>; expr can't be a "or" 2018-03-20 16:14:53 -04:00
rocky
85a49aec2f Work on fragments API...
* Add code_deparse_around_offset
* find_globals -> find_globals_and_nonlocals
2018-03-20 13:43:16 -04:00
rocky
9f2c7352e7 Administrivia: run-and-email.sh tweaks 2018-03-20 12:34:48 -04:00
rocky
e9cf370e11 Administrivia:
Adjust Travis 2.7 environment
Batch testing of all 3.4.8 pyenv files
2018-03-20 11:44:46 -04:00
rocky
90ac8a463d Adjust 3.x while1else reduction check 2018-03-20 11:33:10 -04:00
rocky
0e64111195 Extend 3.4: "while 1: if : continue" handling 2018-03-20 10:37:19 -04:00
rocky
fd84325e4f Fix status on failed runtests 2018-03-20 07:26:42 -04:00
rocky
ddc00edd42 Correct max on email subject header 2018-03-20 07:17:07 -04:00
rocky
4259963859 Increase batch testing for 3.4.8 2018-03-20 05:30:07 -04:00
rocky
4905cc6bb0 Note where 3.4's 05 test came from 2018-03-20 05:14:28 -04:00
rocky
f008b8f411 Two 3.4 fixes..
* LOAD_DEREF does not signal "nonlocal" variables
* Add rule for "if" with a "continue" and "return"
2018-03-20 05:07:19 -04:00
rocky
2e81ee5d2e Add 3.5.5 pyenv testing 2018-03-19 22:04:54 -04:00
rocky
50e59a37c1 Python 2 "for" grammar rule isolation 2018-03-19 16:15:53 -04:00
rocky
5c8f93b735 Fix 3.6 try/except with return 2018-03-19 16:12:44 -04:00
rocky
88ef4baca8 Fix a 3.6 try/except-as bug 2018-03-19 11:10:37 -04:00
rocky
6ab711baab More 3.6 lambda handling 2018-03-19 09:36:02 -04:00
rocky
9e05750537 Another 3.6 lambda parsing bug 2018-03-19 09:09:59 -04:00
rocky
5c662b334e Handle 3.x "nonlocal" statement 2018-03-19 07:57:25 -04:00
rocky
56b2e17e30 Adjust 3.6 "while" loop grammar 2018-03-19 06:01:39 -04:00
rocky
94038151f4 Add Python 3.6 mklambda rule 2018-03-18 23:37:32 -04:00
rocky
b9281c79be Fix 3.6 list if "and" comprehension bug 2018-03-18 19:12:16 -04:00
rocky
51dec051df Slightly better assert detection 2018-03-08 08:31:50 -05:00
rocky
f5ac06013f We don't do python 3.1 or 3.2 2018-03-08 02:34:05 -05:00
rocky
06bbacef45 And another 2018-03-07 13:27:20 -05:00
rocky
bfdc6529a0 One more 2018-03-07 13:24:57 -05:00
rocky
1ed389ce61 More run-and-email tweaks 2018-03-07 13:22:33 -05:00
rocky
19f2e1277b Another run-and-email shell tweak 2018-03-07 13:06:27 -05:00
rocky
6290311143 Test administrivia 2018-03-07 11:46:14 -05:00
rocky
947d619c77 Tweak summary message 2018-03-07 11:07:56 -05:00
rocky
908d313204 More test shell tweaking 2018-03-07 08:12:34 -05:00
rocky
38dffa3290 Allow setting max tests via MAX_TESTS env var 2018-03-07 08:00:36 -05:00
rocky
c8747cc899 Only run if pyenv works 2018-03-07 07:53:19 -05:00
rocky
8a705a70f5 Set pyenv version in test 2018-03-07 07:48:45 -05:00
119 changed files with 2366 additions and 1428 deletions

1
.gitignore vendored
View File

@@ -21,3 +21,4 @@
ChangeLog
__pycache__
build
nohup.out

View File

@@ -4,7 +4,7 @@ sudo: false
python:
- '3.5'
- '2.7.12'
- '2.7'
- '2.6'
- '3.3'
- '3.4'

View File

@@ -27,21 +27,18 @@ check:
check-short: pytest
$(MAKE) -C test check-short
# Note for 2.6 use <=3.0.1 see requirements-dev.txt
#: Tests for Python 2.7, 3.3 and 3.4
check-2.7 check-3.3 check-3.4: pytest
check-2.6 check-2.7 check-3.3 check-3.4 check-3.5: pytest
$(MAKE) -C test $@
#: Tests for Python 3.2 and 3.5 - pytest doesn't work here
# Or rather 3.5 doesn't work not on Travis
check-3.0 check-3.1 check-3.2 check-3.5 check-3.6:
check-3.0 check-3.1 check-3.2 check-3.6:
$(MAKE) -C test $@
check-3.7: pytest
#:Tests for Python 2.6 (doesn't have pytest)
check-2.6:
$(MAKE) -C test $@
#:PyPy 2.6.1 PyPy 5.0.1, or PyPy 5.8.0-beta0
# Skip for now
2.6 5.0 5.3 5.6 5.8:

29
NEWS
View File

@@ -1,3 +1,32 @@
uncompyle6 3.1.2 2018-04-08 Eastern Orthodox Easter
- Python 3.x subclass and call parsing fixes
- Allow/note running on Python 3.1
- improve 3.5+ BUILD_MAP_UNPACK
- DRY instruction building code between 2.x and 3.x
- expand testing
uncompyle6 3.1.1 2018-04-01 Easter April Fool's
Jesus on Friday's New York Times puzzle: "I'm stuck on 2A"
- fill out 3.5+ BUILD_MAP_UNPACK (more work is needed)
- fill out 3.4+ CALL_FUNCTION_... (more work is needed)
- fill out 3.5 MAKE_FUNCTION (more work is needed)
- reduce 3.5, 3.6 control-flow bugs
- reduce ambiguity in rules that lead to long (exponential?) parses
- limit/isolate some 2.6/2.7,3.x grammar rules
- more runtime testing of decompiled code
- more removal of parenthesis around calls via setting precidence
uncompyle6 3.1.0 2018-03-21 Equinox
- Add code_deparse_with_offset() fragment function.
- Correct paramenter call fragment deparse_code()
- Lots of 3.6, 3.x, and 2.7 bug fixes
About 5% of 3.6 fail parsing now. But
semantics still needs much to be desired.
uncompyle6 3.0.1 2018-02-17
- All Python 2.6.9 standard library files weakly verify

View File

@@ -56,7 +56,7 @@ entry_points = {
]}
ftp_url = None
install_requires = ['spark-parser >= 1.8.5, < 1.9.0',
'xdis >= 3.7.0, < 3.8.0', 'six']
'xdis >= 3.8.0, < 3.9.0', 'six']
license = 'GPL3'
mailing_list = 'python-debugger@googlegroups.com'

View File

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

View File

@@ -1,8 +1,6 @@
#!/usr/bin/env python
from uncompyle6 import PYTHON_VERSION, IS_PYPY
from uncompyle6.scanner import get_scanner
from xdis.bytecode import Bytecode
from array import array
def bug(state, slotstate):
if state:
if slotstate is not None:
@@ -24,16 +22,8 @@ def bug_loop(disassemble, tb=None):
def test_if_in_for():
code = bug.__code__
scan = get_scanner(PYTHON_VERSION)
print(PYTHON_VERSION)
if 2.7 <= PYTHON_VERSION <= 3.0 and not IS_PYPY:
n = scan.setup_code(code)
bytecode = Bytecode(code, scan.opc)
scan.build_lines_data(code, n)
scan.insts = list(bytecode)
scan.offset2inst_index = {}
for i, inst in enumerate(scan.insts):
scan.offset2inst_index[inst.offset] = i
scan.build_prev_op(n)
scan.build_instructions(code)
fjt = scan.find_jump_targets(False)
## FIXME: the data below is wrong.
@@ -48,14 +38,7 @@ def test_if_in_for():
# {'start': 62, 'end': 63, 'type': 'for-else'}]
code = bug_loop.__code__
n = scan.setup_code(code)
bytecode = Bytecode(code, scan.opc)
scan.build_lines_data(code, n)
scan.insts = list(bytecode)
scan.build_prev_op(n)
scan.offset2inst_index = {}
for i, inst in enumerate(scan.insts):
scan.offset2inst_index[inst.offset] = i
scan.build_instructions(code)
fjt = scan.find_jump_targets(False)
assert{64: [42], 67: [42, 42], 42: [16, 41], 19: [6]} == fjt
assert scan.structs == [
@@ -69,14 +52,7 @@ def test_if_in_for():
{'start': 48, 'end': 67, 'type': 'while-loop'}]
elif 3.2 < PYTHON_VERSION <= 3.4:
bytecode = Bytecode(code, scan.opc)
scan.code = array('B', code.co_code)
scan.lines = scan.build_lines_data(code)
scan.build_prev_op()
scan.insts = list(bytecode)
scan.offset2inst_index = {}
for i, inst in enumerate(scan.insts):
scan.offset2inst_index[inst.offset] = i
scan.build_instructions(code)
fjt = scan.find_jump_targets(False)
assert {69: [66], 63: [18]} == fjt
assert scan.structs == \
@@ -86,5 +62,6 @@ def test_if_in_for():
{'end': 59, 'type': 'for-loop', 'start': 31},
{'end': 63, 'type': 'for-else', 'start': 62}]
else:
assert True, "FIXME: should note fixed"
print("FIXME: should fix for %s" % PYTHON_VERSION)
assert True
return

View File

@@ -6,7 +6,7 @@ import pytest
# uncompyle
from validate import validate_uncompyle
from test_fstring import expressions
from uncompyle6 import PYTHON_VERSION
alpha = st.sampled_from(string.ascii_lowercase)
numbers = st.sampled_from(string.digits)
@@ -81,7 +81,8 @@ def function_calls(draw,
def test_function_no_args():
validate_uncompyle("fn()")
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
reason="need at least Python 2.7")
def isolated_function_calls(which):
"""
Returns a strategy for generating function calls, but isolated to
@@ -108,21 +109,29 @@ def isolated_function_calls(which):
with settings(max_examples=25):
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
reason="need at least Python 2.7")
@given(isolated_function_calls('positional'))
@example("fn(0)")
def test_function_positional_only(expr):
validate_uncompyle(expr)
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
reason="need at least Python 2.7")
@given(isolated_function_calls('keyword'))
@example("fn(a=0)")
def test_function_call_keyword_only(expr):
validate_uncompyle(expr)
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
reason="need at least Python 2.7")
@given(isolated_function_calls('star'))
@example("fn(*items)")
def test_function_call_star_only(expr):
validate_uncompyle(expr)
@pytest.mark.skipif(PYTHON_VERSION < 2.7,
reason="need at least Python 2.7")
@given(isolated_function_calls('double_star'))
@example("fn(**{})")
def test_function_call_double_star_only(expr):

View File

@@ -18,40 +18,44 @@ def test_grammar():
right_recursive, dup_rhs) = p.check_sets()
# We have custom rules that create the below
expect_lhs = set(['expr1024', 'pos_arg', 'get_iter', 'attribute'])
expect_lhs = set(['pos_arg', 'get_iter', 'attribute'])
unused_rhs = set(['list', 'mkfunc',
'mklambda',
'unpack',])
expect_right_recursive = set([('designList',
('store', 'DUP_TOP', 'designList'))])
if PYTHON3:
expect_lhs.add('load_genexpr')
if PYTHON_VERSION > 2.6:
expect_lhs.add('kvlist')
expect_lhs.add('kv3')
unused_rhs.add('dict')
if PYTHON3:
expect_lhs.add('load_genexpr')
unused_rhs = unused_rhs.union(set("""
except_pop_except generator_exp classdefdeco2
dict
except_pop_except generator_exp
""".split()))
if PYTHON_VERSION >= 3.0:
expect_lhs.add("annotate_arg")
expect_lhs.add("annotate_tuple")
unused_rhs.add("mkfunc_annotate")
unused_rhs.add('call')
unused_rhs.add("dict_comp")
unused_rhs.add("classdefdeco1")
if PYTHON_VERSION < 3.6:
# 3.6 has at least one non-custom call rule
# the others don't
unused_rhs.add('call')
if PYTHON_VERSION == 3.5:
expect_right_recursive.add((('l_stmts',
('lastl_stmt', 'COME_FROM', 'l_stmts'))))
('lastl_stmt', 'come_froms', 'l_stmts'))))
pass
pass
else:
expect_right_recursive.add((('l_stmts',
('lastl_stmt', 'COME_FROM', 'l_stmts'))))
# expect_lhs.add('kwargs1')
pass
pass
pass
@@ -85,6 +89,8 @@ def test_grammar():
""".split())
if 2.6 <= PYTHON_VERSION <= 2.7:
opcode_set = set(s.opc.opname).union(ignore_set)
if PYTHON_VERSION == 2.6:
opcode_set.add("THEN")
check_tokens(tokens, opcode_set)
elif PYTHON_VERSION == 3.4:
ignore_set.add('LOAD_CLASSNAME')

View File

@@ -1,6 +1,8 @@
import pytest
from uncompyle6 import PYTHON_VERSION, PYTHON3, deparse_code
from uncompyle6 import PYTHON_VERSION, deparse_code
@pytest.mark.skip(PYTHON_VERSION < 2.7,
reason="need at least Python 2.7")
def test_single_mode():
single_expressions = (
'i = 1',

View File

@@ -1,3 +1,3 @@
pytest>=3.0.0
pytest>=3.0.0,<=3.0.1
flake8
hypothesis<=3.8.3
hypothesis<=3.0.0

View File

@@ -4,12 +4,12 @@ import sys
"""Setup script for the 'uncompyle6' distribution."""
SYS_VERSION = sys.version_info[0:2]
if not ((2, 6) <= SYS_VERSION <= (3, 7)) or ((3, 0) <= SYS_VERSION <= (3, 1)):
mess = "Python Release 2.6 .. 3.7 excluding 3.0 and 3.1 are supported in this code branch."
if not ((2, 6) <= SYS_VERSION <= (3, 7)) or ((3, 0) <= SYS_VERSION <= (3, 0)):
mess = "Python Release 2.6 .. 3.7 excluding 3.0 are supported in this code branch."
if ((2, 4) <= SYS_VERSION <= (2, 7)):
mess += ("\nFor your Python, version %s, use the python-2.4 code/branch." %
sys.version[0:3])
elif SYS_VERSION < (2, 4) or ((3, 0) <= SYS_VERSION <= (3, 1)):
elif SYS_VERSION < (2, 4) or (3, 0) <= SYS_VERSION:
mess += ("\nThis package is not supported for Python version %s."
% sys.version[0:3])
print(mess)

1
test/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/nohup.out

View File

@@ -3,9 +3,9 @@ PHONY=check clean dist distclean test test-unit test-functional rmChangeLog clea
check-bytecode-2.2 check-byteocde-2.3 check-bytecode-2.4 \
check-short check-2.6 check-2.7 check-3.0 check-3.1 check-3.2 check-3.3 \
check-3.4 check-3.5 check-5.6 5.6 5.8 \
grammar-coverage-2.5 grammar-coverage-2.6 grammarcoverage-2.7 \
grammar-coverage-3.1 grammar-coverage-3.2 grammarcoverage-3.3 \
grammar-coverage-3.4 grammar-coverage-3.5 grammarcoverage-3.6
grammar-coverage-2.5 grammar-coverage-2.6 grammar-coverage-2.7 \
grammar-coverage-3.1 grammar-coverage-3.2 grammar-coverage-3.3 \
grammar-coverage-3.4 grammar-coverage-3.5 grammar-coverage-3.6
GIT2CL ?= git2cl
@@ -37,18 +37,22 @@ check-3.0: check-bytecode
#: Run working tests from Python 3.1
check-3.1: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.1 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.1-run --verify-run
#: Run working tests from Python 3.2
check-3.2: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.2 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.2-run --verify-run
#: Run working tests from Python 3.3
check-3.3: check-bytecode
$(PYTHON) test_pythonlib.py --bytecode-3.3 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.3-run --verify-run
#: Run working tests from Python 3.4
check-3.4: check-bytecode check-3.4-ok check-2.7-ok
$(PYTHON) test_pythonlib.py --bytecode-3.4 --weak-verify $(COMPILE)
$(PYTHON) test_pythonlib.py --bytecode-3.4-run --verify-run
#: Run working tests from Python 3.5
check-3.5: check-bytecode
@@ -114,23 +118,29 @@ check-bytecode-2.4:
check-bytecode-2.5:
$(PYTHON) test_pythonlib.py --bytecode-2.5
#: Get grammar coverage for Python 2.4
grammar-coverage-2.4:
-rm $(COVER_DIR)/spark-grammar-24.cover
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.4.cover $(PYTHON) test_pythonlib.py --bytecode-2.4
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.4.cover $(PYTHON) test_pyenvlib.py --2.4.6 --max= 800
#: Get grammar coverage for Python 2.5
grammar-coverage-2.5:
-rm $(COVER_DIR)/spark-grammar-25.cover
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-25.cover $(PYTHON) test_pythonlib.py --bytecode-2.5
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-25.cover $(PYTHON) test_pyenvlib.py --2.5.6
-rm $(COVER_DIR)/spark-grammar-2.5.cover || true
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.5.cover $(PYTHON) test_pythonlib.py --bytecode-2.5
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.5.cover $(PYTHON) test_pyenvlib.py --2.5.6 --max=800
#: Get grammar coverage for Python 2.6
grammar-coverage-2.6:
-rm $(COVER_DIR)/spark-grammar-26.cover
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-26.cover $(PYTHON) test_pythonlib.py --bytecode-2.6
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-26.cover $(PYTHON) test_pyenvlib.py --2.6.9
-rm $(COVER_DIR)/spark-grammar-2.6.cover || true
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.6.cover $(PYTHON) test_pythonlib.py --bytecode-2.6
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.6.cover $(PYTHON) test_pyenvlib.py --2.6.9 --max=800
#: Get grammar coverage for Python 2.7
grammar-coverage-2.7:
-rm $(COVER_DIR)/spark-grammar-27.cover
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-27.cover $(PYTHON) test_pythonlib.py --bytecode-2.7
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-27.cover $(PYTHON) test_pyenvlib.py --2.7.13
-rm $(COVER_DIR)/spark-grammar-2.7.cover || true
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.7.cover $(PYTHON) test_pythonlib.py --bytecode-2.7
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-2.7.cover $(PYTHON) test_pyenvlib.py --2.7.14 --max=600
#: Get grammar coverage for Python 3.0
grammar-coverage-3.0:
@@ -141,33 +151,39 @@ SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-30.cover $(PYTHON) test_pythonl
#: Get grammar coverage for Python 3.1
grammar-coverage-3.1:
-rm $(COVER_DIR)/spark-grammar-31.cover
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-31.cover $(PYTHON) test_pythonlib.py --bytecode-3.1
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-31.cover $(PYTHON) test_pyenvlib.py --3.1.5
-rm $(COVER_DIR)/spark-grammar-3.1.cover
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.1.cover $(PYTHON) test_pythonlib.py --bytecode-3.1
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.1.cover $(PYTHON) test_pyenvlib.py --3.1.5
#: Get grammar coverage for Python 3.2
grammar-coverage-3.2:
-rm $(COVER_DIR)/spark-grammar-32.cover
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-32.cover $(PYTHON) test_pythonlib.py --bytecode-3.2
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-32.cover $(PYTHON) test_pyenvlib.py --3.2.6
-rm $(COVER_DIR)/spark-grammar-3.2.cover || true
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.2.cover $(PYTHON) test_pythonlib.py --bytecode-3.2
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.2.cover $(PYTHON) test_pyenvlib.py --3.2.6
#: Get grammar coverage for Python 3.3
grammar-coverage-3.3:
-rm $(COVER_DIR)/spark-grammar-33.cover
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-33.cover $(PYTHON) test_pythonlib.py --bytecode-3.3
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-33.cover $(PYTHON) test_pyenvlib.py --3.3.6
-rm $(COVER_DIR)/spark-grammar-3.3.cover || true
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.3.cover $(PYTHON) test_pythonlib.py --bytecode-3.3
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.3.cover $(PYTHON) test_pyenvlib.py --3.3.7 --max=800
#: Get grammar coverage for Python 3.4
grammar-coverage-3.4:
-rm $(COVER_DIR)/spark-grammar-34.cover
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-34.cover $(PYTHON) test_pythonlib.py --bytecode-3.4
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-34.cover $(PYTHON) test_pyenvlib.py --3.4.2
-rm $(COVER_DIR)/spark-grammar-3.4.cover || true
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.4.cover $(PYTHON) test_pythonlib.py --bytecode-3.4
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.4.cover $(PYTHON) test_pyenvlib.py --3.4.8 --max=800
#: Get grammar coverage for Python 3.5
grammar-coverage-3.5:
rm $(COVER_DIR)/spark-grammar-35.cover || /bin/true
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-35.cover $(PYTHON) test_pythonlib.py --bytecode-3.5
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-35.cover $(PYTHON) test_pyenvlib.py --3.5.3
rm $(COVER_DIR)/spark-grammar-3.5.cover || /bin/true
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.5.cover $(PYTHON) test_pythonlib.py --bytecode-3.5
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.5.cover $(PYTHON) test_pyenvlib.py --3.5.5 --max=450
#: Get grammar coverage for Python 3.6
grammar-coverage-3.6:
rm $(COVER_DIR)/spark-grammar-3.6.cover || /bin/true
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.6.cover $(PYTHON) test_pythonlib.py --bytecode-3.6
SPARK_PARSER_COVERAGE=$(COVER_DIR)/spark-grammar-3.6.cover $(PYTHON) test_pyenvlib.py --3.6.4 --max=280
#: Check deparsing Python 2.6
check-bytecode-2.6:
@@ -186,10 +202,12 @@ check-bytecode-3.0:
#: Check deparsing Python 3.1
check-bytecode-3.1:
$(PYTHON) test_pythonlib.py --bytecode-3.1 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-3.1-run --verify-run
#: Check deparsing Python 3.2
check-bytecode-3.2:
$(PYTHON) test_pythonlib.py --bytecode-3.2 --weak-verify
$(PYTHON) test_pythonlib.py --bytecode-3.2-run --verify-run
#: Check deparsing Python 3.3
check-bytecode-3.3:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
test/grammar-cover/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/.python-version

View File

@@ -0,0 +1 @@
Code in this directory gets statistics on grammar coverage

5
test/grammar-cover/convert.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
for VERS in 2{4,5,6,7} 3{2,3,4,5} ; do
GRAMMAR_TXT=grammar-${VERS}.txt
spark-parser-coverage --max-count 3000 --path spark-grammar-${VERS}.cover > $GRAMMAR_TXT
done

View File

@@ -0,0 +1,2 @@
#!/bin/bash
$SHELL ./grammar.sh 2.4 2.5 2.6 2.7 3.2 3.3 3.4 3.5 3.6

44
test/grammar-cover/grammar.sh Executable file
View File

@@ -0,0 +1,44 @@
#!/bin/bash
# Remake Python grammar statistics
typeset -A ALL_VERS=([2.4]=2.4.6 [2.5]=2.5.6 [2.6]=2.6.9 [2.7]=2.7.14 [3.2]=3.2.6 [3.3]=3.3.6 [3.4]=3.4.8 [3.5]=3.5.5 [3.6]=3.6.4)
if (( $# == 0 )); then
echo 1>&2 "usage: $0 two-digit-version"
exit 1
fi
me=${BASH_SOURCE[0]}
workdir=$(dirname $me)
cd $workdir
workdir=$(pwd)
while [[ -n $1 ]] ; do
SHORT_VERSION=$1; shift
LONG_VERSION=${ALL_VERS[$SHORT_VERSION]}
if [[ -z ${LONG_VERSION} ]] ; then
echo 1>&2 "Version $SHORT_VERSION not known"
exit 2
fi
tmpdir=$workdir/../../tmp/grammar-cover
COVER_FILE=${tmpdir}/spark-grammar-${SHORT_VERSION}.cover
[[ -d $tmpdir ]] || mkdir $tmpdir
cd $workdir/../..
if [[ $SHORT_VERSION > 2.5 ]] ; then
source ./admin-tools/setup-master.sh
else
source ./admin-tools/setup-python-2.4.sh
fi
GRAMMAR_TXT=$tmpdir/grammar-${SHORT_VERSION}.txt
(cd ../.. && pyenv local ${LONG_VERSION})
cd ./test
if [[ -r $COVER_FILE ]]; then
rm $COVER_FILE
fi
if [[ -r $GRAMMAR_TXT ]]; then
GRAMMAR_SAVE_TXT=${tmpdir}/grammar-${SHORT_VERSION}-save.txt
cp $GRAMMAR_TXT $GRAMMAR_SAVE_TXT
fi
make grammar-coverage-${SHORT_VERSION};
spark-parser-coverage --max-count=3000 --path $COVER_FILE > $GRAMMAR_TXT
done

View File

@@ -0,0 +1,13 @@
#!/bin/bash
USER=${USER:-rocky}
EMAIL=${EMAIL:-rb@dustyfeet.com}
SUBJECT_PREFIX="grammar cover testing for"
LOGFILE=/tmp/grammar-cover-$$.log
/bin/bash ./grammar-all.sh >$LOGFILE 2>&1
rc=$?
if ((rc == 0)); then
tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX ok" ${USER}@localhost
else
tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX not ok" ${USER}@localhost
tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX not ok" $EMAIL
fi

View File

@@ -1,13 +1,69 @@
#!/usr/bin/bash
#!/bin/bash
function displaytime {
printf "ran in "
local T=$1
local D=$((T/60/60/24))
local H=$((T/60/60%24))
local M=$((T/60%60))
local S=$((T%60))
(( $D > 0 )) && printf '%d days ' $D
(( $H > 0 )) && printf '%d hours ' $H
(( $M > 0 )) && printf '%d minutes ' $M
(( $D > 0 || $H > 0 || $M > 0 )) && printf 'and '
printf '%d seconds\n' $S
}
PYVERSION=${PYVERSION:-"3.5.5 2.7.14 3.2.6 3.3.7 3.4.8 2.6.9 3.6.4"}
# PYVERSION=${PYVERSION:-"3.5.5"}
USER=${USER:-rocky}
EMAIL=${EMAIL:-rb@dustyfeet.com}
for VERSION in 2.7.14 2.6.9 ; do
LOGFILE=/tmp/pyenlib-$VERSION-$$.log
python ./test_pyenvlib.py --max 800 --weak-verify --$VERSION >$LOGFILE 2>&1
rc=$?
if ((rc == 0)); then
tail -v $LOGFILE | mail -s \""$VERSION ok"\" rocky@localhost
MAX_TESTS=${MAX_TESTS:-800}
typeset -i RUN_STARTTIME=$(date +%s)
for VERSION in $PYVERSION ; do
typeset -i rc=0
LOGFILE=/tmp/pyenvlib-$VERSION-$$.log
if [[ $VERSION == '3.5.5' ]] ; then
MAX_TESTS=224
elif [[ $VERSION == '3.2.6' ]] ; then
MAX_TESTS=700
elif [[ $VERSION == '3.6.4' ]] ; then
MAX_TESTS=400
else
tail -v $LOGFILE | mail -s \""$VERSION not ok"\" rocky@localhost
tail -v $LOGFILE | mail -s \""$VERSION not ok"\" rb@dustyfeet.com
MAX_TESTS=800
fi
if ! pyenv local $VERSION ; then
rc=1
else
echo Python Version $(pyenv local) > $LOGFILE
echo "" >> $LOGFILE
typeset -i ALL_FILES_STARTTIME=$(date +%s)
python ./test_pyenvlib.py --max ${MAX_TESTS} --weak-verify --$VERSION >>$LOGFILE 2>&1
rc=$?
echo Python Version $(pyenv local) >> $LOGFILE
echo "" >>$LOGFILE
typeset -i ALL_FILES_ENDTIME=$(date +%s)
(( time_diff = ALL_FILES_ENDTIME - ALL_FILES_STARTTIME))
displaytime $time_diff >> $LOGFILE
fi
SUBJECT_PREFIX="pyenv weak verify (max $MAX_TESTS) for"
if ((rc == 0)); then
tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION ok" ${USER}@localhost
else
tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION not ok" ${USER}@localhost
tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION not ok" ${EMAIL}
fi
rm .python-version
done
typeset -i RUN_ENDTIME=$(date +%s)
(( time_diff = RUN_ENDTIME - RUN_STARTTIME))
elapsed_time=$(displaytime $time_diff)
echo "Run complete $elapsed_time for versions $PYVERSION" | mail -s "pyenv weak verify in $elapsed_time" ${EMAIL}

View File

@@ -0,0 +1,18 @@
# Bug found in 2.4 test_math.py
# Bug was turning last try/except/else into try/else
import math
def test_exceptions():
try:
x = math.exp(-1000000000)
except:
raise RuntimeError
x = 1
try:
x = math.sqrt(-1.0)
except ValueError:
return x
else:
raise RuntimeError
test_exceptions()

View File

@@ -0,0 +1,31 @@
# From 2.7 test_argparse.py
# Bug was turning assert into an "or raise" statement
def __call__(arg, dest):
try:
assert arg == 'spam', 'dest: %s' % dest
except:
raise
__call__('spam', __file__)
# From python 2.7.14 lib2to3/refactor.py
# Bug was mangling assert turning if into "or"
def refactor_doctest(clipped, new):
assert clipped, clipped
if not new:
new += u"\n"
return
# From 2.7.14 test_hashlib.py
# The bug was turning assert into an "if"
# statement which isn't wrong, but we got the
# range of the if incorrect. When we have
# better control flow analysis we can revisit.
def test_threaded_hashing():
for threadnum in xrange(1):
result = 1
assert result > 0
result = 2
return result
assert test_threaded_hashing() == 2

View File

@@ -1,5 +1,5 @@
# From 2.7 test_itertools.py
# Bug was in 2.7 decompiling like the commented out
# Bug was in 2.7 decompiling the target assignment
# code below
from itertools import izip_longest
for args in [

View File

@@ -0,0 +1,18 @@
# Extracted from Python 3.5 test_abc.py
# Bug is class having only a single kwarg
# subclass.
import abc
import unittest
from inspect import isabstract
def test_abstractmethod_integration(self):
for abstractthing in [abc.abstractmethod]:
class C(metaclass=abc.ABCMeta):
@abstractthing
def foo(self): pass # abstract
def bar(self): pass # concrete
assert C.__abstractmethods__, {"foo"}
assert isabstract(C)
pass
test_abstractmethod_integration(None)

View File

@@ -1,5 +1,6 @@
# Python 3.6 subprocess.py bug
# Bug is getting params correct: timeout before **kwargs
import subprocess
def call(*popenargs, timeout=None, **kwargs):
return
@@ -14,6 +15,9 @@ def subprocess_shell(self, protocol_factory, cmd, *, stdin=subprocess.PIPE,
# From 3.4 asyncio/locks.py
# Bug was handling" "value=1, *"
class Semaphore:
pass
class BoundedSemaphore(Semaphore):
def __init__(self, value=1, *, loop=None):
super().__init__(value, loop=loop)

View File

@@ -0,0 +1,12 @@
# From Python 3.6 functools.py
# Bug was in detecting "nonlocal" access
def not_bug():
cache_token = 5
def register():
nonlocal cache_token
return cache_token == 5
return register()
assert not_bug()

View File

@@ -0,0 +1,37 @@
# Bug in Python 3.4 text_file.py
# Bug is handling: while true ... if ... continue
def readline(b):
a = 1
while True:
if b:
if b[0]:
a = 2
b = None
continue
b = None
a = 5
return a
assert readline(None) == 1
assert readline([2]) == 2
def readline2(self):
while True:
line = 5
if self[0]:
if self:
self[0] = 1
continue
return line + self[0]
# From 3.4.4 connection.py
def PipeClient(address):
while 1:
try:
address += 1
except OSError as e:
raise e
else:
raise

View File

@@ -0,0 +1,13 @@
# From 3.6.4 pathlib.py
# Bug was handling "continue" as last statement of "if"
# RUNNABLE!
def parse_parts(it, parts):
for part in it:
if not part:
continue
parts = 1
return parts
assert parse_parts([], 5) == 5
assert parse_parts([True], 6) == 1
assert parse_parts([False], 6) == 6

View File

@@ -1,9 +1,19 @@
# Python 3.5+ PEP 448 - Additional Unpacking Generalizations for dictionaries
{**{}}
{**{'a': 1, 'b': 2}}
## {**{'x': 1}, **{'y': 2}}
# RUNNABLE!
b = {**{}}
assert b == {}
c = {**{'a': 1, 'b': 2}}
assert c == {'a': 1, 'b': 2}
d = {**{'x': 1}, **{'y': 2}}
assert d == {'x': 1, 'y': 2}
# {'c': 1, {'d': 2}, **{'e': 3}}
[*[]]
{**{0:0 for a in b}}
## {**{}, **{}}
## {**{}, **{}, **{}}
assert {0: 0} == {**{0:0 for a in c}}
# FIXME: assert deparsing is incorrect for:
# {**{}, **{}}
# assert {} == {**{}, **{}, **{}}
# {**{}, **{}, **{}}
# assert {} == {**{}, **{}, **{}}

View File

@@ -0,0 +1,23 @@
# From python 3.5.5 telnetlib
# The bug is the end of a "then" jumping
# back to the loop which could look like
# a "continue" and also not like a then/else
# break
def process_rawq(self, cmd, cmd2):
while self.rawq:
if self.iacseq:
if cmd:
pass
elif cmd2:
if self.option_callback:
self.option = 2
else:
self.option = 3
# From python 3.5.5 telnetlib
def listener(data):
while 1:
if data:
data = 1
else:
data = 2

View File

@@ -1,5 +1,8 @@
# From sql/schema.py and 3.5 _strptime.py
# Note that kwargs comes before "positional" args
# Bug was code not knowing which Python versions
# have kwargs coming before positional args in code.
# RUNNABLE!
def tometadata(self, metadata, schema, Table, args, name=None):
table = Table(
@@ -10,3 +13,69 @@ def tometadata(self, metadata, schema, Table, args, name=None):
def _strptime_datetime(cls, args):
return cls(*args)
# From 3.5.5 imaplib
# Bug is in parsing *date_time[:6] parameter
from datetime import datetime, timezone, timedelta
import time
def Time2Internaldate(date_time):
delta = timedelta(seconds=0)
return datetime(*date_time[:6], tzinfo=timezone(delta))
assert Time2Internaldate(time.localtime())
# From 3.5.5 tkinter/dialog.py
def test_varargs0_ext():
try:
{}.__contains__(*())
except TypeError:
pass
test_varargs0_ext()
# From 3.4.6 tkinter/dialog.py
# Bug is in position of *cnf.
def __init__(self, cnf={}):
self.num = self.tk.call(
'tk_dialog', self._w,
cnf['title'], cnf['text'],
cnf['bitmap'], cnf['default'],
*cnf['strings'])
# From python 3.4.8 multiprocessing/context.py
def Value(self, fn, typecode_or_type, *args, lock=True):
return fn(typecode_or_type, *args, lock=lock,
ctx=self.get_context())
# From 3.6.4 heapq.py
def merge(*iterables, key=None, reverse=False):
return
def __call__(self, *args, **kwds):
pass
# From 3.6.4 shutil
def unpack_archive(func, filename, dict, format_info, extract_dir=None):
func(filename, extract_dir, **dict(format_info[2]))
# From 3.5.5 test_xrdrlib.py
import xdrlib
def assertRaisesConversion(self, *args):
self.assertRaises(xdrlib.ConversionError, *args)
# From 3.2.6 _pyio.py
class BlockingIOError(IOError):
def __init__(self, errno, strerror, characters_written=5):
super().__init__(errno, strerror)
# From urllib/parse.py
# Bug was using a subclass made from a call (to namedtuple)
from collections import namedtuple
class ResultMixin(object):
pass
class SplitResult(namedtuple('SplitResult', 'scheme netloc path query fragment'), ResultMixin):
pass

View File

@@ -0,0 +1,12 @@
# From 3.6.4 pdb.py
# Bug was not having a semantic action for "except_return" tree
def do_commands(self, arg):
if not arg:
bnum = 1
else:
try:
bnum = int(arg)
except:
self.error("Usage:")
return
self.commands_bnum = bnum

View File

@@ -0,0 +1,10 @@
# Adapted from Python 3.6 trace.py
# Bug was in handling BUID_TUPLE_UNPACK created via
# *opts.arguments
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('filename', nargs='?')
parser.add_argument('arguments', nargs=argparse.REMAINDER)
opts = parser.parse_args(["foo", "a", "b"])
argv = opts.filename, *opts.arguments
assert argv == ('foo', 'a', 'b')

View File

@@ -1,5 +1,18 @@
# Self-checking 3.6+ string interpolation tests
var1 = 'x'
var2 = 'y'
print(f'interpolate {var1} strings {var2!r} {var2!s} py36')
print(f'{abc}0')
print(f'{abc}{abc!s}')
abc = 'def'
assert (f'interpolate {var1} strings {var2!r} {var2!s} py36' ==
"interpolate x strings 'y' y py36")
assert 'def0' == f'{abc}0'
assert 'defdef' == f'{abc}{abc!s}'
# From 3.6 functools.py
# Bug was handling format operator strings.
k, v = "1", ["2"]
x = f"{k}={v!r}"
y = f"functools.{x}({', '.join(v)})"
assert x == "1=['2']"
assert y == "functools.1=['2'](2)"

View File

@@ -1,5 +1,13 @@
# From 3.6 _markupbase _parse_doctype_subset()
def bug(self, j):
def bug(self, j, a, b):
self.parse_comment(j, report=0)
self.parse_comment(j, report=1, foo=2)
self.parse_comment(a, b, report=3)
# From 3.6 fnmatch.py
# Bug was precidence parenthesis around decorator
import functools
@functools.lru_cache(maxsize=256, typed=True)
def _compile_pattern(pat):
pass

View File

@@ -0,0 +1,30 @@
# From Python 3.6 bdb.py
# Bug was handling try's with returns
# END_FINALLY in 3.6 starts disasppearing
def effective(possibles):
for b in possibles:
try:
return 1
except:
return 2
return 3
assert effective([5]) == 1
assert effective([]) == 3
def effective2(possibles):
b = 0
for b in possibles:
try:
if b >= 5:
b = 5
else:
return 2
except:
return 3
return b
assert effective2([5]) == 5
assert effective2([]) == 0
assert effective2(['a']) == 3

View File

@@ -0,0 +1,17 @@
# From 3.6 test_abc.py
# Bug was Reciever() class definition
import abc
import unittest
class TestABCWithInitSubclass(unittest.TestCase):
def test_works_with_init_subclass(self):
class ReceivesClassKwargs:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__()
class Receiver(ReceivesClassKwargs, abc.ABC, x=1, y=2, z=3):
pass
def test_abstractmethod_integration(self):
for abstractthing in [abc.abstractmethod]:
class C(metaclass=abc.ABCMeta):
@abstractthing
def foo(self): pass # abstract

View File

@@ -18,3 +18,31 @@ def getvalue1(self):
finally:
pass
return 2
# From Python 3.6 asynchat.py
# Bug is handling as why in the face of a return.
# uncompyle6 shows removal of "why" after the return.
def handle_read(self):
try:
data = 5
except ZeroDivisionError:
return
except OSError as why:
return why
return data
# From 3.6 contextlib
# Bug is indentation of "return exc"
# Also there are extra statements to remove exec,
# which we hide (unless doing fragments).
# Note: The indentation bug may be a result of using improper
# grammar.
def __exit__(self, type, value, traceback):
try:
value()
except StopIteration as exc:
return exc
except RuntimeError as exc:
return exc
return

View File

@@ -0,0 +1,13 @@
# From 3.6.4 configparser.py
# Bug in 3.6 was handling "else" with compound
# if. there is no POP_BLOCK and
# there are several COME_FROMs before the else
def _read(self, fp, a, value, f):
for line in fp:
for prefix in a:
fp()
if (value and fp and
prefix > 5):
f()
else:
f()

View File

@@ -0,0 +1,20 @@
# From Python 3.6 hmac.py
# needed to change mklambda rule
def __init__(self, msg = None, digestmod = None):
self.digest_cons = lambda d='': digestmod.new(d)
# From Python 3.6 functools.py
# Bug was handling lambda for MAKE_FUNCTION_8 (closure)
# vs to MAKE_FUNCTION_9 (pos_args + closure)
def bug():
def register(cls, func=None):
return lambda f: register(cls, f)
# From Python 3.6 configparser.py
def items(self, d, section=5, raw=False, vars=None):
if vars:
for key, value in vars.items():
d[self.optionxform(key)] = value
d = lambda option: self._interpolation.before_get(self,
section, option, d[option], d)
return

View File

@@ -0,0 +1,12 @@
# From 3.6 base64.py
# Bug was handling "and" condition in the presense of POP_JUMP_IF_FALSE
# locations
def _85encode(foldnuls, words):
return ['z' if foldnuls and word
else 'y'
for word in words]
# From Python 3.6 enum.py
def __new__(metacls, cls, bases, classdict):
{k: classdict[k] for k in classdict._member_names}

View File

@@ -0,0 +1,13 @@
# From Python 3.6 getopt.py
# Bug showing that "while" can have several "COME_FROMS" before loop end
# NOTE: uncompyle6 still gets the "if"s wrong.
def getopt(args):
while args and args[0] and args[0] != '-':
if args[0] == '--':
break
if args[0]:
opts = 5
else:
opts = 6
return opts

View File

@@ -0,0 +1,18 @@
# From 3.6.4 test_argparse.py
# Bug was in parsing ** args
import argparse
def test_namespace_starkwargs_notidentifier(self):
ns = argparse.Namespace(**{'"': 'quote'})
string = """Namespace(**{'"': 'quote'})"""
assert ns == string
def test_namespace_kwargs_and_starkwargs_notidentifier(self):
ns = argparse.Namespace(a=1, **{'"': 'quote'})
string = """Namespace(a=1, **{'"': 'quote'})"""
assert ns == string
def test_namespace(self):
ns = argparse.Namespace(foo=42, bar='spam')
string = "Namespace(bar='spam', foo=42)"
assert ns == string

View File

@@ -0,0 +1,16 @@
# Adapted from Python 3.3 idlelib/PyParse.py
# Bug is continue flowing back to while messing up the determination
# that it is inside an "if".
# RUNNABLE!
def _study1(i, n, ch):
while i == 3:
i = 4
if ch:
i = 10
assert i < 5
continue
if n:
return n
assert _study1(3, 4, False) == 4

View File

@@ -1,3 +1,5 @@
# RUNNABLE!
# Tests:
# 2.7:
# assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1
@@ -16,7 +18,7 @@ for method_name in ['a']:
if method_name in ('b',):
method = 'a'
else:
assert 0, "instance installed"
assert True, "instance installed"
methods = 'b'
@@ -25,5 +27,9 @@ for method_name in ['a']:
# if not not do_setlocal:
# raise AssertError
# Hmmm.. this isn't strickly a bug
def getpreferredencoding(do_setlocale=True):
assert not do_setlocale
getpreferredencoding(False)

1
test/stdlib/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/.python-version

View File

@@ -1,13 +1,20 @@
#!/usr/bin/bash
#!/bin/bash
USER=${USER:-rocky}
EMAIL=${EMAIL:-rb@dustyfeet.com}
for VERSION in 2.7.14 2.6.9 ; do
SUBJECT_PREFIX="stdlib unit testing for"
for VERSION in 2.6.9 2.7.14 3.4.8 3.5.5 3.6.4 ; do
typeset -i rc=0
LOGFILE=/tmp/runtests-$VERSION-$$.log
./runtests.sh >$LOGFILE 2>&1
rc=$?
if ((rc == 0)); then
tail -v $LOGFILE | mail -s \""$VERSION ok"\" rocky@localhost
if ! pyenv local $VERSION ; then
rc=1
else
tail -v $LOGFILE | mail -s \""$VERSION not ok"\" rocky@localhost
tail -v $LOGFILE | mail -s \""$VERSION not ok"\" rb@dustyfeet.com
/bin/bash ./runtests.sh >$LOGFILE 2>&1
rc=$?
fi
if ((rc == 0)); then
tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION ok" ${USER}@localhost
else
tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION not ok" ${USER}@localhost
tail -v $LOGFILE | mail -s "$SUBJECT_PREFIX $VERSION not ok" $EMAIL
fi
done

View File

@@ -48,6 +48,7 @@ case $PYVERSION in
;;
2.6)
SKIP_TESTS=(
[test_compile.py]=1 # Intermittent - sometimes works and sometimes doesn't
[test_grp.py]=1 # Long test - might work Control flow?
[test_opcodes.py]=1
[test_pwd.py]=1 # Long test - might work? Control flow?
@@ -77,7 +78,8 @@ case $PYVERSION in
[test_curses.py]=1 # Possibly fails on its own but not detected
[test_dis.py]=1 # We change line numbers - duh!
[test_doctest.py]=1 # Fails on its own
[test_grammar.py]=1 # Too many stmts. Handle large stmts
[test_generators.py]=1 # control flow. uncompyle2 has problem here too
[test_grammar.py]=1 # Too many stmts. Handle large stmts
[test_io.py]=1 # Test takes too long to run
[test_ioctl.py]=1 # Test takes too long to run
[test_itertools.py]=1 # Fix erroneous reduction to "conditional_true".
@@ -96,9 +98,26 @@ case $PYVERSION in
[test_zipfile64.py]=1 # Runs ok but takes 204 seconds
)
;;
3.5)
SKIP_TESTS=(
[test_decorators.py]=1 # Control flow wrt "if elif"
[test_quopri.py]=1 # Fails in crontab environment?
)
;;
3.6)
SKIP_TESTS=(
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
[test_decorators.py]=1 # Control flow wrt "if elif"
[test_pow.py]=1 # Control flow wrt "continue"
[test_quopri.py]=1 # Only fails on POWER
)
;;
*)
SKIP_TESTS=( [test_aepack.py]=1 [audiotests.py]=1
SKIP_TESTS=( [test_aepack.py]=1
[audiotests.py]=1
[test_dis.py]=1 # We change line numbers - duh!
[test_generators.py]=1 # I think string formatting of docstrings gets in the way. Not sure
)
;;
esac
@@ -178,7 +197,7 @@ typeset -i ALL_FILES_ENDTIME=$(date +%s)
(( time_diff = ALL_FILES_ENDTIME - ALL_FILES_STARTTIME))
printf "Ran $i tests in "
printf "Ran $i unit-test files in "
displaytime $time_diff
exit $allerrs

View File

@@ -38,7 +38,11 @@ def _get_outstream(outfile):
os.makedirs(dir)
except OSError:
pass
return open(outfile, 'w')
if PYTHON_VERSION < 3.0:
mode = 'wb'
else:
mode = 'w'
return open(outfile, mode)
def decompile(
bytecode_version, co, out=None, showasm=None, showast=False,
@@ -161,6 +165,7 @@ def main(in_base, out_base, files, codes, outfile=None,
for filename in files:
infile = os.path.join(in_base, filename)
# print("XXX", infile)
if not os.path.exists(infile):
sys.stderr.write("File '%s' doesn't exist. Skipped\n"
% infile)

View File

@@ -431,9 +431,6 @@ class PythonParser(GenericASTBuilder):
for_block ::= l_stmts_opt _come_froms JUMP_BACK
for ::= SETUP_LOOP expr for_iter store
for_block POP_BLOCK _come_froms
forelsestmt ::= SETUP_LOOP expr for_iter store
for_block POP_BLOCK else_suite _come_froms
@@ -570,9 +567,6 @@ class PythonParser(GenericASTBuilder):
# Positional arguments in make_function
pos_arg ::= expr
expr32 ::= expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr expr
expr1024 ::= expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32 expr32
'''
def p_store(self, args):

View File

@@ -1,8 +1,21 @@
# Copyright (c) 2015-2017 Rocky Bernstein
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
#
# Copyright (c) 1999 John Aycock
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
A spark grammar for Python 2.x.
Base grammar for Python 2.x.
However instead of terminal symbols being the usual ASCII text,
e.g. 5, myvariable, "for", etc. they are CPython Bytecode tokens,
@@ -82,6 +95,9 @@ class Python2Parser(PythonParser):
raise_stmt2 ::= expr expr RAISE_VARARGS_2
raise_stmt3 ::= expr expr expr RAISE_VARARGS_3
for ::= SETUP_LOOP expr for_iter store
for_block POP_BLOCK _come_froms
del_stmt ::= expr DELETE_SLICE+0
del_stmt ::= expr expr DELETE_SLICE+1
del_stmt ::= expr expr DELETE_SLICE+2
@@ -93,11 +109,8 @@ class Python2Parser(PythonParser):
_mklambda ::= load_closure mklambda
kwarg ::= LOAD_CONST expr
kvlist ::= kvlist kv3
kv3 ::= expr expr STORE_MAP
dict ::= BUILD_MAP kvlist
classdef ::= buildclass store
buildclass ::= LOAD_CONST expr mkfunc
@@ -175,6 +188,7 @@ class Python2Parser(PythonParser):
def p_expr2(self, args):
"""
expr ::= LOAD_LOCALS
expr ::= LOAD_ASSERT
expr ::= slice0
expr ::= slice1
expr ::= slice2
@@ -281,19 +295,8 @@ class Python2Parser(PythonParser):
# The order of opname listed is roughly sorted below
if opname_base in ('BUILD_LIST', 'BUILD_SET', 'BUILD_TUPLE'):
v = token.attr
thousands = (v//1024)
thirty32s = ((v//32) % 32)
if thirty32s > 0:
rule = "expr32 ::=%s" % (' expr' * 32)
self.add_unique_rule(rule, opname_base, v, customize)
self.seen32 = True
if thousands > 0:
self.add_unique_rule("expr1024 ::=%s" % (' expr32' * 32),
opname_base, v, customize)
self.seen1024 = True
collection = opname_base[opname_base.find('_')+1:].lower()
rule = (('%s ::= ' % collection) + 'expr1024 '*thousands +
'expr32 '*thirty32s + 'expr '*(v % 32) + opname)
rule = '%s ::= %s%s' % (collection, (token.attr * 'expr '), opname)
self.add_unique_rules([
"expr ::= %s" % collection,
rule], customize)
@@ -313,11 +316,9 @@ class Python2Parser(PythonParser):
'dict_comp_func', 0, customize)
else:
kvlist_n = "kvlist_%s" % token.attr
self.add_unique_rules([
(kvlist_n + " ::=" + ' kv3' * token.attr),
"dict ::= %s %s" % (opname, kvlist_n)
], customize)
kvlist_n = ' kv3' * token.attr
rule = "dict ::= %s%s" % (opname, kvlist_n)
self.addRule(rule, nop_func)
continue
elif opname_base == 'BUILD_SLICE':
slice_num = token.attr
@@ -503,8 +504,9 @@ class Python2Parser(PythonParser):
self.addRule(rule, nop_func)
pass
self.check_reduce['aug_assign1'] = 'AST'
self.check_reduce['raise_stmt1'] = 'tokens'
self.check_reduce['aug_assign2'] = 'AST'
self.check_reduce['or'] = 'AST'
# self.check_reduce['_stmts'] = 'AST'
# Dead code testing...
@@ -520,8 +522,16 @@ class Python2Parser(PythonParser):
# if lhs == 'while1elsestmt':
# from trepan.api import debug; debug()
if lhs in ('aug_assign1', 'aug_assign2') and ast[0] and ast[0][0] == 'and':
if lhs in ('aug_assign1', 'aug_assign2') and ast[0] and ast[0][0] in ('and', 'or'):
return True
elif lhs in ('raise_stmt1',):
# We will assme 'LOAD_ASSERT' will be handled by an assert grammar rule
return (tokens[first] == 'LOAD_ASSERT' and
(last >= len(tokens) or tokens[last] not in
('COME_FROM', 'JUMP_BACK','JUMP_FORWARD')))
elif rule == ('or', ('expr', 'jmp_true', 'expr', '\\e_come_from_opt')):
expr2 = ast[2]
return expr2 == 'expr' and expr2[0] == 'LOAD_ASSERT'
return False
class Python2ParserSingle(Python2Parser, PythonParserSingle):

View File

@@ -65,7 +65,6 @@ class Python25Parser(Python26Parser):
classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1
classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS
kv3 ::= expr expr STORE_MAP
kvlist ::= kvlist kv3
ret_cond ::= expr jmp_false_then expr RETURN_END_IF POP_TOP ret_expr_or_cond
return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP
return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP

View File

@@ -261,6 +261,9 @@ class Python26Parser(Python2Parser):
def p_misc26(self, args):
"""
dict ::= BUILD_MAP kvlist
kvlist ::= kvlist kv3
conditional ::= expr jmp_false expr jf_cf_pop expr come_from_opt
and ::= expr JUMP_IF_FALSE POP_TOP expr JUMP_IF_FALSE POP_TOP

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