From 85739d513e2dceba4e9c9190aead68b7d9f96870 Mon Sep 17 00:00:00 2001 From: Ashley Whetter Date: Wed, 29 Mar 2023 17:42:10 -0700 Subject: [PATCH] Switched to Google style docstrings --- autoapi/extension.py | 8 +- autoapi/mappers/base.py | 49 +++++---- autoapi/mappers/dotnet.py | 20 ++-- autoapi/mappers/python/astroid_utils.py | 127 +++++++++++++----------- autoapi/mappers/python/mapper.py | 32 +++--- autoapi/mappers/python/objects.py | 10 +- autoapi/settings.py | 3 +- docs/changes/+a772f117.misc.rst | 1 + docs/conf.py | 4 +- pyproject.toml | 3 + 10 files changed, 131 insertions(+), 126 deletions(-) create mode 100644 docs/changes/+a772f117.misc.rst diff --git a/autoapi/extension.py b/autoapi/extension.py index d18ed08d..a39d5267 100644 --- a/autoapi/extension.py +++ b/autoapi/extension.py @@ -65,9 +65,7 @@ def _normalise_autoapi_dirs(autoapi_dirs, srcdir): def run_autoapi(app): # pylint: disable=too-many-branches - """ - Load AutoAPI data from the filesystem. - """ + """Load AutoAPI data from the filesystem.""" if app.config.autoapi_type not in LANGUAGE_MAPPERS: allowed = ", ".join(f'"{api_type}"' for api_type in sorted(LANGUAGE_MAPPERS)) raise ExtensionError( @@ -178,9 +176,7 @@ def source_read(app, docname, source): # pylint: disable=unused-argument def doctree_read(app, doctree): - """ - Inject AutoAPI into the TOC Tree dynamically. - """ + """Inject AutoAPI into the TOC Tree dynamically.""" if app.env.docname == "index": all_docs = set() diff --git a/autoapi/mappers/base.py b/autoapi/mappers/base.py index a386f663..9f14d054 100644 --- a/autoapi/mappers/base.py +++ b/autoapi/mappers/base.py @@ -20,8 +20,7 @@ class PythonMapperBase: - """ - Base object for JSON -> Python object mapping. + """Base object for JSON -> Python object mapping. Subclasses of this object will handle their language specific JSON input, and map that onto this standard Python object. @@ -29,22 +28,24 @@ class PythonMapperBase: Arguments: - :param obj: JSON object representing this object - :param jinja_env: A template environment for rendering this object + Args: + obj: JSON object representing this object + jinja_env: A template environment for rendering this object Required attributes: - :var str id: A globally unique identifier for this object. - Generally a fully qualified name, including namespace. - :var str name: A short "display friendly" name for this object. + Attributes: + id (str): A globally unique identifier for this object. + Generally a fully qualified name, including namespace. + name (str): A short "display friendly" name for this object. + docstring (str): The documentation for this object + imports (list): Imports in this object + children (list): Children of this object + parameters (list): Parameters to this object + methods (list): Methods on this object Optional attributes: - :var str docstring: The documentation for this object - :var list imports: Imports in this object - :var list children: Children of this object - :var list parameters: Parameters to this object - :var list methods: Methods on this object """ language = "base" @@ -164,8 +165,8 @@ class SphinxMapperBase: """Base class for mapping `PythonMapperBase` objects to Sphinx. - :param app: Sphinx application instance - + Args: + app: Sphinx application instance """ def __init__(self, app, template_dir=None, url_root=None): @@ -204,10 +205,7 @@ def _wrapped_prepare(value): self.top_level_objects = OrderedDict() def load(self, patterns, dirs, ignore=None): - """ - Load objects from the filesystem into the ``paths`` dictionary. - - """ + """Load objects from the filesystem into the ``paths`` dictionary.""" paths = list(self.find_files(patterns=patterns, dirs=dirs, ignore=ignore)) for path in sphinx.util.status_iterator( paths, @@ -270,17 +268,18 @@ def find_files(patterns, dirs, ignore): def read_file(self, path, **kwargs): """Read file input into memory - :param path: Path of file to read + Args: + path: Path of file to read """ # TODO support JSON here # TODO sphinx way of reporting errors in logs? raise NotImplementedError def add_object(self, obj): - """ - Add object to local and app environment storage + """Add object to local and app environment storage - :param obj: Instance of a AutoAPI object + Args: + obj: Instance of a AutoAPI object """ self.objects[obj.id] = obj self.all_objects[obj.id] = obj @@ -302,10 +301,10 @@ def map(self, options=None): self.add_object(obj) def create_class(self, data, options=None, **kwargs): - """ - Create class object. + """Create class object. - :param data: Instance of a AutoAPI object + Args: + data: Instance of a AutoAPI object """ raise NotImplementedError diff --git a/autoapi/mappers/dotnet.py b/autoapi/mappers/dotnet.py index c93e97dc..0bcf92da 100644 --- a/autoapi/mappers/dotnet.py +++ b/autoapi/mappers/dotnet.py @@ -285,8 +285,9 @@ class DotNetPythonMapper(PythonMapperBase): """Base .NET object representation - :param references: object reference list from docfx - :type references: list of dict objects + Args: + references (list of dict objects): object reference list from + docfx """ language = "dotnet" @@ -446,14 +447,13 @@ def ref_short_name(self): @staticmethod def transform_doc_comments(text): - """ - Parse XML content for references and other syntax. + """Parse XML content for references and other syntax. This avoids an LXML dependency, we only need to parse out a small subset of elements here. Iterate over string to reduce regex pattern complexity and make substitutions easier - .. seealso:: + See Also: `Doc comment reference ` Reference on XML documentation comment syntax @@ -514,13 +514,15 @@ def resolve_spec_identifier(self, obj_name): a compound reference that should be linked in a special way. Resolve to a nested reference, with the corrected nodes. - .. note:: + Note: This uses a special format that is interpreted by the domain for parameter type and return type fields. - :param obj_name: spec identifier to resolve to a correct reference - :returns: resolved string with one or more references - :rtype: str + Args: + obj_name: spec identifier to resolve to a correct reference + + Returns: + str: resolved string with one or more references """ ref = self.references.get(obj_name) if ref is None: diff --git a/autoapi/mappers/python/astroid_utils.py b/autoapi/mappers/python/astroid_utils.py index c2c2e6e7..873e9413 100644 --- a/autoapi/mappers/python/astroid_utils.py +++ b/autoapi/mappers/python/astroid_utils.py @@ -40,13 +40,13 @@ def resolve_import_alias(name, import_names): def get_full_import_name(import_from, name): """Get the full path of a name from a ``from x import y`` statement. - :param import_from: The astroid node to resolve the name of. - :type import_from: astroid.nodes.ImportFrom - :param name: - :type name: str + Args: + import_from (astroid.nodes.ImportFrom): The astroid node to + resolve the name of. + name (str) - :returns: The full import path of the name. - :rtype: str + Returns: + str: The full import path of the name. """ partial_basename = resolve_import_alias(name, import_from.names) @@ -64,13 +64,12 @@ def get_full_import_name(import_from, name): def resolve_qualname(node, basename): """Resolve where a node is defined to get its fully qualified name. - :param node: The node representing the base name. - :type node: astroid.NodeNG - :param basename: The partial base name to resolve. - :type basename: str + Args: + node (astroid.NodeNG): The node representing the base name. + basename (str): The partial base name to resolve. - :returns: The fully resolved base name. - :rtype: str + Returns: + str: The fully resolved base name. """ full_basename = basename @@ -115,11 +114,12 @@ def resolve_qualname(node, basename): def get_full_basenames(node): """Resolve the partial names of a class' bases to fully qualified names. - :param node: The class definition node to resolve the bases of. + Args: + node: The class definition node to resolve the bases of. :type: astroid.ClassDef - :returns: The full names. - :rtype: iterable(str) + Returns: + iterable(str): The full names. """ for base in node.bases: yield _resolve_annotation(base) @@ -153,12 +153,13 @@ def get_assign_value(node): Assignments to multiple names are ignored, as per PEP 257. - :param node: The node to get the assignment value from. - :type node: astroid.nodes.Assign or astroid.nodes.AnnAssign + Args: + node (astroid.nodes.Assign or astroid.nodes.AnnAssign): The node + to get the assignment value from. - :returns: The name that is assigned to, - and the value assigned to the name (if it can be converted). - :rtype: tuple(str, object or None) or None + Returns: + tuple(str, object or None) or None: The name that is assigned + to, and the value assigned to the name (if it can be converted). """ try: targets = node.targets @@ -181,11 +182,13 @@ def get_assign_value(node): def get_assign_annotation(node): """Get the type annotation of the assignment of the given node. - :param node: The node to get the annotation for. - :type node: astroid.nodes.Assign or astroid.nodes.AnnAssign + Args: + node (astroid.nodes.Assign or astroid.nodes.AnnAssign): The node + to get the annotation for. - :returns: The type annotation as a string, or None if one does not exist. - :rtype: str or None + Returns: + str or None: The type annotation as a string, or None if one + does not exist. """ annotation_node = None try: @@ -199,11 +202,11 @@ def get_assign_annotation(node): def is_decorated_with_property(node): """Check if the function is decorated as a property. - :param node: The node to check. - :type node: astroid.nodes.FunctionDef + Args: + node (astroid.nodes.FunctionDef): The node to check. - :returns: True if the function is a property, False otherwise. - :rtype: bool + Returns: + bool: True if the function is a property, False otherwise. """ if not node.decorators: return False @@ -244,11 +247,12 @@ def _is_property_class(class_node): def is_decorated_with_property_setter(node): """Check if the function is decorated as a property setter. - :param node: The node to check. - :type node: astroid.nodes.FunctionDef + Args: + node (astroid.nodes.FunctionDef): The node to check. - :returns: True if the function is a property setter, False otherwise. - :rtype: bool + Returns: + bool: True if the function is a property setter, False + otherwise. """ if not node.decorators: return False @@ -266,11 +270,12 @@ def is_decorated_with_property_setter(node): def is_decorated_with_overload(node): """Check if the function is decorated as an overload definition. - :param node: The node to check. - :type node: astroid.nodes.FunctionDef + Args: + node (astroid.nodes.FunctionDef): The node to check. - :returns: True if the function is an overload definition, False otherwise. - :rtype: bool + Returns: + bool: True if the function is an overload definition, False + otherwise. """ if not node.decorators: return False @@ -302,11 +307,11 @@ def _is_overload_decorator(decorator): def is_constructor(node): """Check if the function is a constructor. - :param node: The node to check. - :type node: astroid.nodes.FunctionDef + Args: + node (astroid.nodes.FunctionDef): The node to check. - :returns: True if the function is a constructor, False otherwise. - :rtype: bool + Returns: + bool: True if the function is a constructor, False otherwise. """ return ( node.parent @@ -318,11 +323,11 @@ def is_constructor(node): def is_exception(node): """Check if a class is an exception. - :param node: The node to check. - :type node: astroid.nodes.ClassDef + Args: + node (astroid.nodes.ClassDef): The node to check. - :returns: True if the class is an exception, False otherwise. - :rtype: bool + Returns: + bool: True if the class is an exception, False otherwise. """ if node.name in ("Exception", "BaseException") and node.root().name == "builtins": return True @@ -336,15 +341,13 @@ def is_exception(node): def is_local_import_from(node, package_name): """Check if a node is an import from the local package. - :param node: The node to check. - :type node: astroid.node.NodeNG + Args: + node (astroid.node.NodeNG): The node to check. + package_name (str): The name of the local package. - :param package_name: The name of the local package. - :type package_name: str - - :returns: True if the node is an import from the local package, + Returns: + bool: True if the node is an import from the local package, False otherwise. - :rtype: bool """ if not isinstance(node, astroid.ImportFrom): return False @@ -359,11 +362,12 @@ def is_local_import_from(node, package_name): def get_module_all(node): """Get the contents of the ``__all__`` variable from a module. - :param node: The module to get ``__all__`` from. - :type node: astroid.nodes.Module + Args: + node (astroid.nodes.Module): The module to get ``__all__`` from. - :returns: The contents of ``__all__`` if defined. Otherwise None. - :rtype: list(str) or None + Returns: + list(str) or None: The contents of ``__all__`` if defined. + Otherwise None. """ all_ = None @@ -575,7 +579,9 @@ def get_args_info(args_node): # pylint: disable=too-many-branches,too-many-stat def get_return_annotation(node): """Get the return annotation of a node. - :type node: astroid.nodes.FunctionDef + + Args: + node (astroid.nodes.FunctionDef) """ return_annotation = None @@ -590,8 +596,9 @@ def get_return_annotation(node): def get_func_docstring(node): """Get the docstring of a node, using a parent docstring if needed. - :param node: The node to get a docstring for. - :type node: astroid.nodes.FunctionDef + Args: + node (astroid.nodes.FunctionDef): The node to get a docstring + for. """ doc = node.doc @@ -617,8 +624,8 @@ def get_func_docstring(node): def get_class_docstring(node): """Get the docstring of a node, using a parent docstring if needed. - :param node: The node to get a docstring for. - :type node: astroid.nodes.ClassDef + Args: + node (astroid.nodes.ClassDef): The node to get a docstring for. """ doc = node.doc diff --git a/autoapi/mappers/python/mapper.py b/autoapi/mappers/python/mapper.py index d375f6bd..bbdc8241 100644 --- a/autoapi/mappers/python/mapper.py +++ b/autoapi/mappers/python/mapper.py @@ -77,15 +77,13 @@ def _expand_wildcard_placeholder(original_module, originals_map, placeholder): def _resolve_module_placeholders(modules, module_name, visit_path, resolved): """Resolve all placeholder children under a module. - :param modules: A mapping of module names to their data dictionary. - Placeholders are resolved in place. - :type modules: dict(str, dict) - :param module_name: The name of the module to resolve. - :type module_name: str - :param visit_path: An ordered set of visited module names. - :type visited: collections.OrderedDict - :param resolved: A set of already resolved module names. - :type resolved: set(str) + Args: + modules (dict(str, dict)): A mapping of module names to their + data dictionary. Placeholders are resolved in place. + module_name (str): The name of the module to resolve. + visit_path: An ordered set of visited module names. + visited (collections.OrderedDict) + resolved (set(str)): A set of already resolved module names. """ if module_name in resolved: return @@ -157,10 +155,9 @@ def _resolve_module_placeholders(modules, module_name, visit_path, resolved): def _resolve_placeholder(placeholder, original): """Resolve a placeholder to the given original object. - :param placeholder: The placeholder to resolve, in place. - :type placeholder: dict - :param original: The object that the placeholder represents. - :type original: dict + Args: + placeholder (dict): The placeholder to resolve, in place. + original (dict): The object that the placeholder represents. """ new = copy.deepcopy(original) # We are supposed to be resolving the placeholder, @@ -223,7 +220,8 @@ class PythonSphinxMapper(SphinxMapperBase): Parses directly from Python files. - :param app: Sphinx application passed in as part of the extension + Args: + app: Sphinx application passed in as part of the extension """ _OBJ_MAP = { @@ -309,7 +307,8 @@ def load(self, patterns, dirs, ignore=None): def read_file(self, path, **kwargs): """Read file input into memory, returning deserialized objects - :param path: Path of file to read + Args: + path: Path of file to read """ dir_root = kwargs.get("dir_root") try: @@ -363,7 +362,8 @@ def map(self, options=None): def create_class(self, data, options=None, **kwargs): """Create a class from the passed in data - :param data: dictionary data of parser output + Args: + data: dictionary data of parser output """ try: cls = self._OBJ_MAP[data["type"]] diff --git a/autoapi/mappers/python/objects.py b/autoapi/mappers/python/objects.py index ec8ac158..564e6130 100644 --- a/autoapi/mappers/python/objects.py +++ b/autoapi/mappers/python/objects.py @@ -29,12 +29,10 @@ def _format_args(args_info, include_annotations=True, ignore_self=None): class PythonPythonMapper(PythonMapperBase): """A base class for all types of representations of Python objects. - :var name: The name given to this object. - :vartype name: str - :var id: A unique identifier for this object. - :vartype id: str - :var children: The members of this object. - :vartype children: list(PythonPythonMapper) + Attributes: + name (str): The name given to this object. + id (str): A unique identifier for this object. + children (list(PythonPythonMapper)): The members of this object. """ language = "python" diff --git a/autoapi/settings.py b/autoapi/settings.py index aadb1f7d..58704b41 100644 --- a/autoapi/settings.py +++ b/autoapi/settings.py @@ -1,5 +1,4 @@ -""" -Basic settings for AutoAPI projects. +"""Basic settings for AutoAPI projects. You shouldn't need to touch this. """ diff --git a/docs/changes/+a772f117.misc.rst b/docs/changes/+a772f117.misc.rst new file mode 100644 index 00000000..d7ddfc82 --- /dev/null +++ b/docs/changes/+a772f117.misc.rst @@ -0,0 +1 @@ +Switched to Google style docstrings \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 3e467233..167bac14 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,7 +20,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['autoapi.extension', 'sphinx.ext.intersphinx'] +extensions = ['autoapi.extension', 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon'] autoapi_type = 'python' autoapi_dirs = ['../autoapi'] @@ -73,7 +73,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ['_build', 'changes/*.rst'] # The reST default role (used for this markup: `text`) to use for all # documents. diff --git a/pyproject.toml b/pyproject.toml index b8717054..cf01a5c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,9 @@ ignore_missing_imports = true module = "autoapi.documenters" ignore_errors = true +[tool.ruff.pydocstyle] +convention = "google" + [tool.towncrier] directory = "docs/changes" filename = "CHANGELOG.rst"