snakemake-software-deployment-plugin-container 0.7.1__tar.gz → 0.7.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (11) hide show
  1. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/CHANGELOG.md +14 -0
  2. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/PKG-INFO +1 -1
  3. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/pyproject.toml +1 -1
  4. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/src/snakemake_software_deployment_plugin_container/__init__.py +85 -2
  5. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/.github/workflows/ci.yml +0 -0
  6. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/.github/workflows/conventional-prs.yml +0 -0
  7. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/.github/workflows/release-please.yml +0 -0
  8. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/.gitignore +0 -0
  9. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/LICENSE +0 -0
  10. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/README.md +0 -0
  11. {snakemake_software_deployment_plugin_container-0.7.1 → snakemake_software_deployment_plugin_container-0.7.3}/tests/test_plugin.py +0 -0
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.3](https://github.com/snakemake/snakemake-software-deployment-plugin-container/compare/v0.7.2...v0.7.3) (2026-09-10)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * add quiet flag to udocker execution ([fcb5780](https://github.com/snakemake/snakemake-software-deployment-plugin-container/commit/fcb57800287a59cee68c1ec87a47d17a304ce207))
9
+
10
+ ## [0.7.2](https://github.com/snakemake/snakemake-software-deployment-plugin-container/compare/v0.7.1...v0.7.2) (2026-09-08)
11
+
12
+
13
+ ### Performance Improvements
14
+
15
+ * explicit handling of deployment ([#25](https://github.com/snakemake/snakemake-software-deployment-plugin-container/issues/25)) ([127dff9](https://github.com/snakemake/snakemake-software-deployment-plugin-container/commit/127dff9b49f81a0fd55504676e1385b1dea977f7))
16
+
3
17
  ## [0.7.1](https://github.com/snakemake/snakemake-software-deployment-plugin-container/compare/v0.7.0...v0.7.1) (2026-09-07)
4
18
 
5
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: snakemake-software-deployment-plugin-container
3
- Version: 0.7.1
3
+ Version: 0.7.3
4
4
  Project-URL: repository, https://github.com/snakemake/snakemake-software-deployment-plugin-container
5
5
  Project-URL: documentation, https://snakemake.github.io/snakemake-plugin-catalog/plugins/software-deployment/container.html
6
6
  Author-email: Ben Carrillo <ben.uzh@pm.me>, Johannes Köster <johannes.koester@uni-due.de>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "snakemake-software-deployment-plugin-container"
3
- version = "0.7.1"
3
+ version = "0.7.3"
4
4
  authors = [
5
5
  { name = "Ben Carrillo", email = "ben.uzh@pm.me" },
6
6
  { name = "Johannes Köster", email = "johannes.koester@uni-due.de" }
@@ -1,3 +1,6 @@
1
+ from pathlib import Path
2
+ from abc import abstractmethod
3
+ from snakemake_interface_software_deployment_plugins import DeployableEnvBase
1
4
  import re
2
5
 
3
6
  __author__ = "ben carrillo"
@@ -91,7 +94,7 @@ class EnvSpec(EnvSpecBase):
91
94
 
92
95
 
93
96
  # All errors should be wrapped with snakemake-interface-common.errors.WorkflowError
94
- class Env(EnvBase):
97
+ class Env(DeployableEnvBase, EnvBase):
95
98
  # image_repo is the de-referenced repository from where the image was obtained
96
99
  image_repo: str
97
100
  settings: Settings
@@ -159,11 +162,65 @@ class Env(EnvBase):
159
162
  # Return an empty tuple () if no software can be reported.
160
163
  return [SoftwareReport(name=self.spec.image_uri)]
161
164
 
165
+ def is_deployment_path_portable(self) -> bool:
166
+ """Return whether the deployment path matters for the environment, i.e.
167
+ whether the environment is portable. If this returns False, the deployment
168
+ path is considered for the deployment hash. For example, conda environments are not
169
+ portable because they hardcode the path in binaries, while containers are
170
+ portable.
171
+ """
172
+ return True
173
+
174
+ async def deploy(self) -> None:
175
+ """Deploy the environment to self.deployment_path.
176
+
177
+ When issuing shell commands, the environment should use
178
+ self.run_cmd(cmd: str) in order to ensure that it runs within eventual
179
+ parent environments (e.g. a container or an env module).
180
+ """
181
+ deploy_cmd = self.runtime_manager.deploy_cmd()
182
+ assert deploy_cmd is not None
183
+ self.deployment_path.mkdir(parents=True, exist_ok=True)
184
+ self.run_cmd(
185
+ deploy_cmd,
186
+ check=True,
187
+ )
188
+
189
+ def remove(self) -> None:
190
+ """Remove the deployed environment."""
191
+ if (
192
+ self.is_deployable()
193
+ and self.runtime_manager.deployed_image_path() is not None
194
+ ):
195
+ self.runtime_manager.deployed_image_path.unlink(missing_ok=True)
196
+
197
+ def is_deployable(self) -> bool:
198
+ return (
199
+ self.settings.runtime is Runtime.UDOCKER
200
+ or self.settings.runtime is Runtime.APPTAINER
201
+ )
202
+
162
203
 
163
204
  @dataclass
164
205
  class RuntimeManager:
165
206
  env: Env
166
207
 
208
+ def deployed_image_name(self) -> str:
209
+ return (
210
+ self.env.spec.image_uri.replace("/", "_")
211
+ .replace(":", "_")
212
+ .replace("#", "_")
213
+ )
214
+
215
+ @abstractmethod
216
+ def deployed_image_path(self) -> Path | None: ...
217
+
218
+ @abstractmethod
219
+ def deploy_cmd(self) -> str | None: ...
220
+
221
+ def pre_subcommand_options(self) -> str:
222
+ return ""
223
+
167
224
  def options(self) -> str:
168
225
  return "--rm"
169
226
 
@@ -202,7 +259,9 @@ class RuntimeManager:
202
259
  def decorate_shellcmd(self, cmd: str) -> str:
203
260
  mountpoints = self.get_mountpoint_args()
204
261
  return (
205
- f"{self.env.settings.runtime} {self.subcommand()}"
262
+ f"{self.env.settings.runtime}"
263
+ f" {self.pre_subcommand_options()}"
264
+ f" {self.subcommand()}"
206
265
  f" {self.options()}"
207
266
  f" {self.workdir_option()} {getcwd()!r}" # Working directory inside container
208
267
  f" {mountpoints}"
@@ -234,6 +293,14 @@ class RuntimeManagerApptainer(RuntimeManager):
234
293
  return super().image_uri()
235
294
  return f"docker://{super().image_uri()}"
236
295
 
296
+ def deployed_image_path(self) -> Path | None:
297
+ return (self.env.deployment_path / self.deployed_image_name()).with_suffix(
298
+ ".sif"
299
+ )
300
+
301
+ def deploy_cmd(self) -> str | None:
302
+ return f"apptainer pull {self.deployed_image_path()} {self.image_uri()}"
303
+
237
304
 
238
305
  class RuntimeManagerDocker(RuntimeManager):
239
306
  def options(self) -> str:
@@ -248,11 +315,27 @@ class RuntimeManagerDocker(RuntimeManager):
248
315
  options += f" --env {env_var}"
249
316
  return options
250
317
 
318
+ def deployed_image_path(self) -> Path | None:
319
+ return None
320
+
321
+ def deploy_cmd(self) -> str | None:
322
+ # No need to deploy anything in docker, the daemon handles that on the fly.
323
+ return None
324
+
251
325
 
252
326
  class RuntimeManagerUdocker(RuntimeManager):
327
+ def pre_subcommand_options(self) -> str:
328
+ return "--quiet"
329
+
253
330
  def options(self) -> str:
254
331
  options = super().options()
255
332
  options += " --nobanner --env TINI_SUBREAPER=1"
256
333
  for env_var in self.env.envvars:
257
334
  options += f" --env {env_var}={os.environ[env_var]}"
258
335
  return options
336
+
337
+ def deployed_image_path(self) -> Path | None:
338
+ return None
339
+
340
+ def deploy_cmd(self) -> str | None:
341
+ return f"UDOCKER_DIR={self.env.deployment_path} udocker pull {self.image_uri()}"