From 14034e0d32ffcd2b0ad802eb16204789b308dd6c Mon Sep 17 00:00:00 2001 From: Manuel Lera-Ramirez Date: Thu, 11 Jun 2026 09:44:04 +0100 Subject: [PATCH 01/21] version working for deletion --- .../batch_cloning/pombe/__init__.py | 78 ++++++----- .../batch_cloning/pombe/index.html | 61 +++++---- .../batch_cloning/pombe/pombe_clone.py | 123 +++++++----------- .../batch_cloning/pombe/pombe_get_primers.py | 114 ---------------- .../src/opencloning/primer_design.py | 78 ++++++----- pombe_all.sh | 9 -- uv.lock | 6 +- 7 files changed, 171 insertions(+), 298 deletions(-) delete mode 100644 packages/opencloning/src/opencloning/batch_cloning/pombe/pombe_get_primers.py delete mode 100644 pombe_all.sh diff --git a/packages/opencloning/src/opencloning/batch_cloning/pombe/__init__.py b/packages/opencloning/src/opencloning/batch_cloning/pombe/__init__.py index f1779344..75087440 100644 --- a/packages/opencloning/src/opencloning/batch_cloning/pombe/__init__.py +++ b/packages/opencloning/src/opencloning/batch_cloning/pombe/__init__.py @@ -1,16 +1,19 @@ from fastapi import Form, File, UploadFile, HTTPException from typing import Annotated, Literal -from tempfile import TemporaryDirectory import os +import tempfile from fastapi.responses import FileResponse -from .pombe_get_primers import main as pombe_primers from .pombe_clone import main as pombe_clone from .pombe_summary import main as pombe_summary from .pombe_gather import main as pombe_gather import shutil -import traceback from ...get_router import get_router from fastapi import Request +from opencloning.dna_functions import request_from_addgene, request_from_snapgene +from pydna.primer import Primer +from pydna.opencloning_models import UploadedFileSource +from pydna.parsers import parse as pydna_parse +from pydna.parsers import parse_snapgene router = get_router() @@ -20,53 +23,60 @@ async def get_batch_cloning_page(request: Request): return FileResponse(os.path.join(os.path.dirname(__file__), 'index.html')) +ASSEMBLY_ACCESSION = 'GCF_000002945.2' + + @router.post('/batch_cloning/pombe') async def post_batch_cloning( gene_list: str = Form(...), plasmid_file: UploadFile | None = File(None), addgene_id: str | None = Form(None), - plasmid_option: Annotated[Literal['addgene', 'file'], Form(...)] = None, + plasmid_option: Annotated[Literal['addgene', 'file', 'default'], Form(...)] = None, checking_primer_forward: str = Form(..., pattern=r'^[ACGTacgt]+$', min_length=1), checking_primer_reverse: str = Form(..., pattern=r'^[ACGTacgt]+$', min_length=1), + resistance_marker: Annotated[Literal['kanmx6', 'natmx6', 'hphmx6', 'other'], Form(...)] = None, ): - - plasmid = plasmid_file if plasmid_option == 'file' else addgene_id - if plasmid is None: - raise HTTPException(status_code=400, detail='No plasmid provided') - genes = [gene.strip() for gene in gene_list.split() if gene.strip()] if not genes: raise HTTPException(status_code=400, detail='No valid genes provided') - with TemporaryDirectory() as temp_dir: - if plasmid_option == 'file': - # Write the plasmid to the temp dir - with open(os.path.join(temp_dir, plasmid_file.filename), 'wb') as f: - shutil.copyfileobj(plasmid_file.file, f) + common_primers = [ + Primer(checking_primer_forward, name='common_insert_fwd'), + Primer(checking_primer_reverse, name='common_insert_rvs'), + ] + + if plasmid_option == 'default': + if resistance_marker == 'kanmx6': + addgene_id = '39296' + elif resistance_marker == 'natmx6': + plasmid = await request_from_snapgene('yeast_plasmids', 'pFA6a-natMX6') + elif resistance_marker == 'hphmx6': + plasmid = await request_from_snapgene('yeast_plasmids', 'pFA6a-hphMX6') + else: + raise HTTPException(status_code=400, detail='resistance_marker other is not supported for default plasmid') - # Write the checking primers - with open(os.path.join(temp_dir, 'checking_primers.fa'), 'w') as f: - f.write(f'>common_insert_fwd\n{checking_primer_forward}\n>common_insert_rvs\n{checking_primer_reverse}') + elif plasmid_option == 'file': + assert plasmid_file is not None + assert plasmid_file.filename is not None + file_content = await plasmid_file.read() + if plasmid_file.filename.endswith('.dna'): + plasmid = parse_snapgene(file_content)[0] + else: + plasmid = pydna_parse(file_content)[0] + plasmid.source = UploadedFileSource( + file_name=plasmid_file.filename, + sequence_file_format=plasmid.annotations['pydna_parse_sequence_file_format'], + index_in_file=0, + ) + if plasmid_option == 'addgene': + assert addgene_id is not None + plasmid = await request_from_addgene(addgene_id) + with tempfile.TemporaryDirectory() as temp_dir: for gene in genes: - try: - await pombe_primers(gene, temp_dir) - except Exception: - raise HTTPException(status_code=404, detail=f'Primers for {gene} not found') - try: - if plasmid_option == 'file': - with open(os.path.join(temp_dir, plasmid_file.filename), 'rb') as f: - await pombe_clone( - gene, 'GCF_000002945.2', temp_dir, UploadFile(file=f, filename=plasmid_file.filename) - ) - else: - await pombe_clone(gene, 'GCF_000002945.2', temp_dir, addgene_id) - except Exception: - # Show the stack trace in console - print(f'Error occurred while cloning {gene}:') - traceback.print_exc() - raise HTTPException(status_code=400, detail=f'Clone for {gene} failed') + await pombe_clone(gene, ASSEMBLY_ACCESSION, temp_dir, plasmid, common_primers) + try: pombe_summary(temp_dir) pombe_gather(temp_dir) diff --git a/packages/opencloning/src/opencloning/batch_cloning/pombe/index.html b/packages/opencloning/src/opencloning/batch_cloning/pombe/index.html index a3373e9d..73587de4 100644 --- a/packages/opencloning/src/opencloning/batch_cloning/pombe/index.html +++ b/packages/opencloning/src/opencloning/batch_cloning/pombe/index.html @@ -103,15 +103,16 @@

Best way to get started

gene locus via homologous recombination.

- + +
+ -
-
- - +