• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Edinburgh-Genome-Foundry / DnaChisel / 14225235949

02 Apr 2025 04:56PM UTC coverage: 90.508% (+0.5%) from 90.054%
14225235949

push

github

veghp
Bump to v3.2.14

1 of 1 new or added line in 1 file covered. (100.0%)

101 existing lines in 35 files now uncovered.

2994 of 3308 relevant lines covered (90.51%)

0.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.94
/dnachisel/Location.py
1
"""Implements the Location class.
2

3
The class has useful methods for finding overlaps between locations, extract
4
a subsequence from a sequence, etc.
5
"""
6

7
from functools import total_ordering
1✔
8

9
from Bio.SeqFeature import FeatureLocation, SeqFeature
1✔
10

11
from .biotools import reverse_complement
1✔
12
from Bio.SeqFeature import SeqFeature, FeatureLocation
1✔
13

14

15
@total_ordering
1✔
16
class Location:
1✔
17
    """Represent a segment of a sequence, with a start, end, and strand.
18

19
    Warning: we use Python's splicing notation, so Location(5, 10) represents
20
    sequence[5, 6, 7, 8, 9] which corresponds to nucleotides number
21
    6, 7, 8, 9, 10.
22

23
    The data structure is similar to a Biopython's FeatureLocation, but with
24
    different methods for different purposes.
25

26
    Parameters
27
    ----------
28
    start
29
      Lowest position index of the segment.
30

31
    end
32
      Highest position index of the segment.
33

34
    strand
35
      Either 1 or -1 for sense or anti-sense orientation.
36
    """
37

38
    __slots__ = ["strand", "start", "end"]
1✔
39

40
    def __init__(self, start, end, strand=0):
1✔
41
        """Initialize."""
42
        self.start = start
1✔
43
        self.end = end
1✔
44
        self.strand = strand
1✔
45

46
    def overlap_region(self, other_location):
1✔
47
        """Return the overlap span between two locations (None if None)."""
48
        if other_location.start < self.start:
1✔
49
            left_location, right_location = other_location, self
1✔
50
        else:
51
            left_location, right_location = self, other_location
1✔
52

53
        if right_location.start >= left_location.end:
1✔
54
            return None
1✔
55

56
        start = right_location.start
1✔
57
        end = min(left_location.end, right_location.end)
1✔
58
        return Location(start, end, self.strand)
1✔
59

60
    def extended(
1✔
61
        self,
62
        extension_length,
63
        lower_limit=0,
64
        upper_limit=None,
65
        left=True,
66
        right=True,
67
    ):
68
        """Extend the location of a few basepairs on each side."""
69

70
        if left:
1✔
71
            lower = max(lower_limit, self.start - extension_length)
1✔
72
        else:
UNCOV
73
            lower = self.start
×
74

75
        if right:
1✔
76
            upper = self.end + extension_length
1✔
77
            if upper_limit is not None:
1✔
UNCOV
78
                upper = min(upper_limit, upper)
×
79
        else:
80
            upper = self.end
1✔
81

82
        return Location(lower, upper, self.strand)
1✔
83

84
    def extract_sequence(self, sequence):
1✔
85
        """Return the subsequence read at the given location."""
86
        result = sequence[self.start : self.end]
1✔
87
        if self.strand == -1:
1✔
88
            return reverse_complement(result)
1✔
89
        else:
90
            return result
1✔
91

92
    def to_tuple(self):
1✔
93
        """Return (start, end, strand)."""
94
        return (self.start, self.end, self.strand)
1✔
95

96
    @property
1✔
97
    def indices(self):
1✔
98
        result = list(range(self.start, self.end))
1✔
99
        return result if (self.strand != -1) else result[::-1]
1✔
100

101
    def __eq__(self, other):
1✔
102
        """Equal to."""
103
        return self.to_tuple() == other.to_tuple()
1✔
104

105
    def __lt__(self, other):
1✔
106
        """Lower than."""
107
        return self.to_tuple() < other.to_tuple()
1✔
108

109
    def __add__(self, number):
1✔
110
        """Return the location shifted by the number."""
111
        return Location(self.start + number, self.end + number, self.strand)
1✔
112

113
    def __sub__(self, number):
1✔
114
        """Return the location shifted by the number."""
115
        return Location(self.start - number, self.end - number, self.strand)
1✔
116

117
    def __repr__(self):
1✔
118
        """Represent."""
119
        result = "%d-%d" % (self.start, self.end)
1✔
120
        if self.strand is not None:
1✔
121
            result += {1: "(+)", -1: "(-)", 0: ""}[self.strand]
1✔
122
        return result
1✔
123

124
    def __len__(self):
1✔
125
        """Size of the location."""
126
        return self.end - self.start
1✔
127

128
    def __hash__(self):
1✔
129
        return hash(self.to_tuple())
1✔
130

131
    @staticmethod
1✔
132
    def merge_overlapping_locations(locations):
1✔
133
        """Return a list of locations obtained by merging all overlapping."""
134
        if len(locations) == 0:
1✔
135
            return locations
1✔
136
        locations = sorted(locations)
1✔
137
        new_locations = [locations[0]]
1✔
138
        for loc in locations[1:]:
1✔
139
            if new_locations[-1].overlap_region(loc) is not None:
1✔
140
                new_locations[-1].end = max(new_locations[-1].end, loc.end)
1✔
141
            else:
142
                new_locations.append(loc)
1✔
143
        return new_locations
1✔
144

145
    @staticmethod
1✔
146
    def from_biopython_location(location):
1✔
147
        """Return a DnaChisel Location from a Biopython location."""
148
        start, end, strand = [
1✔
149
            None if e is None else int(e)
150
            for e in [location.start, location.end, location.strand]
151
        ]
152
        return Location(start, end, strand)
1✔
153

154
    @staticmethod
1✔
155
    def from_tuple(some_tuple, default_strand=0):
1✔
156
        if len(some_tuple) == 2:
1✔
157
            start, end = some_tuple
1✔
158
            strand = default_strand
1✔
159
        else:
160
            start, end, strand = some_tuple
1✔
161
        return Location(start, end, strand)
1✔
162

163
    @staticmethod
1✔
164
    def from_data(location_data):
1✔
165
        """Return a location, from varied data formats.
166

167
        This method is used in particular in every built-in specification to
168
        quickly standardize the input location.
169

170
        ``location_data`` can be a tuple (start, end) or (start, end, strand),
171
        or a Biopython FeatureLocation, or a Location instance. In any case,
172
        a new Location object will be returned.
173
        """
174
        if location_data is None:
1✔
175
            return None
1✔
176
        if isinstance(location_data, (tuple, list)):
1✔
177
            return Location.from_tuple(location_data)
1✔
178
        if isinstance(location_data, FeatureLocation):
1✔
179
            feature_location = Location.from_biopython_location(location_data)
1✔
180
            if feature_location.strand is None:
1✔
UNCOV
181
                feature_location.strand = 0
×
182
            return feature_location
1✔
183
        if isinstance(location_data, Location):
1✔
184
            return Location(
1✔
185
                location_data.start, location_data.end, location_data.strand
186
            )
187

188
    def to_biopython_location(self):
1✔
189
        """Return a Biopython FeatureLocation equivalent to the location."""
190
        start, end, strand = [
1✔
191
            None if e is None else int(e) for e in [self.start, self.end, self.strand]
192
        ]
193
        return FeatureLocation(start, end, strand)
1✔
194

195
    def to_biopython_feature(self, feature_type="misc_feature", **qualifiers):
1✔
196
        """Return a Biopython SeqFeature with same location and custom
197
        qualifiers."""
198
        return SeqFeature(
1✔
199
            self.to_biopython_location(),
200
            type=feature_type,
201
            qualifiers=qualifiers,
202
        )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc