diff --git a/copier.yml b/copier.yml index 700449a..81e998f 100644 --- a/copier.yml +++ b/copier.yml @@ -1,6 +1,13 @@ -_subdirectory: template -_answers_file: .copier-answers.ess.yml +_subdirectory: "{% if template=='ess' %}template{% else %}subpackage-template{% endif %}" +_answers_file: .copier-answers.{{ template }}.yml # Questions +template: + type: str + choices: + - ess + - subpackages + default: ess + subpackages: type: yaml multiline: true @@ -15,4 +22,60 @@ subpackages: description: Neutron imaging (ODIN, TBL, YMIR) dependencies: - essreduce + when: "{% if template == 'ess' %}true{% endif %}" + +# Subpackages Questions + +projectname: + type: str + help: What is your project name? + when: "{% if template != 'ess' %}true{% endif %}" +prettyname: + default: '{{projectname|capitalize}}' + type: str + help: What is your project name in title case? + when: "{% if template != 'ess' %}true{% endif %}" +orgname: + default: scipp + type: str + help: What is your organization name? + when: "{% if template != 'ess' %}true{% endif %}" +namespace_package: + default: 'ess' + type: str + help: Use a namespace package with this name. If empty, no namespace package is used. + when: "{% if template != 'ess' %}true{% endif %}" +description: + type: str + help: Brief description? + when: "{% if template != 'ess' %}true{% endif %}" +min_python: + type: str + help: Minimum Python version? + when: "{% if template != 'ess' %}true{% endif %}" +max_python: + type: str + help: Maximum Python version that is known to work? + when: "{% if template != 'ess' %}true{% endif %}" +year: + type: int + default: 2026 + when: "{% if template != 'ess' %}true{% endif %}" +nightly_deps: + type: str + help: | + List of dependencies to install from GitHub during nightly builds, + separated by commas. Make sure to also list transitive dependencies, + otherwise their released versions will be used. Specify either a + repository name or 'org/repo'. If no organization is given it defaults + to 'scipp'. In either case, the 'main' branch will be used. Example: + scipp,sciline,dask/dask + when: "{% if template != 'ess' %}true{% endif %}" +related_projects: + type: str + help: | + List of related projects, separated by commas. + This will be used to generate a list of links in the documentation. + For example, "Scipp,Sciline,Plopp". + when: "{% if template != 'ess' %}true{% endif %}" diff --git a/subpackage-template/MANIFEST.in b/subpackage-template/MANIFEST.in new file mode 100644 index 0000000..1aba38f --- /dev/null +++ b/subpackage-template/MANIFEST.in @@ -0,0 +1 @@ +include LICENSE diff --git a/subpackage-template/README.md.jinja b/subpackage-template/README.md.jinja new file mode 100644 index 0000000..97dd0fa --- /dev/null +++ b/subpackage-template/README.md.jinja @@ -0,0 +1,16 @@ +[](CODE_OF_CONDUCT.md) +[](https://pypi.python.org/pypi/{{projectname}}) +[](https://anaconda.org/conda-forge/{{projectname}}) +[](LICENSE) + +# {{prettyname}} + +## About + +{{description}} + +## Installation + +```sh +python -m pip install {{projectname}} +``` diff --git a/subpackage-template/docs/_static/anaconda-icon.js b/subpackage-template/docs/_static/anaconda-icon.js new file mode 100644 index 0000000..024350e --- /dev/null +++ b/subpackage-template/docs/_static/anaconda-icon.js @@ -0,0 +1,13 @@ +FontAwesome.library.add( + (faListOldStyle = { + prefix: "fa-custom", + iconName: "anaconda", + icon: [ + 67.65, // viewBox width + 67.500267, // viewBox height + [], // ligature + "e001", // unicode codepoint - private use area + "M 33.900391 0 C 32.600392 0 31.299608 0.09921885 30.099609 0.19921875 A 39.81 39.81 0 0 1 35.199219 4.3007812 L 36.5 5.5 L 35.199219 6.8007812 A 34.65 34.65 0 0 0 32 10.199219 L 32 10.300781 A 6.12 6.12 0 0 0 31.5 10.900391 A 19.27 19.27 0 0 1 33.900391 10.800781 A 23 23 0 0 1 33.900391 56.800781 A 22.39 22.39 0 0 1 21.900391 53.400391 A 45.33 45.33 0 0 1 16.699219 53.699219 A 19.27 19.27 0 0 1 14.300781 53.599609 A 78.24 78.24 0 0 0 15 61.699219 A 33.26 33.26 0 0 0 33.900391 67.5 A 33.75 33.75 0 0 0 33.900391 0 z M 23 1.8007812 A 33.78 33.78 0 0 0 15.599609 5.4003906 A 47 47 0 0 1 20.699219 6.5996094 A 52.38 52.38 0 0 1 23 1.8007812 z M 26.5 2 A 41.8 41.8 0 0 0 23.699219 7.5996094 C 25.199217 8.1996088 26.69922 8.8000007 28.199219 9.5 C 28.799218 8.7000008 29.300391 8.0999999 29.400391 8 C 30.10039 7.2000008 30.800001 6.399218 31.5 5.6992188 A 58.59 58.59 0 0 0 26.5 2 z M 13.199219 8.1992188 A 48.47 48.47 0 0 0 13.099609 14.800781 A 44.05 44.05 0 0 1 18.300781 14.5 A 39.43 39.43 0 0 1 19.699219 9.5996094 A 46.94 46.94 0 0 0 13.199219 8.1992188 z M 10.099609 9.8007812 A 33.47 33.47 0 0 0 4.9003906 16.5 C 6.6003889 16 8.3992205 15.599218 10.199219 15.199219 C 10.099219 13.399221 10.099609 11.600779 10.099609 9.8007812 z M 22.599609 10.599609 C 22.19961 11.799608 21.8 13.100392 21.5 14.400391 A 29.18 29.18 0 0 1 26.199219 12.099609 A 27.49 27.49 0 0 0 22.599609 10.599609 z M 17.699219 17.5 C 16.19922 17.5 14.80078 17.599219 13.300781 17.699219 A 33.92 33.92 0 0 0 14.099609 22.099609 A 20.36 20.36 0 0 1 17.699219 17.5 z M 10.599609 17.900391 A 43.62 43.62 0 0 0 3.3007812 19.900391 L 3.0996094 20 L 3.1992188 20.199219 A 30.3 30.3 0 0 0 6.5 27.300781 L 6.5996094 27.5 L 6.8007812 27.400391 A 50.41 50.41 0 0 1 11.699219 24.300781 L 11.900391 24.199219 L 11.900391 24 A 38.39 38.39 0 0 1 10.800781 18.099609 L 10.800781 17.900391 L 10.599609 17.900391 z M 1.8007812 22.800781 L 1.5996094 23.400391 A 33.77 33.77 0 0 0 0 32.900391 L 0 33.5 L 0.40039062 33.099609 A 24.93 24.93 0 0 1 4.8007812 28.900391 L 5 28.800781 L 4.9003906 28.599609 A 54.49 54.49 0 0 1 2 23.300781 L 1.8007812 22.800781 z M 12.300781 26.300781 L 11.800781 26.599609 C 10.500783 27.399609 9.2003893 28.19961 7.9003906 29.099609 L 7.6992188 29.199219 L 8 29.400391 C 8.8999991 30.600389 9.8007822 31.900001 10.800781 33 L 11.099609 33.5 L 11.099609 32.900391 A 23.54 23.54 0 0 1 12.099609 26.900391 L 12.300781 26.300781 z M 6.0996094 30.5 L 5.9003906 30.699219 A 47 47 0 0 0 0.80078125 35.599609 L 0.59960938 35.800781 L 0.80078125 36 A 58.38 58.38 0 0 0 6.4003906 40.199219 L 6.5996094 40.300781 L 6.6992188 40.099609 A 45.3 45.3 0 0 1 9.6992188 35.5 L 9.8007812 35.300781 L 9.6992188 35.199219 A 52 52 0 0 1 6.1992188 30.800781 L 6.0996094 30.5 z M 11.300781 36.400391 L 11 36.900391 C 10.100001 38.200389 9.2003898 39.600001 8.4003906 41 L 8.3007812 41.199219 L 8.5 41.300781 C 9.8999986 42.10078 11.400392 42.800001 12.900391 43.5 L 13.400391 43.699219 L 13.199219 43.199219 A 23.11 23.11 0 0 1 11.400391 37 L 11.300781 36.400391 z M 0.099609375 37.699219 L 0.19921875 38.300781 A 31.56 31.56 0 0 0 2.9003906 47.699219 L 3.0996094 48.199219 L 3.3007812 47.699219 A 55.47 55.47 0 0 1 5.6992188 42.099609 L 5.8007812 41.800781 L 5.5996094 41.699219 A 57.36 57.36 0 0 1 0.59960938 38.099609 L 0.099609375 37.699219 z M 7.4003906 42.800781 L 7.3007812 43 A 53.76 53.76 0 0 0 4.5 50 L 4.4003906 50.199219 L 4.5996094 50.300781 A 39.14 39.14 0 0 0 12.199219 51.699219 L 12.5 51.699219 L 12.5 51.5 A 36.79 36.79 0 0 1 13 45.699219 L 13 45.5 L 12.800781 45.400391 A 49.67 49.67 0 0 1 7.5996094 42.900391 L 7.4003906 42.800781 z M 14.5 45.900391 L 14.5 46.199219 A 45.53 45.53 0 0 0 14.099609 51.5 L 14.099609 51.699219 L 14.300781 51.699219 C 15.10078 51.699219 15.89922 51.800781 16.699219 51.800781 A 12.19 12.19 0 0 0 19.400391 51.800781 L 20 51.800781 L 19.5 51.400391 A 20.73 20.73 0 0 1 14.900391 46.199219 L 14.900391 46.099609 L 14.5 45.900391 z M 5.1992188 52.099609 L 5.5 52.599609 A 34.87 34.87 0 0 0 12.599609 60.400391 L 13 60.800781 L 13 60.099609 A 51.43 51.43 0 0 1 12.5 53.5 L 12.5 53.300781 L 12.300781 53.300781 A 51.94 51.94 0 0 1 5.8007812 52.199219 L 5.1992188 52.099609 z" + ], + }) +); diff --git a/subpackage-template/docs/_templates/class-template.rst b/subpackage-template/docs/_templates/class-template.rst new file mode 100644 index 0000000..0200267 --- /dev/null +++ b/subpackage-template/docs/_templates/class-template.rst @@ -0,0 +1,31 @@ +{{ fullname | escape | underline }} + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + :members: + :special-members: __getitem__ + + {% block methods %} + .. automethod:: __init__ + + {% if methods %} + .. rubric:: {{ _('Methods') }} + + .. autosummary:: + {% for item in methods %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block attributes %} + {% if attributes %} + .. rubric:: {{ _('Attributes') }} + + .. autosummary:: + {% for item in attributes %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% endblock %} diff --git a/subpackage-template/docs/_templates/doc_version.html.jinja b/subpackage-template/docs/_templates/doc_version.html.jinja new file mode 100644 index 0000000..5b20f16 --- /dev/null +++ b/subpackage-template/docs/_templates/doc_version.html.jinja @@ -0,0 +1,2 @@ + +Current {{prettyname}} version: {%raw %}{{ version }}{% endraw %} (older versions). diff --git a/subpackage-template/docs/_templates/module-template.rst b/subpackage-template/docs/_templates/module-template.rst new file mode 100644 index 0000000..6fee8d7 --- /dev/null +++ b/subpackage-template/docs/_templates/module-template.rst @@ -0,0 +1,66 @@ +{{ fullname | escape | underline}} + +.. automodule:: {{ fullname }} + + {% block attributes %} + {% if attributes %} + .. rubric:: {{ _('Module Attributes') }} + + .. autosummary:: + :toctree: + {% for item in attributes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block functions %} + {% if functions %} + .. rubric:: {{ _('Functions') }} + + .. autosummary:: + :toctree: + {% for item in functions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block classes %} + {% if classes %} + .. rubric:: {{ _('Classes') }} + + .. autosummary:: + :toctree: + :template: class-template.rst + {% for item in classes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block exceptions %} + {% if exceptions %} + .. rubric:: {{ _('Exceptions') }} + + .. autosummary:: + :toctree: + {% for item in exceptions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + +{% block modules %} +{% if modules %} +.. rubric:: Modules + +.. autosummary:: + :toctree: + :template: module-template.rst + :recursive: +{% for item in modules %} + {{ item }} +{%- endfor %} +{% endif %} +{% endblock %} diff --git a/subpackage-template/docs/about/index.md.jinja b/subpackage-template/docs/about/index.md.jinja new file mode 100644 index 0000000..2de35ce --- /dev/null +++ b/subpackage-template/docs/about/index.md.jinja @@ -0,0 +1,26 @@ +# About + +## Development + +{{prettyname}} is an open source project by the [European Spallation Source ERIC](https://ess.eu/) (ESS). + +## License + +{{prettyname}} is available as open source under the [BSD-3 license](https://opensource.org/license/BSD-3-Clause). + +## Citing {{prettyname}} + +Please cite the following: + +[](https://zenodo.org/doi/10.5281/zenodo.FIXME) + +To cite a specific version of {{prettyname}}, select the desired version on Zenodo to get the corresponding DOI. + +## Older versions of the documentation + +Older versions of the documentation pages can be found under the assets of each [release](https://github.com/{{orgname}}/{{projectname}}/releases). +Simply download the archive, unzip and view locally in a web browser. + +## Source code and development + +{{prettyname}} is hosted and developed [on GitHub](https://github.com/{{orgname}}/{{projectname}}). diff --git a/subpackage-template/docs/api-reference/index.md.jinja b/subpackage-template/docs/api-reference/index.md.jinja new file mode 100644 index 0000000..49165c0 --- /dev/null +++ b/subpackage-template/docs/api-reference/index.md.jinja @@ -0,0 +1,29 @@ +# API Reference + +## Classes + +```{eval-rst} +.. currentmodule:: {% if namespace_package %}{{ namespace_package }}.{{ projectname.removeprefix(namespace_package) }}{% else %}{{ projectname }}{% endif %} + +.. autosummary:: + :toctree: ../generated/classes + :template: class-template.rst + :recursive: +``` + +## Top-level functions + +```{eval-rst} +.. autosummary:: + :toctree: ../generated/functions + :recursive: +``` + +## Submodules + +```{eval-rst} +.. autosummary:: + :toctree: ../generated/modules + :template: module-template.rst + :recursive: +``` diff --git a/subpackage-template/docs/conf.py.jinja b/subpackage-template/docs/conf.py.jinja new file mode 100644 index 0000000..44e2dbd --- /dev/null +++ b/subpackage-template/docs/conf.py.jinja @@ -0,0 +1,270 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) {{year}} {{orgname|capitalize}} contributors (https://github.com/{{orgname}}) + +import doctest +import os +import sys +from importlib.metadata import PackageNotFoundError +from importlib.metadata import version as get_version + +from sphinx.util import logging + +sys.path.insert(0, os.path.abspath('.')) + +logger = logging.getLogger(__name__) + +# General information about the project. +project = '{{prettyname}}' +copyright = '{{year}} Scipp contributors' +author = 'Scipp contributors' + +html_show_sourcelink = True + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.doctest', + 'sphinx.ext.githubpages', + 'sphinx.ext.intersphinx', + 'sphinx.ext.mathjax', + 'sphinx.ext.napoleon', + 'sphinx.ext.viewcode', + 'sphinx_autodoc_typehints', + 'sphinx_copybutton', + 'sphinx_design', + 'sphinxcontrib.autodoc_pydantic', + 'nbsphinx', + 'myst_parser', +] +{% if orgname == 'scipp' %} +try: + import sciline.sphinxext.domain_types # noqa: F401 + + extensions.append('sciline.sphinxext.domain_types') + # See https://github.com/tox-dev/sphinx-autodoc-typehints/issues/457 + suppress_warnings = ["config.cache"] +except ModuleNotFoundError: + pass +{% endif %} + +myst_enable_extensions = [ + "amsmath", + "colon_fence", + "deflist", + "dollarmath", + "fieldlist", + "html_admonition", + "html_image", + "replacements", + "smartquotes", + "strikethrough", + "substitution", + "tasklist", +] + +myst_heading_anchors = 3 + +autodoc_type_aliases = { + 'array_like': 'array_like', +} + +intersphinx_mapping = { + 'python': ('https://docs.python.org/3', None), + 'numpy': ('https://numpy.org/doc/stable/', None),{% if orgname == 'scipp' %} + 'scipp': ('https://scipp.github.io/', None),{% endif %} +} + +# autodocs includes everything, even irrelevant API internals. autosummary +# looks more suitable in the long run when the API grows. +# For a nice example see how xarray handles its API documentation. +autosummary_generate = True + +napoleon_google_docstring = False +napoleon_numpy_docstring = True +napoleon_use_param = True +napoleon_use_rtype = False +napoleon_preprocess_types = True +napoleon_type_aliases = { + # objects without namespace: numpy + "ndarray": "~numpy.ndarray", +} +typehints_defaults = 'comma' +typehints_use_rtype = False + +{% if orgname == 'scipp' %} +sciline_domain_types_prefix = '{% if namespace_package %}{{namespace_package}}.{% endif %}{{ projectname.removeprefix(namespace_package) }}' +sciline_domain_types_aliases = { + 'scipp._scipp.core.DataArray': 'scipp.DataArray', + 'scipp._scipp.core.Dataset': 'scipp.Dataset', + 'scipp._scipp.core.DType': 'scipp.DType', + 'scipp._scipp.core.Unit': 'scipp.Unit', + 'scipp._scipp.core.Variable': 'scipp.Variable', + 'scipp.core.data_group.DataGroup': 'scipp.DataGroup', +} +{% endif %} + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +source_suffix = ['.rst', '.md'] +html_sourcelink_suffix = '' # Avoid .ipynb.txt extensions in sources + +# The master toctree document. +master_doc = 'index' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# + +try: + release = get_version("{{projectname}}") + version = ".".join(release.split('.')[:3]) # CalVer +except PackageNotFoundError: + logger.info( + "Warning: determining version from package metadata failed, falling back to " + "a dummy version number." + ) + release = version = "0.0.0-dev" + +warning_is_error = True + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '**.ipynb_checkpoints'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + +# -- Options for HTML output ---------------------------------------------- + +html_theme = "pydata_sphinx_theme" +html_theme_options = { + "primary_sidebar_end": ["edit-this-page", "sourcelink"], + "secondary_sidebar_items": [], + "navbar_persistent": ["search-button"], + "show_nav_level": 1, + # Adjust this to ensure external links are moved to "Move" menu + "header_links_before_dropdown": 4, + "pygment_light_style": "github-light-high-contrast", + "pygment_dark_style": "github-dark-high-contrast", + "logo": { + "image_light": "_static/logo.svg", + "image_dark": "_static/logo-dark.svg", + }, + "external_links": [ +{% for link in related_projects.replace(' ', '').split(',')|sort -%} +{% raw %} {% endraw %}{"name": "{{ link }}", "url": "https://{{orgname}}.github.io{% if link == 'Scipp' %}{% else %}/{{ link|lower }}{% endif %}"}, +{% endfor %} ], + "icon_links": [ + { + "name": "GitHub", + "url": "https://github.com/{{orgname}}/{{projectname}}", + "icon": "fa-brands fa-github", + "type": "fontawesome", + }, + { + "name": "PyPI", + "url": "https://pypi.org/project/{{projectname}}/", + "icon": "fa-brands fa-python", + "type": "fontawesome", + }, + { + "name": "Conda", + "url": "https://anaconda.org/conda-forge/{{projectname}}", + "icon": "fa-custom fa-anaconda", + "type": "fontawesome", + }, + ], + "footer_start": ["copyright", "sphinx-version"], + "footer_end": ["doc_version", "theme-version"], +} +html_context = { + "doc_path": "docs", +} +html_sidebars = { + "**": ["sidebar-nav-bs", "page-toc"], +} + +html_title = "{{prettyname}}" +html_logo = "_static/logo.svg" +html_favicon = "_static/favicon.ico" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] +html_css_files = [] +html_js_files = ["anaconda-icon.js"] + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = '{{projectname}}doc' + +# -- Options for Matplotlib in notebooks ---------------------------------- + +nbsphinx_execute_arguments = [ + "--Session.metadata=scipp_sphinx_build=True", +] + +# -- Options for doctest -------------------------------------------------- + +# sc.plot returns a Figure object and doctest compares that against the +# output written in the docstring. But we only want to show an image of the +# figure, not its `repr`. +# In addition, there is no need to make plots in doctest as the documentation +# build already tests if those plots can be made. +# So we simply disable plots in doctests. +doctest_global_setup = ''' +import numpy as np + +try: + import scipp as sc + + def do_not_plot(*args, **kwargs): + pass + + sc.plot = do_not_plot + sc.Variable.plot = do_not_plot + sc.DataArray.plot = do_not_plot + sc.DataGroup.plot = do_not_plot + sc.Dataset.plot = do_not_plot +except ImportError: + # Scipp is not needed by docs if it is not installed. + pass +''' + +# Using normalize whitespace because many __str__ functions in scipp produce +# extraneous empty lines and it would look strange to include them in the docs. +doctest_default_flags = ( + doctest.ELLIPSIS + | doctest.IGNORE_EXCEPTION_DETAIL + | doctest.DONT_ACCEPT_TRUE_FOR_1 + | doctest.NORMALIZE_WHITESPACE +) + +# -- Options for linkcheck ------------------------------------------------ + +linkcheck_ignore = [ + # Specific lines in Github blobs cannot be found by linkcheck. + r'https?://github\.com/.*?/blob/[a-f0-9]+/.+?#', + # Linkcheck seems to be denied access by some DOI resolvers. + # Since DOIs are supposed to be permanent, we don't need to check them.' + r'https?://doi\.org/', + r'https?://dx\.doi\.org/', +] diff --git a/subpackage-template/docs/developer/coding-conventions.md b/subpackage-template/docs/developer/coding-conventions.md new file mode 100644 index 0000000..4fafc18 --- /dev/null +++ b/subpackage-template/docs/developer/coding-conventions.md @@ -0,0 +1,117 @@ +# Coding conventions + +## Code formatting + +There are no explicit code formatting conventions since we use `ruff` to enforce a format. + +## Docstring format + +We use the [NumPy docstring format](https://www.sphinx-doc.org/en/master/usage/extensions/example_numpy.html). +We use `sphinx-autodocs-typehints` to automatically insert type hints into the docstrings. +Our format thus deviates from the default NumPy example given by the link above. +Docstrings should therefore be laid out as follows, including spacing and punctuation: + +```python + +def foo(x: int, y: float) -> float: + """Short description. + + Long description. + + With multiple paragraphs. + + Warning + ------- + Be careful! + + Parameters + ---------- + x: + First input. + y: + Second input. + + Returns + ------- + : + The result. + + Raises + ------ + ValueError + If the input is bad. + IndexError + If some lookup failed. + + See Also + -------- + scitacean.bar: + A bit less foo. + + Examples + -------- + This is how to use it: + + >>> foo(1, 2) + 3 + + And also: + + >>> foo(1, 3) + 6 + """ +``` + +The order of sections is fixed as shown in the example. + +- **Short description** (*required*) A single sentence describing the purpose of the function / class. +- **Long description** (*optional*) One or more paragraphs of detailed explanations. + Can include additional sections like `Warning` or `Hint`. +- **Parameters** (*required for functions*) List of all function arguments including their name but not their type. + Listing arguments like this can seem ridiculous if the explanation is as devoid of content as in the example. + But it is still required in order for sphinx to show the types. +- **Returns** (*required for functions*) Description of the return value. + Required for the same reason as the parameter list. + + For a single return value, neither a name nor type should be given. + But a colon is required as in the example above in order to produce proper formatting. + + For multiple return values, to produce proper formatting, + both name and type must be given even though the latter repeats the type annotation: + + ```python + + """ + Returns + ------- + n: int + The first return value. + z: float + The second return value. + """ + ``` + +- **Raises** (*optional*) We generally do not document what exceptions can be raised from a function. + But if there are some important cases, this section can list those exceptions with an explanation + of when the exception is raised. + The exception type is required. + Note that there are no colons here. +- **See Also** (*optional*) List of related functions and/or classes. + The function/class name should include the module it is in but without reST markup. + For simple cases, the explanation can be left out. + In this case, the colon should be omitted as well and multiple entries must be separated by commas. +- **Examples** (*optional*) Example code given using `>>>` as the Python prompt. + May include text before, after, and between code blocks. + Note the spacing in the example. + +Some functions can be sufficiently described by a single sentence. +In this case, the 'Parameters' and 'Returns' sections may be omitted and the docstring should be laid out on a single line. +If it does not fit on a single line, it is too complicated. +For example + +```python +def bar(self) -> int: + """Returns the number of dimensions.""" +``` + +Note that the argument types are not shown in the rendered documentation. diff --git a/subpackage-template/docs/developer/dependency-management.md.jinja b/subpackage-template/docs/developer/dependency-management.md.jinja new file mode 100644 index 0000000..8a1bfd2 --- /dev/null +++ b/subpackage-template/docs/developer/dependency-management.md.jinja @@ -0,0 +1,13 @@ +# Dependency management + +{{projectname}} is a library, so the package dependencies are never pinned. +Lower bounds are fine and individual versions can be excluded. +See, e.g., [Should You Use Upper Bound Version Constraints](https://iscinumpy.dev/post/bound-version-constraints/) for an explanation. + +Development dependencies (as opposed to dependencies of the deployed package that users need to install) are pinned to an exact version in order to ensure reproducibility. +This also includes dependencies used for the various CI builds. +This is done by specifying packages (and potential version constraints) in `requirements/*.in` files and locking those dependencies using [pip-compile-multi](https://pip-compile-multi.readthedocs.io/en/latest/index.html) to produce `requirements/*.txt` files. +Those files are then used by [tox](https://tox.wiki/en/latest/) to create isolated environments and run tests, build docs, etc. + +`tox` can be cumbersome to use for local development. +Therefore `requirements/dev.txt` can be used to create a virtual environment with all dependencies. diff --git a/subpackage-template/docs/developer/getting-started.md.jinja b/subpackage-template/docs/developer/getting-started.md.jinja new file mode 100644 index 0000000..bfeb2d3 --- /dev/null +++ b/subpackage-template/docs/developer/getting-started.md.jinja @@ -0,0 +1,91 @@ +# Getting started + +## Setting up + +### Dependencies + +Development dependencies are specified in `requirements/dev.txt` and can be installed using (see [Dependency Management](./dependency-management.md) for more information) + +```sh +pip install -r requirements/dev.txt +``` + +Additionally, building the documentation requires [pandoc](https://pandoc.org/) which is not on PyPI and needs to be installed through other means, e.g. with your OS package manager. + +### Install the package + +Install the package in editable mode using + +```sh +pip install -e . +``` + +### Set up git hooks + +The CI pipeline runs a number of code formatting and static analysis tools. +If they fail, a build is rejected. +To avoid that, you can run the same tools locally. +This can be done conveniently using [pre-commit](https://pre-commit.com/): + +```sh +pre-commit install +``` + +Alternatively, if you want a different workflow, take a look at ``tox.ini`` or ``.pre-commit.yaml`` to see what tools are run and how. + +## Running tests + +`````{tab-set} +````{tab-item} tox +Run the tests using + +```sh +tox -e py{{min_python|replace(".", "")}} +``` + +(or just `tox` if you want to run all environments). + +```` +````{tab-item} Manually +Run the tests using + +```sh +python -m pytest +``` +```` +````` + +## Building the docs + +`````{tab-set} +````{tab-item} tox +Build the documentation using + +```sh +tox -e docs +``` + +This builds the docs and also runs `doctest`. +`linkcheck` can be run separately using + +```sh +tox -e linkcheck +``` +```` + +````{tab-item} Manually + +Build the documentation using + +```sh +python -m sphinx -v -b html -d .tox/docs_doctrees docs html +``` + +Additionally, test the documentation using + +```sh +python -m sphinx -v -b doctest -d .tox/docs_doctrees docs html +python -m sphinx -v -b linkcheck -d .tox/docs_doctrees docs html +``` +```` +````` \ No newline at end of file diff --git a/subpackage-template/docs/developer/index.md.jinja b/subpackage-template/docs/developer/index.md.jinja new file mode 100644 index 0000000..9dc534a --- /dev/null +++ b/subpackage-template/docs/developer/index.md.jinja @@ -0,0 +1,16 @@ +# Development + +```{include} ../../CONTRIBUTING.md +``` + +## Table of contents + +```{toctree} +--- +maxdepth: 2 +--- + +getting-started +coding-conventions +dependency-management +``` diff --git a/subpackage-template/docs/index.md.jinja b/subpackage-template/docs/index.md.jinja new file mode 100644 index 0000000..1876a1c --- /dev/null +++ b/subpackage-template/docs/index.md.jinja @@ -0,0 +1,49 @@ +:::{image} _static/logo.svg +:class: only-light +:alt: {{prettyname}} +:width: 60% +:align: center +::: +:::{image} _static/logo-dark.svg +:class: only-dark +:alt: {{prettyname}} +:width: 60% +:align: center +::: + +```{raw} html + +``` + +```{role} transparent +``` + +# {transparent}`{{prettyname}}` + +