diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 28f0840..bdbaf43 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -12,11 +12,11 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v3 diff --git a/src/mavehgvs/variant.py b/src/mavehgvs/variant.py index 98d7460..ea3a0cb 100644 --- a/src/mavehgvs/variant.py +++ b/src/mavehgvs/variant.py @@ -309,7 +309,7 @@ def _process_string_variant( # noqa: max-complexity: 23 positions = VariantPosition(match_dict[f"{pattern_group}_position"]) if self._prefix == "p": sequences = (positions.amino_acid, match_dict[f"{pattern_group}_new"]) - elif self._prefix in tuple("gmo" "cn" "r"): + elif self._prefix in tuple("gmocnr"): sequences = ( match_dict[f"{pattern_group}_ref"], match_dict[f"{pattern_group}_new"], @@ -479,43 +479,18 @@ def _variant_dictionary_to_string( # noqa: max-complexity: 25 else: return variant_string - def __eq__(self, other: "Variant") -> bool: - """Equality comparison operator. + def _format_component_variants(self) -> List[str]: # noqa: max-complexity: 14 + """Format each of the component variants of this variant into a variant string. - Parameters - ---------- - other : Variant - The other Variant to compare to. + The result is a list of strings, each representing a single variant. If this + variant is a single variant, the list will contain a single element equivalent + to the input string. For multi-variants, the list will contain each component + variant of the variant. Returns ------- - bool - True if this variant is the same as the other position; else False. - - """ - return ( - self._target_id, - self.variant_count, - self._prefix, - self._variant_types, - self._positions, - self._sequences, - ) == ( - other._target_id, - other.variant_count, - other._prefix, - other._variant_types, - other._positions, - other._sequences, - ) - - def __repr__(self) -> str: # noqa: max-complexity: 14 - """The object representation is equivalent to the input string. - - Returns - ------- - str - The object representation. + List[str] + List of formatted component variants. """ @@ -569,12 +544,55 @@ def format_variant( else: # pragma: no cover raise ValueError("invalid variant type") + return [format_variant(*t) for t in self.variant_tuples()] + + def __eq__(self, other: "Variant") -> bool: + """Equality comparison operator. + + Parameters + ---------- + other : Variant + The other Variant to compare to. + + Returns + ------- + bool + True if this variant is the same as the other position; else False. + + """ + return ( + self._target_id, + self.variant_count, + self._prefix, + self._variant_types, + self._positions, + self._sequences, + ) == ( + other._target_id, + other.variant_count, + other._prefix, + other._variant_types, + other._positions, + other._sequences, + ) + + def __repr__(self) -> str: + """The object representation is equivalent to the input string. + + Returns + ------- + str + The object representation. + + """ + + elements = self._format_component_variants() + if self._target_id is not None: prefix = f"{self._target_id}:{self._prefix}" else: prefix = f"{self._prefix}" - elements = [format_variant(*t) for t in self.variant_tuples()] if self.is_multi_variant(): return f"{prefix}.[{';'.join(elements)}]" else: @@ -834,3 +852,21 @@ def target_id(self) -> Optional[str]: """ return self._target_id + + def components(self) -> Tuple[str, ...]: + """The component substrings of a variant. + + Returns + ------- + Tuple[str, ...] + List of component substrings for this variant. + + """ + if self.target_id is not None: + prefix = f"{self.target_id}:{self.prefix}" + else: + prefix = f"{self.prefix}" + + return tuple( + [f"{prefix}.{component}" for component in self._format_component_variants()] + ) diff --git a/tests/test_variant.py b/tests/test_variant.py index fe9a4f0..fb4dc60 100644 --- a/tests/test_variant.py +++ b/tests/test_variant.py @@ -987,6 +987,30 @@ def test_uses_extended_positions(self): v = Variant(s) self.assertTrue(v.uses_extended_positions()) + def test_components(self): + variant_strings = [ + ("p.[Glu27Trp;Ter345Lys]", ("p.Glu27Trp", "p.Ter345Lys")), + ("p.[Glu27Trp;Lys212fs]", ("p.Glu27Trp", "p.Lys212fs")), + ( + "p.[Gly18del;Glu27Trp;Ter345Lys]", + ("p.Gly18del", "p.Glu27Trp", "p.Ter345Lys"), + ), + ( + "p.[Gln7_Asn19del;Glu27Trp;Ter345Lys]", + ("p.Gln7_Asn19del", "p.Glu27Trp", "p.Ter345Lys"), + ), + ( + "c.[1_35del;78+5_78+10del;122T>A]", + ("c.1_35del", "c.78+5_78+10del", "c.122T>A"), + ), + ("p.Glu27Trp", ("p.Glu27Trp",)), + ] + + for s, expected_components in variant_strings: + with self.subTest(s=s): + v = Variant(s) + self.assertTrue(all([c in expected_components for c in v.components()])) + # TODO: multi-variant test cases class TestMiscProperties(unittest.TestCase):