Skip to content

Commit 0f80c38

Browse files
committed
Better doc string detection
A bug in 2.7 test_descr.py revealed a problem with the way we were detecting docstrings. __doc__ = DocDescr() was getting confused with a docstring. This program also reveals other bugs in 3.2+ but we'll deal with that in another commit.
1 parent bd07de5 commit 0f80c38

8 files changed

Lines changed: 53 additions & 8 deletions

File tree

test/add-test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
cfile = "bytecode_%s%s/%s" % (version, suffix, short) + "c"
2222
print("byte-compiling %s to %s" % (path, cfile))
2323
optimize = 2
24-
if vers >= (3, 0):
24+
if vers > (3, 1):
2525
py_compile.compile(path, cfile, optimize=optimize)
2626
else:
2727
py_compile.compile(path, cfile)
1.42 KB
Binary file not shown.
1.65 KB
Binary file not shown.
1.6 KB
Binary file not shown.
1 KB
Binary file not shown.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# From 2.7 test_descr.py
2+
# Testing __doc__ descriptor...
3+
# The bug in decompilation was erroneously matching
4+
# __doc__ = as a docstring
5+
6+
"""This program is self-checking!"""
7+
8+
def test_doc_descriptor():
9+
# Testing __doc__ descriptor...
10+
# Python SF bug 542984
11+
class DocDescr(object):
12+
def __get__(self, object, otype):
13+
if object:
14+
object = object.__class__.__name__ + ' instance'
15+
if otype:
16+
otype = otype.__name__
17+
return 'object=%s; type=%s' % (object, otype)
18+
class OldClass:
19+
__doc__ = DocDescr()
20+
class NewClass(object):
21+
__doc__ = DocDescr()
22+
assert OldClass.__doc__ == 'object=None; type=OldClass'
23+
assert OldClass().__doc__ == 'object=OldClass instance; type=OldClass'
24+
assert NewClass.__doc__ == 'object=None; type=NewClass'
25+
assert NewClass().__doc__ == 'object=NewClass instance; type=NewClass'
26+
27+
test_doc_descriptor()

uncompyle6/semantics/pysource.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@
164164
NONE,
165165
RETURN_NONE,
166166
PASS,
167-
ASSIGN_DOC_STRING,
168167
NAME_MODULE,
169168
TAB,
170169
INDENT_PER_LEVEL,
@@ -2324,6 +2323,7 @@ def build_class(self, code):
23242323
if ast[0] == "docstring":
23252324
self.println(self.traverse(ast[0]))
23262325
del ast[0]
2326+
first_stmt = ast[0]
23272327

23282328
if 3.0 <= self.version <= 3.3:
23292329
try:

uncompyle6/semantics/transform.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,42 @@
1313
# You should have received a copy of the GNU General Public License
1414
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515

16-
from xdis import iscode
1716
from uncompyle6.show import maybe_show_tree
1817
from copy import copy
1918
from spark_parser import GenericASTTraversal, GenericASTTraversalPruningException
2019

2120
from uncompyle6.semantics.helper import find_code_node
2221
from uncompyle6.parsers.treenode import SyntaxTree
2322
from uncompyle6.scanners.tok import NoneToken, Token
24-
from uncompyle6.semantics.consts import RETURN_NONE
23+
from uncompyle6.semantics.consts import RETURN_NONE, ASSIGN_DOC_STRING
2524

2625

2726
def is_docstring(node):
2827
if node == "sstmt":
2928
node = node[0]
30-
try:
31-
return node.kind == "assign" and node[1][0].pattr == "__doc__"
32-
except:
33-
return False
29+
# TODO: the test below on 2.7 succeeds for
30+
# class OldClass:
31+
# __doc__ = DocDescr()
32+
# which produces:
33+
#
34+
# assign (2)
35+
# 0. expr
36+
# call (2)
37+
# 0. expr
38+
# L. 16 6 LOAD_DEREF 0 'DocDescr'
39+
# 1. 9 CALL_FUNCTION_0 0 None
40+
# 1. store
41+
#
42+
# See Python 2.7 test_descr.py
43+
44+
# If ASSIGN_DOC_STRING doesn't work we need something like the below
45+
# but more elaborate to address the above.
46+
47+
# try:
48+
# return node.kind == "assign" and node[1][0].pattr == "__doc__"
49+
# except:
50+
# return False
51+
return node == ASSIGN_DOC_STRING
3452

3553

3654
def is_not_docstring(call_stmt_node):

0 commit comments

Comments
 (0)