diff --git a/test/add-test.py b/test/add-test.py index 513f3b63..ab4cbec8 100755 --- a/test/add-test.py +++ b/test/add-test.py @@ -21,7 +21,7 @@ for path in py_source: cfile = "bytecode_%s%s/%s" % (version, suffix, short) + "c" print("byte-compiling %s to %s" % (path, cfile)) optimize = 2 - if vers >= (3, 0): + if vers > (3, 1): py_compile.compile(path, cfile, optimize=optimize) else: py_compile.compile(path, cfile) diff --git a/test/bytecode_2.7_run/03_doc_assign.pyc b/test/bytecode_2.7_run/03_doc_assign.pyc new file mode 100644 index 00000000..2b44aac1 Binary files /dev/null and b/test/bytecode_2.7_run/03_doc_assign.pyc differ diff --git a/test/bytecode_3.1_run/03_doc_assign.pyc b/test/bytecode_3.1_run/03_doc_assign.pyc new file mode 100644 index 00000000..e0b5755c Binary files /dev/null and b/test/bytecode_3.1_run/03_doc_assign.pyc differ diff --git a/test/bytecode_3.3_run/03_doc_assign.pyc-notyet b/test/bytecode_3.3_run/03_doc_assign.pyc-notyet new file mode 100644 index 00000000..d5543923 Binary files /dev/null and b/test/bytecode_3.3_run/03_doc_assign.pyc-notyet differ diff --git a/test/bytecode_3.6_run/03_doc_assign.pyc-notyet b/test/bytecode_3.6_run/03_doc_assign.pyc-notyet new file mode 100644 index 00000000..3025a174 Binary files /dev/null and b/test/bytecode_3.6_run/03_doc_assign.pyc-notyet differ diff --git a/test/simple_source/bug27+/03_doc_assign.py b/test/simple_source/bug27+/03_doc_assign.py new file mode 100644 index 00000000..bc1be2d5 --- /dev/null +++ b/test/simple_source/bug27+/03_doc_assign.py @@ -0,0 +1,27 @@ +# From 2.7 test_descr.py +# Testing __doc__ descriptor... +# The bug in decompilation was erroneously matching +# __doc__ = as a docstring + +"""This program is self-checking!""" + +def test_doc_descriptor(): + # Testing __doc__ descriptor... + # Python SF bug 542984 + class DocDescr(object): + def __get__(self, object, otype): + if object: + object = object.__class__.__name__ + ' instance' + if otype: + otype = otype.__name__ + return 'object=%s; type=%s' % (object, otype) + class OldClass: + __doc__ = DocDescr() + class NewClass(object): + __doc__ = DocDescr() + assert OldClass.__doc__ == 'object=None; type=OldClass' + assert OldClass().__doc__ == 'object=OldClass instance; type=OldClass' + assert NewClass.__doc__ == 'object=None; type=NewClass' + assert NewClass().__doc__ == 'object=NewClass instance; type=NewClass' + +test_doc_descriptor() diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index a5d4ac83..da55eb7b 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -164,7 +164,6 @@ from uncompyle6.semantics.consts import ( NONE, RETURN_NONE, PASS, - ASSIGN_DOC_STRING, NAME_MODULE, TAB, INDENT_PER_LEVEL, @@ -2324,6 +2323,7 @@ class SourceWalker(GenericASTTraversal, object): if ast[0] == "docstring": self.println(self.traverse(ast[0])) del ast[0] + first_stmt = ast[0] if 3.0 <= self.version <= 3.3: try: diff --git a/uncompyle6/semantics/transform.py b/uncompyle6/semantics/transform.py index e01220ee..f9fe6bbf 100644 --- a/uncompyle6/semantics/transform.py +++ b/uncompyle6/semantics/transform.py @@ -13,7 +13,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from xdis import iscode from uncompyle6.show import maybe_show_tree from copy import copy from spark_parser import GenericASTTraversal, GenericASTTraversalPruningException @@ -21,16 +20,35 @@ from spark_parser import GenericASTTraversal, GenericASTTraversalPruningExceptio from uncompyle6.semantics.helper import find_code_node from uncompyle6.parsers.treenode import SyntaxTree from uncompyle6.scanners.tok import NoneToken, Token -from uncompyle6.semantics.consts import RETURN_NONE +from uncompyle6.semantics.consts import RETURN_NONE, ASSIGN_DOC_STRING def is_docstring(node): if node == "sstmt": node = node[0] - try: - return node.kind == "assign" and node[1][0].pattr == "__doc__" - except: - return False + # TODO: the test below on 2.7 succeeds for + # class OldClass: + # __doc__ = DocDescr() + # which produces: + # + # assign (2) + # 0. expr + # call (2) + # 0. expr + # L. 16 6 LOAD_DEREF 0 'DocDescr' + # 1. 9 CALL_FUNCTION_0 0 None + # 1. store + # + # See Python 2.7 test_descr.py + + # If ASSIGN_DOC_STRING doesn't work we need something like the below + # but more elaborate to address the above. + + # try: + # return node.kind == "assign" and node[1][0].pattr == "__doc__" + # except: + # return False + return node == ASSIGN_DOC_STRING def is_not_docstring(call_stmt_node):