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

Edinburgh-Genome-Foundry / DnaChisel / 5190565251

pending completion
5190565251

push

github

veghp
Bump to v3.2.11

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

2966 of 3299 relevant lines covered (89.91%)

0.9 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
from functools import total_ordering
1✔
7

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

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

13

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

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

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

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

30
    end
31
      Highest position index of the segment.
32

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

194
    def to_biopython_feature(self, feature_type="misc_feature", **qualifiers):
1✔
195
        """Return a Biopython SeqFeature with same location and custom
196
        qualifiers."""
197
        return SeqFeature(
1✔
198
            self.to_biopython_location(),
199
            type=feature_type,
200
            qualifiers=qualifiers,
201
        )
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

© 2025 Coveralls, Inc