You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Fix Python 3.x bugs
* class definitions made via closures * Add "make check-short" to top-level * parse3.py: Python 3.3 uses STORE_LOGALS
This commit is contained in:
4
Makefile
4
Makefile
@@ -23,6 +23,10 @@ check:
|
|||||||
@PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2`; \
|
@PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2`; \
|
||||||
$(MAKE) check-$$PYTHON_VERSION
|
$(MAKE) check-$$PYTHON_VERSION
|
||||||
|
|
||||||
|
# Run all quick tests
|
||||||
|
check-short: pytest
|
||||||
|
$(MAKE) -C test check-short
|
||||||
|
|
||||||
#: Tests for Python 2.7, 3.3 and 3.4
|
#: Tests for Python 2.7, 3.3 and 3.4
|
||||||
check-2.7 check-3.3 check-3.4: pytest
|
check-2.7 check-3.3 check-3.4: pytest
|
||||||
$(MAKE) -C test $@
|
$(MAKE) -C test $@
|
||||||
|
BIN
test/bytecode_3.2/09_class_closure.pyc
Normal file
BIN
test/bytecode_3.2/09_class_closure.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.5/09_class_closure.pyc
Normal file
BIN
test/bytecode_3.5/09_class_closure.pyc
Normal file
Binary file not shown.
7
test/simple_source/def/09_class_closure.py
Normal file
7
test/simple_source/def/09_class_closure.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Bug from 3.4 functools.py
|
||||||
|
# class is made with a closure not a makefunc
|
||||||
|
def cmp_to_key(mycmp):
|
||||||
|
class K(object):
|
||||||
|
def __ne__(self, other):
|
||||||
|
return mycmp(self.obj, other.obj)
|
||||||
|
return K
|
@@ -471,6 +471,11 @@ def get_python_parser(version, debug_parser, compile_mode='exec'):
|
|||||||
p = parse3.Python32Parser(debug_parser)
|
p = parse3.Python32Parser(debug_parser)
|
||||||
else:
|
else:
|
||||||
p = parse3.Python32ParserSingle(debug_parser)
|
p = parse3.Python32ParserSingle(debug_parser)
|
||||||
|
elif version == 3.3:
|
||||||
|
if compile_mode == 'exec':
|
||||||
|
p = parse3.Python33Parser(debug_parser)
|
||||||
|
else:
|
||||||
|
p = parse3.Python33ParserSingle(debug_parser)
|
||||||
elif version == 3.4:
|
elif version == 3.4:
|
||||||
if compile_mode == 'exec':
|
if compile_mode == 'exec':
|
||||||
p = parse3.Python34Parser(debug_parser)
|
p = parse3.Python34Parser(debug_parser)
|
||||||
|
@@ -398,6 +398,8 @@ class Python3Parser(PythonParser):
|
|||||||
for i in range(i+1, len(tokens)):
|
for i in range(i+1, len(tokens)):
|
||||||
if tokens[i].type.startswith('MAKE_FUNCTION'):
|
if tokens[i].type.startswith('MAKE_FUNCTION'):
|
||||||
break
|
break
|
||||||
|
elif tokens[i].type.startswith('MAKE_CLOSURE'):
|
||||||
|
break
|
||||||
pass
|
pass
|
||||||
assert i < len(tokens), "build_class needs to find MAKE_FUNCTION"
|
assert i < len(tokens), "build_class needs to find MAKE_FUNCTION"
|
||||||
assert tokens[i+1].type == 'LOAD_CONST', \
|
assert tokens[i+1].type == 'LOAD_CONST', \
|
||||||
@@ -592,7 +594,14 @@ class Python3Parser(PythonParser):
|
|||||||
class Python32Parser(Python3Parser):
|
class Python32Parser(Python3Parser):
|
||||||
def p_32(self, args):
|
def p_32(self, args):
|
||||||
"""
|
"""
|
||||||
# Store locals is only used in Python 3.2
|
# Store locals is only in Python 3.2 and 3.3
|
||||||
|
designator ::= STORE_LOCALS
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Python33Parser(Python3Parser):
|
||||||
|
def p_33(self, args):
|
||||||
|
"""
|
||||||
|
# Store locals is only in Python 3.2 and 3.3
|
||||||
designator ::= STORE_LOCALS
|
designator ::= STORE_LOCALS
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -628,6 +637,9 @@ class Python32ParserSingle(Python32Parser, PythonParserSingle):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Python33ParserSingle(Python33Parser, PythonParserSingle):
|
||||||
|
pass
|
||||||
|
|
||||||
class Python34ParserSingle(Python34Parser, PythonParserSingle):
|
class Python34ParserSingle(Python34Parser, PythonParserSingle):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@@ -666,9 +666,29 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
buildclass = node[0]
|
buildclass = node[0]
|
||||||
if buildclass[1][0] == 'kwargs':
|
if buildclass[1][0] == 'kwargs':
|
||||||
subclass = buildclass[1][1].attr
|
subclass = buildclass[1][1].attr
|
||||||
|
subclass_info = node[0]
|
||||||
|
elif buildclass[1][0] == 'load_closure':
|
||||||
|
# Python 3 with closures not functions
|
||||||
|
load_closure = buildclass[1]
|
||||||
|
if hasattr(load_closure[-3], 'attr'):
|
||||||
|
# Python 3.3 classes with closures work like this.
|
||||||
|
# Note have to test before 3.2 case because
|
||||||
|
# index -2 also has an attr.
|
||||||
|
subclass = load_closure[-3].attr
|
||||||
|
elif hasattr(load_closure[-2], 'attr'):
|
||||||
|
# Python 3.2 works like this
|
||||||
|
subclass = load_closure[-2].attr
|
||||||
|
else:
|
||||||
|
raise 'Internal Error n_classdef: cannot find class body'
|
||||||
|
if hasattr(buildclass[3], '__len__'):
|
||||||
|
subclass_info = buildclass[3]
|
||||||
|
elif hasattr(buildclass[2], '__len__'):
|
||||||
|
subclass_info = buildclass[2]
|
||||||
|
else:
|
||||||
|
raise 'Internal Error n_classdef: cannot superclass name'
|
||||||
else:
|
else:
|
||||||
subclass = buildclass[1][0].attr
|
subclass = buildclass[1][0].attr
|
||||||
subclass_info = node[0]
|
subclass_info = node[0]
|
||||||
else:
|
else:
|
||||||
buildclass = node[0]
|
buildclass = node[0]
|
||||||
build_list = buildclass[1][0]
|
build_list = buildclass[1][0]
|
||||||
|
@@ -1141,7 +1141,6 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
def n_classdef(self, node):
|
def n_classdef(self, node):
|
||||||
# class definition ('class X(A,B,C):')
|
# class definition ('class X(A,B,C):')
|
||||||
|
|
||||||
cclass = self.currentclass
|
cclass = self.currentclass
|
||||||
|
|
||||||
if self.version > 3.0:
|
if self.version > 3.0:
|
||||||
@@ -1149,9 +1148,29 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
buildclass = node[0]
|
buildclass = node[0]
|
||||||
if buildclass[1][0] == 'kwargs':
|
if buildclass[1][0] == 'kwargs':
|
||||||
subclass = buildclass[1][1].attr
|
subclass = buildclass[1][1].attr
|
||||||
|
subclass_info = node[0]
|
||||||
|
elif buildclass[1][0] == 'load_closure':
|
||||||
|
# Python 3 with closures not functions
|
||||||
|
load_closure = buildclass[1]
|
||||||
|
if hasattr(load_closure[-3], 'attr'):
|
||||||
|
# Python 3.3 classes with closures work like this.
|
||||||
|
# Note have to test before 3.2 case because
|
||||||
|
# index -2 also has an attr.
|
||||||
|
subclass = load_closure[-3].attr
|
||||||
|
elif hasattr(load_closure[-2], 'attr'):
|
||||||
|
# Python 3.2 works like this
|
||||||
|
subclass = load_closure[-2].attr
|
||||||
|
else:
|
||||||
|
raise 'Internal Error n_classdef: cannot find class body'
|
||||||
|
if hasattr(buildclass[3], '__len__'):
|
||||||
|
subclass_info = buildclass[3]
|
||||||
|
elif hasattr(buildclass[2], '__len__'):
|
||||||
|
subclass_info = buildclass[2]
|
||||||
|
else:
|
||||||
|
raise 'Internal Error n_classdef: cannot superclass name'
|
||||||
else:
|
else:
|
||||||
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]
|
buildclass = node if (node == 'classdefdeco2') else node[0]
|
||||||
build_list = buildclass[1][0]
|
build_list = buildclass[1][0]
|
||||||
@@ -1208,26 +1227,32 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
self.write(')')
|
self.write(')')
|
||||||
|
|
||||||
def print_super_classes3(self, node):
|
def print_super_classes3(self, node):
|
||||||
|
|
||||||
n = len(node)-1
|
n = len(node)-1
|
||||||
assert node[n].type.startswith('CALL_FUNCTION')
|
if node.type != 'expr':
|
||||||
|
assert node[n].type.startswith('CALL_FUNCTION')
|
||||||
|
for i in range(n-2, 0, -1):
|
||||||
|
if not node[i].type in ['expr', 'LOAD_CLASSNAME']:
|
||||||
|
break
|
||||||
|
pass
|
||||||
|
|
||||||
for i in range(n-2, 0, -1):
|
if i == n-2:
|
||||||
if not node[i].type in ['expr', 'LOAD_CLASSNAME']:
|
return
|
||||||
break
|
line_separator = ', '
|
||||||
|
sep = ''
|
||||||
|
self.write('(')
|
||||||
|
i += 2
|
||||||
|
while i < n:
|
||||||
|
value = self.traverse(node[i])
|
||||||
|
i += 1
|
||||||
|
self.write(sep, value)
|
||||||
|
sep = line_separator
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.write('(')
|
||||||
|
value = self.traverse(node[0])
|
||||||
|
self.write(value)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if i == n-2:
|
|
||||||
return
|
|
||||||
self.write('(')
|
|
||||||
line_separator = ', '
|
|
||||||
sep = ''
|
|
||||||
i += 2
|
|
||||||
while i < n:
|
|
||||||
value = self.traverse(node[i])
|
|
||||||
i += 1
|
|
||||||
self.write(sep, value)
|
|
||||||
sep = line_separator
|
|
||||||
|
|
||||||
self.write(')')
|
self.write(')')
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user