endoreg-db 0.8.6.1__py3-none-any.whl → 0.8.8.9__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.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/authz/auth.py +74 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +18 -0
- endoreg_db/authz/middleware.py +83 -0
- endoreg_db/authz/permissions.py +127 -0
- endoreg_db/authz/policy.py +218 -0
- endoreg_db/authz/views_auth.py +66 -0
- endoreg_db/config/env.py +13 -8
- endoreg_db/data/__init__.py +2 -11
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
- endoreg_db/data/event_classification/data.yaml +4 -0
- endoreg_db/data/event_classification_choice/data.yaml +9 -0
- endoreg_db/data/examination/examinations/data.yaml +114 -14
- endoreg_db/data/examination/time-type/data.yaml +0 -3
- endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
- endoreg_db/data/finding/00_generic.yaml +35 -0
- endoreg_db/data/finding/00_generic_complication.yaml +9 -0
- endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
- endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
- endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
- endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
- endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
- endoreg_db/data/finding_classification/00_generic.yaml +44 -0
- endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
- endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
- endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
- endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
- endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
- endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
- endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
- endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
- endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
- endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
- endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
- endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
- endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
- endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
- endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
- endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
- endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
- endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
- endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
- endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
- endoreg_db/data/finding_type/data.yaml +8 -12
- endoreg_db/data/requirement/01_patient_data.yaml +93 -0
- endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
- endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
- endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
- endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
- endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set_type/data.yaml +21 -0
- endoreg_db/data/setup_config.yaml +4 -4
- endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
- endoreg_db/exceptions.py +4 -2
- endoreg_db/forms/examination_form.py +1 -1
- endoreg_db/helpers/data_loader.py +125 -53
- endoreg_db/helpers/default_objects.py +116 -81
- endoreg_db/import_files/__init__.py +27 -0
- endoreg_db/import_files/context/__init__.py +7 -0
- endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
- endoreg_db/import_files/context/ensure_center.py +17 -0
- endoreg_db/import_files/context/file_lock.py +66 -0
- endoreg_db/import_files/context/import_context.py +43 -0
- endoreg_db/import_files/context/validate_directories.py +56 -0
- endoreg_db/import_files/file_storage/__init__.py +15 -0
- endoreg_db/import_files/file_storage/create_report_file.py +76 -0
- endoreg_db/import_files/file_storage/create_video_file.py +75 -0
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
- endoreg_db/import_files/file_storage/state_management.py +400 -0
- endoreg_db/import_files/file_storage/storage.py +36 -0
- endoreg_db/import_files/import_service.md +26 -0
- endoreg_db/import_files/processing/__init__.py +11 -0
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
- endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
- endoreg_db/import_files/pseudonymization/fake.py +52 -0
- endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
- endoreg_db/import_files/report_import_service.py +141 -0
- endoreg_db/import_files/video_import_service.py +150 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
- endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
- endoreg_db/management/commands/import_report.py +130 -65
- endoreg_db/management/commands/import_video.py +9 -10
- endoreg_db/management/commands/import_video_with_classification.py +2 -2
- endoreg_db/management/commands/list_routes.py +18 -0
- endoreg_db/management/commands/load_ai_model_data.py +5 -5
- endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
- endoreg_db/management/commands/load_base_db_data.py +5 -134
- endoreg_db/management/commands/load_center_data.py +12 -12
- endoreg_db/management/commands/load_contraindication_data.py +14 -16
- endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
- endoreg_db/management/commands/load_disease_classification_data.py +15 -18
- endoreg_db/management/commands/load_disease_data.py +25 -28
- endoreg_db/management/commands/load_endoscope_data.py +20 -27
- endoreg_db/management/commands/load_event_data.py +14 -16
- endoreg_db/management/commands/load_examination_data.py +31 -44
- endoreg_db/management/commands/load_examination_indication_data.py +20 -21
- endoreg_db/management/commands/load_finding_data.py +52 -80
- endoreg_db/management/commands/load_information_source.py +21 -23
- endoreg_db/management/commands/load_lab_value_data.py +17 -26
- endoreg_db/management/commands/load_medication_data.py +13 -12
- endoreg_db/management/commands/load_organ_data.py +15 -19
- endoreg_db/management/commands/load_pdf_type_data.py +19 -18
- endoreg_db/management/commands/load_profession_data.py +14 -17
- endoreg_db/management/commands/load_qualification_data.py +20 -23
- endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
- endoreg_db/management/commands/load_requirement_data.py +62 -39
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/load_risk_data.py +7 -6
- endoreg_db/management/commands/load_shift_data.py +20 -23
- endoreg_db/management/commands/load_tag_data.py +8 -11
- endoreg_db/management/commands/load_unit_data.py +17 -19
- endoreg_db/management/commands/setup_endoreg_db.py +3 -3
- endoreg_db/management/commands/start_filewatcher.py +46 -37
- endoreg_db/management/commands/storage_management.py +271 -203
- endoreg_db/management/commands/validate_video_files.py +1 -5
- endoreg_db/migrations/0001_initial.py +297 -250
- endoreg_db/models/__init__.py +78 -123
- endoreg_db/models/administration/__init__.py +21 -42
- endoreg_db/models/administration/ai/active_model.py +2 -2
- endoreg_db/models/administration/ai/ai_model.py +7 -6
- endoreg_db/models/administration/case/__init__.py +1 -15
- endoreg_db/models/administration/case/case.py +3 -3
- endoreg_db/models/administration/case/case_template/__init__.py +2 -14
- endoreg_db/models/administration/case/case_template/case_template.py +2 -124
- endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
- endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
- endoreg_db/models/administration/center/center.py +33 -19
- endoreg_db/models/administration/center/center_product.py +12 -9
- endoreg_db/models/administration/center/center_resource.py +25 -19
- endoreg_db/models/administration/center/center_shift.py +21 -17
- endoreg_db/models/administration/center/center_waste.py +16 -8
- endoreg_db/models/administration/person/__init__.py +2 -0
- endoreg_db/models/administration/person/employee/employee.py +10 -5
- endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
- endoreg_db/models/administration/person/employee/employee_type.py +12 -6
- endoreg_db/models/administration/person/examiner/examiner.py +13 -11
- endoreg_db/models/administration/person/patient/__init__.py +2 -0
- endoreg_db/models/administration/person/patient/patient.py +129 -100
- endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
- endoreg_db/models/administration/person/person.py +4 -0
- endoreg_db/models/administration/person/profession/__init__.py +8 -4
- endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
- endoreg_db/models/administration/product/product.py +20 -15
- endoreg_db/models/administration/product/product_material.py +17 -18
- endoreg_db/models/administration/product/product_weight.py +12 -8
- endoreg_db/models/administration/product/reference_product.py +23 -55
- endoreg_db/models/administration/qualification/qualification.py +7 -3
- endoreg_db/models/administration/qualification/qualification_type.py +7 -3
- endoreg_db/models/administration/shift/scheduled_days.py +8 -5
- endoreg_db/models/administration/shift/shift.py +16 -12
- endoreg_db/models/administration/shift/shift_type.py +23 -31
- endoreg_db/models/label/__init__.py +8 -9
- endoreg_db/models/label/annotation/image_classification.py +10 -9
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
- endoreg_db/models/label/label.py +15 -15
- endoreg_db/models/label/label_set.py +19 -6
- endoreg_db/models/label/label_type.py +1 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
- endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
- endoreg_db/models/label/video_segmentation_label.py +4 -0
- endoreg_db/models/label/video_segmentation_labelset.py +4 -3
- endoreg_db/models/media/frame/frame.py +22 -22
- endoreg_db/models/media/pdf/raw_pdf.py +194 -194
- endoreg_db/models/media/pdf/report_file.py +25 -29
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
- endoreg_db/models/media/processing_history/__init__.py +5 -0
- endoreg_db/models/media/processing_history/processing_history.py +96 -0
- endoreg_db/models/media/video/__init__.py +1 -0
- endoreg_db/models/media/video/create_from_file.py +139 -77
- endoreg_db/models/media/video/pipe_2.py +8 -9
- endoreg_db/models/media/video/video_file.py +174 -112
- endoreg_db/models/media/video/video_file_ai.py +288 -74
- endoreg_db/models/media/video/video_file_anonymize.py +38 -38
- endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
- endoreg_db/models/media/video/video_file_io.py +113 -61
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
- endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
- endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
- endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
- endoreg_db/models/media/video/video_file_segments.py +24 -17
- endoreg_db/models/media/video/video_metadata.py +19 -35
- endoreg_db/models/media/video/video_processing.py +96 -95
- endoreg_db/models/medical/contraindication/README.md +1 -0
- endoreg_db/models/medical/contraindication/__init__.py +13 -3
- endoreg_db/models/medical/disease.py +22 -16
- endoreg_db/models/medical/event.py +31 -18
- endoreg_db/models/medical/examination/__init__.py +13 -6
- endoreg_db/models/medical/examination/examination.py +39 -20
- endoreg_db/models/medical/examination/examination_indication.py +30 -95
- endoreg_db/models/medical/examination/examination_time.py +23 -8
- endoreg_db/models/medical/examination/examination_time_type.py +9 -6
- endoreg_db/models/medical/examination/examination_type.py +3 -4
- endoreg_db/models/medical/finding/finding.py +32 -40
- endoreg_db/models/medical/finding/finding_classification.py +42 -72
- endoreg_db/models/medical/finding/finding_intervention.py +25 -22
- endoreg_db/models/medical/finding/finding_type.py +13 -12
- endoreg_db/models/medical/hardware/endoscope.py +26 -26
- endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
- endoreg_db/models/medical/laboratory/lab_value.py +62 -91
- endoreg_db/models/medical/medication/medication.py +22 -10
- endoreg_db/models/medical/medication/medication_indication.py +29 -3
- endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
- endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
- endoreg_db/models/medical/medication/medication_schedule.py +27 -16
- endoreg_db/models/medical/organ/__init__.py +15 -12
- endoreg_db/models/medical/patient/medication_examples.py +6 -6
- endoreg_db/models/medical/patient/patient_disease.py +20 -23
- endoreg_db/models/medical/patient/patient_event.py +19 -22
- endoreg_db/models/medical/patient/patient_examination.py +48 -54
- endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
- endoreg_db/models/medical/patient/patient_finding.py +122 -139
- endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
- endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
- endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
- endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
- endoreg_db/models/medical/patient/patient_medication.py +27 -38
- endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
- endoreg_db/models/medical/risk/risk.py +7 -6
- endoreg_db/models/medical/risk/risk_type.py +8 -5
- endoreg_db/models/metadata/model_meta.py +60 -29
- endoreg_db/models/metadata/model_meta_logic.py +125 -18
- endoreg_db/models/metadata/pdf_meta.py +31 -24
- endoreg_db/models/metadata/sensitive_meta.py +105 -85
- endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
- endoreg_db/models/metadata/video_meta.py +51 -31
- endoreg_db/models/metadata/video_prediction_logic.py +16 -23
- endoreg_db/models/metadata/video_prediction_meta.py +29 -33
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
- endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
- endoreg_db/models/other/emission/emission_factor.py +18 -8
- endoreg_db/models/other/gender.py +10 -5
- endoreg_db/models/other/information_source.py +50 -29
- endoreg_db/models/other/material.py +9 -5
- endoreg_db/models/other/resource.py +6 -4
- endoreg_db/models/other/tag.py +10 -5
- endoreg_db/models/other/transport_route.py +13 -8
- endoreg_db/models/other/unit.py +10 -6
- endoreg_db/models/other/waste.py +6 -5
- endoreg_db/models/report/report.py +6 -0
- endoreg_db/models/requirement/requirement.py +329 -361
- endoreg_db/models/requirement/requirement_error.py +85 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
- endoreg_db/models/requirement/requirement_operator.py +103 -112
- endoreg_db/models/requirement/requirement_set.py +74 -57
- endoreg_db/models/state/__init__.py +4 -4
- endoreg_db/models/state/abstract.py +2 -2
- endoreg_db/models/state/anonymization.py +12 -0
- endoreg_db/models/state/audit_ledger.py +49 -51
- endoreg_db/models/state/label_video_segment.py +9 -0
- endoreg_db/models/state/raw_pdf.py +101 -68
- endoreg_db/models/state/sensitive_meta.py +6 -2
- endoreg_db/models/state/video.py +110 -90
- endoreg_db/models/upload_job.py +35 -34
- endoreg_db/models/utils.py +28 -25
- endoreg_db/queries/__init__.py +3 -1
- endoreg_db/root_urls.py +21 -2
- endoreg_db/schemas/examination_evaluation.py +1 -1
- endoreg_db/serializers/__init__.py +2 -10
- endoreg_db/serializers/anonymization.py +18 -10
- endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
- endoreg_db/serializers/meta/__init__.py +1 -6
- endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
- endoreg_db/serializers/misc/file_overview.py +11 -99
- endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
- endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
- endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
- endoreg_db/serializers/requirements/requirement_sets.py +92 -22
- endoreg_db/serializers/video/segmentation.py +2 -1
- endoreg_db/serializers/video/video_file_list.py +65 -34
- endoreg_db/serializers/video/video_processing_history.py +20 -5
- endoreg_db/services/__old/pdf_import.py +1487 -0
- endoreg_db/services/__old/video_import.py +1306 -0
- endoreg_db/services/anonymization.py +128 -89
- endoreg_db/services/lookup_service.py +65 -52
- endoreg_db/services/lookup_store.py +2 -2
- endoreg_db/services/pdf_import.py +0 -1382
- endoreg_db/services/report_import.py +10 -0
- endoreg_db/services/video_import.py +6 -1255
- endoreg_db/tasks/upload_tasks.py +79 -70
- endoreg_db/tasks/video_ingest.py +8 -4
- endoreg_db/urls/__init__.py +5 -32
- endoreg_db/urls/ai.py +32 -0
- endoreg_db/urls/media.py +121 -83
- endoreg_db/urls/root_urls.py +29 -0
- endoreg_db/utils/__init__.py +15 -5
- endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/dataloader.py +142 -40
- endoreg_db/utils/defaults/set_default_center.py +32 -0
- endoreg_db/utils/names.py +22 -16
- endoreg_db/utils/paths.py +110 -46
- endoreg_db/utils/permissions.py +2 -1
- endoreg_db/utils/pipelines/Readme.md +1 -1
- endoreg_db/utils/pipelines/process_video_dir.py +1 -1
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
- endoreg_db/utils/setup_config.py +8 -5
- endoreg_db/utils/storage.py +115 -0
- endoreg_db/utils/validate_endo_roi.py +8 -2
- endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
- endoreg_db/views/__init__.py +85 -183
- endoreg_db/views/ai/__init__.py +8 -0
- endoreg_db/views/ai/label.py +155 -0
- endoreg_db/views/anonymization/media_management.py +202 -166
- endoreg_db/views/anonymization/overview.py +99 -67
- endoreg_db/views/anonymization/validate.py +182 -44
- endoreg_db/views/media/__init__.py +7 -20
- endoreg_db/views/media/pdf_media.py +197 -174
- endoreg_db/views/media/sensitive_metadata.py +193 -138
- endoreg_db/views/media/video_media.py +89 -82
- endoreg_db/views/meta/__init__.py +0 -8
- endoreg_db/views/misc/__init__.py +1 -7
- endoreg_db/views/misc/upload_views.py +94 -93
- endoreg_db/views/patient/patient.py +5 -4
- endoreg_db/views/report/__init__.py +5 -7
- endoreg_db/views/{pdf → report}/reimport.py +22 -22
- endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
- endoreg_db/views/requirement/evaluate.py +188 -187
- endoreg_db/views/requirement/lookup.py +17 -3
- endoreg_db/views/requirement/lookup_store.py +22 -90
- endoreg_db/views/requirement/requirement_utils.py +89 -0
- endoreg_db/views/video/__init__.py +23 -24
- endoreg_db/views/video/correction.py +201 -172
- endoreg_db/views/video/reimport.py +1 -1
- endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
- endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
- endoreg_db/views/video/video_stream.py +7 -8
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
- endoreg_db/data/finding/anatomy_colon.yaml +0 -128
- endoreg_db/data/finding/colonoscopy.yaml +0 -40
- endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
- endoreg_db/data/finding/complication.yaml +0 -16
- endoreg_db/data/finding/data.yaml +0 -105
- endoreg_db/data/finding/examination_setting.yaml +0 -16
- endoreg_db/data/finding/medication_related.yaml +0 -18
- endoreg_db/data/finding/outcome.yaml +0 -12
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
- endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
- endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
- endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
- endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
- endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
- endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
- endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
- endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
- endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
- endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
- endoreg_db/data/finding_classification/medication_related.yaml +0 -23
- endoreg_db/data/finding_classification/visualized.yaml +0 -33
- endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
- endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
- endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
- endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
- endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
- endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
- endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
- endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
- endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
- endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
- endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
- endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
- endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
- endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
- endoreg_db/data/requirement/age.yaml +0 -26
- endoreg_db/data/requirement/gender.yaml +0 -25
- endoreg_db/management/commands/init_default_ai_model.py +0 -112
- endoreg_db/management/commands/reset_celery_schedule.py +0 -9
- endoreg_db/management/commands/validate_video.py +0 -204
- endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
- endoreg_db/migrations/0003_add_center_display_name.py +0 -30
- endoreg_db/models/administration/permissions/__init__.py +0 -44
- endoreg_db/models/rule/__init__.py +0 -13
- endoreg_db/models/rule/rule.py +0 -27
- endoreg_db/models/rule/rule_applicator.py +0 -224
- endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
- endoreg_db/models/rule/rule_type.py +0 -20
- endoreg_db/models/rule/ruleset.py +0 -17
- endoreg_db/renames.yml +0 -8
- endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
- endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
- endoreg_db/serializers/_old/video.py +0 -71
- endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
- endoreg_db/serializers/meta/report_meta.py +0 -53
- endoreg_db/serializers/report/__init__.py +0 -9
- endoreg_db/serializers/report/mixins.py +0 -45
- endoreg_db/serializers/report/report.py +0 -105
- endoreg_db/serializers/report/report_list.py +0 -22
- endoreg_db/serializers/report/secure_file_url.py +0 -26
- endoreg_db/serializers/video/video_metadata.py +0 -105
- endoreg_db/services/requirements_object.py +0 -147
- endoreg_db/services/storage_aware_video_processor.py +0 -344
- endoreg_db/urls/files.py +0 -6
- endoreg_db/urls/label_video_segment_validate.py +0 -33
- endoreg_db/urls/label_video_segments.py +0 -46
- endoreg_db/urls/report.py +0 -48
- endoreg_db/urls/video.py +0 -61
- endoreg_db/utils/case_generator/case_generator.py +0 -159
- endoreg_db/utils/case_generator/utils.py +0 -30
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
- endoreg_db/views/label/__init__.py +0 -5
- endoreg_db/views/label/label.py +0 -15
- endoreg_db/views/label_video_segment/__init__.py +0 -16
- endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
- endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
- endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
- endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
- endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
- endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
- endoreg_db/views/label_video_segment/validate.py +0 -226
- endoreg_db/views/media/segments.py +0 -71
- endoreg_db/views/meta/available_files_list.py +0 -146
- endoreg_db/views/meta/report_meta.py +0 -53
- endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
- endoreg_db/views/misc/secure_file_serving_view.py +0 -80
- endoreg_db/views/misc/secure_file_url_view.py +0 -84
- endoreg_db/views/misc/secure_url_validate.py +0 -79
- endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
- endoreg_db/views/patient_finding_location/__init__.py +0 -5
- endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
- endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
- endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
- endoreg_db/views/pdf/__init__.py +0 -8
- endoreg_db/views/report/report_list.py +0 -112
- endoreg_db/views/report/report_with_secure_url.py +0 -28
- endoreg_db/views/report/start_examination.py +0 -7
- endoreg_db/views/video/segmentation.py +0 -274
- endoreg_db/views/video/task_status.py +0 -49
- endoreg_db/views/video/timeline.py +0 -46
- endoreg_db/views/video/video_analyze.py +0 -52
- endoreg_db/views.py +0 -0
- /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
- /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
- /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
- /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
- /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
- /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
- /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
- /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
- /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
- /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
- /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
- /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
- /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,70 +1,73 @@
|
|
|
1
|
-
import shutil
|
|
2
1
|
import logging
|
|
2
|
+
import shutil
|
|
3
3
|
import uuid
|
|
4
|
+
from importlib import import_module
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import TYPE_CHECKING, Optional, Type
|
|
6
7
|
|
|
7
8
|
# Import the new exceptions from the correct path
|
|
8
9
|
from endoreg_db.exceptions import InsufficientStorageError, TranscodingError
|
|
9
|
-
from
|
|
10
|
-
from importlib import import_module
|
|
10
|
+
from endoreg_db.utils.paths import IMPORT_VIDEO_DIR, SENSITIVE_VIDEO_DIR, TRANSCODING_DIR
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
13
|
from endoreg_db.models import VideoFile
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
from ....utils.hashs import get_video_hash
|
|
15
|
+
import endoreg_db.utils.paths as path_utils
|
|
17
16
|
from ....utils.file_operations import get_uuid_filename
|
|
17
|
+
from ....utils.hashs import get_video_hash
|
|
18
|
+
from ....utils.video.ffmpeg_wrapper import transcode_videofile_if_required
|
|
18
19
|
|
|
19
20
|
logger = logging.getLogger(__name__)
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
def check_storage_capacity(
|
|
23
|
+
def check_storage_capacity(
|
|
24
|
+
src_path: Path, dst_root: Path, safety_margin: float = 1.2
|
|
25
|
+
) -> None:
|
|
23
26
|
"""
|
|
24
27
|
Check if there's enough storage space before starting operations.
|
|
25
|
-
|
|
28
|
+
|
|
26
29
|
Args:
|
|
27
30
|
src_path: Source file path
|
|
28
31
|
dst_root: Destination root directory
|
|
29
32
|
safety_margin: Safety factor (1.2 = 20% extra space required)
|
|
30
|
-
|
|
33
|
+
|
|
31
34
|
Raises:
|
|
32
35
|
InsufficientStorageError: If insufficient storage space
|
|
33
36
|
"""
|
|
34
37
|
try:
|
|
35
38
|
src_size = src_path.stat().st_size
|
|
36
39
|
required_space = int(src_size * safety_margin)
|
|
37
|
-
|
|
40
|
+
|
|
38
41
|
# Check free space on destination
|
|
39
42
|
free_space = shutil.disk_usage(dst_root).free
|
|
40
|
-
|
|
43
|
+
|
|
41
44
|
if free_space < required_space:
|
|
42
45
|
raise InsufficientStorageError(
|
|
43
|
-
f"Insufficient storage space. Required: {required_space/1e9:.1f} GB, "
|
|
44
|
-
f"Available: {free_space/1e9:.1f} GB on {dst_root}",
|
|
46
|
+
f"Insufficient storage space. Required: {required_space / 1e9:.1f} GB, Available: {free_space / 1e9:.1f} GB on {dst_root}",
|
|
45
47
|
required_space=required_space,
|
|
46
|
-
available_space=free_space
|
|
48
|
+
available_space=free_space,
|
|
47
49
|
)
|
|
48
|
-
|
|
49
|
-
logger.info(
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
|
|
51
|
+
logger.info(
|
|
52
|
+
f"Storage check passed: {free_space / 1e9:.1f} GB available, {required_space / 1e9:.1f} GB required"
|
|
53
|
+
)
|
|
54
|
+
|
|
52
55
|
except OSError as e:
|
|
53
56
|
logger.warning(f"Could not check storage capacity: {e}")
|
|
54
57
|
# Don't fail the operation, just log the warning
|
|
55
58
|
|
|
56
59
|
|
|
57
|
-
def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
|
|
60
|
+
def atomic_copy_with_fallback(src_path: Path = IMPORT_VIDEO_DIR, dst_path: Path = SENSITIVE_VIDEO_DIR) -> bool:
|
|
58
61
|
"""
|
|
59
62
|
Atomically copy file from src to dst, preserving the source file.
|
|
60
|
-
|
|
63
|
+
|
|
61
64
|
Args:
|
|
62
65
|
src_path: Source file path
|
|
63
66
|
dst_path: Destination file path
|
|
64
|
-
|
|
67
|
+
|
|
65
68
|
Returns:
|
|
66
69
|
True if successful
|
|
67
|
-
|
|
70
|
+
|
|
68
71
|
Raises:
|
|
69
72
|
InsufficientStorageError: If not enough space for the operation
|
|
70
73
|
OSError: For other file system errors
|
|
@@ -73,18 +76,17 @@ def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
|
|
|
73
76
|
# Check space before copy
|
|
74
77
|
src_size = src_path.stat().st_size
|
|
75
78
|
free_space = shutil.disk_usage(dst_path.parent).free
|
|
76
|
-
|
|
79
|
+
|
|
77
80
|
if free_space < src_size * 1.1: # 10% safety margin
|
|
78
81
|
raise InsufficientStorageError(
|
|
79
|
-
f"Insufficient space for copy operation. Required: {src_size/1e9:.1f} GB, "
|
|
80
|
-
f"Available: {free_space/1e9:.1f} GB",
|
|
82
|
+
f"Insufficient space for copy operation. Required: {src_size / 1e9:.1f} GB, Available: {free_space / 1e9:.1f} GB",
|
|
81
83
|
required_space=src_size,
|
|
82
|
-
available_space=free_space
|
|
84
|
+
available_space=free_space,
|
|
83
85
|
)
|
|
84
|
-
|
|
86
|
+
|
|
85
87
|
# Use a temporary name during copy for atomicity
|
|
86
|
-
temp_dst = dst_path.with_suffix(dst_path.suffix +
|
|
87
|
-
|
|
88
|
+
temp_dst = dst_path.with_suffix(dst_path.suffix + ".tmp")
|
|
89
|
+
|
|
88
90
|
try:
|
|
89
91
|
shutil.copy2(str(src_path), str(temp_dst))
|
|
90
92
|
temp_dst.rename(dst_path)
|
|
@@ -95,7 +97,7 @@ def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
|
|
|
95
97
|
if temp_dst.exists():
|
|
96
98
|
temp_dst.unlink(missing_ok=True)
|
|
97
99
|
raise
|
|
98
|
-
|
|
100
|
+
|
|
99
101
|
except Exception as e:
|
|
100
102
|
logger.error(f"Copy operation failed: {src_path} -> {dst_path}: {e}")
|
|
101
103
|
raise
|
|
@@ -104,14 +106,14 @@ def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
|
|
|
104
106
|
def atomic_move_with_fallback(src_path: Path, dst_path: Path) -> bool:
|
|
105
107
|
"""
|
|
106
108
|
Atomically move file from src to dst, with fallback to copy+remove.
|
|
107
|
-
|
|
109
|
+
|
|
108
110
|
Args:
|
|
109
111
|
src_path: Source file path
|
|
110
112
|
dst_path: Destination file path
|
|
111
|
-
|
|
113
|
+
|
|
112
114
|
Returns:
|
|
113
115
|
True if successful
|
|
114
|
-
|
|
116
|
+
|
|
115
117
|
Raises:
|
|
116
118
|
InsufficientStorageError: If not enough space for the operation
|
|
117
119
|
OSError: For other file system errors
|
|
@@ -127,32 +129,31 @@ def atomic_move_with_fallback(src_path: Path, dst_path: Path) -> bool:
|
|
|
127
129
|
logger.debug("Cross-device move detected, falling back to copy+remove")
|
|
128
130
|
else:
|
|
129
131
|
raise
|
|
130
|
-
|
|
132
|
+
|
|
131
133
|
# Check space before cross-filesystem copy
|
|
132
134
|
src_size = src_path.stat().st_size
|
|
133
135
|
free_space = shutil.disk_usage(dst_path.parent).free
|
|
134
|
-
|
|
136
|
+
|
|
135
137
|
if free_space < src_size * 1.1: # 10% safety margin
|
|
136
138
|
raise InsufficientStorageError(
|
|
137
|
-
f"Insufficient space for copy operation. Required: {src_size/1e9:.1f} GB, "
|
|
138
|
-
f"Available: {free_space/1e9:.1f} GB",
|
|
139
|
+
f"Insufficient space for copy operation. Required: {src_size / 1e9:.1f} GB, Available: {free_space / 1e9:.1f} GB",
|
|
139
140
|
required_space=src_size,
|
|
140
|
-
available_space=free_space
|
|
141
|
+
available_space=free_space,
|
|
141
142
|
)
|
|
142
|
-
|
|
143
|
+
|
|
143
144
|
# Fallback to copy+remove for cross-filesystem moves
|
|
144
145
|
logger.info(f"Copying file (cross-filesystem): {src_path} -> {dst_path}")
|
|
145
|
-
|
|
146
|
+
|
|
146
147
|
# Use a temporary name during copy for atomicity
|
|
147
|
-
temp_dst = dst_path.with_suffix(dst_path.suffix +
|
|
148
|
-
|
|
148
|
+
temp_dst = dst_path.with_suffix(dst_path.suffix + ".tmp")
|
|
149
|
+
|
|
149
150
|
try:
|
|
150
151
|
shutil.copy2(str(src_path), str(temp_dst))
|
|
151
152
|
temp_dst.rename(dst_path)
|
|
152
153
|
src_path.unlink() # Remove source only after successful copy
|
|
153
154
|
logger.debug(f"Copy+remove successful: {src_path} -> {dst_path}")
|
|
154
155
|
return True
|
|
155
|
-
|
|
156
|
+
|
|
156
157
|
except OSError as e:
|
|
157
158
|
# Clean up temp file on failure
|
|
158
159
|
if temp_dst.exists():
|
|
@@ -162,10 +163,10 @@ def atomic_move_with_fallback(src_path: Path, dst_path: Path) -> bool:
|
|
|
162
163
|
raise InsufficientStorageError(
|
|
163
164
|
f"No space left on device during copy: {e}",
|
|
164
165
|
required_space=src_path.stat().st_size,
|
|
165
|
-
available_space=shutil.disk_usage(dst_path.parent).free
|
|
166
|
+
available_space=shutil.disk_usage(dst_path.parent).free,
|
|
166
167
|
)
|
|
167
168
|
raise
|
|
168
|
-
|
|
169
|
+
|
|
169
170
|
except Exception as e:
|
|
170
171
|
logger.error(f"Failed to move {src_path} -> {dst_path}: {e}")
|
|
171
172
|
raise
|
|
@@ -192,14 +193,14 @@ def _create_from_file(
|
|
|
192
193
|
file_path: Path,
|
|
193
194
|
center_name: str,
|
|
194
195
|
processor_name: Optional[str] = None,
|
|
195
|
-
video_dir: Path =
|
|
196
|
+
video_dir: Path = IMPORT_VIDEO_DIR,
|
|
196
197
|
save: bool = True,
|
|
197
198
|
delete_source: bool = False,
|
|
198
|
-
**kwargs
|
|
199
|
+
**kwargs,
|
|
199
200
|
) -> "VideoFile":
|
|
200
201
|
"""
|
|
201
202
|
Creates a VideoFile instance from a given video file path with improved error handling.
|
|
202
|
-
|
|
203
|
+
|
|
203
204
|
Raises:
|
|
204
205
|
InsufficientStorageError: When not enough disk space
|
|
205
206
|
TranscodingError: When video transcoding fails
|
|
@@ -208,7 +209,7 @@ def _create_from_file(
|
|
|
208
209
|
"""
|
|
209
210
|
from endoreg_db.models.administration.center.center import Center
|
|
210
211
|
from endoreg_db.models.medical.hardware import EndoscopyProcessor
|
|
211
|
-
|
|
212
|
+
|
|
212
213
|
original_file_name = file_path.name
|
|
213
214
|
original_suffix = file_path.suffix
|
|
214
215
|
final_storage_path = None
|
|
@@ -223,25 +224,28 @@ def _create_from_file(
|
|
|
223
224
|
resolved_storage_root = _get_path(data_paths, "storage", storage_root_default)
|
|
224
225
|
storage_root = Path(resolved_storage_root)
|
|
225
226
|
storage_root.mkdir(parents=True, exist_ok=True)
|
|
226
|
-
|
|
227
|
+
|
|
227
228
|
# Check storage capacity before starting any work
|
|
228
229
|
check_storage_capacity(file_path, storage_root)
|
|
229
230
|
|
|
230
231
|
# 1. Transcode if necessary
|
|
231
232
|
logger.debug("Checking transcoding requirement for %s", file_path)
|
|
232
|
-
temp_transcode_dir =
|
|
233
|
+
temp_transcode_dir = TRANSCODING_DIR
|
|
233
234
|
temp_transcode_dir.mkdir(parents=True, exist_ok=True)
|
|
234
|
-
|
|
235
|
+
|
|
235
236
|
# Use a unique name for the potential transcoded file
|
|
236
|
-
temp_transcoded_output_path =
|
|
237
|
+
temp_transcoded_output_path = (
|
|
238
|
+
temp_transcode_dir / f"{uuid.uuid4()}{original_suffix}"
|
|
239
|
+
)
|
|
237
240
|
|
|
238
241
|
try:
|
|
239
242
|
transcoded_file_path = transcode_videofile_if_required(
|
|
240
|
-
input_path=file_path,
|
|
241
|
-
output_path=temp_transcoded_output_path
|
|
243
|
+
input_path=file_path, output_path=temp_transcoded_output_path
|
|
242
244
|
)
|
|
243
245
|
if transcoded_file_path is None:
|
|
244
|
-
raise TranscodingError(
|
|
246
|
+
raise TranscodingError(
|
|
247
|
+
f"Transcoding check/process failed for {file_path}"
|
|
248
|
+
)
|
|
245
249
|
except Exception as e:
|
|
246
250
|
raise TranscodingError(f"Video transcoding failed: {e}") from e
|
|
247
251
|
|
|
@@ -250,24 +254,42 @@ def _create_from_file(
|
|
|
250
254
|
# 2. Calculate hash (this will be the raw_video_hash)
|
|
251
255
|
video_hash = get_video_hash(transcoded_file_path)
|
|
252
256
|
if not video_hash:
|
|
253
|
-
raise ValueError(
|
|
254
|
-
|
|
257
|
+
raise ValueError(
|
|
258
|
+
f"Could not calculate video hash for {transcoded_file_path}"
|
|
259
|
+
)
|
|
260
|
+
logger.info(
|
|
261
|
+
"Calculated raw video hash: %s for %s", video_hash, original_file_name
|
|
262
|
+
)
|
|
255
263
|
|
|
256
264
|
# 3. Check if hash already exists
|
|
257
265
|
if cls_model.check_hash_exists(video_hash=video_hash):
|
|
258
266
|
existing_video = cls_model.objects.get(video_hash=video_hash)
|
|
259
|
-
logger.warning(
|
|
260
|
-
|
|
267
|
+
logger.warning(
|
|
268
|
+
"Video with hash %s already exists (UUID: %s)",
|
|
269
|
+
video_hash,
|
|
270
|
+
existing_video.uuid,
|
|
271
|
+
)
|
|
272
|
+
|
|
261
273
|
# Check if the existing video has a valid file
|
|
262
274
|
existing_raw_path = existing_video.get_raw_file_path()
|
|
263
|
-
if
|
|
264
|
-
|
|
275
|
+
if (
|
|
276
|
+
existing_video.has_raw
|
|
277
|
+
and existing_raw_path
|
|
278
|
+
and existing_raw_path.exists()
|
|
279
|
+
):
|
|
280
|
+
logger.warning(
|
|
281
|
+
"Video with hash %s already exists and file is present. Returning existing instance.",
|
|
282
|
+
video_hash,
|
|
283
|
+
)
|
|
265
284
|
# Clean up transcoded file if it was created temporarily
|
|
266
285
|
if transcoded_file_path != file_path and transcoded_file_path.exists():
|
|
267
286
|
transcoded_file_path.unlink(missing_ok=True)
|
|
268
287
|
return existing_video
|
|
269
288
|
|
|
270
|
-
logger.warning(
|
|
289
|
+
logger.warning(
|
|
290
|
+
"Video with hash %s exists but file is missing. Deleting orphaned record.",
|
|
291
|
+
video_hash,
|
|
292
|
+
)
|
|
271
293
|
existing_video.delete()
|
|
272
294
|
|
|
273
295
|
# 4. Generate UUID and final storage path
|
|
@@ -278,16 +300,26 @@ def _create_from_file(
|
|
|
278
300
|
# 5. Move or Copy the file to final storage using improved method
|
|
279
301
|
try:
|
|
280
302
|
if delete_source and transcoded_file_path == file_path:
|
|
281
|
-
logger.debug(
|
|
303
|
+
logger.debug(
|
|
304
|
+
"Moving original file %s to %s", file_path, final_storage_path
|
|
305
|
+
)
|
|
282
306
|
atomic_move_with_fallback(file_path, final_storage_path)
|
|
283
307
|
elif delete_source and transcoded_file_path != file_path:
|
|
284
|
-
logger.debug(
|
|
308
|
+
logger.debug(
|
|
309
|
+
"Moving transcoded file %s to %s",
|
|
310
|
+
transcoded_file_path,
|
|
311
|
+
final_storage_path,
|
|
312
|
+
)
|
|
285
313
|
atomic_move_with_fallback(transcoded_file_path, final_storage_path)
|
|
286
314
|
else:
|
|
287
|
-
logger.debug(
|
|
315
|
+
logger.debug(
|
|
316
|
+
"Copying file %s to %s", transcoded_file_path, final_storage_path
|
|
317
|
+
)
|
|
288
318
|
atomic_copy_with_fallback(transcoded_file_path, final_storage_path)
|
|
289
319
|
if transcoded_file_path != file_path and transcoded_file_path.exists():
|
|
290
|
-
logger.debug(
|
|
320
|
+
logger.debug(
|
|
321
|
+
"Cleaning up temporary transcoded file %s", transcoded_file_path
|
|
322
|
+
)
|
|
291
323
|
transcoded_file_path.unlink(missing_ok=True)
|
|
292
324
|
except InsufficientStorageError:
|
|
293
325
|
# Re-raise storage errors as-is
|
|
@@ -298,15 +330,29 @@ def _create_from_file(
|
|
|
298
330
|
# 6. Verify hash after move/copy
|
|
299
331
|
final_hash = get_video_hash(final_storage_path)
|
|
300
332
|
if final_hash != video_hash:
|
|
301
|
-
logger.error(
|
|
333
|
+
logger.error(
|
|
334
|
+
"Hash mismatch after file operation! Expected %s, got %s",
|
|
335
|
+
video_hash,
|
|
336
|
+
final_hash,
|
|
337
|
+
)
|
|
302
338
|
final_storage_path.unlink(missing_ok=True)
|
|
303
|
-
raise RuntimeError(
|
|
339
|
+
raise RuntimeError(
|
|
340
|
+
f"Hash mismatch after file operation for {final_storage_path}"
|
|
341
|
+
)
|
|
304
342
|
|
|
305
343
|
# 7. Get related objects
|
|
306
344
|
try:
|
|
307
345
|
center = Center.objects.get(name=center_name)
|
|
308
|
-
processor =
|
|
309
|
-
|
|
346
|
+
processor = (
|
|
347
|
+
EndoscopyProcessor.objects.get(name=processor_name)
|
|
348
|
+
if processor_name
|
|
349
|
+
else None
|
|
350
|
+
)
|
|
351
|
+
logger.debug(
|
|
352
|
+
"Found Center: %s, Processor: %s",
|
|
353
|
+
center.name,
|
|
354
|
+
processor.name if processor else "None",
|
|
355
|
+
)
|
|
310
356
|
except Center.DoesNotExist as e:
|
|
311
357
|
logger.error("Center '%s' not found", center_name)
|
|
312
358
|
if final_storage_path and final_storage_path.exists():
|
|
@@ -321,8 +367,10 @@ def _create_from_file(
|
|
|
321
367
|
# 8. Create the VideoFile instance
|
|
322
368
|
logger.info("Creating new VideoFile instance with UUID: %s", uuid_val)
|
|
323
369
|
# Store FileField path relative to storage root including the videos prefix
|
|
324
|
-
|
|
325
|
-
|
|
370
|
+
# TODO Review removal, since this is now newly handled by path_utils
|
|
371
|
+
#storage_base = Path(_get_path(data_paths, "storage", final_storage_path.parent))
|
|
372
|
+
|
|
373
|
+
relative_name = path_utils.to_storage_relative(final_storage_path)
|
|
326
374
|
video = cls_model(
|
|
327
375
|
uuid=uuid_val,
|
|
328
376
|
raw_file=relative_name,
|
|
@@ -339,7 +387,9 @@ def _create_from_file(
|
|
|
339
387
|
if save:
|
|
340
388
|
logger.info("Saving new VideoFile instance (UUID: %s)", uuid_val)
|
|
341
389
|
video.save()
|
|
342
|
-
logger.info(
|
|
390
|
+
logger.info(
|
|
391
|
+
"Successfully created VideoFile PK %s (UUID: %s)", video.pk, video.uuid
|
|
392
|
+
)
|
|
343
393
|
|
|
344
394
|
return video
|
|
345
395
|
|
|
@@ -347,12 +397,24 @@ def _create_from_file(
|
|
|
347
397
|
# Re-raise these specific errors as-is
|
|
348
398
|
raise
|
|
349
399
|
except Exception as e:
|
|
350
|
-
logger.error(
|
|
400
|
+
logger.error(
|
|
401
|
+
"Failed to create VideoFile from %s: (%s) %s",
|
|
402
|
+
file_path,
|
|
403
|
+
type(e).__name__,
|
|
404
|
+
e,
|
|
405
|
+
exc_info=True,
|
|
406
|
+
)
|
|
351
407
|
# Clean up any created files
|
|
352
408
|
if final_storage_path and final_storage_path.exists():
|
|
353
409
|
logger.warning("Cleaning up orphaned file: %s", final_storage_path)
|
|
354
410
|
final_storage_path.unlink(missing_ok=True)
|
|
355
|
-
if
|
|
356
|
-
|
|
411
|
+
if (
|
|
412
|
+
transcoded_file_path
|
|
413
|
+
and transcoded_file_path != file_path
|
|
414
|
+
and transcoded_file_path.exists()
|
|
415
|
+
):
|
|
416
|
+
logger.warning(
|
|
417
|
+
"Cleaning up orphaned transcoded file: %s", transcoded_file_path
|
|
418
|
+
)
|
|
357
419
|
transcoded_file_path.unlink(missing_ok=True)
|
|
358
|
-
raise RuntimeError(f"Video processing failed: {e}") from e
|
|
420
|
+
raise RuntimeError(f"Video processing failed: {e}") from e
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
from itertools import filterfalse
|
|
2
1
|
import logging
|
|
3
2
|
from typing import TYPE_CHECKING
|
|
4
|
-
from django.db import transaction
|
|
5
3
|
|
|
4
|
+
from django.db import transaction
|
|
6
5
|
|
|
7
6
|
# Configure logging
|
|
8
|
-
logger = logging.getLogger(__name__)
|
|
7
|
+
logger = logging.getLogger(__name__) # Changed from "video_file"
|
|
9
8
|
|
|
10
9
|
if TYPE_CHECKING:
|
|
11
10
|
from endoreg_db.models import VideoFile, VideoState
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
|
|
13
|
+
def _pipe_2(video_file: "VideoFile") -> bool:
|
|
14
14
|
"""
|
|
15
15
|
Process the given video file through pipeline 2 operations which include frame extraction,
|
|
16
16
|
anonymization of the video, and deletion of sensitive meta data.
|
|
@@ -70,11 +70,10 @@ def _pipe_2(video_file:"VideoFile") -> bool:
|
|
|
70
70
|
logger.info("Pipe 2: Anonymization complete.")
|
|
71
71
|
else:
|
|
72
72
|
logger.info("Pipe 2: Video already anonymized.")
|
|
73
|
-
|
|
74
73
|
|
|
75
74
|
# --- Part 3: Final DB operations (now in its own atomic transaction) ---
|
|
76
75
|
with transaction.atomic():
|
|
77
|
-
video_file.refresh_from_db()
|
|
76
|
+
video_file.refresh_from_db() # Ensure we have the latest video_file state for these ops
|
|
78
77
|
|
|
79
78
|
# Set sensitive_meta_processed True atomically
|
|
80
79
|
state: "VideoState" = video_file.get_or_create_state()
|
|
@@ -86,8 +85,8 @@ def _pipe_2(video_file:"VideoFile") -> bool:
|
|
|
86
85
|
try:
|
|
87
86
|
sm_pk = video_file.sensitive_meta.pk
|
|
88
87
|
video_file.sensitive_meta.delete()
|
|
89
|
-
video_file.sensitive_meta = None
|
|
90
|
-
video_file.save(update_fields=[
|
|
88
|
+
video_file.sensitive_meta = None # Important after SET_NULL
|
|
89
|
+
video_file.save(update_fields=["sensitive_meta"]) # Persist the null relation
|
|
91
90
|
logger.info("Pipe 2: Deleted sensitive meta object (PK: %s).", sm_pk)
|
|
92
91
|
except Exception as e:
|
|
93
92
|
logger.error("Pipe 2: Failed to delete sensitive meta object: %s", e, exc_info=True)
|
|
@@ -102,4 +101,4 @@ def _pipe_2(video_file:"VideoFile") -> bool:
|
|
|
102
101
|
# This will catch exceptions from I/O operations if they raise,
|
|
103
102
|
# or from the final transaction block, or any other unhandled error.
|
|
104
103
|
logger.error(f"Pipe 2 failed for video {video_file.uuid} with unhandled exception: {e}", exc_info=True)
|
|
105
|
-
return False
|
|
104
|
+
return False
|