opencloning 0.4.8__py3-none-any.whl → 0.5.0.1__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.
Files changed (37) hide show
  1. opencloning/app_settings.py +7 -0
  2. opencloning/batch_cloning/pombe/__init__.py +2 -2
  3. opencloning/batch_cloning/pombe/pombe_clone.py +31 -112
  4. opencloning/batch_cloning/pombe/pombe_summary.py +20 -8
  5. opencloning/batch_cloning/ziqiang_et_al2024/__init__.py +8 -8
  6. opencloning/batch_cloning/ziqiang_et_al2024/ziqiang_et_al2024.json +2 -9
  7. opencloning/bug_fixing/backend_v0_3.py +13 -5
  8. opencloning/catalogs/__init__.py +36 -0
  9. opencloning/catalogs/igem2024.yaml +2172 -0
  10. opencloning/catalogs/openDNA_collections.yaml +1161 -0
  11. opencloning/catalogs/readme.txt +1 -0
  12. opencloning/catalogs/seva.tsv +231 -0
  13. opencloning/catalogs/snapgene.yaml +2837 -0
  14. opencloning/dna_functions.py +155 -158
  15. opencloning/dna_utils.py +45 -62
  16. opencloning/ebic/primer_design.py +1 -1
  17. opencloning/endpoints/annotation.py +9 -13
  18. opencloning/endpoints/assembly.py +157 -378
  19. opencloning/endpoints/endpoint_utils.py +52 -0
  20. opencloning/endpoints/external_import.py +169 -124
  21. opencloning/endpoints/no_assembly.py +23 -39
  22. opencloning/endpoints/no_input.py +32 -47
  23. opencloning/endpoints/other.py +1 -1
  24. opencloning/endpoints/primer_design.py +2 -1
  25. opencloning/http_client.py +2 -2
  26. opencloning/ncbi_requests.py +113 -47
  27. opencloning/primer_design.py +1 -1
  28. opencloning/pydantic_models.py +10 -510
  29. opencloning/request_examples.py +10 -22
  30. opencloning/temp_functions.py +50 -0
  31. {opencloning-0.4.8.dist-info → opencloning-0.5.0.1.dist-info}/METADATA +18 -8
  32. opencloning-0.5.0.1.dist-info/RECORD +51 -0
  33. {opencloning-0.4.8.dist-info → opencloning-0.5.0.1.dist-info}/WHEEL +1 -1
  34. opencloning/cre_lox.py +0 -116
  35. opencloning/gateway.py +0 -154
  36. opencloning-0.4.8.dist-info/RECORD +0 -45
  37. {opencloning-0.4.8.dist-info → opencloning-0.5.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -22,6 +22,11 @@ if os.environ.get('ALLOWED_ORIGINS') is not None:
22
22
 
23
23
  # External services settings =================================
24
24
  NCBI_API_KEY = os.environ.get('NCBI_API_KEY')
25
+ NCBI_MAX_SEQUENCE_LENGTH = (
26
+ int(os.environ.get('NCBI_MAX_SEQUENCE_LENGTH'))
27
+ if os.environ.get('NCBI_MAX_SEQUENCE_LENGTH') is not None
28
+ else 500000
29
+ )
25
30
  PLANNOTATE_URL = os.environ['PLANNOTATE_URL'] if 'PLANNOTATE_URL' in os.environ else None
26
31
  PLANNOTATE_TIMEOUT = int(os.environ['PLANNOTATE_TIMEOUT']) if 'PLANNOTATE_TIMEOUT' in os.environ else 20
27
32
  # Handle trailing slash:
@@ -58,6 +63,7 @@ class Settings(BaseModel):
58
63
  BATCH_CLONING: bool
59
64
  RECORD_STUBS: bool
60
65
  NCBI_API_KEY: str | None
66
+ NCBI_MAX_SEQUENCE_LENGTH: int
61
67
  ALLOWED_ORIGINS: list[str]
62
68
  PLANNOTATE_URL: str | None
63
69
  PLANNOTATE_TIMEOUT: int
@@ -73,6 +79,7 @@ settings = Settings(
73
79
  BATCH_CLONING=BATCH_CLONING,
74
80
  RECORD_STUBS=RECORD_STUBS,
75
81
  NCBI_API_KEY=NCBI_API_KEY,
82
+ NCBI_MAX_SEQUENCE_LENGTH=NCBI_MAX_SEQUENCE_LENGTH,
76
83
  ALLOWED_ORIGINS=ALLOWED_ORIGINS,
77
84
  PLANNOTATE_URL=PLANNOTATE_URL,
78
85
  PLANNOTATE_TIMEOUT=PLANNOTATE_TIMEOUT,
@@ -70,8 +70,8 @@ async def post_batch_cloning(
70
70
  try:
71
71
  pombe_summary(temp_dir)
72
72
  pombe_gather(temp_dir)
73
- except Exception:
74
- raise HTTPException(status_code=400, detail='Summary failed')
73
+ except Exception as e:
74
+ raise HTTPException(status_code=400, detail=f'Summary failed: {e}')
75
75
 
76
76
  # zip the temp dir and return it
77
77
  zip_filename = f'{temp_dir}_archive'
@@ -1,35 +1,34 @@
1
1
  import os
2
- from opencloning.endpoints.external_import import genome_coordinates, get_from_repository_id_addgene, read_from_file
3
- from opencloning.endpoints.assembly import pcr, homologous_recombination
4
- from opencloning.pydantic_models import (
5
- GenomeCoordinatesSource,
6
- TextFileSequence,
7
- AddgeneIdSource,
8
- PCRSource,
9
- PrimerModel,
10
- HomologousRecombinationSource,
11
- BaseCloningStrategy,
12
- UploadedFileSource,
13
- )
14
-
15
- from opencloning.ncbi_requests import get_annotations_from_query
2
+ from pydna.assembly2 import homologous_recombination_integration, pcr_assembly
3
+ from opencloning.dna_functions import request_from_addgene
4
+ from opencloning.ncbi_requests import get_annotations_from_query, get_genome_region_from_annotation
16
5
  import asyncio
17
- import json
18
6
  from Bio import SeqIO
7
+ from pydna.primer import Primer
8
+ from pydna.opencloning_models import CloningStrategy
9
+ from fastapi.datastructures import UploadFile
19
10
  from pydna.parsers import parse as pydna_parse
20
11
 
21
12
 
22
13
  async def main(
23
- gene: str, assembly_accession: str, output_dir: str, plasmid: str | dict = '19343', padding: int = 1000
14
+ gene: str,
15
+ assembly_accession: str,
16
+ output_dir: str,
17
+ plasmid_input: UploadFile | str = '19343',
18
+ padding: int = 1000,
24
19
  ):
25
20
  print(f"\033[92mCloning {gene}\033[0m")
26
21
  # Parse primers =================================================================================
27
- primer_records = list(SeqIO.parse(os.path.join(output_dir, gene, 'primers.fa'), 'fasta'))
28
- checking_primers = list(SeqIO.parse(os.path.join(output_dir, 'checking_primers.fa'), 'fasta'))
29
- primer_records = primer_records[:3] + checking_primers[1:] + primer_records[3:] + checking_primers[:1]
30
- primers = []
31
- for primer in primer_records:
32
- primers.append(PrimerModel(sequence=str(primer.seq), id=0, name=primer.id))
22
+ primers = [Primer(p) for p in SeqIO.parse(os.path.join(output_dir, gene, 'primers.fa'), 'fasta')]
23
+ common_primers = [Primer(p) for p in SeqIO.parse(os.path.join(output_dir, 'checking_primers.fa'), 'fasta')]
24
+
25
+ # Get plasmid sequence =================================================================================
26
+ if isinstance(plasmid_input, UploadFile):
27
+ file_content = (await plasmid_input.read()).decode()
28
+
29
+ plasmid = pydna_parse(file_content)[0]
30
+ else:
31
+ plasmid = await request_from_addgene(plasmid_input)
33
32
 
34
33
  # Get genome region =====================================================================
35
34
  annotations = await get_annotations_from_query(gene, assembly_accession)
@@ -40,104 +39,24 @@ async def main(
40
39
  if len(annotations) != 1:
41
40
  raise ValueError(f'No right annotation found for {gene}')
42
41
 
43
- annotation = annotations[0]
44
-
45
- gene_range = annotation['genomic_regions'][0]['gene_range']['range'][0]
46
- sequence_accession = annotation['genomic_regions'][0]['gene_range']['accession_version']
47
- locus_tag = annotation.get('locus_tag', None)
48
- gene_id = annotation.get('gene_id', None)
49
- start = int(gene_range['begin'])
50
- end = int(gene_range['end'])
51
- orientation = 1 if gene_range['orientation'] == 'plus' else -1
52
-
53
- source = GenomeCoordinatesSource(
54
- id=0,
55
- start=start - padding,
56
- end=end + padding,
57
- strand=orientation,
58
- assembly_accession=assembly_accession,
59
- sequence_accession=sequence_accession,
60
- locus_tag=locus_tag,
61
- gene_id=gene_id,
62
- output_name=gene,
63
- )
64
- locus = await genome_coordinates(source)
65
-
66
- cloning_strategy = BaseCloningStrategy(
67
- sequences=[],
68
- sources=[],
69
- primers=[],
70
- description=f'Cloning strategy for deleting the gene {gene} using PCR and homologous recombination',
71
- )
72
- for primer in primers:
73
- cloning_strategy.add_primer(primer)
74
- locus_seq: TextFileSequence = TextFileSequence.model_validate(locus['sequences'][0])
75
- locus_source: GenomeCoordinatesSource = GenomeCoordinatesSource.model_validate(locus['sources'][0])
76
- cloning_strategy.add_source_and_sequence(locus_source, locus_seq)
77
-
78
- # Get plasmid sequence =================s================================================================
79
- if not isinstance(plasmid, str):
80
- if plasmid.filename.endswith('.fa') or plasmid.filename.endswith('.fasta'):
81
- resp = await read_from_file(plasmid, None, None, True, None, None, None)
82
- else:
83
- resp = await read_from_file(plasmid, None, None, None, None, None, None)
84
- # Verify that plasmid is circular
85
- if not pydna_parse(resp['sequences'][0].file_content)[0].circular:
86
- raise ValueError('Plasmid is not circular')
87
- plasmid_source: UploadedFileSource = UploadedFileSource.model_validate(resp['sources'][0])
88
- else:
89
- addgene_source = AddgeneIdSource(
90
- id=0,
91
- repository_id=plasmid,
92
- repository_name='addgene',
93
- )
94
- resp = await get_from_repository_id_addgene(addgene_source)
95
- plasmid_source: AddgeneIdSource = AddgeneIdSource.model_validate(resp['sources'][0])
96
-
97
- plasmid_seq: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0])
98
- cloning_strategy.add_source_and_sequence(plasmid_source, plasmid_seq)
42
+ locus = await get_genome_region_from_annotation(annotations[0], 1000, 1000)
99
43
 
100
44
  # PCR ================================================================================================
101
- pcr_source = PCRSource(id=0, output_name='amplified_marker')
102
- resp = await pcr(pcr_source, [plasmid_seq], [primers[0], primers[1]], 15, 0)
45
+ pcr_products = pcr_assembly(plasmid, primers[0], primers[1], limit=14, mismatches=0)
46
+ pcr_products[0].name = 'amplified_marker'
47
+ alleles = homologous_recombination_integration(locus, [pcr_products[0]], 40)
48
+ pcr_check1 = pcr_assembly(alleles[0], primers[2], common_primers[1], limit=14, mismatches=0)[0]
49
+ pcr_check1.name = 'check_pcr_left'
50
+ pcr_check2 = pcr_assembly(alleles[0], primers[3], common_primers[0], limit=14, mismatches=0)[0]
51
+ pcr_check2.name = 'check_pcr_right'
103
52
 
104
- pcr_product: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0])
105
- pcr_source: PCRSource = PCRSource.model_validate(resp['sources'][0])
106
- cloning_strategy.add_source_and_sequence(pcr_source, pcr_product)
107
-
108
- # Homologous recombination ========================================================================
109
- hrec_source = HomologousRecombinationSource(id=0, output_name='deletion_allele')
110
- resp = await homologous_recombination(hrec_source, [locus_seq, pcr_product], 50)
111
-
112
- hrec_product: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0])
113
- hrec_source: HomologousRecombinationSource = HomologousRecombinationSource.model_validate(resp['sources'][0])
114
- cloning_strategy.add_source_and_sequence(hrec_source, hrec_product)
115
-
116
- # Checking pcr 1 ======================================================================================
117
- check_pcr_source_left = PCRSource(id=0, output_name='check_pcr_left')
118
- resp = await pcr(check_pcr_source_left, [hrec_product], [primers[2], primers[3]], 15, 0)
119
-
120
- check_pcr_product_left: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0])
121
- check_pcr_source_left: PCRSource = PCRSource.model_validate(resp['sources'][0])
122
- cloning_strategy.add_source_and_sequence(check_pcr_source_left, check_pcr_product_left)
123
-
124
- # Checking pcr 2 ======================================================================================
125
- check_pcr_source_right = PCRSource(id=0, output_name='check_pcr_right')
126
- resp = await pcr(check_pcr_source_right, [hrec_product], [primers[4], primers[5]], 15, 0)
127
-
128
- check_pcr_product_right: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0])
129
- check_pcr_source_right: PCRSource = PCRSource.model_validate(resp['sources'][0])
130
- cloning_strategy.add_source_and_sequence(check_pcr_source_right, check_pcr_product_right)
131
-
132
- cloning_strategy.description = (
133
- f'Cloning strategy for deleting the gene {gene} using PCR and homologous recombination'
134
- )
53
+ cs = CloningStrategy.from_dseqrecords([pcr_check1, pcr_check2])
135
54
 
136
55
  if not os.path.exists(os.path.join(output_dir, gene)):
137
56
  os.makedirs(os.path.join(output_dir, gene))
138
57
 
139
58
  with open(os.path.join(output_dir, gene, 'cloning_strategy.json'), 'w') as f:
140
- json.dump(cloning_strategy.model_dump(), f, indent=2)
59
+ f.write(cs.model_dump_json(indent=2))
141
60
 
142
61
 
143
62
  if __name__ == '__main__':
@@ -1,10 +1,17 @@
1
- from ...pydantic_models import BaseCloningStrategy, PrimerModel, PCRSource, HomologousRecombinationSource
1
+ from pydna.utils import location_boundaries
2
+ from ...pydantic_models import BaseCloningStrategy
3
+ from opencloning_linkml.datamodel import (
4
+ Primer as PrimerModel,
5
+ PCRSource,
6
+ HomologousRecombinationSource,
7
+ )
2
8
  from pydna.parsers import parse as pydna_parse
3
9
  import os
4
10
  import json
5
11
  from pydna import tm
6
12
  from Bio.Seq import reverse_complement
7
13
  import argparse
14
+ from Bio.SeqFeature import Location
8
15
 
9
16
  chromosomes = {
10
17
  'NC_003424.3': 'I',
@@ -17,11 +24,11 @@ chromosomes = {
17
24
  def find_primer_aligned_sequence(pcr_sources: list[PCRSource], primer: PrimerModel) -> str:
18
25
  for source in pcr_sources:
19
26
  if source.input[0].sequence == primer.id:
20
- loc = source.input[0].right_location
21
- return str(primer.sequence[loc.start : loc.end])
27
+ loc = Location.fromstring(source.input[0].right_location)
28
+ return loc.extract(primer.sequence)
22
29
  if source.input[-1].sequence == primer.id:
23
- loc = source.input[-1].left_location
24
- return str(reverse_complement(primer.sequence)[loc.start : loc.end])
30
+ loc = Location.fromstring(source.input[-1].left_location)
31
+ return loc.extract(reverse_complement(primer.sequence))
25
32
  raise ValueError(f"Primer {primer.id} not found in any PCR source")
26
33
 
27
34
 
@@ -33,13 +40,18 @@ def process_folder(working_dir: str):
33
40
  # We do this to have action to .end and .start
34
41
  pcr_sources = [PCRSource.model_validate(s.model_dump()) for s in pcr_sources]
35
42
  locus_source = next(s for s in strategy.sources if s.type == 'GenomeCoordinatesSource')
43
+ locus_location = Location.fromstring(locus_source.coordinates)
36
44
  hrec_source = next(s for s in strategy.sources if s.type == 'HomologousRecombinationSource')
37
45
  # We do this to have action to .end and .start
38
46
  hrec_source: HomologousRecombinationSource = HomologousRecombinationSource.model_validate(hrec_source.model_dump())
39
47
 
40
- chromosome = chromosomes[locus_source.sequence_accession]
41
- insertion_start = locus_source.start + hrec_source.input[0].right_location.end
42
- insertion_end = locus_source.start + hrec_source.input[-1].left_location.start
48
+ chromosome = chromosomes[locus_source.repository_id]
49
+ insertion_start = (
50
+ locus_location.start + location_boundaries(Location.fromstring(hrec_source.input[0].right_location))[1]
51
+ )
52
+ insertion_end = (
53
+ locus_location.start + location_boundaries(Location.fromstring(hrec_source.input[-1].left_location))[0]
54
+ )
43
55
 
44
56
  # Write out the sequences in genbank format and extract some relevant info
45
57
  sequences = [pydna_parse(sequence.file_content)[0] for sequence in strategy.sequences]
@@ -6,10 +6,10 @@ from typing import Annotated
6
6
  from fastapi import Body, Query, HTTPException
7
7
 
8
8
  from ...get_router import get_router
9
- from ...pydantic_models import (
10
- BaseCloningStrategy,
11
- PrimerModel,
9
+ from ...pydantic_models import BaseCloningStrategy
10
+ from opencloning_linkml.datamodel import (
12
11
  TextFileSequence,
12
+ Primer as PrimerModel,
13
13
  PCRSource,
14
14
  RestrictionAndLigationSource,
15
15
  GatewaySource,
@@ -96,7 +96,7 @@ async def ziqiang_et_al2024_post(
96
96
  else:
97
97
  name = f'end_ps{i}_start_ps{i + 1}'
98
98
 
99
- pcr_source = PCRSource(id=0, output_name=name)
99
+ pcr_source = PCRSource(id=0, input=[], output_name=name)
100
100
  fwd_primer = next(p for p in cloning_strategy.primers if p.id == fwd_primer_id)
101
101
  rvs_primer = next(p for p in cloning_strategy.primers if p.id == rvs_primer_id)
102
102
 
@@ -112,18 +112,18 @@ async def ziqiang_et_al2024_post(
112
112
 
113
113
  # Make all input of a Golden gate assembly
114
114
  golden_gate_source = RestrictionAndLigationSource(
115
- id=0, output_name='golden_gate_assembly', restriction_enzymes=['BsaI']
115
+ id=0, input=[], output_name='golden_gate_assembly', restriction_enzymes=['BsaI']
116
116
  )
117
117
 
118
118
  # Make them
119
119
  input_sequences = [next(s for s in cloning_strategy.sequences if s.id == p) for p in pcr_product_ids]
120
- resp = await restriction_and_ligation(golden_gate_source, input_sequences, False, False)
120
+ resp = await restriction_and_ligation(golden_gate_source, input_sequences, False)
121
121
  golden_gate_product: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0])
122
122
  golden_gate_source: RestrictionAndLigationSource = RestrictionAndLigationSource.model_validate(resp['sources'][0])
123
123
  cloning_strategy.add_source_and_sequence(golden_gate_source, golden_gate_product)
124
124
 
125
125
  bp_target = next(s for s in cloning_strategy.sequences if s.id == 6)
126
- gateway_source = GatewaySource(id=0, output_name='entry_clone', reaction_type='BP', greedy=False)
126
+ gateway_source = GatewaySource(id=0, input=[], output_name='entry_clone', reaction_type='BP', greedy=False)
127
127
  resp = await gateway(gateway_source, [golden_gate_product, bp_target], circular_only=True, only_multi_site=True)
128
128
  gateway_product: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0])
129
129
  gateway_source: GatewaySource = GatewaySource.model_validate(resp['sources'][0])
@@ -141,7 +141,7 @@ async def ziqiang_et_al2024_post(
141
141
  all_input_ids = [s.sequence for s in all_inputs]
142
142
  sequences_to_clone = [s for s in cloning_strategy.sequences if s.id not in all_input_ids]
143
143
 
144
- gateway_source = GatewaySource(id=0, output_name='expression_clone', reaction_type='LR', greedy=False)
144
+ gateway_source = GatewaySource(id=0, input=[], output_name='expression_clone', reaction_type='LR', greedy=False)
145
145
  resp = await gateway(gateway_source, sequences_to_clone, circular_only=True, only_multi_site=True)
146
146
  index_of_product = next(i for i, s in enumerate(resp['sequences']) if '/label="Cas9"' in s.file_content)
147
147
  expression_clone: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][index_of_product])
@@ -81,7 +81,6 @@
81
81
  "database_id": null,
82
82
  "input": [],
83
83
  "repository_id": "71287",
84
- "repository_name": "addgene",
85
84
  "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/352460/6c8b0369-e549-4517-95da-8d07146ca49d/addgene-plasmid-71287-sequence-352460.gbk",
86
85
  "addgene_sequence_type": "addgene-full"
87
86
  },
@@ -92,7 +91,6 @@
92
91
  "database_id": null,
93
92
  "input": [],
94
93
  "repository_id": "71287",
95
- "repository_name": "addgene",
96
94
  "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/352460/6c8b0369-e549-4517-95da-8d07146ca49d/addgene-plasmid-71287-sequence-352460.gbk",
97
95
  "addgene_sequence_type": "addgene-full"
98
96
  },
@@ -103,7 +101,6 @@
103
101
  "database_id": null,
104
102
  "input": [],
105
103
  "repository_id": "213912",
106
- "repository_name": "addgene",
107
104
  "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/437264/8bd82b44-a1c3-4f81-8936-ebcc16d171e9/addgene-plasmid-213912-sequence-437264.gbk",
108
105
  "addgene_sequence_type": "addgene-full"
109
106
  },
@@ -114,7 +111,6 @@
114
111
  "database_id": null,
115
112
  "input": [],
116
113
  "repository_id": "213913",
117
- "repository_name": "addgene",
118
114
  "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/437263/af62d64e-1f22-4dce-aafa-7935d1665700/addgene-plasmid-213913-sequence-437263.gbk",
119
115
  "addgene_sequence_type": "addgene-full"
120
116
  },
@@ -125,7 +121,6 @@
125
121
  "database_id": null,
126
122
  "input": [],
127
123
  "repository_id": "133748",
128
- "repository_name": "addgene",
129
124
  "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/271264/c0ae5f43-46e6-4175-a0c1-9a00cbb92034/addgene-plasmid-133748-sequence-271264.gbk",
130
125
  "addgene_sequence_type": "addgene-full"
131
126
  },
@@ -135,8 +130,7 @@
135
130
  "output_name": "pDONR_P2r-P3",
136
131
  "database_id": null,
137
132
  "input": [],
138
- "repository_id": "gateway_cloning_vectors/pDONR_P2r-P3",
139
- "repository_name": "snapgene"
133
+ "repository_id": "gateway_cloning_vectors/pDONR_P2r-P3"
140
134
  },
141
135
  {
142
136
  "id": 7,
@@ -207,7 +201,6 @@
207
201
  "database_id": null,
208
202
  "input": [],
209
203
  "repository_id": "63143",
210
- "repository_name": "addgene",
211
204
  "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/223326/8c81fe9a-fb57-40bc-93d6-e17d83502061/addgene-plasmid-63143-sequence-223326.gbk",
212
205
  "addgene_sequence_type": "addgene-full"
213
206
  }
@@ -258,7 +251,7 @@
258
251
  ],
259
252
  "description": "",
260
253
  "files": null,
261
- "schema_version": "0.4.3",
254
+ "schema_version": "0.4.9",
262
255
  "backend_version": null,
263
256
  "frontend_version": null
264
257
  }
@@ -4,10 +4,12 @@ See info in README.md
4
4
 
5
5
  from ..pydantic_models import (
6
6
  BaseCloningStrategy as CloningStrategy,
7
+ )
8
+ from pydna.opencloning_models import SequenceLocationStr
9
+ from opencloning_linkml.datamodel import (
7
10
  AssemblySource,
8
11
  TextFileSequence,
9
- PrimerModel,
10
- SequenceLocationStr,
12
+ Primer as PrimerModel,
11
13
  )
12
14
  from .._version import __version__
13
15
  import json
@@ -50,9 +52,15 @@ def fix_backend_v0_3(input_data: dict) -> CloningStrategy | None:
50
52
  primers = [PrimerModel.model_validate(p) for p in data['primers'] if p['id'] in primer_ids]
51
53
  input_seqs = [primers[0], input_seqs[0], primers[1]]
52
54
 
53
- assembly_plan = assembly_source.get_assembly_plan(input_seqs)
54
- for join in assembly_plan:
55
- if len(join[2]) != len(join[3]):
55
+ assembly_fragments = [a for a in assembly_source.input if a.type == 'AssemblyFragment']
56
+
57
+ for prev_f, next_f in zip(assembly_fragments, assembly_fragments[1:] + assembly_fragments[:1]):
58
+ left = prev_f.right_location
59
+ right = next_f.left_location
60
+ if (left is not None and right is not None) and (
61
+ len(SequenceLocationStr(left).to_biopython_location())
62
+ != len(SequenceLocationStr(right).to_biopython_location())
63
+ ):
56
64
  problematic_source_ids.add(source['id'])
57
65
  break
58
66
 
@@ -0,0 +1,36 @@
1
+ import os
2
+ import yaml
3
+
4
+
5
+ def get_seva_catalog():
6
+ seva_catalog_path = os.path.join(os.path.dirname(__file__), 'seva.tsv')
7
+ seva_catalog = dict()
8
+ with open(seva_catalog_path, 'r') as f:
9
+ for line in f:
10
+ name, genbank_link = line.strip().split('\t')
11
+ seva_catalog[name] = genbank_link
12
+ return seva_catalog
13
+
14
+
15
+ def get_snapgene_catalog():
16
+ snapgene_catalog_path = os.path.join(os.path.dirname(__file__), 'snapgene.yaml')
17
+ with open(snapgene_catalog_path, 'r') as f:
18
+ return yaml.safe_load(f)
19
+
20
+
21
+ def get_openDNA_collections_catalog():
22
+ catalog_path = os.path.join(os.path.dirname(__file__), 'openDNA_collections.yaml')
23
+ with open(catalog_path, 'r') as f:
24
+ return yaml.safe_load(f)
25
+
26
+
27
+ def get_iGEM2024_catalog():
28
+ catalog_path = os.path.join(os.path.dirname(__file__), 'igem2024.yaml')
29
+ with open(catalog_path, 'r') as f:
30
+ return yaml.safe_load(f)
31
+
32
+
33
+ seva_catalog = get_seva_catalog()
34
+ snapgene_catalog = get_snapgene_catalog()
35
+ openDNA_collections_catalog = get_openDNA_collections_catalog()
36
+ iGEM2024_catalog = get_iGEM2024_catalog()