• 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

87.5
/dnachisel/Specification/Specification.py
1
"""Base class for specification.
2

3
Notable features implemented here:
4

5
- Many empty methods that features subclass will overwrite
6
- Feature import/export from/to Genbank features.
7
"""
8

9
import copy
1✔
10
from ..Location import Location
1✔
11
from .FeatureRepresentationMixin import FeatureRepresentationMixin
1✔
12

13

14
class Specification(FeatureRepresentationMixin):
1✔
15
    """General class to define specifications to optimize.
16

17
    Note that all specifications have a ``boost`` attribute that is a
18
    multiplicator that will be used when computing the global specification
19
    score of a problem with ``problem.all_objectives_score()``.
20

21
    New types of specifications are defined by subclassing ``Specification`` and
22
    providing a custom ``evaluate`` and ``localized`` methods.
23

24
    Parameters
25
    -----------
26
    evaluate
27
      function (sequence) => SpecEvaluation
28

29
    boost
30
      Relative importance of the Specification's score in a multi-specification
31
      problem.
32

33
    Attributes
34
    ----------
35

36
    best_possible_score
37
      Best score that the specification can achieve. Used by the optimization
38
      algorithm to understand when no more optimization is required.
39

40
    optimize_passively (boolean)
41
      Indicates that there should not be a pass of the optimization algorithm
42
      to optimize this objective. Instead, this objective is simply taken into
43
      account when optimizing other objectives.
44

45
    enforced_by_nucleotide_restrictions (boolean)
46
      When the spec is used as a constraints, this indicates that the
47
      constraint will initially restrict the mutation space in a way that
48
      ensures that the constraint will always be valid. The constraint does
49
      not need to be evaluated again, which speeds up the resolution algorithm.
50

51
    priority
52
      Value used to sort the specifications and solve/optimize them in order,
53
      with highest priority first.
54

55
    shorthand_name
56
      Shorter name for the specification class that will be recognized when
57
      parsing annotations from genbanks.
58

59
    """
60

61
    best_possible_score = None
1✔
62
    optimize_passively = False
1✔
63
    enforced_by_nucleotide_restrictions = False
1✔
64
    priority = 0
1✔
65
    shorthand_name = None
1✔
66
    is_focus = False
1✔
67

68
    def __init__(self, evaluate=None, boost=1.0):
1✔
69
        """Initialize."""
70
        self.boost = boost
×
71
        if evaluate is not None:
×
UNCOV
72
            self.evaluate = evaluate
×
73

74
    def localized(self, location, problem=None):
1✔
75
        """Return a modified version of the specification for the case where
76
        sequence modifications are only performed inside the provided location.
77

78
        For instance if an specification concerns local GC content, and we are
79
        only making local mutations to destroy a restriction site, then we only
80
        need to check the local GC content around the restriction site after
81
        each mutation (and not compute it for the whole sequence), so
82
        ``EnforceGCContent.localized(location)`` will return an specification
83
        that only looks for GC content around the provided location.
84

85
        If an specification concerns a DNA segment that is completely disjoint
86
        from the provided location, this must return None.
87

88
        Must return an object of class ``Constraint``.
89
        """
90
        return self
1✔
91

92
    def copy_with_changes(self, **kwargs):
1✔
93
        """Return a copy of the Specification with modified properties.
94

95
        For instance ``new_spec = spec.copy_with_changes(boost=10)``.
96
        """
97
        new_specification = copy.copy(self)
1✔
98
        new_specification.__dict__.update(kwargs)
1✔
99
        return new_specification
1✔
100

101
    def shifted(self, shift):
1✔
102
        """Shift the location of the specification.
103

104
        Some specification classes may have a special method to do side effects
105
        when shifting the location.
106

107
        Location shifting is used in particular when solving circular DNA
108
        optimization problems.
109
        """
110
        new_location = None if self.location is None else self.location + shift
1✔
111
        return self.copy_with_changes(location=new_location, derived_from=self)
1✔
112

113
    def initialized_on_problem(self, problem, role="constraint"):
1✔
114
        """Complete specification initialization when the sequence gets known.
115

116
        Some specifications like to know what their role is and on which
117
        sequence they are employed before they complete some values.
118
        """
119
        return self
1✔
120

121
    def label(
1✔
122
        self,
123
        role=None,
124
        with_location=True,
125
        assignment_symbol=":",
126
        use_short_form=False,
127
        use_breach_form=False,
128
    ):
129
        """Return a string label for this specification.
130

131
        Parameters
132
        ----------
133

134
        role
135
          Either 'constraint' or 'objective' (for prefixing the label with @
136
          or ~), or None.
137

138
        with_location
139
          If true, the location will appear in the label.
140

141
        assignment_symbol
142
          Indicates whether to use ":" or "=" or anything else when indicating
143
          parameters values.
144

145
        use_short_form
146
          If True, the label will use self.short_label(), so for instance
147
          AvoidPattern(BsmBI_site) will become "no BsmBI". How this is handled
148
          is dependent on the specification.
149
        """
150
        prefix = {"constraint": "@", "objective": "~", None: ""}[role]
1✔
151
        if use_short_form:
1✔
152
            label = self.short_label()
1✔
153
            if with_location:
1✔
UNCOV
154
                label += ", %s" % self.location
×
155
            return prefix + label
1✔
156
        if use_breach_form:
1✔
157
            label = self.breach_label()
1✔
158
            if with_location:
1✔
UNCOV
159
                label += ", %s" % self.location
×
160
            return label
1✔
161
        if with_location and hasattr(self, "location") and self.location:
1✔
162
            location = "[%s]" % self.location
1✔
163
        else:
UNCOV
164
            location = ""
×
165
        params = self.label_parameters()
1✔
166
        if params == []:
1✔
167
            params = ""
1✔
168
        else:
169
            params = "(%s)" % ", ".join(
1✔
170
                [
171
                    (
172
                        assignment_symbol.join(map(str, p))
173
                        if isinstance(p, tuple)
174
                        else str(p)
175
                    )
176
                    for p in params
177
                ]
178
            )
179

180
        return "".join([prefix, self.__class__.__name__, location, params])
1✔
181

182
    def short_label(self):
1✔
183
        """Shorter, less precise label to be used in tables, reports, etc.
184

185
        This is meant for specifications such as EnforceGCContent(0.4, 0.6)
186
        to be represented as '40-60% GC' in reports tables etc..
187
        """
UNCOV
188
        return self.__class__.__name__
×
189

190
    def breach_label(self):
1✔
191
        """Shorter, less precise label to be used in tables, reports, etc.
192

193
        This is meant for specifications such as EnforceGCContent(0.4, 0.6)
194
        to be represented as '40-60% GC' in reports tables etc..
195
        """
UNCOV
196
        return "'%s' breach" % (self.short_label())
×
197

198
    def label_parameters(self):
1✔
199
        """In subclasses, returns a list of the creation parameters.
200

201
        For instance [('pattern', 'ATT'), ('occurences', 2)]
202
        """
203
        return []
1✔
204

205
    def __str__(self):
1✔
206
        """By default, represent the Specification using its label()"""
207
        return self.label()
1✔
208

209
    def __repr__(self):
1✔
210
        """By default, represent the Specification using its label()"""
211
        return self.label()
1✔
212

213
    def restrict_nucleotides(self, sequence, location=None):
1✔
214
        """Restrict the mutation space to speed up optimization.
215

216
        This method only kicks in when this specification is used as a
217
        constraint. By default it does nothing, but subclasses such as
218
        EnforceTranslation, AvoidChanges, EnforceSequence, etc. have custom
219
        methods.
220

221
        In the code, this method is run during the initialize() step of
222
        DNAOptimizationProblem, when the MutationSpace is created for each
223
        constraint
224
        """
225
        return []
1✔
226

227
    def as_passive_objective(self):
1✔
228
        """Return a copy with optimize_passively set to true.
229

230
        "Optimize passively" means that when the specification is used as an
231
        objective, the solver will not do a specific pass to optimize this
232
        specification, however this specification's score will be taken into
233
        account in the global score when optimizing other objectives, and
234
        may therefore influence the final sequence.
235
        """
236
        return self.copy_with_changes(optimize_passively=True)
1✔
237

238
    def _copy_with_full_span_if_no_location(self, problem):
1✔
239
        """Return either self, or a copy with location "everywhere".
240

241
        And by "everywhere" we mean Location(0, L) where L is the problem's
242
        sequence length.
243

244
        Most Specifications use this method in their "initialized_on_problem()"
245
        custom method.
246
        """
247
        if self.location is None:
1✔
248
            location = Location(0, len(problem.sequence))
1✔
249
            return self.copy_with_changes(location=location)
1✔
250
        else:
251
            return self
1✔
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