diff --git a/docs/_autoapi_templates/python/class.rst b/docs/_autoapi_templates/python/class.rst new file mode 100644 index 000000000..5fa91e1d0 --- /dev/null +++ b/docs/_autoapi_templates/python/class.rst @@ -0,0 +1,96 @@ +{# Adapted from sphinx-autoapi https://github.com/readthedocs/sphinx-autoapi #} +{% if obj.display %} + {% if is_own_page %} +{{ obj.id }} +{{ "=" * obj.id | length }} + {% endif %} + {% set visible_children = obj.children|selectattr("display")|list %} + {% set own_page_children = visible_children|selectattr("type", "in", own_page_types)|list %} + {% if is_own_page and own_page_children %} +.. toctree:: + :hidden: + {% for child in own_page_children %} + {{ child.include_path }} + {% endfor %} + {% endif %} +.. py:{{ obj.type }}:: {% if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}{% if obj.args %}({{ obj.args }}){% endif %} + + {% for (args, return_annotation) in obj.overloads %} + {{ " " * (obj.type | length) }} {{ obj.short_name }}{% if args %}({{ args }}){% endif %} + + {% endfor %} + {% if obj.bases %} + {% if "show-inheritance" in autoapi_options %} + + Bases: {% for base in obj.bases %}{{ base|link_objs }}{% if not loop.last %}, {% endif %}{% endfor %} + {% endif %} + {% if "show-inheritance-diagram" in autoapi_options and obj.bases != ["object"] %} + .. autoapi-inheritance-diagram:: {{ obj.obj["full_name"] }} + :parts: 1 + {% if "private-members" in autoapi_options %} + :private-bases: + {% endif %} + + {% endif %} + {% endif %} + {% if obj.docstring %} + {{ obj.docstring|indent(3) }} + {% endif %} + {% for obj_item in visible_children %} + {% if obj_item.type not in own_page_types %} +{{ obj_item.render()|indent(3) }} + {% endif %} + {% endfor %} + {% if is_own_page and own_page_children %} + {% set visible_methods = visible_children|selectattr("type", "equalto", "method")|list %} + {% if visible_methods %} +Methods +------- + +.. autoapisummary:: + + {% for method in visible_methods %} + {{ method.id }} + {% endfor %} + + + {% endif %} + {% set visible_attributes = visible_children|selectattr("type", "equalto", "attribute")|list %} + {% if visible_attributes %} +Attributes +---------- + +.. autoapisummary:: + + {% for attribute in visible_attributes %} + {{ attribute.id }} + {% endfor %} + + + {% endif %} + {% set visible_exceptions = own_page_children|selectattr("type", "equalto", "exception")|list %} + {% if visible_exceptions %} +Exceptions +---------- + +.. autoapisummary:: + + {% for exception in visible_exceptions %} + {{ exception.id }} + {% endfor %} + + + {% endif %} + {% set visible_classes = own_page_children|selectattr("type", "equalto", "class")|list %} + {% if visible_classes %} +Classes +------- + +.. autoapisummary:: + + {% for klass in visible_classes %} + {{ klass.id }} + {% endfor %} + {% endif %} + {% endif %} +{% endif %} diff --git a/docs/_autoapi_templates/python/module.rst b/docs/_autoapi_templates/python/module.rst new file mode 100644 index 000000000..659cfa638 --- /dev/null +++ b/docs/_autoapi_templates/python/module.rst @@ -0,0 +1,152 @@ +{# Adapted from sphinx-autoapi https://github.com/readthedocs/sphinx-autoapi #} +{% if obj.display %} + {% if is_own_page %} +{{ obj.id }} +{{ "=" * obj.id|length }} + +.. py:module:: {{ obj.name }} + + {% if obj.docstring %} +.. autoapi-nested-parse:: + + {{ obj.docstring|indent(3) }} + + {% endif %} + + {% block content %} + {% set visible_children = obj.children|selectattr("display")|list %} + {% if visible_children %} + {% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %} + {% if visible_classes %} + {% if "class" in own_page_types or "show-module-summary" in autoapi_options %} +Classes +------- + + {% if "class" in own_page_types %} +.. toctree:: + :hidden: + :caption: Classes + + {% for klass in visible_classes %} + {{ klass.include_path }} + {% endfor %} + + {% endif %} +.. autoapisummary:: + + {% for klass in visible_classes %} + {{ klass.id }} + {% endfor %} + {% endif %} + + + {% endif %} + {% set visible_exceptions = visible_children|selectattr("type", "equalto", "exception")|list %} + {% if visible_exceptions %} + {% if "exception" in own_page_types or "show-module-summary" in autoapi_options %} +Exceptions +---------- + + {% if "exception" in own_page_types %} +.. toctree:: + :hidden: + + {% for exception in visible_exceptions %} + {{ exception.include_path }} + {% endfor %} + + {% endif %} +.. autoapisummary:: + + {% for exception in visible_exceptions %} + {{ exception.id }} + {% endfor %} + {% endif %} + + + {% endif %} + {% set visible_attributes = visible_children|selectattr("type", "equalto", "data")|list %} + {% if visible_attributes %} + {% if "attribute" in own_page_types or "show-module-summary" in autoapi_options %} +Attributes +---------- + + {% if "attribute" in own_page_types %} +.. toctree:: + :hidden: + + {% for attribute in visible_attributes %} + {{ attribute.include_path }} + {% endfor %} + + {% endif %} +.. autoapisummary:: + + {% for attribute in visible_attributes %} + {{ attribute.id }} + {% endfor %} + {% endif %} + + + {% endif %} + {% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %} + {% if visible_functions %} + {% if "function" in own_page_types or "show-module-summary" in autoapi_options %} +Functions +--------- + + {% if "function" in own_page_types %} +.. toctree:: + :hidden: + + {% for function in visible_functions %} + {{ function.include_path }} + {% endfor %} + + {% endif %} +.. autoapisummary:: + + {% for function in visible_functions %} + {{ function.id }} + {% endfor %} + {% endif %} + + + {% endif %} + {% set visible_subpackages = obj.subpackages|selectattr("display")|list %} + {% set visible_submodules = obj.submodules|selectattr("display")|list %} + {% set visible_submodules = (visible_subpackages + visible_submodules)|sort %} + {% if visible_submodules %} +.. toctree:: + :caption: Submodules + :maxdepth: 1 + + {% for submodule in visible_submodules %} + {{ submodule.include_path }} + {% endfor %} + {% endif %} + {% set this_page_children = visible_children|rejectattr("type", "in", own_page_types)|list %} + {% if this_page_children %} +{{ obj.type|title }} Contents +{{ "-" * obj.type|length }}--------- + + {% for obj_item in this_page_children %} +{{ obj_item.render()|indent(0) }} + {% endfor %} + {% endif %} + {% endif %} + {% endblock %} + {% else %} +.. py:module:: {{ obj.name }} + + {% if obj.docstring %} + .. autoapi-nested-parse:: + + {{ obj.docstring|indent(6) }} + + {% endif %} + {% for obj_item in visible_children %} + {{ obj_item.render()|indent(3) }} + {% endfor %} + {% endif %} +{% endif %} diff --git a/docs/conf.py b/docs/conf.py index 7fd13ba1f..b00701094 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,4 @@ -"""Sphinx configuration file for Parcels documentation.""" +"""autoSphinx configuration file for Parcels documentation.""" # parcels documentation build configuration file, created by # sphinx-quickstart on Tue Oct 20 09:58:20 2015. # @@ -40,6 +40,7 @@ "numpydoc", "sphinxcontrib.mermaid", "sphinx_design", + "autoapi.extension", ] # Add any paths that contain templates here, relative to this directory. @@ -115,6 +116,7 @@ # directories to ignore when looking for source files. exclude_patterns = [ "_build", + "_autoapi_templates", "jupyter_execute", "**.ipynb_checkpoints", "user_guide/examples_v3", @@ -528,3 +530,19 @@ def linkcode_resolve(domain, info): nb_execution_excludepatterns = ["jupyter_execute", ".jupyter_cache"] nb_execution_raise_on_error = True nb_execution_timeout = 75 + +# -- Options for autoapi -------------------------------------------------- +autoapi_dirs = ["../src/parcels"] +# autoapi_add_toctree_entry = False +autoapi_root = "reference" +autoapi_options = [ + "members", + # "show-inheritance", + "undoc-members", + "show-module-summary", + "imported-members", +] +autoapi_member_order = "bysource" +autodoc_typehints = "none" +autoapi_template_dir = "_autoapi_templates" +autoapi_own_page_level = "class" diff --git a/docs/index.md b/docs/index.md index 50d366cfc..5737dccbc 100755 --- a/docs/index.md +++ b/docs/index.md @@ -12,7 +12,7 @@ _Animation of virtual particles carried by ocean surface flow in the global ocea You can browse the documentation for older versions by using the version switcher in the bottom right. ``` -**Useful links**: [Installation instructions](getting_started/installation.md) | [Discussions on GitHub](https://github.com/Parcels-code/parcels/discussions) | [Issue on GitHub](https://github.com/Parcels-code/parcels/issues) | [Parcels website](https://parcels-code.org/) | [CLAM community website](https://clam-community.github.io/) | [API reference](reference.md) +**Useful links**: [Installation instructions](getting_started/installation.md) | [Discussions on GitHub](https://github.com/Parcels-code/parcels/discussions) | [Issue on GitHub](https://github.com/Parcels-code/parcels/issues) | [Parcels website](https://parcels-code.org/) | [CLAM community website](https://clam-community.github.io/) | [API reference](reference/parcels/index) `````{grid} 1 2 2 2 :gutter: 4 @@ -94,7 +94,7 @@ Getting started User guide Community Development -API reference +API reference v4 Parcels website ``` diff --git a/docs/reference.md b/docs/reference.md deleted file mode 100644 index 9d36706ec..000000000 --- a/docs/reference.md +++ /dev/null @@ -1,5 +0,0 @@ -# Parcels API - -```{note} -This section is a work in progress. -``` diff --git a/pixi.toml b/pixi.toml index 633ce8cf1..7b6fafac1 100644 --- a/pixi.toml +++ b/pixi.toml @@ -73,6 +73,7 @@ matplotlib-base = ">=2.0.2" gsw = "*" [feature.docs.dependencies] +parcels = { path = "." } numpydoc = "!=1.9.0" myst-nb = "*" ipython = "*" @@ -82,6 +83,7 @@ pydata-sphinx-theme = "*" sphinx-autobuild = "*" sphinxcontrib-mermaid = "*" sphinx-design = "*" +sphinx-autoapi = "*" [feature.docs.tasks] docs = "sphinx-build docs docs/_build" diff --git a/pyproject.toml b/pyproject.toml index ca43f03ba..86e1420bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -110,12 +110,6 @@ ignore = [ # TODO: ignore for now (requires more work). Remove ignore once fixed # Missing docstring in public module "D100", - # Missing docstring in public class - "D101", - # Missing docstring in public method - "D102", - # Missing docstring in public function - "D103", # Missing docstring in public package "D104", # Missing docstring in magic method @@ -131,6 +125,17 @@ ignore = [ "F811", ] +[tool.ruff.lint.per-file-ignores] +# Ignore docstring rules everywhere except for the stable files (particleset.py, interpolators.py). +"!src/parcels/{_core/basegrid,_core/field,_core/fieldset,_core/kernel,_core/particle,_core/particlefile,_core/particleset,_core/uxgrid,_core/xgrid,kernels/advection,kernels/advectiondiffusion,interpolators}.py" = [ + # Missing docstring in public class + "D101", + # Missing docstring in public method + "D102", + # Missing docstring in public function + "D103", +] + [tool.ruff.lint.pydocstyle] convention = "numpy" diff --git a/src/parcels/__init__.py b/src/parcels/__init__.py index 5fba2a72e..177eceb7b 100644 --- a/src/parcels/__init__.py +++ b/src/parcels/__init__.py @@ -1,3 +1,4 @@ +# isort: skip_file from importlib.metadata import version as _version try: @@ -8,7 +9,21 @@ import warnings as _stdlib_warnings +from parcels._core.fieldset import FieldSet +from parcels._core.particleset import ParticleSet +from parcels._core.kernel import Kernel +from parcels._core.particlefile import ParticleFile +from parcels._core.particle import ( + Variable, + Particle, + ParticleClass, + KernelParticle, # ? remove? +) +from parcels._core.field import Field, VectorField from parcels._core.basegrid import BaseGrid +from parcels._core.uxgrid import UxGrid +from parcels._core.xgrid import XGrid + from parcels._core.converters import ( Geographic, GeographicPolar, @@ -16,17 +31,7 @@ GeographicSquare, Unity, ) -from parcels._core.field import Field, VectorField -from parcels._core.fieldset import FieldSet -from parcels._core.kernel import Kernel -from parcels._core.particle import ( - KernelParticle, # ? remove? - Particle, - ParticleClass, - Variable, -) -from parcels._core.particlefile import ParticleFile -from parcels._core.particleset import ParticleSet + from parcels._core.statuscodes import ( AllParcelsErrorCodes, FieldInterpolationError, @@ -36,31 +41,29 @@ OutsideTimeInterval, StatusCode, ) -from parcels._core.uxgrid import UxGrid from parcels._core.warnings import ( FieldSetWarning, FileWarning, KernelWarning, ParticleSetWarning, ) -from parcels._core.xgrid import XGrid from parcels._logger import logger from parcels._tutorial import download_example_dataset, list_example_datasets __all__ = [ # noqa: RUF022 # Core classes - "BaseGrid", - "Field", - "VectorField", "FieldSet", + "ParticleSet", "Kernel", - "Particle", - "ParticleClass", "ParticleFile", - "ParticleSet", "Variable", - "XGrid", + "Particle", + "ParticleClass", + "Field", + "VectorField", + "BaseGrid", "UxGrid", + "XGrid", # Converters "Geographic", "GeographicPolar", diff --git a/src/parcels/_core/__init__.py b/src/parcels/_core/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/parcels/_core/basegrid.py b/src/parcels/_core/basegrid.py index a05ea6dfc..af64e7109 100644 --- a/src/parcels/_core/basegrid.py +++ b/src/parcels/_core/basegrid.py @@ -1,3 +1,5 @@ +"""Module defining the BaseGrid class for XGrid and UXGrid""" + from __future__ import annotations from abc import ABC, abstractmethod @@ -20,6 +22,8 @@ class GridType(IntEnum): class BaseGrid(ABC): + """Base class for parcels.XGrid and parcels.UxGrid defining common methods and properties""" + @abstractmethod def search(self, z: float, y: float, x: float, ei=None) -> dict[str, tuple[int, float | np.ndarray]]: """ diff --git a/src/parcels/_core/fieldset.py b/src/parcels/_core/fieldset.py index 4948a6796..1477479d8 100644 --- a/src/parcels/_core/fieldset.py +++ b/src/parcels/_core/fieldset.py @@ -52,8 +52,8 @@ class FieldSet: to and what parent model the field is associated with. Parcels uses this metadata during execution for interpolation. Each `UXDataArray.attributes` field dictionary must have: - * "location" key set to "face", "node", or "edge" to define which pairing of points a field is associated with. - * "mesh" key to define which parent model the fields are associated with (e.g. "fesom_mesh", "icon_mesh") + * "location" key set to "face", "node", or "edge" to define which pairing of points a field is associated with. + * "mesh" key to define which parent model the fields are associated with (e.g. "fesom_mesh", "icon_mesh") """ diff --git a/src/parcels/_core/particle.py b/src/parcels/_core/particle.py index 69f37d68f..2587d3750 100644 --- a/src/parcels/_core/particle.py +++ b/src/parcels/_core/particle.py @@ -193,6 +193,7 @@ def get_default_particle(spatial_dtype: np.float32 | np.float64) -> ParticleClas Particle = get_default_particle(np.float32) +"""The default Particle used in Parcels simulations.""" def create_particle_data(