opencloning 0.2.6.4__tar.gz → 0.2.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 (45) hide show
  1. {opencloning-0.2.6.4 → opencloning-0.2.7}/PKG-INFO +1 -1
  2. {opencloning-0.2.6.4 → opencloning-0.2.7}/pyproject.toml +1 -1
  3. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/endpoints/primer_design.py +81 -0
  4. {opencloning-0.2.6.4 → opencloning-0.2.7}/LICENSE +0 -0
  5. {opencloning-0.2.6.4 → opencloning-0.2.7}/README.md +0 -0
  6. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/__init__.py +0 -0
  7. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/api_config_utils.py +0 -0
  8. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/app_settings.py +0 -0
  9. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/assembly2.py +0 -0
  10. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/EBIC/__init__.py +0 -0
  11. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/EBIC/barcode.gb +0 -0
  12. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/EBIC/common_plasmid.gb +0 -0
  13. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/EBIC/example.py +0 -0
  14. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/EBIC/primer_design_settings.py +0 -0
  15. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/__init__.py +0 -0
  16. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/index.html +0 -0
  17. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/pombe/__init__.py +0 -0
  18. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/pombe/index.html +0 -0
  19. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/pombe/pombe_all.sh +0 -0
  20. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/pombe/pombe_clone.py +0 -0
  21. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/pombe/pombe_gather.py +0 -0
  22. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/pombe/pombe_get_primers.py +0 -0
  23. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/pombe/pombe_summary.py +0 -0
  24. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/ziqiang_et_al2024/__init__.py +0 -0
  25. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/ziqiang_et_al2024/index.html +0 -0
  26. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/batch_cloning/ziqiang_et_al2024/ziqiang_et_al2024.json +0 -0
  27. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/dna_functions.py +0 -0
  28. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/dna_utils.py +0 -0
  29. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/ebic/__init__.py +0 -0
  30. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/ebic/primer_design.py +0 -0
  31. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/ebic/primer_design_settings.py +0 -0
  32. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/endpoints/annotation.py +0 -0
  33. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/endpoints/assembly.py +0 -0
  34. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/endpoints/external_import.py +0 -0
  35. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/endpoints/no_assembly.py +0 -0
  36. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/endpoints/no_input.py +0 -0
  37. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/endpoints/other.py +0 -0
  38. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/gateway.py +0 -0
  39. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/get_router.py +0 -0
  40. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/main.py +0 -0
  41. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/ncbi_requests.py +0 -0
  42. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/primer_design.py +0 -0
  43. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/pydantic_models.py +0 -0
  44. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/request_examples.py +0 -0
  45. {opencloning-0.2.6.4 → opencloning-0.2.7}/src/opencloning/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: opencloning
3
- Version: 0.2.6.4
3
+ Version: 0.2.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
  Author: Manuel Lera-Ramirez
@@ -3,7 +3,7 @@ authors = ["Manuel Lera-Ramirez <manulera14@gmail.com>"]
3
3
  description = "Backend of OpenCloning, a web application to generate molecular cloning strategies in json format, and share them with others."
4
4
  license = "MIT"
5
5
  name = "opencloning"
6
- version = "v0.2.6.4"
6
+ version = "v0.2.7"
7
7
  package-mode = true
8
8
  readme = "README.md"
9
9
  repository = "https://github.com/manulera/OpenCloning_backend"
@@ -2,6 +2,9 @@ from fastapi import Body, Query, HTTPException
2
2
  from pydantic import create_model
3
3
  import re
4
4
  from Bio.Restriction import RestrictionBatch
5
+ from Bio.SeqUtils import gc_fraction
6
+ from primer3 import bindings
7
+ from itertools import product
5
8
 
6
9
  from ..dna_functions import get_invalid_enzyme_names
7
10
  from ..pydantic_models import PrimerModel, PrimerDesignQuery
@@ -13,6 +16,7 @@ from ..primer_design import (
13
16
  )
14
17
  from ..get_router import get_router
15
18
  from ..ebic.primer_design import ebic_primers
19
+ from pydantic import BaseModel
16
20
 
17
21
  router = get_router()
18
22
 
@@ -235,3 +239,80 @@ async def primer_design_ebic(
235
239
  # raise HTTPException(400, *e.args)
236
240
 
237
241
  # return {'primers': primers}
242
+
243
+
244
+ class ThermodynamicResult(BaseModel):
245
+ melting_temperature: float
246
+ deltaG: float
247
+ figure: str | None
248
+
249
+ @classmethod
250
+ def from_binding(cls, result):
251
+ return cls(
252
+ melting_temperature=result.tm,
253
+ deltaG=result.dg,
254
+ figure='\n'.join(result.ascii_structure_lines),
255
+ )
256
+
257
+
258
+ def get_sequence_thermodynamic_result(sequences: list[str], method: callable) -> ThermodynamicResult | None:
259
+ """Get the thermodynamic result for a sequence, if the sequence is longer than primer3 60bp limit, it will be split into two
260
+ and the result with the lowest deltaG will be returned."""
261
+ results = [method(seq, output_structure=True) for seq in sequences]
262
+ results = [r for r in results if r.structure_found]
263
+ if len(results) == 0:
264
+ return None
265
+
266
+ result = min(results, key=lambda r: r.dg)
267
+ return ThermodynamicResult.from_binding(result)
268
+
269
+
270
+ class PrimerDetailsResponse(BaseModel):
271
+ melting_temperature: float
272
+ gc_content: float
273
+ homodimer: ThermodynamicResult | None
274
+ hairpin: ThermodynamicResult | None
275
+
276
+
277
+ @router.get('/primer_details', response_model=PrimerDetailsResponse)
278
+ async def primer_details(
279
+ sequence: str = Query(..., description='Primer sequence', regex=r'^[ACGTacgt]+$'),
280
+ ):
281
+ """Get information about a primer"""
282
+ sequence = sequence.upper()
283
+ tm = bindings.calc_tm(sequence)
284
+ gc_content = gc_fraction(sequence)
285
+
286
+ thermodynamic_sequences = [sequence]
287
+ if len(sequence) > 60:
288
+ thermodynamic_sequences = [sequence[:60], sequence[-60:]]
289
+ homodimer = get_sequence_thermodynamic_result(thermodynamic_sequences, bindings.calc_homodimer)
290
+ hairpin = get_sequence_thermodynamic_result(thermodynamic_sequences, bindings.calc_hairpin)
291
+
292
+ return {
293
+ 'melting_temperature': tm,
294
+ 'gc_content': gc_content,
295
+ 'homodimer': homodimer,
296
+ 'hairpin': hairpin,
297
+ }
298
+
299
+
300
+ @router.get('/primer_heterodimer', response_model=ThermodynamicResult | None)
301
+ async def primer_heterodimer(
302
+ sequence1: str = Query(..., description='First primer sequence', regex=r'^[ACGTacgt]+$'),
303
+ sequence2: str = Query(..., description='Second primer sequence', regex=r'^[ACGTacgt]+$'),
304
+ ):
305
+ """Get information about a primer pair"""
306
+
307
+ if len(sequence1) <= 60 or len(sequence2) <= 60:
308
+ sequence_pairs = [(sequence1, sequence2)]
309
+ else:
310
+ sequence_pairs = list(product((sequence1[:60], sequence1[-60:]), (sequence2[:60], sequence2[-60:])))
311
+
312
+ results = [bindings.calc_heterodimer(s1, s2, output_structure=True) for s1, s2 in sequence_pairs]
313
+ results = [r for r in results if r.structure_found]
314
+ if len(results) == 0:
315
+ return None
316
+
317
+ result = min(results, key=lambda r: r.dg)
318
+ return ThermodynamicResult.from_binding(result)
File without changes
File without changes