diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..c43490a
--- /dev/null
+++ b/.github/CODE_OF_CONDUCT.md
@@ -0,0 +1,128 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+ overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+jgpauloski@uchicago.edu.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..9370017
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,46 @@
+# Contributing Guide
+Welcome! We appreciate your interest in contributing.
+
+## Issues
+
+Report bugs using GitHub's Issue Tracker.
+A useful bug report has detail, background, and sample code.
+For example, try to include:
+
+- A quick summary and/or background.
+- Steps to reproduce:
+ - Be specific!
+ - Give sample code if you can.
+- What you expected would happen.
+- What actually happens.
+- Any additional information that could help us.
+ - Why you think this might be happening.
+ - Things you tried that didn't work.
+ - Etc.
+
+## Pull Requests
+
+We use the [Github Flow](https://docs.github.com/en/get-started/quickstart/github-flow), so all changes happen through pull requests.
+
+For small bugs, feel free to open a pull request directly.
+For larger bugs or enhancements, please open an issue first
+Having an associated issue makes it easier to track changes and discuss proposals before you get started.
+
+1. Fork the repo and create a new branch from `main`.
+ - We suggest naming your branch `issue-##` if your pull request is addressing an open issue.
+2. Make your changes.
+ - If you've added code that should be tested, add tests.
+ - If you've changed APIs, update the documentation.
+3. Ensure the test suite passes and your code lints.
+4. Open the pull request!
+
+## Coding Style
+Be consistent with the coding style of the repository you are contributing to.
+Our projects generally have strict code formatters and linters which can fix basic style issues for you.
+
+## License
+Any contributions you make will be under the MIT Software License
+Feel free to contact the maintainers if that's a concern.
+
+## References
+This document was adapted from an [adaptation](https://gist.github.com/briandk/3d2e8b3ec8daf5a27a62) of the open-source contribution guidelines for [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md).
diff --git a/.github/ISSUE_TEMPLATE/01_bug.yml b/.github/ISSUE_TEMPLATE/01_bug.yml
new file mode 100644
index 0000000..3dae025
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/01_bug.yml
@@ -0,0 +1,42 @@
+name: Bug Report
+description: Report errors or unexpected results.
+labels: ["bug"]
+assignees:
+ - foobar-bug-assign-dev
+body:
+ - type: textarea
+ id: install
+ attributes:
+ label: How did you install foobar?
+ description: >
+ E.g., install via pip, install from source, etc. **Note:** this will
+ be rendered as console text automatically.
+ placeholder: |
+ $ pip install foobar
+ Collecting foobar
+ ...
+ Successfully installed foobar...
+ render: console
+ validations:
+ required: true
+
+ - type: input
+ id: version
+ attributes:
+ label: What version of foobar are you using?
+ description: >
+ Package version if installed via Pip or commit ID if installed
+ from source.
+ placeholder: v1.2.3
+ validations:
+ required: true
+
+ - type: textarea
+ id: freeform
+ attributes:
+ label: Describe the problem.
+ description: >
+ Please provide sample code and directions for reproducing
+ your problem and what you expected to happen.
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/02_enhancement.yml b/.github/ISSUE_TEMPLATE/02_enhancement.yml
new file mode 100644
index 0000000..b324e5b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/02_enhancement.yml
@@ -0,0 +1,38 @@
+name: Enhancement Request
+description: Request a new feature or enhancement.
+labels: ["enhancement"]
+assignees:
+ - foobar-enh-assign-dev
+body:
+ - type: textarea
+ id: request
+ attributes:
+ label: Describe the Request
+ description: >
+ Please describe your use case and why the current feature set does
+ not satisfy your needs.
+ validations:
+ required: true
+
+ - type: textarea
+ id: example
+ attributes:
+ label: Sample Code
+ description: >
+ If relevant, please provide sample code such as the proposed
+ interface, usage, or results. **Note:** this will be rendered as
+ Python code automatically.
+ render: python
+ validations:
+ required: false
+
+ - type: textarea
+ id: additional
+ attributes:
+ label: Additional Code or Information
+ description: >
+ Optional space for additional code or text. **Note:** this will
+ be rendered as console text automatically.
+ render: console
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/03_docs.yml b/.github/ISSUE_TEMPLATE/03_docs.yml
new file mode 100644
index 0000000..e6d1d82
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/03_docs.yml
@@ -0,0 +1,15 @@
+name: Documentation Improvements
+description: Suggest improvements to the documentation.
+labels: ["documentation"]
+assignees:
+ - foobar-doc-assignee-dev
+body:
+ - type: textarea
+ id: freeform
+ attributes:
+ label: Describe the Request
+ description: >
+ Please describe limitations of the current documentation or
+ suggested improvements.
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..0086358
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1 @@
+blank_issues_enabled: true
diff --git a/.github/SECURITY.md b/.github/SECURITY.md
new file mode 100644
index 0000000..15946f0
--- /dev/null
+++ b/.github/SECURITY.md
@@ -0,0 +1,14 @@
+# Security Policy
+
+## Supported Versions
+
+We currently only support the latest versions of the software with security
+updates. I.e., we will not backport new security updates to old versions.
+
+## Reporting a Vulnerability
+
+If you believe you have found a security vulnerability in the repository, we
+encourage you to let us know right away. We will investigate all legitimate
+reports and do our best to quickly fix the problem.
+
+Please report security issues to the Issue Tracker or Security Advisories.
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..b608ffc
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,8 @@
+version: 2
+
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ # Check for updates to GitHub Actions every week
+ interval: "weekly"
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..ee1bae0
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,34 @@
+# Description
+
+
+
+### Fixes
+
+
+- Fixes #XX
+- Fixes #XX
+
+### Type of Change
+
+
+- [ ] Bug fix (non-breaking change which fixes an issue)
+- [ ] New feature (non-breaking change which adds functionality)
+- [ ] Refactoring (internal implementation changes)
+- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
+- [ ] Documentation update (no changes to the code)
+- [ ] CI change (changes to CI workflows, packages, templates, etc.)
+- [ ] Version changes (changes to the package or dependency versions)
+
+## Testing
+
+
+N/A
+
+## Pull Request Checklist
+
+Please confirm the PR meets the following requirements.
+- [ ] Relevant tags are added (breaking, bug, dependencies, documentation, enhancement, refactor).
+- [ ] Code changes pass `pre-commit` (e.g., ruff, mypy, etc.).
+- [ ] Tests have been added to show the fix is effective or that the new feature works.
+- [ ] New and existing unit tests pass locally with the changes.
+- [ ] Docs have been updated and reviewed if relevant.
diff --git a/.github/release.yml b/.github/release.yml
new file mode 100644
index 0000000..c783b72
--- /dev/null
+++ b/.github/release.yml
@@ -0,0 +1,45 @@
+changelog:
+ exclude:
+ labels:
+ - ignore-for-release
+ authors:
+ - pre-commit-ci
+ categories:
+ # Provide steps for upgrading the package and adjusting for
+ # breaking changes. No PRs included here.
+ - title: Upgrade Steps
+ exclude:
+ labels:
+ - "*"
+ # All PRs tagged as "breaking"
+ - title: Breaking Changes
+ labels:
+ - breaking
+ # All PRs tagged as "enhancement"
+ - title: New Features
+ labels:
+ - enhancement
+ # All PRs tagged as "bug"
+ - title: Bug Fixes
+ labels:
+ - bug
+ # All PRs not tagged as the above or below
+ - title: Improvements
+ labels:
+ - refactor
+ exclude:
+ labels:
+ - dependencies
+ - documentation
+ # All PRs tagged as documentation
+ - title: Improvements
+ labels:
+ - documentation
+ # All PRs tagged "dependencies"
+ - title: Dependencies
+ labels:
+ - dependencies
+ # All PRs not tagged as the above
+ - title: Other Changes
+ labels:
+ - "*"
diff --git a/.github/workflows/cache.yml b/.github/workflows/cache.yml
new file mode 100644
index 0000000..4179718
--- /dev/null
+++ b/.github/workflows/cache.yml
@@ -0,0 +1,34 @@
+# Clean up GitHub Actions caches for closed pull requests.
+# Source: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
+name: cache-cleanup
+
+on:
+ pull_request:
+ types:
+ - closed
+
+jobs:
+ cleanup:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v4
+
+ - name: Cleanup
+ run: |
+ gh extension install actions/gh-actions-cache
+ REPO=${{ github.repository }}
+ BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge"
+ echo "Fetching list of cache key"
+ cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 )
+ ## Setting this to not fail the workflow while deleting cache keys.
+ set +e
+ echo "Deleting caches..."
+ for cacheKey in $cacheKeysForPR
+ do
+ echo "Deleting $REPO $BRANCH $cacheKey"
+ gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
+ done
+ echo "Done"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/check-docs.yml b/.github/workflows/check-docs.yml
new file mode 100644
index 0000000..231f7ab
--- /dev/null
+++ b/.github/workflows/check-docs.yml
@@ -0,0 +1,45 @@
+# This workflow just verifies that the docs build without any
+# warnings (as configured in the tox recipe). This is only run on
+# the test-me-* branches and PRs as pushes to main will trigger the docs
+# workflow.
+name: check-docs
+
+on:
+ push:
+ branches: [test-me-*]
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ check-docs:
+ timeout-minutes: 10
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Python 3.11
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+
+ - name: Get pip cache dir
+ id: pip-cache-dir
+ run: echo "PIP_CACHE_DIR=$(pip cache dir)" >> $GITHUB_ENV
+
+ - name: Use pip cache
+ id: pip-cache
+ uses: actions/cache@v4
+ with:
+ path: ${{ env.PIP_CACHE_DIR }}
+ key: docs-ubuntu-latest-pip-3.11-${{ hashFiles('pyproject.toml') }}
+ restore-keys: |
+ docs-ubuntu-latest-pip-3.11-
+
+ - name: Install Packages
+ run: pip install --upgrade setuptools pip tox virtualenv
+
+ - name: Run Tox to build docs
+ run: tox -e docs
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 0000000..dc7614d
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,49 @@
+name: docs
+
+on:
+ push:
+ branches: [main]
+ workflow_dispatch:
+
+jobs:
+ docs:
+ timeout-minutes: 10
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Set up Python 3.11
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+
+ - name: Get pip cache dir
+ id: pip-cache-dir
+ run: echo "PIP_CACHE_DIR=$(pip cache dir)" >> $GITHUB_ENV
+
+ - name: Use pip cache
+ id: pip-cache
+ uses: actions/cache@v4
+ with:
+ path: ${{ env.PIP_CACHE_DIR }}
+ key: docs-ubuntu-latest-pip-3.11-${{ hashFiles('pyproject.toml') }}
+ restore-keys: |
+ docs-ubuntu-latest-pip-3.11-
+
+ - name: Install Packages
+ run: |
+ pip install --upgrade setuptools pip
+ pip install .[docs]
+
+ - name: Configure git
+ run: |
+ git config --local user.name "GitHub Actions Bot"
+ git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ - name: Deploy docs for main:latest to gh-pages branch
+ run: |
+ mike deploy --push --update-aliases main
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..164e5d3
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,62 @@
+name: publish
+
+on:
+ release:
+ types: [published]
+ workflow_dispatch:
+
+permissions:
+ contents: write
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Extract package version from pyproject.toml
+ run: |
+ echo "PACKAGE_VERSION=$(grep -Po '^version\s*=\s*\"\K.*?(?=\")' pyproject.toml)" >> $GITHUB_ENV
+ echo "Found version in pyproject.toml: ${{ env.PACKAGE_VERSION }}"
+
+ - name: Check package version is PEP440 compliant
+ # This is only a partial PEP440 match, it just checks the major, minor
+ # patch, but not any optional suffixes.
+ run: echo "${{ env.PACKAGE_VERSION }}" | grep -P "^\d+\.\d+\.\d+.*$"
+
+ - name: Check version matches release tag
+ run: |
+ if [ "${{ format('v{0}', env.PACKAGE_VERSION) }}" != "${{ github.event.release.tag_name }}" ]
+ then
+ echo "v\$\{PACKAGE_VERSION\} = v${{ env.PACKAGE_VERSION }} does not match tag name: ${{ github.event.release.tag_name }}"
+ exit 1
+ fi
+
+ - name: Setup Python 3.11
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+
+ - name: Install pypa/build and build
+ run: |
+ pip install build
+ python -m build --sdist --wheel --outdir dist/ .
+
+ - name: Publish to PyPI
+ if: startsWith(github.ref, 'refs/tags')
+ uses: pypa/gh-action-pypi-publish@release/v1
+ with:
+ password: ${{ secrets.PYPI_TOKEN }}
+
+ - name: Configure git
+ run: |
+ git config --local user.name "GitHub Actions Bot"
+ git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ - name: Deploy docs for release version to gh-pages branch
+ if: startsWith(github.ref, 'refs/tags/')
+ run: |
+ pip install .[docs]
+ mike deploy --push --update-aliases "${{ env.PACKAGE_VERSION }}" latest
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..5a3b131
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,60 @@
+name: tests
+
+on:
+ push:
+ branches: [main, test-me-*]
+ tags:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ tests:
+ timeout-minutes: 10
+
+ strategy:
+ matrix:
+ include:
+ - os: ubuntu-latest
+ python: 3.8
+ toxenv: py38
+ - os: ubuntu-latest
+ python: 3.9
+ toxenv: py39
+ - os: ubuntu-latest
+ python: '3.10'
+ toxenv: py310
+ - os: ubuntu-latest
+ python: '3.11'
+ toxenv: py311
+ - os: ubuntu-latest
+ python: '3.12'
+ toxenv: py312
+ runs-on: ${{ matrix.os }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Python ${{matrix.python}}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python }}
+
+ - name: Get pip cache dir
+ id: pip-cache-dir
+ run: echo "PIP_CACHE_DIR=$(pip cache dir)" >> $GITHUB_ENV
+
+ - name: Use pip cache
+ id: pip-cache
+ uses: actions/cache@v4
+ with:
+ path: ${{ env.PIP_CACHE_DIR }}
+ key: tests-${{ matrix.os }}-pip-${{ matrix.python }}-${{ hashFiles('pyproject.toml') }}
+ restore-keys: |
+ tests-${{ matrix.os }}-pip-${{ matrix.python }}-
+
+ - name: Install Packages
+ run: python -mpip install --upgrade pip tox
+
+ - name: Run Tox
+ run: tox -e ${{ matrix.toxenv }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b6e4761
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,129 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..239bf63
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,31 @@
+ci:
+ autofix_prs: false
+repos:
+ - repo: 'https://github.com/pre-commit/pre-commit-hooks'
+ rev: v4.5.0
+ hooks:
+ - id: mixed-line-ending
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-added-large-files
+ - id: check-docstring-first
+ - id: check-json
+ - id: check-yaml
+ - id: check-merge-conflict
+ - id: name-tests-test
+ - repo: 'https://github.com/codespell-project/codespell'
+ rev: v2.2.6
+ hooks:
+ - id: codespell
+ - repo: 'https://github.com/charliermarsh/ruff-pre-commit'
+ rev: v0.2.2
+ hooks:
+ - id: ruff
+ args:
+ - '--fix'
+ - id: ruff-format
+ - repo: 'https://github.com/pre-commit/mirrors-mypy'
+ rev: v1.8.0
+ hooks:
+ - id: mypy
+ additional_dependencies: []
diff --git a/CITATION.cff b/CITATION.cff
new file mode 100644
index 0000000..7a0f4a2
--- /dev/null
+++ b/CITATION.cff
@@ -0,0 +1,10 @@
+cff-version: 1.2.0
+message: If you use this software, please cite it as below.
+authors:
+ - family-names: Pauloski
+ given-names: Greg
+ orcid: https://orcid.org/0000-0002-6547-6902
+license: MIT
+repository-code: https://github.com/foobar-author/foobar
+title: FooBar
+url: https://foobar.dev
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7b7753f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2023-Present FooBar Author
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a101020
--- /dev/null
+++ b/README.md
@@ -0,0 +1,67 @@
+# Python Package Template Repo
+
+[![docs](https://github.com/gpauloski/python-template/actions/workflows/docs.yml/badge.svg)](https://github.com/gpauloski/python-template/actions)
+[![tests](https://github.com/gpauloski/python-template/actions/workflows/tests.yml/badge.svg)](https://github.com/gpauloski/python-template/actions)
+[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/gpauloski/python-template/main.svg)](https://results.pre-commit.ci/latest/github/gpauloski/python-template/main)
+
+Python package template repo that provides:
+- Package, examples, and testing layout.
+- GitHub PR and Issue templates.
+- Example docs with MKDocs and GitHub Pages.
+- CI framework with `pre-commit` and `tox`.
+- GitHub actions for running tests and publishing packages.
+
+This package setup was based on [Anthony Sottile's project setup](https://www.youtube.com/watch?v=q8DkatMZvUs&list=PLWBKAf81pmOaP9naRiNAqug6EBnkPakvY) but deviates in some places (e.g., `pyproject.toml` and `ruff`).
+
+## Setup Instructions
+
+1. Click the "Use this template" button at the top right of this page.
+2. Delete and directories you will not be using (commonly `docs/` if you do not want to use MKDocs or `examples/` if you will not have example code).
+3. Follow the instructions to create the new repo then clone your repo locally.
+4. The template uses "foobar" to indicate things that need to be changed.
+ Start by searching for all instances (`git grep foobar`) and changing them accordingly.
+5. Configure pre-commit:
+ - Go to [https://pre-commit.ci/](https://pre-commit.ci/) and enable pre-commit on your repo.
+ - Update the pre-commit badge URL in this README with your new badge URL.
+6. Configure GitHub pages:
+ - Go to the "Pages" section of your repository settings.
+ - Select "Deploy from a branch" and use the "gh-pages" branch.
+7. Configure PyPI releases (if relevant):
+ - Create a new API token for [https://pypi.org/](https://pypi.org/).
+ - Add the token as a GitHub actions secret (see the instructions [here](https://github.com/pypa/gh-action-pypi-publish)).
+8. Delete this boilerplate stuff in the README.
+9. Commit and push changes.
+
+### GitHub Configuration
+
+I recommend making a few other changes to the repo's setting on GitHub.
+- In "General"
+ - Select/deselect features you need/don't need.
+ - Select "Automatically delete head branches
+- In "Branches": enable branch protection on `main`.
+ - Check "Require a pull request before merging"
+ - Check "Require status checks to pass before merging"
+ - Check "Require branches to be up to date before merging"
+ - Set required checks (e.g., pre-commit.ci, tests, etc.)
+ - Check "Do not allow bypassing the above settings"
+
+## Installation
+
+Install via pip:
+```
+$ pip install foobar
+```
+
+For local development:
+```
+$ tox --devenv venv -e py310
+$ pre-commit install
+```
+or
+```
+$ pip install -e .
+```
+
+## Additional README Sections
+
+...
diff --git a/docs/_overrides/base.html b/docs/_overrides/base.html
new file mode 100644
index 0000000..0af326a
--- /dev/null
+++ b/docs/_overrides/base.html
@@ -0,0 +1,8 @@
+{% extends "base.html" %}
+
+{% block outdated %}
+ You're not viewing the latest version.
+
+ Click here to go to latest.
+
+{% endblock %}
diff --git a/docs/_templates/python/material/docstring/admonition.html b/docs/_templates/python/material/docstring/admonition.html
new file mode 100644
index 0000000..2105eab
--- /dev/null
+++ b/docs/_templates/python/material/docstring/admonition.html
@@ -0,0 +1,5 @@
+{{ log.debug("Rendering admonition") }}
+{{ section.title|convert_markdown(heading_level, html_id, strip_paragraph=True) }}
+ {{ section.value.contents|convert_markdown(heading_level, html_id) }}
+
{{ function.relative_filepath }}
{{ module_name }}
+ {% endif %}
+ {% endwith %}
+
+ {% with labels = module.labels %}
+ {% include "labels.html" with context %}
+ {% endwith %}
+
+ {% endfilter %}
+
+ {% else %}
+ {% if config.show_root_toc_entry %}
+ {% filter heading(heading_level,
+ role="module",
+ id=html_id,
+ toc_label=module.path if config.show_root_full_path else module.name,
+ hidden=True) %}
+ {% endfilter %}
+ {% endif %}
+ {% set heading_level = heading_level - 1 %}
+ {% endif %}
+
+ + Source file: {{ module.relative_package_filepath }} +
+ +