From a4adde77ca9ae50054bfb4407a850cde1a59e89f Mon Sep 17 00:00:00 2001 From: Matthew Carroll <28577806+MJC598@users.noreply.github.com> Date: Wed, 18 Mar 2026 16:03:41 -0400 Subject: [PATCH 1/4] Adding the buildwheel workflow --- .github/workflows/buildwheels.yml | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/buildwheels.yml diff --git a/.github/workflows/buildwheels.yml b/.github/workflows/buildwheels.yml new file mode 100644 index 0000000..07c8f1b --- /dev/null +++ b/.github/workflows/buildwheels.yml @@ -0,0 +1,48 @@ +name: Build Wheels + +on: + push: + tags: + - "v*.*.*" + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + # macos-15-intel is an Intel runner, macos-14 is Apple silicon + os: + [ + ubuntu-latest, + ubuntu-24.04-arm, + windows-latest, + windows-11-arm, + macos-15-intel, + macos-14, + ] + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + version: "0.10.11" + + - name: Build wheels + uses: pypa/cibuildwheel@v3.4.0 + # env: + # CIBW_BUILD_FRONTEND: value + # ... + # with: + # package-dir: . + # output-dir: wheelhouse + # config-file: "{package}/pyproject.toml" + + - uses: actions/upload-artifact@v4 + with: + name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} + path: ./wheelhouse/*.whl From fc8533cc9554d23d018b955c2c3f725e739b4b2e Mon Sep 17 00:00:00 2001 From: Matthew Carroll <28577806+MJC598@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:19:45 -0400 Subject: [PATCH 2/4] Adding badges and nox/pylint checks --- .github/workflows/nox-pylint.yml | 34 ++++++++++ .github/workflows/tests.yml | 34 ++++++++++ README.md | 5 ++ noxfile.py | 23 +++++++ pyproject.toml | 1 + uv.lock | 111 +++++++++++++++++++++++++++++++ 6 files changed, 208 insertions(+) create mode 100644 .github/workflows/nox-pylint.yml create mode 100644 .github/workflows/tests.yml create mode 100644 noxfile.py diff --git a/.github/workflows/nox-pylint.yml b/.github/workflows/nox-pylint.yml new file mode 100644 index 0000000..a464eac --- /dev/null +++ b/.github/workflows/nox-pylint.yml @@ -0,0 +1,34 @@ +name: Nox Pylint + +on: + push: + branches: + - main + - feature/** + pull_request: + branches: + - main + +jobs: + pylint: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + version: "0.10.11" + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Install dependencies + run: uv sync --group github + + - name: Run pylint session + run: uv run nox -s pylint diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..c568001 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,34 @@ +name: Tests + +on: + push: + branches: + - main + - feature/** + pull_request: + branches: + - main + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + version: "0.10.11" + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Install dependencies + run: uv sync --group github + + - name: Run tests + run: uv run pytest --benchmark-disable tests diff --git a/README.md b/README.md index eabba76..ecd607e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # RESPONDPY +[![Coverage](https://codecov.io/gh/SyndemicsLab/respondpy/branch/main/graph/badge.svg)](https://app.codecov.io/gh/SyndemicsLab/respondpy) +[![Tests](https://github.com/SyndemicsLab/respondpy/actions/workflows/tests.yml/badge.svg)](https://github.com/SyndemicsLab/respondpy/actions/workflows/tests.yml) +[![Nox Pylint](https://github.com/SyndemicsLab/respondpy/actions/workflows/nox-pylint.yml/badge.svg)](https://github.com/SyndemicsLab/respondpy/actions/workflows/nox-pylint.yml) +[![PyPI Deploy](https://github.com/SyndemicsLab/respondpy/actions/workflows/buildwheels.yml/badge.svg)](https://github.com/SyndemicsLab/respondpy/actions/workflows/buildwheels.yml) + :snake: Welcome to RESPOND for Python! :snake: This repository acts as a set of python bindings for the Syndemics Lab's RESPOND model. As such, it is simply a set of wrappers and helper functions for ease of use in various lab projects. Our project can be installed from PyPI or built locally. ## RESPOND diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 0000000..eff8540 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,23 @@ +################################################################################ +# File: noxfile.py # +# Project: respondpy # +# Created Date: 2026-04-08 # +# Author: Matthew Carroll # +# ----- # +# Last Modified: 2026-04-08 # +# Modified By: Matthew Carroll # +# ----- # +# Copyright (c) 2026 Syndemics Lab at Boston Medical Center # +################################################################################ + +from __future__ import annotations + +import nox # type: ignore[import-not-found] # pylint: disable=import-error + + +@nox.session(python=["3.12"], venv_backend="uv") +def pylint(session: nox.Session) -> None: + """Run pylint checks for source code only.""" + session.env["PYTHONPATH"] = "src" + session.install("pylint", "numpy", "polars") + session.run("pylint", "src/respondpy") diff --git a/pyproject.toml b/pyproject.toml index fa022dc..c29cbdb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,7 @@ keywords = ["simulation", "Opioid Use Disorder", "Syndemics"] license = "AGPL-3.0-or-later" license-files = ["LICENSE.txt"] dependencies = [ + "nox>=2026.2.9", "numpy", "polars>=1.37.1", "pytest-cov>=7.0.0", diff --git a/uv.lock b/uv.lock index d7ddd0c..4023278 100644 --- a/uv.lock +++ b/uv.lock @@ -36,6 +36,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, ] +[[package]] +name = "argcomplete" +version = "3.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" }, +] + [[package]] name = "asttokens" version = "3.0.1" @@ -303,6 +312,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "colorlog" +version = "6.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, +] + [[package]] name = "comm" version = "0.2.3" @@ -463,6 +484,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, ] +[[package]] +name = "dependency-groups" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/55/f054de99871e7beb81935dea8a10b90cd5ce42122b1c3081d5282fdb3621/dependency_groups-1.3.1.tar.gz", hash = "sha256:78078301090517fd938c19f64a53ce98c32834dfe0dee6b88004a569a6adfefd", size = 10093, upload-time = "2025-05-02T00:34:29.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/c7/d1ec24fb280caa5a79b6b950db565dab30210a66259d17d5bb2b3a9f878d/dependency_groups-1.3.1-py3-none-any.whl", hash = "sha256:51aeaa0dfad72430fcfb7bcdbefbd75f3792e5919563077f30bc0d73f4493030", size = 8664, upload-time = "2025-05-02T00:34:27.085Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + [[package]] name = "docutils" version = "0.21.2" @@ -511,6 +554,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, ] +[[package]] +name = "filelock" +version = "3.25.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/b8/00651a0f559862f3bb7d6f7477b192afe3f583cc5e26403b44e59a55ab34/filelock-3.25.2.tar.gz", hash = "sha256:b64ece2b38f4ca29dd3e810287aa8c48182bbecd1ae6e9ae126c9b35f1382694", size = 40480, upload-time = "2026-03-11T20:45:38.487Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl", hash = "sha256:ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70", size = 26759, upload-time = "2026-03-11T20:45:37.437Z" }, +] + +[[package]] +name = "humanize" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/66/a3921783d54be8a6870ac4ccffcd15c4dc0dd7fcce51c6d63b8c63935276/humanize-4.15.0.tar.gz", hash = "sha256:1dd098483eb1c7ee8e32eb2e99ad1910baefa4b75c3aff3a82f4d78688993b10", size = 83599, upload-time = "2025-12-20T20:16:13.19Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/7b/bca5613a0c3b542420cf92bd5e5fb8ebd5435ce1011a091f66bb7693285e/humanize-4.15.0-py3-none-any.whl", hash = "sha256:b1186eb9f5a9749cd9cb8565aee77919dd7c8d076161cf44d70e59e3301e1769", size = 132203, upload-time = "2025-12-20T20:16:11.67Z" }, +] + [[package]] name = "hypothesis" version = "6.150.0" @@ -969,6 +1030,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, ] +[[package]] +name = "nox" +version = "2026.2.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "attrs" }, + { name = "colorlog" }, + { name = "dependency-groups" }, + { name = "humanize" }, + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6e/8e/55a9679b31f1efc48facedd2448eb53c7f1e647fb592aa1403c9dd7a4590/nox-2026.2.9.tar.gz", hash = "sha256:1bc8a202ee8cd69be7aaada63b2a7019126899a06fc930a7aee75585bf8ee41b", size = 4031165, upload-time = "2026-02-10T04:38:58.878Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/58/0d5e5a044f1868bdc45f38afdc2d90ff9867ce398b4e8fa9e666bfc9bfba/nox-2026.2.9-py3-none-any.whl", hash = "sha256:1b7143bc8ecdf25f2353201326152c5303ae4ae56ca097b1fb6179ad75164c47", size = 74615, upload-time = "2026-02-10T04:38:57.266Z" }, +] + [[package]] name = "numpy" version = "2.2.6" @@ -1399,6 +1479,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-discovery" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", size = 58872, upload-time = "2026-04-07T17:28:49.249Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", size = 31894, upload-time = "2026-04-07T17:28:48.09Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" @@ -1570,6 +1663,7 @@ name = "respondpy" version = "0.1.2" source = { editable = "." } dependencies = [ + { name = "nox" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "polars" }, @@ -1628,6 +1722,7 @@ test = [ [package.metadata] requires-dist = [ + { name = "nox", specifier = ">=2026.2.9" }, { name = "numpy" }, { name = "polars", specifier = ">=1.37.1" }, { name = "pytest-cov", specifier = ">=7.0.0" }, @@ -2186,6 +2281,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] +[[package]] +name = "virtualenv" +version = "21.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "python-discovery" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/92/58199fe10049f9703c2666e809c4f686c54ef0a68b0f6afccf518c0b1eb9/virtualenv-21.2.0.tar.gz", hash = "sha256:1720dc3a62ef5b443092e3f499228599045d7fea4c79199770499df8becf9098", size = 5840618, upload-time = "2026-03-09T17:24:38.013Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/59/7d02447a55b2e55755011a647479041bc92a82e143f96a8195cb33bd0a1c/virtualenv-21.2.0-py3-none-any.whl", hash = "sha256:1bd755b504931164a5a496d217c014d098426cddc79363ad66ac78125f9d908f", size = 5825084, upload-time = "2026-03-09T17:24:35.378Z" }, +] + [[package]] name = "wcwidth" version = "0.2.14" From ed68e1c8540f79e79db6ce8d8b7fe1cc04dc9433 Mon Sep 17 00:00:00 2001 From: Matthew Carroll <28577806+MJC598@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:31:46 -0400 Subject: [PATCH 3/4] Updating the buildwheels workflow for the attestations --- .github/workflows/buildwheels.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/buildwheels.yml b/.github/workflows/buildwheels.yml index 07c8f1b..bf65c9c 100644 --- a/.github/workflows/buildwheels.yml +++ b/.github/workflows/buildwheels.yml @@ -46,3 +46,24 @@ jobs: with: name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} path: ./wheelhouse/*.whl + + publish: + name: Publish to PyPI + needs: build_wheels + runs-on: ubuntu-latest + permissions: + id-token: write + + steps: + - name: Download wheel artifacts + uses: actions/download-artifact@v5 + with: + path: dist + pattern: cibw-wheels-* + merge-multiple: true + + - name: Publish distributions to PyPI with attestations + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist + attestations: true From d54ada481fe099bf71fdaf7a6a32e6eb5b20bc33 Mon Sep 17 00:00:00 2001 From: Matthew Carroll <28577806+MJC598@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:36:53 -0400 Subject: [PATCH 4/4] adding the fix to push a code coverage report to codecov --- .github/workflows/tests.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c568001..acd2126 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,4 +31,10 @@ jobs: run: uv sync --group github - name: Run tests - run: uv run pytest --benchmark-disable tests + run: uv run pytest --benchmark-disable --cov=respondpy --cov-report=term-missing --cov-report=xml tests + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + files: ./coverage.xml + fail_ci_if_error: false