Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand Down
18 changes: 9 additions & 9 deletions .github/workflows/test-spras.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ jobs:
os: [macos-latest, windows-latest]
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install conda environment
uses: conda-incubator/setup-miniconda@v2
uses: conda-incubator/setup-miniconda@v4
with:
activate-environment: spras
environment-file: environment.yml
auto-activate-base: false
auto-activate: false
miniconda-version: 'latest'
- name: Log conda environment
# Log conda environment contents
Expand Down Expand Up @@ -49,11 +49,11 @@ jobs:
sudo docker image prune --all --force
sudo docker builder prune -a
- name: Install conda environment
uses: conda-incubator/setup-miniconda@v2
uses: conda-incubator/setup-miniconda@v4
with:
activate-environment: spras
environment-file: environment.yml
auto-activate-base: false
auto-activate: false
miniconda-version: 'latest'
- name: Install spras in conda env
# Install spras in the environment using pip
Expand Down Expand Up @@ -85,11 +85,11 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install conda environment
uses: conda-incubator/setup-miniconda@v2
uses: conda-incubator/setup-miniconda@v4
with:
activate-environment: spras
environment-file: environment.yml
auto-activate-base: false
auto-activate: false
miniconda-version: 'latest'
# Install spras in the environment using pip
- name: Install spras in conda env
Expand All @@ -110,11 +110,11 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install conda environment
uses: conda-incubator/setup-miniconda@v2
uses: conda-incubator/setup-miniconda@v4
with:
activate-environment: spras
environment-file: environment.yml
auto-activate-base: false
auto-activate: false
miniconda-version: 'latest'
- name: Run pre-commit
shell: bash --login {0}
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# See https://pre-commit.com/hooks.html for more hooks
default_language_version:
# Match this to the version specified in environment.yml
python: python3.11
python: python3.13
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0 # Use the ref you want to point at
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ version: 2
build:
os: ubuntu-22.04
tools:
python: "3.11"
python: "3.13"

# Build documentation in the "docs/" directory with Sphinx
sphinx:
Expand Down
4 changes: 2 additions & 2 deletions docker-wrappers/SPRAS/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ FROM almalinux:9
RUN dnf update -y && \
dnf install -y epel-release && \
dnf install -y gcc gcc-c++ \
python3.11 python3.11-pip python3.11-devel \
python3.13 python3.13-pip python3.13-devel \
docker apptainer && \
dnf clean all

Expand All @@ -13,4 +13,4 @@ RUN chmod -R 777 /spras
WORKDIR /spras

# Install spras into the container
RUN pip3.11 install .
RUN pip3.13 install .
38 changes: 19 additions & 19 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,37 @@ channels:
- conda-forge
dependencies:
- adjusttext=1.3.0
- bioconda::snakemake-minimal=9.6.2
- bioconda::snakemake-minimal=9.20.0
# Conda refers to pypi/docker as docker-py.
- docker-py=7.1.0
- matplotlib=3.10.3
- networkx=3.5
- pandas=2.3.0
- pydantic=2.11.7
- numpy=2.3.1
- requests=2.32.4
- scikit-learn=1.7.0
- matplotlib=3.10.9
- networkx=3.6.1
- pandas=3.0.2
- pydantic=2.13.3
- numpy=2.4.4
- requests=2.33.1
- scikit-learn=1.8.0
- seaborn=0.13.2
- spython=0.3.14

# conda-specific for dsub
- python-dateutil=2.9.0
- pytz=2025.2
- pyyaml=6.0.2
- tenacity=9.1.2
- tabulate=0.9.0
- pytz=2026.1
- pyyaml=6.0.3
- tenacity=9.1.4
- tabulate=0.10.0

# toolchain deps
- pip=25.3
- pip=26.0.1
# This should be the same as requires-python minus the >=.
- python=3.11
- python=3.13

# development dependencies
- pre-commit=4.2.0
- pytest=8.4.1
- pytest-split=0.10.0
- sphinx=7.4.7
- sphinx-rtd-theme=2.0.0
- pre-commit=4.6.0
- pytest=9.0.3
- pytest-split=0.11.0
- sphinx=9.1.0
- sphinx-rtd-theme=3.1.0

- pip:
- dsub==0.4.13
30 changes: 15 additions & 15 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,31 @@ classifiers = [
"Programming Language :: Python :: 3",
"Topic :: Scientific/Engineering :: Bio-Informatics",
]
requires-python = ">=3.11"
requires-python = ">=3.13"
dependencies = [
"adjusttext==0.7.3",
"snakemake==9.6.2",
"adjusttext==1.3.0",
"snakemake==9.20.0",
"docker==7.1.0",
"matplotlib==3.10.3",
"networkx==3.5",
"pandas==2.3.0",
"pydantic==2.11.7",
"numpy==2.3.1",
"requests==2.32.4",
"scikit-learn==1.7.0",
"matplotlib==3.10.9",
"networkx==3.6.1",
"pandas==3.0.2",
"pydantic==2.13.3",
"numpy==2.4.4",
"requests==2.33.1",
"scikit-learn==1.8.0",
"seaborn==0.13.2",
"spython==0.3.14",

# toolchain deps
"pip==25.3",
"pip==26.0.1",
]

[project.optional-dependencies]
dev = [
# Only required for development
"pre-commit==4.2.0",
"pytest==8.4.1",
"pytest-split==0.10.0",
"pre-commit==4.6.0",
"pytest==9.0.3",
"pytest-split==0.11.0",
]

[project.urls]
Expand All @@ -52,7 +52,7 @@ requires = ["setuptools>=64.0"]
build-backend = "setuptools.build_meta"

[tool.ruff]
target-version = "py311"
target-version = "py313"
# Autofix errors when possible
fix = true
# Select categories or specific rules from https://beta.ruff.rs/docs/rules/
Expand Down
5 changes: 2 additions & 3 deletions spras/dataset.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import pickle as pkl
import warnings
from typing import Union
from typing import Self, Union

import pandas as pd

Expand Down Expand Up @@ -60,9 +60,8 @@ def to_file(self, file: LoosePathLike):
with open(file, "wb") as f:
pkl.dump(self, f)

# NOTE: When we bump to Python 3.13, we can use the reference Dataset instead of the literal "Dataset" for typing.
@classmethod
def from_file(cls, file: Union[LoosePathLike, "Dataset"]):
def from_file(cls, file: Union[LoosePathLike, Self]):
"""
Loads dataset object from a pickle file or another `Dataset` object.
Usage: dataset = Dataset.from_file(pickle_file)
Expand Down
26 changes: 17 additions & 9 deletions spras/prm.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
from abc import ABC, abstractmethod
from pathlib import Path
from types import get_original_bases
from typing import Any, Generic, Mapping, Optional, TypeVar, cast, get_args

from pydantic import BaseModel
Expand Down Expand Up @@ -52,10 +53,22 @@ def get_params_generic(cls) -> type[T]:
For example, on `class PathLinker(PRM[PathLinkerParams])`,
calling `PathLinker.get_params_generic()` returns `PathLinkerParams`.
"""
# TODO: use the type-safe get_original_bases when we bump to >= Python 3.12
# This is hacky reflection from https://stackoverflow.com/a/71720366/7589775
# which grabs the class of type T by the definition of `__orig_bases__`.
return get_args(cast(Any, cls).__orig_bases__[0])[0]
# This gives us (PRM[PathLinkerParams], )
original_bases = get_original_bases(cls)

# Since we just used reflection, we provide a few mountain-dewey error messages here
# to protect against any developer confusion.
assert len(original_bases) == 1, f"{cls} inherits from several classes, when precisely one is required."
original_bases_args = get_args(original_bases[0])
assert len(original_bases_args) == 1, "There were several generics passed into PRM, when precisely one is required."
T_class, = original_bases_args

if not issubclass(T_class, BaseModel):
raise RuntimeError("The generic passed into PRM is not a pydantic.BaseModel.")

# Finally, we cast, since issubclass overeagerly restricts T_class to type[BaseModel]
# instead of type[T] without imposing the restriction that T inherits from BaseModel
return cast(type[T], T_class)

# This is used in `runner.py` to avoid a dependency diamond when trying
# to import the actual algorithm schema.
Expand All @@ -66,11 +79,6 @@ def run_typeless(cls, inputs: dict[str, str | os.PathLike], output_file: str | o
"""
T_class = cls.get_params_generic()

# Since we just used reflection, we provide a mountain-dewey error message here
# to protect against any developer confusion.
if not issubclass(T_class, BaseModel):
raise RuntimeError("The generic passed into PRM is not a pydantic.BaseModel.")

# Validates our untyped `args` parameter against our parameter class of type T
# using BaseModel.model_validate (https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_validate)
# (Pydantic already provides nice error messages, so we don't need to worry about catching this.)
Expand Down
2 changes: 1 addition & 1 deletion spras/responsenet.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def parse_output(raw_pathway_file, standardized_pathway_file, params):
df = raw_pathway_df(raw_pathway_file, sep='\t', header=0)
if not df.empty:
df.columns = ['Node1', 'Node2', 'Flow']
df = df.drop(columns=['Flow'], axis=1)
df = df.drop(columns=['Flow'])
df = add_rank_column(df)
# ResponseNet's outputs should be treated as undirected outputs.
df = reinsert_direction_col_undirected(df)
Expand Down
Loading