Skip to content

Commit

Permalink
fix: Allow autodoc functions to have no parameters (#1072)
Browse files Browse the repository at this point in the history
Fixes https://deephaven.atlassian.net/browse/DH-18247

Allows autodoc functions to have no parameters and adds better error
checking for params to ensure that all expected parameters are there in
a fine-tuned way.

Tested on all existing docs as well as a local `use_render_queue` doc.
  • Loading branch information
jnumainville authored Dec 23, 2024
1 parent 716b3d9 commit 6b261d6
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 17 deletions.
2 changes: 1 addition & 1 deletion plugins/ui/src/deephaven/ui/components/action_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def action_menu(
ActionMenu combines an ActionButton with a Menu for simple "more actions" use cases.
Args:
children: The contents of the collection.
*children: The contents of the collection.
is_disabled: Whether the button is disabled.
is_quiet: Whether the button should be displayed with a quiet style.
auto_focus: Whether the element should receive focus on render.
Expand Down
2 changes: 1 addition & 1 deletion plugins/ui/src/deephaven/ui/components/column.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def column(
Each element will be placed below its prior sibling.
Args:
children: Elements to render in the column.
*children: Elements to render in the column.
width: The percent width of the column relative to other children of its parent. If not provided, the column will be sized automatically.
key: A unique identifier used by React to render elements in a list.
Expand Down
56 changes: 41 additions & 15 deletions sphinx_ext/deephaven_autodoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,38 @@ class SignatureData(TypedDict):

AUTOFUNCTION_COMMENT_PREFIX = "AutofunctionCommentPrefix:"

# Some parameters don't need to be documented such as function parameter dividers
UNDOCUMENTED_PARAMS = {"*", "/"}


def extract_parameter_defaults(
node: sphinx.addnodes.desc_parameterlist,
) -> ParamDefaults:
) -> tuple[ParamDefaults, set[str]]:
"""
Extract the default values for the parameters from the parameter list
Args:
node: The node to extract the defaults from
Returns:
The parameter defaults
The parameter defaults and the expected parameters for comparison
"""
defaults = {}
expected_params = set()
for child in node.children:
params = child.astext().split("=")
if len(params) == 2:
defaults[params[0]] = params[1]
# otherwise, no default value - do not add it because None is not the same as no default
return defaults
# otherwise, no default value - do not add it to defaults because None is not the same as no default
# but add it to expected_params so that we can check that all parameters are documented
expected_params.add(params[0])

return defaults, expected_params


def extract_signature_data(
node: sphinx.addnodes.desc_signature,
) -> tuple[FunctionMetadata, ParamDefaults]:
) -> tuple[FunctionMetadata, ParamDefaults, set[str]]:
"""
Extract the signature data from the signature node
The default values for the parameters are extracted from the signature
Expand All @@ -79,18 +86,19 @@ def extract_signature_data(
node: The node to extract the signature data from
Returns:
The function metadata and the parameter defaults
The function metadata, the parameter defaults, and the expected parameters
"""
result = {}
param_defaults = {}
expected_params = set()
for child in node.children:
if isinstance(child, sphinx.addnodes.desc_addname):
result["module_name"] = child.astext()
elif isinstance(child, sphinx.addnodes.desc_name):
result["name"] = child.astext()
elif isinstance(child, sphinx.addnodes.desc_parameterlist):
param_defaults = extract_parameter_defaults(child)
return FunctionMetadata(**result), param_defaults
param_defaults, expected_params = extract_parameter_defaults(child)
return FunctionMetadata(**result), param_defaults, expected_params


def extract_list_item(node: docutils.nodes.list_item) -> ParamData:
Expand All @@ -108,7 +116,7 @@ def extract_list_item(node: docutils.nodes.list_item) -> ParamData:
match = re.match(r"(.+?) \((.*?)\) -- (.+)", field, re.DOTALL)
if match is None:
raise ValueError(
f"Could not match {field} to extract param data. "
f"Could not match '{field}' to extract param data. "
f"Verify this parameter is documented correctly within 'Args:' with type and description."
)
matched = match.groups()
Expand Down Expand Up @@ -245,6 +253,18 @@ def attach_parameter_defaults(params: Params, param_defaults: ParamDefaults) ->
param["default"] = param_defaults[name]


def missing_parameters(params: Params, expected_params: set[str]) -> set[str]:
"""
Get the parameters that are missing from the documentation
Args:
params: The parameters that are documented
expected_params: The parameters that are expected
"""
param_names = set(param["name"] for param in params)
return expected_params - UNDOCUMENTED_PARAMS - param_names


def extract_desc_data(node: sphinx.addnodes.desc) -> SignatureData:
"""
Extract the content of the description.
Expand All @@ -258,21 +278,27 @@ def extract_desc_data(node: sphinx.addnodes.desc) -> SignatureData:
"""
result = {}
param_defaults = {}
params_expected = set()
for child_node in node.children:
if isinstance(child_node, sphinx.addnodes.desc_signature):
signature_results, param_defaults = extract_signature_data(child_node)
signature_results, param_defaults, params_expected = extract_signature_data(
child_node
)
result.update(signature_results)
elif isinstance(child_node, sphinx.addnodes.desc_content):
result.update(extract_content_data(child_node))
# map all to lowercase for consistency
function = f"{result['module_name']}{result['name']}"
try:
result["parameters"] = result.pop("Parameters")
except KeyError:

result["parameters"] = result.pop("Parameters") if "Parameters" in result else []
missing_params = missing_parameters(result["parameters"], params_expected)

if missing_params:
raise ValueError(
"Parameters missing from description. "
f"Verify the function description for {function} is formatted correctly."
f"Missing documentation for {function} parameters {missing_params}. "
"Verify that parameter names have leading asterisks in the description."
)

try:
result["return_description"] = result.pop("Returns")
except KeyError:
Expand Down

0 comments on commit 6b261d6

Please sign in to comment.