diff --git a/src/InSillyCloWeb/assemblies/admin.py b/src/InSillyCloWeb/assemblies/admin.py index 0594370ee63ef80c7edeb1e74e3253117cb86e91..ca777ec808a8c5c02294d5f036f2f9eaca365304 100644 --- a/src/InSillyCloWeb/assemblies/admin.py +++ b/src/InSillyCloWeb/assemblies/admin.py @@ -37,6 +37,7 @@ class InputPartAdmin(ViewOnSiteModelAdmin, admin.ModelAdmin): 'is_in_output_plasmid_name', ) + @admin.register(models.SimulatorJob) class SimulatorJobAdmin(ViewOnSiteModelAdmin, admin.ModelAdmin): date_hierarchy = 'created_at' @@ -54,4 +55,3 @@ class UserAdmin(auth_admin.UserAdmin): 'is_staff', 'is_superuser', ) - diff --git a/src/InSillyCloWeb/assemblies/models.py b/src/InSillyCloWeb/assemblies/models.py index f319b3df26c701d6d0b4cd587dd0f8619c95a522..3e5c22a7c3edfc985400cbac100bc52b150261e8 100644 --- a/src/InSillyCloWeb/assemblies/models.py +++ b/src/InSillyCloWeb/assemblies/models.py @@ -17,11 +17,14 @@ from django.db.models.functions import Upper from django.urls import reverse from django.utils.translation import gettext_lazy as _ from django.conf import settings +from .insillyclo_impl import InSillyCloDjangoMessageObserver import insillyclo.data_source import insillyclo.models import insillyclo.template_generator +import insillyclo +import insillyclo.simulator class UserManager(auth_models.UserManager): @@ -269,11 +272,11 @@ class SimulatorJob(models.Model): updated_at = models.DateTimeField(auto_now=True) def save(self, *args, **kwargs): - if not self.uuid: - super().save(*args, **kwargs) - if not os.path.isdir(self.job_dir): os.mkdir(self.job_dir) + os.mkdir(self.results_dir) + + super().save(*args, **kwargs) def add_design_to_dir(self, design_file): file_name = os.path.join(self.job_dir, 'design_file.xlsx') @@ -288,7 +291,7 @@ class SimulatorJob(models.Model): with zipfile.ZipFile(gb_file, 'r') as zip: for member in zip.namelist(): - if Path(member).suffix == '.gb': + if Path(member).suffix == '.gb' and not Path(member).stem.startswith('.'): source = zip.open(member) new_filename = os.path.join(self.genbank_dir, Path(member).stem + '.gb') with open(new_filename, 'wb') as dest: @@ -300,10 +303,33 @@ class SimulatorJob(models.Model): with zipfile.ZipFile(db_ip_file, 'r') as zip: for member in zip.namelist(): - source = zip.open(member) - new_filename = os.path.join(self.dbip_dir, Path(member).stem + Path(member).suffix) - with open(new_filename, 'wb') as dest: - shutil.copyfileobj(source, dest) + if not Path(member).stem.startswith('.'): + source = zip.open(member) + new_filename = os.path.join(self.dbip_dir, Path(member).stem + Path(member).suffix) + with open(new_filename, 'wb') as dest: + shutil.copyfileobj(source, dest) + + def run_insillyclo(self, request): + return insillyclo.simulator.compute_all( + observer=InSillyCloDjangoMessageObserver( + request=request, + debug=False, + fail_on_error=False, + ), + input_template_filled=os.path.join(self.job_dir, 'design_file.xlsx'), + input_parts_files=self.db_ip_files, + gb_plasmids=self.genbank_files, + output_dir=Path(self.results_dir), + data_source=insillyclo.data_source.DataSourceHardCodedImplementation(), + ) + + @property + def db_ip_files(self): + return [os.path.join(self.dbip_dir, file) for file in os.listdir(self.dbip_dir)] + + @property + def genbank_files(self): + return [Path(os.path.join(self.genbank_dir, file)) for file in os.listdir(self.genbank_dir)] @property def job_dir(self): @@ -317,5 +343,9 @@ class SimulatorJob(models.Model): def dbip_dir(self): return os.path.join(self.job_dir, 'db_ip') + @property + def results_dir(self): + return os.path.join(self.job_dir, 'results') + def __str__(self): return f'{str(self.uuid)[:8]} - {str(self.created_at)}' diff --git a/src/InSillyCloWeb/assemblies/urls.py b/src/InSillyCloWeb/assemblies/urls.py index dacaaedf7f4b4b1064d16c9456b42d0a4dc3d170..47aea977137b4bf766d72b55605941e5919e4c2d 100644 --- a/src/InSillyCloWeb/assemblies/urls.py +++ b/src/InSillyCloWeb/assemblies/urls.py @@ -67,6 +67,7 @@ urlpatterns = [ path('assembly/<int:pk>/', views.AssemblyDetailView.as_view(), name='assembly-detail'), path('assembly-simulator/create/<str:step>/', simulator_wizard, name='simulator-create-step'), path('assembly-simulator/create/', simulator_wizard, name='simulator-create'), + path('assembly-simulator/<uuid:uuid>/results/', views.simulator_results, name='simulator-results'), path('assembly/<int:pk>/download/', views.AssemblyDetailDownloadView.as_view(), name='assembly-download'), path('assembly/<int:pk>/delete/', views.AssemblyDeleteView.as_view(), name='assembly-delete'), path('fragment', views.show_fragment, name='fragment'), diff --git a/src/InSillyCloWeb/assemblies/views.py b/src/InSillyCloWeb/assemblies/views.py index ce4c963440fc218d098ffebab0471638b31a8523..56fa3b3f0d3dc6e1fa72cce0fcc7bde68b689378 100644 --- a/src/InSillyCloWeb/assemblies/views.py +++ b/src/InSillyCloWeb/assemblies/views.py @@ -4,7 +4,7 @@ from typing import Tuple from django.contrib import messages from django.http import HttpResponse -from django.shortcuts import render, redirect +from django.shortcuts import render, redirect, get_object_or_404 from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from django.views.generic import ListView, DetailView, View, DeleteView @@ -108,3 +108,20 @@ class AssemblyDeleteView( def form_valid(self, form): messages.info(self.request, _(f"Assembly {self.object} deleted")) return super().form_valid(form) + + +def simulator_results(request, uuid): + """ + This view is used to display the results of the assembly simulation. + """ + simulation = get_object_or_404(models.SimulatorJob, uuid=uuid) + + simulation.run_insillyclo(request) + + return render( + request, + template_name='assemblies/simulator_results.html', + context=dict( + simulation=simulation, + ), + ) diff --git a/src/InSillyCloWeb/assemblies/wizard_views.py b/src/InSillyCloWeb/assemblies/wizard_views.py index f0c7d1b3681667495d57e4500dc08cc79ef9e6e7..88ef0daa38d5af1a36851c331c221726ec28ae34 100644 --- a/src/InSillyCloWeb/assemblies/wizard_views.py +++ b/src/InSillyCloWeb/assemblies/wizard_views.py @@ -20,8 +20,8 @@ import os from assemblies import forms, models, mixins from .models import SimulatorJob -from .insillyclo_impl import InSillyCloDjangoMessageObserver from .utils import get_files +from .insillyclo_impl import InSillyCloDjangoMessageObserver class AssemblySimulatorNotProtected(wizard_views.NamedUrlSessionWizardView): @@ -103,38 +103,17 @@ class AssemblySimulatorNotProtected(wizard_views.NamedUrlSessionWizardView): sjob = SimulatorJob.objects.create() sjob.save() - print(sjob.uuid) - - sjob.add_design_to_dir(self.get_cleaned_data_for_step("InputFile")["input_file"]) - - sjob.add_gb_to_dir(self.get_cleaned_data_for_step("Data")["sequence_file"]) - - sjob.add_db_ip_to_dir(self.get_cleaned_data_for_step("Data")["db_ip_files"]) - - """ - results = insillyclo.simulator.compute_all( - observer = InSillyCloDjangoMessageObserver( - request=self.request, - debug=False, - fail_on_error=False, - ), - input_template_filled = input_template, - input_parts_files = db_ip_files, - gb_plasmids = gb_files, - output_dir = pathlib.Path(output_directory), - data_source = insillyclo.data_source.DataSourceHardCodedImplementation(), + sjob.add_design_to_dir( + self.get_cleaned_data_for_step("InputFile")["input_file"], ) - - print(results) - """ - - return render( - self.request, - 'simple_message_page.html', - context=dict( - sub_message="test results", - ), + sjob.add_gb_to_dir( + self.get_cleaned_data_for_step("Data")["sequence_file"], ) + sjob.add_db_ip_to_dir( + self.get_cleaned_data_for_step("Data")["db_ip_files"], + ) + + return redirect('assemblies:simulator-results', uuid=sjob.uuid) class AssemblyDesignerNotProtected(wizard_views.NamedUrlSessionWizardView):