From c01197cd7749aa52ed9daf681af1759e2f117fc2 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 3 May 2026 03:19:38 +0000 Subject: [PATCH 1/2] Apply senior-engineer review fixes across packaging, CI, and docs Real bugs: - .readthedocs.yml referenced docs/requirements.txt which is never committed; switch RTD to install the package's new [docs] extra so builds work out of the box. - docs/conf.py inserted ../my_package on sys.path (subpackages would import as top-level names); use ../ so autodoc resolves my_package.*. - Drop hard pin pandas==2.1.4 to >=2.1.4 to unblock numpy 2.x stacks. Packaging: - Move dev tooling (pre-commit, pytest, mypy, IPython, ipykernel, ipywidgets, sphinx) out of runtime dependencies into [test], [docs], [notebook], and an aggregate [dev] extra. - Fix Development Status classifier (5 -> 1) and add 3.10-3.13 classifiers to match requires-python. CI hardening: - python-app.yml now runs a 3.10/3.11/3.12/3.13 matrix, installs the [test] extra, and uploads codecov only from the 3.12 leg with fail_ci_if_error=false. Added concurrency, least-privilege permissions, and timeout-minutes. - pre-commit.yml and codeql.yml gain matching concurrency / timeout / permissions blocks. - .gitlab-ci.yml synced to ruff/pytest, parallel matrix, and cobertura coverage report. Template hygiene: - README: replace blanket sed loop with a file-extension-restricted find, drop the now-stale pip-compile docs workflow, document the new extras, expand the pre-release checklist (CITATION + classifiers), and clarify the dev-branch caveat for CI triggers. - docs/conf.py: dynamic copyright year, document how to enable sphinxcontrib-bibtex, and correct the misleading nbsphinx_execute comment. - tests/test_example.py: add TODO marker so the no-op suite is not mistaken for real coverage; rename setUpClass parameter to cls. --- .github/workflows/codeql.yml | 5 +++ .github/workflows/pre-commit.yml | 8 +++++ .github/workflows/python-app.yml | 52 ++++++++++++++++++++------------ .gitlab-ci.yml | 26 ++++++++-------- .readthedocs.yml | 19 +++++------- README.md | 45 ++++++++++++++------------- docs/conf.py | 10 ++++-- docs/requirements.in | 6 ---- pyproject.toml | 33 +++++++++++++++----- tests/test_example.py | 6 +++- 10 files changed, 128 insertions(+), 82 deletions(-) delete mode 100644 docs/requirements.in diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index fda4259..2a5d306 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -8,10 +8,15 @@ on: schedule: - cron: "0 6 * * 1" # Mondays at 06:00 UTC +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: analyze: name: Analyze (python) runs-on: ubuntu-latest + timeout-minutes: 30 permissions: security-events: write actions: read diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 26d22b7..1d0851e 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -6,9 +6,17 @@ on: pull_request: branches: [main] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + jobs: pre-commit: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 4444122..e0b906d 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -5,30 +5,42 @@ name: Python application on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read jobs: build: - runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.12" - cache: "pip" - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pytest pytest-cov - pip install . - - name: Run tests with coverage - run: pytest --cov --cov-report=xml - - name: Upload coverage report - uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: "pip" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e ".[test]" + - name: Run tests with coverage + run: pytest --cov --cov-report=xml + - name: Upload coverage report + if: matrix.python-version == '3.12' + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: false diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2be4dac..998106a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,20 +1,22 @@ -# If using GitLab instead of GitHub +# Optional GitLab CI mirror of `.github/workflows/python-app.yml`. # https://medium.com/swlh/automate-testing-with-gitlab-pipelines-4d35c72c18a default: - image: python:3.10 + image: python:3.12 before_script: - - apt-get update - - apt-get install -y python3-pip - - pip install --upgrade pip - - pip install flake8 pytest coverage + - python -m pip install --upgrade pip + - pip install -e ".[test]" stages: - - install - test -install: - script: - - pip install . test: + parallel: + matrix: + - PYTHON_VERSION: ["3.10", "3.11", "3.12", "3.13"] + image: python:$PYTHON_VERSION script: - - coverage run -m pytest - - coverage report + - pytest --cov --cov-report=term --cov-report=xml coverage: '/TOTAL.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/' + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: coverage.xml diff --git a/.readthedocs.yml b/.readthedocs.yml index 252631b..b348af5 100755 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -8,14 +8,11 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.10" + python: "3.12" # You can also specify other tool versions: # nodejs: "20" # rust: "1.70" # golang: "1.20" - commands: - - python -m pip install --exists-action=w --no-cache-dir -r docs/requirements.txt - - python -m sphinx -T -b html -d docs/_build/doctrees -D language=en docs $READTHEDOCS_OUTPUT/html # Build documentation in the "docs/" directory with Sphinx sphinx: @@ -31,13 +28,11 @@ sphinx: # - pdf # - epub -# Optional but recommended, declare the Python requirements required -# to build your documentation -# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -# -# docs/requirements.txt can be generated using pip-tools (see https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html) +# Install the package with its `docs` extra so the Sphinx build matches the +# pinned toolchain declared in pyproject.toml. python: install: - - requirements: docs/requirements.txt - - method: pip - path: . + - method: pip + path: . + extra_requirements: + - docs diff --git a/README.md b/README.md index 06f88d5..4469224 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,15 @@ PyPI Package Template Instructions 1. Choose a name that does not exist in [pypi](https://pypi.org/). You can check by going to `https://pypi.org/simple/{my_awesome_new_package}`; a 404 means the name is available. -2. Replace all `my_package` names, strings, etc. in this repo with your desired package name (e.g., `my_awesome_new_package`). The command below makes this simple; run it after cloning the repo locally. The `sed` syntax below is for GNU `sed` (Linux); on macOS use `sed -i ''` instead of `sed -i`. +2. Replace all `my_package` names, strings, etc. in this repo with your desired package name (e.g., `my_awesome_new_package`). The command below makes this simple; run it after cloning the repo locally. It restricts the rewrite to plain-text files and skips `.git/` so binaries (logos, etc.) are left alone. The `sed` syntax below is for GNU `sed` (Linux); on macOS use `sed -i ''` instead of `sed -i`. ```bash -for file in $(find . -type f -not -path "./.git/*"); do - sed -i "s/my_package/my_awesome_new_package/g" "$file" -done +find . -type f \ + -not -path "./.git/*" \ + \( -name "*.py" -o -name "*.md" -o -name "*.rst" -o -name "*.toml" \ + -o -name "*.cfg" -o -name "*.yml" -o -name "*.yaml" -o -name "*.in" \ + -o -name "*.cff" -o -name "*.sh" -o -name "Makefile*" -o -name "CODEOWNERS" \) \ + -exec sed -i "s/my_package/my_awesome_new_package/g" {} + ``` Similarly, replace all instances of `mahynski` with your GitHub username, and rename the `my_package/` directory to match your chosen name. @@ -26,12 +29,15 @@ git mv my_package my_awesome_new_package git commit -m "rename package to my_awesome_new_package" ``` -3. Replace the placeholder `LICENSE.md` with the full text of your chosen license (see [choosealicense.com](https://choosealicense.com/)) and update the `license` field in `pyproject.toml` accordingly. +3. Replace the placeholder `LICENSE.md` with the full text of your chosen license (see [choosealicense.com](https://choosealicense.com/)) and update the `license` field in `pyproject.toml` accordingly. Per [PEP 639](https://peps.python.org/pep-0639/), prefer an SPDX expression: `license = "MIT"`. 4. Get coding! Follow the best practices below. When you are ready to publish, proceed to the next step. -5. Bump the [version](https://semver.org/) in `my_package/__init__.py` and in `CITATION.cff`. +5. Before tagging a release, update **all** of: + - `__version__` in `my_package/__init__.py` + - `version:` and `date-released:` in `CITATION.cff` (and the `doi:` once Zenodo mints it) + - the `Development Status` classifier in `pyproject.toml` 6. When finished, first enable preservation of this repo on [Zenodo](https://zenodo.org/), then create a release on GitHub. Zenodo will detect the new release and mint a DOI and badge. Update the `{github_id}` placeholder in this `README.md` and in `docs/index.rst` with the ID generated by Zenodo. 7. Follow [these instructions](https://packaging.python.org/en/latest/tutorials/packaging-projects/) to publish to PyPI. -8. Develop on a `dev` branch and merge into `main` for releases. This template assumes that pattern; adjust to taste. +8. The included GitHub Actions workflows trigger on pushes and PRs to `main`. If you adopt a `dev` → `main` pattern for releases, update the `on:` blocks in `.github/workflows/*.yml` so CI runs on `dev` too. Best Practices === @@ -45,37 +51,34 @@ Create a conda/mamba environment, then install the package in editable mode so c mamba create -n awesome_env python=3.12 mamba activate awesome_env cd my_awesome_new_package -pip install -e . # editable install +pip install -e ".[dev]" # editable install with dev/test/docs/notebook extras python -m ipykernel install --user --name=awesome_env # register Jupyter kernel jupyter notebook --port 4321 # launch on localhost (default auth enabled) ``` +The package declares the following extras in `pyproject.toml`: + +- `test` — `pytest` + `pytest-cov` (what CI installs) +- `docs` — Sphinx and the theme/extensions used by `docs/conf.py` +- `notebook` — `IPython`, `ipywidgets`, `ipykernel` +- `dev` — superset of the above plus `pre-commit` and `mypy` + Note: don't disable Jupyter's token/password or bind it to `0.0.0.0` unless you understand the access implications. The default (localhost + token) is the safe choice. Documentation --- -Documentation lives in `docs/` and is built with [Sphinx](https://www.sphinx-doc.org/en/master/). - -The doc build pulls Sphinx extensions from `docs/requirements.in`. Pin them with `pip-compile` whenever you change them: - -```bash -cd docs -pip install pip-tools -pip-compile requirements.in # produces requirements.txt -``` - -Tweak `docs/conf.py` as needed, then generate the API reference and HTML output: +Documentation lives in `docs/` and is built with [Sphinx](https://www.sphinx-doc.org/en/master/). Sphinx and the extensions enabled in `docs/conf.py` are declared as the `docs` extra in `pyproject.toml`, so a single editable install pulls everything in: ```bash +pip install -e ".[docs]" cd docs -pip install -r requirements.txt bash make_docs.sh ``` Adjust the landing page in `docs/index.rst` manually — see the [reStructuredText primer](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html). -For hosted docs, link the repo at [Read the Docs](https://about.readthedocs.com/). The `.readthedocs.yml` already installs both `docs/requirements.txt` and the package itself; adjust as needed. +For hosted docs, link the repo at [Read the Docs](https://about.readthedocs.com/). The `.readthedocs.yml` installs the package with its `docs` extra so the build matches the pinned toolchain in `pyproject.toml`. To start fresh, run `sphinx-quickstart` in `docs/`. diff --git a/docs/conf.py b/docs/conf.py index 7bb31dd..04741a7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -5,16 +5,17 @@ https://www.sphinx-doc.org/en/master/usage/configuration.html """ +import datetime import os import sys -sys.path.insert(0, os.path.abspath("../my_package/")) +sys.path.insert(0, os.path.abspath("..")) # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = "my_package" -copyright = "2024, Nathan A. Mahynski" +copyright = f"{datetime.date.today().year}, Nathan A. Mahynski" author = "Nathan A. Mahynski" # -- General configuration --------------------------------------------------- @@ -29,6 +30,9 @@ "nbsphinx", "sphinx_gallery.load_style", ] +# To enable BibTeX citations, add "sphinxcontrib.bibtex" above, install +# `sphinxcontrib-bibtex` (e.g. add it to the docs extra), and set +# `bibtex_bibfiles = ["refs.bib"]` with at least one *.bib file under docs/. templates_path = ["_templates"] exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] @@ -46,7 +50,7 @@ html_theme = "sphinx_book_theme" #'sphinx_rtd_theme' html_static_path = ["_static"] pygments_style = "sphinx" -nbsphinx_execute = "never" # Always pre-run notebooks and save their output - just display on readthedocs +nbsphinx_execute = "never" # Notebooks must be pre-executed locally; RTD just renders the saved output. # Examples for setting thumbnails for jupyter notebook tiles # nbsphinx_kernel_name = 'my_package-kernel' # nbsphinx_thumbnails = { diff --git a/docs/requirements.in b/docs/requirements.in deleted file mode 100644 index 2f19248..0000000 --- a/docs/requirements.in +++ /dev/null @@ -1,6 +0,0 @@ -sphinx-book-theme==1.0.1 -sphinx -readthedocs-sphinx-search>=0.3.2 -nbsphinx==0.9.2 -sphinx_gallery==0.14.0 -sphinxcontrib-bibtex==2.5.0 diff --git a/pyproject.toml b/pyproject.toml index 9ef37b5..ccd8d45 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,18 +16,24 @@ maintainers = [ ] keywords = [] classifiers = [ - "Development Status :: 5 - Production/Stable", + "Development Status :: 1 - Planning", "Intended Audience :: Science/Research", "Operating System :: OS Independent", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] readme = "README.md" +# Replace with an SPDX expression (e.g. license = "MIT") once LICENSE.md +# is populated. See PEP 639. license = {file = "LICENSE.md"} requires-python = ">=3.10" dependencies = [ "matplotlib>=3.9.0", "numpy>=1.26.4", - "pandas==2.1.4", # For Colab + "pandas>=2.1.4", "scikit-learn>=1.5.0", "scipy>=1.13.1", "seaborn>=0.13.0", @@ -35,18 +41,31 @@ dependencies = [ "watermark>=2.4.3", "missingno>=0.5.2", "wandb>=0.17.5", +] + +[project.optional-dependencies] +test = [ + "pytest>=7.4.0", + "pytest-cov", +] +docs = [ + "sphinx", + "sphinx-book-theme>=1.0.1", + "readthedocs-sphinx-search>=0.3.2", + "nbsphinx>=0.9.2", + "sphinx_gallery>=0.14.0", +] +notebook = [ "IPython", "ipywidgets", "ipykernel", +] +dev = [ + "my_package[test,docs,notebook]", "pre-commit>=3.3.3", - "pytest>=7.4.0", "mypy", - "sphinx" ] -[project.optional-dependencies] -all = [] - [tool.pytest.ini_options] testpaths = [ "tests", diff --git a/tests/test_example.py b/tests/test_example.py index 6ecb9ec..e76ad8c 100644 --- a/tests/test_example.py +++ b/tests/test_example.py @@ -1,6 +1,10 @@ """ Unittests template example. +TODO: Replace this no-op test with real tests for your package. The dummy +test below exists only to keep the test suite green on a fresh template +checkout — coverage numbers it produces are not meaningful. + Author: Nathan A. Mahynski """ @@ -13,7 +17,7 @@ class DummyTest(unittest.TestCase): """Perform dummy tests.""" @classmethod - def setUpClass(self): + def setUpClass(cls): """Set up things for all members of this test class.""" return From a4294edf2caba784d87de79c652f2aaef9e3a6dc Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 3 May 2026 11:07:38 +0000 Subject: [PATCH 2/2] Round-2 review fixes: RTD apidoc, SHA pins, ruff/coverage config Real bugs: - docs/index.rst references a `modules` toctree but RTD only ran sphinx-build, never sphinx-apidoc, so the hosted API reference was empty (only suppressed by fail_on_warning: false). Add a pre_build job to .readthedocs.yml that runs sphinx-apidoc, and gitignore the generated docs/modules.rst / docs/my_package*.rst. - docs/Makefile.txt was unreachable by `make` (wrong filename); rename to docs/Makefile and rewrite docs/make_docs.sh to call sphinx-build directly with `set -euo pipefail`, dropping the redundant second `make html`. Supply-chain hardening: - Pin every third-party GitHub Action to a 40-char commit SHA with a trailing version comment (actions/checkout v4.3.1, setup-python v5.6.0, codecov-action v5.5.4, codeql-action v3.35.3, pre-commit action v3.0.1). Bump codecov-action v4 -> v5 along the way. - Group Dependabot updates so SHA bumps land as a single PR per ecosystem instead of one per action. Tooling config: - Add [tool.ruff] / [tool.ruff.lint] (target-version = py310, line-length = 100, E/W/F/I/B/UP) so config is in pyproject.toml rather than only in pre-commit. - Add [tool.coverage.run] source = ["my_package"] and branch = true so coverage reflects the package, not whatever happens to import during tests (tests/ inflated the previous numbers to 100%). - Bump ruff pre-commit hook v0.9.9 -> v0.15.12 and pin default_language_version to python3.12. Template polish: - Remove tests/__init__.py: pytest doesn't need it, and it makes the tests/ tree behave inconsistently across import modes. - Comment out the {github_id} Zenodo badge in README.md and docs/index.rst so the rendered docs don't ship a broken image. - CITATION.cff: drop placeholder doi / date-released values so cff-convert validation passes; leave commented hints for when Zenodo mints a real DOI. - docs/conf.py: shorten the nbsphinx comment to fit the new ruff line-length, and document why html_logo and the README image point at different files in _static/. --- .github/dependabot.yml | 7 +++++++ .github/workflows/codeql.yml | 9 ++++++--- .github/workflows/pre-commit.yml | 9 ++++++--- .github/workflows/python-app.yml | 10 +++++++--- .gitignore | 3 +++ .pre-commit-config.yaml | 4 +++- .readthedocs.yml | 5 +++++ CITATION.cff | 22 ++++++++++++---------- README.md | 3 +++ docs/{Makefile.txt => Makefile} | 0 docs/conf.py | 7 +++++-- docs/index.rst | 6 ++++-- docs/make_docs.sh | 18 +++++++++++------- pyproject.toml | 26 ++++++++++++++++++++++++++ tests/__init__.py | 5 ----- 15 files changed, 98 insertions(+), 36 deletions(-) rename docs/{Makefile.txt => Makefile} (100%) delete mode 100644 tests/__init__.py diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 21395ed..810dee7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,9 +5,16 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 5 + groups: + actions: + patterns: ["*"] - package-ecosystem: "pip" directory: "/" schedule: interval: "weekly" open-pull-requests-limit: 5 + groups: + python-deps: + patterns: ["*"] + update-types: ["minor", "patch"] diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2a5d306..011ffee 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,3 +1,6 @@ +# Third-party actions are pinned to commit SHAs (with version comments) for +# supply-chain safety. See python-app.yml for rationale. + name: CodeQL on: @@ -23,12 +26,12 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@0daab03d71ff584ef619d027a3fd9146679c5d84 # v3.35.3 with: languages: python - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@0daab03d71ff584ef619d027a3fd9146679c5d84 # v3.35.3 with: category: "/language:python" diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 1d0851e..3812e23 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -1,3 +1,6 @@ +# Third-party actions are pinned to commit SHAs (with version comments) for +# supply-chain safety. See python-app.yml for rationale. + name: pre-commit on: @@ -18,9 +21,9 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.12" cache: "pip" - - uses: pre-commit/action@v3.0.1 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index e0b906d..9e3234e 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -1,5 +1,9 @@ # This workflow will install Python dependencies, run tests and lint with a single version of Python # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions +# +# Third-party actions are pinned to commit SHAs (with version comments) for +# supply-chain safety. Dependabot's `github-actions` ecosystem keeps both the +# SHA and the comment in sync. name: Python application @@ -26,9 +30,9 @@ jobs: python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ matrix.python-version }} cache: "pip" @@ -40,7 +44,7 @@ jobs: run: pytest --cov --cov-report=xml - name: Upload coverage report if: matrix.python-version == '3.12' - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4 with: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: false diff --git a/.gitignore b/.gitignore index 82f9275..2907992 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,9 @@ instance/ # Sphinx documentation docs/_build/ +# Generated by sphinx-apidoc; regenerated on each docs build. +docs/modules.rst +docs/my_package*.rst # PyBuilder .pybuilder/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 07f1e0d..532779d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,7 @@ --- fail_fast: false +default_language_version: + python: python3.12 repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 @@ -14,7 +16,7 @@ repos: - id: debug-statements - id: requirements-txt-fixer - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.9 + rev: v0.15.12 hooks: - id: ruff args: [--fix] diff --git a/.readthedocs.yml b/.readthedocs.yml index b348af5..286c9b5 100755 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -13,6 +13,11 @@ build: # nodejs: "20" # rust: "1.70" # golang: "1.20" + jobs: + pre_build: + # Generate API reference pages so the `modules` toctree in + # docs/index.rst resolves on Read the Docs (mirrors make_docs.sh). + - sphinx-apidoc -o docs/ my_package/ # Build documentation in the "docs/" directory with Sphinx sphinx: diff --git a/CITATION.cff b/CITATION.cff index 965aeee..b462f01 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,10 +1,12 @@ -cff-version: 1.2.0 -message: "Please cite this repository as indicated below." -authors: - - family-names: Mahynski - given-names: Nathan - orcid: https://orcid.org/0000-0002-0008-8749 -title: "my_package" -version: v0.0.0 -doi: 10.1234/zenodo.12345678 -date-released: YYYY-MM-DD +cff-version: 1.2.0 +message: "Please cite this repository as indicated below." +authors: + - family-names: Mahynski + given-names: Nathan + orcid: https://orcid.org/0000-0002-0008-8749 +title: "my_package" +version: 0.0.0 +# Populate `doi` and `date-released` once Zenodo mints a DOI for the first +# release. Until then, leave them absent so cff-convert validation passes. +# doi: 10.5281/zenodo.XXXXXXX +# date-released: 2026-01-01 diff --git a/README.md b/README.md index 4469224..3c33164 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,10 @@ [![codecov](https://codecov.io/gh/mahynski/my_package/branch/main/graph/badge.svg?token=YSLBQ33C7F)](https://codecov.io/gh/mahynski/my_package) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) + + PyPI Package Template Instructions === diff --git a/docs/Makefile.txt b/docs/Makefile similarity index 100% rename from docs/Makefile.txt rename to docs/Makefile diff --git a/docs/conf.py b/docs/conf.py index 04741a7..3585953 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -39,7 +39,9 @@ # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output -html_logo = "_static/logo.png" # SPECIFY YOUR LOGO LINK HERE +# `_static/logo.png` is used by the Sphinx theme; `_static/logo_transparent.png` +# is what README.md embeds. Keep both in sync (or trim to one) when replacing. +html_logo = "_static/logo.png" html_context = { "display_github": True, # Integrate GitHub "github_user": "mahynski", # Username @@ -50,7 +52,8 @@ html_theme = "sphinx_book_theme" #'sphinx_rtd_theme' html_static_path = ["_static"] pygments_style = "sphinx" -nbsphinx_execute = "never" # Notebooks must be pre-executed locally; RTD just renders the saved output. +# Notebooks must be pre-executed locally; RTD just renders saved output. +nbsphinx_execute = "never" # Examples for setting thumbnails for jupyter notebook tiles # nbsphinx_kernel_name = 'my_package-kernel' # nbsphinx_thumbnails = { diff --git a/docs/index.rst b/docs/index.rst index a5a84d3..73d3dbb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,8 +17,10 @@ documentation for details. :target: https://codecov.io/gh/mahynski/my_package .. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white :target: https://github.com/pre-commit/pre-commit -.. image:: https://zenodo.org/badge/331207062.svg - :target: https://zenodo.org/badge/latestdoi/331207062 +.. + Uncomment after Zenodo mints a DOI for this repo and replace the badge ID. + .. image:: https://zenodo.org/badge/331207062.svg + :target: https://zenodo.org/badge/latestdoi/331207062 ---- diff --git a/docs/make_docs.sh b/docs/make_docs.sh index c356875..275131b 100644 --- a/docs/make_docs.sh +++ b/docs/make_docs.sh @@ -1,8 +1,12 @@ -#!/bin/bash -sphinx-apidoc -o ./ ../my_package/; -make clean html; -make html; +#!/usr/bin/env bash +# Build the Sphinx HTML docs locally. Mirrors the RTD pre_build / build flow. +set -euo pipefail -# Run these commands the first time to set up -# pip install pip-tools -# pip-compile requirements.in +# Generate API reference pages from my_package/. Output goes alongside conf.py +# in docs/, where they're picked up by the `modules` toctree in index.rst. +sphinx-apidoc -o ./ ../my_package/ + +# Clean and rebuild HTML. Equivalent to `make clean html` but doesn't depend +# on the Makefile being named correctly. +rm -rf _build/html _build/doctrees +sphinx-build -b html -d _build/doctrees . _build/html diff --git a/pyproject.toml b/pyproject.toml index ccd8d45..a045abc 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,6 +71,32 @@ testpaths = [ "tests", ] +[tool.coverage.run] +source = ["my_package"] +branch = true + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "raise NotImplementedError", + "if TYPE_CHECKING:", + "if __name__ == .__main__.:", +] + +[tool.ruff] +line-length = 100 +target-version = "py310" + +[tool.ruff.lint] +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # pyflakes + "I", # isort + "B", # flake8-bugbear + "UP", # pyupgrade +] + [tool.setuptools.packages.find] where = ["."] include = ["my_package*"] diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 5eefcbd..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -""" -Unittests - -Author: Nathan A. Mahynski -"""