Skip to content

Commit

Permalink
feat: initial code for software deployment plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
johanneskoester committed Nov 6, 2024
1 parent 20d1097 commit 5bb73e2
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
132 changes: 132 additions & 0 deletions poetry_snakemake_plugin/templates/software-deployment-plugins/init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
from dataclasses import dataclass, field
import json
from typing import Any, Iterable, Optional, List
import subprocess as sp
from snakemake_interface_software_deployment_plugins.settings import (
SoftwareDeploymentProviderSettingsBase,
)
from snakemake_interface_software_deployment_plugins import (
SoftwareDeploymentProviderBase,
EnvBase,
DeployableEnvBase,
ArchiveableEnvBase,
)


# Optional:
# Define settings for your storage plugin (e.g. host url, credentials).
# They will occur in the Snakemake CLI as --sdm-<plugin-name>-<param-name>
# Make sure that all defined fields are 'Optional' and specify a default value
# of None or anything else that makes sense in your case.
# Note that we allow storage plugin settings to be tagged by the user. That means,
# that each of them can be specified multiple times (an implicit nargs=+), and
# the user can add a tag in front of each value (e.g. tagname1:value1 tagname2:value2).
# This way, a storage plugin can be used multiple times within a workflow with different
# settings.
@dataclass
class SoftwareDeploymentProviderSettings(SoftwareDeploymentProviderSettingsBase):
myparam: Optional[int] = field(
default=None,
metadata={
"help": "Some help text",
# Optionally request that setting is also available for specification
# via an environment variable. The variable will be named automatically as
# SNAKEMAKE_<storage-plugin-name>_<param-name>, all upper case.
# This mechanism should only be used for passwords, usernames, and other
# credentials.
# For other items, we rather recommend to let people use a profile
# for setting defaults
# (https://snakemake.readthedocs.io/en/stable/executing/cli.html#profiles).
"env_var": False,
# Optionally specify a function that parses the value given by the user.
# This is useful to create complex types from the user input.
"parse_func": ...,
# If a parse_func is specified, you also have to specify an unparse_func
# that converts the parsed value back to a string.
"unparse_func": ...,
# Optionally specify that setting is required when the executor is in use.
"required": True,
# Optionally specify multiple args with "nargs": "+"
},
)


# Required:
# Implementation of your software deployment provider
# This class can be empty as the one below.
# You can however use it to store global information or check for certain tools
# to be available.
class SoftwareDeploymentProvider(SoftwareDeploymentProviderBase):
# For compatibility with future changes, you should not overwrite the __init__
# method. Instead, use __post_init__ to set additional attributes and initialize
# futher stuff.

def __post_init__(self):
# You can e.g. use this method to store global information or check for
# certain tools to be available.
# Overwrite the example code below with your own or remove the entire method
# if not needed.

# Example code:
# Here we run conda info to get information about the current conda installation.
# Important: We use the inherited method self.run() to run the command.
# This is mandatory since providers can be stacked by the user, such that
# e.g. this provider is supposed to be used from within a particular environment
# like a container or an environment module.
# The self.run() method takes care of that automatically.
self.conda_info = json.loads(self.run("conda info --json").decode())


# Required:
# Implementation of an environment object.
# If your environment cannot be archived or deployed, remove the respective methods
# and the respective base classes.
class Env(EnvBase, DeployableEnvBase, ArchiveableEnvBase):
# For compatibility with future changes, you should not overwrite the __init__
# method. Instead, use __post_init__ to set additional attributes and initialize
# futher stuff.

def __post_init__(self) -> None:
# This is optional and can be removed if not needed.
# Alternatively, you can e.g. prepare anything or set additional attributes.
pass

def decorate_shellcmd(self, cmd: str) -> str:
# Decorate given shell command such that it runs within the environment.
...

def hash(self, hash_object) -> None:
# Update given hash such that it changes whenever the environment
# could potentially contain a different set of software (in terms of versions or
# packages).
...

# The methods below are optional. Remove them if not needed and adjust the
# base classes above.

def deploy(self) -> None:
# Remove if not deployable!
# Deploy the environment to self.provider.deployment_path.

# When issuing shell commands, the environment should use
# self.provider.run(cmd: str) -> bytes in order to ensure that it runs within
# eventual parent environments (e.g. a container or an env module).
...

def deployment_hash(self, hash_object) -> None:
# Remove if not deployable!
# Update given hash such that it changes whenever the environment
# needs to be redeployed, e.g. because its content has changed or the
# deployment location has changed. The latter is only relevant if the
# deployment is senstivive to the path (e.g. in case of conda, which patches
# the RPATH in binaries).
...

def archive(self) -> None:
# Remove if not archiveable!
# Archive the environment to self.provider.archive_path.

# When issuing shell commands, the environment should use
# self.provider.run(cmd: str) -> bytes in order to ensure that it runs within
# eventual parent environments (e.g. a container or an env module).
...
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Optional, Type
from snakemake_interface_software_deployment_plugins.tests import TestSoftwareDeploymentBase
from snakemake_interface_software_deployment_plugins import SoftwareDeploymentProviderBase
from snakemake_interface_software_deployment_plugins.settings import SoftwareDeploymentProviderSettingsBase


class TestSoftwareDeployment(TestSoftwareDeploymentBase):
__test__ = True
deploy = True # set to True if the provider deploys its envs
archive = True # set to True if envs can be archived

def get_env_spec(self) -> str:
# Return an env spec query. If deploy == False the env should be present a priori.
...

def get_software_deployment_provider_cls(self) -> Type[SoftwareDeploymentProviderBase]:
# Return the SoftwareDeploymentProvider class of this plugin
...

def get_software_deployment_provider_settings(self) -> Optional[SoftwareDeploymentProviderSettingsBase]:
# instantiate StorageProviderSettings of this plugin as appropriate
...

0 comments on commit 5bb73e2

Please sign in to comment.