diff --git a/prymer/offtarget/offtarget_detector.py b/prymer/offtarget/offtarget_detector.py index 659cf27..34b5d9e 100644 --- a/prymer/offtarget/offtarget_detector.py +++ b/prymer/offtarget/offtarget_detector.py @@ -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. @@ -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}" @@ -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. diff --git a/tests/offtarget/test_offtarget.py b/tests/offtarget/test_offtarget.py index 8924e41..8aa7692 100644 --- a/tests/offtarget/test_offtarget.py +++ b/tests/offtarget/test_offtarget.py @@ -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 @@ -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): @@ -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, )