Skip to content

Commit 99b1b29

Browse files
committed
feat: Add components method to Variant class
Adds a `components` method to the Variant class which is a tuple of fully qualified variant strings that comprises the current variant object. The `format_variant` function was refactored into a new function `_format_component_variants`, which returns a list of the component variants of a Variant object. In turn, the __repr__ function uses this class function to return the variant string representation. The `components` method returns the result of this new internal formatting function, with the prefix and transcript identifier prepended to each variant string. For multi-variants, each tuple element is parsable into a single-variant Variant object which comprises the original multi-variant. For single- variants, the single element tuple contains the original variant string.
1 parent fc179ee commit 99b1b29

File tree

2 files changed

+95
-35
lines changed

2 files changed

+95
-35
lines changed

src/mavehgvs/variant.py

Lines changed: 71 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ def _process_string_variant( # noqa: max-complexity: 23
309309
positions = VariantPosition(match_dict[f"{pattern_group}_position"])
310310
if self._prefix == "p":
311311
sequences = (positions.amino_acid, match_dict[f"{pattern_group}_new"])
312-
elif self._prefix in tuple("gmo" "cn" "r"):
312+
elif self._prefix in tuple("gmocnr"):
313313
sequences = (
314314
match_dict[f"{pattern_group}_ref"],
315315
match_dict[f"{pattern_group}_new"],
@@ -479,43 +479,18 @@ def _variant_dictionary_to_string( # noqa: max-complexity: 25
479479
else:
480480
return variant_string
481481

482-
def __eq__(self, other: "Variant") -> bool:
483-
"""Equality comparison operator.
482+
def _format_component_variants(self) -> List[str]: # noqa: max-complexity: 14
483+
"""Format each of the component variants of this variant into a variant string.
484484
485-
Parameters
486-
----------
487-
other : Variant
488-
The other Variant to compare to.
485+
The result is a list of strings, each representing a single variant. If this
486+
variant is a single variant, the list will contain a single element equivalent
487+
to the input string. For multi-variants, the list will contain each component
488+
variant of the variant.
489489
490490
Returns
491491
-------
492-
bool
493-
True if this variant is the same as the other position; else False.
494-
495-
"""
496-
return (
497-
self._target_id,
498-
self.variant_count,
499-
self._prefix,
500-
self._variant_types,
501-
self._positions,
502-
self._sequences,
503-
) == (
504-
other._target_id,
505-
other.variant_count,
506-
other._prefix,
507-
other._variant_types,
508-
other._positions,
509-
other._sequences,
510-
)
511-
512-
def __repr__(self) -> str: # noqa: max-complexity: 14
513-
"""The object representation is equivalent to the input string.
514-
515-
Returns
516-
-------
517-
str
518-
The object representation.
492+
List[str]
493+
List of formatted component variants.
519494
520495
"""
521496

@@ -569,12 +544,55 @@ def format_variant(
569544
else: # pragma: no cover
570545
raise ValueError("invalid variant type")
571546

547+
return [format_variant(*t) for t in self.variant_tuples()]
548+
549+
def __eq__(self, other: "Variant") -> bool:
550+
"""Equality comparison operator.
551+
552+
Parameters
553+
----------
554+
other : Variant
555+
The other Variant to compare to.
556+
557+
Returns
558+
-------
559+
bool
560+
True if this variant is the same as the other position; else False.
561+
562+
"""
563+
return (
564+
self._target_id,
565+
self.variant_count,
566+
self._prefix,
567+
self._variant_types,
568+
self._positions,
569+
self._sequences,
570+
) == (
571+
other._target_id,
572+
other.variant_count,
573+
other._prefix,
574+
other._variant_types,
575+
other._positions,
576+
other._sequences,
577+
)
578+
579+
def __repr__(self) -> str:
580+
"""The object representation is equivalent to the input string.
581+
582+
Returns
583+
-------
584+
str
585+
The object representation.
586+
587+
"""
588+
589+
elements = self._format_component_variants()
590+
572591
if self._target_id is not None:
573592
prefix = f"{self._target_id}:{self._prefix}"
574593
else:
575594
prefix = f"{self._prefix}"
576595

577-
elements = [format_variant(*t) for t in self.variant_tuples()]
578596
if self.is_multi_variant():
579597
return f"{prefix}.[{';'.join(elements)}]"
580598
else:
@@ -834,3 +852,21 @@ def target_id(self) -> Optional[str]:
834852
835853
"""
836854
return self._target_id
855+
856+
def components(self) -> Tuple[str, ...]:
857+
"""The component substrings of a variant.
858+
859+
Returns
860+
-------
861+
Tuple[str, ...]
862+
List of component substrings for this variant.
863+
864+
"""
865+
if self.target_id is not None:
866+
prefix = f"{self.target_id}:{self.prefix}"
867+
else:
868+
prefix = f"{self.prefix}"
869+
870+
return tuple(
871+
[f"{prefix}.{component}" for component in self._format_component_variants()]
872+
)

tests/test_variant.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,30 @@ def test_uses_extended_positions(self):
987987
v = Variant(s)
988988
self.assertTrue(v.uses_extended_positions())
989989

990+
def test_components(self):
991+
variant_strings = [
992+
("p.[Glu27Trp;Ter345Lys]", ("p.Glu27Trp", "p.Ter345Lys")),
993+
("p.[Glu27Trp;Lys212fs]", ("p.Glu27Trp", "p.Lys212fs")),
994+
(
995+
"p.[Gly18del;Glu27Trp;Ter345Lys]",
996+
("p.Gly18del", "p.Glu27Trp", "p.Ter345Lys"),
997+
),
998+
(
999+
"p.[Gln7_Asn19del;Glu27Trp;Ter345Lys]",
1000+
("p.Gln7_Asn19del", "p.Glu27Trp", "p.Ter345Lys"),
1001+
),
1002+
(
1003+
"c.[1_35del;78+5_78+10del;122T>A]",
1004+
("c.1_35del", "c.78+5_78+10del", "c.122T>A"),
1005+
),
1006+
("p.Glu27Trp", ("p.Glu27Trp",)),
1007+
]
1008+
1009+
for s, expected_components in variant_strings:
1010+
with self.subTest(s=s):
1011+
v = Variant(s)
1012+
self.assertTrue(all([c in expected_components for c in v.components()]))
1013+
9901014

9911015
# TODO: multi-variant test cases
9921016
class TestMiscProperties(unittest.TestCase):

0 commit comments

Comments
 (0)