diff --git a/Makefile b/Makefile index b5f37dd..e4d646d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ test: check poetry run maturin develop --release - poetry run pytest -v . + poetry run pytest . check: cargo fmt --check diff --git a/haem.pyi b/haem.pyi index f92f2f7..0a5a272 100644 --- a/haem.pyi +++ b/haem.pyi @@ -56,9 +56,13 @@ class DNABase: ... def __invert__(self) -> DNABase: """See `DNABase.complement`.""" - def __add__(self, other: typing.Union[DNABase, DNASequence]) -> DNASequence: - """Create a DNA sequence from the concatenation of this base and either - another base or a DNA sequence.""" + def __add__(self, other: typing.Union[DNABase, DNASequence, str]) -> DNASequence: + """Create a new sequence consisting of this base followed by the given + sequence member(s).""" + ... + def __radd__(self, other: typing.Union[DNABase, DNASequence, str]) -> DNASequence: + """Create a new sequence consisting of the given sequence member(s) + followed by this base.""" ... class RNABase: @@ -111,9 +115,13 @@ class RNABase: ... def __invert__(self) -> RNABase: """See `RNABase.complement`.""" - def __add__(self, other: typing.Union[RNABase, RNASequence]) -> RNASequence: - """Create a RNA sequence from the concatenation of this base and either - another base or a RNA sequence.""" + def __add__(self, other: typing.Union[RNABase, RNASequence, str]) -> RNASequence: + """Create a new sequence consisting of this base followed by the given + sequence member(s).""" + ... + def __radd__(self, other: typing.Union[RNABase, RNASequence, str]) -> RNASequence: + """Create a new sequence consisting of the given sequence member(s) + followed by this base.""" ... class AminoAcid: @@ -186,10 +194,16 @@ class AminoAcid: """Always true.""" ... def __add__( - self, other: typing.Union[AminoAcid, AminoAcidSequence] + self, other: typing.Union[AminoAcid, AminoAcidSequence, str] + ) -> AminoAcidSequence: + """Create a new sequence consisting of this amino acid followed by the + given sequence member(s).""" + ... + def __radd__( + self, other: typing.Union[AminoAcid, AminoAcidSequence, str] ) -> AminoAcidSequence: - """Create an amino acid sequence from the concatenation of this amino - acid and either another amino acid or an amino acid sequence.""" + """Create a new sequence consisting of the given sequence member(s) + followed by this amino acid.""" ... class DNASequence: @@ -232,9 +246,13 @@ class DNASequence: def __bool__(self) -> bool: """Casting to bool is False for empty sequences and True otherwise.""" ... - def __add__(self, other: typing.Union[DNABase, DNASequence]) -> DNASequence: - """Create a DNA sequence from the concatenation of this sequence and - either a DNABase or another DNASequence.""" + def __add__(self, other: typing.Union[DNABase, DNASequence, str]) -> DNASequence: + """Create a new sequence consisting of this sequence followed by the + given sequence member(s).""" + def __radd__(self, other: typing.Union[DNABase, DNASequence, str]) -> DNASequence: + """Create a new sequence consisting of the given sequence member(s) + followed by this sequence.""" + ... def __contains__(self, item: typing.Union[DNABase, DNASequence]) -> bool: """Return true if the given DNABase or DNASequence is contained within this sequence.""" @@ -288,9 +306,13 @@ class RNASequence: def __bool__(self) -> bool: """Casting to bool is False for empty sequences and True otherwise.""" ... - def __add__(self, other: typing.Union[RNABase, RNASequence]) -> RNASequence: - """Create a RNA sequence from the concatenation of this sequence and - either a RNABase or another RNASequence.""" + def __add__(self, other: typing.Union[RNABase, RNASequence, str]) -> RNASequence: + """Create a new sequence consisting of this sequence followed by the + given sequence member(s).""" + def __radd__(self, other: typing.Union[RNABase, RNASequence, str]) -> RNASequence: + """Create a new sequence consisting of the given sequence member(s) + followed by this sequence.""" + ... def __contains__(self, item: typing.Union[RNABase, RNASequence]) -> bool: """Return true if the given RNABase or RNASequence is contained within this sequence.""" @@ -337,10 +359,16 @@ class AminoAcidSequence: """Casting to bool is False for empty sequences and True otherwise.""" ... def __add__( - self, other: typing.Union[AminoAcid, AminoAcidSequence] + self, other: typing.Union[AminoAcid, AminoAcidSequence, str] ) -> AminoAcidSequence: - """Create an amino acid sequence from the concatenation of this - sequence and either an AminoAcid or another AminoAcidSequence.""" + """Create a new sequence consisting of this sequence followed by the + given sequence member(s).""" + def __radd__( + self, other: typing.Union[AminoAcidSequence, AminoAcid, str] + ) -> AminoAcidSequence: + """Create a new sequence consisting of the given sequence member(s) + followed by this sequence.""" + ... def __contains__(self, item: typing.Union[AminoAcid, AminoAcidSequence]) -> bool: """Return true if the given AminoAcid or AminoAcidSequence is contained within this sequence.""" diff --git a/src/aminoacid.rs b/src/aminoacid.rs index 295963f..8341400 100644 --- a/src/aminoacid.rs +++ b/src/aminoacid.rs @@ -1,6 +1,7 @@ use crate::aminoacidsequence::AminoAcidSequence; -use crate::member::{Member, MemberOrMembers}; +use crate::member::Member; use crate::rnabase::RNABase; +use crate::utils::AddInput; use pyo3::class::basic::CompareOp; use pyo3::create_exception; use pyo3::prelude::*; @@ -195,10 +196,16 @@ impl AminoAcid { true } - fn __add__(&self, other: MemberOrMembers) -> AminoAcidSequence { - AminoAcidSequence { - amino_acids: self.add(other), - } + fn __add__(&self, other: AddInput) -> PyResult { + Ok(AminoAcidSequence { + amino_acids: self.add(other, false)?, + }) + } + + fn __radd__(&self, other: AddInput) -> PyResult { + Ok(AminoAcidSequence { + amino_acids: self.add(other, true)?, + }) } } diff --git a/src/aminoacidsequence.rs b/src/aminoacidsequence.rs index fc88f54..4acaf95 100644 --- a/src/aminoacidsequence.rs +++ b/src/aminoacidsequence.rs @@ -1,7 +1,7 @@ use crate::aminoacid::AminoAcid; use crate::member::{MemberOrCode, MemberOrMembers}; use crate::sequence::{Sequence, SequenceInput}; -use crate::utils::IntOrSlice; +use crate::utils::{AddInput, IntOrSlice}; use pyo3::class::basic::CompareOp; use pyo3::prelude::*; @@ -41,10 +41,16 @@ impl AminoAcidSequence { self.bool() } - fn __add__(&self, other: MemberOrMembers) -> Self { - Self { - amino_acids: self.add(other), - } + fn __add__(&self, other: AddInput) -> PyResult { + Ok(Self { + amino_acids: self.add(other, false)?, + }) + } + + fn __radd__(&self, other: AddInput) -> PyResult { + Ok(Self { + amino_acids: self.add(other, true)?, + }) } fn __contains__(&self, amino_acid_or_seq: MemberOrMembers) -> PyResult { diff --git a/src/dnabase.rs b/src/dnabase.rs index 67b0aba..4535753 100644 --- a/src/dnabase.rs +++ b/src/dnabase.rs @@ -1,6 +1,7 @@ use crate::dnasequence::DNASequence; -use crate::member::{Member, MemberOrMembers}; +use crate::member::Member; use crate::rnabase::RNABase; +use crate::utils::AddInput; use pyo3::class::basic::CompareOp; use pyo3::prelude::*; use std::fmt; @@ -107,10 +108,16 @@ impl DNABase { self.get_complement() } - fn __add__(&self, other: MemberOrMembers) -> DNASequence { - DNASequence { - bases: self.add(other), - } + fn __add__(&self, other: AddInput) -> PyResult { + Ok(DNASequence { + bases: self.add(other, false)?, + }) + } + + fn __radd__(&self, other: AddInput) -> PyResult { + Ok(DNASequence { + bases: self.add(other, true)?, + }) } fn __str__(&self) -> String { diff --git a/src/dnasequence.rs b/src/dnasequence.rs index 345cc85..daeddec 100644 --- a/src/dnasequence.rs +++ b/src/dnasequence.rs @@ -3,7 +3,7 @@ use crate::member::{MemberOrCode, MemberOrMembers}; use crate::rnabase::RNABase; use crate::rnasequence::RNASequence; use crate::sequence::{Sequence, SequenceInput}; -use crate::utils::IntOrSlice; +use crate::utils::{AddInput, IntOrSlice}; use pyo3::class::basic::CompareOp; use pyo3::prelude::*; use rayon::prelude::*; @@ -61,10 +61,16 @@ impl DNASequence { self.bool() } - fn __add__(&self, other: MemberOrMembers) -> Self { - Self { - bases: self.add(other), - } + fn __add__(&self, other: AddInput) -> PyResult { + Ok(Self { + bases: self.add(other, false)?, + }) + } + + fn __radd__(&self, other: AddInput) -> PyResult { + Ok(Self { + bases: self.add(other, true)?, + }) } fn __len__(&self) -> usize { diff --git a/src/member.rs b/src/member.rs index cca77e9..64d4f39 100644 --- a/src/member.rs +++ b/src/member.rs @@ -1,4 +1,4 @@ -use crate::utils::Wrapper; +use crate::utils::{AddInput, Wrapper}; use pyo3::class::basic::CompareOp; use pyo3::prelude::*; use pyo3::pyclass::PyClass; @@ -6,22 +6,49 @@ use pyo3::types::PyIterator; use rayon::prelude::*; pub trait Member { - fn add(&self, other: MemberOrMembers) -> Vec; + fn add(&self, other: AddInput, swap: bool) -> PyResult>; fn richcmp(&self, other: &Self, op: CompareOp, py: Python<'_>) -> PyObject; } -impl Member for T { - fn add(&self, other: MemberOrMembers) -> Vec { - match other { - MemberOrMembers::Member(member) => { - vec![self.clone(), member] +impl Member for T +where + T: TryFrom + Send + Clone, +{ + fn add(&self, other: AddInput, swap: bool) -> PyResult> { + Ok(match other { + AddInput::Member(member) => match swap { + true => vec![member, self.clone()], + false => vec![self.clone(), member], + }, + AddInput::Members(members) => { + let mut sequence = Vec::with_capacity(members.len() + 1); + match swap { + false => { + sequence.push(self.clone()); + sequence.extend(members); + } + true => { + sequence.extend(members); + sequence.push(self.clone()); + } + } + sequence } - MemberOrMembers::Sequence(sequence) => { - let mut sequence = sequence; - sequence.insert(0, self.clone()); + AddInput::Codes(codes) => { + let mut sequence = Vec::with_capacity(codes.len() + 1); + match swap { + false => { + sequence.push(self.clone()); + sequence.extend(Wrapper::try_from(codes)?.into_inner()); + } + true => { + sequence.extend(Wrapper::try_from(codes)?.into_inner()); + sequence.push(self.clone()); + } + } sequence } - } + }) } fn richcmp(&self, other: &Self, op: CompareOp, py: Python<'_>) -> PyObject { @@ -59,8 +86,8 @@ where fn try_from(codes: Vec) -> PyResult { Ok(Wrapper( codes - .par_iter() - .map(|c| T::try_from(*c)) + .into_par_iter() + .map(T::try_from) .collect::>()?, )) } diff --git a/src/rnabase.rs b/src/rnabase.rs index 06eef8c..601c443 100644 --- a/src/rnabase.rs +++ b/src/rnabase.rs @@ -1,6 +1,7 @@ use crate::dnabase::DNABase; -use crate::member::{Member, MemberOrMembers}; +use crate::member::Member; use crate::rnasequence::RNASequence; +use crate::utils::AddInput; use pyo3::class::basic::CompareOp; use pyo3::prelude::*; use std::fmt; @@ -107,10 +108,16 @@ impl RNABase { self.get_complement() } - fn __add__(&self, other: MemberOrMembers) -> RNASequence { - RNASequence { - bases: self.add(other), - } + fn __add__(&self, other: AddInput) -> PyResult { + Ok(RNASequence { + bases: self.add(other, false)?, + }) + } + + fn __radd__(&self, other: AddInput) -> PyResult { + Ok(RNASequence { + bases: self.add(other, true)?, + }) } fn __str__(&self) -> String { diff --git a/src/rnasequence.rs b/src/rnasequence.rs index 58c8917..212f148 100644 --- a/src/rnasequence.rs +++ b/src/rnasequence.rs @@ -3,7 +3,7 @@ use crate::dnasequence::DNASequence; use crate::member::{MemberOrCode, MemberOrMembers}; use crate::rnabase::RNABase; use crate::sequence::{Sequence, SequenceInput}; -use crate::utils::IntOrSlice; +use crate::utils::{AddInput, IntOrSlice}; use pyo3::class::basic::CompareOp; use pyo3::prelude::*; use rayon::prelude::*; @@ -61,10 +61,16 @@ impl RNASequence { self.bool() } - fn __add__(&self, other: MemberOrMembers) -> Self { - Self { - bases: self.add(other), - } + fn __add__(&self, other: AddInput) -> PyResult { + Ok(Self { + bases: self.add(other, false)?, + }) + } + + fn __radd__(&self, other: AddInput) -> PyResult { + Ok(Self { + bases: self.add(other, true)?, + }) } fn __len__(&self) -> usize { diff --git a/src/sequence.rs b/src/sequence.rs index f68e927..f320ed4 100644 --- a/src/sequence.rs +++ b/src/sequence.rs @@ -1,5 +1,5 @@ use crate::member::{MemberOrCode, MemberOrMembers}; -use crate::utils::{IntOrSlice, Wrapper}; +use crate::utils::{AddInput, IntOrSlice, Wrapper}; use pyo3::class::basic::CompareOp; use pyo3::prelude::*; use pyo3::pyclass::PyClass; @@ -72,19 +72,60 @@ where } } - fn add(&self, other: MemberOrMembers) -> Vec { - match other { - MemberOrMembers::Member(member) => { - let mut members = self.members().to_vec(); - members.push(member); + fn add(&self, other: AddInput, swap: bool) -> PyResult> + where + T: TryFrom + Send + Clone, + { + Ok(match other { + AddInput::Member(member) => { + let mut members = Vec::with_capacity(self.len() + 1); + + match swap { + true => { + members.push(member); + members.extend(self.members().to_vec()); + } + false => { + members.extend(self.members().to_vec()); + members.push(member); + } + } + + members + } + AddInput::Members(others) => { + let mut members = Vec::with_capacity(self.len() + others.len()); + + match swap { + true => { + members.extend(others); + members.extend(self.members().to_vec()); + } + false => { + members.extend(self.members().to_vec()); + members.extend(others); + } + } + members } - MemberOrMembers::Sequence(sequence) => { - let mut members = self.members().to_vec(); - members.extend(sequence); + AddInput::Codes(codes) => { + let mut members = Vec::with_capacity(self.len() + codes.len()); + + match swap { + true => { + members.extend(Wrapper::try_from(codes)?.into_inner()); + members.extend(self.members().to_vec()); + } + false => { + members.extend(self.members().to_vec()); + members.extend(Wrapper::try_from(codes)?.into_inner()); + } + } + members } - } + }) } fn getitem(&self, index_or_slice: IntOrSlice) -> PyResult> { diff --git a/src/utils.rs b/src/utils.rs index 69c2e9a..f105f08 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -14,3 +14,10 @@ impl Wrapper { self.0 } } + +#[derive(FromPyObject)] +pub enum AddInput<'a, T> { + Member(T), + Members(Vec), + Codes(&'a str), +} diff --git a/tests/test_amino_acid.py b/tests/test_amino_acid.py index baddfa4..41fa811 100644 --- a/tests/test_amino_acid.py +++ b/tests/test_amino_acid.py @@ -573,26 +573,41 @@ def test__bool__() -> None: @pytest.mark.parametrize( "left,right,result", [ + (haem.AminoAcid("M"), haem.AminoAcid("V"), haem.AminoAcidSequence("MV")), ( - haem.AminoAcid.METHIONINE, - haem.AminoAcid.VALINE, - haem.AminoAcidSequence("MV"), - ), - ( - haem.AminoAcid.METHIONINE, + haem.AminoAcid("M"), haem.AminoAcidSequence("VVR"), haem.AminoAcidSequence("MVVR"), ), - ( - haem.AminoAcid.METHIONINE, - haem.AminoAcidSequence(""), - haem.AminoAcidSequence("M"), - ), + (haem.AminoAcid("M"), haem.AminoAcidSequence(), haem.AminoAcidSequence("M")), + (haem.AminoAcid("V"), "M", haem.AminoAcidSequence("VM")), + (haem.AminoAcid("V"), "", haem.AminoAcidSequence("V")), ], ) def test__add__( left: haem.AminoAcid, - right: typing.Union[haem.AminoAcid, haem.AminoAcidSequence], + right: typing.Union[haem.AminoAcid, haem.AminoAcidSequence, str], + result: haem.AminoAcidSequence, +) -> None: + assert left + right == result + + +@pytest.mark.parametrize( + "left,right,result", + [ + ( + haem.AminoAcidSequence("VVR"), + haem.AminoAcid("M"), + haem.AminoAcidSequence("VVRM"), + ), + (haem.AminoAcidSequence(), haem.AminoAcid("M"), haem.AminoAcidSequence("M")), + ("V", haem.AminoAcid("M"), haem.AminoAcidSequence("VM")), + ("", haem.AminoAcid("M"), haem.AminoAcidSequence("M")), + ], +) +def test__radd__( + left: typing.Union[haem.AminoAcidSequence, str], + right: haem.AminoAcid, result: haem.AminoAcidSequence, ) -> None: assert left + right == result diff --git a/tests/test_amino_acid_sequence.py b/tests/test_amino_acid_sequence.py index d0992d5..3cbcddd 100644 --- a/tests/test_amino_acid_sequence.py +++ b/tests/test_amino_acid_sequence.py @@ -136,7 +136,7 @@ def test__bool__(amino_acids: typing.List[haem.AminoAcid], result: bool) -> None [ ( haem.AminoAcidSequence("MV"), - haem.AminoAcid.ARGININE, + haem.AminoAcid("R"), haem.AminoAcidSequence("MVR"), ), ( @@ -146,24 +146,43 @@ def test__bool__(amino_acids: typing.List[haem.AminoAcid], result: bool) -> None ), ( haem.AminoAcidSequence("MV"), - haem.AminoAcidSequence(""), + haem.AminoAcidSequence(), haem.AminoAcidSequence("MV"), ), - ( - haem.AminoAcidSequence(""), - haem.AminoAcidSequence(""), - haem.AminoAcidSequence(""), - ), - ( - haem.AminoAcidSequence(""), - haem.AminoAcid.METHIONINE, - haem.AminoAcidSequence("M"), - ), + (haem.AminoAcidSequence(), haem.AminoAcidSequence(), haem.AminoAcidSequence()), + (haem.AminoAcidSequence(), haem.AminoAcid("M"), haem.AminoAcidSequence("M")), + (haem.AminoAcidSequence(), "", haem.AminoAcidSequence()), + (haem.AminoAcidSequence(), "R", haem.AminoAcidSequence("R")), + (haem.AminoAcidSequence("MV"), "R", haem.AminoAcidSequence("MVR")), + (haem.AminoAcidSequence("MV"), "", haem.AminoAcidSequence("MV")), ], ) def test__add__( left: haem.AminoAcidSequence, - right: typing.Union[haem.AminoAcid, haem.AminoAcidSequence], + right: typing.Union[haem.AminoAcid, haem.AminoAcidSequence, str], + result: haem.AminoAcidSequence, +) -> None: + assert left + right == result + + +@pytest.mark.parametrize( + "left,right,result", + [ + ( + haem.AminoAcid("R"), + haem.AminoAcidSequence("MV"), + haem.AminoAcidSequence("RMV"), + ), + (haem.AminoAcid("M"), haem.AminoAcidSequence(), haem.AminoAcidSequence("M")), + ("", haem.AminoAcidSequence(), haem.AminoAcidSequence()), + ("R", haem.AminoAcidSequence(), haem.AminoAcidSequence("R")), + ("R", haem.AminoAcidSequence("MV"), haem.AminoAcidSequence("RMV")), + ("", haem.AminoAcidSequence("MV"), haem.AminoAcidSequence("MV")), + ], +) +def test__radd__( + left: typing.Union[haem.AminoAcid, str], + right: haem.AminoAcidSequence, result: haem.AminoAcidSequence, ) -> None: assert left + right == result @@ -173,11 +192,11 @@ def test__add__( "sequence,target,result", [ (haem.AminoAcidSequence("M"), haem.AminoAcid.METHIONINE, True), - (haem.AminoAcidSequence(""), haem.AminoAcid.METHIONINE, False), + (haem.AminoAcidSequence(), haem.AminoAcid.METHIONINE, False), (haem.AminoAcidSequence("V"), haem.AminoAcid.METHIONINE, False), (haem.AminoAcidSequence("MVV"), haem.AminoAcid.VALINE, True), (haem.AminoAcidSequence("MVV"), haem.AminoAcid.ARGININE, False), - (haem.AminoAcidSequence(""), haem.AminoAcidSequence(""), True), + (haem.AminoAcidSequence(), haem.AminoAcidSequence(), True), (haem.AminoAcidSequence("MVR"), haem.AminoAcidSequence("VR"), True), (haem.AminoAcidSequence("MVR"), haem.AminoAcidSequence("RV"), False), (haem.AminoAcidSequence("M"), haem.AminoAcidSequence("MM"), False), @@ -224,7 +243,7 @@ def test__getitem__index_out_of_range(index: int) -> None: @pytest.mark.parametrize( "sequence,slic,result", [ - (haem.AminoAcidSequence(""), slice(0, 0), haem.AminoAcidSequence("")), + (haem.AminoAcidSequence(), slice(0, 0), haem.AminoAcidSequence()), (haem.AminoAcidSequence("MVR"), slice(0, 2), haem.AminoAcidSequence("MV")), (haem.AminoAcidSequence("MVR"), slice(1, 3), haem.AminoAcidSequence("VR")), (haem.AminoAcidSequence("MVR"), slice(0, 3), haem.AminoAcidSequence("MVR")), @@ -280,7 +299,7 @@ def test__iter__(amino_acids: typing.List[haem.AminoAcid]) -> None: @pytest.mark.parametrize( "sequence,target,total", [ - (haem.AminoAcidSequence(""), haem.AminoAcid.VALINE, 0), + (haem.AminoAcidSequence(), haem.AminoAcid.VALINE, 0), (haem.AminoAcidSequence("MVRV"), haem.AminoAcid.VALINE, 2), (haem.AminoAcidSequence("MVRV"), "V", 2), ], diff --git a/tests/test_dna_base.py b/tests/test_dna_base.py index db60e7a..9d05a3f 100644 --- a/tests/test_dna_base.py +++ b/tests/test_dna_base.py @@ -174,14 +174,16 @@ def test__bool__(base: haem.DNABase, result: bool) -> None: @pytest.mark.parametrize( "left,right,result", [ - (haem.DNABase.ADENINE, haem.DNABase.GAP, haem.DNASequence("A-")), - (haem.DNABase.ADENINE, haem.DNASequence("CTT"), haem.DNASequence("ACTT")), - (haem.DNABase.ADENINE, haem.DNASequence(""), haem.DNASequence("A")), + (haem.DNABase("A"), haem.DNABase("-"), haem.DNASequence("A-")), + (haem.DNABase("A"), haem.DNASequence("CTT"), haem.DNASequence("ACTT")), + (haem.DNABase("A"), haem.DNASequence(), haem.DNASequence("A")), + (haem.DNABase("A"), "", haem.DNASequence("A")), + (haem.DNABase("A"), haem.DNASequence("T"), haem.DNASequence("AT")), ], ) def test__add__( left: haem.DNABase, - right: typing.Union[haem.DNABase, haem.DNASequence], + right: typing.Union[haem.DNABase, haem.DNASequence, str], result: haem.DNASequence, ) -> None: assert left + right == result @@ -190,12 +192,14 @@ def test__add__( @pytest.mark.parametrize( "left,right,result", [ - (haem.DNASequence("CTT"), haem.DNABase.ADENINE, haem.DNASequence("CTTA")), - (haem.DNASequence(""), haem.DNABase.ADENINE, haem.DNASequence("A")), + (haem.DNASequence("CTT"), haem.DNABase("A"), haem.DNASequence("CTTA")), + (haem.DNASequence(), haem.DNABase("A"), haem.DNASequence("A")), + ("", haem.DNABase("A"), haem.DNASequence("A")), + ("T", haem.DNABase("A"), haem.DNASequence("TA")), ], ) def test__radd__( - left: typing.Union[haem.DNABase, haem.DNASequence], + left: typing.Union[haem.DNASequence, str], right: haem.DNABase, result: haem.DNASequence, ) -> None: diff --git a/tests/test_dna_sequence.py b/tests/test_dna_sequence.py index 95d98b2..9f98a84 100644 --- a/tests/test_dna_sequence.py +++ b/tests/test_dna_sequence.py @@ -66,7 +66,7 @@ def test__new__sequence_str() -> None: @pytest.mark.parametrize( "sequence,complement", [ - (haem.DNASequence(""), haem.DNASequence("")), + (haem.DNASequence(), haem.DNASequence()), (haem.DNASequence("A"), haem.DNASequence("T")), (haem.DNASequence("ACGT"), haem.DNASequence("TGCA")), ], @@ -79,7 +79,7 @@ def test_complement(sequence: haem.DNASequence, complement: haem.DNASequence) -> @pytest.mark.parametrize( "dna_sequence,rna_sequence", [ - (haem.DNASequence(""), haem.RNASequence("")), + (haem.DNASequence(), haem.RNASequence()), (haem.DNASequence("ACGT"), haem.RNASequence("ACGU")), ], ) @@ -148,14 +148,18 @@ def test__bool__(bases: typing.List[haem.DNABase], result: bool) -> None: [ (haem.DNASequence("A-"), haem.DNABase.GUANINE, haem.DNASequence("A-G")), (haem.DNASequence("A-"), haem.DNASequence("CTT"), haem.DNASequence("A-CTT")), - (haem.DNASequence("A-"), haem.DNASequence(""), haem.DNASequence("A-")), - (haem.DNASequence(""), haem.DNASequence(""), haem.DNASequence("")), - (haem.DNASequence(""), haem.DNABase.GUANINE, haem.DNASequence("G")), + (haem.DNASequence("A-"), haem.DNASequence(), haem.DNASequence("A-")), + (haem.DNASequence(), haem.DNASequence(), haem.DNASequence()), + (haem.DNASequence(), haem.DNABase.GUANINE, haem.DNASequence("G")), + (haem.DNASequence("A-"), "", haem.DNASequence("A-")), + (haem.DNASequence("A-"), "GT", haem.DNASequence("A-GT")), + (haem.DNASequence(), "", haem.DNASequence()), + (haem.DNASequence(), "TG", haem.DNASequence("TG")), ], ) def test__add__( left: haem.DNASequence, - right: typing.Union[haem.DNABase, haem.DNASequence], + right: typing.Union[haem.DNABase, haem.DNASequence, str], result: haem.DNASequence, ) -> None: assert left + right == result @@ -164,13 +168,17 @@ def test__add__( @pytest.mark.parametrize( "left,right,result", [ - (haem.DNABase.GUANINE, haem.DNASequence("A-"), haem.DNASequence("GA-")), - (haem.DNABase.GUANINE, haem.DNASequence(""), haem.DNASequence("G")), + (haem.DNABase("G"), haem.DNASequence("A-"), haem.DNASequence("GA-")), + (haem.DNABase("G"), haem.DNASequence(), haem.DNASequence("G")), + ("", haem.DNASequence("A-"), haem.DNASequence("A-")), + ("GT", haem.DNASequence("A-"), haem.DNASequence("GTA-")), + ("", haem.DNASequence(), haem.DNASequence()), + ("TG", haem.DNASequence(), haem.DNASequence("TG")), ], ) def test__radd__( - left: haem.DNASequence, - right: typing.Union[haem.DNABase, haem.DNASequence], + left: typing.Union[haem.DNABase, str], + right: haem.DNASequence, result: haem.DNASequence, ) -> None: assert left + right == result @@ -180,11 +188,11 @@ def test__radd__( "sequence,target,result", [ (haem.DNASequence("A"), haem.DNABase.ADENINE, True), - (haem.DNASequence(""), haem.DNABase.ADENINE, False), + (haem.DNASequence(), haem.DNABase.ADENINE, False), (haem.DNASequence("G"), haem.DNABase.ADENINE, False), (haem.DNASequence("AGCG"), haem.DNABase.GUANINE, True), (haem.DNASequence("AGCG"), haem.DNABase.THYMINE, False), - (haem.DNASequence(""), haem.DNASequence(""), True), + (haem.DNASequence(), haem.DNASequence(), True), (haem.DNASequence("AGT"), haem.DNASequence("GT"), True), (haem.DNASequence("AGT"), haem.DNASequence("TG"), False), (haem.DNASequence("A"), haem.DNASequence("AA"), False), @@ -231,7 +239,7 @@ def test__getitem__index_out_of_range(index: int) -> None: @pytest.mark.parametrize( "sequence,slic,result", [ - (haem.DNASequence(""), slice(0, 0), haem.DNASequence("")), + (haem.DNASequence(), slice(0, 0), haem.DNASequence()), (haem.DNASequence("GAT"), slice(0, 2), haem.DNASequence("GA")), (haem.DNASequence("GAT"), slice(1, 3), haem.DNASequence("AT")), (haem.DNASequence("GAT"), slice(0, 3), haem.DNASequence("GAT")), @@ -270,7 +278,7 @@ def test__iter__(bases: typing.List[haem.DNABase]) -> None: @pytest.mark.parametrize( "sequence,target,total", [ - (haem.DNASequence(""), haem.DNABase.ADENINE, 0), + (haem.DNASequence(), haem.DNABase.ADENINE, 0), (haem.DNASequence("AGCG"), haem.DNABase.GUANINE, 2), (haem.DNASequence("AGCG"), "G", 2), ], diff --git a/tests/test_rna_base.py b/tests/test_rna_base.py index 1a3cb54..6f5130f 100644 --- a/tests/test_rna_base.py +++ b/tests/test_rna_base.py @@ -174,14 +174,16 @@ def test__bool__(base: haem.RNABase, result: bool) -> None: @pytest.mark.parametrize( "left,right,result", [ - (haem.RNABase.ADENINE, haem.RNABase.GAP, haem.RNASequence("A-")), + (haem.RNABase.ADENINE, haem.RNABase("-"), haem.RNASequence("A-")), (haem.RNABase.ADENINE, haem.RNASequence("CUU"), haem.RNASequence("ACUU")), - (haem.RNABase.ADENINE, haem.RNASequence(""), haem.RNASequence("A")), + (haem.RNABase.ADENINE, haem.RNASequence(), haem.RNASequence("A")), + (haem.RNABase.ADENINE, "-", haem.RNASequence("A-")), + (haem.RNABase.ADENINE, "", haem.RNASequence("A")), ], ) def test__add__( left: haem.RNABase, - right: typing.Union[haem.RNABase, haem.RNASequence], + right: typing.Union[haem.RNABase, haem.RNASequence, str], result: haem.RNASequence, ) -> None: assert left + right == result @@ -190,12 +192,14 @@ def test__add__( @pytest.mark.parametrize( "left,right,result", [ - (haem.RNASequence("CUU"), haem.RNABase.ADENINE, haem.RNASequence("CUUA")), - (haem.RNASequence(""), haem.RNABase.ADENINE, haem.RNASequence("A")), + (haem.RNASequence("CUU"), haem.RNABase("A"), haem.RNASequence("CUUA")), + (haem.RNASequence(), haem.RNABase("A"), haem.RNASequence("A")), + ("C", haem.RNABase("A"), haem.RNASequence("CA")), + ("", haem.RNABase("A"), haem.RNASequence("A")), ], ) def test__radd__( - left: typing.Union[haem.RNABase, haem.RNASequence], + left: typing.Union[haem.RNASequence, str], right: haem.RNABase, result: haem.RNASequence, ) -> None: diff --git a/tests/test_rna_sequence.py b/tests/test_rna_sequence.py index cf91c17..dfaad7c 100644 --- a/tests/test_rna_sequence.py +++ b/tests/test_rna_sequence.py @@ -66,7 +66,7 @@ def test__new__sequence_str() -> None: @pytest.mark.parametrize( "sequence,complement", [ - (haem.RNASequence(""), haem.RNASequence("")), + (haem.RNASequence(), haem.RNASequence()), (haem.RNASequence("A"), haem.RNASequence("U")), (haem.RNASequence("ACGU"), haem.RNASequence("UGCA")), ], @@ -79,7 +79,7 @@ def test_complement(sequence: haem.RNASequence, complement: haem.RNASequence) -> @pytest.mark.parametrize( "rna_sequence,dna_sequence", [ - (haem.RNASequence(""), haem.DNASequence("")), + (haem.RNASequence(), haem.DNASequence("")), (haem.RNASequence("ACGU"), haem.DNASequence("ACGT")), ], ) @@ -148,14 +148,18 @@ def test__bool__(bases: typing.List[haem.RNABase], result: bool) -> None: [ (haem.RNASequence("A-"), haem.RNABase.GUANINE, haem.RNASequence("A-G")), (haem.RNASequence("A-"), haem.RNASequence("CUU"), haem.RNASequence("A-CUU")), - (haem.RNASequence("A-"), haem.RNASequence(""), haem.RNASequence("A-")), - (haem.RNASequence(""), haem.RNASequence(""), haem.RNASequence("")), - (haem.RNASequence(""), haem.RNABase.GUANINE, haem.RNASequence("G")), + (haem.RNASequence("A-"), haem.RNASequence(), haem.RNASequence("A-")), + (haem.RNASequence(), haem.RNASequence(), haem.RNASequence()), + (haem.RNASequence(), haem.RNABase.GUANINE, haem.RNASequence("G")), + (haem.RNASequence("A-"), "", haem.RNASequence("A-")), + (haem.RNASequence("A-"), "GU", haem.RNASequence("A-GU")), + (haem.RNASequence(), "", haem.RNASequence()), + (haem.RNASequence(), "UG", haem.RNASequence("UG")), ], ) def test__add__( left: haem.RNASequence, - right: typing.Union[haem.RNABase, haem.RNASequence], + right: typing.Union[haem.RNABase, haem.RNASequence, str], result: haem.RNASequence, ) -> None: assert left + right == result @@ -165,12 +169,16 @@ def test__add__( "left,right,result", [ (haem.RNABase.GUANINE, haem.RNASequence("A-"), haem.RNASequence("GA-")), - (haem.RNABase.GUANINE, haem.RNASequence(""), haem.RNASequence("G")), + (haem.RNABase.GUANINE, haem.RNASequence(), haem.RNASequence("G")), + ("", haem.RNASequence("A-"), haem.RNASequence("A-")), + ("GU", haem.RNASequence("A-"), haem.RNASequence("GUA-")), + ("", haem.RNASequence(), haem.RNASequence()), + ("UG", haem.RNASequence(), haem.RNASequence("UG")), ], ) def test__radd__( - left: haem.RNASequence, - right: typing.Union[haem.RNABase, haem.RNASequence], + left: typing.Union[haem.RNABase, str], + right: haem.RNASequence, result: haem.RNASequence, ) -> None: assert left + right == result @@ -180,11 +188,11 @@ def test__radd__( "sequence,target,result", [ (haem.RNASequence("A"), haem.RNABase.ADENINE, True), - (haem.RNASequence(""), haem.RNABase.ADENINE, False), + (haem.RNASequence(), haem.RNABase.ADENINE, False), (haem.RNASequence("G"), haem.RNABase.ADENINE, False), (haem.RNASequence("AGCG"), haem.RNABase.GUANINE, True), (haem.RNASequence("AGCG"), haem.RNABase.URACIL, False), - (haem.RNASequence(""), haem.RNASequence(""), True), + (haem.RNASequence(), haem.RNASequence(), True), (haem.RNASequence("AGU"), haem.RNASequence("GU"), True), (haem.RNASequence("AGU"), haem.RNASequence("UG"), False), (haem.RNASequence("A"), haem.RNASequence("AA"), False), @@ -231,7 +239,7 @@ def test__getitem__index_out_of_range(index: int) -> None: @pytest.mark.parametrize( "sequence,slic,result", [ - (haem.RNASequence(""), slice(0, 0), haem.RNASequence("")), + (haem.RNASequence(), slice(0, 0), haem.RNASequence()), (haem.RNASequence("GAU"), slice(0, 2), haem.RNASequence("GA")), (haem.RNASequence("GAU"), slice(1, 3), haem.RNASequence("AU")), (haem.RNASequence("GAU"), slice(0, 3), haem.RNASequence("GAU")), @@ -270,7 +278,7 @@ def test__iter__(bases: typing.List[haem.RNABase]) -> None: @pytest.mark.parametrize( "sequence,target,total", [ - (haem.RNASequence(""), haem.RNABase.ADENINE, 0), + (haem.RNASequence(), haem.RNABase.ADENINE, 0), (haem.RNASequence("AGCG"), haem.RNABase.GUANINE, 2), (haem.RNASequence("AGCG"), "G", 2), ],