Repository: snakemake/snakemake-wrappers
Pull request #3714: feat: Add jackhmmer wrapper from hmmer package.
Author: login: thomasmulvaney
Created: 2025-03-11T14:42:16Z | Merged: 2025-03-12T22:01:02Z

This builds on earlier work of N. Tessa Pierce who added many commands from the hmmer suite. 
Here, I include the jackhmmer tool.

<!-- Ensure that the PR title follows conventional commit style (<type>: <description>)-->
<!-- Possible types are here: https://github.com/commitizen/conventional-commit-types/blob/master/index.json -->

<!-- Add a description of your PR here-->

### QC
<!-- Make sure that you can tick the boxes below. -->

* [x] I confirm that I have followed the [documentation for contributing to `snakemake-wrappers`](https://snakemake-wrappers.readthedocs.io/en/stable/contributing.html).

While the contributions guidelines are more extensive, please particularly ensure that:
* [x] `test.py` was updated to call any added or updated example rules in a `Snakefile`
* [x] `input:` and `output:` file paths in the rules can be chosen arbitrarily
* [ ] wherever possible, command line arguments are inferred and set automatically (e.g. based on file extensions in `input:` or `output:`)
* [ ] temporary files are either written to a unique hidden folder in the working directory, or (better) stored where the Python function `tempfile.gettempdir()` points to 
* [x] the `meta.yaml` contains a link to the documentation of the respective tool or command under `url:`
* [x] conda environments use a minimal amount of channels and packages, in recommended ordering


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced configuration files to streamline setting up a Conda environment on Linux 64-bit systems.
  - Enhanced the sequence search tool with detailed metadata and an integrated execution process.
  - Added new input files for testing the `jackhmmer` tool.

- **Tests**
  - Added automated tests and improved command formatting to boost overall reliability and consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/bio/hmmer/jackhmmer/environment.linux-64.pin.txt b/bio/hmmer/jackhmmer/environment.linux-64.pin.txt
new file mode 100644
index 00000000000..7a50b70aef7
--- /dev/null
+++ b/bio/hmmer/jackhmmer/environment.linux-64.pin.txt
@@ -0,0 +1,10 @@
+# This file may be used to create an environment using:
+# $ conda create --name <env> --file <this file>
+# platform: linux-64
+@EXPLICIT
+https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81
+https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-h7e041cc_3.conda#937eaed008f6bf2191c5fe76f87755e9
+https://conda.anaconda.org/conda-forge/linux-64/libgomp-13.2.0-h807b86a_3.conda#7124cbb46b13d395bdde68f2d215c989
+https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d
+https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-13.2.0-h807b86a_3.conda#23fdf1fef05baeb7eadc2aed5fb0011f
+https://conda.anaconda.org/bioconda/linux-64/hmmer-3.4-hdbdd923_0.tar.bz2#6bd688f98d54a7118bd655b12e4d2c34
diff --git a/bio/hmmer/jackhmmer/environment.yaml b/bio/hmmer/jackhmmer/environment.yaml
new file mode 100644
index 00000000000..3f36064d15c
--- /dev/null
+++ b/bio/hmmer/jackhmmer/environment.yaml
@@ -0,0 +1,6 @@
+channels:
+  - conda-forge
+  - bioconda
+  - nodefaults
+dependencies:
+  - hmmer =3.4
diff --git a/bio/hmmer/jackhmmer/meta.yaml b/bio/hmmer/jackhmmer/meta.yaml
new file mode 100644
index 00000000000..1a0efd85618
--- /dev/null
+++ b/bio/hmmer/jackhmmer/meta.yaml
@@ -0,0 +1,15 @@
+name: jackhmmer
+description: "search profile(s) against a sequence database"
+url: http://hmmer.org/
+authors:
+  - Thomas Mulvaney
+input:
+  - query: query file in FASTA format
+  - db: database file in FASTA format.
+output:
+  - hits_tbl: table of per-sequence hits (optional)
+  - hits_aln: multiple sequence alignment (MSA) in Stockholm format of all significant hits (optional)
+  - dom_tbl: table of per-domain hits (optional)
+  - summary: human-readable output (optional)
+citations:
+  - "`Johnson, L.S., Eddy, S.R. & Portugaly, E. Hidden Markov model speed heuristic and iterative HMM search procedure. BMC Bioinformatics 11, 431 (2010). <https://doi.org/10.1186/1471-2105-11-431>`_"
diff --git a/bio/hmmer/jackhmmer/test/Snakefile b/bio/hmmer/jackhmmer/test/Snakefile
new file mode 100644
index 00000000000..3f5bb454723
--- /dev/null
+++ b/bio/hmmer/jackhmmer/test/Snakefile
@@ -0,0 +1,17 @@
+rule jackhmmer:
+    input:
+        db="test-protein.fa",
+        query="query.fa"
+    output:
+        hits_tbl="test-prot-tbl.txt",
+        hits_aln="test-prot-alignment-hits.sto",
+        dom_tbl="test-prot-domtbl.txt",
+        summary="test-prot-out1.txt",
+    log:
+        "logs/jackhmmer.log"
+    params:
+       # Additional flags can be set using extra, for example:
+       extra="-E 0.001 --F1=0.005"
+    threads: 4
+    wrapper:
+        "master/bio/hmmer/jackhmmer"
diff --git a/bio/hmmer/jackhmmer/test/query.fa b/bio/hmmer/jackhmmer/test/query.fa
new file mode 100644
index 00000000000..9e8d03b8f21
--- /dev/null
+++ b/bio/hmmer/jackhmmer/test/query.fa
@@ -0,0 +1,2 @@
+>query
+WPVKSANFILDLLKNAE
diff --git a/bio/hmmer/jackhmmer/test/test-protein.fa b/bio/hmmer/jackhmmer/test/test-protein.fa
new file mode 100644
index 00000000000..b579067a536
--- /dev/null
+++ b/bio/hmmer/jackhmmer/test/test-protein.fa
@@ -0,0 +1,5 @@
+>test_protein
+MVKYSREPDNPTKSCKARGSDLRVHFKNTRETAHAIRKMQLGKAKSYLEDVLAHKQAIPF
+RRFCRGVGRTAQAKNRQSNGQGRWPVKSANFILDLLKNAESNAEVKGLDVDSLYVSHIQV
+NQAQKQRRRTYRAHGRINPYMSSPCHIELVLSEKEEPVKKEPETQLAPRKSRKGQALHSG
+AS
diff --git a/bio/hmmer/jackhmmer/wrapper.py b/bio/hmmer/jackhmmer/wrapper.py
new file mode 100644
index 00000000000..c086fff65a5
--- /dev/null
+++ b/bio/hmmer/jackhmmer/wrapper.py
@@ -0,0 +1,34 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+extra = snakemake.params.get("extra", "")
+log = snakemake.log_fmt_shell(stdout=False, stderr=True)
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = f" -o {snakemake.output.get('summary', '/dev/null')}"
+
+if snakemake.output.get("hits_tbl") is not None:
+    out_cmd += f" --tblout {snakemake.output.get('hits_tbl')}"
+
+if snakemake.output.get("dom_tbl") is not None:
+    out_cmd += f" --domtblout {snakemake.output.get('dom_tbl')}"
+
+if snakemake.output.get("hits_aln") is not None:
+    out_cmd += f" -A {snakemake.output.get('hits_aln')}"
+
+shell(
+    "jackhmmer --cpu {snakemake.threads}"
+    " {extra}"
+    " {out_cmd}"
+    " {snakemake.input.query}"
+    " {snakemake.input.db}"
+    " {log}"
+)
diff --git a/test_wrappers.py b/test_wrappers.py
index 83b000150eb..bb916709889 100644
--- a/test_wrappers.py
+++ b/test_wrappers.py
@@ -113,7 +113,7 @@ def _run(wrapper, cmd, check_log=None, compare_results_with_expected=None):
             subprocess.check_call(cmd)
             if compare_results_with_expected:
                 for generated, expected in compare_results_with_expected.items():
-                    assert(filecmp.cmp(generated, expected, shallow=False))
+                    assert filecmp.cmp(generated, expected, shallow=False)
         except Exception as e:
             # go back to original directory
             os.chdir(origdir)
@@ -464,6 +464,7 @@ def test_seqkit_concat(run):
         ],
     )
 
+
 def test_seqkit_split2_part(run):
     run(
         "bio/seqkit",
@@ -5358,6 +5359,13 @@ def test_hmmsearch(run):
     )
 
 
+def test_jackhmmer(run):
+    run(
+        "bio/hmmer/jackhmmer",
+        ["snakemake", "--cores", "1", "test-prot-tbl.txt", "--use-conda", "-F"],
+    )
+
+
 def test_paladin_index(run):
     run(
         "bio/paladin/index",
@@ -5456,7 +5464,7 @@ def test_ensembl_sequence_multiple_chromosomes(run):
         ["snakemake", "--cores", "1", "refs/chr6_and_chr1.fasta", "--use-conda", "-F"],
         compare_results_with_expected={
             "refs/chr6_and_chr1.fasta": "expected/chr6_and_chr1.fasta"
-        }
+        },
     )
 
 
@@ -6760,15 +6768,9 @@ def test_overturemaps_download(run):
         ],
     )
 
+
 def test_pygadm_item(run):
     run(
         "geo/pygadm/item",
-        [
-            "snakemake",
-            "--cores",
-            "2",
-            "--use-conda",
-            "-F",
-            "results/mexico.parquet"
-        ]
-    )
\ No newline at end of file
+        ["snakemake", "--cores", "2", "--use-conda", "-F", "results/mexico.parquet"],
+    )


Reviews:
user: login: coderabbitai[bot]
body: > [!CAUTION]
> Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.  If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

**Actionable comments posted: 3**

<details>
<summary>🧹 Nitpick comments (4)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/environment.yaml (1)</summary><blockquote>

`1-7`: **Conda Environment Configuration Review.**  
The YAML file properly specifies the conda channels and dependencies. One minor nitpick: consider using the standard dependency format without extra whitespace (e.g. `hmmer=3.4` instead of `hmmer =3.4`) to ensure maximum compatibility with conda parsers.

</blockquote></details>
<details>
<summary>bio/hmmer/jackhmmer/meta.yaml (1)</summary><blockquote>

`1-12`: **Metadata File Clarity.**  
The meta.yaml file clearly provides the tool’s name, description, authorship, input/output specifications, and relevant citations. For consistency, consider removing the trailing period from the second input description (i.e. “database file in FASTA format.” → “database file in FASTA format”) so that the style matches the other entries.

</blockquote></details>
<details>
<summary>bio/hmmer/jackhmmer/test/Snakefile (1)</summary><blockquote>

`1-30`: **LGTM, with minor formatting consistency suggestion**

The Snakefile rule is well-structured with clear input/output definitions and helpful comments explaining the purpose of each output file and parameter.

The rule appropriately handles mutually exclusive parameters with clear comments, and the thread specification and wrapper reference look good.


Consider standardizing indentation (line 14 uses tabs while other lines use spaces):

```diff
-	# Setting both will raise an error.
+        # Setting both will raise an error.
```

And similarly on lines 23-24:
```diff
-	# There are three filter parameters to tuned.  Not setting these will use the
-	# defaults of jackhmmer
+        # There are three filter parameters to tuned.  Not setting these will use the
+        # defaults of jackhmmer
```

</blockquote></details>
<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (1)</summary><blockquote>

`8-10`: **Remove unused import**

The `path` import from `os` is not used in the code.

```diff
-from os import path
 from snakemake.shell import shell
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🛑 Comments failed to post (3)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (3)</summary><blockquote>

44-46: _🛠️ Refactor suggestion_

**Update function name references**

Update calls to match the corrected function name.

```diff
# Raise an error if any of these are set at the same time
-exlusive_parameters(["evalue_threshold", "tvalue_threshold"])
-exlusive_parameters(["inclusion_evalue", "inclusion_tvalue"])
+exclusive_parameters(["evalue_threshold", "tvalue_threshold"])
+exclusive_parameters(["inclusion_evalue", "inclusion_tvalue"])
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
# Raise an error if any of these are set at the same time
exclusive_parameters(["evalue_threshold", "tvalue_threshold"])
exclusive_parameters(["inclusion_evalue", "inclusion_tvalue"])
`````

</details>

<!-- suggestion_end -->

---

11-12: _⚠️ Potential issue_

**Fix input variable name mismatch**

The variable `query_file` is assigned from `snakemake.input.get("query")` but the shell command uses `snakemake.input.query_file`. This will cause an error when executing the wrapper.

```diff
-query_file = snakemake.input.get("query")
+# No need to extract the query_file separately, use snakemake.input.query_file directly in the command
```

Alternatively, if you want to keep the variable:
```diff
-query_file = snakemake.input.get("query")
+query_file = snakemake.input.get("query_file")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
query_file = snakemake.input.get("query_file")
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

11-11: Undefined name `snakemake`

(F821)

</details>

</details>

---

13-23: _🛠️ Refactor suggestion_

**Fix typo in function name and logic issue**

There's a typo in the function name and the exclusivity check logic has an issue.

```diff
# Some parameters are mutually exclusive
-def exlusive_parameters(params):
+def exclusive_parameters(params):
    num_set = 0
    for p in params:
        if snakemake.params.get(p) is not None:
            num_set += 1
-        if num_set > 1:
-            raise Exception(
-                f"Only one of the parameters {', '.join(params)} can be set at a time"
-            )
+    if num_set > 1:
+        raise Exception(
+            f"Only one of the parameters {', '.join(params)} can be set at a time"
+        )
```

The current implementation could raise an exception before checking all parameters, which may lead to confusing error messages. Moving the check outside the loop ensures all parameters are evaluated before determining exclusivity.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
# Some parameters are mutually exclusive
def exclusive_parameters(params):
    num_set = 0
    for p in params:
        if snakemake.params.get(p) is not None:
            num_set += 1
    if num_set > 1:
        raise Exception(
            f"Only one of the parameters {', '.join(params)} can be set at a time"
        )
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

17-17: Undefined name `snakemake`

(F821)

</details>

</details>

</blockquote></details>

</blockquote></details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T14:46:59Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (2)</summary><blockquote>

`8-8`: **Remove unused import**

The `os.path` module is imported but never used in the code.

```diff
-from os import path
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

</details>

</details>

---

`11-11`: **Add a check for required input files**

The wrapper assumes the input files exist but doesn't validate their presence.

```diff
-query_file = snakemake.input.get("query")
+query_file = snakemake.input.get("query_file")
+if not query_file:
+    raise ValueError("Input query_file is required")
+
+database_file = snakemake.input.get("database_file")
+if not database_file:
+    raise ValueError("Input database_file is required")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

11-11: Undefined name `snakemake`

(F821)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 7611e9cd31e80d2d413c1dd338f3bfcc95b451a8 and 6be66c9fc64bcfe7035d1feb6ec76a8d599eb08a.

</details>

<details>
<summary>📒 Files selected for processing (8)</summary>

* `bio/hmmer/jackhmmer/environment.linux-64.pin.txt` (1 hunks)
* `bio/hmmer/jackhmmer/environment.yaml` (1 hunks)
* `bio/hmmer/jackhmmer/meta.yaml` (1 hunks)
* `bio/hmmer/jackhmmer/test/Snakefile` (1 hunks)
* `bio/hmmer/jackhmmer/test/query.fa` (1 hunks)
* `bio/hmmer/jackhmmer/test/test-protein.fa` (1 hunks)
* `bio/hmmer/jackhmmer/wrapper.py` (1 hunks)
* `test_wrappers.py` (5 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (6)</summary>

* bio/hmmer/jackhmmer/environment.yaml
* bio/hmmer/jackhmmer/test/test-protein.fa
* bio/hmmer/jackhmmer/meta.yaml
* bio/hmmer/jackhmmer/environment.linux-64.pin.txt
* bio/hmmer/jackhmmer/test/query.fa
* bio/hmmer/jackhmmer/test/Snakefile

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (2)</summary>

<details>
<summary>`**/*.py`: Do not try to improve formatting.
Do not suggest ...</summary>

> `**/*.py`: Do not try to improve formatting.
> Do not suggest type annotations for functions that are defined inside of functions or methods.
> Do not suggest type annotation of the `self` argument of methods.
> Do not suggest type annotation of the `cls` argument of classmethods.
> Do not suggest return type annotation if a function or method does not contain a `return` statement.

- `test_wrappers.py`
- `bio/hmmer/jackhmmer/wrapper.py`

</details>
<details>
<summary>`**/wrapper.py`: Do not complain about use of undefined vari...</summary>

> `**/wrapper.py`: Do not complain about use of undefined variable called `snakemake`.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

11-11: Undefined name `snakemake`

(F821)

---

17-17: Undefined name `snakemake`

(F821)

---

50-50: Undefined name `snakemake`

(F821)

---

55-55: Undefined name `snakemake`

(F821)

---

59-59: Undefined name `snakemake`

(F821)

</details>

</details>
<details>
<summary>🪛 GitHub Actions: Code quality</summary>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py</summary>

[error] 1-1: Black formatting check failed. 1 file would be reformatted. Please run 'black' to fix code style issues in this file.

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: testing
* GitHub Check: docs
* GitHub Check: Summary

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (1)</summary>

`1-66`: <details>
<summary>❓ Verification inconclusive</summary>

**Address Black formatting error in CI pipeline**

The CI pipeline indicates a formatting issue with this file. While I won't suggest specific formatting changes as per your guidelines, please run Black on this file to resolve the formatting issues before merging.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if this file would be reformatted by black
black --check bio/hmmer/jackhmmer/wrapper.py
```

Length of output: 142

---



</details>

**Manual Verification of Black Formatting Required**

The CI pipeline reported a formatting error for this file, but the automated check failed because Black isn't installed in the environment. Please ensure that Black is available (or run it locally) and verify that the file is properly formatted before merging.

- Confirm Black is installed in your CI or local environment.
- Run `black --check bio/hmmer/jackhmmer/wrapper.py` to verify formatting.
- Reformat the file with Black if any issues are detected.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

11-11: Undefined name `snakemake`

(F821)

---

17-17: Undefined name `snakemake`

(F821)

---

50-50: Undefined name `snakemake`

(F821)

---

55-55: Undefined name `snakemake`

(F821)

---

59-59: Undefined name `snakemake`

(F821)

</details>
<details>
<summary>🪛 GitHub Actions: Code quality</summary>

[error] 1-1: Black formatting check failed. 1 file would be reformatted. Please run 'black' to fix code style issues in this file.

</details>

</details>

</details>
<details>
<summary>test_wrappers.py (2)</summary>

`5362-5367`: **Looks good - new test for jackhmmer wrapper added correctly.**

The test function follows the standard pattern used throughout the file and properly tests the jackhmmer wrapper functionality.

---

`6773-6776`: **Code formatting looks good.**

The command list formatting in test_pygadm_item has been simplified to a single line, which is consistent with other test functions in the file.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T14:51:39Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>♻️ Duplicate comments (3)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (3)</summary><blockquote>

`11-11`: _⚠️ Potential issue_

**Ensure consistent naming of input variables**

The query file is accessed here using `get("query")`, but in the shell command (line 64), it's accessed directly as `snakemake.input.query_file`.


```diff
-query_file = snakemake.input.get("query")
+query_file = snakemake.input.get("query_file")
```

Alternatively, adjust the shell command to match this variable name.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

11-11: Undefined name `snakemake`

(F821)

</details>

</details>

---

`14-22`: _⚠️ Potential issue_

**Fix logical issue in exclusive_parameters implementation**

The check for multiple parameters being set should be outside the loop to correctly validate all parameters.


```diff
def exclusive_parameters(params):
    num_set = 0
    for p in params:
        if snakemake.params.get(p) is not None:
            num_set += 1
-        if num_set > 1:
-            raise Exception(
-                f"Only one of the parameters {', '.join(params)} can be set at a time"
-            )
+    if num_set > 1:
+        raise Exception(
+            f"Only one of the parameters {', '.join(params)} can be set at a time"
+        )
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

17-17: Undefined name `snakemake`

(F821)

</details>

</details>

---

`64-64`: _⚠️ Potential issue_

**Fix inconsistent input variable references**

The shell command references `query_file` and `database_file` directly, but earlier code uses a different approach to access the query file.


```diff
- " {snakemake.input.query_file} {snakemake.input.database_file} {log}"
+ " {query_file} {snakemake.input.database_file} {log}"
```

Alternatively, update line 11 to be consistent with how inputs are accessed here.

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (2)</summary><blockquote>

`8-8`: **Remove unused import**

The `path` import from `os` is not used anywhere in the code.

```diff
-from os import path
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

</details>

</details>

---

`1-66`: <details>
<summary>❓ Verification inconclusive</summary>

**Fix formatting issues with Black**

The code failed Black formatting checks. Format this file with Black to comply with project style guidelines.

---

🏁 Script executed:

```shell
#!/bin/bash
# Run Black formatting check on this file
black --check bio/hmmer/jackhmmer/wrapper.py
```

Length of output: 142

---



</details>

**Attention: Black Formatting Verification Needed**

The automated Black check could not be performed because the tool isn't available in the current environment. Please ensure that Black is installed and then verify that `bio/hmmer/jackhmmer/wrapper.py` complies with the project's Black formatting guidelines. If necessary, run the Black formatting check manually to confirm that no formatting issues persist.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

11-11: Undefined name `snakemake`

(F821)

---

17-17: Undefined name `snakemake`

(F821)

---

50-50: Undefined name `snakemake`

(F821)

---

55-55: Undefined name `snakemake`

(F821)

---

59-59: Undefined name `snakemake`

(F821)

</details>
<details>
<summary>🪛 GitHub Actions: Code quality</summary>

[error] 1-1: Black formatting check failed. 1 file would be reformatted. Please run 'black' to fix code style issues in this file.

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 6be66c9fc64bcfe7035d1feb6ec76a8d599eb08a and 4bc4400173cf3e0a89e3adda93cff892ab1bbd23.

</details>

<details>
<summary>📒 Files selected for processing (8)</summary>

* `bio/hmmer/jackhmmer/environment.linux-64.pin.txt` (1 hunks)
* `bio/hmmer/jackhmmer/environment.yaml` (1 hunks)
* `bio/hmmer/jackhmmer/meta.yaml` (1 hunks)
* `bio/hmmer/jackhmmer/test/Snakefile` (1 hunks)
* `bio/hmmer/jackhmmer/test/query.fa` (1 hunks)
* `bio/hmmer/jackhmmer/test/test-protein.fa` (1 hunks)
* `bio/hmmer/jackhmmer/wrapper.py` (1 hunks)
* `test_wrappers.py` (5 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (7)</summary>

* bio/hmmer/jackhmmer/test/query.fa
* bio/hmmer/jackhmmer/test/test-protein.fa
* bio/hmmer/jackhmmer/test/Snakefile
* bio/hmmer/jackhmmer/meta.yaml
* test_wrappers.py
* bio/hmmer/jackhmmer/environment.yaml
* bio/hmmer/jackhmmer/environment.linux-64.pin.txt

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (2)</summary>

<details>
<summary>`**/*.py`: Do not try to improve formatting.
Do not suggest ...</summary>

> `**/*.py`: Do not try to improve formatting.
> Do not suggest type annotations for functions that are defined inside of functions or methods.
> Do not suggest type annotation of the `self` argument of methods.
> Do not suggest type annotation of the `cls` argument of classmethods.
> Do not suggest return type annotation if a function or method does not contain a `return` statement.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>
<details>
<summary>`**/wrapper.py`: Do not complain about use of undefined vari...</summary>

> `**/wrapper.py`: Do not complain about use of undefined variable called `snakemake`.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

11-11: Undefined name `snakemake`

(F821)

---

17-17: Undefined name `snakemake`

(F821)

---

50-50: Undefined name `snakemake`

(F821)

---

55-55: Undefined name `snakemake`

(F821)

---

59-59: Undefined name `snakemake`

(F821)

</details>

</details>
<details>
<summary>🪛 GitHub Actions: Code quality</summary>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py</summary>

[error] 1-1: Black formatting check failed. 1 file would be reformatted. Please run 'black' to fix code style issues in this file.

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: docs
* GitHub Check: testing
* GitHub Check: Summary

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T15:31:30Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>♻️ Duplicate comments (2)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (2)</summary><blockquote>

`63-63`: _⚠️ Potential issue_

**Fix inconsistent input variable references**

The shell command references `query_file` and `database_file` directly, but there's no clear definition of these input variables. Consider using a consistent approach to access input files.



Either define these variables explicitly before using them in the shell command:

```diff
+query_file = snakemake.input.query_file
+database_file = snakemake.input.database_file
 shell(
     " jackhmmer --cpu {snakemake.threads} "
     " {out_cmd} {param_cmd} "
-    " {snakemake.input.query_file} {snakemake.input.database_file} {log}"
+    " {query_file} {database_file} {log}"
 )
```

Or ensure your Snakefile defines these exact input names.

---

`13-21`: _⚠️ Potential issue_

**Fix logical issue in `exclusive_parameters` implementation**

The check for multiple parameters being set should be outside the loop to correctly validate all parameters.

```diff
def exclusive_parameters(params):
    num_set = 0
    for p in params:
        if snakemake.params.get(p) is not None:
            num_set += 1
-        if num_set > 1:
-            raise Exception(
-                f"Only one of the parameters {', '.join(params)} can be set at a time"
-            )
+    if num_set > 1:
+        raise Exception(
+            f"Only one of the parameters {', '.join(params)} can be set at a time"
+        )
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

16-16: Undefined name `snakemake`

(F821)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (4)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (4)</summary><blockquote>

`8-8`: **Remove unused import**

The `path` import from `os` is not being used anywhere in the code.

```diff
-from os import path
+from snakemake.shell import shell
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

</details>

</details>

---

`47-49`: **Consider handling missing output parameters**

The current implementation doesn't check if an output parameter exists before adding it to the command. This could lead to errors if certain output parameters are not defined.

```diff
out_cmd = ""
for flag, snake_param_name, default in output_parameters:
-    out_cmd += f" {flag} {snakemake.output.get(snake_param_name, default)}"
+    output_value = snakemake.output.get(snake_param_name)
+    if output_value is not None:
+        out_cmd += f" {flag} {output_value}"
+    elif default:
+        out_cmd += f" {flag} {default}"
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

49-49: Undefined name `snakemake`

(F821)

</details>

</details>

---

`58-64`: **Add error handling for failed command execution**

The shell command doesn't include any error handling. Consider adding error handling to provide more informative error messages.

```diff
log = snakemake.log_fmt_shell(stdout=False, stderr=True)

+try:
    shell(
        " jackhmmer --cpu {snakemake.threads} "
        " {out_cmd} {param_cmd} "
        " {snakemake.input.query_file} {snakemake.input.database_file} {log}"
    )
+except Exception as e:
+    raise WorkflowError(f"Error executing jackhmmer: {e}")
```

Note: You would need to add `from snakemake.exceptions import WorkflowError` to the imports.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

58-58: Undefined name `snakemake`

(F821)

</details>

</details>

---

`1-10`: **Consider adding more detailed documentation**

The wrapper would benefit from more detailed documentation, including information about required inputs and outputs, available parameters, and examples of usage.

```diff
-"""Snakemake wrapper for jackhmmer"""
+"""Snakemake wrapper for jackhmmer
+
+This wrapper provides a way to use jackhmmer from the HMMER package
+in Snakemake workflows.
+
+Required inputs:
+    query_file: Path to query sequence file
+    database_file: Path to database file
+
+Outputs:
+    outfile: Path to output file
+    tblout: Path to table output file (optional)
+    domtblout: Path to domain table output file (optional)
+    alignment_hits: Path to alignment hits file (optional)
+
+Parameters:
+    evalue_threshold: E-value threshold (mutually exclusive with tvalue_threshold)
+    tvalue_threshold: T-value threshold (mutually exclusive with evalue_threshold)
+    inclusion_evalue: Inclusion E-value threshold (mutually exclusive with inclusion_tvalue)
+    inclusion_tvalue: Inclusion T-value threshold (mutually exclusive with inclusion_evalue)
+    filter1: Filter parameter 1
+    filter2: Filter parameter 2
+    filter3: Filter parameter 3
+"""
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 4bc4400173cf3e0a89e3adda93cff892ab1bbd23 and 77ea3da87461d9599e5e76b20075ad8ba5010616.

</details>

<details>
<summary>📒 Files selected for processing (8)</summary>

* `bio/hmmer/jackhmmer/environment.linux-64.pin.txt` (1 hunks)
* `bio/hmmer/jackhmmer/environment.yaml` (1 hunks)
* `bio/hmmer/jackhmmer/meta.yaml` (1 hunks)
* `bio/hmmer/jackhmmer/test/Snakefile` (1 hunks)
* `bio/hmmer/jackhmmer/test/query.fa` (1 hunks)
* `bio/hmmer/jackhmmer/test/test-protein.fa` (1 hunks)
* `bio/hmmer/jackhmmer/wrapper.py` (1 hunks)
* `test_wrappers.py` (5 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (7)</summary>

* bio/hmmer/jackhmmer/test/query.fa
* bio/hmmer/jackhmmer/meta.yaml
* bio/hmmer/jackhmmer/environment.yaml
* bio/hmmer/jackhmmer/test/test-protein.fa
* bio/hmmer/jackhmmer/environment.linux-64.pin.txt
* bio/hmmer/jackhmmer/test/Snakefile
* test_wrappers.py

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (2)</summary>

<details>
<summary>`**/*.py`: Do not try to improve formatting.
Do not suggest ...</summary>

> `**/*.py`: Do not try to improve formatting.
> Do not suggest type annotations for functions that are defined inside of functions or methods.
> Do not suggest type annotation of the `self` argument of methods.
> Do not suggest type annotation of the `cls` argument of classmethods.
> Do not suggest return type annotation if a function or method does not contain a `return` statement.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>
<details>
<summary>`**/wrapper.py`: Do not complain about use of undefined vari...</summary>

> `**/wrapper.py`: Do not complain about use of undefined variable called `snakemake`.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

16-16: Undefined name `snakemake`

(F821)

---

49-49: Undefined name `snakemake`

(F821)

---

54-54: Undefined name `snakemake`

(F821)

---

58-58: Undefined name `snakemake`

(F821)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: docs
* GitHub Check: testing
* GitHub Check: Summary

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T15:38:26Z
user: login: fgvieira
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T15:53:25Z
user: login: fgvieira
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T15:56:04Z
user: login: fgvieira
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T15:58:54Z
user: login: fgvieira
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T16:00:44Z
user: login: thomasmulvaney
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T09:12:21Z
user: login: thomasmulvaney
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T09:12:47Z
user: login: thomasmulvaney
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T09:13:33Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>🔭 Outside diff range comments (2)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (2)</summary><blockquote>

`1-39`: _⚠️ Potential issue_

**Add missing exclusive_parameters function**

Based on previous review comments, there should be an `exclusive_parameters` function to ensure only one parameter from a list can be set at a time. This function is missing from the current implementation.

Add the following function before line 11:

```python
def exclusive_parameters(params):
    num_set = 0
    for p in params:
        if snakemake.params.get(p) is not None:
            num_set += 1
    if num_set > 1:
        raise Exception(
            f"Only one of the parameters {', '.join(params)} can be set at a time"
        )
```

Then add the necessary function calls before the shell command:

```python
# Add parameter validation
exclusive_parameters(["evalue_threshold", "tvalue_threshold"])
exclusive_parameters(["inclusion_evalue", "inclusion_tvalue"])
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

20-20: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

---

23-23: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

---

26-26: Undefined name `snakemake`

(F821)

---

28-28: Undefined name `snakemake`

(F821)

---

29-29: Undefined name `snakemake`

(F821)

---

31-31: Undefined name `snakemake`

(F821)

---

32-32: Undefined name `snakemake`

(F821)

</details>
<details>
<summary>🪛 GitHub Actions: Code quality</summary>

[error] 1-1: Black formatting check failed. 1 file would be reformatted. Please run 'black' to fix code style issues in this file.

</details>

</details>

---

`1-39`: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Run Black code formatter to fix code style issues**

The pipeline is failing because the code doesn't conform to the Black formatting standards.

---

🏁 Script executed:

```shell
#!/bin/bash
# Find the CI check that's failing
cat .github/workflows/*.yml | grep -A 5 -B 5 "black"
```

Length of output: 703

---



</details>

**Fix Black formatting issues for bio/hmmer/jackhmmer/wrapper.py**

Please run the Black code formatter on the file to resolve the style issues flagged by CI. The CI workflow uses the command `black --check` on matching `wrapper.py` files, and the current formatting in lines 1–39 of this file is causing the pipeline to fail.

- **File to update:** `bio/hmmer/jackhmmer/wrapper.py` (lines 1–39)
- **Action:** Run Black (e.g., `black bio/hmmer/jackhmmer/wrapper.py`) and commit the formatted changes so that the CI check passes.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

20-20: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

---

23-23: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

---

26-26: Undefined name `snakemake`

(F821)

---

28-28: Undefined name `snakemake`

(F821)

---

29-29: Undefined name `snakemake`

(F821)

---

31-31: Undefined name `snakemake`

(F821)

---

32-32: Undefined name `snakemake`

(F821)

</details>
<details>
<summary>🪛 GitHub Actions: Code quality</summary>

[error] 1-1: Black formatting check failed. 1 file would be reformatted. Please run 'black' to fix code style issues in this file.

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (2)</summary><blockquote>

`8-8`: **Remove unused import**

The `path` import from the `os` module is not used anywhere in the code.

```diff
-from os import path
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

</details>

</details>

---

`12-16`: **Defined output_parameters list is not utilized**

You define this list of output parameters, but then don't use it in the rest of the code. Instead, you directly check for output variables. Consider either removing this unused list or refactoring the code to use it for building the output command.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 77ea3da87461d9599e5e76b20075ad8ba5010616 and b9bd2ad17901bf7ce960a2a0d28a98a3af6682c3.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `bio/hmmer/jackhmmer/test/Snakefile` (1 hunks)
* `bio/hmmer/jackhmmer/wrapper.py` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* bio/hmmer/jackhmmer/test/Snakefile

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (2)</summary>

<details>
<summary>`**/*.py`: Do not try to improve formatting.
Do not suggest ...</summary>

> `**/*.py`: Do not try to improve formatting.
> Do not suggest type annotations for functions that are defined inside of functions or methods.
> Do not suggest type annotation of the `self` argument of methods.
> Do not suggest type annotation of the `cls` argument of classmethods.
> Do not suggest return type annotation if a function or method does not contain a `return` statement.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>
<details>
<summary>`**/wrapper.py`: Do not complain about use of undefined vari...</summary>

> `**/wrapper.py`: Do not complain about use of undefined variable called `snakemake`.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

20-20: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

---

23-23: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

---

26-26: Undefined name `snakemake`

(F821)

---

28-28: Undefined name `snakemake`

(F821)

---

29-29: Undefined name `snakemake`

(F821)

---

31-31: Undefined name `snakemake`

(F821)

---

32-32: Undefined name `snakemake`

(F821)

</details>

</details>
<details>
<summary>🪛 GitHub Actions: Code quality</summary>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py</summary>

[error] 1-1: Black formatting check failed. 1 file would be reformatted. Please run 'black' to fix code style issues in this file.

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: testing
* GitHub Check: docs
* GitHub Check: Summary

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (1)</summary>

`37-37`: **Fix inconsistent input variable references**

The shell command references `query_file` and `database_file` directly, but there's no validation or consistent approach for accessing these inputs.


```shell
#!/bin/bash
# Check how inputs are supposed to be defined/accessed in the Snakefile
rg -A 5 "input:" bio/hmmer/jackhmmer/test/Snakefile
```

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T09:14:56Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>♻️ Duplicate comments (5)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (5)</summary><blockquote>

`13-13`: _⚠️ Potential issue_

**Fix tuple definition causing command building issue.**

The trailing comma at the end of this line creates a tuple instead of a string. This will cause issues when you try to append to it with `+=` in the following lines and when formatting the shell command.


```diff
-out_cmd = (f" -o {snakemake.output.get('outfile', '/dev/null')}",)
+out_cmd = f" -o {snakemake.output.get('outfile', '/dev/null')}"
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

13-13: Undefined name `snakemake`

(F821)

</details>

</details>

---

`16-16`: _⚠️ Potential issue_

**Fix tuple concatenation issue.**

Due to the trailing comma in the initial definition of `out_cmd`, this line is adding a string as a new element to a tuple rather than concatenating strings.


```diff
-    out_cmd += (f" --tblout {snakemake.output.get('tblout')}",)
+    out_cmd += f" --tblout {snakemake.output.get('tblout')}"
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

16-16: Undefined name `snakemake`

(F821)

</details>

</details>

---

`19-19`: _⚠️ Potential issue_

**Fix flag format and tuple concatenation issue.**

There are two issues here:
1. The domtblout flag should be `--domtblout` (with double dash) not `-domtblout`
2. The trailing comma creates another tuple element instead of concatenating strings



```diff
-    out_cmd += (f" --domtblout {snakemake.output.get('domtblout')}",)
+    out_cmd += f" --domtblout {snakemake.output.get('domtblout')}"
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

19-19: Undefined name `snakemake`

(F821)

</details>

</details>

---

`22-22`: _⚠️ Potential issue_

**Fix tuple concatenation issue.**

Due to the trailing comma in the initial definition of `out_cmd`, this line is adding a string as a new element to a tuple rather than concatenating strings.


```diff
-    out_cmd += (f" -A {snakemake.output.get('alignment_hits')}",)
+    out_cmd += f" -A {snakemake.output.get('alignment_hits')}"
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

22-22: Undefined name `snakemake`

(F821)

</details>

</details>

---

`11-31`: _⚠️ Potential issue_

**Add missing exclusive_parameters function.**

Based on previous comments, there should be a function to check for mutually exclusive parameters. This function is missing from the implementation.



Add the following function before building the command:

```python
def exclusive_parameters(params):
    num_set = 0
    for p in params:
        if snakemake.params.get(p) is not None:
            num_set += 1
    if num_set > 1:
        raise Exception(
            f"Only one of the parameters {', '.join(params)} can be set at a time"
        )
```

And add these function calls where appropriate:

```python
# Check for mutually exclusive parameters
exclusive_parameters(["evalue_threshold", "tvalue_threshold"])
exclusive_parameters(["inclusion_evalue", "inclusion_tvalue"])
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

13-13: Undefined name `snakemake`

(F821)

---

15-15: Undefined name `snakemake`

(F821)

---

16-16: Undefined name `snakemake`

(F821)

---

18-18: Undefined name `snakemake`

(F821)

---

19-19: Undefined name `snakemake`

(F821)

---

21-21: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

---

24-24: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (1)</summary><blockquote>

`8-8`: **Remove unused import.**

The `path` module is imported but never used in the code. Consider removing this unused import.

```diff
-from os import path
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between b9bd2ad17901bf7ce960a2a0d28a98a3af6682c3 and 740de371fd3de0fec9a291d21db0a8d88bb2688a.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `bio/hmmer/jackhmmer/test/Snakefile` (1 hunks)
* `bio/hmmer/jackhmmer/wrapper.py` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* bio/hmmer/jackhmmer/test/Snakefile

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (2)</summary>

<details>
<summary>`**/*.py`: Do not try to improve formatting.
Do not suggest ...</summary>

> `**/*.py`: Do not try to improve formatting.
> Do not suggest type annotations for functions that are defined inside of functions or methods.
> Do not suggest type annotation of the `self` argument of methods.
> Do not suggest type annotation of the `cls` argument of classmethods.
> Do not suggest return type annotation if a function or method does not contain a `return` statement.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>
<details>
<summary>`**/wrapper.py`: Do not complain about use of undefined vari...</summary>

> `**/wrapper.py`: Do not complain about use of undefined variable called `snakemake`.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

13-13: Undefined name `snakemake`

(F821)

---

15-15: Undefined name `snakemake`

(F821)

---

16-16: Undefined name `snakemake`

(F821)

---

18-18: Undefined name `snakemake`

(F821)

---

19-19: Undefined name `snakemake`

(F821)

---

21-21: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

---

24-24: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: testing
* GitHub Check: docs
* GitHub Check: Summary

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (1)</summary>

`29-30`: _⚠️ Potential issue_

**Fix variable name in shell command.**

The `extra_flags` variable is defined on line 24, but then `{extra_flags}` is used in the shell command. Make sure to use the correct variable name.

```diff
- " {out_cmd} {extra_flags} "
+ " {out_cmd} {extra_flags} "
```



> Likely an incorrect or invalid review comment.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T09:31:57Z
user: login: fgvieira
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-12T21:25:13Z
user: login: fgvieira
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-12T21:28:42Z
user: login: fgvieira
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-12T21:41:15Z
user: login: fgvieira
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-12T21:41:55Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 3**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (1)</summary><blockquote>

`8-8`: **Remove unused import**

The `path` module is imported but never used in the code. This import should be removed.

```diff
-from os import path
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 6024dfeade4dc0f2f92a89cae5a82d4ef4a0fc1d and 14b303276790c7f221d845506cf9836dde315aeb.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `bio/hmmer/jackhmmer/test/Snakefile` (1 hunks)
* `bio/hmmer/jackhmmer/wrapper.py` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* bio/hmmer/jackhmmer/test/Snakefile

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (2)</summary>

<details>
<summary>`**/*.py`: Do not try to improve formatting.
Do not suggest ...</summary>

> `**/*.py`: Do not try to improve formatting.
> Do not suggest type annotations for functions that are defined inside of functions or methods.
> Do not suggest type annotation of the `self` argument of methods.
> Do not suggest type annotation of the `cls` argument of classmethods.
> Do not suggest return type annotation if a function or method does not contain a `return` statement.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>
<details>
<summary>`**/wrapper.py`: Do not complain about use of undefined vari...</summary>

> `**/wrapper.py`: Do not complain about use of undefined variable called `snakemake`.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

12-12: Undefined name `snakemake`

(F821)

---

13-13: Undefined name `snakemake`

(F821)

---

16-16: Undefined name `snakemake`

(F821)

---

18-18: Undefined name `snakemake`

(F821)

---

19-19: Undefined name `snakemake`

(F821)

---

21-21: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

---

24-24: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: testing
* GitHub Check: docs
* GitHub Check: Summary

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (3)</summary>

`16-16`: **LGTM: Output command correctly defaults to /dev/null**

The wrapper properly ensures that the output must be set even if it's not desired, with a good default to '/dev/null'.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

16-16: Undefined name `snakemake`

(F821)

</details>

</details>

---

`27-34`: **LGTM: Shell command construction**

The shell command is correctly constructed with proper multiline formatting and variable interpolation.

---

`1-34`: **Missing exclusive parameters function**

The previous reviews mentioned adding an `exclusive_parameters` function to ensure certain parameters are mutually exclusive (like "evalue_threshold" and "tvalue_threshold"), but this function is missing from the current implementation.

Please check if the `exclusive_parameters` function is needed for this wrapper, as it was recommended in previous reviews.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

12-12: Undefined name `snakemake`

(F821)

---

13-13: Undefined name `snakemake`

(F821)

---

16-16: Undefined name `snakemake`

(F821)

---

18-18: Undefined name `snakemake`

(F821)

---

19-19: Undefined name `snakemake`

(F821)

---

21-21: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

---

24-24: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

</details>

</details>

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T21:46:29Z
user: login: fgvieira
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-12T21:51:22Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (1)</summary><blockquote>

`8-8`: **Remove unused import.**

The `path` import from `os` module is not used anywhere in the code.

```diff
-from os import path
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 14b303276790c7f221d845506cf9836dde315aeb and 9874db0e77520cb909e1f36a0b63f35a3814f559.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `bio/hmmer/jackhmmer/wrapper.py` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (2)</summary>

<details>
<summary>`**/*.py`: Do not try to improve formatting.
Do not suggest ...</summary>

> `**/*.py`: Do not try to improve formatting.
> Do not suggest type annotations for functions that are defined inside of functions or methods.
> Do not suggest type annotation of the `self` argument of methods.
> Do not suggest type annotation of the `cls` argument of classmethods.
> Do not suggest return type annotation if a function or method does not contain a `return` statement.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>
<details>
<summary>`**/wrapper.py`: Do not complain about use of undefined vari...</summary>

> `**/wrapper.py`: Do not complain about use of undefined variable called `snakemake`.

- `bio/hmmer/jackhmmer/wrapper.py`

</details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

12-12: Undefined name `snakemake`

(F821)

---

13-13: Undefined name `snakemake`

(F821)

---

16-16: Undefined name `snakemake`

(F821)

---

18-18: Undefined name `snakemake`

(F821)

---

19-19: Undefined name `snakemake`

(F821)

---

21-21: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

---

24-24: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: testing
* GitHub Check: docs
* GitHub Check: Summary

</details>

<details>
<summary>🔇 Additional comments (4)</summary><blockquote>

<details>
<summary>bio/hmmer/jackhmmer/wrapper.py (4)</summary>

`12-16`: **Implementation appears complete and well-structured.**

The parameter handling and output command initialization follow the expected pattern for Snakemake wrappers. The default to '/dev/null' for the output is a good practice when the output file is optional.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

12-12: Undefined name `snakemake`

(F821)

---

13-13: Undefined name `snakemake`

(F821)

---

16-16: Undefined name `snakemake`

(F821)

</details>

</details>

---

`18-25`: **Output handling logic is correctly implemented.**

The conditional checks for each optional output type and correctly builds the command string with appropriate flags.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

18-18: Undefined name `snakemake`

(F821)

---

19-19: Undefined name `snakemake`

(F821)

---

21-21: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

---

24-24: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

</details>

</details>

---

`27-34`: **Shell command construction is well-formatted.**

The shell command correctly uses the multi-line string approach for readability and includes all necessary parameters with proper spacing.

---

`1-34`: <details>
<summary>❓ Verification inconclusive</summary>

**Missing exclusive parameter validation.**

Based on previous review comments, there should be an `exclusive_parameters` function to validate that mutually exclusive parameters aren't used together. This function appears to be missing from the current implementation.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check for the usage of exclusive parameters in other HMMER wrappers
rg --type py "def exclusive_parameters" bio/hmmer/
```

Length of output: 52

---



</details>

I'll perform an additional repository‐wide search to check whether an `exclusive_parameters` function exists elsewhere. This will help verify if the intended exclusive parameter validation is truly missing or simply located in another module.

Please run the following shell script to search for any Python definition of `exclusive_parameters` in the repository:

```shell
#!/bin/bash
# Searching for any occurrence of "def exclusive_parameters" in the entire repository
rg --type py "def exclusive_parameters" .
```

[data: request_verification]

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

8-8: `os.path` imported but unused

Remove unused import: `os.path`

(F401)

---

12-12: Undefined name `snakemake`

(F821)

---

13-13: Undefined name `snakemake`

(F821)

---

16-16: Undefined name `snakemake`

(F821)

---

18-18: Undefined name `snakemake`

(F821)

---

19-19: Undefined name `snakemake`

(F821)

---

21-21: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

---

24-24: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

</details>

</details>

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T21:54:57Z
user: login: fgvieira
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-12T22:00:20Z

Review comments:
diff_hunk: @@ -0,0 +1,65 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+query_file = snakemake.input.get("query")
+
+# Some parameters are mutually exclusive
+def exlusive_parameters(params):
+    num_set = 0
+    for p in params:
+        if snakemake.params.get(p) is not None:
+            num_set += 1
+        if num_set > 1:
+            raise Exception(
+                f"Only one of the parameters {', '.join(params)} can be set at a time"
+            )
+
+
+# Map outputs to flags
+output_parameters = [
+    ("-o", "outfile", ""),
+    ("--tblout", "tblout", ""),
+    ("--domtblout", "domtblout", ""),
+    ("-A", "alignment_hits", ""),
+]
+
+# Map parameters to flags
+parameters = [
+    ("--F1", "filter1"),
+    ("--F2", "filter2"),
+    ("--F3", "filter3"),
+    ("-E", "evalue_threshold"),
+    ("-T", "tvalue_threshold"),
+    ("--incE", "inclusion_evalue"),
+    ("--incT", "inclusion_tvalue"),
+]
+
+# Raise an error if any of these are set at the same time
+exlusive_parameters(["evalue_threshold", "tvalue_threshold"])
+exlusive_parameters(["inclusion_evalue", "inclusion_tvalue"])
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Update function calls to match the corrected function name**

Once the function name is corrected, the calls to it need to be updated as well.

```diff
-exlusive_parameters(["evalue_threshold", "tvalue_threshold"])
-exlusive_parameters(["inclusion_evalue", "inclusion_tvalue"])
+exclusive_parameters(["evalue_threshold", "tvalue_threshold"])
+exclusive_parameters(["inclusion_evalue", "inclusion_tvalue"])
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
exclusive_parameters(["evalue_threshold", "tvalue_threshold"])
exclusive_parameters(["inclusion_evalue", "inclusion_tvalue"])
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Fixed in commit 4bc4400
created_at: 2025-03-11T14:51:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+query_file = snakemake.input.get("query")
+
+# Some parameters are mutually exclusive
+def exlusive_parameters(params):
+    num_set = 0
+    for p in params:
+        if snakemake.params.get(p) is not None:
+            num_set += 1
+        if num_set > 1:
+            raise Exception(
+                f"Only one of the parameters {', '.join(params)} can be set at a time"
+            )
+
+
+# Map outputs to flags
+output_parameters = [
+    ("-o", "outfile", ""),
+    ("--tblout", "tblout", ""),
+    ("--domtblout", "domtblout", ""),
+    ("-A", "alignment_hits", ""),
+]
+
+# Map parameters to flags
+parameters = [
+    ("--F1", "filter1"),
+    ("--F2", "filter2"),
+    ("--F3", "filter3"),
+    ("-E", "evalue_threshold"),
+    ("-T", "tvalue_threshold"),
+    ("--incE", "inclusion_evalue"),
+    ("--incT", "inclusion_tvalue"),
+]
+
+# Raise an error if any of these are set at the same time
+exlusive_parameters(["evalue_threshold", "tvalue_threshold"])
+exlusive_parameters(["inclusion_evalue", "inclusion_tvalue"])
+
+out_cmd = ""
+for flag, snake_param_name, default in output_parameters:
+    out_cmd += f" {flag} {snakemake.output.get(snake_param_name, default)}"
+
+
+param_cmd = ""
+for flag, snake_param_name in parameters:
+    value = snakemake.params.get(snake_param_name)
+    if value is not None:
+        param_cmd += f" {flag} {value}"
+
+log = snakemake.log_fmt_shell(stdout=False, stderr=True)
+
+shell(
+    " jackhmmer --cpu {snakemake.threads} "
+    " {out_cmd} {param_cmd} "
+    " {snakemake.input.query_file} {snakemake.input.database_file} {log}"
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix inconsistent input variable references**

The shell command references `query_file` and `database_file` directly, but earlier code uses a different approach to access the query file.

```diff
- " {snakemake.input.query_file} {snakemake.input.database_file} {log}"
+ " {query_file} {snakemake.input.database_file} {log}"
```

Alternatively, update line 11 to be consistent with how inputs are accessed here.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    " {query_file} {snakemake.input.database_file} {log}"
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-11T14:51:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+query_file = snakemake.input.get("query")
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Ensure consistent naming of input variables**

The query file is accessed here using `get("query")`, but in the shell command (line 64), it's accessed directly as `snakemake.input.query_file`.

```diff
-query_file = snakemake.input.get("query")
+query_file = snakemake.input.get("query_file")
```

Alternatively, adjust the shell command to match this variable name.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
query_file = snakemake.input.get("query_file")
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

11-11: Undefined name `snakemake`

(F821)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-11T14:51:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+query_file = snakemake.input.get("query")
+
+# Some parameters are mutually exclusive
+def exlusive_parameters(params):
+    num_set = 0
+    for p in params:
+        if snakemake.params.get(p) is not None:
+            num_set += 1
+        if num_set > 1:
+            raise Exception(
+                f"Only one of the parameters {', '.join(params)} can be set at a time"
+            )
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Fix typo in function name and logical issue in implementation**

The function name has a typo ("exlusive" instead of "exclusive") and there's a logical issue with the implementation. The check for multiple parameters being set should be outside the loop to correctly validate all parameters.

```diff
-def exlusive_parameters(params):
+def exclusive_parameters(params):
    num_set = 0
    for p in params:
        if snakemake.params.get(p) is not None:
            num_set += 1
-        if num_set > 1:
-            raise Exception(
-                f"Only one of the parameters {', '.join(params)} can be set at a time"
-            )
+    if num_set > 1:
+        raise Exception(
+            f"Only one of the parameters {', '.join(params)} can be set at a time"
+        )
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def exclusive_parameters(params):
    num_set = 0
    for p in params:
        if snakemake.params.get(p) is not None:
            num_set += 1
    if num_set > 1:
        raise Exception(
            f"Only one of the parameters {', '.join(params)} can be set at a time"
        )
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

17-17: Undefined name `snakemake`

(F821)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-11T14:51:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,11 @@
+name: jackhmmer
+description: "search profile(s) against a sequence database"
+authors:
path: bio/hmmer/jackhmmer/meta.yaml
user: login: fgvieira
body: ```suggestion
url: http://hmmer.org/
authors:
```
created_at: 2025-03-11T15:53:25Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,30 @@
+rule jackhmmer:
+    input:
+        database_file="test-protein.fa",
+        query_file="query.fa"
+    output:
+        tblout="test-prot-tbl.txt", # save parseable table of per-sequence hits to file <f>
+        domtblout="test-prot-domtbl.txt", # save parseable table of per-domain hits to file <f>
+        alignment_hits="test-prot-alignment-hits.sto", # Save a multiple alignment of all significant hits (those satisfying inclusion thresholds) to the file <f>
+        outfile="test-prot-out1.txt", # Direct the main human-readable output to a file <f> instead of the default stdout. 
+    log:
+        "logs/jackhmmer.log"
+    params:
+        # One can optionally set an evalue_threshold or tvalue_threshold.
+	# Setting both will raise an error.
+        evalue_threshold=0.0001,
+        # tvalue_threshold=0.00001,
+
+        # One can optionally set an inclusion_evalue or inclusion_tvalue.
+        # Setting both will raise an error.
+        inclusion_evalue=0.0001,
+        # inclusion_tvalue=0.0001,
+
+	# There are three filter parameters to tuned.  Not setting these will use the
+	# defaults of jackhmmer
+        filter1=0.0005,
+        filter2=0.00005,
+        filter3=0.0000005
path: bio/hmmer/jackhmmer/test/Snakefile
user: login: fgvieira
body: Any reason why these parameters are all separated?
Couldn't we just have:
`extra = "-E 0.0001 --F1 0.005 --F2 0.00005 --F3 0000005 [...]"`
created_at: 2025-03-11T15:56:04Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,30 @@
+rule jackhmmer:
+    input:
+        database_file="test-protein.fa",
+        query_file="query.fa"
+    output:
+        tblout="test-prot-tbl.txt", # save parseable table of per-sequence hits to file <f>
+        domtblout="test-prot-domtbl.txt", # save parseable table of per-domain hits to file <f>
+        alignment_hits="test-prot-alignment-hits.sto", # Save a multiple alignment of all significant hits (those satisfying inclusion thresholds) to the file <f>
+        outfile="test-prot-out1.txt", # Direct the main human-readable output to a file <f> instead of the default stdout. 
path: bio/hmmer/jackhmmer/test/Snakefile
user: login: fgvieira
body: Are all these outputs mandatory?
created_at: 2025-03-11T15:58:54Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,30 @@
+rule jackhmmer:
+    input:
+        database_file="test-protein.fa",
+        query_file="query.fa"
path: bio/hmmer/jackhmmer/test/Snakefile
user: login: fgvieira
body: ```suggestion
        db="test-protein.fa",
        query="query.fa"
```
created_at: 2025-03-11T16:00:44Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,30 @@
+rule jackhmmer:
+    input:
+        database_file="test-protein.fa",
+        query_file="query.fa"
+    output:
+        tblout="test-prot-tbl.txt", # save parseable table of per-sequence hits to file <f>
+        domtblout="test-prot-domtbl.txt", # save parseable table of per-domain hits to file <f>
+        alignment_hits="test-prot-alignment-hits.sto", # Save a multiple alignment of all significant hits (those satisfying inclusion thresholds) to the file <f>
+        outfile="test-prot-out1.txt", # Direct the main human-readable output to a file <f> instead of the default stdout. 
path: bio/hmmer/jackhmmer/test/Snakefile
user: login: thomasmulvaney
body: No, they are not mandatory. I have now emphasised that in a comment, but leave them all as an example.
created_at: 2025-03-12T09:12:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+rule jackhmmer:
+    input:
+        database_file="test-protein.fa",
+        query_file="query.fa"
path: bio/hmmer/jackhmmer/test/Snakefile
user: login: thomasmulvaney
body: Sure, i have now shortened these, as you suggest.
created_at: 2025-03-12T09:12:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+rule jackhmmer:
+    input:
+        database_file="test-protein.fa",
+        query_file="query.fa"
+    output:
+        tblout="test-prot-tbl.txt", # save parseable table of per-sequence hits to file <f>
+        domtblout="test-prot-domtbl.txt", # save parseable table of per-domain hits to file <f>
+        alignment_hits="test-prot-alignment-hits.sto", # Save a multiple alignment of all significant hits (those satisfying inclusion thresholds) to the file <f>
+        outfile="test-prot-out1.txt", # Direct the main human-readable output to a file <f> instead of the default stdout. 
+    log:
+        "logs/jackhmmer.log"
+    params:
+        # One can optionally set an evalue_threshold or tvalue_threshold.
+	# Setting both will raise an error.
+        evalue_threshold=0.0001,
+        # tvalue_threshold=0.00001,
+
+        # One can optionally set an inclusion_evalue or inclusion_tvalue.
+        # Setting both will raise an error.
+        inclusion_evalue=0.0001,
+        # inclusion_tvalue=0.0001,
+
+	# There are three filter parameters to tuned.  Not setting these will use the
+	# defaults of jackhmmer
+        filter1=0.0005,
+        filter2=0.00005,
+        filter3=0.0000005
path: bio/hmmer/jackhmmer/test/Snakefile
user: login: thomasmulvaney
body: Fair, enough. All parameters are now moved into extra.
created_at: 2025-03-12T09:13:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,38 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+output_parameters = [
+    ("--tblout", "tblout"),
+    ("--domtblout", "domtblout"),
+    ("-A", "alignment_hits"),
+]
+
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = f" -o {snakemake.output.get('outfile', '/dev/null')}",
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix tuple definition causing command building issue**

The trailing comma at the end of this line creates a tuple instead of a string. This will cause issues when you try to append to it with `+=` in the following lines and when formatting the shell command.

```diff
-out_cmd = f" -o {snakemake.output.get('outfile', '/dev/null')}",
+out_cmd = f" -o {snakemake.output.get('outfile', '/dev/null')}"
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
out_cmd = f" -o {snakemake.output.get('outfile', '/dev/null')}"
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

20-20: Undefined name `snakemake`

(F821)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Fixed in commit e9cc437
created_at: 2025-03-12T09:14:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,38 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+output_parameters = [
+    ("--tblout", "tblout"),
+    ("--domtblout", "domtblout"),
+    ("-A", "alignment_hits"),
+]
+
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = f" -o {snakemake.output.get('outfile', '/dev/null')}",
+
+if snakemake.output.get('tblout') is not None:
+    out_cmd += f" --tblout {snakemake.output.get('tblout')}",
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix tuple concatenation issue**

Due to the trailing comma in the initial definition of `out_cmd`, this line is adding a string as a new element to a tuple rather than concatenating strings.

```diff
-    out_cmd += f" --tblout {snakemake.output.get('tblout')}",
+    out_cmd += f" --tblout {snakemake.output.get('tblout')}"
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    out_cmd += f" --tblout {snakemake.output.get('tblout')}"
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

23-23: Undefined name `snakemake`

(F821)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Fixed in commit e9cc437
created_at: 2025-03-12T09:14:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,38 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+output_parameters = [
+    ("--tblout", "tblout"),
+    ("--domtblout", "domtblout"),
+    ("-A", "alignment_hits"),
+]
+
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = f" -o {snakemake.output.get('outfile', '/dev/null')}",
+
+if snakemake.output.get('tblout') is not None:
+    out_cmd += f" --tblout {snakemake.output.get('tblout')}",
+
+if snakemake.output.get('domtblout') is not None:
+    out_cmd += f" -domtblout {snakemake.output.get('domtblout')}",
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix flag format and tuple concatenation issue**

There are two issues here:
1. The domtblout flag should be `--domtblout` (with double dash) not `-domtblout`
2. The trailing comma creates another tuple element instead of concatenating strings


```diff
-    out_cmd += f" -domtblout {snakemake.output.get('domtblout')}",
+    out_cmd += f" --domtblout {snakemake.output.get('domtblout')}"
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    out_cmd += f" --domtblout {snakemake.output.get('domtblout')}"
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

26-26: Undefined name `snakemake`

(F821)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Fixed in commit e9cc437
created_at: 2025-03-12T09:14:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,38 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+output_parameters = [
+    ("--tblout", "tblout"),
+    ("--domtblout", "domtblout"),
+    ("-A", "alignment_hits"),
+]
+
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = f" -o {snakemake.output.get('outfile', '/dev/null')}",
+
+if snakemake.output.get('tblout') is not None:
+    out_cmd += f" --tblout {snakemake.output.get('tblout')}",
+
+if snakemake.output.get('domtblout') is not None:
+    out_cmd += f" -domtblout {snakemake.output.get('domtblout')}",
+
+if snakemake.output.get('alignment_hits') is not None:
+    out_cmd += f" -A {snakemake.output.get('alignment_hits')}",
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix tuple concatenation issue**

Due to the trailing comma in the initial definition of `out_cmd`, this line is adding a string as a new element to a tuple rather than concatenating strings.

```diff
-    out_cmd += f" -A {snakemake.output.get('alignment_hits')}",
+    out_cmd += f" -A {snakemake.output.get('alignment_hits')}"
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    out_cmd += f" -A {snakemake.output.get('alignment_hits')}"
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

29-29: Undefined name `snakemake`

(F821)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Fixed in commit e9cc437
created_at: 2025-03-12T09:14:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,31 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = (f" -o {snakemake.output.get('outfile', '/dev/null')}",)
+
+if snakemake.output.get("tblout") is not None:
+    out_cmd += (f" --tblout {snakemake.output.get('tblout')}",)
+
+if snakemake.output.get("domtblout") is not None:
+    out_cmd += (f" --domtblout {snakemake.output.get('domtblout')}",)
+
+if snakemake.output.get("alignment_hits") is not None:
+    out_cmd += (f" -A {snakemake.output.get('alignment_hits')}",)
+
+extra_flags = snakemake.params.get("extra", "")
+log = snakemake.log_fmt_shell(stdout=False, stderr=True)
+
+shell(
+    " jackhmmer --cpu {snakemake.threads} "
+    " {out_cmd} {extra_flags} "
+    " {snakemake.input.query} {snakemake.input.db} {log}"
+)
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Use string concatenation correctly in shell command.**

Since `out_cmd` is currently defined as a tuple due to the trailing commas, it will not format correctly in the shell command. After fixing the tuple issues, ensure it's used properly in the shell command.

```diff
shell(
    " jackhmmer --cpu {snakemake.threads} "
-    " {out_cmd} {extra_flags} "
+    "{out_cmd} {extra_flags} "
    " {snakemake.input.query} {snakemake.input.db} {log}"
)
```

Note the removal of the leading space before `{out_cmd}` since `out_cmd` already includes a leading space.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
shell(
    " jackhmmer --cpu {snakemake.threads} "
    "{out_cmd} {extra_flags} "
    " {snakemake.input.query} {snakemake.input.db} {log}"
)
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-12T09:31:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,12 @@
+name: jackhmmer
+description: "search profile(s) against a sequence database"
+url: http://hmmer.org/
+authors:
+  - Thomas Mulvaney
+input:
+  - query file in FASTA format
+  - database file in FASTA format.
path: bio/hmmer/jackhmmer/meta.yaml
user: login: fgvieira
body: ```suggestion
  - query: query file in FASTA format
  - db: database file in FASTA format.
```
created_at: 2025-03-12T21:25:13Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,12 @@
+name: jackhmmer
+description: "search profile(s) against a sequence database"
+url: http://hmmer.org/
+authors:
+  - Thomas Mulvaney
+input:
+  - query: query file in FASTA format
+  - db: database file in FASTA format.
+output:
+  - A multiple sequence alignment (MSA) in Stockholm format
path: bio/hmmer/jackhmmer/meta.yaml
user: login: fgvieira
body: ```suggestion
  - hits_tbl: table of per-sequence hits (optional)
  - hits_aln: multiple sequence alignment (MSA) in Stockholm format of all significant hits (optional)
  - dom_tbl: table of per-domain hits (optional)
  - summary: human-readable output (optional)
```
created_at: 2025-03-12T21:28:42Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,31 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = (f" -o {snakemake.output.get('outfile', '/dev/null')}",)
+
+if snakemake.output.get("tblout") is not None:
+    out_cmd += (f" --tblout {snakemake.output.get('tblout')}",)
+
+if snakemake.output.get("domtblout") is not None:
+    out_cmd += (f" --domtblout {snakemake.output.get('domtblout')}",)
+
+if snakemake.output.get("alignment_hits") is not None:
+    out_cmd += (f" -A {snakemake.output.get('alignment_hits')}",)
+
+extra_flags = snakemake.params.get("extra", "")
+log = snakemake.log_fmt_shell(stdout=False, stderr=True)
+
+shell(
+    " jackhmmer --cpu {snakemake.threads} "
+    " {out_cmd} {extra_flags} "
+    " {snakemake.input.query} {snakemake.input.db} {log}"
+)
path: bio/hmmer/jackhmmer/wrapper.py
user: login: fgvieira
body: ```suggestion
extra = snakemake.params.get("extra", "")
log = snakemake.log_fmt_shell(stdout=False, stderr=True)

# Output must be set even if its not desired.  Default to '/dev/null'
out_cmd = f" -o {snakemake.output.get('summary', '/dev/null')}"

if snakemake.output.get("tblout") is not None:
    out_cmd += f" --tblout {snakemake.output.get('hits_tbl')}"

if snakemake.output.get("domtblout") is not None:
    out_cmd += f" --domtblout {snakemake.output.get('dom_tbl')}"

if snakemake.output.get("alignment_hits") is not None:
    out_cmd += f" -A {snakemake.output.get('hits_aln')}"

shell(
    "jackhmmer --cpu {snakemake.threads}"
    " {extra}"
    " {out_cmd}"
    " {snakemake.input.query}"
    " {snakemake.input.db}"
    " {log}"
)
```
created_at: 2025-03-12T21:41:15Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,18 @@
+rule jackhmmer:
+    input:
+        db="test-protein.fa",
+        query="query.fa"
+    output:
+        # Each of the following outputs is optional, and are described below as an example.
+        tblout="test-prot-tbl.txt", # save parseable table of per-sequence hits to file <f>
+        domtblout="test-prot-domtbl.txt", # save parseable table of per-domain hits to file <f>
+        alignment_hits="test-prot-alignment-hits.sto", # Save a multiple alignment of all significant hits (those satisfying inclusion thresholds) to the file <f>
+        outfile="test-prot-out1.txt", # Direct the main human-readable output to a file <f> instead of the default stdout. 
path: bio/hmmer/jackhmmer/test/Snakefile
user: login: fgvieira
body: ```suggestion
        hits_tbl="test-prot-tbl.txt",
        hits_aln="test-prot-alignment-hits.sto",
        dom_tbl="test-prot-domtbl.txt",
        summary="test-prot-out1.txt",
```
created_at: 2025-03-12T21:41:55Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,34 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+extra = snakemake.params.get("extra", "")
+log = snakemake.log_fmt_shell(stdout=False, stderr=True)
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = f" -o {snakemake.output.get('summary', '/dev/null')}"
+
+if snakemake.output.get("tblout") is not None:
+    out_cmd += f" --tblout {snakemake.output.get('hits_tbl')}"
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Inconsistent output variable names**

The condition checks for `tblout` but the command uses `hits_tbl`. This inconsistency could lead to errors if users provide output with the wrong name.

```diff
-if snakemake.output.get("tblout") is not None:
-    out_cmd += f" --tblout {snakemake.output.get('hits_tbl')}"
+if snakemake.output.get("hits_tbl") is not None:
+    out_cmd += f" --tblout {snakemake.output.get('hits_tbl')}"
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
if snakemake.output.get("hits_tbl") is not None:
    out_cmd += f" --tblout {snakemake.output.get('hits_tbl')}"
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

18-18: Undefined name `snakemake`

(F821)

---

19-19: Undefined name `snakemake`

(F821)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-12T21:46:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+extra = snakemake.params.get("extra", "")
+log = snakemake.log_fmt_shell(stdout=False, stderr=True)
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = f" -o {snakemake.output.get('summary', '/dev/null')}"
+
+if snakemake.output.get("tblout") is not None:
+    out_cmd += f" --tblout {snakemake.output.get('hits_tbl')}"
+
+if snakemake.output.get("domtblout") is not None:
+    out_cmd += f" --domtblout {snakemake.output.get('dom_tbl')}"
+
+if snakemake.output.get("alignment_hits") is not None:
+    out_cmd += f" -A {snakemake.output.get('hits_aln')}"
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Inconsistent output variable names**

The condition checks for `alignment_hits` but the command uses `hits_aln`. This inconsistency could lead to errors if users provide output with the wrong name.

```diff
-if snakemake.output.get("alignment_hits") is not None:
-    out_cmd += f" -A {snakemake.output.get('hits_aln')}"
+if snakemake.output.get("hits_aln") is not None:
+    out_cmd += f" -A {snakemake.output.get('hits_aln')}"
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
if snakemake.output.get("hits_aln") is not None:
    out_cmd += f" -A {snakemake.output.get('hits_aln')}"
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

24-24: Undefined name `snakemake`

(F821)

---

25-25: Undefined name `snakemake`

(F821)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-12T21:46:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+extra = snakemake.params.get("extra", "")
+log = snakemake.log_fmt_shell(stdout=False, stderr=True)
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = f" -o {snakemake.output.get('summary', '/dev/null')}"
+
+if snakemake.output.get("tblout") is not None:
+    out_cmd += f" --tblout {snakemake.output.get('hits_tbl')}"
+
+if snakemake.output.get("domtblout") is not None:
+    out_cmd += f" --domtblout {snakemake.output.get('dom_tbl')}"
path: bio/hmmer/jackhmmer/wrapper.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Inconsistent output variable names**

The condition checks for `domtblout` but the command uses `dom_tbl`. This inconsistency could lead to errors if users provide output with the wrong name.

```diff
-if snakemake.output.get("domtblout") is not None:
-    out_cmd += f" --domtblout {snakemake.output.get('dom_tbl')}"
+if snakemake.output.get("dom_tbl") is not None:
+    out_cmd += f" --domtblout {snakemake.output.get('dom_tbl')}"
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
if snakemake.output.get("dom_tbl") is not None:
    out_cmd += f" --domtblout {snakemake.output.get('dom_tbl')}"
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

21-21: Undefined name `snakemake`

(F821)

---

22-22: Undefined name `snakemake`

(F821)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-12T21:46:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+"""Snakemake wrapper for jackhmmer"""
+
+__author__ = "Thomas Mulvaney, N. Tessa Pierce"
+__copyright__ = "Copyright 2025, Thomas Mulvaney, N. Tessa Pierce"
+__email__ = "mulvaney@mailbox.org"
+__license__ = "MIT"
+
+from os import path
+from snakemake.shell import shell
+
+
+extra = snakemake.params.get("extra", "")
+log = snakemake.log_fmt_shell(stdout=False, stderr=True)
+
+# Output must be set even if its not desired.  Default to '/dev/null'
+out_cmd = f" -o {snakemake.output.get('summary', '/dev/null')}"
+
+if snakemake.output.get("tblout") is not None:
+    out_cmd += f" --tblout {snakemake.output.get('hits_tbl')}"
+
+if snakemake.output.get("domtblout") is not None:
+    out_cmd += f" --domtblout {snakemake.output.get('dom_tbl')}"
+
+if snakemake.output.get("alignment_hits") is not None:
+    out_cmd += f" -A {snakemake.output.get('hits_aln')}"
path: bio/hmmer/jackhmmer/wrapper.py
user: login: fgvieira
body: ```suggestion
if snakemake.output.get("hits_tbl") is not None:
    out_cmd += f" --tblout {snakemake.output.get('hits_tbl')}"

if snakemake.output.get("dom_tbl") is not None:
    out_cmd += f" --domtblout {snakemake.output.get('dom_tbl')}"

if snakemake.output.get("hits_aln") is not None:
    out_cmd += f" -A {snakemake.output.get('hits_aln')}"
```
created_at: 2025-03-12T21:51:21Z
author_association: COLLABORATOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-03-11T14:42:26Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

## Walkthrough
This pull request introduces new Conda environment configuration files for Linux 64-bit, along with metadata detailing the jackhmmer tool’s inputs, outputs, and author information. It adds a new Snakemake rule in the Snakefile to run jackhmmer and includes corresponding FASTA test input files. Additionally, a dedicated Snakemake wrapper with exclusive parameter checks and dynamic command construction for jackhmmer is added, and testing functions are modified to support these new components.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `bio/hmmer/jackhmmer/environment.linux-64.pin.txt`, `bio/hmmer/jackhmmer/environment.yaml` | Added new Conda environment configuration files with explicit package dependencies and channel specifications. |
| `bio/hmmer/jackhmmer/meta.yaml` | New metadata file for jackhmmer defining the tool’s description, inputs, outputs, author, and citation. |
| `bio/hmmer/jackhmmer/test/Snakefile`, `bio/hmmer/jackhmmer/test/query.fa`, `bio/hmmer/jackhmmer/test/test-protein.fa` | Introduced a new Snakefile rule for jackhmmer along with FASTA test files for query and protein sequences. |
| `bio/hmmer/jackhmmer/wrapper.py` | Added a new Snakemake wrapper for jackhmmer that implements exclusive parameter checks and constructs the command for execution. |
| `test_wrappers.py` | Added a new test function for jackhmmer and applied formatting improvements in existing test functions. |

## Possibly related PRs
- **snakemake/snakemake-wrappers#3500:** Introduces an `environment.linux-64.pin.txt` file to define Conda dependencies, closely related to the new environment files here.
- **snakemake/snakemake-wrappers#3162:** Adds environment specification files (`environment.linux-64.pin.txt` and `environment.yaml`) for bioinformatics tools, matching the approach in this PR.
- **snakemake/snakemake-wrappers#3496:** Implements a new `environment.linux-64.pin.txt` file for setting up Conda environments, directly comparable to the changes introduced in this PR.

</details>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡🧪 Multi-step agentic review comment chat (experimental)</summary>
> 
> - We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
> 						- To enable this feature, set early_access to true under in the settings.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=snakemake/snakemake-wrappers&utm_content=3714):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: thomasmulvaney
created_at: 2025-03-11T14:44:09Z
body: Hmm, looks like my editor ran black on test_wrapper.py, hence a few "style" changes beyond the test for my Snakefile...

Maybe it would be best if we also ran black on test_wrapper.py though?
author_association: CONTRIBUTOR