Commit bb32de01 authored by Stefan Behnel's avatar Stefan Behnel

Make "__doc__" available to the class body if it has a docstring.

Closes #1635.
parent 580984ec
...@@ -47,6 +47,9 @@ Bugs fixed ...@@ -47,6 +47,9 @@ Bugs fixed
as integer 0 instead of the expected float value. as integer 0 instead of the expected float value.
Patch by Kryštof Pilnáček. (Github issue #2133) Patch by Kryštof Pilnáček. (Github issue #2133)
* ``__doc__`` was not available inside of the class body during class creation.
(Github issue #1635)
* Setting ``language_level=2`` in a file did not work if ``language_level=3`` * Setting ``language_level=2`` in a file did not work if ``language_level=3``
was enabled globally before. was enabled globally before.
Patch by Jeroen Demeyer. (Github issue #2791) Patch by Jeroen Demeyer. (Github issue #2791)
......
...@@ -1300,6 +1300,8 @@ class ControlFlowAnalysis(CythonTransform): ...@@ -1300,6 +1300,8 @@ class ControlFlowAnalysis(CythonTransform):
self.env_stack.append(self.env) self.env_stack.append(self.env)
self.env = node.scope self.env = node.scope
self.flow.nextblock() self.flow.nextblock()
if node.doc_node:
self.flow.mark_assignment(node.doc_node, fake_rhs_expr, node.doc_node.entry)
self.visitchildren(node, ('body',)) self.visitchildren(node, ('body',))
self.flow.nextblock() self.flow.nextblock()
self.env = self.env_stack.pop() self.env = self.env_stack.pop()
......
...@@ -4429,7 +4429,7 @@ class PyClassDefNode(ClassDefNode): ...@@ -4429,7 +4429,7 @@ class PyClassDefNode(ClassDefNode):
# A Python class definition. # A Python class definition.
# #
# name EncodedString Name of the class # name EncodedString Name of the class
# doc string or None # doc string or None The class docstring
# body StatNode Attribute definition code # body StatNode Attribute definition code
# entry Symtab.Entry # entry Symtab.Entry
# scope PyClassScope # scope PyClassScope
...@@ -4437,17 +4437,19 @@ class PyClassDefNode(ClassDefNode): ...@@ -4437,17 +4437,19 @@ class PyClassDefNode(ClassDefNode):
# #
# The following subnodes are constructed internally: # The following subnodes are constructed internally:
# #
# doc_node NameNode '__doc__' name that is made available to the class body
# dict DictNode Class dictionary or Py3 namespace # dict DictNode Class dictionary or Py3 namespace
# classobj ClassNode Class object # classobj ClassNode Class object
# target NameNode Variable to assign class object to # target NameNode Variable to assign class object to
child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result", child_attrs = ["doc_node", "body", "dict", "metaclass", "mkw", "bases", "class_result",
"target", "class_cell", "decorators"] "target", "class_cell", "decorators"]
decorators = None decorators = None
class_result = None class_result = None
is_py3_style_class = False # Python3 style class (kwargs) is_py3_style_class = False # Python3 style class (kwargs)
metaclass = None metaclass = None
mkw = None mkw = None
doc_node = None
def __init__(self, pos, name, bases, doc, body, decorators=None, def __init__(self, pos, name, bases, doc, body, decorators=None,
keyword_args=None, force_py3_semantics=False): keyword_args=None, force_py3_semantics=False):
...@@ -4461,6 +4463,7 @@ class PyClassDefNode(ClassDefNode): ...@@ -4461,6 +4463,7 @@ class PyClassDefNode(ClassDefNode):
if self.doc and Options.docstrings: if self.doc and Options.docstrings:
doc = embed_position(self.pos, self.doc) doc = embed_position(self.pos, self.doc)
doc_node = ExprNodes.StringNode(pos, value=doc) doc_node = ExprNodes.StringNode(pos, value=doc)
self.doc_node = ExprNodes.NameNode(name=EncodedString('__doc__'), type=py_object_type, pos=pos)
else: else:
doc_node = None doc_node = None
...@@ -4565,6 +4568,8 @@ class PyClassDefNode(ClassDefNode): ...@@ -4565,6 +4568,8 @@ class PyClassDefNode(ClassDefNode):
cenv = self.create_scope(env) cenv = self.create_scope(env)
cenv.directives = env.directives cenv.directives = env.directives
cenv.class_obj_cname = self.target.entry.cname cenv.class_obj_cname = self.target.entry.cname
if self.doc_node:
self.doc_node.analyse_target_declaration(cenv)
self.body.analyse_declarations(cenv) self.body.analyse_declarations(cenv)
def analyse_expressions(self, env): def analyse_expressions(self, env):
......
...@@ -14,10 +14,21 @@ doctest = u"""# Python 3 gets all of these right ... ...@@ -14,10 +14,21 @@ doctest = u"""# Python 3 gets all of these right ...
>>> C.__doc__ >>> C.__doc__
'\\n This is a class docstring.\\n ' '\\n This is a class docstring.\\n '
>>> C.docstring_copy_C
'\\n This is a class docstring.\\n '
>>> CS.docstring_copy_C
'\\n This is a class docstring.\\n '
>>> CS.__doc__ >>> CS.__doc__
'\\n This is a subclass docstring.\\n ' '\\n This is a subclass docstring.\\n '
>>> CS.docstring_copy_CS
'\\n This is a subclass docstring.\\n '
>>> CSS.docstring_copy_CS
'\\n This is a subclass docstring.\\n '
>>> print(CSS.__doc__) >>> print(CSS.__doc__)
None None
>>> CSS.docstring_copy_CSS
'A module docstring'
>>> T.__doc__ >>> T.__doc__
'\\n This is an extension type docstring.\\n ' '\\n This is an extension type docstring.\\n '
...@@ -34,22 +45,38 @@ Compare with standard Python: ...@@ -34,22 +45,38 @@ Compare with standard Python:
>>> Pyf.__doc__ >>> Pyf.__doc__
'\\n This is a function docstring.\\n ' '\\n This is a function docstring.\\n '
>>> class PyC: >>> class PyC(object):
... ''' ... '''
... This is a class docstring. ... This is a class docstring.
... ''' ... '''
>>> class PyCS(C): ... docstring_copy_C = __doc__
>>> class PyCS(PyC):
... ''' ... '''
... This is a subclass docstring. ... This is a subclass docstring.
... ''' ... '''
>>> class PyCSS(CS): ... docstring_copy_CS = __doc__
... pass >>> class PyCSS(PyCS):
... docstring_copy_CSS = __doc__
>>> PyC.__doc__ >>> PyC.__doc__
'\\n This is a class docstring.\\n ' '\\n This is a class docstring.\\n '
>>> PyC.docstring_copy_C
'\\n This is a class docstring.\\n '
>>> PyCS.docstring_copy_C
'\\n This is a class docstring.\\n '
>>> PyCSS.docstring_copy_C
'\\n This is a class docstring.\\n '
>>> PyCS.__doc__ >>> PyCS.__doc__
'\\n This is a subclass docstring.\\n ' '\\n This is a subclass docstring.\\n '
>>> PyCS.docstring_copy_CS
'\\n This is a subclass docstring.\\n '
>>> PyCSS.docstring_copy_CS
'\\n This is a subclass docstring.\\n '
>>> PyCSS.__doc__ >>> PyCSS.__doc__
>>> PyCSS.docstring_copy_CSS
'A module docstring'
""" """
__test__ = {"test_docstrings" : doctest} __test__ = {"test_docstrings" : doctest}
...@@ -59,18 +86,24 @@ def f(): ...@@ -59,18 +86,24 @@ def f():
This is a function docstring. This is a function docstring.
""" """
class C:
class C(object):
""" """
This is a class docstring. This is a class docstring.
""" """
docstring_copy_C = __doc__
class CS(C): class CS(C):
""" """
This is a subclass docstring. This is a subclass docstring.
""" """
docstring_copy_CS = __doc__
class CSS(CS): class CSS(CS):
pass docstring_copy_CSS = __doc__
cdef class T: cdef class T:
""" """
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment