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..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.10", "3.11", "3.12", "3.13"] + python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"] 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..afd6613c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,10 +18,11 @@ 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", + "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.10" +requires-python = ">=3.11" dynamic = ["version"] dependencies = [ "pydantic~=2.1", @@ -49,7 +50,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/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 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