Skip to content

Commit

Permalink
feat: added validation and test of validation for min_amplicon_size p…
Browse files Browse the repository at this point in the history
…arameter
  • Loading branch information
ameynert committed Jan 7, 2025
1 parent 2648128 commit 434218d
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 36 deletions.
34 changes: 7 additions & 27 deletions prymer/offtarget/offtarget_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ def __init__(
Raises:
ValueError: If `max_amplicon_size` is not greater than 0.
ValueError: If `min_amplicon_size` is outside the range 1 to `max_amplicon_size`,
inclusive.
ValueError: If any of `max_primer_hits`, `max_primer_pair_hits`, or
`min_primer_pair_hits` are not greater than or equal to 0.
ValueError: If `three_prime_region_length` is not greater than 0.
Expand All @@ -235,6 +237,11 @@ def __init__(
errors: list[str] = []
if max_amplicon_size < 1:
errors.append(f"'max_amplicon_size' must be greater than 0. Saw {max_amplicon_size}")
if min_amplicon_size < 1 or min_amplicon_size > max_amplicon_size:
errors.append(
f"'min_amplicon_size' must be between 1 and 'max_amplicon_size'={max_amplicon_size}"
f" inclusive. Saw {min_amplicon_size}"
)
if max_primer_hits < 0:
errors.append(
f"'max_primer_hits' must be greater than or equal to 0. Saw {max_primer_hits}"
Expand Down Expand Up @@ -292,33 +299,6 @@ def __init__(
self._keep_spans: bool = keep_spans
self._keep_primer_spans: bool = keep_primer_spans

def __post_init__(self) -> None:
"""
Validates parameters.
Raises:
ValueError: If `min_amplicon_size` is greater than `max_amplicon_size`, or if either
value is less than 1.
ValueError: If `max_primer_hits`, `max_primer_pair_hits`, or `min_primer_pair_hits` are
less than 0.
"""
errors: list[str] = []
if self._min_amplicon_size < 1:
errors.append("'min_amplicon_size' must be greater than or equal to 1.")
if self._max_amplicon_size < 1:
errors.append("'max_amplicon_size' must be greater than or equal to 1.")
if self._min_amplicon_size > self._max_amplicon_size:
errors.append("'min_amplicon_size' must be less than or equal to 'max_amplicon_size'.")
if self._max_primer_hits < 0:
errors.append("'max_primer_hits' must be greater than or equal to 0.")
if self._max_primer_pair_hits < 0:
errors.append("'max_primer_pair_hits' must be greater than or equal to 0.")
if self._min_primer_pair_hits < 0:
errors.append("'min_primer_pair_hits' must be greater than or equal to 0.")

if len(errors) > 0:
raise ValueError("\n".join(errors))

def filter(self, primers: list[PrimerType]) -> list[PrimerType]:
"""
Remove primers that have more than `max_primer_hits` mappings to the genome.
Expand Down
23 changes: 14 additions & 9 deletions tests/offtarget/test_offtarget.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,17 +428,20 @@ class CustomPrimer(Oligo):
@pytest.mark.parametrize(
(
"max_primer_hits,max_primer_pair_hits,min_primer_pair_hits,three_prime_region_length,"
"max_mismatches_in_three_prime_region,max_mismatches,max_amplicon_size,expected_error"
"max_mismatches_in_three_prime_region,max_mismatches,max_amplicon_size,min_amplicon_size,"
"expected_error"
),
[
(-1, 1, 1, 20, 0, 0, 1, "'max_primer_hits' must be greater than or equal to 0. Saw -1"),
(1, -1, 1, 20, 0, 0, 1, "'max_primer_pair_hits' must be greater than or equal to 0. Saw -1"), # noqa: E501
(1, 1, -1, 20, 0, 0, 1, "'min_primer_pair_hits' must be greater than or equal to 0. Saw -1"), # noqa: E501
(1, 1, 1, 0, 0, 0, 1, "'three_prime_region_length' must be greater than 0. Saw 0"),
(1, 1, 1, 20, -1, 0, 1, "'max_mismatches_in_three_prime_region' must be between 0 and 20 inclusive. Saw -1"), # noqa: E501
(1, 1, 1, 20, 21, 0, 1, "'max_mismatches_in_three_prime_region' must be between 0 and 20 inclusive. Saw 21"), # noqa: E501
(1, 1, 1, 20, 0, -1, 1, "'max_mismatches' must be greater than or equal to 0. Saw -1"),
(1, 1, 1, 20, 0, 0, 0, "'max_amplicon_size' must be greater than 0. Saw 0"),
(-1, 1, 1, 20, 0, 0, 1, 1, "'max_primer_hits' must be greater than or equal to 0. Saw -1"),
(1, -1, 1, 20, 0, 0, 1, 1, "'max_primer_pair_hits' must be greater than or equal to 0. Saw -1"), # noqa: E501
(1, 1, -1, 20, 0, 0, 1, 1, "'min_primer_pair_hits' must be greater than or equal to 0. Saw -1"), # noqa: E501
(1, 1, 1, 0, 0, 0, 1, 1, "'three_prime_region_length' must be greater than 0. Saw 0"),
(1, 1, 1, 20, -1, 0, 1, 1, "'max_mismatches_in_three_prime_region' must be between 0 and 20 inclusive. Saw -1"), # noqa: E501
(1, 1, 1, 20, 21, 0, 1, 1, "'max_mismatches_in_three_prime_region' must be between 0 and 20 inclusive. Saw 21"), # noqa: E501
(1, 1, 1, 20, 0, -1, 1, 1, "'max_mismatches' must be greater than or equal to 0. Saw -1"),
(1, 1, 1, 20, 0, 0, 0, 1, "'max_amplicon_size' must be greater than 0. Saw 0"),
(1, 1, 1, 20, 0, 0, 10, 0, "'min_amplicon_size' must be between 1 and 'max_amplicon_size'=10 inclusive. Saw 0"), # noqa: E501
(1, 1, 1, 20, 0, 0, 10, 11, "'min_amplicon_size' must be between 1 and 'max_amplicon_size'=10 inclusive. Saw 11"), # noqa: E501
],
)
# fmt: on
Expand All @@ -451,6 +454,7 @@ def test_init(
max_mismatches_in_three_prime_region: int,
max_mismatches: int,
max_amplicon_size: int,
min_amplicon_size: int,
expected_error: str,
) -> None:
with pytest.raises(ValueError, match=expected_error):
Expand All @@ -463,4 +467,5 @@ def test_init(
max_mismatches_in_three_prime_region=max_mismatches_in_three_prime_region,
max_mismatches=max_mismatches,
max_amplicon_size=max_amplicon_size,
min_amplicon_size=min_amplicon_size,
)

0 comments on commit 434218d

Please sign in to comment.