cg 76.0.0__py3-none-any.whl → 83.14.0__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.
- cg/__init__.py +1 -1
- cg/apps/housekeeper/hk.py +18 -1
- cg/apps/tb/api.py +42 -5
- cg/cli/transfer.py +13 -2
- cg/cli/upload/mutacc.py +16 -3
- cg/cli/upload/scout.py +2 -2
- cg/cli/upload/utils.py +10 -1
- cg/cli/workflow/balsamic/base.py +86 -172
- cg/cli/workflow/balsamic/options.py +3 -48
- cg/cli/workflow/balsamic/umi.py +210 -15
- cg/cli/workflow/microsalt/base.py +4 -2
- cg/cli/workflow/mip_dna/base.py +1 -1
- cg/cli/workflow/nallo/base.py +73 -23
- cg/cli/workflow/nf_analysis.py +5 -207
- cg/cli/workflow/raredisease/base.py +41 -54
- cg/cli/workflow/rnafusion/base.py +38 -8
- cg/cli/workflow/taxprofiler/base.py +31 -18
- cg/cli/workflow/tomte/base.py +83 -10
- cg/constants/constants.py +25 -30
- cg/constants/devices.py +6 -1
- cg/constants/gene_panel.py +3 -1
- cg/constants/housekeeper_tags.py +28 -28
- cg/constants/lims.py +4 -0
- cg/constants/nf_analysis.py +0 -1
- cg/constants/observations.py +21 -5
- cg/constants/orderforms.py +3 -3
- cg/constants/pacbio.py +1 -0
- cg/constants/priority.py +1 -1
- cg/constants/report.py +1 -0
- cg/constants/scout.py +12 -9
- cg/constants/sequencing.py +2 -2
- cg/constants/tb.py +5 -5
- cg/exc.py +27 -5
- cg/meta/compress/compress.py +7 -2
- cg/meta/delivery_report/balsamic.py +3 -1
- cg/meta/delivery_report/delivery_report_api.py +4 -3
- cg/meta/delivery_report/nallo.py +11 -11
- cg/meta/delivery_report/raredisease.py +7 -3
- cg/meta/delivery_report/templates/macros/data_analysis/qc_metrics/balsamic_qc_metrics.html +1 -0
- cg/meta/delivery_report/templates/macros/ticket_system.html +1 -1
- cg/meta/observations/balsamic_observations_api.py +110 -14
- cg/meta/observations/mip_dna_observations_api.py +1 -1
- cg/meta/observations/nallo_observations_api.py +1 -1
- cg/meta/observations/observations_api.py +23 -32
- cg/meta/observations/raredisease_observations_api.py +1 -1
- cg/meta/tar/tar.py +5 -2
- cg/meta/transfer/lims.py +32 -3
- cg/meta/upload/balsamic/balsamic.py +1 -8
- cg/meta/upload/coverage.py +5 -5
- cg/meta/upload/raredisease/raredisease.py +3 -0
- cg/meta/upload/scout/hk_tags.py +1 -0
- cg/meta/upload/scout/nallo_config_builder.py +31 -7
- cg/meta/workflow/balsamic.py +70 -36
- cg/meta/workflow/fastq.py +8 -0
- cg/meta/workflow/microsalt/quality_controller/models.py +0 -2
- cg/meta/workflow/microsalt/quality_controller/quality_controller.py +8 -16
- cg/meta/workflow/microsalt/quality_controller/result_logger.py +3 -6
- cg/meta/workflow/microsalt/quality_controller/utils.py +2 -45
- cg/meta/workflow/nallo.py +21 -99
- cg/meta/workflow/nf_analysis.py +12 -263
- cg/meta/workflow/raredisease.py +3 -112
- cg/meta/workflow/rnafusion.py +2 -34
- cg/meta/workflow/taxprofiler.py +2 -38
- cg/meta/workflow/tomte.py +2 -42
- cg/models/balsamic/config.py +0 -24
- cg/models/balsamic/metrics.py +5 -3
- cg/models/cg_config.py +39 -16
- cg/models/deliverables/metric_deliverables.py +1 -1
- cg/models/delivery_report/metadata.py +2 -1
- cg/models/nallo/nallo.py +14 -64
- cg/models/nf_analysis.py +1 -41
- cg/models/raredisease/raredisease.py +1 -63
- cg/models/rnafusion/rnafusion.py +0 -26
- cg/models/scout/scout_load_config.py +5 -2
- cg/models/taxprofiler/taxprofiler.py +0 -42
- cg/models/tomte/tomte.py +0 -69
- cg/resources/nallo_bundle_filenames.yaml +292 -22
- cg/resources/raredisease_bundle_filenames.yaml +11 -1
- cg/resources/taxprofiler_bundle_filenames.yaml +20 -0
- cg/server/admin.py +106 -25
- cg/server/app.py +15 -4
- cg/server/endpoints/sequencing_run/dtos.py +21 -3
- cg/server/endpoints/sequencing_run/pacbio_sequencing_run.py +29 -10
- cg/server/endpoints/sequencing_run/pacbio_smrt_cell_metrics.py +20 -0
- cg/services/analysis_starter/{service.py → analysis_starter.py} +11 -9
- cg/services/analysis_starter/configurator/abstract_model.py +8 -0
- cg/services/analysis_starter/configurator/configurator.py +1 -1
- cg/services/analysis_starter/configurator/extensions/nallo.py +27 -0
- cg/services/analysis_starter/configurator/extensions/{abstract.py → pipeline_extension.py} +1 -1
- cg/services/analysis_starter/configurator/extensions/raredisease.py +3 -1
- cg/services/analysis_starter/configurator/extensions/tomte_extension.py +28 -0
- cg/services/analysis_starter/configurator/file_creators/balsamic_config.py +240 -0
- cg/services/analysis_starter/configurator/file_creators/gene_panel.py +10 -5
- cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/abstract.py +2 -1
- cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/models.py +40 -1
- cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/nallo.py +37 -0
- cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/raredisease.py +8 -5
- cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/tomte_params_file_creator.py +64 -0
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/creator.py +1 -1
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/nallo_sample_sheet_creator.py +65 -0
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/protocol.py +12 -0
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{raredisease.py → raredisease_sample_sheet_creator.py} +2 -2
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{rnafusion.py → rnafusion_sample_sheet_creator.py} +2 -2
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{taxprofiler.py → taxprofiler_sample_sheet_creator.py} +2 -2
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/tomte_sample_sheet_creator.py +36 -0
- cg/services/analysis_starter/configurator/implementations/balsamic.py +68 -0
- cg/services/analysis_starter/configurator/implementations/nextflow.py +22 -5
- cg/services/analysis_starter/configurator/models/balsamic.py +152 -0
- cg/services/analysis_starter/configurator/models/mip_dna.py +6 -8
- cg/services/analysis_starter/configurator/models/nextflow.py +9 -0
- cg/services/analysis_starter/constants.py +2 -0
- cg/services/analysis_starter/factories/configurator_factory.py +131 -51
- cg/services/analysis_starter/factories/starter_factory.py +36 -7
- cg/services/analysis_starter/input_fetcher/implementations/bam_fetcher.py +57 -0
- cg/services/analysis_starter/input_fetcher/implementations/fastq_fetcher.py +3 -3
- cg/services/analysis_starter/submitters/seqera_platform/{client.py → seqera_platform_client.py} +19 -3
- cg/services/analysis_starter/submitters/seqera_platform/seqera_platform_submitter.py +73 -0
- cg/services/analysis_starter/submitters/submitter.py +1 -1
- cg/services/analysis_starter/submitters/subprocess/submitter.py +2 -1
- cg/services/analysis_starter/tracker/implementations/balsamic.py +22 -0
- cg/services/analysis_starter/tracker/implementations/microsalt.py +4 -4
- cg/services/analysis_starter/tracker/implementations/mip_dna.py +4 -1
- cg/services/analysis_starter/tracker/implementations/{nextflow.py → nextflow_tracker.py} +6 -4
- cg/services/analysis_starter/tracker/tracker.py +19 -15
- cg/services/deliver_files/factory.py +1 -1
- cg/services/delivery_message/messages/__init__.py +24 -14
- cg/services/delivery_message/messages/{microsalt_mwr_message.py → microsalt_message.py} +1 -1
- cg/services/delivery_message/utils.py +4 -40
- cg/services/illumina/backup/backup_service.py +29 -7
- cg/services/orders/validation/constants.py +3 -0
- cg/services/orders/validation/index_sequences.py +558 -0
- cg/services/orders/validation/order_types/microsalt/models/sample.py +2 -3
- cg/services/run_devices/pacbio/data_storage_service/pacbio_store_service.py +39 -18
- cg/services/run_devices/pacbio/data_transfer_service/data_transfer_service.py +8 -2
- cg/services/run_devices/pacbio/data_transfer_service/dto.py +9 -3
- cg/services/run_devices/pacbio/data_transfer_service/utils.py +14 -7
- cg/services/run_devices/pacbio/metrics_parser/models.py +1 -0
- cg/services/run_devices/pacbio/sequencing_runs_service.py +35 -7
- cg/services/sequencing_qc_service/quality_checks/checks.py +18 -16
- cg/services/sequencing_qc_service/quality_checks/utils.py +82 -18
- cg/services/sequencing_qc_service/sequencing_qc_service.py +12 -10
- cg/store/crud/create.py +73 -42
- cg/store/crud/read.py +73 -7
- cg/store/crud/update.py +14 -3
- cg/store/models.py +98 -35
- cg/store/store.py +8 -1
- {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/METADATA +1 -1
- {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/RECORD +150 -138
- cg/services/analysis_starter/submitters/seqera_platform/submitter.py +0 -39
- cg/services/delivery_message/messages/microsalt_mwx_message.py +0 -18
- {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/WHEEL +0 -0
- {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/entry_points.txt +0 -0
cg/server/admin.py
CHANGED
|
@@ -12,6 +12,7 @@ from wtforms.form import Form
|
|
|
12
12
|
|
|
13
13
|
from cg.constants.constants import NG_UL_SUFFIX, CaseActions, DataDelivery, Workflow
|
|
14
14
|
from cg.models.orders.constants import OrderType
|
|
15
|
+
from cg.server.app_config import app_config
|
|
15
16
|
from cg.server.ext import applications_service, db, sample_service
|
|
16
17
|
from cg.server.utils import MultiCheckboxField
|
|
17
18
|
from cg.store.models import Application
|
|
@@ -111,12 +112,6 @@ def view_pacbio_sample_sequencing_metrics_link(unused1, unused2, model, unused3)
|
|
|
111
112
|
)
|
|
112
113
|
|
|
113
114
|
|
|
114
|
-
def is_external_application(unused1, unused2, model, unused3):
|
|
115
|
-
"""column formatter to open this view"""
|
|
116
|
-
del unused1, unused2, unused3
|
|
117
|
-
return model.application_version.application.is_external if model.application_version else ""
|
|
118
|
-
|
|
119
|
-
|
|
120
115
|
def view_order_types(unused1, unused2, model, unused3):
|
|
121
116
|
del unused1, unused2, unused3
|
|
122
117
|
order_type_list = "<br>".join(model.order_types)
|
|
@@ -197,6 +192,44 @@ def view_customer_link(unused1, unused2, model, unused3):
|
|
|
197
192
|
return markup
|
|
198
193
|
|
|
199
194
|
|
|
195
|
+
def view_ticket_link(unused1, unused2, model, attribute_name):
|
|
196
|
+
"""Column formatter used to add hyperlink to ticket ID, if applicable."""
|
|
197
|
+
del unused1, unused2
|
|
198
|
+
|
|
199
|
+
# Ticket attribute called differently from models, infer attribute name from args
|
|
200
|
+
ticket_attr = getattr(model, attribute_name)
|
|
201
|
+
ticket_str = str(ticket_attr).strip()
|
|
202
|
+
|
|
203
|
+
# Freshdesk ticket IDs have >=7 digits
|
|
204
|
+
if len(ticket_str) >= 7:
|
|
205
|
+
ticket_link = f"{app_config.freshdesk_url}/a/tickets/{ticket_str}"
|
|
206
|
+
ticket_markup = Markup(f"<a href='{ticket_link}'>{ticket_str}</a>")
|
|
207
|
+
return ticket_markup
|
|
208
|
+
else:
|
|
209
|
+
return ticket_str
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def view_tickets_links(unused1, unused2, model, unused3):
|
|
213
|
+
"""Column formatter used to add hyperlinks to comma-separated ticket IDs, if applicable. Assumes attribute name 'tickets'."""
|
|
214
|
+
del unused1, unused2, unused3
|
|
215
|
+
|
|
216
|
+
tickets_list = str(model.tickets).strip().split(sep=",")
|
|
217
|
+
|
|
218
|
+
tickets_markups = []
|
|
219
|
+
for ticket in tickets_list:
|
|
220
|
+
ticket_str = str(ticket).strip()
|
|
221
|
+
|
|
222
|
+
# Freshdesk ticket IDs have >=7 digits
|
|
223
|
+
if len(ticket_str) >= 7:
|
|
224
|
+
ticket_link = f"{app_config.freshdesk_url}/a/tickets/{ticket_str}"
|
|
225
|
+
ticket_markup = Markup(f"<a href='{ticket_link}'>{ticket_str}</a>")
|
|
226
|
+
tickets_markups.append(ticket_markup)
|
|
227
|
+
else:
|
|
228
|
+
tickets_markups.append(ticket_str)
|
|
229
|
+
|
|
230
|
+
return Markup(", ".join(tickets_markups))
|
|
231
|
+
|
|
232
|
+
|
|
200
233
|
class ApplicationView(BaseView):
|
|
201
234
|
"""Admin view for Model.Application"""
|
|
202
235
|
|
|
@@ -207,6 +240,8 @@ class ApplicationView(BaseView):
|
|
|
207
240
|
"is_accredited",
|
|
208
241
|
"target_reads",
|
|
209
242
|
"percent_reads_guaranteed",
|
|
243
|
+
"target_hifi_yield",
|
|
244
|
+
"percent_hifi_yield_guaranteed",
|
|
210
245
|
"comment",
|
|
211
246
|
"prep_category",
|
|
212
247
|
"sequencing_depth",
|
|
@@ -267,10 +302,11 @@ class ApplicationView(BaseView):
|
|
|
267
302
|
def on_model_change(self, form: Form, model: Application, is_created: bool):
|
|
268
303
|
"""Override to persist entries to the OrderTypeApplication table."""
|
|
269
304
|
super(ApplicationView, self).on_model_change(form=form, model=model, is_created=is_created)
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
305
|
+
if "suitable_order_types" in form.data:
|
|
306
|
+
order_types: list[OrderType] = form["suitable_order_types"].data
|
|
307
|
+
applications_service.update_application_order_types(
|
|
308
|
+
application=model, order_types=order_types
|
|
309
|
+
)
|
|
274
310
|
|
|
275
311
|
def edit_form(self, obj=None):
|
|
276
312
|
"""Override to prefill the order types according to the current Application entry."""
|
|
@@ -435,6 +471,7 @@ class CaseView(BaseView):
|
|
|
435
471
|
"customer": view_customer_link,
|
|
436
472
|
"internal_id": view_case_sample_link,
|
|
437
473
|
"priority": view_priority,
|
|
474
|
+
"tickets": view_tickets_links,
|
|
438
475
|
}
|
|
439
476
|
column_searchable_list = [
|
|
440
477
|
"internal_id",
|
|
@@ -650,7 +687,10 @@ class OrderView(BaseView):
|
|
|
650
687
|
|
|
651
688
|
column_default_sort = ("order_date", True)
|
|
652
689
|
column_editable_list = ["is_open"]
|
|
653
|
-
column_formatters = {
|
|
690
|
+
column_formatters = {
|
|
691
|
+
"customer": view_customer_link,
|
|
692
|
+
"ticket_id": view_ticket_link,
|
|
693
|
+
}
|
|
654
694
|
column_searchable_list = ["id", "ticket_id"]
|
|
655
695
|
column_display_pk = True
|
|
656
696
|
create_modal = True
|
|
@@ -691,10 +731,36 @@ class PoolView(BaseView):
|
|
|
691
731
|
class SampleView(BaseView):
|
|
692
732
|
"""Admin view for Model.Sample"""
|
|
693
733
|
|
|
694
|
-
|
|
695
|
-
"
|
|
696
|
-
"
|
|
697
|
-
"
|
|
734
|
+
column_list = [
|
|
735
|
+
"application_version",
|
|
736
|
+
"customer",
|
|
737
|
+
"organism",
|
|
738
|
+
"invoice",
|
|
739
|
+
"is_cancelled",
|
|
740
|
+
"capture_kit",
|
|
741
|
+
"comment",
|
|
742
|
+
"control",
|
|
743
|
+
"created_at",
|
|
744
|
+
"delivered_at",
|
|
745
|
+
"downsampled_to",
|
|
746
|
+
"from_sample",
|
|
747
|
+
"internal_id",
|
|
748
|
+
"is_tumour",
|
|
749
|
+
"loqusdb_id",
|
|
750
|
+
"name",
|
|
751
|
+
"no_invoice",
|
|
752
|
+
"order",
|
|
753
|
+
"ordered_at",
|
|
754
|
+
"original_ticket",
|
|
755
|
+
"prepared_at",
|
|
756
|
+
"priority",
|
|
757
|
+
"reads",
|
|
758
|
+
"hifi_yield",
|
|
759
|
+
"last_sequenced_at",
|
|
760
|
+
"received_at",
|
|
761
|
+
"reference_genome",
|
|
762
|
+
"sex",
|
|
763
|
+
"subject_id",
|
|
698
764
|
]
|
|
699
765
|
column_default_sort = ("created_at", True)
|
|
700
766
|
column_editable_list = [
|
|
@@ -714,9 +780,9 @@ class SampleView(BaseView):
|
|
|
714
780
|
column_formatters = {
|
|
715
781
|
"application_version": view_application_link_via_application_version,
|
|
716
782
|
"customer": view_customer_link,
|
|
717
|
-
"is_external": is_external_application,
|
|
718
783
|
"internal_id": view_case_sample_link,
|
|
719
784
|
"invoice": InvoiceView.view_invoice_link,
|
|
785
|
+
"original_ticket": view_ticket_link,
|
|
720
786
|
"priority": view_priority,
|
|
721
787
|
}
|
|
722
788
|
column_searchable_list = [
|
|
@@ -834,12 +900,12 @@ class IlluminaSampleSequencingMetricsView(BaseView):
|
|
|
834
900
|
column_searchable_list = ["sample.internal_id", "instrument_run.device.internal_id"]
|
|
835
901
|
|
|
836
902
|
|
|
837
|
-
class
|
|
903
|
+
class PacbioSmrtCellMetricsView(BaseView):
|
|
838
904
|
"""Admin view for Model.PacbioSMRTCell"""
|
|
839
905
|
|
|
840
906
|
column_list = (
|
|
841
907
|
"internal_id",
|
|
842
|
-
"run_name",
|
|
908
|
+
"sequencing_run.run_name",
|
|
843
909
|
"movie_name",
|
|
844
910
|
"well",
|
|
845
911
|
"plate",
|
|
@@ -863,8 +929,9 @@ class PacbioSmrtCellView(BaseView):
|
|
|
863
929
|
"internal_id": view_pacbio_sample_sequencing_metrics_link,
|
|
864
930
|
"model": view_smrt_cell_model,
|
|
865
931
|
}
|
|
932
|
+
column_labels = {"sequencing_run.run_name": "Run Name"}
|
|
866
933
|
column_default_sort = ("completed_at", True)
|
|
867
|
-
column_searchable_list = ["device.internal_id", "
|
|
934
|
+
column_searchable_list = ["device.internal_id", "movie_name", "sequencing_run.run_name"]
|
|
868
935
|
column_sortable_list = [
|
|
869
936
|
("internal_id", "device.internal_id"),
|
|
870
937
|
"started_at",
|
|
@@ -880,7 +947,7 @@ class PacbioSmrtCellView(BaseView):
|
|
|
880
947
|
"<a href='%s'>%s</a>"
|
|
881
948
|
% (
|
|
882
949
|
url_for(
|
|
883
|
-
"
|
|
950
|
+
"pacbiosmrtcellmetrics.index_view",
|
|
884
951
|
search=model.instrument_run.device.internal_id,
|
|
885
952
|
),
|
|
886
953
|
model.instrument_run.device.internal_id,
|
|
@@ -892,16 +959,30 @@ class PacbioSmrtCellView(BaseView):
|
|
|
892
959
|
|
|
893
960
|
|
|
894
961
|
class PacbioSampleRunMetricsView(BaseView):
|
|
962
|
+
column_filters = [
|
|
963
|
+
"instrument_run.plate",
|
|
964
|
+
"instrument_run.sequencing_run.run_name",
|
|
965
|
+
]
|
|
966
|
+
column_formatters = {
|
|
967
|
+
"smrt_cell": PacbioSmrtCellMetricsView.view_smrt_cell_link,
|
|
968
|
+
"sample": SampleView.view_sample_link,
|
|
969
|
+
}
|
|
970
|
+
column_labels = {
|
|
971
|
+
"instrument_run.plate": "Plate",
|
|
972
|
+
"instrument_run.sequencing_run.run_name": "Run Name",
|
|
973
|
+
}
|
|
895
974
|
column_list = [
|
|
896
975
|
"smrt_cell",
|
|
897
976
|
"sample",
|
|
977
|
+
"instrument_run.sequencing_run.run_name",
|
|
978
|
+
"instrument_run.plate",
|
|
898
979
|
"hifi_reads",
|
|
899
980
|
"hifi_yield",
|
|
900
981
|
"hifi_mean_read_length",
|
|
901
982
|
"hifi_median_read_quality",
|
|
902
983
|
]
|
|
903
|
-
|
|
904
|
-
"
|
|
905
|
-
"
|
|
906
|
-
|
|
907
|
-
|
|
984
|
+
column_searchable_list = [
|
|
985
|
+
"sample.internal_id",
|
|
986
|
+
"instrument_run.device.internal_id",
|
|
987
|
+
"instrument_run.sequencing_run.run_name",
|
|
988
|
+
]
|
cg/server/app.py
CHANGED
|
@@ -19,7 +19,12 @@ from cg.server.endpoints.sequencing_metrics.illumina_sequencing_metrics import F
|
|
|
19
19
|
from cg.server.endpoints.sequencing_metrics.pacbio_sequencing_metrics import (
|
|
20
20
|
PACBIO_SAMPLE_SEQUENCING_METRICS_BLUEPRINT,
|
|
21
21
|
)
|
|
22
|
-
from cg.server.endpoints.sequencing_run.pacbio_sequencing_run import
|
|
22
|
+
from cg.server.endpoints.sequencing_run.pacbio_sequencing_run import (
|
|
23
|
+
PACBIO_SEQUENCING_RUNS_BLUEPRINT,
|
|
24
|
+
)
|
|
25
|
+
from cg.server.endpoints.sequencing_run.pacbio_smrt_cell_metrics import (
|
|
26
|
+
PACBIO_SMRT_CELL_METRICS_BLUEPRINT,
|
|
27
|
+
)
|
|
23
28
|
from cg.server.endpoints.users import USERS_BLUEPRINT
|
|
24
29
|
from cg.store.database import get_scoped_session_registry
|
|
25
30
|
from cg.store.models import (
|
|
@@ -39,7 +44,7 @@ from cg.store.models import (
|
|
|
39
44
|
Order,
|
|
40
45
|
Organism,
|
|
41
46
|
PacbioSampleSequencingMetrics,
|
|
42
|
-
|
|
47
|
+
PacbioSMRTCellMetrics,
|
|
43
48
|
Panel,
|
|
44
49
|
Pool,
|
|
45
50
|
Sample,
|
|
@@ -107,7 +112,8 @@ def _register_blueprints(app: Flask):
|
|
|
107
112
|
app.register_blueprint(ANALYSES_BLUEPRINT)
|
|
108
113
|
app.register_blueprint(USERS_BLUEPRINT)
|
|
109
114
|
app.register_blueprint(PACBIO_SAMPLE_SEQUENCING_METRICS_BLUEPRINT)
|
|
110
|
-
app.register_blueprint(
|
|
115
|
+
app.register_blueprint(PACBIO_SEQUENCING_RUNS_BLUEPRINT)
|
|
116
|
+
app.register_blueprint(PACBIO_SMRT_CELL_METRICS_BLUEPRINT)
|
|
111
117
|
app.register_blueprint(INDEX_SEQUENCES_BLUEPRINT)
|
|
112
118
|
_register_admin_views()
|
|
113
119
|
|
|
@@ -119,6 +125,7 @@ def _register_blueprints(app: Flask):
|
|
|
119
125
|
ext.csrf.exempt(FLOW_CELLS_BLUEPRINT)
|
|
120
126
|
ext.csrf.exempt(ANALYSES_BLUEPRINT)
|
|
121
127
|
ext.csrf.exempt(USERS_BLUEPRINT)
|
|
128
|
+
ext.csrf.exempt(PACBIO_SEQUENCING_RUNS_BLUEPRINT)
|
|
122
129
|
|
|
123
130
|
@app.route("/")
|
|
124
131
|
def index():
|
|
@@ -158,7 +165,11 @@ def _register_admin_views():
|
|
|
158
165
|
ext.admin.add_view(
|
|
159
166
|
admin.IlluminaSampleSequencingMetricsView(IlluminaSampleSequencingMetrics, ext.db.session)
|
|
160
167
|
)
|
|
161
|
-
ext.admin.add_view(
|
|
168
|
+
ext.admin.add_view(
|
|
169
|
+
admin.PacbioSmrtCellMetricsView(
|
|
170
|
+
PacbioSMRTCellMetrics, ext.db.session, "Pacbio SMRT Cell Metrics"
|
|
171
|
+
)
|
|
172
|
+
)
|
|
162
173
|
ext.admin.add_view(
|
|
163
174
|
admin.PacbioSampleRunMetricsView(PacbioSampleSequencingMetrics, ext.db.session)
|
|
164
175
|
)
|
|
@@ -3,7 +3,7 @@ from datetime import datetime
|
|
|
3
3
|
from pydantic import BaseModel
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
class
|
|
6
|
+
class PacbioSmrtCellMetricsDTO(BaseModel):
|
|
7
7
|
barcoded_hifi_mean_read_length: int
|
|
8
8
|
barcoded_hifi_reads: int
|
|
9
9
|
barcoded_hifi_reads_percentage: float
|
|
@@ -24,5 +24,23 @@ class PacbioSequencingRunDTO(BaseModel):
|
|
|
24
24
|
well: str
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class
|
|
28
|
-
runs: list[
|
|
27
|
+
class PacbioSmrtCellMetricsResponse(BaseModel):
|
|
28
|
+
runs: list[PacbioSmrtCellMetricsDTO]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class PacbioSequencingRunDTO(BaseModel):
|
|
32
|
+
id: int
|
|
33
|
+
run_name: str
|
|
34
|
+
comment: str
|
|
35
|
+
processed: bool
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class PacbioSequencingRunResponse(BaseModel):
|
|
39
|
+
pacbio_sequencing_runs: list[PacbioSequencingRunDTO]
|
|
40
|
+
total_count: int
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class PacbioSequencingRunUpdateRequest(BaseModel):
|
|
44
|
+
id: int
|
|
45
|
+
comment: str | None = None
|
|
46
|
+
processed: bool | None = None
|
|
@@ -1,20 +1,39 @@
|
|
|
1
|
-
from
|
|
1
|
+
from http import HTTPStatus
|
|
2
|
+
|
|
3
|
+
from flask import Blueprint, Response, jsonify, request
|
|
4
|
+
from pydantic import ValidationError
|
|
2
5
|
|
|
3
6
|
from cg.server.endpoints.error_handler import handle_missing_entries
|
|
4
|
-
from cg.server.endpoints.sequencing_run.dtos import
|
|
7
|
+
from cg.server.endpoints.sequencing_run.dtos import (
|
|
8
|
+
PacbioSequencingRunResponse,
|
|
9
|
+
PacbioSequencingRunUpdateRequest,
|
|
10
|
+
)
|
|
5
11
|
from cg.server.endpoints.utils import before_request
|
|
6
12
|
from cg.server.ext import pacbio_sequencing_runs_service
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
"
|
|
14
|
+
PACBIO_SEQUENCING_RUNS_BLUEPRINT = Blueprint(
|
|
15
|
+
"pacbio_sequencing_runs", __name__, url_prefix="/api/v1/"
|
|
10
16
|
)
|
|
11
|
-
|
|
17
|
+
PACBIO_SEQUENCING_RUNS_BLUEPRINT.before_request(before_request)
|
|
12
18
|
|
|
13
19
|
|
|
14
|
-
@
|
|
20
|
+
@PACBIO_SEQUENCING_RUNS_BLUEPRINT.route("/pacbio_sequencing_runs", methods=["GET"])
|
|
15
21
|
@handle_missing_entries
|
|
16
|
-
def get_sequencing_runs(
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
def get_sequencing_runs():
|
|
23
|
+
page: int = int(request.args.get("page", "0"))
|
|
24
|
+
page_size: int = int(request.args.get("pageSize", "0"))
|
|
25
|
+
sequencing_runs: PacbioSequencingRunResponse = (
|
|
26
|
+
pacbio_sequencing_runs_service.get_sequencing_runs(page=page, page_size=page_size)
|
|
19
27
|
)
|
|
20
|
-
return jsonify(
|
|
28
|
+
return jsonify(sequencing_runs.model_dump())
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@PACBIO_SEQUENCING_RUNS_BLUEPRINT.route("/pacbio_sequencing_runs/<id>", methods=["PATCH"])
|
|
32
|
+
@handle_missing_entries
|
|
33
|
+
def update_sequencing_run(id: str):
|
|
34
|
+
try:
|
|
35
|
+
update_request = PacbioSequencingRunUpdateRequest(id=id, **request.json)
|
|
36
|
+
except ValidationError:
|
|
37
|
+
return Response(status=HTTPStatus.UNPROCESSABLE_ENTITY)
|
|
38
|
+
pacbio_sequencing_runs_service.update_sequencing_run(update_request=update_request)
|
|
39
|
+
return Response(status=HTTPStatus.NO_CONTENT)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from flask import Blueprint, jsonify
|
|
2
|
+
|
|
3
|
+
from cg.server.endpoints.error_handler import handle_missing_entries
|
|
4
|
+
from cg.server.endpoints.sequencing_run.dtos import PacbioSmrtCellMetricsResponse
|
|
5
|
+
from cg.server.endpoints.utils import before_request
|
|
6
|
+
from cg.server.ext import pacbio_sequencing_runs_service
|
|
7
|
+
|
|
8
|
+
PACBIO_SMRT_CELL_METRICS_BLUEPRINT = Blueprint(
|
|
9
|
+
"pacbio_smrt_cell_metrics", __name__, url_prefix="/api/v1/pacbio_smrt_cell_metrics"
|
|
10
|
+
)
|
|
11
|
+
PACBIO_SMRT_CELL_METRICS_BLUEPRINT.before_request(before_request)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@PACBIO_SMRT_CELL_METRICS_BLUEPRINT.route("/<run_name>", methods=["GET"])
|
|
15
|
+
@handle_missing_entries
|
|
16
|
+
def get_smrt_cell_metrics(run_name: str):
|
|
17
|
+
response: PacbioSmrtCellMetricsResponse = (
|
|
18
|
+
pacbio_sequencing_runs_service.get_sequencing_runs_by_name(run_name)
|
|
19
|
+
)
|
|
20
|
+
return jsonify(response.model_dump())
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from subprocess import CalledProcessError
|
|
3
3
|
|
|
4
|
+
from requests import HTTPError
|
|
5
|
+
|
|
4
6
|
from cg.constants import Workflow
|
|
5
|
-
from cg.exc import AnalysisNotReadyError
|
|
7
|
+
from cg.exc import AnalysisNotReadyError, SeqeraError
|
|
6
8
|
from cg.services.analysis_starter.configurator.abstract_model import CaseConfig
|
|
7
9
|
from cg.services.analysis_starter.configurator.configurator import Configurator
|
|
8
10
|
from cg.services.analysis_starter.input_fetcher.input_fetcher import InputFetcher
|
|
@@ -51,20 +53,20 @@ class AnalysisStarter:
|
|
|
51
53
|
LOG.info(f"Starting case {case_id}")
|
|
52
54
|
self.tracker.ensure_analysis_not_ongoing(case_id)
|
|
53
55
|
self.input_fetcher.ensure_files_are_ready(case_id)
|
|
54
|
-
|
|
55
|
-
self._run_and_track(case_id=case_id,
|
|
56
|
+
case_config: CaseConfig = self.configurator.configure(case_id=case_id, **flags)
|
|
57
|
+
self._run_and_track(case_id=case_id, case_config=case_config)
|
|
56
58
|
|
|
57
59
|
def run(self, case_id: str, **flags) -> None:
|
|
58
60
|
"""Run a case using an assumed existing configuration."""
|
|
59
61
|
self.tracker.ensure_analysis_not_ongoing(case_id)
|
|
60
|
-
|
|
61
|
-
self._run_and_track(case_id=case_id,
|
|
62
|
+
case_config: CaseConfig = self.configurator.get_config(case_id=case_id, **flags)
|
|
63
|
+
self._run_and_track(case_id=case_id, case_config=case_config)
|
|
62
64
|
|
|
63
|
-
def _run_and_track(self, case_id: str,
|
|
65
|
+
def _run_and_track(self, case_id: str, case_config: CaseConfig):
|
|
64
66
|
self.tracker.set_case_as_running(case_id)
|
|
65
67
|
try:
|
|
66
|
-
|
|
67
|
-
self.tracker.track(case_config=
|
|
68
|
-
except CalledProcessError as exception:
|
|
68
|
+
submitted_case_config: CaseConfig = self.submitter.submit(case_config)
|
|
69
|
+
self.tracker.track(case_config=submitted_case_config)
|
|
70
|
+
except (CalledProcessError, HTTPError, SeqeraError) as exception:
|
|
69
71
|
self.tracker.set_case_as_not_running(case_id)
|
|
70
72
|
raise exception
|
|
@@ -6,3 +6,11 @@ from cg.constants import Workflow
|
|
|
6
6
|
class CaseConfig(BaseModel):
|
|
7
7
|
case_id: str
|
|
8
8
|
workflow: Workflow
|
|
9
|
+
|
|
10
|
+
def get_session_id(self) -> str | None:
|
|
11
|
+
# This will be set by the NextflowCaseConfig
|
|
12
|
+
return None
|
|
13
|
+
|
|
14
|
+
def get_workflow_id(self) -> str | None:
|
|
15
|
+
# This will be set by the NextflowCaseConfig
|
|
16
|
+
return None
|
|
@@ -20,7 +20,7 @@ class Configurator(ABC):
|
|
|
20
20
|
@staticmethod
|
|
21
21
|
def _set_flags(config: SpecificCaseConfig, **flags) -> SpecificCaseConfig:
|
|
22
22
|
curated_flags: dict = {key: value for key, value in flags.items() if value is not None}
|
|
23
|
-
return config.
|
|
23
|
+
return config.model_validate(config.model_dump(by_alias=True) | curated_flags)
|
|
24
24
|
|
|
25
25
|
@abstractmethod
|
|
26
26
|
def _ensure_required_config_files_exist(self, **kwargs) -> None:
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from cg.constants.scout import ScoutExportFileName
|
|
4
|
+
from cg.services.analysis_starter.configurator.extensions.pipeline_extension import (
|
|
5
|
+
PipelineExtension,
|
|
6
|
+
)
|
|
7
|
+
from cg.services.analysis_starter.configurator.file_creators.gene_panel import GenePanelFileCreator
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class NalloExtension(PipelineExtension):
|
|
11
|
+
def __init__(self, gene_panel_file_creator: GenePanelFileCreator):
|
|
12
|
+
self.gene_panel_file_creator = gene_panel_file_creator
|
|
13
|
+
|
|
14
|
+
def configure(self, case_id: str, case_run_directory: Path) -> None:
|
|
15
|
+
self.gene_panel_file_creator.create(
|
|
16
|
+
case_id=case_id,
|
|
17
|
+
file_path=self._get_gene_panel_file_path(case_run_directory),
|
|
18
|
+
double_hashtag_filtering=True,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def do_required_files_exist(self, case_run_directory: Path) -> bool:
|
|
22
|
+
gene_panel_file_path: Path = self._get_gene_panel_file_path(case_run_directory)
|
|
23
|
+
return gene_panel_file_path.is_file()
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def _get_gene_panel_file_path(case_run_directory: Path) -> Path:
|
|
27
|
+
return case_run_directory.joinpath(ScoutExportFileName.PANELS_TSV)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from os.path import isfile
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
|
-
from cg.services.analysis_starter.configurator.extensions.
|
|
4
|
+
from cg.services.analysis_starter.configurator.extensions.pipeline_extension import (
|
|
5
|
+
PipelineExtension,
|
|
6
|
+
)
|
|
5
7
|
from cg.services.analysis_starter.configurator.file_creators.gene_panel import GenePanelFileCreator
|
|
6
8
|
from cg.services.analysis_starter.configurator.file_creators.managed_variants import (
|
|
7
9
|
ManagedVariantsFileCreator,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from os.path import isfile
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from cg.constants.scout import ScoutExportFileName
|
|
5
|
+
from cg.services.analysis_starter.configurator.extensions.pipeline_extension import (
|
|
6
|
+
PipelineExtension,
|
|
7
|
+
)
|
|
8
|
+
from cg.services.analysis_starter.configurator.file_creators.gene_panel import GenePanelFileCreator
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TomteExtension(PipelineExtension):
|
|
12
|
+
def __init__(self, gene_panel_file_creator: GenePanelFileCreator):
|
|
13
|
+
self.gene_panel_file_creator = gene_panel_file_creator
|
|
14
|
+
|
|
15
|
+
def configure(self, case_id: str, case_run_directory: Path) -> None:
|
|
16
|
+
self.gene_panel_file_creator.create(
|
|
17
|
+
case_id=case_id,
|
|
18
|
+
file_path=self._get_gene_panel_file_path(case_run_directory),
|
|
19
|
+
double_hashtag_filtering=False,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
def do_required_files_exist(self, case_run_directory: Path) -> bool:
|
|
23
|
+
gene_panel_file_path: Path = self._get_gene_panel_file_path(case_run_directory)
|
|
24
|
+
return isfile(gene_panel_file_path)
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def _get_gene_panel_file_path(case_run_directory: Path) -> Path:
|
|
28
|
+
return case_run_directory.joinpath(ScoutExportFileName.PANELS)
|