chiark / gitweb /
documentation/python: properly handle nested INPUT_MODULES.
authorVladimír Vondruš <mosra@centrum.cz>
Fri, 27 Sep 2024 22:48:30 +0000 (00:48 +0200)
committerVladimír Vondruš <mosra@centrum.cz>
Sat, 28 Sep 2024 01:44:29 +0000 (03:44 +0200)
The use case is explicitly including a module that otherwise doesn't get
transitively imported from the parents. They were treated as a standalone
root module until now, causing quite a mess. Now they aren't, but there's
an additional check requiring the user to explicitly supply also all
parents.

documentation/python.py
documentation/test_python/inspect_string/classes.html
documentation/test_python/inspect_string/inspect_string.html
documentation/test_python/inspect_string/inspect_string.subpackage.html [new file with mode: 0644]
documentation/test_python/inspect_string/inspect_string.subpackage.inner.html [new file with mode: 0644]
documentation/test_python/inspect_string/inspect_string/subpackage/inner.py [new file with mode: 0644]
documentation/test_python/inspect_string/modules.html
documentation/test_python/test_inspect.py

index 2bb70124c3dbbd42dd8c5b157c539c1c1f40a971..2465dc3acd6764fb0b06024db4d3bf127a64a24d 100755 (executable)
@@ -620,8 +620,16 @@ def crawl_module(state: State, path: List[str], module) -> List[Tuple[List[str],
     state.crawled.add(id(module))
 
     # This module isn't a duplicate, thus we can now safely add itself to
-    # parent's members (if there's a parent)
-    if len(path) > 1: state.name_map['.'.join(path[:-1])].members += [path[-1]]
+    # parent's members, if this is not a root module
+    if len(path) > 1:
+        # It's possible to supply nested modules in INPUT_MODULES, but for each
+        # such module all parents should be listed as well. We could probably
+        # add some dummies for the missing modules but the extra logic for
+        # deduplicating those if they get actually crawled later etc etc is
+        # way more complicated than just telling the user to list everything.
+        parent_path_str = '.'.join(path[:-1])
+        assert parent_path_str in state.name_map, "%s listed in INPUT_MODULES without %s being known yet, add the parent explicitly earlier" % ('.'.join(path), parent_path_str)
+        state.name_map[parent_path_str].members += [path[-1]]
 
     module_entry = Empty()
     module_entry.type = EntryType.MODULE
@@ -2720,8 +2728,12 @@ def run(basedir, config, *, templates=default_templates, search_add_lookahead_ba
             module = importlib.import_module(module)
         else:
             module_name = module.__name__
-        modules_to_crawl += [([module_name], module)]
-        class_index += [module_name]
+        module_path = module_name.split('.')
+        modules_to_crawl += [(module_path, module)]
+        # Add the module to the class index only if it's a top-level one,
+        # otherwise expect that it'll appear somewhere deeper on its own
+        if len(module_path) == 1:
+            class_index += [module_name]
     while modules_to_crawl:
         path, object = modules_to_crawl.pop(0)
         if id(object) in state.crawled: continue
index 13e5de16ecf4ed5ce30a902f8c3341adc8429676..ce78d9776aa0ca1ca3e20f66f51ac119cafafdbe 100644 (file)
           <li class="m-doc-collapsible">
             <a href="#" onclick="return toggle(this)">module</a> <a href="inspect_string.html" class="m-doc">inspect_string</a> <span class="m-doc">A module</span>
             <ul class="m-doc">
-              <li>module <a href="inspect_string.another_module.html" class="m-doc">another_module</a> <span class="m-doc">Another module</span></li>
               <li class="m-doc-collapsible collapsed">
                 <a href="#" onclick="return toggle(this)">module</a> <a href="inspect_string.subpackage.html" class="m-doc">subpackage</a> <span class="m-doc">A subpackage</span>
                 <ul class="m-doc">
+                  <li>module <a href="inspect_string.subpackage.inner.html" class="m-doc">inner</a> <span class="m-doc">An inner module that&#x27;s not transitively imported</span></li>
                   <li>class <a href="inspect_string.subpackage.Foo.html" class="m-doc">Foo</a> <span class="m-doc">A class in a subpackage. Shouldn&#x27;t cause the module tree to have an expander for it.</span></li>
                 </ul>
               </li>
+              <li>module <a href="inspect_string.another_module.html" class="m-doc">another_module</a> <span class="m-doc">Another module</span></li>
               <li>class <a href="inspect_string.DerivedException.html" class="m-doc">DerivedException</a> <span class="m-doc">A class deriving from BaseException, which has the weird args getset_descriptor</span></li>
               <li class="m-doc-collapsible collapsed">
                 <a href="#" onclick="return toggle(this)">class</a> <a href="inspect_string.Foo.html" class="m-doc">Foo</a> <span class="m-doc">The foo class</span>
index 9dc7908cfe61c763c16c23d3548109239883415f..780ef8b012e5f727a7dc6efe30845b1f346e5ce7 100644 (file)
         <section id="namespaces">
           <h2><a href="#namespaces">Modules</a></h2>
           <dl class="m-doc">
-            <dt>module <a href="inspect_string.another_module.html" class="m-doc">another_module</a></dt>
-            <dd>Another module</dd>
             <dt>module <a href="inspect_string.subpackage.html" class="m-doc">subpackage</a></dt>
             <dd>A subpackage</dd>
+            <dt>module <a href="inspect_string.another_module.html" class="m-doc">another_module</a></dt>
+            <dd>Another module</dd>
           </dl>
         </section>
         <section id="classes">
diff --git a/documentation/test_python/inspect_string/inspect_string.subpackage.html b/documentation/test_python/inspect_string/inspect_string.subpackage.html
new file mode 100644 (file)
index 0000000..01330ea
--- /dev/null
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>inspect_string.subpackage | My Python Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+      <div class="m-col-t-4 m-hide-m m-text-right m-nopadr">
+        <a id="m-navbar-show" href="#navigation" title="Show navigation"></a>
+        <a id="m-navbar-hide" href="#" title="Hide navigation"></a>
+      </div>
+      <div id="m-navbar-collapse" class="m-col-t-12 m-show-m m-col-m-none m-right-m">
+        <div class="m-row">
+          <ol class="m-col-t-12 m-col-m-none">
+            <li><a href="modules.html">Modules</a></li>
+            <li><a href="classes.html">Classes</a></li>
+          </ol>
+        </div>
+      </div>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          <span class="m-breadcrumb"><a href="inspect_string.html">inspect_string</a>.<wbr/></span>subpackage <span class="m-thin">module</span>
+        </h1>
+        <p>A subpackage</p>
+        <nav class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#packages">Modules</a></li>
+                <li><a href="#classes">Classes</a></li>
+              </ul>
+            </li>
+          </ul>
+        </nav>
+        <section id="namespaces">
+          <h2><a href="#namespaces">Modules</a></h2>
+          <dl class="m-doc">
+            <dt>module <a href="inspect_string.subpackage.inner.html" class="m-doc">inner</a></dt>
+            <dd>An inner module that&#x27;s not transitively imported</dd>
+          </dl>
+        </section>
+        <section id="classes">
+          <h2><a href="#classes">Classes</a></h2>
+          <dl class="m-doc">
+            <dt>class <a href="inspect_string.subpackage.Foo.html" class="m-doc">Foo</a></dt>
+            <dd>A class in a subpackage. Shouldn&#x27;t cause the module tree to have an expander for it.</dd>
+          </dl>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/documentation/test_python/inspect_string/inspect_string.subpackage.inner.html b/documentation/test_python/inspect_string/inspect_string.subpackage.inner.html
new file mode 100644 (file)
index 0000000..7de76e9
--- /dev/null
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>inspect_string.subpackage.inner | My Python Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+      <div class="m-col-t-4 m-hide-m m-text-right m-nopadr">
+        <a id="m-navbar-show" href="#navigation" title="Show navigation"></a>
+        <a id="m-navbar-hide" href="#" title="Hide navigation"></a>
+      </div>
+      <div id="m-navbar-collapse" class="m-col-t-12 m-show-m m-col-m-none m-right-m">
+        <div class="m-row">
+          <ol class="m-col-t-12 m-col-m-none">
+            <li><a href="modules.html">Modules</a></li>
+            <li><a href="classes.html">Classes</a></li>
+          </ol>
+        </div>
+      </div>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          <span class="m-breadcrumb"><a href="inspect_string.html">inspect_string</a>.<wbr/></span><span class="m-breadcrumb"><a href="inspect_string.subpackage.html">subpackage</a>.<wbr/></span>inner <span class="m-thin">module</span>
+        </h1>
+        <p>An inner module that&#x27;s not transitively imported</p>
+<p>But added explicitly via its full path instead, and should be properly inserted
+into the hierarchy.</p>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/documentation/test_python/inspect_string/inspect_string/subpackage/inner.py b/documentation/test_python/inspect_string/inspect_string/subpackage/inner.py
new file mode 100644 (file)
index 0000000..5154660
--- /dev/null
@@ -0,0 +1,5 @@
+"""An inner module that's not transitively imported
+
+But added explicitly via its full path instead, and should be properly inserted
+into the hierarchy.
+"""
index c5d761e16982c2549de731a13aed85a7c648d5df..644483f5a4a9bd944f67f44fccd8c9ec432473ac 100644 (file)
           <li class="m-doc-collapsible">
             <a href="#" onclick="return toggle(this)">module</a> <a href="inspect_string.html" class="m-doc">inspect_string</a> <span class="m-doc">A module</span>
             <ul class="m-doc">
+              <li class="m-doc-collapsible">
+                <a href="#" onclick="return toggle(this)">module</a> <a href="inspect_string.subpackage.html" class="m-doc">subpackage</a> <span class="m-doc">A subpackage</span>
+                <ul class="m-doc">
+                  <li>module <a href="inspect_string.subpackage.inner.html" class="m-doc">inner</a> <span class="m-doc">An inner module that&#x27;s not transitively imported</span></li>
+                </ul>
+              </li>
               <li>module <a href="inspect_string.another_module.html" class="m-doc">another_module</a> <span class="m-doc">Another module</span></li>
-              <li>module <a href="inspect_string.subpackage.html" class="m-doc">subpackage</a> <span class="m-doc">A subpackage</span></li>
             </ul>
           </li>
         </ul>
index c5a9cf0e50782e7cde7d373125ba370bcf0df1d0..7bd2a0a62a600f93cd7ee1894742c2821b44123c 100644 (file)
@@ -37,12 +37,16 @@ import m.sphinx
 
 class String(BaseInspectTestCase):
     def test(self):
+        sys.path.append(self.path)
         self.run_python({
             'LINKS_NAVBAR1': [
                 ('Modules', 'modules', []),
                 ('Classes', 'classes', [])],
+            'INPUT_MODULES': ['inspect_string', 'inspect_string.subpackage', 'inspect_string.subpackage.inner']
         })
         self.assertEqual(*self.actual_expected_contents('inspect_string.html'))
+        self.assertEqual(*self.actual_expected_contents('inspect_string.subpackage.html'))
+        self.assertEqual(*self.actual_expected_contents('inspect_string.subpackage.inner.html'))
         self.assertEqual(*self.actual_expected_contents('inspect_string.another_module.html'))
         self.assertEqual(*self.actual_expected_contents('inspect_string.Foo.html'))
         self.assertEqual(*self.actual_expected_contents('inspect_string.FooSlots.html'))
@@ -63,15 +67,18 @@ class Object(BaseInspectTestCase):
         # an object and not a string
         sys.path.append(os.path.join(os.path.dirname(self.path), 'inspect_string'))
         import inspect_string
+        import inspect_string.subpackage.inner
         self.run_python({
             'LINKS_NAVBAR1': [
                 ('Modules', 'modules', []),
                 ('Classes', 'classes', [])],
-            'INPUT_MODULES': [inspect_string]
+            'INPUT_MODULES': [inspect_string, inspect_string.subpackage, inspect_string.subpackage.inner]
         })
 
         # The output should be the same as when inspecting a string
         self.assertEqual(*self.actual_expected_contents('inspect_string.html', '../inspect_string/inspect_string.html'))
+        self.assertEqual(*self.actual_expected_contents('inspect_string.subpackage.html', '../inspect_string/inspect_string.subpackage.html'))
+        self.assertEqual(*self.actual_expected_contents('inspect_string.subpackage.inner.html', '../inspect_string/inspect_string.subpackage.inner.html'))
         self.assertEqual(*self.actual_expected_contents('inspect_string.another_module.html', '../inspect_string/inspect_string.another_module.html'))
         self.assertEqual(*self.actual_expected_contents('inspect_string.Foo.html', '../inspect_string/inspect_string.Foo.html'))
         self.assertEqual(*self.actual_expected_contents('inspect_string.FooSlots.html', '../inspect_string/inspect_string.FooSlots.html'))