pydna 5.5.4__py3-none-any.whl → 5.5.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pydna/tm.py CHANGED
@@ -8,12 +8,12 @@
8
8
  """This module provide functions for melting temperature calculations."""
9
9
 
10
10
 
11
- import math as _math
12
- from Bio.SeqUtils import MeltingTemp as _mt
13
- from Bio.SeqUtils import gc_fraction as _GC
11
+ import math
12
+ from Bio.SeqUtils import MeltingTemp as mt
13
+ from Bio.SeqUtils import gc_fraction
14
14
 
15
- import textwrap as _textwrap
16
- from pydna._pretty import pretty_str as _pretty_str
15
+ import textwrap
16
+ from pydna._pretty import pretty_str as ps
17
17
 
18
18
  # See the documentation for Bio.SeqUtils.MeltingTemp for more details
19
19
  # The 10X Taq Buffer with (NH4)2SO4 is commercialized by companies like
@@ -30,7 +30,7 @@ def tm_default(
30
30
  strict=True,
31
31
  c_seq=None,
32
32
  shift=0,
33
- nn_table=_mt.DNA_NN4, # DNA_NN4: values from SantaLucia & Hicks (2004)
33
+ nn_table=mt.DNA_NN4, # DNA_NN4: values from SantaLucia & Hicks (2004)
34
34
  tmm_table=None,
35
35
  imm_table=None,
36
36
  de_table=None,
@@ -43,7 +43,7 @@ def tm_default(
43
43
  Mg=1.5, # 1.5 mM Mg2+ is often seen in modern protocols
44
44
  dNTPs=0.8, # I assume 200 µM of each dNTP
45
45
  saltcorr=7, # Tm = 81.5 + 0.41(%GC) - 600/N + 16.6 x log[Na+]
46
- func=_mt.Tm_NN, # Used by Primer3Plus to calculate the product Tm.
46
+ func=mt.Tm_NN, # Used by Primer3Plus to calculate the product Tm.
47
47
  ):
48
48
  return func(
49
49
  seq,
@@ -73,7 +73,7 @@ def tm_dbd(
73
73
  strict=True,
74
74
  c_seq=None,
75
75
  shift=0,
76
- nn_table=_mt.DNA_NN3,
76
+ nn_table=mt.DNA_NN3,
77
77
  tmm_table=None,
78
78
  imm_table=None,
79
79
  de_table=None,
@@ -86,7 +86,7 @@ def tm_dbd(
86
86
  Mg=1.5,
87
87
  dNTPs=0.8,
88
88
  saltcorr=1,
89
- func=_mt.Tm_NN,
89
+ func=mt.Tm_NN,
90
90
  ):
91
91
  return func(
92
92
  seq,
@@ -119,7 +119,7 @@ def tm_product(seq: str, K=0.050):
119
119
  ing temperature for DNA amplification in vitro
120
120
  http://www.ncbi.nlm.nih.gov/pubmed/2243783
121
121
  """
122
- tmp = 81.5 + 0.41 * _GC(seq) * 100 + 16.6 * _math.log10(K) - 675 / len(seq)
122
+ tmp = 81.5 + 0.41 * gc_fraction(seq) * 100 + 16.6 * math.log10(K) - 675 / len(seq)
123
123
  return tmp
124
124
 
125
125
 
@@ -160,7 +160,7 @@ def program(amplicon, tm=tm_default, ta=ta_default):
160
160
  extension_time_taq = max(30, int(taq_extension_rate * len(amplicon) / 1000))
161
161
  # seconds
162
162
 
163
- f = _textwrap.dedent(
163
+ f = textwrap.dedent(
164
164
  r"""
165
165
  |95°C|95°C | |tmf:{tmf:.1f}
166
166
  |____|_____ 72°C|72°C|tmr:{tmr:.1f}
@@ -185,7 +185,7 @@ def program(amplicon, tm=tm_default, ta=ta_default):
185
185
  )
186
186
  ).strip()
187
187
 
188
- return _pretty_str(f)
188
+ return ps(f)
189
189
 
190
190
 
191
191
  taq_program = program
@@ -228,7 +228,7 @@ def dbd_program(amplicon, tm=tm_dbd, ta=ta_dbd):
228
228
  tmr = tm(amplicon.reverse_primer.footprint)
229
229
 
230
230
  if tmf >= 69.0 and tmr >= 69.0:
231
- f = _textwrap.dedent(
231
+ f = textwrap.dedent(
232
232
  r"""
233
233
  |98°C|98°C | |tmf:{tmf:.1f}
234
234
  |____|____ | |tmr:{tmr:.1f}
@@ -245,7 +245,7 @@ def dbd_program(amplicon, tm=tm_dbd, ta=ta_dbd):
245
245
  )
246
246
  ).strip()
247
247
  else:
248
- f = _textwrap.dedent(
248
+ f = textwrap.dedent(
249
249
  r"""
250
250
  |98°C|98°C | |tmf:{tmf:.1f}
251
251
  |____|_____ 72°C|72°C|tmr:{tmr:.1f}
@@ -270,7 +270,7 @@ def dbd_program(amplicon, tm=tm_dbd, ta=ta_dbd):
270
270
  )
271
271
  ).strip()
272
272
 
273
- return _pretty_str(f)
273
+ return ps(f)
274
274
 
275
275
 
276
276
  pfu_sso7d_program = dbd_program
@@ -327,8 +327,8 @@ def tmbresluc(primer: str, *args, primerc=500.0, saltc=50, **kwargs):
327
327
  dS += _thermodynamic_data.dSBr[n1 - 97][n2 - 97]
328
328
 
329
329
  tm = (
330
- dH / (1.9872 * _math.log(pri / 1600) + dS)
331
- + (16.6 * _math.log(saltc)) / _math.log(10)
330
+ dH / (1.9872 * math.log(pri / 1600) + dS)
331
+ + (16.6 * math.log(saltc)) / math.log(10)
332
332
  ) - 273.15
333
333
 
334
334
  return tm
pydna/types.py CHANGED
@@ -5,32 +5,32 @@ Types used in the pydna package.
5
5
 
6
6
  from typing import (
7
7
  TYPE_CHECKING,
8
- Tuple as _Tuple,
9
- Union as _Union,
10
- TypeVar as _TypeVar,
11
- Iterable as _Iterable,
12
- Callable as _Callable,
8
+ Tuple,
9
+ Union,
10
+ TypeVar,
11
+ Iterable,
12
+ Callable,
13
13
  )
14
14
 
15
15
  # Import AbstractCut at runtime for CutSiteType
16
- from Bio.Restriction.Restriction import AbstractCut as _AbstractCut
17
- from pydna.crispr import _cas as __cas
16
+ from Bio.Restriction.Restriction import AbstractCut
17
+ from pydna.crispr import _cas
18
18
 
19
19
  if TYPE_CHECKING:
20
- from Bio.Restriction import RestrictionBatch as _RestrictionBatch
20
+ from Bio.Restriction import RestrictionBatch
21
21
  from pydna.dseq import Dseq
22
- from Bio.SeqFeature import Location as _Location
23
- from pydna.dseqrecord import Dseqrecord as _Dseqrecord
22
+ from Bio.SeqFeature import Location
23
+ from pydna.dseqrecord import Dseqrecord
24
24
 
25
25
 
26
26
  # To represent any subclass of Dseq
27
- DseqType = _TypeVar("DseqType", bound="Dseq")
28
- EnzymesType = _TypeVar(
29
- "EnzymesType", "_RestrictionBatch", _Iterable["_AbstractCut"], "_AbstractCut"
27
+ DseqType = TypeVar("DseqType", bound="Dseq")
28
+ EnzymesType = TypeVar(
29
+ "EnzymesType", "RestrictionBatch", Iterable["AbstractCut"], "AbstractCut"
30
30
  )
31
- CutSiteType = _Tuple[_Tuple[int, int], _Union[_AbstractCut, None, __cas]]
32
- AssemblyEdgeType = _Tuple[int, int, "_Location | None", "_Location | None"]
33
- AssemblySubFragmentType = _Tuple[int, "_Location | None", "_Location | None"]
31
+ CutSiteType = Tuple[Tuple[int, int], Union[AbstractCut, None, _cas]]
32
+ AssemblyEdgeType = Tuple[int, int, "Location | None", "Location | None"]
33
+ AssemblySubFragmentType = Tuple[int, "Location | None", "Location | None"]
34
34
  EdgeRepresentationAssembly = list[AssemblyEdgeType]
35
35
  SubFragmentRepresentationAssembly = list[AssemblySubFragmentType]
36
36
 
@@ -38,7 +38,7 @@ SubFragmentRepresentationAssembly = list[AssemblySubFragmentType]
38
38
  # Type alias that describes overlap between two sequences x and y
39
39
  # the two first numbers are the positions where the overlap starts on x and y
40
40
  # the third number is the length of the overlap
41
- SequenceOverlap = _Tuple[int, int, int]
42
- AssemblyAlgorithmType = _Callable[
43
- ["_Dseqrecord", "_Dseqrecord", int], list[SequenceOverlap]
41
+ SequenceOverlap = Tuple[int, int, int]
42
+ AssemblyAlgorithmType = Callable[
43
+ ["Dseqrecord", "Dseqrecord", int], list[SequenceOverlap]
44
44
  ]
pydna/utils.py CHANGED
@@ -6,43 +6,30 @@
6
6
  # as part of this package.
7
7
  """Miscellaneous functions."""
8
8
 
9
- from Bio.Data.IUPACData import ambiguous_dna_complement as _ambiguous_dna_complement
10
- from Bio.Seq import _maketrans
11
-
12
- # import shelve as _shelve
13
- # import os as _os
14
- import re as _re
15
-
16
- # import logging as _logging
17
- # import base64 as _base64
18
- # import pickle as _pickle
19
- # import hashlib as _hashlib
20
- import keyword as _keyword
21
- import collections as _collections
22
- import itertools as _itertools
23
- from copy import deepcopy as _deepcopy
24
-
25
- import sys as _sys
26
- import random
27
- import subprocess as _subprocess
28
- from bisect import bisect as _bisect
29
- from math import ceil as _ceil
9
+ import re
10
+ import keyword
11
+ import collections
12
+ import itertools
13
+ from copy import deepcopy
30
14
 
31
- from pydna.codon import weights as _weights
32
- from pydna.codon import rare_codons as _rare_codons
15
+ import sys
16
+ import random
17
+ import subprocess
18
+ from bisect import bisect
19
+ from math import ceil
33
20
 
34
- from Bio.SeqFeature import SimpleLocation as _sl
35
- from Bio.SeqFeature import CompoundLocation as _cl
36
- from Bio.SeqFeature import Location as _Location
21
+ from pydna.codon import weights
22
+ from pydna.codon import rare_codons
23
+ from pydna.alphabet import basepair_dict
24
+ from pydna.alphabet import complement_table_for_dscode
25
+ from Bio.SeqFeature import SimpleLocation
26
+ from Bio.SeqFeature import CompoundLocation
27
+ from Bio.SeqFeature import Location
37
28
 
38
- from typing import Union as _Union, TypeVar as _TypeVar, List as _List
29
+ from typing import Union, TypeVar, List
39
30
 
40
31
  # For functions that take str or bytes as input and return str or bytes as output, matching the input type
41
- StrOrBytes = _TypeVar("StrOrBytes", str, bytes)
42
-
43
- # _module_logger = _logging.getLogger("pydna." + __name__)
44
- _ambiguous_dna_complement.update({"U": "A"})
45
- _complement_table = _maketrans(_ambiguous_dna_complement)
32
+ StrOrBytes = TypeVar("StrOrBytes", str, bytes)
46
33
 
47
34
 
48
35
  def three_frame_orfs(
@@ -55,7 +42,7 @@ def three_frame_orfs(
55
42
  ):
56
43
  """Overlapping orfs in three frames."""
57
44
  # breakpoint()
58
- limit = _ceil(limit / 3) - 1
45
+ limit = ceil(limit / 3) - 1
59
46
  dna = dna.upper()
60
47
 
61
48
  orfs = []
@@ -69,7 +56,7 @@ def three_frame_orfs(
69
56
 
70
57
  for startindex in startdindices:
71
58
  try:
72
- stopindex = stopdindices[_bisect(stopdindices, startindex)]
59
+ stopindex = stopdindices[bisect(stopdindices, startindex)]
73
60
  except IndexError:
74
61
  pass
75
62
  else:
@@ -90,7 +77,7 @@ def shift_location(original_location, shift, lim):
90
77
  raise ValueError(
91
78
  "Shift moves location below zero, use a `lim` to loop around if sequence is circular."
92
79
  )
93
- lim = _sys.maxsize
80
+ lim = sys.maxsize
94
81
 
95
82
  for part in original_location.parts:
96
83
  new_start = (part.start + shift) % lim
@@ -106,7 +93,7 @@ def shift_location(original_location, shift, lim):
106
93
  # https://github.com/pydna-group/pydna/issues/195
107
94
 
108
95
  if len(part) == 0:
109
- newparts.append(_sl(new_start, new_start, strand))
96
+ newparts.append(SimpleLocation(new_start, new_start, strand))
110
97
  continue
111
98
  # Join with old, case 1
112
99
  elif strand != -1 and old_end == new_start:
@@ -119,12 +106,15 @@ def shift_location(original_location, shift, lim):
119
106
  part._start = new_start
120
107
  new_end = part.end
121
108
  if new_start < new_end:
122
- newparts.append(_sl(new_start, new_end, strand))
109
+ newparts.append(SimpleLocation(new_start, new_end, strand))
123
110
  else:
124
- parttuple = (_sl(new_start, lim, strand), _sl(0, new_end, strand))
111
+ parttuple = (
112
+ SimpleLocation(new_start, lim, strand),
113
+ SimpleLocation(0, new_end, strand),
114
+ )
125
115
  newparts.extend(parttuple if strand != -1 else parttuple[::-1])
126
116
  try:
127
- newloc = _cl(newparts)
117
+ newloc = CompoundLocation(newparts)
128
118
  except ValueError:
129
119
  newloc, *n = newparts
130
120
  assert len(newloc) == len(original_location)
@@ -144,7 +134,7 @@ def shift_feature(feature, shift, lim):
144
134
  """Return a new feature with shifted location."""
145
135
  # TODO: Missing tests
146
136
  new_location = shift_location(feature.location, shift, lim)
147
- new_feature = _deepcopy(feature)
137
+ new_feature = deepcopy(feature)
148
138
  new_feature.location = new_location
149
139
  return new_feature
150
140
 
@@ -210,16 +200,42 @@ def smallest_rotation(s):
210
200
  return s[k:] + s[:k]
211
201
 
212
202
 
213
- def cai(seq: str, organism: str = "sce", weights: dict = _weights):
203
+ def anneal_from_left(watson: str, crick: str) -> int:
204
+ """
205
+ The length of the common prefix shared by two strings.
206
+
207
+ Args:
208
+ str1 (str): The first string.
209
+ str2 (str): The second string.
210
+
211
+ Returns:
212
+ int: The length of the common prefix.
213
+ """
214
+
215
+ result = len(
216
+ list(
217
+ itertools.takewhile(
218
+ lambda x: basepair_dict.get((x[0], x[1])), zip(watson, crick[::-1])
219
+ )
220
+ )
221
+ )
222
+
223
+ return result
224
+
225
+
226
+ def cai(seq: str, organism: str = "sce", weights_dict: dict = None):
214
227
  """docstring."""
215
- from cai2 import CAI as _CAI
228
+ from cai2 import CAI
216
229
 
217
- return round(_CAI(seq.upper(), weights=weights[organism]), 3)
230
+ if weights_dict is None:
231
+ weights_dict = weights
232
+
233
+ return round(CAI(seq.upper(), weights=weights_dict[organism]), 3)
218
234
 
219
235
 
220
236
  def rarecodons(seq: str, organism="sce"):
221
237
  """docstring."""
222
- rare = _rare_codons[organism]
238
+ rare = rare_codons[organism]
223
239
  s = seq.upper()
224
240
  slices = []
225
241
  for i in range(0, len(seq) // 3):
@@ -260,13 +276,13 @@ def express(seq: str, organism="sce"):
260
276
 
261
277
  def open_folder(pth):
262
278
  """docstring."""
263
- if _sys.platform == "win32":
264
- _subprocess.run(["start", pth], shell=True)
265
- elif _sys.platform == "darwin":
266
- _subprocess.run(["open", pth])
279
+ if sys.platform == "win32":
280
+ subprocess.run(["start", pth], shell=True)
281
+ elif sys.platform == "darwin":
282
+ subprocess.run(["open", pth])
267
283
  else:
268
284
  try:
269
- _subprocess.run(["xdg-open", pth])
285
+ subprocess.run(["xdg-open", pth])
270
286
  except OSError:
271
287
  return "no cache to open."
272
288
 
@@ -276,15 +292,15 @@ def rc(sequence: StrOrBytes) -> StrOrBytes:
276
292
 
277
293
  accepts mixed DNA/RNA
278
294
  """
279
- return sequence.translate(_complement_table)[::-1]
295
+ return complement(sequence)[::-1]
280
296
 
281
297
 
282
- def complement(sequence: str):
298
+ def complement(sequence: StrOrBytes) -> StrOrBytes:
283
299
  """Complement.
284
300
 
285
301
  accepts mixed DNA/RNA
286
302
  """
287
- return sequence.translate(_complement_table)
303
+ return sequence.translate(complement_table_for_dscode)
288
304
 
289
305
 
290
306
  # def memorize(filename):
@@ -295,17 +311,16 @@ def complement(sequence: str):
295
311
 
296
312
  # def decorator(f):
297
313
  # def wrappee(*args, **kwargs):
298
- # _module_logger.info("#### memorizer ####")
299
- # _module_logger.info("cache filename = %s", filename)
300
- # _module_logger.info(
314
+
315
+
301
316
  # "os.environ['pydna_cached_funcs'] = %s",
302
317
  # _os.getenv("pydna_cached_funcs", ""),
303
318
  # )
304
319
  # if filename not in _os.getenv("pydna_cached_funcs", ""):
305
- # _module_logger.info("cache filename not among cached functions, made it new!")
320
+
306
321
  # return f(*args, **kwargs)
307
322
  # key = _base64.urlsafe_b64encode(_hashlib.sha1(_pickle.dumps((args, kwargs))).digest()).decode("ascii")
308
- # _module_logger.info("key = %s", key)
323
+
309
324
  # cache = _shelve.open(
310
325
  # _os.path.join(_os.environ["pydna_data_dir"], identifier_from_string(filename)),
311
326
  # writeback=False,
@@ -313,17 +328,17 @@ def complement(sequence: str):
313
328
  # try:
314
329
  # result = cache[key]
315
330
  # except KeyError:
316
- # _module_logger.info(
331
+
317
332
  # "no result for key %s in shelve %s",
318
333
  # key,
319
334
  # identifier_from_string(filename),
320
335
  # )
321
336
  # result = f(*args, **kwargs)
322
- # _module_logger.info("made it new!")
337
+
323
338
  # cache[key] = result
324
- # _module_logger.info("saved result under key %s", key)
339
+
325
340
  # else:
326
- # _module_logger.info("found %s in cache", key)
341
+
327
342
  # cache.close()
328
343
  # return result
329
344
 
@@ -338,16 +353,16 @@ def identifier_from_string(s: str) -> str:
338
353
  based on the argument s or an empty string
339
354
  """
340
355
  s = s.strip()
341
- s = _re.sub(r"\s+", r"_", s)
356
+ s = re.sub(r"\s+", r"_", s)
342
357
  s.replace("-", "_")
343
- s = _re.sub("[^0-9a-zA-Z_]", "", s)
344
- if s and not s[0].isidentifier() or _keyword.iskeyword(s):
358
+ s = re.sub("[^0-9a-zA-Z_]", "", s)
359
+ if s and not s[0].isidentifier() or keyword.iskeyword(s):
345
360
  s = "_{s}".format(s=s)
346
361
  assert s == "" or s.isidentifier()
347
362
  return s
348
363
 
349
364
 
350
- def flatten(*args) -> _List:
365
+ def flatten(*args) -> List:
351
366
  """Flattens an iterable of iterables.
352
367
 
353
368
  Down to str, bytes, bytearray or any of the pydna or Biopython seq objects
@@ -357,7 +372,7 @@ def flatten(*args) -> _List:
357
372
  while args:
358
373
  top = args.pop()
359
374
  if (
360
- isinstance(top, _collections.abc.Iterable)
375
+ isinstance(top, collections.abc.Iterable)
361
376
  and not isinstance(top, (str, bytes, bytearray))
362
377
  and not hasattr(top, "reverse_complement")
363
378
  ):
@@ -653,12 +668,12 @@ def eq(*args, **kwargs):
653
668
 
654
669
  if topology == "circular":
655
670
  # force circular comparison of all given sequences
656
- for s1, s2 in _itertools.combinations(args_string_list, 2):
671
+ for s1, s2 in itertools.combinations(args_string_list, 2):
657
672
  if not (s1 in s2 + s2 or rc(s1) in s2 + s2):
658
673
  same = False
659
674
  elif topology == "linear":
660
675
  # force linear comparison of all given sequences
661
- for s1, s2 in _itertools.combinations(args_string_list, 2):
676
+ for s1, s2 in itertools.combinations(args_string_list, 2):
662
677
  if not (s1 == s2 or s1 == rc(s2)):
663
678
  same = False
664
679
  return same
@@ -697,6 +712,7 @@ def eq(*args, **kwargs):
697
712
 
698
713
 
699
714
  def cuts_overlap(left_cut, right_cut, seq_len):
715
+
700
716
  # Special cases:
701
717
  if left_cut is None or right_cut is None or left_cut == right_cut:
702
718
  return False
@@ -718,17 +734,23 @@ def cuts_overlap(left_cut, right_cut, seq_len):
718
734
  # Convert into ranges x and y and see if ranges overlap
719
735
  x = sorted([left_watson, left_crick])
720
736
  y = sorted([right_watson, right_crick])
721
- return (x[1] > y[0]) != (y[1] < x[0])
737
+ # if (x[1] >= y[0]) != (y[1] <= x[0]):
738
+ # breakpoint()
739
+ return (x[1] >= y[0]) != (y[1] <= x[0]) # (x[1] > y[0]) != (y[1] < x[0])
722
740
 
723
741
 
724
- def location_boundaries(loc: _Union[_sl, _cl]):
742
+ def location_boundaries(loc: Union[SimpleLocation, CompoundLocation]):
725
743
  if loc.strand == -1:
726
744
  return loc.parts[-1].start, loc.parts[0].end
727
745
  else:
728
746
  return loc.parts[0].start, loc.parts[-1].end
729
747
 
730
748
 
731
- def locations_overlap(loc1: _Union[_sl, _cl], loc2: _Union[_sl, _cl], seq_len):
749
+ def locations_overlap(
750
+ loc1: Union[SimpleLocation, CompoundLocation],
751
+ loc2: Union[SimpleLocation, CompoundLocation],
752
+ seq_len,
753
+ ):
732
754
  start1, end1 = location_boundaries(loc1)
733
755
  start2, end2 = location_boundaries(loc2)
734
756
 
@@ -746,7 +768,7 @@ def locations_overlap(loc1: _Union[_sl, _cl], loc2: _Union[_sl, _cl], seq_len):
746
768
  [start2 - seq_len, end2],
747
769
  ]
748
770
 
749
- for b1, b2 in _itertools.product(boundaries1, boundaries2):
771
+ for b1, b2 in itertools.product(boundaries1, boundaries2):
750
772
  if b1[0] < b2[1] and b1[1] > b2[0]:
751
773
  return True
752
774
 
@@ -801,7 +823,7 @@ def limit_iterator(iterator, limit):
801
823
 
802
824
  def create_location(
803
825
  start: int, end: int, lim: int, strand: int | None = None
804
- ) -> _Location:
826
+ ) -> Location:
805
827
  """
806
828
  Create a location object from a start and end position.
807
829
  If the end position is less than the start position, the location is circular. It handles negative positions.
@@ -854,6 +876,6 @@ def create_location(
854
876
  while end < 0:
855
877
  end += lim
856
878
  if end > start:
857
- return _sl(start, end, strand)
879
+ return SimpleLocation(start, end, strand)
858
880
  else:
859
- return shift_location(_sl(start, end + lim, strand), 0, lim)
881
+ return shift_location(SimpleLocation(start, end + lim, strand), 0, lim)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydna
3
- Version: 5.5.4
3
+ Version: 5.5.6
4
4
  Summary: Representing double stranded DNA and functions for simulating cloning and homologous recombination between DNA molecules.
5
5
  License: BSD
6
6
  License-File: LICENSE.txt
@@ -23,6 +23,7 @@ Provides-Extra: clipboard
23
23
  Provides-Extra: download
24
24
  Provides-Extra: express
25
25
  Provides-Extra: gel
26
+ Provides-Extra: primer-screen
26
27
  Requires-Dist: appdirs (>=1.4.4)
27
28
  Requires-Dist: biopython (==1.85)
28
29
  Requires-Dist: cai2 (>=1.0.5) ; extra == "express"
@@ -30,9 +31,10 @@ Requires-Dist: matplotlib (>=3.4.3) ; extra == "gel"
30
31
  Requires-Dist: networkx (>=2.8.8)
31
32
  Requires-Dist: numpy (>1.26) ; python_version < "3.12"
32
33
  Requires-Dist: numpy (>=2.3.0) ; python_version >= "3.12"
33
- Requires-Dist: opencloning-linkml (==0.4.5)
34
+ Requires-Dist: opencloning-linkml (>=0.4.9,<0.5.0)
34
35
  Requires-Dist: pillow (>=8.4.0) ; extra == "gel"
35
36
  Requires-Dist: prettytable (>=3.5.0)
37
+ Requires-Dist: pyahocorasick (>=2.2.0) ; extra == "primer-screen"
36
38
  Requires-Dist: pydivsufsort (>=0.0.14)
37
39
  Requires-Dist: pyfiglet (==0.8.post1)
38
40
  Requires-Dist: pyparsing (>=2.4.7) ; extra == "download"
@@ -506,7 +508,7 @@ poetry run pre-commit install
506
508
  > =================================== FAILURES ===================================
507
509
  > ___________________ [doctest] pydna.assembly2.blunt_overlap ____________________
508
510
  > ```
509
- > This means that the doctest of the function `blunt_overlap` failed. You can run the same test locally with `python -m doctest src/pydna/assembly2.py` (use the appropriate path to the module file). That will give you information of what's failing. Fix, and re-run until it passes!
511
+ > This means that the doctest of the function `blunt_overlap` failed. You can run the same test locally with `pytest src/pydna --doctest-modules` (use the appropriate path to the module file). That will give you information of what's failing. Fix, and re-run until it passes!
510
512
 
511
513
  ### Creating a PR 🔗
512
514
 
@@ -531,17 +533,15 @@ To work locally with the documentation, check the [documentation README](docs/RE
531
533
  See the [releases](https://github.com/pydna-group/pydna/releases) for changes and releases.
532
534
 
533
535
  The build workflow builds a PyPI packages using poetry. This workflow is triggered by publishing a Github release manually from the Github web interface.
536
+ We keep future release names [here](https://docs.google.com/document/d/1PrBYKzDh6QBcqfH9ksjpgArJo3ibDhMRNcibfXtYmCc/edit?tab=t.0). Please edit to
537
+ reflect used release names.
534
538
 
535
- ![----]( http://bit.ly/coloredline)
539
+ ![----](http://bit.ly/coloredline)
536
540
 
537
541
  ## History 📜
538
542
 
539
543
  Pydna was made public in 2012 on [Google code](https://code.google.com/archive/p/pydna).
540
544
 
541
- :microbe:
542
-
543
- :portugal:
544
-
545
545
  ## Who is using pydna? 🧪
546
546
 
547
547
  Taylor, L. J., & Strebel, K. (2017).
@@ -0,0 +1,42 @@
1
+ pydna/__init__.py,sha256=4u9wd3RbQkivNRKpEGXHT7Lrk7W7G5V64PJLOiSXKAk,7086
2
+ pydna/_pretty.py,sha256=S3J0z_czeP1HpR-lj5fXQo9OeZc3ONsvxEGAc-Oqvjo,885
3
+ pydna/_thermodynamic_data.py,sha256=ctOCzI0SclCBQVk7tG01bDv76fMeOROrp_WdVG5jp20,10885
4
+ pydna/all.py,sha256=jPeYTAPh5uNXnqsK-HfMFzlVXE6sSqsonHCgmt6lf2I,1502
5
+ pydna/alphabet.py,sha256=NOWIcsVjdPSR9aAZx5wzWD8061Pq2fOE1qAKfjqDzGg,29654
6
+ pydna/amplicon.py,sha256=zql6MVqoKu9XEDlEmqxCQa5oZMDk3pyayP536k-yS38,5135
7
+ pydna/amplify.py,sha256=DsMDJi6bRmP1CMku-jZ1_QXQ3-gbQ_P2M9kHR30zJ-Y,18738
8
+ pydna/assembly.py,sha256=1bAaFZDAEAlz_LB31sjAPRtAkIFK_VIXpMIQpTf_8xU,19291
9
+ pydna/assembly2.py,sha256=WmzygtYKLONRoccaqHM5O3xjbNzaSeOHR15EH-tVOmk,108764
10
+ pydna/codon.py,sha256=AZb8DjrS5lBAzNhL32GvE_P9V5DvSBbc7w9TaSeQHlc,2553
11
+ pydna/common_sub_strings.py,sha256=pnSx3OAjwf2uclYxv-90XYZT3bMl_d8ZTDeoGtlgtWs,11467
12
+ pydna/contig.py,sha256=yBF4TMq1pLL0Pe3tefl2sDzNFaeSddBpytN-z-xBeSw,14971
13
+ pydna/cre_lox.py,sha256=sOj9R8_oFPGWs68vc4jf6LqWOXjMsVSwtJaeKl6ZF2M,4476
14
+ pydna/crispr.py,sha256=iwu0Cjskzdb2r-In9633QIxQYKGmSNVOEM_dLK6lC54,3619
15
+ pydna/design.py,sha256=GQTyH4fKsvd6fSel0uC8DNQIulq3HMg-jYHxqsQzoLw,31743
16
+ pydna/dseq.py,sha256=cZN1Micwlgt8L73WjaIUlblb9KuQBxLzhM91cd5ijKo,83324
17
+ pydna/dseqrecord.py,sha256=jzo8jr6i4zZ6SdJJfbabdkGh_6U8PI0Ywa9LCdn91XE,49598
18
+ pydna/fakeseq.py,sha256=uxyu1PXF-sVasEqhmyhMcsbpTy84uUtubDiZuxHNb9c,1174
19
+ pydna/fusionpcr.py,sha256=tfIfGGkNoZjg_dodcEx9wTc12aLRnC7J3g-Vg3Jg1uA,2821
20
+ pydna/gateway.py,sha256=2AluaHCvgWwIq3f4ICK27iX1uSSpg97F3c_xv4o0lQM,8651
21
+ pydna/gel.py,sha256=cZ8IctRO62BXK3BQe4_8c4IgOOspHawi1WZKr0PNGss,3338
22
+ pydna/genbank.py,sha256=TZExxq5NVAL23Rb4y_tdbN32FFTUE_kddb_Zpv5RO6E,8574
23
+ pydna/genbankfixer.py,sha256=ackTNoGk9aiXdWeH4ReXjGPmhTh9kl3FkfHsnZPi_eY,20302
24
+ pydna/ladders.py,sha256=2Y5gcqmxCXdYFgW4MAosbqISSHD_uEQj_05ZYBREBOY,3284
25
+ pydna/oligonucleotide_hybridization.py,sha256=x75pVVNvUn8N0F2j8fY_oOT61VlrlFauk0Iq5QFJ2XY,4165
26
+ pydna/opencloning_models.py,sha256=gMWAwcxDQx7T4xXftUTKA99NHdA7CCRSMB0HFJ5UXok,23892
27
+ pydna/parsers.py,sha256=mAkkkIv14KFmZt0TrROtE0Z54otpB11MrM3ihhdd3Ow,7847
28
+ pydna/primer.py,sha256=s3CoPheB4PUuQJU_11VGEBZW62DesEiWmTC2HHzD7so,2248
29
+ pydna/primer_screen.py,sha256=0CodBc9JThE-qkk5Z2DacSYIvSqhsFCGARzh-Bu236U,26418
30
+ pydna/readers.py,sha256=9ZopQFW0CyYCmW4jy-6_w0_0BRUMLV2VAVDmHH4Ns5w,1731
31
+ pydna/seq.py,sha256=H-MPWo2qQG6s5N0LKSziTKmb79ORCCNHofE2Gs0R5U8,10979
32
+ pydna/seqrecord.py,sha256=aQtkx8Wjy_FbnD2_uVY--ULuWwLtxiVeQ0wlsZs2OXA,22816
33
+ pydna/sequence_picker.py,sha256=wuRfQhuMgxrK6rrNykBFbRqErk-qXBPRvmEEIM0ji4o,1305
34
+ pydna/sequence_regex.py,sha256=bp0JhUILRlXQ-zOjK6oz-cxjca46LBjA5wCuzga-Hmw,1238
35
+ pydna/threading_timer_decorator_exit.py,sha256=D91kqjKSavWDnXyc1Fo-CwPYtbmR2DjTXnBYSRXKmSA,2793
36
+ pydna/tm.py,sha256=kM31byeBog17xi-NnVL6yXPLyZrzpXRY9J6XfEAJa9I,11083
37
+ pydna/types.py,sha256=W1qY6TSRv1nIj9dxEwTlc4XB3778arSeMg713fPnT9U,1337
38
+ pydna/utils.py,sha256=vYJJnJlaSTVxmbusv-WDNid54nBUqs8pTFDcJG_I7tA,24989
39
+ pydna-5.5.6.dist-info/METADATA,sha256=jUQ1ZJ5NYSJe71DHPnRWDYF1_pUeWqoMeOcLvYjitFE,24626
40
+ pydna-5.5.6.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
41
+ pydna-5.5.6.dist-info/licenses/LICENSE.txt,sha256=u8QfcsnNXZM0UCexerK_MvyA2lPWgeGyUtSYXvLG6Oc,6119
42
+ pydna-5.5.6.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.2.1
2
+ Generator: poetry-core 2.3.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any