From 8170bf11ac2c90b3dcaa8980da905640394be8c4 Mon Sep 17 00:00:00 2001 From: Kori Kuzma Date: Tue, 27 Oct 2026 13:24:03 -0400 Subject: [PATCH 1/3] build!: require python >=3.11,<3.15 close #477 * Excluding 3.15 for now until dill compatibility is fixed * Also update dev python version from 3.12 to 3.14 --- .binder/postBuild | 4 ++-- .binder/runtime.txt | 2 +- .devcontainer/devcontainer.json | 2 +- .github/workflows/python-cqa.yml | 2 +- CLAUDE.md | 8 ++++---- Makefile | 2 +- README.md | 14 +++++++------- notebooks/getting_started/README.md | 8 ++++---- pyproject.toml | 4 ++-- src/ga4gh/core/models.py | 4 ++-- 10 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.binder/postBuild b/.binder/postBuild index 2941be16..865dcd52 100644 --- a/.binder/postBuild +++ b/.binder/postBuild @@ -2,5 +2,5 @@ set -e make devready -source venv/3.12/bin/activate -python -m ipykernel install --user --name=3.12 --display-name="VRS_kernel" +source venv/3.14/bin/activate +python -m ipykernel install --user --name=3.14 --display-name="VRS_kernel" diff --git a/.binder/runtime.txt b/.binder/runtime.txt index d2aca3a7..2278a662 100644 --- a/.binder/runtime.txt +++ b/.binder/runtime.txt @@ -1 +1 @@ -python-3.12 +python-3.14 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 27e423ce..ff4cf435 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "VRS-Python Notebooks", - "image": "mcr.microsoft.com/vscode/devcontainers/python:3.12", + "image": "mcr.microsoft.com/vscode/devcontainers/python:3.14", "customizations": { "vscode": { "extensions": [ diff --git a/.github/workflows/python-cqa.yml b/.github/workflows/python-cqa.yml index 4bb45d92..7a13245d 100644 --- a/.github/workflows/python-cqa.yml +++ b/.github/workflows/python-cqa.yml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10", "3.11", "3.12", "3.13"] + python-version: ["3.11", "3.12", "3.13", "3.14"] env: SEQREPO_ROOT_DIR: ./tests/data/seqrepo/latest steps: diff --git a/CLAUDE.md b/CLAUDE.md index fec92bad..07fd78d4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,9 +9,9 @@ VRS-Python is the reference implementation of the GA4GH Variation Representation ## Development Commands ### Environment Setup -- `make devready` - Create Python 3.12 venv, install dev dependencies, setup pre-commit hooks -- `make nbready` - Create Python 3.12 venv, install notebook dependencies for Jupyter usage -- `source venv/3.12/bin/activate` - Activate the virtual environment (required before development) +- `make devready` - Create Python 3.14 venv, install dev dependencies, setup pre-commit hooks +- `make nbready` - Create Python 3.14 venv, install notebook dependencies for Jupyter usage +- `source venv/3.14/bin/activate` - Activate the virtual environment (required before development) ### Development Tasks - `make test` - Run pytest test suite @@ -51,7 +51,7 @@ VRS-Python is the reference implementation of the GA4GH Variation Representation ## Development Notes ### Dependencies -- Requires Python >= 3.10 (Python 3.12 required for development) +- Requires Python >= 3.11 (Python 3.14 required for development) - External services: SeqRepo (sequence data), UTA (transcript alignments) - Key libraries: Pydantic 2.x, bioutils, HGVS, requests diff --git a/Makefile b/Makefile index 607fd1ad..3631420d 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ else endif XRM=xargs -0${_XRM_R} rm -PYV:=3.12 +PYV:=3.14 VEDIR=venv/${PYV} export SEQREPO_ROOT_DIR=tests/data/seqrepo/latest diff --git a/README.md b/README.md index 9f86a581..4a7af41b 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,10 @@ All known issues are listed there. Please report any issues you find. ### Prerequisites -- Python >= 3.10 - - _Note: Python 3.12 is required for developers contributing to VRS-Python. The - Makefile sets up a virtual environment in `venv/3.12` and expects Python to be - available as `python3.12`._ +- Python >= 3.11 + - _Note: Python 3.14 is required for developers contributing to VRS-Python. The + Makefile sets up a virtual environment in `venv/3.14` and expects Python to be + available as `python3.14`._ - libpq - postgresql @@ -277,13 +277,13 @@ Then, clone your fork and initialize a development environment: git clone --recurse-submodules git@github.com:YOUR_GITHUB_ID/vrs-python.git cd vrs-python make devready -source venv/3.12/bin/activate +source venv/3.14/bin/activate ``` This setup includes [pre-commit hooks](https://pre-commit.com/). If you create a virtual environment manually, be sure to install the hooks yourself; otherwise, commits may fail during [CI/CD checks](https://github.com/ga4gh/vrs-python/actions/workflows/python-cqa.yml): ```shell -source venv/3.12/bin/activate +source venv/3.14/bin/activate pre-commit install ``` @@ -339,7 +339,7 @@ We have created a public [`VRS-demo-notebooks`](https://app.terra.bio/#workspace 1. Open VS Code. 2. Use Extensions view (Ctrl+Shift+X or ⌘+Shift+X) to install the [Jupyter extension](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter). 3. Navigate to your vrs-python project folder and open it in VS Code. -4. In a notebook, click `Select Kernel` at the top right. Select the option where the path is `venv/3.12/bin/python3`. See [here](https://code.visualstudio.com/docs/datascience/jupyter-kernel-management) for more information on managing Jupyter Kernels in VS Code. +4. In a notebook, click `Select Kernel` at the top right. Select the option where the path is `venv/3.14/bin/python3`. See [here](https://code.visualstudio.com/docs/datascience/jupyter-kernel-management) for more information on managing Jupyter Kernels in VS Code. 5. After selecting the kernel you can now run the notebook. ## Security Note (from the GA4GH Security Team) diff --git a/notebooks/getting_started/README.md b/notebooks/getting_started/README.md index 45176672..bc4bc798 100644 --- a/notebooks/getting_started/README.md +++ b/notebooks/getting_started/README.md @@ -27,20 +27,20 @@ cd vrs-python ### Virtual Environment -You must first install python@3.12, if not already installed. +You must first install python@3.14, if not already installed. Next, run the following: ```shell make nbready -source venv/3.12/bin/activate +source venv/3.14/bin/activate ``` #### Virtual Environment: Selecting the Kernel When opening a notebook with this option, click `Select Kernel`, `Python Environments...`, and select the first option: -`3.12 (Python 3.12.z) venv/3.12/bin/python` +`3.14 (Python 3.14.z) venv/3.14/bin/python` _Note: Patch version may vary._ @@ -114,7 +114,7 @@ You should see `Dev Container: VRS-Python Notebooks @ desktop-linux` on the bott When opening a notebook with this option, click `Select Kernel`, `Python Environments...`, and select the first option: -`Python 3.12.z /usr/local/bin/python` +`Python 3.14.z /usr/local/bin/python` _Note: Patch version may vary._ diff --git a/pyproject.toml b/pyproject.toml index 6e90ba45..f9e76d3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,10 +18,10 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Scientific/Engineering :: Bio-Informatics", "Topic :: Scientific/Engineering :: Medical Science Apps.", ] @@ -33,7 +33,7 @@ keywords = [ "spdi", "variation" ] -requires-python = ">=3.10" +requires-python = ">=3.11,<3.15" dynamic = ["version"] dependencies = [ "pydantic~=2.1", diff --git a/src/ga4gh/core/models.py b/src/ga4gh/core/models.py index 6cb0cf3b..cfd005cb 100644 --- a/src/ga4gh/core/models.py +++ b/src/ga4gh/core/models.py @@ -3,7 +3,7 @@ from __future__ import annotations from enum import Enum -from typing import Annotated, Any, ClassVar, Literal +from typing import Annotated, Any, ClassVar, Literal, Self from pydantic import ( BaseModel, @@ -13,7 +13,7 @@ StringConstraints, model_validator, ) -from typing_extensions import Self, deprecated +from typing_extensions import deprecated from ga4gh.core.identifiers import GA4GH_IR_REGEXP from ga4gh.core.metadata import GKMMetadataMixin, Maturity From f8320af588ece95603712ddc024448e6622f5276 Mon Sep 17 00:00:00 2001 From: Kyle Ferriter Date: Tue, 27 Oct 2026 14:54:23 -0400 Subject: [PATCH 2/3] build!: replace dill with stdlib pickle in object store Sqlite3MutableMapping used dill to serialize values. Nothing in the library needs dill's by-value pickling: enref/deref only stores VRS models, which pickle by reference. The only dependent was test_classes, which stored a class defined inside the test function. Move that class to module level, switch to pickle, and drop the dill dependency. dill 0.3.x also fails on Python 3.15, where code objects no longer have co_lnotab. Values written by dill for importable classes contain no dill references and load with pickle. Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 1 - src/ga4gh/vrs/extras/object_store.py | 7 +++--- tests/extras/test_object_store.py | 32 +++++++++++++++++----------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f9e76d3f..b89769f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,6 @@ extras = [ "biocommons.seqrepo>=0.5.1", "bioutils>=0.5.2", "hgvs>=2.0.0a0,<3.0", - "dill~=0.3.7", "click", "pysam>=0.24.0", ] diff --git a/src/ga4gh/vrs/extras/object_store.py b/src/ga4gh/vrs/extras/object_store.py index 8712bb31..576da868 100644 --- a/src/ga4gh/vrs/extras/object_store.py +++ b/src/ga4gh/vrs/extras/object_store.py @@ -1,10 +1,9 @@ +import pickle import sqlite3 from collections.abc import MutableMapping from threading import Lock from typing import Any -import dill - class Sqlite3MutableMapping(MutableMapping): """Class that can be used like a Python dictionary but that uses a sqlite3 database @@ -59,7 +58,7 @@ def __delitem__(self, key: Any) -> None: def __setitem__(self, key: Any, value: Any) -> None: cur = self.db.cursor() try: - ser = dill.dumps(value) + ser = pickle.dumps(value) cur.execute( "insert or replace into mapping(key, value) values (?, ?)", (key, sqlite3.Binary(ser)), @@ -75,7 +74,7 @@ def __getitem__(self, key: Any) -> Any: rows = cur.execute("select value from mapping where key = ?", (key,)) row0 = next(rows) if row0: - return dill.loads(row0[0]) # noqa: S301 + return pickle.loads(row0[0]) # noqa: S301 except StopIteration as e: raise KeyError("Key not found: " + str(key)) from e finally: diff --git a/tests/extras/test_object_store.py b/tests/extras/test_object_store.py index 4a11e27a..2d65910b 100644 --- a/tests/extras/test_object_store.py +++ b/tests/extras/test_object_store.py @@ -55,23 +55,31 @@ def test_complex(tmp_path): object_store.close() -def test_classes(tmp_path): - db_path = str(tmp_path) + "/test_complex.sqlite3" +class StoredObject: + """Custom class for object store round-trip tests. + + Defined at module level because pickle stores classes by reference, and a class + local to the test function can't be imported when unpickling. + """ + + def __init__(self, id_value): + """Initialize with an id and some nested attribute values.""" + self.id = id_value + self.A = "A" + self.B = ["B1", "B2", 3] + self.C = {"C1": "C1-value"} - class TestClass: - def __init__(self, id_value): - self.id = id_value - self.A = "A" - self.B = ["B1", "B2", 3] - self.C = {"C1": "C1-value"} + def somefunction(self, arg): + return f"{self.id}-{arg}" - def somefunction(self, arg): - return f"{self.id}-{arg}" + +def test_classes(tmp_path): + db_path = str(tmp_path) + "/test_complex.sqlite3" object_store = Sqlite3MutableMapping(db_path) - val1 = TestClass("val1") - val2 = TestClass("val2") + val1 = StoredObject("val1") + val2 = StoredObject("val2") object_store["val1"] = val1 object_store["val2"] = val2 From 83e35757fa09d2e46558058be1156a287efacfbd Mon Sep 17 00:00:00 2001 From: Kyle Ferriter Date: Tue, 27 Oct 2026 14:54:39 -0400 Subject: [PATCH 3/3] build: allow python 3.15 The <3.15 cap was only needed for dill compatibility, and dill is no longer a dependency. Add 3.15 to the classifiers and CI matrix. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/python-cqa.yml | 2 +- pyproject.toml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-cqa.yml b/.github/workflows/python-cqa.yml index 7a13245d..741bfd78 100644 --- a/.github/workflows/python-cqa.yml +++ b/.github/workflows/python-cqa.yml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.11", "3.12", "3.13", "3.14"] + python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"] env: SEQREPO_ROOT_DIR: ./tests/data/seqrepo/latest steps: diff --git a/pyproject.toml b/pyproject.toml index b89769f1..afd6613c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Topic :: Scientific/Engineering :: Bio-Informatics", "Topic :: Scientific/Engineering :: Medical Science Apps.", ] @@ -33,7 +34,7 @@ keywords = [ "spdi", "variation" ] -requires-python = ">=3.11,<3.15" +requires-python = ">=3.11" dynamic = ["version"] dependencies = [ "pydantic~=2.1",