Skip to content

Commit 01de7c0

Browse files
committed
feat: autogenerate site content if no sections specified
1 parent a75926a commit 01de7c0

File tree

3 files changed

+73
-7
lines changed

3 files changed

+73
-7
lines changed

quartodoc/autosummary.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,8 @@ def __init_subclass__(cls, **kwargs):
416416
def __init__(
417417
self,
418418
package: str,
419-
sections: "list[Any]",
419+
# TODO: correct typing
420+
sections: "list[Any]" = tuple(),
420421
version: "str | None" = None,
421422
dir: str = "reference",
422423
title: str = "Function reference",
@@ -451,10 +452,12 @@ def load_layout(self, sections: dict, package: str):
451452
try:
452453
return layout.Layout(sections=sections, package=package)
453454
except ValidationError as e:
454-
msg = 'Configuration error for YAML:\n - '
455+
msg = "Configuration error for YAML:\n - "
455456
errors = [fmt(err) for err in e.errors() if fmt(err)]
456-
first_error = errors[0] # we only want to show one error at a time b/c it is confusing otherwise
457-
msg += first_error
457+
first_error = errors[
458+
0
459+
] # we only want to show one error at a time b/c it is confusing otherwise
460+
msg += first_error
458461
raise ValueError(msg) from None
459462

460463
# building ----------------------------------------------------------------

quartodoc/builder/blueprint.py

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from __future__ import annotations
22

33
import logging
4+
import json
5+
import yaml
46

57
from griffe import dataclasses as dc
68
from griffe.loader import GriffeLoader
@@ -31,6 +33,36 @@
3133
_log = logging.getLogger(__name__)
3234

3335

36+
def _auto_package(mod: dc.Module) -> list[Section]:
37+
"""Create default sections for the given package."""
38+
39+
import griffe.docstrings.dataclasses as ds
40+
41+
# get module members for content ----
42+
contents = []
43+
for name, member in mod.members.items():
44+
if member.is_module or name.startswith("__all__"):
45+
continue
46+
47+
contents.append(Auto(name=name))
48+
49+
# try to fetch a description of the module ----
50+
mod_summary = mod.docstring.parsed[0]
51+
if isinstance(mod_summary, ds.DocstringSectionText):
52+
desc = mod_summary.value
53+
else:
54+
desc = ""
55+
56+
return [Section(title=mod.name, desc=desc, contents=contents)]
57+
58+
59+
def _to_simple_dict(el):
60+
# round-trip to json, so we can take advantage of pydantic
61+
# dumping Enums, etc.. There may be a simple way to do
62+
# this in pydantic v2.
63+
return json.loads(el.json(exclude_unset=True))
64+
65+
3466
class BlueprintTransformer(PydanticTransformer):
3567
def __init__(self, get_object=None, parser="numpy"):
3668

@@ -80,6 +112,37 @@ def visit(self, el):
80112
finally:
81113
self.crnt_package = old
82114

115+
@dispatch
116+
def enter(self, el: Layout):
117+
if not el.sections:
118+
# TODO: should be shown all the time, not just logged,
119+
# but also want to be able to disable (similar to pins)
120+
print("Autogenerating contents (since no contents specified in config)")
121+
122+
package = el.package
123+
124+
mod = self.get_object_fixed(package)
125+
sections = _auto_package(mod)
126+
127+
if not sections:
128+
# TODO: informative message. When would this occur?
129+
raise ValueError()
130+
131+
new_el = el.copy()
132+
new_el.sections = sections
133+
134+
print(
135+
"Use the following config configuration to recreate the automatically",
136+
" generated site:\n\n\n",
137+
yaml.safe_dump(_to_simple_dict(new_el)),
138+
"\n",
139+
sep="",
140+
)
141+
142+
return super().enter(new_el)
143+
144+
return super().enter(el)
145+
83146
@dispatch
84147
def exit(self, el: Section):
85148
"""Transform top-level sections, so their contents are all Pages."""
@@ -178,8 +241,8 @@ def _fetch_members(el: Auto, obj: dc.Object | dc.Alias):
178241
# for modules, remove any Alias objects, since they were imported from
179242
# other places. Sphinx has a flag for this behavior, so may be good
180243
# to do something similar.
181-
if obj.is_module:
182-
options = {k: v for k, v in options.items() if not v.is_alias}
244+
# if obj.is_module:
245+
# options = {k: v for k, v in options.items() if not v.is_alias}
183246

184247
return sorted(options)
185248

quartodoc/layout.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class Layout(_Structural):
4646
The package being documented.
4747
"""
4848

49-
sections: list[Union[SectionElement, Section]]
49+
sections: list[Union[SectionElement, Section]] = []
5050
package: Union[str, None, MISSING] = MISSING()
5151

5252

0 commit comments

Comments
 (0)