Skip to content
Merged
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
26 changes: 26 additions & 0 deletions docker-wrappers/OmicsIntegrator2/0001-disable-graph-exports.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
From 5dc0e69fa3d1049ae8e1d8f51859335910245ad7 Mon Sep 17 00:00:00 2001
From: "Tristan F.-R." <[email protected]>
Date: Mon, 26 May 2025 09:52:34 -0700
Subject: [PATCH] fix: disable graph exports

this allows OI2 to work offline; plus, SPRAS already has graph visualizers.
---
src/__main__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/__main__.py b/src/__main__.py
index 49ef402..b7afbca 100644
--- a/src/__main__.py
+++ b/src/__main__.py
@@ -80,7 +80,7 @@ def main():
forest, augmented_forest = graph.output_forest_as_networkx(vertex_indices, edge_indices)

#oi.output_networkx_graph_as_graphml_for_cytoscape(augmented_forest, args.output_dir)
- oi.output_networkx_graph_as_interactive_html(augmented_forest, args.output_dir, args.filename+'.html')
+ # oi.output_networkx_graph_as_interactive_html(augmented_forest, args.output_dir, args.filename+'.html')
augmented_forest_df = oi.get_networkx_graph_as_dataframe_of_edges(augmented_forest)
output_dataframe_to_tsv(augmented_forest_df, args.output_dir, args.filename+'.tsv')

--
2.47.0

9 changes: 9 additions & 0 deletions docker-wrappers/OmicsIntegrator2/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,14 @@
# https://github.com/fraenkel-lab/OmicsIntegrator2
FROM continuumio/miniconda3:4.9.2

COPY 0001-disable-graph-exports.patch .

RUN git clone https://github.com/agitter/OmicsIntegrator2 && \
cd OmicsIntegrator2 && \
git reset --hard 568f170eae388e42e923c478ac9f3308b487760b && \
git config user.email "[email protected]" && \
git config user.name "Non-existent User" && \
git am /0001-disable-graph-exports.patch

COPY environment.yml .
RUN conda env update --name base --file environment.yml --prune
1 change: 1 addition & 0 deletions docker-wrappers/OmicsIntegrator2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ The Docker wrapper can be tested with `pytest`.
## Versions:
- v1: Created a named conda environment in the container and used `ENTRYPOINT` to execute commands inside that environment. Not compatible with Singularity.
- v2: Used the environment file to update the base conda environment so the `ENTRYPOINT` command was no longer needed. Compatible with Singularity.
- v3: Patch to work offline by never running `output_networkx_graph_as_interactive_html` ([#226](https://github.com/Reed-CompBio/spras/pull/226))

## TODO
- Attribute https://github.com/fraenkel-lab/OmicsIntegrator2
Expand Down
2 changes: 1 addition & 1 deletion docker-wrappers/OmicsIntegrator2/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ dependencies:
- pcst_fast==1.0.7
- goenrich==1.7.0
- axial==0.1.10
- git+https://github.com/agitter/OmicsIntegrator2@568f170eae388e42e923c478ac9f3308b487760b
- git+file:///OmicsIntegrator2
23 changes: 23 additions & 0 deletions docs/contributing/patching.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Patching Algorithms
===================

Some wrapped algorithms require extra fixes inside their code. For permissively licensed algorithms,
we use ``.patch`` files generated from ``git format-patch``.

To create patch files using ``git format-patch`` (assuming your wrapped algorithm is in a git repository):

#. Clone the repository locally.
#. Commit the changes you want to make (with good commit messages and descriptions).

* Distinct changes should be made in different commits to make patch files easy to read
* For removing code, we prefer to comment out code instead of removing it, to make potential stacktraces less confusing for end users.

#. Run ``git format-patch HEAD~[N]`` where ``N`` is the number of commits you made.

To use ``.patch`` files in ``Dockerfiles``, we create a fake user for ``git`` and apply the patch files using ``git am``:

.. code:: shell

git config user.email "[email protected]"
git config user.name "Non-existent User"
git am /0001-my-patch.patch
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ methods (PRMs) to omics data.

contributing/index
contributing/maintain
contributing/patching

Indices and tables
==================
Expand Down
16 changes: 10 additions & 6 deletions spras/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,31 +132,32 @@ def env_to_items(environment: dict[str, str]) -> Iterator[str]:
# TODO consider a better default environment variable
# Follow docker-py's naming conventions (https://docker-py.readthedocs.io/en/stable/containers.html)
# Technically the argument is an image, not a container, but we use container here.
def run_container(framework: str, container_suffix: str, command: List[str], volumes: List[Tuple[PurePath, PurePath]], working_dir: str, out_dir: str | os.PathLike, environment: Optional[dict[str, str]] = None):
def run_container(framework: str, container_suffix: str, command: List[str], volumes: List[Tuple[PurePath, PurePath]], working_dir: str, out_dir: str | os.PathLike, environment: Optional[dict[str, str]] = None, network_disabled = False):
"""
Runs a command in the container using Singularity or Docker
@param framework: singularity or docker
@param container_suffix: name of the DockerHub container without the 'docker://' prefix
@param command: command to run in the container
@param volumes: a list of volumes to mount where each item is a (source, destination) tuple
@param working_dir: the working directory in the container
@param environment: environment variables to set in the container
@param out_dir: output directory for the rule's artifacts. Only passed into run_container_singularity for the purpose of profiling.
@param environment: environment variables to set in the container
@param network_disabled: Disables the network on the container. Only works for docker for now. This acts as a 'runtime assertion' that a container works w/o networking.
@return: output from Singularity execute or Docker run
"""
normalized_framework = framework.casefold()

container = config.config.container_prefix + "/" + container_suffix
if normalized_framework == 'docker':
return run_container_docker(container, command, volumes, working_dir, environment)
return run_container_docker(container, command, volumes, working_dir, environment, network_disabled)
elif normalized_framework == 'singularity' or normalized_framework == "apptainer":
return run_container_singularity(container, command, volumes, working_dir, out_dir, environment)
elif normalized_framework == 'dsub':
return run_container_dsub(container, command, volumes, working_dir, environment)
else:
raise ValueError(f'{framework} is not a recognized container framework. Choose "docker", "dsub", or "singularity".')

def run_container_and_log(name: str, framework: str, container_suffix: str, command: List[str], volumes: List[Tuple[PurePath, PurePath]], working_dir: str, out_dir: str | os.PathLike, environment: Optional[dict[str, str]] = None):
def run_container_and_log(name: str, framework: str, container_suffix: str, command: List[str], volumes: List[Tuple[PurePath, PurePath]], working_dir: str, out_dir: str | os.PathLike, environment: Optional[dict[str, str]] = None, network_disabled=False):
"""
Runs a command in the container using Singularity or Docker with associated pretty printed messages.
@param name: the display name of the running container for logging purposes
Expand All @@ -166,14 +167,15 @@ def run_container_and_log(name: str, framework: str, container_suffix: str, comm
@param volumes: a list of volumes to mount where each item is a (source, destination) tuple
@param working_dir: the working directory in the container
@param environment: environment variables to set in the container
@param network_disabled: Disables the network on the container. Only works for docker for now. This acts as a 'runtime assertion' that a container works w/o networking.
@return: output from Singularity execute or Docker run
"""
if not environment:
environment = {'SPRAS': 'True'}

print('Running {} on container framework "{}" on env {} with command: {}'.format(name, framework, list(env_to_items(environment)), ' '.join(command)), flush=True)
try:
out = run_container(framework=framework, container_suffix=container_suffix, command=command, volumes=volumes, working_dir=working_dir, out_dir=out_dir, environment=environment)
out = run_container(framework=framework, container_suffix=container_suffix, command=command, volumes=volumes, working_dir=working_dir, out_dir=out_dir, environment=environment, network_disabled=network_disabled)
if out is not None:
if isinstance(out, list):
out = ''.join(out)
Expand All @@ -199,7 +201,7 @@ def run_container_and_log(name: str, framework: str, container_suffix: str, comm
raise err

# TODO any issue with creating a new client each time inside this function?
def run_container_docker(container: str, command: List[str], volumes: List[Tuple[PurePath, PurePath]], working_dir: str, environment: Optional[dict[str, str]] = None):
def run_container_docker(container: str, command: List[str], volumes: List[Tuple[PurePath, PurePath]], working_dir: str, environment: Optional[dict[str, str]] = None, network_disabled=False):
"""
Runs a command in the container using Docker.
Attempts to automatically correct file owner and group for new files created by the container, setting them to the
Expand Down Expand Up @@ -244,6 +246,7 @@ def run_container_docker(container: str, command: List[str], volumes: List[Tuple
stderr=True,
volumes=bind_paths,
working_dir=working_dir,
network_disabled=network_disabled,
environment=environment).decode('utf-8')

# TODO does this cleanup need to still run even if there was an error in the above run command?
Expand Down Expand Up @@ -278,6 +281,7 @@ def run_container_docker(container: str, command: List[str], volumes: List[Tuple
stderr=True,
volumes=bind_paths,
working_dir=working_dir,
network_disabled=network_disabled,
environment=environment).decode('utf-8')

# Raised on non-Unix systems
Expand Down
5 changes: 3 additions & 2 deletions spras/omicsintegrator2.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,15 @@ def run(edges=None, prizes=None, output_file=None, w=None, b=None, g=None, noise
if seed is not None:
command.extend(['--seed', str(seed)])

container_suffix = "omics-integrator-2:v2"
container_suffix = "omics-integrator-2:v3"
run_container_and_log('Omics Integrator 2',
container_framework,
container_suffix,
command,
volumes,
work_dir,
out_dir)
out_dir,
network_disabled=True)

# TODO do we want to retain other output files?
# TODO if deleting other output files, write them all to a tmp directory and copy
Expand Down
Loading