def test_intersection_error(self): with pytest.raises(MismatchedParentException): EmptyLocation().intersection(SingleInterval(0, 1, Strand.PLUS, parent="seq"), strict_parent_compare=True)
def get_3p_interval(self) -> Location: """Returns the 3' UTR as a location, if it exists. WARNING: If this is a chunk-relative transcript, the result of this function will also be chunk-relative. """ if not self.is_coding: raise NoncodingTranscriptError("No 3' UTR on a non-coding transcript") # handle the edge case where the CDS is full length if self.cds.chunk_relative_location == self.chunk_relative_location: return EmptyLocation() cds_inclusive_end_on_transcript = self.cds_pos_to_transcript(len(self.cds.chunk_relative_location) - 1) return self.chunk_relative_location.relative_interval_to_parent_location( cds_inclusive_end_on_transcript + 1, len(self._location), Strand.PLUS )
def test_reverse_strand(self): assert EmptyLocation().reverse_strand() == EmptyLocation()
class TestFeatureInterval: """Test constructing features of various types""" @pytest.mark.parametrize( "schema,expected", [ (se_unspliced, se_unspliced_repr), (e3_spliced, e3_spliced_repr), (e3_spliced, e3_spliced_repr), (se_unspliced_minus, se_unspliced_repr_minus), (e3_spliced_minus, e3_spliced_repr_minus), ], ) def test_feature_constructor(self, schema, expected): assert str(schema.to_feature_interval()) == expected assert str(schema.to_feature_interval(parent_or_seq_chunk_parent=parent)) == expected @pytest.mark.parametrize( "schema,expected_exception", [ ( FeatureIntervalModel.Schema().load( dict(interval_starts=[0], interval_ends=[], strand=Strand.PLUS.name) ), ValidationException, ), ( FeatureIntervalModel.Schema().load( dict(interval_starts=[0], interval_ends=[2, 5], strand=Strand.PLUS.name) ), ValidationException, ), ( FeatureIntervalModel.Schema().load( dict(interval_starts=[], interval_ends=[2, 5], strand=Strand.PLUS.name) ), ValidationException, ), ], ) def test_feature_excecptions(self, schema, expected_exception): with pytest.raises(expected_exception): _ = schema.to_feature_interval() @pytest.mark.parametrize( "schema,value,expected", [ (e3_spliced, 2, 0), (e3_spliced, 7, 4), (e3_spliced, 14, 9), (e3_spliced_minus, 2, 9), (e3_spliced_minus, 7, 5), (e3_spliced_minus, 14, 0), ], ) def test_sequence_pos_to_feature(self, schema, value, expected): feat = schema.to_feature_interval() assert feat.sequence_pos_to_feature(value) == expected assert feat.chunk_relative_pos_to_feature(value) == expected @pytest.mark.parametrize( "schema,value,expected", [ (e3_spliced, (7, 13, Strand.PLUS), SingleInterval(4, 8, Strand.PLUS)), (e3_spliced_minus, (7, 13, Strand.PLUS), (SingleInterval(2, 6, Strand.MINUS))), ], ) def test_sequence_interval_to_feature(self, schema, value, expected): feat = schema.to_feature_interval() assert feat.sequence_interval_to_feature(*value) == expected assert feat.chunk_relative_interval_to_feature(*value) == expected @pytest.mark.parametrize( "schema,value,expected", [ (e3_spliced, 0, 2), (e3_spliced, 9, 14), (e3_spliced, 4, 7), (e3_spliced_minus, 0, 14), (e3_spliced_minus, 9, 2), (e3_spliced_minus, 5, 7), ], ) def test_feature_pos_to_sequence(self, schema, value, expected): feat = schema.to_feature_interval() assert feat.feature_pos_to_sequence(value) == expected assert feat.feature_pos_to_chunk_relative(value) == expected feat = schema.to_feature_interval(parent_or_seq_chunk_parent=parent) assert feat.feature_pos_to_sequence(value) == expected assert feat.feature_pos_to_chunk_relative(value) == expected @pytest.mark.parametrize( "schema,value,expected", [ (e3_spliced, (0, 5, Strand.PLUS), CompoundInterval([2, 7], [6, 8], Strand.PLUS)), (e3_spliced_minus, (0, 5, Strand.PLUS), CompoundInterval([8, 12], [10, 15], Strand.MINUS)), ], ) def test_feature_interval_to_sequence(self, schema, value, expected): feat = schema.to_feature_interval() assert feat.feature_interval_to_sequence(*value).reset_parent(None) == expected assert feat.feature_interval_to_chunk_relative(*value).reset_parent(None) == expected @pytest.mark.parametrize( "schema,value,expected", [ (e3_spliced, (0, 5, Strand.PLUS), CompoundInterval([2, 7], [6, 8], Strand.PLUS, parent=parent)), (e3_spliced_minus, (0, 5, Strand.PLUS), CompoundInterval([8, 12], [10, 15], Strand.MINUS, parent=parent)), ], ) def test_feature_interval_to_sequence_parent(self, schema, value, expected): feat = schema.to_feature_interval(parent_or_seq_chunk_parent=parent) assert feat.feature_interval_to_sequence(*value) == expected assert feat.feature_interval_to_chunk_relative(*value) == expected @pytest.mark.parametrize( "schema,value,expected", [ ( e3_spliced, SingleInterval(0, 10, Strand.PLUS, parent=parent), dict(interval_starts=(2, 7), interval_ends=(6, 10), strand=Strand.PLUS.name), ), ( e3_spliced_minus, SingleInterval(0, 10, Strand.PLUS, parent=parent), dict(interval_starts=(2, 7), interval_ends=(6, 10), strand=Strand.MINUS.name), ), ], ) def test_intersection(self, schema, value, expected): feat = schema.to_feature_interval(parent_or_seq_chunk_parent=parent) val = feat.intersect(value) expected = FeatureIntervalModel.Schema().load(expected).to_feature_interval(parent_or_seq_chunk_parent=parent) assert str(expected) == str(val) @pytest.mark.parametrize( "schema,value,expected", [ ( e3_spliced, SingleInterval(0, 10, Strand.PLUS), dict(interval_starts=(2, 7), interval_ends=(6, 10), strand=Strand.PLUS.name), ), ( e3_spliced_minus, SingleInterval(0, 10, Strand.PLUS), dict(interval_starts=(2, 7), interval_ends=(6, 10), strand=Strand.MINUS.name), ), ], ) def test_intersection_no_parent(self, schema, value, expected): feat = schema.to_feature_interval() val = feat.intersect(value) expected = FeatureIntervalModel.Schema().load(expected).to_feature_interval() assert str(expected) == str(val) @pytest.mark.parametrize( "schema,parent,expected_spliced", [ (e3_spliced, parent, "ATTCTGGCTA"), (e3_spliced, parent_genome2, "GTATCTTACC"), ( # explicit strand on Parent has no effect e3_spliced, parent_genome2_minus, "GTATCTTACC", ), (e3_spliced_minus, parent, "TAGCCAGAAT"), (e3_spliced_minus, parent_genome2, "GGTAAGATAC"), ( # explicit strand on Parent has no effect e3_spliced_minus, parent_genome2_minus, "GGTAAGATAC", ), ], ) def test_spliced_sequence(self, schema, parent, expected_spliced): feat = schema.to_feature_interval(parent_or_seq_chunk_parent=parent) assert str(feat.get_spliced_sequence()) == expected_spliced @pytest.mark.parametrize( "schema,parent,expected_genomic,expected_stranded_genomic", [ # positive strand, so genomic == genomic_stranded (e3_spliced, parent, "ATTCTTGGACCTA", "ATTCTTGGACCTA"), (e3_spliced, parent_genome2, "GTATTCTTGGACC", "GTATTCTTGGACC"), ( # explicit strand on Parent has no effect e3_spliced, parent_genome2_minus, "GTATTCTTGGACC", "GTATTCTTGGACC", ), (e3_spliced_minus, parent, "ATTCTTGGACCTA", "TAGGTCCAAGAAT"), (e3_spliced_minus, parent_genome2, "GTATTCTTGGACC", "GGTCCAAGAATAC"), ( # explicit strand on Parent flips it e3_spliced_minus, parent_genome2_minus, "GTATTCTTGGACC", "GGTCCAAGAATAC", ), ], ) def test_genomic_sequence(self, schema, parent, expected_genomic, expected_stranded_genomic): feat = schema.to_feature_interval(parent_or_seq_chunk_parent=parent) assert str(feat.get_reference_sequence()) == expected_genomic assert str(feat.get_genomic_sequence()) == expected_stranded_genomic @pytest.mark.parametrize( "schema,expected", [(e3_spliced, "GTATCTTACC"), (e3_spliced_minus, "GGTAAGATAC")], ) def test_reset_parent(self, schema, expected): feat = schema.to_feature_interval(parent_or_seq_chunk_parent=parent) feat._reset_parent(parent_genome2) assert str(feat.get_spliced_sequence()) == str(expected) def test_object_conversion(self): for model in [se_unspliced, e3_spliced_minus, e3_spliced]: obj = model.to_feature_interval() new_model = FeatureIntervalModel.from_feature_interval(obj) new_model.feature_interval_guid = None assert model == new_model obj = model.to_feature_interval(parent_or_seq_chunk_parent=parent) new_model = FeatureIntervalModel.from_feature_interval(obj) new_model.feature_interval_guid = None assert model == new_model def test_identifiers(self): feat = se_unspliced.to_feature_interval() feat.feature_name = "test" feat.feature_id = "testid" assert feat.identifiers == {"test", "testid"} assert feat.identifiers_dict == {"feature_name": "test", "feature_id": "testid"} def test_intersection_exception(self): schema = FeatureIntervalModel.Schema().load( dict(interval_starts=[10], interval_ends=[15], strand=Strand.MINUS.name) ) feat = schema.to_feature_interval() s = SingleInterval(0, 5, Strand.PLUS) with pytest.raises(EmptyLocationException): _ = feat.intersect(s) def test_gff_export_exceptions(self): feat = se_unspliced.to_feature_interval(parent_or_seq_chunk_parent=parent) with pytest.raises(GFF3MissingSequenceNameError): _ = "\n".join(str(x) for x in feat.to_gff()) feat.sequence_name = "myseq" with pytest.raises(NoSuchAncestorException): _ = "\n".join(str(x) for x in feat.to_gff(chromosome_relative_coordinates=False)) def test_gff_export(self): feat = se_unspliced.to_feature_interval(parent_or_seq_chunk_parent=parent) feat.sequence_name = "myseq" assert ( "\n".join(str(x) for x in feat.to_gff()) == "myseq\tBioCantor\tfeature_interval\t1\t18\t.\t+\t.\tID=6940c467-070a-3524-2dcb-a478a6fa0388\n" "myseq\tBioCantor\tsubregion\t1\t18\t.\t+\t.\tID=feature-6940c467-070a-3524-2dcb-a478a6fa0388-1;" "Parent=6940c467-070a-3524-2dcb-a478a6fa0388" ) def test_gff_export_subset(self): feat = e3_spliced.to_feature_interval(parent_or_seq_chunk_parent=parent_genome2_1_15) feat.sequence_name = "myseq" assert ( "\n".join(str(x) for x in feat.to_gff()) == "myseq\tBioCantor\tfeature_interval\t3\t15\t.\t+\t.\tID=c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80\n" "myseq\tBioCantor\tsubregion\t3\t6\t.\t+\t.\tID=feature-c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80-1;" "Parent=c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80\n" "myseq\tBioCantor\tsubregion\t8\t10\t.\t+\t.\tID=feature-c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80-2;" "Parent=c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80\n" "myseq\tBioCantor\tsubregion\t13\t15\t.\t+\t.\tID=feature-c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80-3;" "Parent=c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80" ) assert ( "\n".join(str(x) for x in feat.to_gff(chromosome_relative_coordinates=False)) == "myseq\tBioCantor\tfeature_interval\t2\t14\t.\t+\t.\tID=c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80\n" "myseq\tBioCantor\tsubregion\t2\t5\t.\t+\t.\tID=feature-c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80-1;" "Parent=c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80\n" "myseq\tBioCantor\tsubregion\t7\t9\t.\t+\t.\tID=feature-c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80-2;" "Parent=c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80\n" "myseq\tBioCantor\tsubregion\t12\t14\t.\t+\t.\tID=feature-c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80-3;" "Parent=c45e8d7b-cbd6-43b2-bb08-429d9cb7fe80" ) @pytest.mark.parametrize( "feature,parent,expected_span", [ (e3_spliced, None, SingleInterval(2, 15, Strand.PLUS)), (e3_spliced_minus, None, SingleInterval(2, 15, Strand.MINUS)), (se_unspliced, None, SingleInterval(0, 18, Strand.PLUS)), (se_unspliced, None, SingleInterval(0, 18, Strand.PLUS)), (e3_spliced, parent_genome2, SingleInterval(2, 15, Strand.PLUS, parent=parent_genome2)), (e3_spliced_minus, parent_genome2, SingleInterval(2, 15, Strand.MINUS, parent=parent_genome2)), (se_unspliced, parent_genome2, SingleInterval(0, 18, Strand.PLUS, parent=parent_genome2)), (se_unspliced, parent_genome2, SingleInterval(0, 18, Strand.PLUS, parent=parent_genome2)), ( e3_spliced, parent_genome2_1_15, SingleInterval( 2, 15, Strand.PLUS, parent=parent_genome2_1_15.first_ancestor_of_type(SequenceType.CHROMOSOME) ), ), ( e3_spliced_minus, parent_genome2_1_15, SingleInterval( 2, 15, Strand.MINUS, parent=parent_genome2_1_15.first_ancestor_of_type(SequenceType.CHROMOSOME) ), ), ( e3_spliced, parent_genome2_2_8, SingleInterval( 2, 15, Strand.PLUS, parent=parent_genome2_2_8.first_ancestor_of_type(SequenceType.CHROMOSOME) ), ), ( e3_spliced_minus, parent_genome2_2_8, SingleInterval( 2, 15, Strand.MINUS, parent=parent_genome2_2_8.first_ancestor_of_type(SequenceType.CHROMOSOME) ), ), ], ) def test_chromosome_span(self, feature, parent, expected_span): feat = feature.to_feature_interval(parent) assert feat.chromosome_span == expected_span @pytest.mark.parametrize( "feature,parent,expected_gaps", [ (e3_spliced, None, CompoundInterval([6, 10], [7, 12], Strand.PLUS)), (e3_spliced_minus, None, CompoundInterval([6, 10], [7, 12], Strand.MINUS)), (se_unspliced, None, EmptyLocation()), (se_unspliced, None, EmptyLocation()), (e3_spliced, parent_genome2, CompoundInterval([6, 10], [7, 12], Strand.PLUS, parent=parent_genome2)), (e3_spliced_minus, parent_genome2, CompoundInterval([6, 10], [7, 12], Strand.MINUS, parent=parent_genome2)), (se_unspliced, parent_genome2, EmptyLocation()), (se_unspliced, parent_genome2, EmptyLocation()), ( e3_spliced, parent_genome2_1_15, CompoundInterval( [6, 10], [7, 12], Strand.PLUS, parent=parent_genome2_1_15.first_ancestor_of_type(SequenceType.CHROMOSOME), ), ), ( e3_spliced_minus, parent_genome2_1_15, CompoundInterval( [6, 10], [7, 12], Strand.MINUS, parent=parent_genome2_1_15.first_ancestor_of_type(SequenceType.CHROMOSOME), ), ), (se_unspliced, parent_genome2_1_15, EmptyLocation()), (se_unspliced, parent_genome2_1_15, EmptyLocation()), ( e3_spliced, parent_genome2_2_8, CompoundInterval( [6, 10], [7, 12], Strand.PLUS, parent=parent_genome2_1_15.first_ancestor_of_type(SequenceType.CHROMOSOME), ), ), ( e3_spliced_minus, parent_genome2_2_8, CompoundInterval( [6, 10], [7, 12], Strand.MINUS, parent=parent_genome2_1_15.first_ancestor_of_type(SequenceType.CHROMOSOME), ), ), ], ) def test_chromosome_gaps_location(self, feature, parent, expected_gaps): feat = feature.to_feature_interval(parent) assert feat.chromosome_gaps_location == expected_gaps
def test_parent_to_relative_location(self): with pytest.raises(EmptyLocationException): EmptyLocation().parent_to_relative_location( SingleInterval(0, 0, Strand.PLUS))
def test_extract_sequence(self): with pytest.raises(EmptyLocationException): EmptyLocation().extract_sequence()
def test_gap_list(self): assert EmptyLocation().gap_list() == []
def test_num_blocks(self): assert EmptyLocation().num_blocks == 0
def test_merge_overlapping(self): assert EmptyLocation().merge_overlapping() == EmptyLocation()
def test_length(self): assert EmptyLocation().length == 0
def test_distance_to(self): with pytest.raises(EmptyLocationException): EmptyLocation().distance_to(EmptyLocation())
def test_shift_position(self): with pytest.raises(EmptyLocationException): EmptyLocation().shift_position(0)
def test_extend_relative(self): with pytest.raises(EmptyLocationException): EmptyLocation().extend_relative(0, 0)
def test_reset_parent(self): with pytest.raises(EmptyLocationException): EmptyLocation().reset_parent(None)
def test_reset_strand(self): with pytest.raises(EmptyLocationException): EmptyLocation().reset_strand(Strand.PLUS)
def test_blocks(self): assert EmptyLocation().blocks == []
def test_scan_blocks(self): assert not EmptyLocation().scan_blocks()
def test_first_ancestor_of_type(self): with pytest.raises(EmptyLocationException): EmptyLocation().first_ancestor_of_type("seqtype")
def test_optimize_blocks(self): assert EmptyLocation().optimize_blocks() == EmptyLocation()
def test_has_ancestor_of_type(self): assert EmptyLocation().has_ancestor_of_type("seqtype") is False
def test_gaps_location(self): assert EmptyLocation().gaps_location() == EmptyLocation()
def test_union_preserve_overlaps(self): with pytest.raises(EmptyLocationException): EmptyLocation().union_preserve_overlaps( SingleInterval(0, 1, Strand.PLUS))
def test_relative_to_parent_pos(self): with pytest.raises(EmptyLocationException): EmptyLocation().relative_to_parent_pos(0)
def test_parent(self): assert EmptyLocation().parent is None
def test_intersection(self, other): assert EmptyLocation().intersection(other) == EmptyLocation()
def test_start(self): with pytest.raises(EmptyLocationException): EmptyLocation().start
class TestParent: @pytest.mark.parametrize( "id,sequence_type,strand,location,sequence,expected", [ (None, None, None, None, None, Parent()), ( "id", "seqtype", Strand.MINUS, SingleInterval( 0, 1, Strand.MINUS, Parent( id="id", sequence_type="seqtype", strand=Strand.MINUS, sequence=Sequence( "AAA", Alphabet.NT_STRICT, id="id", type="seqtype", parent=Parent( id="id2", sequence=Sequence("CCC", Alphabet.NT_STRICT, id="id2"), ), ), ), ), Sequence( "AAA", Alphabet.NT_STRICT, id="id", type="seqtype", parent=Parent(id="id2", sequence=Sequence("CCC", Alphabet.NT_STRICT, id="id2")), ), Parent( id="id", sequence_type="seqtype", strand=Strand.MINUS, location=SingleInterval( 0, 1, Strand.MINUS, Parent( id="id", sequence_type="seqtype", strand=Strand.MINUS, sequence=Sequence( "AAA", Alphabet.NT_STRICT, id="id", type="seqtype", parent=Parent( id="id2", sequence=Sequence("CCC", Alphabet.NT_STRICT, id="id2"), ), ), ), ), sequence=Sequence( "AAA", Alphabet.NT_STRICT, id="id", type="seqtype", parent=Parent( id="id2", sequence=Sequence("CCC", Alphabet.NT_STRICT, id="id2"), ), ), ), ), ], ) def test_init(self, id, sequence_type, strand, location, sequence, expected): assert expected == Parent( id=id, sequence_type=sequence_type, strand=strand, location=location, sequence=sequence, ) @pytest.mark.parametrize( "id,sequence_type,strand,location,sequence,parent,expected_exception", [ ("id1", None, None, SingleInterval(0, 5, Strand.PLUS, parent="id2"), None, None, ParentException), ("id1", None, None, None, Sequence("AAA", Alphabet.NT_STRICT, id="id2"), None, ParentException), ( None, None, None, SingleInterval(0, 5, Strand.PLUS, parent="id1"), Sequence("AAC", Alphabet.NT_STRICT, id="id2"), None, ParentException, ), ( None, "seqtype", None, SingleInterval(0, 5, Strand.PLUS, parent=Parent(sequence_type="unknown")), None, None, ParentException, ), (None, "seqtype", None, None, Sequence("AAT", Alphabet.NT_STRICT, type="unknown"), None, ParentException), ( None, None, None, SingleInterval(0, 5, Strand.PLUS, parent=Parent(sequence_type="unknown")), Sequence("AAG", Alphabet.NT_STRICT, type="seqtype"), None, ParentException, ), (None, None, Strand.MINUS, SingleInterval(0, 5, Strand.PLUS), None, None, InvalidStrandException), ( None, None, None, SingleInterval(0, 10, Strand.PLUS), Sequence("A", Alphabet.NT_STRICT), None, InvalidPositionException, ), ( None, None, None, None, Sequence("AA", Alphabet.NT_STRICT), Parent(sequence=Sequence("A", Alphabet.NT_STRICT)), LocationException, ), (None, None, Strand.PLUS, SingleInterval(5, 10, Strand.MINUS), None, None, InvalidStrandException), ( None, None, None, None, Sequence("AA", Alphabet.NT_STRICT, parent="id1"), Parent(id="id2"), MismatchedParentException, ), ], ) def test_init_error(self, id, sequence_type, strand, location, sequence, parent, expected_exception): with pytest.raises(expected_exception): Parent( id=id, sequence_type=sequence_type, strand=strand, location=location, sequence=sequence, parent=parent, ) @pytest.mark.parametrize( "obj,expected", [ ( Sequence("AAA", Alphabet.NT_STRICT), Parent(sequence=Sequence("AAA", Alphabet.NT_STRICT)), ), ("parent", Parent(id="parent")), ( SingleInterval(5, 10, Strand.PLUS), Parent(location=SingleInterval(5, 10, Strand.PLUS)), ), ( CompoundInterval([5], [10], Strand.PLUS), Parent(location=CompoundInterval([5], [10], Strand.PLUS)), ), (EmptyLocation(), Parent(location=EmptyLocation())), (Strand.MINUS, Parent(strand=Strand.MINUS)), ( Parent( id="parent", sequence_type="chr", strand=Strand.MINUS, parent=Parent(id="grandparent"), ), Parent( id="parent", sequence_type="chr", strand=Strand.MINUS, parent=Parent(id="grandparent"), ), ), ], ) def test_make_parent(self, obj, expected): assert make_parent(obj) == expected @pytest.mark.parametrize( "parent1,parent2,expected", [ (Parent(), Parent(), True), (Parent(), Parent(id=None, sequence_type=None), True), (Parent(id="id1"), Parent(id="id2"), False), ( Parent(sequence_type=None), Parent(sequence_type="unknown"), False, ), (Parent(strand=Strand.UNSTRANDED), Parent(strand=Strand.MINUS), False), ( Parent(location=SingleInterval(0, 5, Strand.PLUS, parent="id1")), Parent(location=SingleInterval(0, 5, Strand.PLUS, parent="id2")), False, ), ( Parent(sequence=Sequence("A", Alphabet.NT_STRICT)), Parent(sequence=Sequence("A", Alphabet.NT_STRICT, parent=Parent(id="parent"))), False, ), ( Parent(parent="parent1"), Parent(parent="parent2"), False, ), ], ) def test_eq(self, parent1, parent2, expected): assert (parent1 == parent2) is expected @pytest.mark.parametrize( "parent1,parent2,expected", [ (Parent(), Parent(), True), (Parent(id="id1"), Parent(id="id2"), False), ( Parent(sequence_type=None), Parent(sequence_type="unknown"), False, ), (Parent(strand=Strand.UNSTRANDED), Parent(strand=Strand.MINUS), True), ( Parent(location=SingleInterval(0, 5, Strand.PLUS, parent="id1")), Parent(location=SingleInterval(0, 5, Strand.PLUS, parent="id2")), False, ), ( Parent(sequence=Sequence("A", Alphabet.NT_STRICT)), Parent(sequence=Sequence("A", Alphabet.NT_STRICT, parent="parent")), False, ), ( Parent(parent="parent1"), Parent(parent="parent2"), False, ), ], ) def test_equals_except_location(self, parent1, parent2, expected): assert parent1.equals_except_location(parent2) is expected @pytest.mark.parametrize( "id,location,sequence,expected", [ ("id", None, None, "id"), ( None, SingleInterval(0, 1, Strand.PLUS, parent="id"), None, "id", ), ( None, None, Sequence("A", Alphabet.NT_STRICT, id="id", parent="id2"), "id", ), ( "id", SingleInterval(0, 1, Strand.PLUS, parent="id"), Sequence("A", Alphabet.NT_STRICT, id="id", parent="id2"), "id", ), ], ) def test_id(self, id, location, sequence, expected): assert Parent(id=id, location=location, sequence=sequence).id == expected @pytest.mark.parametrize( "sequence_type,location,sequence,expected", [ ("seqtype", None, None, "seqtype"), ( None, SingleInterval( 0, 5, Strand.PLUS, parent=Parent(sequence_type="seqtype"), ), None, "seqtype", ), ( None, None, Sequence("A", Alphabet.NT_STRICT, type="seqtype"), "seqtype", ), ( None, None, Sequence( "A", Alphabet.NT_STRICT, type="seqtype", parent=Parent(sequence_type="seqtype_2"), ), "seqtype", ), ], ) def test_sequence_type(self, sequence_type, location, sequence, expected): assert Parent(sequence_type=sequence_type, location=location, sequence=sequence).sequence_type == expected @pytest.mark.parametrize( "strand,location,sequence,expected", [ (Strand.PLUS, None, None, Strand.PLUS), (None, SingleInterval(0, 5, Strand.MINUS), None, Strand.MINUS), ( Strand.PLUS, None, Sequence("A", Alphabet.NT_STRICT, parent=Strand.MINUS), Strand.PLUS, ), ], ) def test_strand(self, strand, location, sequence, expected): assert Parent(strand=strand, location=location, sequence=sequence).strand == expected def test_location(self): assert Parent(location=SingleInterval(0, 1, Strand.PLUS)).location == SingleInterval(0, 1, Strand.PLUS) def test_sequence(self): assert Parent(sequence=Sequence("A", Alphabet.NT_STRICT)).sequence == Sequence("A", Alphabet.NT_STRICT) @pytest.mark.parametrize( "parent,expected", [ (Parent(parent="id"), Parent(id="id")), ( Parent( sequence=Sequence( "AA", Alphabet.NT_STRICT, parent=Parent(sequence_type="chr"), ) ), Parent(sequence_type="chr"), ), ], ) def test_parent(self, parent, expected): assert parent.parent == expected @pytest.mark.parametrize( "parent,expected", [ (Parent(), Parent()), (Parent(strand=Strand.PLUS), Parent()), ( Parent(strand=Strand.PLUS, location=SingleInterval(5, 10, Strand.PLUS)), Parent(), ), ( Parent( id="parent", sequence_type="unknown", strand=Strand.PLUS, location=SingleInterval(0, 1, Strand.PLUS), sequence=Sequence("AAA", Alphabet.NT_STRICT), parent="grandparent", ), Parent( id="parent", sequence_type="unknown", sequence=Sequence("AAA", Alphabet.NT_STRICT), parent="grandparent", ), ), ], ) def test_strip_location_info(self, parent, expected): assert parent.strip_location_info() == expected @pytest.mark.parametrize( "parent,sequence_type,include_self,expected", [ ( Parent( id="self", sequence_type="seqtype", parent=Parent(id="parent", sequence_type="seqtype"), ), "seqtype", True, Parent( id="self", sequence_type="seqtype", parent=Parent(id="parent", sequence_type="seqtype"), ), ), ( Parent( id="self", sequence_type="seqtype", parent=Parent(id="parent", sequence_type="seqtype"), ), "seqtype", False, Parent(id="parent", sequence_type="seqtype"), ), ( Parent( id="self", sequence_type="seqtype", parent=Parent( id="parent", sequence_type="seqtype_2", parent=Parent(id="grandparent", sequence_type="seqtype_2"), ), ), "seqtype_2", True, Parent( id="parent", sequence_type="seqtype_2", parent=Parent(id="grandparent", sequence_type="seqtype_2"), ), ), ], ) def test_first_ancestor_of_type(self, parent, sequence_type, include_self, expected): assert parent.first_ancestor_of_type(sequence_type, include_self=include_self) == expected @pytest.mark.parametrize( "parent,sequence_type,include_self", [ (Parent(id="self"), "seqtype_2", True), ( Parent(id="self", parent="parent"), "seqtype_2", True, ), ( Parent( id="self", sequence_type="seqtype", parent=Parent( id="parent", sequence_type="seqtype_2", parent=Parent(id="grandparent", sequence_type="seqtype_2"), ), ), "chr", True, ), ], ) def test_first_ancestor_of_type_error(self, parent, sequence_type, include_self): with pytest.raises(NoSuchAncestorException): parent.first_ancestor_of_type(sequence_type, include_self=include_self) @pytest.mark.parametrize( "parent,sequence_type,include_self,expected", [ ( Parent( id="self", sequence_type="seqtype", parent=Parent(id="parent", sequence_type="seqtype"), ), "seqtype", True, True, ), ( Parent( id="self", sequence_type="seqtype", parent=Parent(id="parent", sequence_type="seqtype"), ), "seqtype", False, True, ), ( Parent( id="self", sequence_type="seqtype", parent=Parent( id="parent", sequence_type="seqtype_2", parent=Parent(id="grandparent", sequence_type="seqtype_2"), ), ), "seqtype_2", True, True, ), ( Parent(id="self"), "seqtype_2", True, False, ), ( Parent(id="self", parent="parent"), "seqtype_2", True, False, ), ( Parent( id="self", sequence_type="seqtype", parent=Parent( id="parent", sequence_type="seqtype_2", parent=Parent(id="grandparent", sequence_type="seqtype_2"), ), ), "chr", True, False, ), ], ) def test_has_ancestor_of_type(self, parent, sequence_type, include_self, expected): assert parent.has_ancestor_of_type(sequence_type, include_self=include_self) is expected @pytest.mark.parametrize( "parent,expected", [ ( Parent( id="parent", location=SingleInterval(3, 5, Strand.PLUS), parent=Parent(id="grandparent", location=SingleInterval(10, 20, Strand.PLUS)), ), SingleInterval(13, 15, Strand.PLUS, parent="grandparent"), ), ( Parent( id="parent", location=SingleInterval(0, 5, Strand.PLUS), sequence_type="unknown", strand=Strand.PLUS, parent=Parent( id="grandparent", location=SingleInterval(100, 200, Strand.MINUS), ), ), SingleInterval(195, 200, Strand.MINUS, parent="grandparent"), ), ( Parent( id="parent", location=SingleInterval(6, 9, Strand.MINUS), parent=Parent( id="grandparent", location=SingleInterval(0, 10, Strand.PLUS), sequence_type="chr", strand=Strand.PLUS, parent="great grandparent", ), ), SingleInterval( 6, 9, Strand.MINUS, parent=Parent( id="grandparent", sequence_type="chr", parent="great grandparent", ), ), ), ( Parent( id="parent", sequence_type="chr", strand=Strand.MINUS, location=SingleInterval(6, 8, Strand.MINUS), parent=Parent( id="grandparent", sequence_type="unknown", strand=Strand.MINUS, location=SingleInterval(5, 15, Strand.MINUS), parent="great grandparent", ), ), SingleInterval( 7, 9, Strand.PLUS, parent=Parent( id="grandparent", sequence_type="unknown", parent="great grandparent", ), ), ), ( Parent( id="parent", location=SingleInterval(3, 5, Strand.UNSTRANDED), parent=Parent(id="grandparent", location=SingleInterval(10, 20, Strand.PLUS)), ), SingleInterval(13, 15, Strand.UNSTRANDED, parent="grandparent"), ), ( Parent( id="parent", location=SingleInterval(3, 5, Strand.UNSTRANDED), parent=Parent(id="grandparent", location=SingleInterval(10, 20, Strand.MINUS)), ), SingleInterval(15, 17, Strand.UNSTRANDED, parent="grandparent"), ), ], ) def test_lift_child_location_contiguous_to_parent_single_interval(self, parent, expected): assert parent.lift_child_location_to_parent() == expected @pytest.mark.parametrize( "parent,expected", [ ( Parent( id="parent", location=CompoundInterval([3, 7], [5, 10], Strand.PLUS), parent=Parent(id="grandparent", location=SingleInterval(10, 20, Strand.PLUS)), ), CompoundInterval([13, 17], [15, 20], Strand.PLUS, parent="grandparent"), ), ( Parent( id="parent", location=CompoundInterval([0, 10], [5, 15], Strand.PLUS), sequence_type="unknown", strand=Strand.PLUS, parent=Parent( id="grandparent", location=SingleInterval(100, 200, Strand.MINUS), ), ), CompoundInterval( [185, 195], [190, 200], Strand.MINUS, parent="grandparent", ), ), ( Parent( id="parent", location=CompoundInterval([6], [9], Strand.MINUS), parent=Parent( id="grandparent", location=SingleInterval(0, 10, Strand.PLUS), sequence_type="chr", strand=Strand.PLUS, parent="great grandparent", ), ), SingleInterval( 6, 9, Strand.MINUS, parent=Parent( id="grandparent", sequence_type="chr", parent="great grandparent", ), ), ), ( Parent( id="parent", sequence_type="chr", strand=Strand.MINUS, location=CompoundInterval([6], [8], Strand.MINUS), parent=Parent( id="grandparent", sequence_type="unknown", strand=Strand.MINUS, location=SingleInterval(5, 15, Strand.MINUS), parent="great grandparent", ), ), SingleInterval( 7, 9, Strand.PLUS, parent=Parent( id="grandparent", sequence_type="unknown", parent="great grandparent", ), ), ), ( Parent( id="parent", location=CompoundInterval([3, 7], [5, 10], Strand.UNSTRANDED), parent=Parent(id="grandparent", location=SingleInterval(10, 20, Strand.PLUS)), ), CompoundInterval( [13, 17], [15, 20], Strand.UNSTRANDED, parent="grandparent", ), ), ( Parent( id="parent", location=CompoundInterval([3], [5], Strand.UNSTRANDED), parent=Parent(id="grandparent", location=SingleInterval(10, 20, Strand.MINUS)), ), SingleInterval(15, 17, Strand.UNSTRANDED, parent="grandparent"), ), ], ) def test_lift_child_location_discontiguous_to_parent_single_interval(self, parent, expected): assert parent.lift_child_location_to_parent() == expected @pytest.mark.parametrize( "parent,expected_error", [ # No location ( Parent(parent=SingleInterval(5, 10, Strand.PLUS)), NullParentException, ), # Parent has no location ( Parent( location=SingleInterval(5, 10, Strand.PLUS), parent="grandparent", ), NullParentException, ), # Location on parent can't be unstranded ( Parent( location=SingleInterval(5, 10, Strand.PLUS), parent=Parent( id="grandparent", location=SingleInterval(0, 100, Strand.UNSTRANDED), ), ), InvalidStrandException, ), # Location must fit inside location on parent ( Parent( location=SingleInterval(5, 10, Strand.PLUS), parent=Parent(id="grandparent", location=SingleInterval(30, 31, Strand.PLUS)), ), ValueError, ), ], ) def test_lift_child_location_to_parent_single_interval_error(self, parent, expected_error): with pytest.raises(expected_error): parent.lift_child_location_to_parent() @pytest.mark.parametrize( "parent,expected", [ # Location takes up entire parent location ( Parent( id="parent", location=SingleInterval(0, 10, Strand.PLUS), parent=Parent( id="grandparent", location=CompoundInterval([5, 20], [10, 25], Strand.PLUS), ), ), CompoundInterval([5, 20], [10, 25], Strand.PLUS, parent="grandparent"), ), # Location (unstranded) takes up part of parent location (minus) ( Parent( id="parent", location=SingleInterval(10, 20, Strand.UNSTRANDED), parent=Parent( id="grandparent", location=CompoundInterval([10, 20, 30], [18, 28, 38], Strand.MINUS), ), ), CompoundInterval( [14, 20], [18, 26], Strand.UNSTRANDED, parent="grandparent", ), ), # Location (minus) takes up one block of parent location (plus); location is at end of sequence ( Parent( id="parent", location=SingleInterval(5, 10, Strand.MINUS), parent=Parent( id="grandparent", location=CompoundInterval([30, 40], [35, 45], Strand.PLUS), ), ), SingleInterval(40, 45, Strand.MINUS, parent="grandparent"), ), # Location (minus) takes up part of one block of parent location (minus) ( Parent( id="parent", location=SingleInterval(0, 4, Strand.MINUS), parent=Parent( id="grandparent", location=CompoundInterval([30, 40], [35, 45], Strand.MINUS), ), ), SingleInterval(41, 45, Strand.PLUS, parent="grandparent"), ), ], ) def test_lift_child_location_contiguous_to_parent_compound_interval(self, parent, expected): assert parent.lift_child_location_to_parent() == expected @pytest.mark.parametrize( "parent,expected", [ # Location takes up entire parent location ( Parent( id="parent", location=CompoundInterval([0, 5], [5, 10], Strand.PLUS), parent=Parent( id="grandparent", location=CompoundInterval([5, 20], [10, 25], Strand.PLUS), ), ), CompoundInterval([5, 20], [10, 25], Strand.PLUS, parent="grandparent"), ), # Location (unstranded) takes up part of parent location (minus) ( Parent( id="parent", location=CompoundInterval([10, 22], [20, 23], Strand.UNSTRANDED), parent=Parent( id="grandparent", location=CompoundInterval([10, 20, 30], [18, 28, 38], Strand.MINUS), ), ), CompoundInterval( [11, 14, 20], [12, 18, 26], Strand.UNSTRANDED, parent="grandparent", ), ), # Location (minus) takes up one block of parent location (plus); location is at end of sequence ( Parent( id="parent", location=CompoundInterval([5], [10], Strand.MINUS), parent=Parent( id="grandparent", location=CompoundInterval([30, 40], [35, 45], Strand.PLUS), ), ), SingleInterval(40, 45, Strand.MINUS, parent="grandparent"), ), # Location (minus) takes up part of one block of parent location (minus) ( Parent( id="parent", location=CompoundInterval([0, 3], [1, 4], Strand.MINUS), parent=Parent( id="grandparent", location=CompoundInterval([30, 40], [35, 45], Strand.MINUS), ), ), CompoundInterval([41, 44], [42, 45], Strand.PLUS, parent="grandparent"), ), ], ) def test_lift_child_location_discontiguous_to_parent_compound_interval(self, parent, expected): assert parent.lift_child_location_to_parent() == expected @pytest.mark.parametrize( "parent,expected_error", [ # Location must fit inside location on parent ( Parent( location=SingleInterval(5, 50, Strand.PLUS), parent=Parent( id="grandparent", location=CompoundInterval([10, 20], [15, 25], Strand.PLUS), ), ), InvalidPositionException, ), ], ) def test_lift_child_location_to_parent_compound_interval_error(self, parent, expected_error): with pytest.raises(expected_error): parent.lift_child_location_to_parent() @pytest.mark.parametrize( "parent,location,expected", [ ( Parent(), SingleInterval(5, 10, Strand.PLUS), Parent(location=SingleInterval(5, 10, Strand.PLUS), strand=Strand.PLUS), ), ( Parent( id="parent", sequence_type="unknown", strand=Strand.MINUS, location=SingleInterval(0, 2, Strand.MINUS), sequence=Sequence("AAA", Alphabet.NT_STRICT), ), SingleInterval(2, 3, Strand.PLUS), Parent( id="parent", sequence_type="unknown", strand=Strand.PLUS, location=SingleInterval(2, 3, Strand.PLUS), sequence=Sequence("AAA", Alphabet.NT_STRICT), ), ), ( Parent( id="parent", sequence_type="unknown", strand=Strand.MINUS, location=SingleInterval(0, 2, Strand.MINUS), sequence=Sequence("AAA", Alphabet.NT_STRICT), ), None, Parent( id="parent", sequence_type="unknown", sequence=Sequence("AAA", Alphabet.NT_STRICT), ), ), ], ) def test_reset_location(self, parent, location, expected): assert parent.reset_location(location) == expected @pytest.mark.parametrize( "parent,location,expected_exception", [ ( Parent(sequence=Sequence("AAA", Alphabet.NT_STRICT)), SingleInterval(0, 5, Strand.PLUS), InvalidPositionException, ), ( Parent(id="id1", sequence=Sequence("AAA", Alphabet.NT_STRICT)), SingleInterval( 0, 1, Strand.PLUS, parent=Parent(id="id2", sequence=Sequence("AAA", Alphabet.NT_STRICT)), ), ParentException, ), ], ) def test_reset_location_error(self, parent, location, expected_exception): with pytest.raises(expected_exception): parent.reset_location(location) @pytest.mark.parametrize( "parent,sequence,include_self,expected", [ (Parent(), Sequence("AA", Alphabet.NT_STRICT), True, False), (Parent(), Sequence("AA", Alphabet.NT_STRICT), False, False), ( Parent(sequence=Sequence("AA", Alphabet.NT_STRICT)), Sequence("AA", Alphabet.NT_STRICT), True, True, ), ( Parent(sequence=Sequence("AA", Alphabet.NT_STRICT)), Sequence("AA", Alphabet.NT_STRICT), False, False, ), ( Parent( sequence=Sequence("AA", Alphabet.NT_STRICT), parent=Sequence("AA", Alphabet.NT_STRICT), ), Sequence("AA", Alphabet.NT_STRICT), False, True, ), ( Parent( sequence=Sequence("AA", Alphabet.NT_STRICT), parent=Sequence("AAT", Alphabet.NT_STRICT), ), Sequence("AAT", Alphabet.NT_STRICT), False, True, ), ( Parent( sequence=Sequence("AA", Alphabet.NT_STRICT), parent=Sequence("AAT", Alphabet.NT_STRICT), ), Sequence("AAT", Alphabet.NT_STRICT, id="id"), True, False, ), ( Parent( parent=Parent(parent=Parent(parent=Parent(sequence=Sequence("AAA", Alphabet.NT_STRICT, id="seq")))) ), Sequence("AAA", Alphabet.NT_STRICT, id="seq"), True, True, ), ], ) def test_has_ancestor_sequence(self, parent, sequence, include_self, expected): assert parent.has_ancestor_sequence(sequence, include_self) == expected
def test_end(self): with pytest.raises(EmptyLocationException): EmptyLocation().end
def test_is_contiguous(self): with pytest.raises(EmptyLocationException): EmptyLocation().is_contiguous
def test_reverse(self): assert EmptyLocation().reverse() == EmptyLocation()