Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
14 changes: 11 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -8,22 +11,27 @@ 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
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"
17 changes: 14 additions & 3 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -6,13 +9,21 @@ 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
- 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
56 changes: 36 additions & 20 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
@@ -1,34 +1,50 @@
# 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

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@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
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@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand Down
26 changes: 14 additions & 12 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -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
4 changes: 3 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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]
Expand Down
24 changes: 12 additions & 12 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ 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
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:
Expand All @@ -31,13 +33,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
22 changes: 12 additions & 10 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -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
48 changes: 27 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,26 @@
[![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)
<!-- Uncomment after Zenodo mints a DOI for this repo and replace {github_id}.
[![DOI](https://zenodo.org/badge/{github_id}.svg)](https://zenodo.org/badge/latestdoi/{github_id})
-->


PyPI Package Template Instructions
===

<img src="docs/_static/logo_transparent.png" align="right" width=200 />

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.
Expand All @@ -26,12 +32,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
===
Expand All @@ -45,37 +54,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/`.

Expand Down
File renamed without changes.
Loading
Loading