diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b2e5df7..5224f28 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.9", "3.12"] + python-version: ["3.10", "3.13"] steps: - uses: actions/checkout@v4 diff --git a/pyproject.toml b/pyproject.toml index c81ed76..f85819b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,7 +67,7 @@ dependencies = [ ] [[tool.hatch.envs.test.matrix]] -python = ["3.9", "3.10", "3.11", "3.12"] +python = ["3.10", "3.11", "3.12", "3.13"] [tool.hatch.envs.test.scripts] run = "pytest {args}" diff --git a/template/.gitignore b/template/.gitignore index b2079ce..b90ccff 100644 --- a/template/.gitignore +++ b/template/.gitignore @@ -154,6 +154,7 @@ instance/ # Sphinx documentation docs/_build/ +docs/api # PyBuilder .pybuilder/ diff --git a/template/pyproject.toml.jinja b/template/pyproject.toml.jinja index 3614b07..da7c8eb 100644 --- a/template/pyproject.toml.jinja +++ b/template/pyproject.toml.jinja @@ -23,7 +23,7 @@ authors = [ ] license = "{{ license }}" readme = {"file" = "README.md", "content-type" = "text/markdown"} -requires-python = ">=3.9" +requires-python = ">=3.10" # Please consult https://pypi.org/classifiers/ for a full list. classifiers = [ "Development Status :: 2 - Pre-Alpha", @@ -38,10 +38,10 @@ classifiers = [ "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Scientific/Engineering", {%- if use_types %} "Typing :: Typed", @@ -126,11 +126,14 @@ ignore = [ "ANN101", # 'Missing type annotation for {self} in method'. "ANN102", # 'Missing type annotation for {cls} in classmethod'. ] -{%- if use_vcs_version %} exclude = [ +{%- if use_vcs_version %} "src/{{ package_name }}/_version.py", -] {%- endif %} +{%- if documentation == "sphinx" %} + "docs/conf.py", +{%- endif %} +] [tool.ruff.lint.extend-per-file-ignores] "__init__.py" = [ @@ -231,13 +234,22 @@ extra-dependencies = [ "mkdocs-awesome-pages-plugin ~=2.9", ] {%- elif documentation == "sphinx" %} +dependencies = [ + "pydata_sphinx_theme ~=0.16", + "myst-parser ~=4.0", + "Sphinx ~=8.0", + "sphinx-autobuild ==2024.10.3" +] {%- endif %} [tool.hatch.envs.docs.scripts] {%- if documentation == "mkdocs" %} build = "mkdocs build {args:--clean --strict}" serve = "mkdocs serve {args}" -{%- elif documentation == "sphinx" %} +{%- endif %} +{%- if documentation == "sphinx" %} +build = ["sphinx-apidoc -o docs/api src/{{ package_name}}", "sphinx-build {args:-W -b html docs docs/_build}"] +serve = ["sphinx-apidoc -o docs/api src/{{ package_name}}", "sphinx-autobuild docs --watch src/{{ package_name }} {args:-b html docs/_build/serve}"] {%- endif %} {%- endif %} @@ -268,7 +280,7 @@ extra-dependencies = [ ] [[tool.hatch.envs.test.matrix]] -python = ["3.9", "3.12"] +python = ["3.10", "3.13"] [tool.hatch.envs.test.scripts] run = "pytest {args:--cov={{ package_name }} --cov-report=term-missing}" diff --git a/template/{% if dev_platform == 'GitHub' %}.github{% endif %}/workflows/test.yml.jinja b/template/{% if dev_platform == 'GitHub' %}.github{% endif %}/workflows/test.yml.jinja index 2daf345..7542bb3 100644 --- a/template/{% if dev_platform == 'GitHub' %}.github{% endif %}/workflows/test.yml.jinja +++ b/template/{% if dev_platform == 'GitHub' %}.github{% endif %}/workflows/test.yml.jinja @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - python-version: ["3.12"] + python-version: ["3.10"] steps: - uses: actions/checkout@v4 @@ -46,7 +46,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.9", "3.12"] + python-version: ["3.10", "3.13"] steps: - uses: actions/checkout@v4 diff --git a/template/{% if documentation != '' %}.readthedocs.yaml{% endif %}.jinja b/template/{% if documentation != '' %}.readthedocs.yaml{% endif %}.jinja index 3a35a84..7e7f3dc 100644 --- a/template/{% if documentation != '' %}.readthedocs.yaml{% endif %}.jinja +++ b/template/{% if documentation != '' %}.readthedocs.yaml{% endif %}.jinja @@ -15,4 +15,5 @@ build: mkdocs: configuration: mkdocs.yml {%- elif documentation == "sphinx" %} + - hatch run docs:build {%- endif %} diff --git a/template/{% if documentation == 'sphinx' %}docs{% endif %}/conf.py.jinja b/template/{% if documentation == 'sphinx' %}docs{% endif %}/conf.py.jinja new file mode 100644 index 0000000..34364e8 --- /dev/null +++ b/template/{% if documentation == 'sphinx' %}docs{% endif %}/conf.py.jinja @@ -0,0 +1,96 @@ +# +# {{ project_name }} documentation build configuration file +# +import importlib.metadata + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + "myst_parser", + "sphinx.ext.intersphinx", + "sphinx.ext.autodoc", +] + +# The suffix of source filenames. +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "{{ project_name }}" +copyright = "Copyright © {{ year }} {{ copyright_holder }}" +html_show_sphinx = False + +# 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. +version = importlib.metadata.version("{{ package_name }}") + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "default" + +# 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" + +# -- Options for extensions ---------------------------------------------------- +# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html +myst_enable_extensions = ["html_image"] + + +# -- Options for HTML output --------------------------------------------------- + +html_theme = "pydata_sphinx_theme" + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# 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'] + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = "{{ project_name }}_doc" + + +intersphinx_mapping = { + "python": ("https://docs.python.org/", None), +} diff --git a/template/{% if documentation == 'sphinx' %}docs{% endif %}/index.md.jinja b/template/{% if documentation == 'sphinx' %}docs{% endif %}/index.md.jinja new file mode 100644 index 0000000..b449557 --- /dev/null +++ b/template/{% if documentation == 'sphinx' %}docs{% endif %}/index.md.jinja @@ -0,0 +1,25 @@ +# {{ project_name }} + +## Overview + +{{ package_description }} + +[API Documentation](./api/modules.rst) + +## Copyright +{% if license == "MIT" %} +- Copyright © {{ year }} {{ copyright_holder }}. +- Free software distributed under the MIT License. +{% elif license == "BSD-3-Clause" %} +- Copyright © {{ year }} {{ copyright_holder }}. +- Free software distributed under the 3-Clause BSD License. +{% elif license == "Apache-2.0" %} +- Copyright © {{ year }} {{ copyright_holder }}. +- Free software distributed under the Apache Software License 2.0. +{% endif %} + + +```{toctree} +:hidden: +./api/modules.rst +``` diff --git a/template/{% if documentation == 'sphinx' %}docs{% endif %}/index.rst.jinja b/template/{% if documentation == 'sphinx' %}docs{% endif %}/index.rst.jinja deleted file mode 100644 index 0647e9e..0000000 --- a/template/{% if documentation == 'sphinx' %}docs{% endif %}/index.rst.jinja +++ /dev/null @@ -1,17 +0,0 @@ -{{ project_name }} -======================================================================================== - -{{ package_description }} - -Copyright ---------- -{% if license == "MIT" %} -- Copyright © {{ year }} {{ copyright_holder }}. -- Free software distributed under the [MIT License](../LICENSE). -{% elif license == "BSD-3-Clause" %} -- Copyright © {{ year }} {{ copyright_holder }}. -- Free software distributed under the [3-Clause BSD License](../LICENSE). -{% elif license == "Apache-2.0" %} -- Copyright © {{ year }} {{ copyright_holder }}. -- Free software distributed under the [Apache Software License 2.0](../LICENSE). -{% endif %} diff --git a/tests/test_template_init.py b/tests/test_template_init.py index aefd953..fd0210b 100644 --- a/tests/test_template_init.py +++ b/tests/test_template_init.py @@ -49,6 +49,15 @@ def license(request: pytest.FixtureRequest) -> str: return request.param +@pytest.fixture( + scope="module", + params=["mkdocs", "sphinx", ""], +) +def documentation(request: pytest.FixtureRequest) -> str: + """Provide a documentation option.""" + return request.param + + @pytest.fixture def destination_path( tmp_path_factory: pytest.TempPathFactory, @@ -71,7 +80,6 @@ def answers() -> dict[str, str]: "package_name": "alien_clones", "package_description": "Wubba Lubba Dub-Dub", "username": "rickprime", - "documentation": "mkdocs", "year": str(today.year), } @@ -81,6 +89,7 @@ def test_init_template( answers: dict[str, str], dev_platform: str, license: str, + documentation: str, ) -> None: """Expect that the template can be initialized with any provided license.""" parent = destination_path / license / answers["project_slug"] @@ -92,6 +101,7 @@ def test_init_template( **answers, "dev_platform": dev_platform, "license": license, + "documentation": documentation, }, defaults=True, ) @@ -111,6 +121,7 @@ def test_template_suite( destination_path: Path, dev_platform: str, answers: dict[str, str], + documentation: str, ) -> None: """Expect that the test suite passes for the initialized template.""" parent = destination_path / answers["project_slug"] @@ -122,6 +133,7 @@ def test_template_suite( **answers, "dev_platform": dev_platform, "license": "MIT", + "documentation": documentation, }, defaults=True, ) @@ -152,12 +164,13 @@ def test_template_suite( check=True, shell=True, ) - subprocess.run( - "hatch run docs:build", - cwd=project_dir, - check=True, - shell=True, - ) + if documentation: + subprocess.run( + "hatch run docs:build", + cwd=project_dir, + check=True, + shell=True, + ) subprocess.run( "hatch run style:check", cwd=project_dir,