Skip to content

Commit 65d19a7

Browse files
authored
Add Open DNA Collections (#358)
* add Open DNA Collections, closes #357 * fix model version in test file
1 parent a337d2b commit 65d19a7

File tree

8 files changed

+64
-8
lines changed

8 files changed

+64
-8
lines changed

poetry.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pydantic = "^2.7.1"
2626
pandas = "^2.2.3"
2727
openpyxl = "^3.1.5"
2828
pyyaml = "^6.0.2"
29-
opencloning-linkml = "0.4.3"
29+
opencloning-linkml = "0.4.4"
3030
primer3-py = "2.2.0"
3131
biopython = "^1.85"
3232
packaging = "^25.0"

src/opencloning/app_settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def parse_bool(value: str) -> bool:
4444
'http://www.euroscarf.de/',
4545
'https://wekwikgene.wllsb.edu.cn',
4646
'http://bahlerweb.cs.ucl.ac.uk',
47+
'https://assets.opencloning.org/open-dna-collections',
4748
]
4849

4950
if os.environ.get('ALLOWED_EXTERNAL_URLS') is not None:

src/opencloning/endpoints/external_import.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
SequenceFileFormat,
2525
SEVASource,
2626
SequenceLocationStr,
27+
OpenDNACollectionsSource,
2728
)
2829
from ..dna_functions import (
2930
format_sequence_genbank,
@@ -234,7 +235,8 @@ def repository_id_http_error_handler(exception: HTTPError, source: RepositoryIdS
234235
| list[BenchlingUrlSource]
235236
| list[EuroscarfSource]
236237
| list[WekWikGeneIdSource]
237-
| list[SEVASource],
238+
| list[SEVASource]
239+
| list[OpenDNACollectionsSource],
238240
...,
239241
),
240242
sequences=(list[TextFileSequence], ...),
@@ -249,6 +251,7 @@ async def get_from_repository_id(
249251
| EuroscarfSource
250252
| WekWikGeneIdSource
251253
| SEVASource
254+
| OpenDNACollectionsSource
252255
),
253256
):
254257
return RedirectResponse(f'/repository_id/{source.repository_name}', status_code=307)
@@ -384,6 +387,22 @@ async def get_from_repository_id_igem(source: IGEMSource):
384387
repository_id_http_error_handler(exception, source)
385388

386389

390+
@router.post(
391+
'/repository_id/open_dna_collections',
392+
response_model=create_model(
393+
'OpenDNACollectionsResponse',
394+
sources=(list[OpenDNACollectionsSource], ...),
395+
sequences=(list[TextFileSequence], ...),
396+
),
397+
)
398+
async def get_from_repository_id_open_dna_collections(source: OpenDNACollectionsSource):
399+
try:
400+
dseq = (await get_sequences_from_file_url(source.sequence_file_url))[0]
401+
return {'sequences': [format_sequence_genbank(dseq, source.output_name)], 'sources': [source]}
402+
except HTTPError as exception:
403+
repository_id_http_error_handler(exception, source)
404+
405+
387406
@router.post(
388407
'/genome_coordinates',
389408
response_model=create_model(

src/opencloning/http_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class AllowedExternalUrlsTransport(AsyncHTTPTransport):
2222
async def handle_async_request(self, request: Request) -> Response:
2323
if any(str(request.url).startswith(url) for url in allowed_external_urls):
2424
return await super().handle_async_request(request)
25-
25+
print('>>>', request.url)
2626
raise HTTPError(request.url, 403, f'Request to {request.url} is not allowed', None, None)
2727

2828

src/opencloning/pydantic_models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
CreLoxRecombinationSource as _CreLoxRecombinationSource,
5151
InVivoAssemblySource as _InVivoAssemblySource,
5252
SourceInput as _SourceInput,
53+
OpenDNACollectionsSource as _OpenDNACollectionsSource,
5354
)
5455
from pydna.assembly2 import (
5556
edge_representation2subfragment_representation,
@@ -183,6 +184,10 @@ def validate_repository_id(self):
183184
return self
184185

185186

187+
class OpenDNACollectionsSource(SourceCommonClass, _OpenDNACollectionsSource):
188+
pass
189+
190+
186191
class SEVASource(SourceCommonClass, _SEVASource):
187192
pass
188193

tests/test_endpoints_external_import.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
IGEMSource,
2424
WekWikGeneIdSource,
2525
SEVASource,
26+
OpenDNACollectionsSource,
2627
)
2728
from opencloning import app_settings, http_client
2829

@@ -1044,6 +1045,36 @@ def test_circularize(self):
10441045
self.assertEqual(seq.circular, True)
10451046

10461047

1048+
class OpenDNACollectionsSourceTest(unittest.TestCase):
1049+
def test_valid_url(self):
1050+
source = OpenDNACollectionsSource(
1051+
id=0,
1052+
repository_id='Ecoli Nanobody Toolkit/BC_RJ_SD8',
1053+
repository_name='open_dna_collections',
1054+
sequence_file_url='https://assets.opencloning.org/open-dna-collections/Ecoli%20Nanobody%20Toolkit/genbank_seq/BC_RJ_SD8.gb',
1055+
)
1056+
response = client.post('/repository_id/open_dna_collections', json=source.model_dump())
1057+
self.assertEqual(response.status_code, 200)
1058+
payload = response.json()
1059+
self.assertEqual(len(payload['sequences']), 1)
1060+
self.assertEqual(len(payload['sources']), 1)
1061+
out_source = payload['sources'][0]
1062+
self.assertEqual(out_source, source.model_dump())
1063+
seq = read_dsrecord_from_json(TextFileSequence.model_validate(payload['sequences'][0]))
1064+
self.assertEqual(seq.name, 'BC_RJ_SD8')
1065+
1066+
def test_errors(self):
1067+
1068+
source = OpenDNACollectionsSource(
1069+
id=0,
1070+
repository_id='Ecoli Nanobody Toolkit/BC_RJ_SD8',
1071+
repository_name='open_dna_collections',
1072+
sequence_file_url='https://assets.opencloning.org/open-dna-collections/Ecoli%20Nanobody%20Toolkit/genbank_seq/hello.txt',
1073+
)
1074+
response = client.post('/repository_id/open_dna_collections', json=source.model_dump())
1075+
self.assertEqual(response.status_code, 404)
1076+
1077+
10471078
class NotAllowedExternalUrlTest(unittest.TestCase):
10481079
def tearDown(self):
10491080
pytest.MonkeyPatch().delenv('ALLOWED_EXTERNAL_URLS', raising=False)

tests/test_files/homologous_recombination.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@
139139
],
140140
"description": "Deletion of the ORF of ase1 by homologous recombination in S.pombe",
141141
"files": null,
142-
"schema_version": "0.4.3",
142+
"schema_version": "0.4.4",
143143
"backend_version": null,
144144
"frontend_version": null
145145
}

0 commit comments

Comments
 (0)