chiark / gitweb /
documentation/python: parse more than just first docstring paragraph.
authorVladimír Vondruš <mosra@centrum.cz>
Tue, 27 Aug 2019 11:14:21 +0000 (13:14 +0200)
committerVladimír Vondruš <mosra@centrum.cz>
Wed, 28 Aug 2019 14:36:13 +0000 (16:36 +0200)
Next step is to allow those to get processed using plugins.

doc/documentation/python.rst
documentation/python.py
documentation/test_python/content/content.html
documentation/test_python/content/content/__init__.py
documentation/test_python/inspect_annotations/math.html
documentation/test_python/inspect_annotations/math36.html
documentation/test_python/inspect_annotations/math373.html

index d21c5eb92b88547f83304e274c9c33475e35e44a..193f00d7dce64e41d8066751e955ad7af319d1de 100644 (file)
@@ -455,11 +455,14 @@ all found submodules in it are ignored.
 
 The first paragraph of a module-level, class-level and function-level docstring
 is used as a doc summary, copied as-is to the output without formatting it in
-any way.
+any way. What follows is put (again without formatting) paragraph-by-paragraph
+into detailed docs.
 
 .. code:: py
 
-    """Module summary"""
+    """Module summary
+
+    First paragraph of module detailed docs."""
 
     class Foo:
         """Class summary"""
@@ -471,8 +474,6 @@ any way.
 
     With the current approach, there are a few limitations:
 
-    -   Everything after the first paragraph is ignored (there's no way to have
-        detailed documentation yet)
     -   Class and module-level variables can't have a docstring attached due to
         how Python works
     -   Because not every Python API can be documented using docstrings, the
index 6c70b9f347d42f3ce00652a1c7f4ce86e549fd1b..4a49bb0e657770641746fc0e760af4150937b479 100755 (executable)
@@ -776,6 +776,13 @@ def format_value(state: State, referrer_path: List[str], value: str) -> Optional
     else:
         return None
 
+# Assumes the content is a bunch of raw paragraphs, wrapping them in <p> one
+# by one
+def split_summary_content(doc: str) -> str:
+    summary, _, content = doc.partition('\n\n')
+    content = content.strip()
+    return summary, ('\n'.join(['<p>{}</p>'.format(p) for p in content.split('\n\n')]) if content else None)
+
 def extract_summary(state: State, external_docs, path: List[str], doc: str) -> str:
     # Prefer external docs, if available
     path_str = '.'.join(path)
@@ -793,20 +800,17 @@ def extract_docs(state: State, external_docs, path: List[str], doc: str) -> Tupl
     else:
         external_doc_entry = None
 
+    # some modules (xml.etree) have None as a docstring :(
+    # TODO: render as rst (config option for that)
+    summary, content = split_summary_content(html.escape(inspect.cleandoc(doc or '')))
+
     # Summary. Prefer external docs, if available
     if external_doc_entry and external_doc_entry['summary']:
         summary = render_inline_rst(state, external_doc_entry['summary'])
-    else:
-        # some modules (xml.etree) have None as a docstring :(
-        # TODO: render as rst (config option for that)
-        summary = html.escape(inspect.cleandoc(doc or '').partition('\n\n')[0])
 
     # Content
     if external_doc_entry and external_doc_entry['content']:
         content = render_rst(state, external_doc_entry['content'])
-    else:
-        # TODO: extract more than just a summary from the docstring
-        content = None
 
     # Mark the docs as used (so it can warn about unused docs at the end)
     if external_doc_entry: external_doc_entry['used'] = True
@@ -980,7 +984,11 @@ def extract_enum_doc(state: State, entry: Empty):
     elif state.config['PYBIND11_COMPATIBILITY']:
         assert hasattr(entry.object, '__members__')
 
-        out.summary, out.content = extract_docs(state, state.enum_docs, entry.path, entry.object.__doc__)
+        # Pybind 2.4 puts enum value docs inside the docstring. We don't parse
+        # that yet and it adds clutter to the output (especially if the values
+        # aren't documented), so cut that away
+        # TODO: implement this
+        out.summary, out.content = extract_docs(state, state.enum_docs, entry.path, entry.object.__doc__.partition('\n\n')[0])
         out.has_details = bool(out.content)
         out.base = None
 
@@ -989,9 +997,6 @@ def extract_enum_doc(state: State, entry: Empty):
             value. name = name
             value.id = state.config['ID_FORMATTER'](EntryType.ENUM_VALUE, entry.path[-1:] + [name])
             value.value = int(v)
-            # TODO: once https://github.com/pybind/pybind11/pull/1160 is
-            #       released, extract from class docs (until then the class
-            #       docstring is duplicated here, which is useless)
             # TODO: external summary for enum values
             value.summary = ''
             out.values += [value]
index 58fb5917424809cb4cd185d00f3d56c05128817b..9ba7c10aa10c262e79fcb37037d5ac40eef4d072 100644 (file)
@@ -83,6 +83,10 @@ doesn't add any detailed block.</dd>
               <span class="m-doc-wrap-bumper">def <a href="#foo_with_details" class="m-doc">foo_with_details</a>(</span><span class="m-doc-wrap">a, b)</span>
             </dt>
             <dd>This overwrites the docstring for <code>content.foo_with_details()</code>.</dd>
+            <dt>
+              <span class="m-doc-wrap-bumper">def <a href="#full_docstring" class="m-doc">full_docstring</a>(</span><span class="m-doc-wrap">a, b) -&gt; str</span>
+            </dt>
+            <dd>This function has a full docstring.</dd>
             <dt>
               <span class="m-doc-wrap-bumper">def <a href="#function_with_summary" class="m-doc">function_with_summary</a>(</span><span class="m-doc-wrap">)</span>
             </dt>
@@ -151,6 +155,16 @@ doesn't add any detailed block.</dd>
             <p>This overwrites the docstring for <code>content.foo_with_details()</code>.</p>
 <div class="m-note m-info">
 Detailed docs for this function</div>
+          </div></section>
+          <section class="m-doc-details" id="full_docstring"><div>
+            <h3>
+              <span class="m-doc-wrap-bumper">def content.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#full_docstring" class="m-doc-self">full_docstring</a>(</span><span class="m-doc-wrap">a, b) -&gt; str</span></span>
+            </h3>
+            <p>This function has a full docstring.</p>
+<p>It takes one parameter and also another. The details are in two paragraphs,
+each wrapped in its own `&lt;p&gt;`, but not additionally formatted or parsed in any
+way.</p>
+<p>Like this.</p>
           </div></section>
           <section class="m-doc-details" id="function_with_summary"><div>
             <h3>
index be50c5371fad42e0fcd64abd7222ae1671b861ff..8f8becbf9fc6a67ddc9e94f0ce2d522b504ed163 100644 (file)
@@ -69,6 +69,16 @@ def param_docs(a: int, b, c: float) -> str:
 def param_docs_wrong(a, b):
     """Should give warnings"""
 
+def full_docstring(a, b) -> str:
+    """This function has a full docstring.
+
+    It takes one parameter and also another. The details are in two paragraphs,
+    each wrapped in its own `<p>`, but not additionally formatted or parsed in any
+    way.
+
+    Like this.
+    """
+
 CONSTANT: float = 3.14
 
 DATA_WITH_DETAILS: str = 'heyoo'
index 222af053d21125cac206eee1c7024a5f78e94112..3807895087755a479bd7ddf3e7e7a111f6c1c88e 100644 (file)
@@ -42,13 +42,24 @@ defined by the C standard.</p>
               <span class="m-doc-wrap-bumper">def <a href="#pow" class="m-doc-self">pow</a>(</span><span class="m-doc-wrap">x, y<span class="m-text m-dim">, /</span>)</span>
             </dt>
             <dd>Return x**y (x to the power of y).</dd>
-            <dt id="log">
-              <span class="m-doc-wrap-bumper">def <a href="#log" class="m-doc-self">log</a>(</span><span class="m-doc-wrap">...)</span>
+            <dt>
+              <span class="m-doc-wrap-bumper">def <a href="#log" class="m-doc">log</a>(</span><span class="m-doc-wrap">...)</span>
             </dt>
             <dd>log(x, [base=math.e])
 Return the logarithm of x to the given base.</dd>
           </dl>
         </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-doc-details" id="log"><div>
+            <h3>
+              <span class="m-doc-wrap-bumper">def math.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#log" class="m-doc-self">log</a>(</span><span class="m-doc-wrap">...)</span></span>
+            </h3>
+            <p>log(x, [base=math.e])
+Return the logarithm of x to the given base.</p>
+<p>If the base not specified, returns the natural logarithm (base e) of x.</p>
+          </div></section>
+        </section>
       </div>
     </div>
   </div>
index 66f3dcd50815003e9c6e81f4e9758cdbee6ead43..333792b0cdadcb6179dc556f01cc68c4b57010c1 100644 (file)
@@ -38,12 +38,23 @@ mathematical functions defined by the C standard.</p>
         <section id="functions">
           <h2><a href="#functions">Functions</a></h2>
           <dl class="m-doc">
-            <dt id="log">
-              <span class="m-doc-wrap-bumper">def <a href="#log" class="m-doc-self">log</a>(</span><span class="m-doc-wrap">...)</span>
+            <dt>
+              <span class="m-doc-wrap-bumper">def <a href="#log" class="m-doc">log</a>(</span><span class="m-doc-wrap">...)</span>
             </dt>
             <dd>log(x[, base])</dd>
           </dl>
         </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-doc-details" id="log"><div>
+            <h3>
+              <span class="m-doc-wrap-bumper">def math.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#log" class="m-doc-self">log</a>(</span><span class="m-doc-wrap">...)</span></span>
+            </h3>
+            <p>log(x[, base])</p>
+<p>Return the logarithm of x to the given base.
+If the base not specified, returns the natural logarithm (base e) of x.</p>
+          </div></section>
+        </section>
       </div>
     </div>
   </div>
index ebfe209dd556e7e39d26bc6b877b209e4d74d81b..660b6ce636c07c05730074ac36b39a6b39f5c8f4 100644 (file)
@@ -42,13 +42,24 @@ mathematical functions defined by the C standard.</p>
               <span class="m-doc-wrap-bumper">def <a href="#pow" class="m-doc-self">pow</a>(</span><span class="m-doc-wrap">x, y<span class="m-text m-dim">, /</span>)</span>
             </dt>
             <dd>Return x**y (x to the power of y).</dd>
-            <dt id="log">
-              <span class="m-doc-wrap-bumper">def <a href="#log" class="m-doc-self">log</a>(</span><span class="m-doc-wrap">...)</span>
+            <dt>
+              <span class="m-doc-wrap-bumper">def <a href="#log" class="m-doc">log</a>(</span><span class="m-doc-wrap">...)</span>
             </dt>
             <dd>log(x, [base=math.e])
 Return the logarithm of x to the given base.</dd>
           </dl>
         </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-doc-details" id="log"><div>
+            <h3>
+              <span class="m-doc-wrap-bumper">def math.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#log" class="m-doc-self">log</a>(</span><span class="m-doc-wrap">...)</span></span>
+            </h3>
+            <p>log(x, [base=math.e])
+Return the logarithm of x to the given base.</p>
+<p>If the base not specified, returns the natural logarithm (base e) of x.</p>
+          </div></section>
+        </section>
       </div>
     </div>
   </div>