diff --git a/plugins/ui/src/deephaven/ui/components/action_menu.py b/plugins/ui/src/deephaven/ui/components/action_menu.py index 2eca69c3b..10bb485ca 100644 --- a/plugins/ui/src/deephaven/ui/components/action_menu.py +++ b/plugins/ui/src/deephaven/ui/components/action_menu.py @@ -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. diff --git a/plugins/ui/src/deephaven/ui/components/column.py b/plugins/ui/src/deephaven/ui/components/column.py index 4dbeea67b..85d9a981a 100644 --- a/plugins/ui/src/deephaven/ui/components/column.py +++ b/plugins/ui/src/deephaven/ui/components/column.py @@ -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. diff --git a/sphinx_ext/deephaven_autodoc.py b/sphinx_ext/deephaven_autodoc.py index 56e6e946b..d987a12c2 100644 --- a/sphinx_ext/deephaven_autodoc.py +++ b/sphinx_ext/deephaven_autodoc.py @@ -46,10 +46,13 @@ 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 @@ -57,20 +60,24 @@ def extract_parameter_defaults( 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 @@ -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: @@ -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() @@ -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. @@ -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: