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.
- opencloning/app_settings.py +7 -0
- opencloning/batch_cloning/pombe/__init__.py +2 -2
- opencloning/batch_cloning/pombe/pombe_clone.py +31 -112
- opencloning/batch_cloning/pombe/pombe_summary.py +20 -8
- opencloning/batch_cloning/ziqiang_et_al2024/__init__.py +8 -8
- opencloning/batch_cloning/ziqiang_et_al2024/ziqiang_et_al2024.json +2 -9
- opencloning/bug_fixing/backend_v0_3.py +13 -5
- opencloning/catalogs/__init__.py +36 -0
- opencloning/catalogs/igem2024.yaml +2172 -0
- opencloning/catalogs/openDNA_collections.yaml +1161 -0
- opencloning/catalogs/readme.txt +1 -0
- opencloning/catalogs/seva.tsv +231 -0
- opencloning/catalogs/snapgene.yaml +2837 -0
- opencloning/dna_functions.py +155 -158
- opencloning/dna_utils.py +45 -62
- opencloning/ebic/primer_design.py +1 -1
- opencloning/endpoints/annotation.py +9 -13
- opencloning/endpoints/assembly.py +157 -378
- opencloning/endpoints/endpoint_utils.py +52 -0
- opencloning/endpoints/external_import.py +169 -124
- opencloning/endpoints/no_assembly.py +23 -39
- opencloning/endpoints/no_input.py +32 -47
- opencloning/endpoints/other.py +1 -1
- opencloning/endpoints/primer_design.py +2 -1
- opencloning/http_client.py +2 -2
- opencloning/ncbi_requests.py +113 -47
- opencloning/primer_design.py +1 -1
- opencloning/pydantic_models.py +10 -510
- opencloning/request_examples.py +10 -22
- opencloning/temp_functions.py +50 -0
- {opencloning-0.4.8.dist-info → opencloning-0.5.0.1.dist-info}/METADATA +18 -8
- opencloning-0.5.0.1.dist-info/RECORD +51 -0
- {opencloning-0.4.8.dist-info → opencloning-0.5.0.1.dist-info}/WHEEL +1 -1
- opencloning/cre_lox.py +0 -116
- opencloning/gateway.py +0 -154
- opencloning-0.4.8.dist-info/RECORD +0 -45
- {opencloning-0.4.8.dist-info → opencloning-0.5.0.1.dist-info}/licenses/LICENSE +0 -0
opencloning/app_settings.py
CHANGED
|
@@ -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
|
|
3
|
-
from opencloning.
|
|
4
|
-
from opencloning.
|
|
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,
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
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
|
-
|
|
102
|
-
|
|
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
|
-
|
|
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
|
-
|
|
59
|
+
f.write(cs.model_dump_json(indent=2))
|
|
141
60
|
|
|
142
61
|
|
|
143
62
|
if __name__ == '__main__':
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
from
|
|
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
|
|
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
|
|
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.
|
|
41
|
-
insertion_start =
|
|
42
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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()
|