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
6 changes: 3 additions & 3 deletions Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ algorithm_params = _config.config.algorithm_params
algorithm_directed = _config.config.algorithm_directed
pca_params = _config.config.pca_params
hac_params = _config.config.hac_params
FRAMEWORK = _config.config.container_settings.framework
container_settings = _config.config.container_settings
include_aggregate_algo_eval = _config.config.analysis_include_evaluation_aggregate_algo

# Return the dataset or gold_standard dictionary from the config file given the label
Expand Down Expand Up @@ -281,7 +281,7 @@ rule reconstruct:
# Remove the default placeholder parameter added for algorithms that have no parameters
if 'spras_placeholder' in params:
params.pop('spras_placeholder')
params['container_framework'] = FRAMEWORK
params['container_settings'] = container_settings
runner.run(wildcards.algorithm, params)

# Original pathway reconstruction output to universal output
Expand Down Expand Up @@ -313,7 +313,7 @@ rule viz_cytoscape:
output:
session = SEP.join([out_dir, '{dataset}-cytoscape.cys'])
run:
cytoscape.run_cytoscape(input.pathways, output.session, FRAMEWORK)
cytoscape.run_cytoscape(input.pathways, output.session, container_settings)


# Write a single summary table for all pathways for each dataset
Expand Down
22 changes: 11 additions & 11 deletions config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ containers:
# For example, "reedcompbio" if the image is available as docker.io/reedcompbio/allpairs
owner: reedcompbio

# Enabling profiling adds a file called 'usage-profile.tsv' to the output directory of each algorithm.
# The contents of this file describe the CPU utilization and peak memory consumption of the algorithm
# as seen by its runtime container.
# NOTE: Profiling is currently supported only when the container framework is set to apptainer/singularity
# and when the host system supports the 'cgroup' filesystem.
# When profiling via HTCondor, this assumes the current process is already in a two-level nested cgroup
# (introduced in HTCondor 24.8.0). To specify a minimum HTCondor version, use the following `requirements`
# expression:
#
# requirements = versionGE(split(Target.CondorVersion)[1], "24.8.0") && (isenforcingdiskusage =!= true)
enable_profiling: false
# Enabling profiling adds a file called 'usage-profile.tsv' to the output directory of each algorithm.
# The contents of this file describe the CPU utilization and peak memory consumption of the algorithm
# as seen by its runtime container.
# NOTE: Profiling is currently supported only when the container framework is set to apptainer/singularity
# and when the host system supports the 'cgroup' filesystem.
# When profiling via HTCondor, this assumes the current process is already in a two-level nested cgroup
# (introduced in HTCondor 24.8.0). To specify a minimum HTCondor version, use the following `requirements`
# expression:
#
# requirements = versionGE(split(Target.CondorVersion)[1], "24.8.0") && (isenforcingdiskusage =!= true)
enable_profiling: false

# This list of algorithms should be generated by a script which checks the filesystem for installs.
# It shouldn't be changed by mere mortals. (alternatively, we could add a path to executable for each algorithm
Expand Down
16 changes: 9 additions & 7 deletions spras/allpairs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import warnings
from pathlib import Path

from spras.config.container_schema import ProcessedContainerSettings
from spras.containers import prepare_volume, run_container_and_log
from spras.dataset import Dataset
from spras.interactome import (
Expand Down Expand Up @@ -69,14 +70,15 @@ def generate_inputs(data: Dataset, filename_map):
header=["#Interactor1", "Interactor2", "Weight"])

@staticmethod
def run(nodetypes=None, network=None, directed_flag=None, output_file=None, container_framework="docker"):
def run(nodetypes=None, network=None, directed_flag=None, output_file=None, container_settings=None):
"""
Run All Pairs Shortest Paths with Docker
@param nodetypes: input node types with sources and targets (required)
@param network: input network file (required)
@param container_framework: choose the container runtime framework, currently supports "docker" or "singularity" (optional)
@param container_settings: configure the container runtime
@param output_file: path to the output pathway file (required)
"""
if not container_settings: container_settings = ProcessedContainerSettings()
if not nodetypes or not network or not output_file or not directed_flag:
raise ValueError('Required All Pairs Shortest Paths arguments are missing')

Expand All @@ -85,16 +87,16 @@ def run(nodetypes=None, network=None, directed_flag=None, output_file=None, cont
# Each volume is a tuple (src, dest)
volumes = list()

bind_path, node_file = prepare_volume(nodetypes, work_dir)
bind_path, node_file = prepare_volume(nodetypes, work_dir, container_settings)
volumes.append(bind_path)

bind_path, network_file = prepare_volume(network, work_dir)
bind_path, network_file = prepare_volume(network, work_dir, container_settings)
volumes.append(bind_path)

# Create the parent directories for the output file if needed
out_dir = Path(output_file).parent
out_dir.mkdir(parents=True, exist_ok=True)
bind_path, mapped_out_file = prepare_volume(output_file, work_dir)
bind_path, mapped_out_file = prepare_volume(output_file, work_dir, container_settings)
volumes.append(bind_path)

command = ['python',
Expand All @@ -108,12 +110,12 @@ def run(nodetypes=None, network=None, directed_flag=None, output_file=None, cont
container_suffix = "allpairs:v4"
run_container_and_log(
'All Pairs Shortest Paths',
container_framework,
container_suffix,
command,
volumes,
work_dir,
out_dir)
out_dir,
container_settings)

@staticmethod
def parse_output(raw_pathway_file, standardized_pathway_file, params):
Expand Down
15 changes: 10 additions & 5 deletions spras/analysis/cytoscape.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@
from shutil import rmtree
from typing import List, Union

from spras.config.container_schema import ProcessedContainerSettings
from spras.containers import prepare_volume, run_container_and_log


def run_cytoscape(pathways: List[Union[str, PurePath]], output_file: str, container_framework="docker") -> None:
def run_cytoscape(pathways: List[Union[str, PurePath]], output_file: str, container_settings=None) -> None:
"""
Create a Cytoscape session file with visualizations of each of the provided pathways
@param pathways: a list of pathways to visualize
@param output_file: the output Cytoscape session file
@param container_framework: choose the container runtime framework, currently supports "docker" or "singularity" (optional)
@param container_settings: configure the container runtime
"""
if not container_settings: container_settings = ProcessedContainerSettings()
work_dir = '/spras'

# To work with Singularity, /spras must be mapped to a writeable location because that directory is fixed as
Expand All @@ -33,25 +35,28 @@ def run_cytoscape(pathways: List[Union[str, PurePath]], output_file: str, contai
volumes.append((cytoscape_output_dir, PurePath(work_dir, 'CytoscapeConfiguration')))

# Map the output file
bind_path, mapped_output = prepare_volume(output_file, work_dir)
bind_path, mapped_output = prepare_volume(output_file, work_dir, container_settings)
volumes.append(bind_path)

# Create the initial Python command to run inside the container
command = ['python', '/py4cytoscape/cytoscape_util.py', '--output', mapped_output]

# Map the pathway filenames and add them to the Python command
for pathway in pathways:
bind_path, mapped_pathway = prepare_volume(pathway, work_dir)
bind_path, mapped_pathway = prepare_volume(pathway, work_dir, container_settings)
volumes.append(bind_path)
# Provided the mapped pathway file path and the original file path as the label Cytoscape
command.extend(['--pathway', f'{mapped_pathway}|{pathway}'])

container_suffix = "py4cytoscape:v3"
run_container_and_log('Cytoscape',
container_framework,
container_suffix,
command,
volumes,
work_dir,
# TODO: doesn't work on Singularity
# (https://github.com/Reed-CompBio/spras/pull/390/files#r2485100875)
None,
container_settings,
env)
rmtree(cytoscape_output_dir)
29 changes: 15 additions & 14 deletions spras/btb.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pathlib import Path

from spras.config.container_schema import ProcessedContainerSettings
from spras.containers import prepare_volume, run_container_and_log
from spras.interactome import (
convert_undirected_to_directed,
Expand Down Expand Up @@ -68,15 +69,16 @@ def generate_inputs(data, filename_map):

# Skips parameter validation step
@staticmethod
def run(sources=None, targets=None, edges=None, output_file=None, container_framework="docker"):
def run(sources=None, targets=None, edges=None, output_file=None, container_settings=None):
"""
Run BTB with Docker
@param sources: input source file (required)
@param targets: input target file (required)
@param edges: input edge file (required)
@param output_file: path to the output pathway file (required)
@param container_framework: choose the container runtime framework, currently supports "docker" or "singularity" (optional)
@param container_settings: configure the container runtime
"""
if not container_settings: container_settings = ProcessedContainerSettings()

# Tests for pytest (docker container also runs this)
# Testing out here avoids the trouble that container errors provide
Expand Down Expand Up @@ -105,19 +107,19 @@ def run(sources=None, targets=None, edges=None, output_file=None, container_fram
# Each volume is a tuple (src, dest)
volumes = list()

bind_path, source_file = prepare_volume(sources, work_dir)
bind_path, source_file = prepare_volume(sources, work_dir, container_settings)
volumes.append(bind_path)

bind_path, target_file = prepare_volume(targets, work_dir)
bind_path, target_file = prepare_volume(targets, work_dir, container_settings)
volumes.append(bind_path)

bind_path, edges_file = prepare_volume(edges, work_dir)
bind_path, edges_file = prepare_volume(edges, work_dir, container_settings)
volumes.append(bind_path)

# Use its --output argument to set the output file prefix to specify an absolute path and prefix
out_dir = Path(output_file).parent
out_dir.mkdir(parents=True, exist_ok=True)
bind_path, mapped_out_dir = prepare_volume(str(out_dir), work_dir)
bind_path, mapped_out_dir = prepare_volume(str(out_dir), work_dir, container_settings)
volumes.append(bind_path)
mapped_out_prefix = mapped_out_dir + '/raw-pathway.txt' # Use posix path inside the container

Expand All @@ -133,14 +135,13 @@ def run(sources=None, targets=None, edges=None, output_file=None, container_fram
mapped_out_prefix]

container_suffix = "bowtiebuilder:v2"
run_container_and_log(
'BowTieBuilder',
container_framework,
container_suffix,
command,
volumes,
work_dir,
out_dir)
run_container_and_log('BowTieBuilder',
container_suffix,
command,
volumes,
work_dir,
out_dir,
container_settings)
# Output is already written to raw-pathway.txt file


Expand Down
5 changes: 1 addition & 4 deletions spras/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ def __init__(self, raw_config: dict[str, Any]):

# Directory used for storing output
self.out_dir = parsed_raw_config.reconstruction_settings.locations.reconstruction_dir
# A Boolean indicating whether to enable container runtime profiling (apptainer/singularity only)
self.enable_profiling = False
# A dictionary to store configured datasets against which SPRAS will be run
self.datasets = None
# A dictionary to store configured gold standard data against output of SPRAS runs
Expand Down Expand Up @@ -292,9 +290,8 @@ def process_config(self, raw_config: RawConfig):
# Set up a few top-level config variables
self.out_dir = raw_config.reconstruction_settings.locations.reconstruction_dir

if raw_config.enable_profiling and raw_config.containers.framework not in ["singularity", "apptainer"]:
if raw_config.containers.enable_profiling and raw_config.containers.framework not in ["singularity", "apptainer"]:
warnings.warn("enable_profiling is set to true, but the container framework is not singularity/apptainer. This setting will have no effect.", stacklevel=2)
self.enable_profiling = raw_config.enable_profiling

self.process_datasets(raw_config)
self.process_algorithms(raw_config)
Expand Down
5 changes: 4 additions & 1 deletion spras/config/container_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,18 @@ class ContainerRegistry(BaseModel):
class ContainerSettings(BaseModel):
framework: ContainerFramework = ContainerFramework.docker
unpack_singularity: bool = False
enable_profiling: bool = False
"A Boolean indicating whether to enable container runtime profiling (apptainer/singularity only)"
registry: ContainerRegistry

model_config = ConfigDict(extra='forbid')
model_config = ConfigDict(extra='forbid', use_attribute_docstrings=True)

@dataclass
class ProcessedContainerSettings:
framework: ContainerFramework = ContainerFramework.docker
unpack_singularity: bool = False
prefix: str = DEFAULT_CONTAINER_PREFIX
enable_profiling: bool = False
hash_length: int = 7
"""
The hash length for container-specific usage. This does not appear in
Expand Down
1 change: 0 additions & 1 deletion spras/config/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ class ReconstructionSettings(BaseModel):

class RawConfig(BaseModel):
containers: ContainerSettings
enable_profiling: bool = False

hash_length: int = DEFAULT_HASH_LENGTH
"The length of the hash used to identify a parameter combination"
Expand Down
Loading
Loading