Attribute docstrings support for cdef public attributes.
authorNikita Nemkin <nikita@nemkin.ru>
Sat, 13 Apr 2013 11:55:42 +0000 (17:55 +0600)
committerNikita Nemkin <nikita@nemkin.ru>
Sat, 13 Apr 2013 11:55:42 +0000 (17:55 +0600)
Cython/Compiler/AutoDocTransforms.py
Cython/Compiler/Nodes.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Parsing.py
tests/errors/w_attr_docstrings.pyx [new file with mode: 0644]
tests/run/embedsignatures.pyx

index da5ebd8..408ce9a 100644 (file)
@@ -127,7 +127,6 @@ class EmbedSignature(CythonTransform):
         else:
             return signature
 
-
     def __call__(self, node):
         if not Options.docstrings:
             return node
@@ -206,8 +205,25 @@ class EmbedSignature(CythonTransform):
                 old_doc = node.py_func.entry.doc
             else:
                 old_doc = None
-            new_doc  = self._embed_signature(signature, old_doc)
+            new_doc = self._embed_signature(signature, old_doc)
             node.entry.doc = EncodedString(new_doc)
             if hasattr(node, 'py_func') and node.py_func is not None:
                 node.py_func.entry.doc = EncodedString(new_doc)
         return node
+
+    def visit_PropertyNode(self, node):
+        if not self.current_directives['embedsignature']:
+            return node
+
+        entry = node.entry
+        if entry.visibility == 'public':
+            # property synthesised from a cdef public attribute
+            type_name = entry.type.declaration_code("", for_display=1)
+            if not entry.type.is_pyobject:
+                type_name = "'%s'" % type_name
+            elif entry.type.is_extension_type:
+                type_name = entry.type.module_name + '.' + type_name
+            signature = '%s: %s' % (entry.name, type_name)
+            new_doc = self._embed_signature(signature, entry.doc)
+            entry.doc = EncodedString(new_doc)
+        return node
index 6c14241..8a1bb57 100644 (file)
@@ -1202,6 +1202,8 @@ class CVarDefNode(StatNode):
                 self.entry = dest_scope.declare_var(name, type, declarator.pos,
                             cname=cname, visibility=visibility, in_pxd=self.in_pxd,
                             api=self.api, is_cdef=1)
+                if Options.docstrings:
+                    self.entry.doc = embed_position(self.pos, self.doc)
 
 
 class CStructOrUnionDefNode(StatNode):
@@ -4286,15 +4288,15 @@ class PropertyNode(StatNode):
     #
     #  name   string
     #  doc    EncodedString or None    Doc string
+    #  entry  Symtab.Entry
     #  body   StatListNode
 
     child_attrs = ["body"]
 
     def analyse_declarations(self, env):
-        entry = env.declare_property(self.name, self.doc, self.pos)
-        if entry:
-            entry.scope.directives = env.directives
-            self.body.analyse_declarations(entry.scope)
+        self.entry = env.declare_property(self.name, self.doc, self.pos)
+        self.entry.scope.directives = env.directives
+        self.body.analyse_declarations(self.entry.scope)
 
     def analyse_expressions(self, env):
         self.body = self.body.analyse_expressions(env)
index a168790..405fb7c 100644 (file)
@@ -1800,23 +1800,7 @@ if VALUE is not None:
                                                  attribute=entry.name),
             }, pos=entry.pos).stats[0]
         property.name = entry.name
-        # ---------------------------------------
-        # XXX This should go to AutoDocTransforms
-        # ---------------------------------------
-        if (Options.docstrings and
-            self.current_directives['embedsignature']):
-            attr_name = entry.name
-            type_name = entry.type.declaration_code("", for_display=1)
-            default_value = ''
-            if not entry.type.is_pyobject:
-                type_name = "'%s'" % type_name
-            elif entry.type.is_extension_type:
-                type_name = entry.type.module_name + '.' + type_name
-            if entry.init is not None:
-                default_value = ' = ' + entry.init
-            docstring = attr_name + ': ' + type_name + default_value
-            property.doc = EncodedString(docstring)
-        # ---------------------------------------
+        property.doc = entry.doc
         return property
 
 
index 86006d0..fb8d908 100644 (file)
@@ -2808,11 +2808,19 @@ def p_c_func_or_var_declaration(s, pos, ctx):
                                         assignable = 1, nonempty = 1)
             declarators.append(declarator)
         s.expect_newline("Syntax error in C variable declaration")
+        if ctx.level == 'c_class':
+            doc_pos = s.position()
+            doc = p_doc_string(s)
+            if doc and ctx.visibility not in ('public', 'readonly'):
+                warning(doc_pos, "Private attributes don't support docstrings.", 1)
+        else:
+            doc = None
         result = Nodes.CVarDefNode(pos,
             visibility = ctx.visibility,
             base_type = base_type,
             declarators = declarators,
             in_pxd = ctx.level in ('module_pxd', 'c_class_pxd'),
+            doc = doc,
             api = ctx.api,
             modifiers = modifiers,
             overridable = ctx.overridable)
diff --git a/tests/errors/w_attr_docstrings.pyx b/tests/errors/w_attr_docstrings.pyx
new file mode 100644 (file)
index 0000000..252dfea
--- /dev/null
@@ -0,0 +1,26 @@
+# mode: error
+# tag: werror
+
+cdef class A:
+    cdef a
+    """docstring"""
+
+    cdef int b
+    """docstring"""
+
+    cdef public c
+    """docstring"""
+
+    cdef public dict d
+    """docstring"""
+
+    cdef readonly e
+    """docstring"""
+
+    cdef readonly list e
+    """docstring"""
+
+_ERRORS = """
+6:4: Private attributes don't support docstrings.
+9:4: Private attributes don't support docstrings.
+"""
index 55ee1ae..e931241 100644 (file)
@@ -7,13 +7,24 @@ __doc__ = ur"""
 
     >>> print (Ext.attr0.__doc__)
     attr0: 'int'
+    attr0 docstring
     >>> print (Ext.attr1.__doc__)
     attr1: object
+    attr1 docstring
     >>> print (Ext.attr2.__doc__)
     attr2: list
     >>> print (Ext.attr3.__doc__)
     attr3: embedsignatures.Ext
 
+    >>> print (Ext.prop0.__doc__)
+    prop0 docstring
+    >>> print (Ext.prop1.__doc__)
+    None
+    >>> print (Ext.attr4.__doc__)
+    attr4 docstring
+    >>> print (Ext.attr5.__doc__)
+    attr5 docstring
+
     >>> print (Ext.a.__doc__)
     Ext.a(self)
 
@@ -166,12 +177,36 @@ __doc__ = ur"""
 cdef class Ext:
 
     cdef public int  attr0
+    """attr0 docstring"""
     cdef public      attr1
+    """attr1 docstring"""
     cdef public list attr2
     cdef public Ext  attr3
+    cdef        int  attr4
+    cdef             attr5
+    """private attr5 docstring"""
 
     CONST1, CONST2 = 1, 2
 
+    property prop0:
+        """prop0 docstring"""
+        def __get__(self):
+            return self.attr0
+
+    property prop1:
+        def __get__(self):
+            return self.attr1
+
+    property attr4:
+        """attr4 docstring"""
+        def __get__(self):
+            return self.attr4
+
+    property attr5:
+        """attr5 docstring"""
+        def __get__(self):
+            return self.attr4
+
     def __init__(self, a, b, c=None):
         pass