From 994b1510766083df7f22d10c0e6e4bb65ffdd710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20K=C3=B6ster?= Date: Wed, 2 Mar 2022 14:24:24 +0100 Subject: [PATCH] fix: fix a bug leading to duplicate conda env initializations; fix display of jobs and output files with changes --- snakemake/dag.py | 1 + snakemake/deployment/conda.py | 20 ++++++++++++++++++++ snakemake/persistence.py | 20 ++++++++++++-------- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/snakemake/dag.py b/snakemake/dag.py index 137c71d7c..7ee6c9b72 100755 --- a/snakemake/dag.py +++ b/snakemake/dag.py @@ -282,6 +282,7 @@ def create_conda_envs( for job in jobs if job.conda_env_spec and (self.workflow.run_local or job.is_local) } + # Then based on md5sum values self.conda_envs = dict() for (env_spec, simg_url) in env_set: diff --git a/snakemake/deployment/conda.py b/snakemake/deployment/conda.py index c2becbfbd..82145ed31 100644 --- a/snakemake/deployment/conda.py +++ b/snakemake/deployment/conda.py @@ -696,6 +696,14 @@ def is_file(self): def contains_wildcard(self): ... + @abstractmethod + def __hash__(self): + ... + + @abstractmethod + def __eq__(self): + ... + class CondaEnvFileSpec(CondaEnvSpec): def __init__(self, filepath: str, rule=None): @@ -731,6 +739,12 @@ def is_file(self): def contains_wildcard(self): return contains_wildcard(self.file) + def __hash__(self): + return hash(self.file) + + def __eq__(self, other): + return self.file == other.file + class CondaEnvNameSpec(CondaEnvSpec): def __init__(self, name: str): @@ -756,6 +770,12 @@ def check(self): def contains_wildcard(self): return contains_wildcard(self.name) + def __hash__(self): + return hash(self.name) + + def __eq__(self, other): + return self.name == other.name + def is_conda_env_file(spec: str): return spec.endswith(".yaml") or spec.endswith(".yml") diff --git a/snakemake/persistence.py b/snakemake/persistence.py index 4f5338946..68853cf8a 100755 --- a/snakemake/persistence.py +++ b/snakemake/persistence.py @@ -323,36 +323,40 @@ def code(self, path): return self.metadata(path).get("code") def version_changed(self, job, file=None): - """Yields output files with changed versions of bool if file given.""" + """Yields output files with changed versions or bool if file given.""" return _bool_or_gen(self._version_changed, job, file=file) def code_changed(self, job, file=None): - """Yields output files with changed code of bool if file given.""" + """Yields output files with changed code or bool if file given.""" return _bool_or_gen(self._code_changed, job, file=file) def input_changed(self, job, file=None): - """Yields output files with changed input of bool if file given.""" + """Yields output files with changed input or bool if file given.""" return _bool_or_gen(self._input_changed, job, file=file) def params_changed(self, job, file=None): - """Yields output files with changed params of bool if file given.""" + """Yields output files with changed params or bool if file given.""" return _bool_or_gen(self._params_changed, job, file=file) def _version_changed(self, job, file=None): assert file is not None - return self.version(file) != job.rule.version + recorded = self.version(file) + return recorded is not None and recorded != job.rule.version def _code_changed(self, job, file=None): assert file is not None - return self.code(file) != self._code(job.rule) + recorded = self.code(file) + return recorded is not None and recorded != self._code(job.rule) def _input_changed(self, job, file=None): assert file is not None - return self.input(file) != self._input(job) + recorded = self.input(file) + return recorded is not None and recorded != self._input(job) def _params_changed(self, job, file=None): assert file is not None - return self.params(file) != self._params(job) + recorded = self.params(file) + return recorded is not None and recorded != self._params(job) def noop(self, *args): pass