opencloning 0.4.6__tar.gz → 0.4.7__tar.gz

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.
Files changed (50) hide show
  1. {opencloning-0.4.6 → opencloning-0.4.7}/PKG-INFO +1 -1
  2. {opencloning-0.4.6 → opencloning-0.4.7}/pyproject.toml +1 -1
  3. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/ebic/primer_design.py +9 -15
  4. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/endpoints/primer_design.py +48 -53
  5. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/ncbi_requests.py +7 -1
  6. opencloning-0.4.7/src/opencloning/primer3_functions.py +109 -0
  7. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/primer_design.py +8 -9
  8. opencloning-0.4.6/src/opencloning/batch_cloning/EBIC/barcode.gb +0 -23
  9. opencloning-0.4.6/src/opencloning/batch_cloning/EBIC/common_plasmid.gb +0 -218
  10. opencloning-0.4.6/src/opencloning/batch_cloning/EBIC/example.py +0 -180
  11. opencloning-0.4.6/src/opencloning/batch_cloning/EBIC/primer_design_settings.py +0 -38
  12. opencloning-0.4.6/src/opencloning/ebic/__init__.py +0 -0
  13. {opencloning-0.4.6 → opencloning-0.4.7}/LICENSE +0 -0
  14. {opencloning-0.4.6 → opencloning-0.4.7}/README.md +0 -0
  15. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/__init__.py +0 -0
  16. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/_version.py +0 -0
  17. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/api_config_utils.py +0 -0
  18. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/app_settings.py +0 -0
  19. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/__init__.py +0 -0
  20. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/index.html +0 -0
  21. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/pombe/__init__.py +0 -0
  22. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/pombe/index.html +0 -0
  23. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/pombe/pombe_clone.py +0 -0
  24. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/pombe/pombe_gather.py +0 -0
  25. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/pombe/pombe_get_primers.py +0 -0
  26. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/pombe/pombe_summary.py +0 -0
  27. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/ziqiang_et_al2024/__init__.py +0 -0
  28. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/ziqiang_et_al2024/index.html +0 -0
  29. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/batch_cloning/ziqiang_et_al2024/ziqiang_et_al2024.json +0 -0
  30. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/bug_fixing/README.md +0 -0
  31. {opencloning-0.4.6/src/opencloning/batch_cloning/EBIC → opencloning-0.4.7/src/opencloning/bug_fixing}/__init__.py +0 -0
  32. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/bug_fixing/backend_v0_3.py +0 -0
  33. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/cre_lox.py +0 -0
  34. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/dna_functions.py +0 -0
  35. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/dna_utils.py +0 -0
  36. {opencloning-0.4.6/src/opencloning/bug_fixing → opencloning-0.4.7/src/opencloning/ebic}/__init__.py +0 -0
  37. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/ebic/primer_design_settings.py +0 -0
  38. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/endpoints/annotation.py +0 -0
  39. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/endpoints/assembly.py +0 -0
  40. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/endpoints/external_import.py +0 -0
  41. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/endpoints/no_assembly.py +0 -0
  42. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/endpoints/no_input.py +0 -0
  43. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/endpoints/other.py +0 -0
  44. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/gateway.py +0 -0
  45. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/get_router.py +0 -0
  46. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/http_client.py +0 -0
  47. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/main.py +0 -0
  48. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/pydantic_models.py +0 -0
  49. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/request_examples.py +0 -0
  50. {opencloning-0.4.6 → opencloning-0.4.7}/src/opencloning/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencloning
3
- Version: 0.4.6
3
+ Version: 0.4.7
4
4
  Summary: Backend of OpenCloning, a web application to generate molecular cloning strategies in json format, and share them with others.
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -8,7 +8,7 @@ authors = ["Manuel Lera-Ramirez <manulera14@gmail.com>"]
8
8
  description = "Backend of OpenCloning, a web application to generate molecular cloning strategies in json format, and share them with others."
9
9
  license = "MIT"
10
10
  name = "opencloning"
11
- version = "0.4.6"
11
+ version = "0.4.7"
12
12
  package-mode = true
13
13
  readme = "README.md"
14
14
  repository = "https://github.com/manulera/OpenCloning_backend"
@@ -1,6 +1,6 @@
1
1
  from pydna.dseqrecord import Dseqrecord
2
2
  from Bio.SeqFeature import SimpleLocation
3
- from primer3 import bindings
3
+ from ..primer3_functions import primer3_design_primers
4
4
 
5
5
  from ..pydantic_models import PrimerModel
6
6
  from .primer_design_settings import amanda_settings
@@ -13,23 +13,13 @@ adapter_right_fwd = 'ataGGTCTCtGCTT'
13
13
  adapter_right_rvs = 'ataGGTCTCtAGCG'
14
14
 
15
15
 
16
- def call_primer3(seq: str, seq_args: dict):
17
- report = bindings.design_primers(
18
- seq_args={
19
- 'SEQUENCE_ID': 'MH1000',
20
- 'SEQUENCE_TEMPLATE': seq,
21
- **seq_args,
22
- },
23
- global_args=amanda_settings,
24
- )
25
- return report
26
-
27
-
28
16
  def ebic_primers(
29
17
  input_seq: Dseqrecord,
30
18
  location: SimpleLocation,
31
19
  max_inside: int,
32
20
  max_outside: int,
21
+ target_tm: float,
22
+ target_tm_tolerance: float,
33
23
  ) -> tuple[PrimerModel, PrimerModel, PrimerModel, PrimerModel]:
34
24
  """Design primers for EBIC"""
35
25
 
@@ -53,9 +43,13 @@ def ebic_primers(
53
43
  'SEQUENCE_PRIMER_PAIR_OK_REGION_LIST': f'0,{max_outside + max_inside},{len(right_template) - int(padding/2)},{int(padding/2)}',
54
44
  }
55
45
 
56
- report_left = call_primer3(left_template, seq_args_left)
57
- report_right = call_primer3(right_template, seq_args_right)
46
+ global_args = amanda_settings.copy()
47
+ global_args['PRIMER_OPT_TM'] = target_tm
48
+ global_args['PRIMER_MIN_TM'] = target_tm - target_tm_tolerance
49
+ global_args['PRIMER_MAX_TM'] = target_tm + target_tm_tolerance
58
50
 
51
+ report_left = primer3_design_primers(left_template, seq_args_left, global_args)
52
+ report_right = primer3_design_primers(right_template, seq_args_right, global_args)
59
53
  primer_names = ['left_fwd', 'left_rvs', 'right_fwd', 'right_rvs']
60
54
  primer_seqs = [
61
55
  adapter_left_fwd + report_left['PRIMER_LEFT'][0]['SEQUENCE'],
@@ -3,8 +3,6 @@ from pydantic import create_model
3
3
  import re
4
4
  from Bio.Restriction import RestrictionBatch
5
5
  from Bio.SeqUtils import gc_fraction
6
- from primer3 import bindings
7
- from itertools import product
8
6
 
9
7
  from ..dna_functions import get_invalid_enzyme_names
10
8
  from ..pydantic_models import PrimerModel, PrimerDesignQuery
@@ -14,6 +12,14 @@ from ..primer_design import (
14
12
  gibson_assembly_primers,
15
13
  simple_pair_primers,
16
14
  )
15
+ from ..primer3_functions import (
16
+ primer3_calc_tm,
17
+ PrimerDesignSettings,
18
+ primer3_calc_homodimer,
19
+ primer3_calc_hairpin,
20
+ primer3_calc_heterodimer,
21
+ ThermodynamicResult,
22
+ )
17
23
  from ..get_router import get_router
18
24
  from ..ebic.primer_design import ebic_primers
19
25
  from pydantic import BaseModel
@@ -45,6 +51,9 @@ def validate_spacers(spacers: list[str] | None, nb_templates: int, circular: boo
45
51
  async def primer_design_homologous_recombination(
46
52
  pcr_template: PrimerDesignQuery,
47
53
  homologous_recombination_target: PrimerDesignQuery,
54
+ settings: PrimerDesignSettings = Body(
55
+ ..., description='Primer design settings.', default_factory=PrimerDesignSettings
56
+ ),
48
57
  spacers: list[str] | None = Body(
49
58
  None,
50
59
  description='Spacers to add at the left and right side of the insertion.',
@@ -80,6 +89,7 @@ async def primer_design_homologous_recombination(
80
89
  insert_forward,
81
90
  target_tm,
82
91
  spacers,
92
+ tm_func=lambda x: primer3_calc_tm(x, settings),
83
93
  )
84
94
  except ValueError as e:
85
95
  raise HTTPException(400, *e.args)
@@ -93,6 +103,9 @@ async def primer_design_homologous_recombination(
93
103
  @router.post('/primer_design/gibson_assembly', response_model=PrimerDesignResponse)
94
104
  async def primer_design_gibson_assembly(
95
105
  pcr_templates: list[PrimerDesignQuery],
106
+ settings: PrimerDesignSettings = Body(
107
+ ..., description='Primer design settings.', default_factory=PrimerDesignSettings
108
+ ),
96
109
  spacers: list[str] | None = Body(
97
110
  None,
98
111
  description='Spacers to add between the restriction site and the 5\' end of the primer footprint (the part that binds the DNA).',
@@ -122,7 +135,13 @@ async def primer_design_gibson_assembly(
122
135
  templates.append(template)
123
136
  try:
124
137
  primers = gibson_assembly_primers(
125
- templates, homology_length, minimal_hybridization_length, target_tm, circular, spacers
138
+ templates,
139
+ homology_length,
140
+ minimal_hybridization_length,
141
+ target_tm,
142
+ circular,
143
+ spacers,
144
+ tm_func=lambda x: primer3_calc_tm(x, settings),
126
145
  )
127
146
  except ValueError as e:
128
147
  raise HTTPException(400, *e.args)
@@ -137,6 +156,9 @@ async def primer_design_simple_pair(
137
156
  None,
138
157
  description='Spacers to add between the restriction site and the 5\' end of the primer footprint (the part that binds the DNA).',
139
158
  ),
159
+ settings: PrimerDesignSettings = Body(
160
+ ..., description='Primer design settings.', default_factory=PrimerDesignSettings
161
+ ),
140
162
  minimal_hybridization_length: int = Query(
141
163
  ..., description='The minimal length of the hybridization region in bps.'
142
164
  ),
@@ -186,6 +208,7 @@ async def primer_design_simple_pair(
186
208
  spacers,
187
209
  left_enzyme_inverted,
188
210
  right_enzyme_inverted,
211
+ tm_func=lambda x: primer3_calc_tm(x, settings),
189
212
  )
190
213
  except ValueError as e:
191
214
  raise HTTPException(400, *e.args)
@@ -198,11 +221,17 @@ async def primer_design_ebic(
198
221
  template: PrimerDesignQuery,
199
222
  max_inside: int = Query(..., description='The maximum length of the inside edge of the EBIC primer.'),
200
223
  max_outside: int = Query(..., description='The maximum length of the outside edge of the EBIC primer.'),
224
+ target_tm: float = Query(
225
+ ..., description='The desired melting temperature for the hybridization part of the primer.'
226
+ ),
227
+ target_tm_tolerance: float = Query(
228
+ 3, description='The tolerance for the desired melting temperature for the hybridization part of the primer.'
229
+ ),
201
230
  ):
202
231
  """Design primers for EBIC"""
203
232
  dseqr = read_dsrecord_from_json(template.sequence)
204
233
  location = template.location.to_biopython_location()
205
- return {'primers': ebic_primers(dseqr, location, max_inside, max_outside)}
234
+ return {'primers': ebic_primers(dseqr, location, max_inside, max_outside, target_tm, target_tm_tolerance)}
206
235
 
207
236
 
208
237
  # @router.post('/primer_design/gateway_attB', response_model=PrimerDesignResponse)
@@ -240,32 +269,6 @@ async def primer_design_ebic(
240
269
  # return {'primers': primers}
241
270
 
242
271
 
243
- class ThermodynamicResult(BaseModel):
244
- melting_temperature: float
245
- deltaG: float
246
- figure: str | None
247
-
248
- @classmethod
249
- def from_binding(cls, result):
250
- return cls(
251
- melting_temperature=result.tm,
252
- deltaG=result.dg,
253
- figure='\n'.join(result.ascii_structure_lines),
254
- )
255
-
256
-
257
- def get_sequence_thermodynamic_result(sequences: list[str], method: callable) -> ThermodynamicResult | None:
258
- """Get the thermodynamic result for a sequence, if the sequence is longer than primer3 60bp limit, it will be split into two
259
- and the result with the lowest deltaG will be returned."""
260
- results = [method(seq, output_structure=True) for seq in sequences]
261
- results = [r for r in results if r.structure_found]
262
- if len(results) == 0:
263
- return None
264
-
265
- result = min(results, key=lambda r: r.dg)
266
- return ThermodynamicResult.from_binding(result)
267
-
268
-
269
272
  class PrimerDetailsResponse(BaseModel):
270
273
  melting_temperature: float
271
274
  gc_content: float
@@ -273,20 +276,20 @@ class PrimerDetailsResponse(BaseModel):
273
276
  hairpin: ThermodynamicResult | None
274
277
 
275
278
 
276
- @router.get('/primer_details', response_model=PrimerDetailsResponse)
279
+ @router.post('/primer_details', response_model=PrimerDetailsResponse)
277
280
  async def primer_details(
278
- sequence: str = Query(..., description='Primer sequence', pattern=r'^[ACGTacgt]+$'),
281
+ sequence: str = Body(..., description='Primer sequence', pattern=r'^[ACGTacgt]+$'),
282
+ settings: PrimerDesignSettings = Body(
283
+ ..., description='Primer design settings.', default_factory=PrimerDesignSettings
284
+ ),
279
285
  ):
280
286
  """Get information about a primer"""
281
287
  sequence = sequence.upper()
282
- tm = bindings.calc_tm(sequence)
288
+ tm = primer3_calc_tm(sequence, settings)
283
289
  gc_content = gc_fraction(sequence)
284
290
 
285
- thermodynamic_sequences = [sequence]
286
- if len(sequence) > 60:
287
- thermodynamic_sequences = [sequence[:60], sequence[-60:]]
288
- homodimer = get_sequence_thermodynamic_result(thermodynamic_sequences, bindings.calc_homodimer)
289
- hairpin = get_sequence_thermodynamic_result(thermodynamic_sequences, bindings.calc_hairpin)
291
+ homodimer = primer3_calc_homodimer(sequence, settings)
292
+ hairpin = primer3_calc_hairpin(sequence, settings)
290
293
 
291
294
  return {
292
295
  'melting_temperature': tm,
@@ -296,22 +299,14 @@ async def primer_details(
296
299
  }
297
300
 
298
301
 
299
- @router.get('/primer_heterodimer', response_model=ThermodynamicResult | None)
302
+ @router.post('/primer_heterodimer', response_model=ThermodynamicResult | None)
300
303
  async def primer_heterodimer(
301
- sequence1: str = Query(..., description='First primer sequence', pattern=r'^[ACGTacgt]+$'),
302
- sequence2: str = Query(..., description='Second primer sequence', pattern=r'^[ACGTacgt]+$'),
304
+ sequence1: str = Body(..., description='First primer sequence', pattern=r'^[ACGTacgt]+$'),
305
+ sequence2: str = Body(..., description='Second primer sequence', pattern=r'^[ACGTacgt]+$'),
306
+ settings: PrimerDesignSettings = Body(
307
+ ..., description='Primer design settings.', default_factory=PrimerDesignSettings
308
+ ),
303
309
  ):
304
310
  """Get information about a primer pair"""
305
311
 
306
- if len(sequence1) <= 60 or len(sequence2) <= 60:
307
- sequence_pairs = [(sequence1, sequence2)]
308
- else:
309
- sequence_pairs = list(product((sequence1[:60], sequence1[-60:]), (sequence2[:60], sequence2[-60:])))
310
-
311
- results = [bindings.calc_heterodimer(s1, s2, output_structure=True) for s1, s2 in sequence_pairs]
312
- results = [r for r in results if r.structure_found]
313
- if len(results) == 0:
314
- return None
315
-
316
- result = min(results, key=lambda r: r.dg)
317
- return ThermodynamicResult.from_binding(result)
312
+ return primer3_calc_heterodimer(sequence1, sequence2, settings)
@@ -110,7 +110,13 @@ async def get_genbank_sequence(sequence_accession, start=None, end=None, strand=
110
110
 
111
111
  resp = await async_get(url, headers=headers, params=params)
112
112
  if resp.status_code == 200:
113
- return pydna_parse(resp.text)[0]
113
+ try:
114
+ return pydna_parse(resp.text)[0]
115
+ except Exception:
116
+ # Now the ncbi returns something like this:
117
+ # Example: https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=nuccore&id=blah&rettype=gbwithparts&retmode=text
118
+ # 'Error: F a i l e d t o u n d e r s t a n d i d : b l a h '
119
+ raise HTTPException(404, 'wrong sequence accession')
114
120
  elif resp.status_code == 400:
115
121
  raise HTTPException(404, 'wrong sequence accession')
116
122
  elif resp.status_code == 503:
@@ -0,0 +1,109 @@
1
+ """
2
+ Functions to calculate primer melting temperature using primer3.
3
+ primer3 should not be imported anywhere else.
4
+ """
5
+
6
+ from pydantic import BaseModel, Field
7
+ from itertools import product
8
+ from primer3.bindings import (
9
+ calc_tm as _calc_tm,
10
+ design_primers as _design_primers,
11
+ calc_homodimer as _calc_homodimer,
12
+ calc_hairpin as _calc_hairpin,
13
+ calc_heterodimer as _calc_heterodimer,
14
+ )
15
+
16
+
17
+ class PrimerDesignSettings(BaseModel):
18
+ primer_dna_conc: float = Field(50, description='The DNA concentration in the primer solution (nM).')
19
+ primer_salt_monovalent: float = Field(
20
+ 50, description='The monovalent salt concentration in the primer solution (mM).'
21
+ )
22
+ primer_salt_divalent: float = Field(
23
+ 1.5, description='The divalent salt concentration in the primer solution (mM).'
24
+ )
25
+
26
+ def to_primer3_args(self) -> dict:
27
+ """Convert the settings to primer3 arguments."""
28
+ return {
29
+ 'dna_conc': self.primer_dna_conc,
30
+ 'mv_conc': self.primer_salt_monovalent,
31
+ 'dv_conc': self.primer_salt_divalent,
32
+ }
33
+
34
+
35
+ def primer3_calc_tm(seq: str, settings: PrimerDesignSettings) -> float:
36
+ return _calc_tm(seq.upper(), **settings.to_primer3_args())
37
+
38
+
39
+ def primer3_design_primers(seq: str, seq_args: dict, global_args: dict):
40
+ report = _design_primers(
41
+ seq_args={
42
+ 'SEQUENCE_ID': 'MH1000',
43
+ 'SEQUENCE_TEMPLATE': seq,
44
+ **seq_args,
45
+ },
46
+ global_args=global_args,
47
+ )
48
+ return report
49
+
50
+
51
+ class ThermodynamicResult(BaseModel):
52
+ melting_temperature: float
53
+ deltaG: float
54
+ figure: str | None
55
+
56
+ @classmethod
57
+ def from_binding(cls, result):
58
+ return cls(
59
+ melting_temperature=result.tm,
60
+ deltaG=result.dg,
61
+ figure='\n'.join(result.ascii_structure_lines),
62
+ )
63
+
64
+
65
+ def get_sequence_thermodynamic_result(sequence: str, method: callable) -> ThermodynamicResult | None:
66
+ """Get the thermodynamic result for a sequence, if the sequence is longer than primer3 60bp limit, it will be split into two
67
+ and the result with the lowest deltaG will be returned."""
68
+ sequence = sequence.upper()
69
+ if len(sequence) <= 60:
70
+ sequences = [sequence]
71
+ else:
72
+ sequences = [sequence[:60], sequence[-60:]]
73
+
74
+ results = [method(seq) for seq in sequences]
75
+ results = [r for r in results if r.structure_found]
76
+ if len(results) == 0:
77
+ return None
78
+
79
+ result = min(results, key=lambda r: r.dg)
80
+ return ThermodynamicResult.from_binding(result)
81
+
82
+
83
+ def primer3_calc_homodimer(seq: str, settings: PrimerDesignSettings) -> ThermodynamicResult:
84
+ return get_sequence_thermodynamic_result(
85
+ seq, lambda x: _calc_homodimer(x, output_structure=True, **settings.to_primer3_args())
86
+ )
87
+
88
+
89
+ def primer3_calc_hairpin(seq: str, settings: PrimerDesignSettings) -> ThermodynamicResult:
90
+ return get_sequence_thermodynamic_result(
91
+ seq, lambda x: _calc_hairpin(x, output_structure=True, **settings.to_primer3_args())
92
+ )
93
+
94
+
95
+ def primer3_calc_heterodimer(seq1: str, seq2: str, settings: PrimerDesignSettings) -> ThermodynamicResult:
96
+ if len(seq1) <= 60 or len(seq2) <= 60:
97
+ sequence_pairs = [(seq1, seq2)]
98
+ else:
99
+ sequence_pairs = list(product((seq1[:60], seq1[-60:]), (seq2[:60], seq2[-60:])))
100
+
101
+ results = [
102
+ _calc_heterodimer(s1, s2, output_structure=True, **settings.to_primer3_args()) for s1, s2 in sequence_pairs
103
+ ]
104
+ results = [r for r in results if r.structure_found]
105
+ if len(results) == 0:
106
+ return None
107
+
108
+ result = min(results, key=lambda r: r.dg)
109
+ return ThermodynamicResult.from_binding(result)
@@ -7,13 +7,8 @@ from .pydantic_models import PrimerModel
7
7
  from Bio.Seq import reverse_complement
8
8
  from Bio.Restriction.Restriction import RestrictionType
9
9
  from Bio.Data.IUPACData import ambiguous_dna_values as _ambiguous_dna_values
10
- from primer3.bindings import calc_tm as _calc_tm
11
10
  from typing import Callable
12
-
13
-
14
- def primer3_calc_tm(seq: str) -> float:
15
- return _calc_tm(seq.upper())
16
-
11
+ from .primer3_functions import primer3_calc_tm, PrimerDesignSettings
17
12
 
18
13
  ambiguous_dna_values = _ambiguous_dna_values.copy()
19
14
  # Remove acgt
@@ -21,6 +16,10 @@ for base in 'ACGT':
21
16
  del ambiguous_dna_values[base]
22
17
 
23
18
 
19
+ def default_tm_func(sequence: str) -> float:
20
+ return primer3_calc_tm(sequence, PrimerDesignSettings())
21
+
22
+
24
23
  def homologous_recombination_primers(
25
24
  pcr_seq: Dseqrecord,
26
25
  pcr_loc: SimpleLocation,
@@ -31,7 +30,7 @@ def homologous_recombination_primers(
31
30
  insert_forward: bool,
32
31
  target_tm: float,
33
32
  spacers: list[str] | None = None,
34
- tm_func: Callable[[str], float] = primer3_calc_tm,
33
+ tm_func: Callable[[str], float] = default_tm_func,
35
34
  estimate_function: Callable[[str], float] | None = None,
36
35
  ) -> tuple[str, str]:
37
36
 
@@ -91,7 +90,7 @@ def gibson_assembly_primers(
91
90
  target_tm: float,
92
91
  circular: bool,
93
92
  spacers: list[str] | None = None,
94
- tm_func: Callable[[str], float] = primer3_calc_tm,
93
+ tm_func: Callable[[str], float] = default_tm_func,
95
94
  estimate_function: Callable[[str], float] | None = None,
96
95
  ) -> list[PrimerModel]:
97
96
 
@@ -157,7 +156,7 @@ def simple_pair_primers(
157
156
  spacers: list[str] | None = None,
158
157
  left_enzyme_inverted: bool = False,
159
158
  right_enzyme_inverted: bool = False,
160
- tm_func: Callable[[str], float] = primer3_calc_tm,
159
+ tm_func: Callable[[str], float] = default_tm_func,
161
160
  estimate_function: Callable[[str], float] | None = None,
162
161
  ) -> tuple[PrimerModel, PrimerModel]:
163
162
  """
@@ -1,23 +0,0 @@
1
- LOCUS barcode 151 bp DNA linear UNA 15-SEP-2024
2
- DEFINITION natural linear DNA
3
- ACCESSION .
4
- VERSION .
5
- KEYWORDS .
6
- SOURCE natural DNA sequence
7
- ORGANISM unspecified
8
- REFERENCE 1 (bases 1 to 151)
9
- AUTHORS SnapGene License
10
- TITLE Direct Submission
11
- JOURNAL Exported Dec 20, 2024 from SnapGene 7.2.1
12
- https://www.snapgene.com
13
- FEATURES Location/Qualifiers
14
- source 1..151
15
- /mol_type="genomic DNA"
16
- /organism="unspecified"
17
- misc_feature 15..137
18
- /label=CG_Barcode1
19
- ORIGIN
20
- 1 ataggtctct aatggctctt attcgggaca tttacaatgc cacccactgg gagtgattat
21
- 61 gagtctcatt gagactgctc accacagcat gaattctctg gttcggtggc gcatagctat
22
- 121 cgctgttcct gccactggct tagagaccta t
23
- //
@@ -1,218 +0,0 @@
1
- LOCUS KanSacB+Scarlett 5747 bp DNA circular SYN 08-AUG-2024
2
- DEFINITION synthetic circular DNA
3
- ACCESSION .
4
- VERSION .
5
- KEYWORDS .
6
- SOURCE synthetic DNA construct
7
- ORGANISM recombinant plasmid
8
- REFERENCE 1 (bases 1 to 5747)
9
- AUTHORS SnapGene License
10
- TITLE Direct Submission
11
- JOURNAL Exported Dec 20, 2024 from SnapGene 7.2.1
12
- https://www.snapgene.com
13
- FEATURES Location/Qualifiers
14
- source 1..5747
15
- /mol_type="other DNA"
16
- /organism="recombinant plasmid"
17
- misc_feature 1..4
18
- /label=AATG
19
- /note="/color=#f7e8f7"
20
- misc_feature 5..2586
21
- /label=From pC0.026
22
- /note="/color=white"
23
- /note="/indicates_part=True"
24
- /note="/source=pC0.026"
25
- promoter 5..450
26
- /gene="sacR"
27
- /label=sacB promoter
28
- /note="sacB promoter and control region"
29
- CDS 451..1872
30
- /codon_start=1
31
- /gene="Bacillus subtilis sacB"
32
- /product="secreted levansucrase that renders
33
- bacterialgrowth sensitive to sucrose"
34
- /label=SacB
35
- /note="negative selection marker"
36
- /translation="MNIKKFAKQATVLTFTTALLAGGATQAFAKETNQKPYKETYGISH
37
- ITRHDMLQIPEQQKNEKYQVPEFDSSTIKNISSAKGLDVWDSWPLQNADGTVANYHGYH
38
- IVFALAGDPKNADDTSIYMFYQKVGETSIDSWKNAGRVFKDSDKFDANDSILKDQTQEW
39
- SGSATFTSDGKIRLFYTDFSGKHYGKQTLTTAQVNVSASDSSLNINGVEDYKSIFDGDG
40
- KTYQNVQQFIDEGNYSSGDNHTLRDPHYVEDKGHKYLVFEANTGTEDGYQGEESLFNKA
41
- YYGKSTSFFRQESQKLLQSDKKRTAELANGALGMIELNDDYTLKKVMKPLIASNTVTDE
42
- IERANVFKMNGKWYLFTDSRGSKMTIDGITSNDIYMLGYVSNSLTGPYKPLNKTGLVLK
43
- MDLDPNDVTFTYSHFAVPQAKGNNVVITSYMTNRGFYADKQSTFAPSFLLNIKGKKTSV
44
- VKDSILEQGQLTVNK"
45
- misc_feature 2587..2590
46
- /label=AGGT
47
- /note="/color=#f7e8f7"
48
- misc_feature 2591..3800
49
- /label=From pC0.027
50
- /note="/color=white"
51
- /note="/indicates_part=True"
52
- /note="/source=pC0.027"
53
- CDS complement(2875..3690)
54
- /codon_start=1
55
- /gene="aph(3')-Ia"
56
- /product="aminoglycoside phosphotransferase"
57
- /label=KanR
58
- /note="confers resistance to kanamycin in bacteria or
59
- G418(Geneticin(R)) in eukaryotes"
60
- /translation="MSHIQRETSCSRPRLNSNMDADLYGYKWARDNVGQSGATIYRLYG
61
- KPDAPELFLKHGKGSVANDVTDEMVRLNWLTEFMPLPTIKHFIRTPDDAWLLTTAIPGK
62
- TAFQVLEEYPDSGENIVDALAVFLRRLHSIPVCNCPFNSDRVFRLAQAQSRMNNGLVDA
63
- SDFDDERNGWPVEQVWKEMHKLLPFSPDSVVTHGDFSLDNLIFDEGKLIGCIDVGRVGI
64
- ADRYQDLAILWNCLGEFSPSLQKRLFQKYGIDNPDMNKLQFHLMLDEFF"
65
- misc_feature 3691..3800
66
- /label=promoter
67
- misc_feature 3801..3804
68
- /label=GCTT
69
- /note="/color=#f7e8f7"
70
- misc_feature 3805..4682
71
- /label=From gblock_OriTOriR
72
- /note="/color=white"
73
- /note="/indicates_part=True"
74
- /note="/source=gblock_OriTOriR"
75
- misc_feature 4675..4681
76
- /label=SapI site
77
- promoter 4713..4842
78
- /label=BBa_J72163 GlpT Promoter
79
- /note="label: BBa_J72163 GlpT Promoter"
80
- primer_bind 4713..4732
81
- /label=CG17
82
- RBS 4843..4878
83
- /label=RBS
84
- /note="label: RBS"
85
- RBS 4861..4872
86
- /label=RBS
87
- /note="note: strong bacterial ribosome binding site
88
- (Elowitz and Leibler, 2000)"
89
- CDS 4879..5577
90
- /label=mScarlet
91
- /note="codon_start: 1 label: mScarlet transl_table: 1
92
- translation:
93
- MVSKGEAVIKEFMRFKVHMEGSMNGHEFEIEGEGEGRPYEGTQTAKLKVTKGGPLPFSW
94
- DILSPQFMYGSRAFTKHPADIPDYYKQSFPEGFKWERVMNFEDGGAVTVTQDTSLEDGT
95
- LIYKVKLRGTNFPPDGPVMQKKTMGWEASTERLYPEDGVLKGDIKMALRLKDGGRYLAD
96
- FKTTYKAKKPVQMPGAYNVDRKLDITSHNEDYTVVEQYERSEGRHSTGGMDELYK*"
97
- terminator 5578..5706
98
- /label=BBa_B0015 Terminator
99
- /note="label: BBa_B0015 Terminator"
100
- terminator 5586..5657
101
- /label=rrnB T1 terminator
102
- /note="label: rrnB T1 terminator note: pLannotate note:
103
- /database=snapgene note: /fragment=False note:
104
- /identity=100.0 note: /match_length=100.0 note:
105
- /other=terminator"
106
- terminator 5673..5700
107
- /label=T7Te terminator
108
- /note="label: T7Te terminator note: pLannotate note:
109
- /database=snapgene note: /fragment=False note:
110
- /identity=100.0 note: /match_length=100.0 note:
111
- /other=terminator"
112
- primer_bind complement(5685..5706)
113
- /label=CG18
114
- misc_feature 5734..5747
115
- /label=From gblock_OriTOriR
116
- /note="/color=white"
117
- /note="/indicates_part=True"
118
- /note="/source=gblock_OriTOriR"
119
- misc_feature 5738..5744
120
- /label=SapI site
121
- ORIGIN
122
- 1 aatgcacata tacctgccgt tcactattat ttagtgaaat gagatattat gatattttct
123
- 61 gaattgtgat taaaaaggca actttatgcc catgcaacag aaactataaa aaatacagag
124
- 121 aatgaaaaga aacagataga ttttttagtt ctttaggccc gtagtctgca aatcctttta
125
- 181 tgattttcta tcaaacaaaa gaggaaaata gaccagttgc aatccaaacg agagtctaat
126
- 241 agaatgaggt cgaaaagtaa atcgcgcggg tttgttactg ataaagcagg caagacctaa
127
- 301 aatgtgtaaa gggcaaagtg tatactttgg cgtcacccct tacatatttt aggtcttttt
128
- 361 ttattgtgcg taactaactt gccatcttca aacaggaggg ctggaagaag cagaccgcta
129
- 421 acacagtaca taaaaaagga gacatgaacg atgaacatca aaaagtttgc aaaacaagca
130
- 481 acagtattaa cctttactac cgcactgctg gcaggaggcg caactcaagc gtttgcgaaa
131
- 541 gaaacgaacc aaaagccata taaggaaaca tacggcattt cccatattac acgccatgat
132
- 601 atgctgcaaa tccctgaaca gcaaaaaaat gaaaaatatc aagttcctga attcgattcg
133
- 661 tccacaatta aaaatatctc ttctgcaaaa ggcctggacg tttgggacag ctggccatta
134
- 721 caaaacgctg acggcactgt cgcaaactat cacggctacc acatcgtctt tgcattagcc
135
- 781 ggagatccta aaaatgcgga tgacacatcg atttacatgt tctatcaaaa agtcggcgaa
136
- 841 acttctattg acagctggaa aaacgctggc cgcgtcttta aagacagcga caaattcgat
137
- 901 gcaaatgatt ctatcctaaa agaccaaaca caagaatggt caggttcagc cacatttaca
138
- 961 tctgacggaa aaatccgttt attctacact gatttctccg gtaaacatta cggcaaacaa
139
- 1021 acactgacaa ctgcacaagt taacgtatca gcatcagaca gctctttgaa catcaacggt
140
- 1081 gtagaggatt ataaatcaat ctttgacggt gacggaaaaa cgtatcaaaa tgtacagcag
141
- 1141 ttcatcgatg aaggcaacta cagctcaggc gacaaccata cgctgagaga tcctcactac
142
- 1201 gtagaagata aaggccacaa atacttagta tttgaagcaa acactggaac tgaagatggc
143
- 1261 taccaaggcg aagaatcttt atttaacaaa gcatactatg gcaaaagcac atcattcttc
144
- 1321 cgtcaagaaa gtcaaaaact tctgcaaagc gataaaaaac gcacggctga gttagcaaac
145
- 1381 ggcgctctcg gtatgattga gctaaacgat gattacacac tgaaaaaagt gatgaaaccg
146
- 1441 ctgattgcat ctaacacagt aacagatgaa attgaacgcg cgaacgtctt taaaatgaac
147
- 1501 ggcaaatggt acctgttcac tgactcccgc ggatcaaaaa tgacgattga cggcattacg
148
- 1561 tctaacgata tttacatgct tggttatgtt tctaattctt taactggccc atacaagccg
149
- 1621 ctgaacaaaa ctggccttgt gttaaaaatg gatcttgatc ctaacgatgt aacctttact
150
- 1681 tactcacact tcgctgtacc tcaagcgaaa ggaaacaatg tcgtgattac aagctatatg
151
- 1741 acaaacagag gattctacgc agacaaacaa tcaacgtttg cgccaagctt cctgctgaac
152
- 1801 atcaaaggca agaaaacatc tgttgtcaaa gacagcatcc ttgaacaagg acaattaaca
153
- 1861 gttaacaaat aaaaacgcaa aagaaaatgc cgatatccta ttggcatttt cttttatttc
154
- 1921 ttatcaacat aaaggtgaat cccatatgaa ctatataaaa gcaggcaaat ggctaaccgt
155
- 1981 attcctaacc ttttggtaat gactccaact tattgatagt gttttatgtt cagataatgc
156
- 2041 ccgatgactt tgtcatgcag ctccaccgat tttgagaacg acagcgactt ccgtcccagc
157
- 2101 cgtgccaggt gctgcctcag attcaggtta tgccgctcaa ttcgctgcgt atatcgcttg
158
- 2161 ctgattacgt gcagctttcc cttcaggcgg gattcataca gcggccagcc atccgtcatc
159
- 2221 catatcacca cgtcaaaggg tgacagcagg ctcataagac gccccagcgt cgccatagtg
160
- 2281 cgttcaccga atacgtgcgc aacaaccgtc taccggagac tgtcatacgc gtaaaacagc
161
- 2341 cagcgctggc gcgatttagc cccgacatag ccccactgtt cgtccatttc cgcgcagacg
162
- 2401 atgacgtcac tgcccggctg tatgcgcgag gttaccgact gcggcctgag ttttttaagt
163
- 2461 gacgtaaaat cgtgttgagg ccaacgccca taatgcgggc tgttgcccgg catccaacgc
164
- 2521 cattcatggc catatcaatg attttctggt gcgtaccggg ttgagaagcg gtgtaagtga
165
- 2581 actgcaaggt ctgaggtctg cctcgtgaag aaggtgttgc tgactcatac caggcctgaa
166
- 2641 tcgccccatc atccagccag aaagtgaggg agccacggtt gatgagagct ttgttgtagg
167
- 2701 tggaccagtt ggtgattttg aacttttgct ttgccacgga acggtctgcg ttgtcgggaa
168
- 2761 gatgcgtgat ctgatccttc aactcagcaa aagttcgatt tattcaacaa agccgccgtc
169
- 2821 ccgtcaagtc agcgtaatgc tctgccagtg ttacaaccaa ttaaccaatt ctgattagaa
170
- 2881 aaactcatcg agcatcaaat gaaactgcaa tttattcata tcaggattat caataccata
171
- 2941 tttttgaaaa agccgtttct gtaatgaagg agaaaactca ccgaggcagt tccataggat
172
- 3001 ggcaagatcc tggtatcggt ctgcgattcc gactcgtcca acatcaatac aacctattaa
173
- 3061 tttcccctcg tcaaaaataa ggttatcaag tgagaaatca ccatgagtga cgactgaatc
174
- 3121 cggtgagaat ggcaaaagct tatgcatttc tttccagact tgttcaacag gccagccatt
175
- 3181 acgctcgtca tcaaaatcac tcgcatcaac caaaccgtta ttcattcgtg attgcgcctg
176
- 3241 agcgagacga aatacgcgat cgctgttaaa aggacaatta caaacaggaa tcgaatgcaa
177
- 3301 ccggcgcagg aacactgcca gcgcatcaac aatattttca cctgaatcag gatattcttc
178
- 3361 taatacctgg aatgctgttt tcccggggat cgcagtggtg agtaaccatg catcatcagg
179
- 3421 agtacggata aaatgcttga tggtcggaag aggcataaat tccgtcagcc agtttagtct
180
- 3481 gaccatctca tctgtaacat cattggcaac gctacctttg ccatgtttca gaaacaactc
181
- 3541 tggcgcatcg ggcttcccat acaatcgata gattgtcgca cctgattgcc cgacattatc
182
- 3601 gcgagcccat ttatacccat ataaatcagc atccatgttg gaatttaatc gcggcctcga
183
- 3661 gcaagacgtt tcccgttgaa tatggctcat aacacccctt gtattactgt ttatgtaagc
184
- 3721 agacagtttt attgttcatg atgatatatt tttatcttgt gcaatgtaac atcagagatt
185
- 3781 ttgagacaca acgtggcttt gcttgtacac cttgataggt gggctgccct tcctggttgg
186
- 3841 cttggtttca tcagccatcc gcttgccctc atctgttacg ccggcggtag ccggccagcc
187
- 3901 tcgcagagca ggattcccgt tgagcaccgc caggtgcgaa taagggacag tgaagaagga
188
- 3961 acacccgctc gcgggtgggc ctacttcacc tatcctgccc ggctgacgcc gttggataca
189
- 4021 ccaaggaaag tctacacgaa ccctttggca aaatatcaaa ggatcttctt gagatccttt
190
- 4081 ttttctgcgc gtaatctgct gcttgcaaac aaaaaaacca ccgctaccag cggtggtttg
191
- 4141 tttgccggat caagagctac caactctttt tccgaaggta actggcttca gcagagcgca
192
- 4201 gataccaaat actgttcttc tagtgtagcc gtagttaggc caccacttca agaactctgt
193
- 4261 agcaccgcct acatacctcg ctctgctaat cctgttacca gtggctgctg ccagtggcga
194
- 4321 taagtcgtgt cttaccgggt tggactcaag acgatagtta ccggataagg cgcagcggtc
195
- 4381 gggctgaacg gggggttcgt gcacacagcc cagcttggag cgaacgacct acaccgaact
196
- 4441 gagataccta cagcgtgagc tatgagaaag cgccacgctt cccgaaggga gaaaggcgga
197
- 4501 caggtatccg gtaagcggca gggtcggaac aggagagcgc acgagggagc ttccaggggg
198
- 4561 aaacgcctgg tatctttata gtcctgtcgg gtttcgccac ctctgacttg agcgtcgatt
199
- 4621 tttgtgatgc tcgtcagggg ggcggagcct atggaaaaac gccagcaacg cggcgctctt
200
- 4681 catgctcgga gagagacctt tgccttgtct tcgaaagtga aacgtgattt catgcgtcat
201
- 4741 tttgaacatt ttgtaaatct tatttaataa tgtgtgcggc aattcacatt taatttatga
202
- 4801 atgttttctt aacatcgcgg caactcaaga aacggcaggt tcggatctta gctactagag
203
- 4861 aaagaggaga aatactagat ggttagcaaa ggcgaggcgg ttatcaagga gtttatgcgt
204
- 4921 tttaaggttc acatggaggg tagcatgaac ggtcacgagt tcgagatcga gggtgaaggc
205
- 4981 gagggtcgtc cgtacgaagg cacccagacc gcgaagctga aagtgaccaa gggtggcccg
206
- 5041 ctgccgttca gctgggacat cctgagcccg cagttcatgt atggcagccg tgcgtttacc
207
- 5101 aaacacccgg cggacattcc ggattactat aagcaaagct tcccggaagg ttttaaatgg
208
- 5161 gagcgtgtta tgaacttcga agatggtggc gcggtgaccg ttacccagga caccagcctg
209
- 5221 gaggatggca ccctgattta caaggtgaaa ctgcgtggca ccaactttcc gccggatggt
210
- 5281 ccggttatgc agaagaaaac gatgggttgg gaagcgagca ccgagcgtct gtatccggaa
211
- 5341 gatggcgtgc tgaagggtga tatcaaaatg gcgctgcgtc tgaaggacgg tggccgttac
212
- 5401 ctggcggatt ttaagaccac ctataaagcg aagaaaccgg tgcaaatgcc gggtgcgtac
213
- 5461 aacgttgacc gtaaactgga tattaccagc cacaacgagg attataccgt ggttgagcaa
214
- 5521 tatgagcgta gcgagggtcg ccacagcacc ggcggcatgg acgaactgta taagtgacca
215
- 5581 ggcatcaaat aaaacgaaag gctcagtcga aagactgggc ctttcgtttt atctgttgtt
216
- 5641 tgtcggtgaa cgctctctac tagagtcaca ctggctcacc ttcgggtggg cctttctgcg
217
- 5701 tttatagaag acaagggaaa ggtctctcgc tgagatagaa gagcacg
218
- //
@@ -1,180 +0,0 @@
1
- import asyncio
2
- import os
3
- from primer3 import bindings
4
- import json
5
- from fastapi import UploadFile, Response
6
-
7
- from opencloning.pydantic_models import (
8
- GenomeCoordinatesSource,
9
- TextFileSequence,
10
- PrimerModel,
11
- PCRSource,
12
- RestrictionAndLigationSource,
13
- BaseCloningStrategy,
14
- HomologousRecombinationSource,
15
- )
16
- from opencloning.batch_cloning.EBIC.primer_design_settings import amanda_settings
17
- from opencloning.endpoints.external_import import genome_coordinates, read_from_file
18
- from opencloning.endpoints.assembly import pcr, restriction_and_ligation, homologous_recombination
19
- from opencloning.dna_functions import read_dsrecord_from_json
20
-
21
- # Settings for design
22
- padding = 1000
23
- max_inside = 20
24
- max_outside = 70
25
- outside_edge = padding - max_outside
26
- inside_edge = padding + max_inside
27
-
28
- adapter_left_fwd = 'ataGGTCTCtGGAG'
29
- adapter_left_rvs = 'ataGGTCTCtCATT'
30
- adapter_right_fwd = 'ataGGTCTCtGCTT'
31
- adapter_right_rvs = 'ataGGTCTCtAGCG'
32
-
33
-
34
- def design_primers_ebic(seq: str, seq_args: dict):
35
-
36
- report = bindings.design_primers(
37
- seq_args={
38
- 'SEQUENCE_ID': 'MH1000',
39
- 'SEQUENCE_TEMPLATE': seq,
40
- **seq_args,
41
- },
42
- global_args=amanda_settings,
43
- )
44
-
45
- return report
46
-
47
-
48
- async def main():
49
- cloning_strategy = BaseCloningStrategy(
50
- sequences=[],
51
- sources=[],
52
- primers=[],
53
- description='EBIC cloning strategy',
54
- )
55
-
56
- initial_source = GenomeCoordinatesSource(
57
- id=0,
58
- assembly_accession='GCF_002847425.1',
59
- sequence_accession='NZ_CP025534.1',
60
- start=2700777 - padding,
61
- end=2701295 + padding,
62
- strand=1,
63
- )
64
-
65
- if os.path.exists('cached_response.json'):
66
- with open('cached_response.json', 'r') as f:
67
- locus = json.load(f)
68
- locus['sequences'][0] = TextFileSequence.model_validate(locus['sequences'][0])
69
- locus['sources'][0] = GenomeCoordinatesSource.model_validate(locus['sources'][0])
70
- else:
71
- print('No cached response found, fetching from server')
72
- locus = await genome_coordinates(initial_source)
73
- with open('cached_response.json', 'w') as f:
74
- json.dump(
75
- {
76
- 'sequences': [locus['sequences'][0].model_dump()],
77
- 'sources': [locus['sources'][0].model_dump()],
78
- },
79
- f,
80
- )
81
-
82
- locus_seq: TextFileSequence = locus['sequences'][0]
83
- locus_source: GenomeCoordinatesSource = locus['sources'][0]
84
- locus_dseqr = read_dsrecord_from_json(locus_seq)
85
-
86
- cloning_strategy.add_source_and_sequence(locus_source, locus_seq)
87
-
88
- left_template = locus_dseqr[:inside_edge]
89
- right_template = locus_dseqr[-inside_edge:]
90
-
91
- seq_args_left = {
92
- 'SEQUENCE_PRIMER_PAIR_OK_REGION_LIST': f'0,{int(padding/2)},{outside_edge},{max_outside + max_inside}',
93
- }
94
- seq_args_right = {
95
- 'SEQUENCE_PRIMER_PAIR_OK_REGION_LIST': f'0,{max_outside + max_inside},{len(right_template) - int(padding/2)},{int(padding/2)}',
96
- }
97
-
98
- report_left = design_primers_ebic(str(left_template.seq), seq_args_left)
99
- report_right = design_primers_ebic(str(right_template.seq), seq_args_right)
100
-
101
- primer_names = ['left_fwd', 'left_rvs', 'right_fwd', 'right_rvs']
102
- primer_seqs = [
103
- adapter_left_fwd + report_left['PRIMER_LEFT'][0]['SEQUENCE'],
104
- adapter_left_rvs + report_left['PRIMER_RIGHT'][0]['SEQUENCE'],
105
- adapter_right_fwd + report_right['PRIMER_LEFT'][0]['SEQUENCE'],
106
- adapter_right_rvs + report_right['PRIMER_RIGHT'][0]['SEQUENCE'],
107
- ]
108
- primers = [PrimerModel(id=0, name=primer_names[i], sequence=primer_seqs[i]) for i in range(4)]
109
- for primer in primers:
110
- cloning_strategy.add_primer(primer)
111
-
112
- pcr_left_source = PCRSource(id=0, output_name='left_homology_arm')
113
- resp = await pcr(pcr_left_source, [locus_seq], [primers[0], primers[1]], 17, 0)
114
- pcr_product_left: TextFileSequence = resp['sequences'][0]
115
- pcr_left_source: PCRSource = resp['sources'][0]
116
- cloning_strategy.add_source_and_sequence(pcr_left_source, pcr_product_left)
117
-
118
- pcr_right_source = PCRSource(id=0, output_name='right_homology_arm')
119
- resp = await pcr(pcr_right_source, [locus_seq], [primers[2], primers[3]], 17, 0)
120
- pcr_product_right: TextFileSequence = resp['sequences'][0]
121
- pcr_right_source: PCRSource = resp['sources'][0]
122
- cloning_strategy.add_source_and_sequence(pcr_right_source, pcr_product_right)
123
-
124
- with open(os.path.join(os.path.dirname(__file__), 'barcode.gb'), 'rb') as f:
125
- dummy_resp = Response()
126
- resp = await read_from_file(
127
- dummy_resp, UploadFile(file=f, filename='barcode.gb'), None, None, True, 'barcode', None, None
128
- )
129
-
130
- barcode_source = resp['sources'][0]
131
- barcode_seq: TextFileSequence = resp['sequences'][0]
132
- cloning_strategy.add_source_and_sequence(barcode_source, barcode_seq)
133
-
134
- with open(os.path.join(os.path.dirname(__file__), 'common_plasmid.gb'), 'rb') as f:
135
- dummy_resp = Response()
136
- resp = await read_from_file(
137
- dummy_resp,
138
- UploadFile(file=f, filename='common_plasmid.gb'),
139
- None,
140
- None,
141
- True,
142
- 'common_plasmid',
143
- None,
144
- None,
145
- )
146
-
147
- common_plasmid_source = resp['sources'][0]
148
- common_plasmid_seq: TextFileSequence = resp['sequences'][0]
149
- cloning_strategy.add_source_and_sequence(common_plasmid_source, common_plasmid_seq)
150
-
151
- golgen_gate = RestrictionAndLigationSource(id=0, output_name='golgen_gate', restriction_enzymes=['BsaI'])
152
- resp = await restriction_and_ligation(
153
- golgen_gate, [pcr_product_left, pcr_product_right, barcode_seq, common_plasmid_seq], False, True
154
- )
155
- golgen_gate_product: TextFileSequence = resp['sequences'][0]
156
- golgen_gate_source: RestrictionAndLigationSource = resp['sources'][0]
157
- cloning_strategy.add_source_and_sequence(golgen_gate_source, golgen_gate_product)
158
-
159
- homologous_recombination_source = HomologousRecombinationSource(id=0, output_name='engineered_allele')
160
- resp = await homologous_recombination(homologous_recombination_source, [locus_seq, golgen_gate_product], 17)
161
-
162
- multi_site_sources = [
163
- i for i, s in enumerate(resp['sources']) if all(join.left_location != join.right_location for join in s.input)
164
- ]
165
- if len(multi_site_sources) > 1:
166
- raise ValueError('Multiple insertions possible')
167
-
168
- possible_sources = [resp['sources'][i] for i in multi_site_sources]
169
- possible_sequences = [resp['sequences'][i] for i in multi_site_sources]
170
- homologous_recombination_product: TextFileSequence = possible_sequences[0]
171
- homologous_recombination_source: HomologousRecombinationSource = possible_sources[0]
172
- cloning_strategy.add_source_and_sequence(homologous_recombination_source, homologous_recombination_product)
173
-
174
- # Save cloning strategy to JSON file
175
- with open('cloning_strategy.json', 'w') as f:
176
- json.dump(cloning_strategy.model_dump(), f, indent=2)
177
- return cloning_strategy
178
-
179
-
180
- asyncio.run(main())
@@ -1,38 +0,0 @@
1
- amanda_settings = {
2
- # Tm: Optimal 60-62°C, but this can be extended to 58-64°C if necessary.
3
- # All primers need to ideally be within 5°C to ensure they can be run on the same plate for high-throughput.
4
- 'PRIMER_OPT_TM': 61, # Optimal Tm
5
- 'PRIMER_MIN_TM': 58, # Minimum Tm
6
- 'PRIMER_MAX_TM': 64, # Maximum Tm
7
- 'PRIMER_PAIR_MAX_DIFF_TM': 5, # Maximum Tm difference within a pair
8
- # Salt concentration: 50mM NaCl, 1.5mM MgCl2
9
- 'PRIMER_SALT_MONOVALENT': 50.0,
10
- 'PRIMER_SALT_DIVALENT': 1.5,
11
- # 500 nM primer concentration
12
- 'PRIMER_DNA_CONC': 500.0,
13
- # Primer size: 17-30nt.
14
- 'PRIMER_MIN_SIZE': 17, # Minimum primer length
15
- 'PRIMER_MAX_SIZE': 30, # Maximum primer length
16
- 'PRIMER_OPT_SIZE': 22, # Typical optimal size (can be adjusted)
17
- # GC content: between 35 and 65%.
18
- 'PRIMER_MIN_GC': 35, # Minimum GC content percentage
19
- 'PRIMER_MAX_GC': 65, # Maximum GC content percentage
20
- # A 1 or 2nt GC clamp at the 3’ end of the primer helps with PCR efficiency.
21
- 'PRIMER_GC_CLAMP': 1, # Number of GC bases required at the 3’ end
22
- # Product size: ~950bp homologous arms, though this can be shortened if necessary.
23
- 'PRIMER_PRODUCT_SIZE_RANGE': [[800, 1000]], # Product size range in base pairs
24
- # Avoid primers with long repetitions of nucleotides in a row (e.g., TTTTT).
25
- 'PRIMER_MAX_POLY_X': 4, # Maximum allowable repetitions of a single nucleotide
26
- # Dimer and hairpin structure considerations:
27
- # Self-dimers – avoid ΔG below -10
28
- # Heterodimers – avoid ΔG below -10
29
- # Hairpin loops - avoid ΔG below -5
30
- 'PRIMER_MAX_SELF_ANY': 47,
31
- 'PRIMER_MAX_SELF_END': 47,
32
- 'PRIMER_MAX_HAIRPIN': 47,
33
- # Return only one primer pair
34
- 'PRIMER_NUM_RETURN': 1,
35
- }
36
-
37
- # Avoid primers with homology to other sites in the genome.
38
- # This can be checked using external tools like BLAST for specificity.
File without changes
File without changes
File without changes