endoreg-db 0.8.6.4__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/__init__.py +0 -0
- endoreg_db/admin.py +92 -0
- endoreg_db/api/serializers/finding_descriptions.py +0 -0
- endoreg_db/api/views/finding_descriptions.py +0 -0
- endoreg_db/api_urls.py +4 -0
- endoreg_db/apps.py +18 -0
- endoreg_db/assets/dummy_model.ckpt +1 -0
- endoreg_db/codemods/readme.md +88 -0
- endoreg_db/codemods/rename_datetime_fields.py +92 -0
- endoreg_db/config/__init__.py +0 -0
- endoreg_db/config/env.py +101 -0
- endoreg_db/data/__init__.py +144 -0
- endoreg_db/data/ai_model/data.yaml +7 -0
- endoreg_db/data/ai_model_label/label/data.yaml +88 -0
- endoreg_db/data/ai_model_label/label/polyp_classification.yaml +52 -0
- endoreg_db/data/ai_model_label/label-set/data.yaml +40 -0
- endoreg_db/data/ai_model_label/label-set/polyp_classifications.yaml +25 -0
- endoreg_db/data/ai_model_label/label-type/data.yaml +7 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +27 -0
- endoreg_db/data/ai_model_type/data.yaml +7 -0
- endoreg_db/data/ai_model_video_segmentation_label/base_segmentation.yaml +176 -0
- endoreg_db/data/ai_model_video_segmentation_labelset/data.yaml +20 -0
- endoreg_db/data/case_template/rule/00_patient_lab_sample_add_default_value.yaml +167 -0
- endoreg_db/data/case_template/rule/01_patient-set-age.yaml +8 -0
- endoreg_db/data/case_template/rule/01_patient-set-gender.yaml +9 -0
- endoreg_db/data/case_template/rule/11_create_patient_lab_sample.yaml +23 -0
- endoreg_db/data/case_template/rule/12_create-patient_medication-anticoagulation.yaml +19 -0
- endoreg_db/data/case_template/rule/13_create-patient_medication_schedule-anticoagulation.yaml +19 -0
- endoreg_db/data/case_template/rule/19_create_patient.yaml +17 -0
- endoreg_db/data/case_template/rule_type/base_types.yaml +35 -0
- endoreg_db/data/case_template/rule_value/.init +0 -0
- endoreg_db/data/case_template/rule_value_type/base_types.yaml +59 -0
- endoreg_db/data/case_template/template/base.yaml +8 -0
- endoreg_db/data/case_template/template_type/pre_endoscopy.yaml +3 -0
- endoreg_db/data/case_template/tmp/_rule_value +13 -0
- endoreg_db/data/case_template/tmp/rule/01_atrial_fibrillation.yaml +21 -0
- endoreg_db/data/case_template/tmp/rule/02_create_object.yaml +10 -0
- endoreg_db/data/case_template/tmp/template/atrial_fibrillation_low_risk.yaml +7 -0
- endoreg_db/data/center/data.yaml +91 -0
- endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -0
- endoreg_db/data/center_shift/ukw.yaml +9 -0
- endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -0
- endoreg_db/data/contraindication/bleeding.yaml +11 -0
- endoreg_db/data/db_summary.csv +58 -0
- endoreg_db/data/db_summary.xlsx +0 -0
- endoreg_db/data/disease/cardiovascular.yaml +37 -0
- endoreg_db/data/disease/hepatology.yaml +5 -0
- endoreg_db/data/disease/misc.yaml +5 -0
- endoreg_db/data/disease/renal.yaml +5 -0
- endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +6 -0
- endoreg_db/data/disease_classification/coronary_vessel_disease.yaml +6 -0
- endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +41 -0
- endoreg_db/data/disease_classification_choice/coronary_vessel_disease.yaml +20 -0
- endoreg_db/data/distribution/date/patient.yaml +7 -0
- endoreg_db/data/distribution/multiple_categorical/.init +0 -0
- endoreg_db/data/distribution/numeric/data.yaml +14 -0
- endoreg_db/data/distribution/single_categorical/patient.yaml +7 -0
- endoreg_db/data/emission_factor/green_endoscopy_dashboard_EmissionFactor.yaml +132 -0
- endoreg_db/data/endoscope/data.yaml +93 -0
- endoreg_db/data/endoscope_type/data.yaml +11 -0
- endoreg_db/data/endoscopy_processor/data.yaml +50 -0
- endoreg_db/data/event/cardiology.yaml +15 -0
- endoreg_db/data/event/neurology.yaml +14 -0
- endoreg_db/data/event/surgery.yaml +13 -0
- endoreg_db/data/event/thrombembolism.yaml +20 -0
- endoreg_db/data/examination/examinations/data.yaml +72 -0
- endoreg_db/data/examination/time/data.yaml +48 -0
- endoreg_db/data/examination/time-type/data.yaml +8 -0
- endoreg_db/data/examination/type/data.yaml +17 -0
- endoreg_db/data/examination_indication/endoscopy.yaml +424 -0
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +160 -0
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +101 -0
- endoreg_db/data/examination_requirement_set/colonoscopy.yaml +15 -0
- endoreg_db/data/finding/anatomy_colon.yaml +128 -0
- endoreg_db/data/finding/colonoscopy.yaml +40 -0
- endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +56 -0
- endoreg_db/data/finding/complication.yaml +16 -0
- endoreg_db/data/finding/data.yaml +105 -0
- endoreg_db/data/finding/examination_setting.yaml +16 -0
- endoreg_db/data/finding/medication_related.yaml +18 -0
- endoreg_db/data/finding/outcome.yaml +12 -0
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +95 -0
- endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +22 -0
- endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +25 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +68 -0
- endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +80 -0
- endoreg_db/data/finding_classification/colonoscopy_lst.yaml +21 -0
- endoreg_db/data/finding_classification/colonoscopy_nice.yaml +20 -0
- endoreg_db/data/finding_classification/colonoscopy_paris.yaml +26 -0
- endoreg_db/data/finding_classification/colonoscopy_sano.yaml +22 -0
- endoreg_db/data/finding_classification/colonoscopy_summary.yaml +53 -0
- endoreg_db/data/finding_classification/complication_generic.yaml +25 -0
- endoreg_db/data/finding_classification/examination_setting_generic.yaml +40 -0
- endoreg_db/data/finding_classification/histology_colo.yaml +51 -0
- endoreg_db/data/finding_classification/intervention_required.yaml +26 -0
- endoreg_db/data/finding_classification/medication_related.yaml +23 -0
- endoreg_db/data/finding_classification/visualized.yaml +33 -0
- endoreg_db/data/finding_classification_choice/bowel_preparation.yaml +78 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +15 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +17 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_paris.yaml +57 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +14 -0
- endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_location.yaml +229 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +82 -0
- endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
- endoreg_db/data/finding_classification_choice/complication_generic_types.yaml +15 -0
- endoreg_db/data/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
- endoreg_db/data/finding_classification_choice/histology.yaml +24 -0
- endoreg_db/data/finding_classification_choice/histology_polyp.yaml +20 -0
- endoreg_db/data/finding_classification_choice/outcome.yaml +19 -0
- endoreg_db/data/finding_classification_choice/yes_no_na.yaml +11 -0
- endoreg_db/data/finding_classification_type/colonoscopy_basic.yaml +48 -0
- endoreg_db/data/finding_intervention/endoscopy.yaml +43 -0
- endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
- endoreg_db/data/finding_intervention/endoscopy_egd.yaml +128 -0
- endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +32 -0
- endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +9 -0
- endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +36 -0
- endoreg_db/data/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +79 -0
- endoreg_db/data/finding_type/data.yaml +43 -0
- endoreg_db/data/gender/data.yaml +42 -0
- endoreg_db/data/information_source/annotation.yaml +6 -0
- endoreg_db/data/information_source/data.yaml +30 -0
- endoreg_db/data/information_source/endoscopy_guidelines.yaml +7 -0
- endoreg_db/data/information_source/medication.yaml +6 -0
- endoreg_db/data/information_source/prediction.yaml +7 -0
- endoreg_db/data/information_source_type/data.yaml +8 -0
- endoreg_db/data/lab_value/cardiac_enzymes.yaml +37 -0
- endoreg_db/data/lab_value/coagulation.yaml +54 -0
- endoreg_db/data/lab_value/electrolytes.yaml +228 -0
- endoreg_db/data/lab_value/gastrointestinal_function.yaml +133 -0
- endoreg_db/data/lab_value/hematology.yaml +184 -0
- endoreg_db/data/lab_value/hormones.yaml +59 -0
- endoreg_db/data/lab_value/lipids.yaml +53 -0
- endoreg_db/data/lab_value/misc.yaml +76 -0
- endoreg_db/data/lab_value/renal_function.yaml +12 -0
- endoreg_db/data/log_type/data.yaml +57 -0
- endoreg_db/data/lx_client_tag/base.yaml +54 -0
- endoreg_db/data/lx_client_type/base.yaml +30 -0
- endoreg_db/data/lx_permission/base.yaml +24 -0
- endoreg_db/data/lx_permission/endoreg.yaml +52 -0
- endoreg_db/data/material/material.yaml +91 -0
- endoreg_db/data/medication/anticoagulation.yaml +65 -0
- endoreg_db/data/medication/tah.yaml +70 -0
- endoreg_db/data/medication_indication/anticoagulation.yaml +115 -0
- endoreg_db/data/medication_indication_type/data.yaml +11 -0
- endoreg_db/data/medication_indication_type/thrombembolism.yaml +41 -0
- endoreg_db/data/medication_intake_time/base.yaml +31 -0
- endoreg_db/data/medication_schedule/apixaban.yaml +95 -0
- endoreg_db/data/medication_schedule/ass.yaml +12 -0
- endoreg_db/data/medication_schedule/enoxaparin.yaml +26 -0
- endoreg_db/data/names_first/first_names.yaml +54 -0
- endoreg_db/data/names_last/last_names.yaml +51 -0
- endoreg_db/data/network_device/data.yaml +59 -0
- endoreg_db/data/network_device_type/data.yaml +12 -0
- endoreg_db/data/organ/data.yaml +29 -0
- endoreg_db/data/patient_lab_sample_type/generic.yaml +6 -0
- endoreg_db/data/pdf_type/data.yaml +46 -0
- endoreg_db/data/product/green_endoscopy_dashboard_Product.yaml +66 -0
- endoreg_db/data/product_group/green_endoscopy_dashboard_ProductGroup.yaml +33 -0
- endoreg_db/data/product_material/green_endoscopy_dashboard_ProductMaterial.yaml +308 -0
- endoreg_db/data/product_weight/green_endoscopy_dashboard_ProductWeight.yaml +88 -0
- endoreg_db/data/profession/data.yaml +70 -0
- endoreg_db/data/qualification/endoscopy.yaml +36 -0
- endoreg_db/data/qualification/m2.yaml +39 -0
- endoreg_db/data/qualification/outpatient_clinic.yaml +35 -0
- endoreg_db/data/qualification/sonography.yaml +36 -0
- endoreg_db/data/qualification_type/base.yaml +29 -0
- endoreg_db/data/reference_product/green_endoscopy_dashboard_ReferenceProduct.yaml +55 -0
- endoreg_db/data/report_reader_flag/rkh-histology-generic.yaml +10 -0
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +30 -0
- endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +24 -0
- endoreg_db/data/requirement/age.yaml +26 -0
- endoreg_db/data/requirement/colonoscopy_baseline_austria.yaml +45 -0
- endoreg_db/data/requirement/disease_cardiovascular.yaml +79 -0
- endoreg_db/data/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
- endoreg_db/data/requirement/disease_hepatology.yaml +12 -0
- endoreg_db/data/requirement/disease_misc.yaml +12 -0
- endoreg_db/data/requirement/disease_renal.yaml +96 -0
- endoreg_db/data/requirement/endoscopy_bleeding_risk.yaml +59 -0
- endoreg_db/data/requirement/event_cardiology.yaml +251 -0
- endoreg_db/data/requirement/event_requirements.yaml +145 -0
- endoreg_db/data/requirement/finding_colon_polyp.yaml +50 -0
- endoreg_db/data/requirement/gender.yaml +25 -0
- endoreg_db/data/requirement/lab_value.yaml +441 -0
- endoreg_db/data/requirement/medication.yaml +93 -0
- endoreg_db/data/requirement_operator/age.yaml +13 -0
- endoreg_db/data/requirement_operator/lab_operators.yaml +129 -0
- endoreg_db/data/requirement_operator/model_operators.yaml +96 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +48 -0
- endoreg_db/data/requirement_set/colonoscopy_austria_screening.yaml +57 -0
- endoreg_db/data/requirement_set/endoscopy_bleeding_risk.yaml +52 -0
- endoreg_db/data/requirement_set_type/data.yaml +20 -0
- endoreg_db/data/requirement_type/requirement_types.yaml +165 -0
- endoreg_db/data/resource/green_endoscopy_dashboard_Resource.yaml +15 -0
- endoreg_db/data/risk/bleeding.yaml +26 -0
- endoreg_db/data/risk/thrombosis.yaml +37 -0
- endoreg_db/data/risk_type/data.yaml +27 -0
- endoreg_db/data/setup_config.yaml +38 -0
- endoreg_db/data/shift/endoscopy.yaml +21 -0
- endoreg_db/data/shift/m2.yaml +0 -0
- endoreg_db/data/shift_type/base.yaml +35 -0
- endoreg_db/data/tag/requirement_set_tags.yaml +11 -0
- endoreg_db/data/tmp/chronic_kidney_disease.yaml +0 -0
- endoreg_db/data/tmp/congestive_heart_failure.yaml +0 -0
- endoreg_db/data/transport_route/green_endoscopy_dashboard_TransportRoute.yaml +12 -0
- endoreg_db/data/unit/concentration.yaml +115 -0
- endoreg_db/data/unit/data.yaml +17 -0
- endoreg_db/data/unit/length.yaml +31 -0
- endoreg_db/data/unit/misc.yaml +20 -0
- endoreg_db/data/unit/rate.yaml +6 -0
- endoreg_db/data/unit/time.yaml +48 -0
- endoreg_db/data/unit/volume.yaml +35 -0
- endoreg_db/data/unit/weight.yaml +38 -0
- endoreg_db/data/waste/data.yaml +12 -0
- endoreg_db/exceptions.py +19 -0
- endoreg_db/factories/__init__.py +0 -0
- endoreg_db/forms/__init__.py +5 -0
- endoreg_db/forms/examination_form.py +11 -0
- endoreg_db/forms/patient_finding_intervention_form.py +18 -0
- endoreg_db/forms/patient_form.py +27 -0
- endoreg_db/forms/questionnaires/__init__.py +1 -0
- endoreg_db/forms/questionnaires/tto_questionnaire.py +23 -0
- endoreg_db/forms/settings/__init__.py +8 -0
- endoreg_db/forms/unit.py +6 -0
- endoreg_db/helpers/__init__.py +0 -0
- endoreg_db/helpers/count_db.py +45 -0
- endoreg_db/helpers/data_loader.py +208 -0
- endoreg_db/helpers/default_objects.py +378 -0
- endoreg_db/helpers/download_segmentation_model.py +31 -0
- endoreg_db/helpers/interact.py +6 -0
- endoreg_db/helpers/test_video_helper.py +119 -0
- endoreg_db/logger_conf.py +140 -0
- endoreg_db/management/__init__.py +1 -0
- endoreg_db/management/commands/__init__.py +1 -0
- endoreg_db/management/commands/anonymize_video.py +0 -0
- endoreg_db/management/commands/check_auth.py +125 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +115 -0
- endoreg_db/management/commands/create_multilabel_model_meta.py +214 -0
- endoreg_db/management/commands/fix_missing_patient_data.py +172 -0
- endoreg_db/management/commands/fix_video_paths.py +165 -0
- endoreg_db/management/commands/import_fallback_video.py +203 -0
- endoreg_db/management/commands/import_report.py +298 -0
- endoreg_db/management/commands/import_video.py +423 -0
- endoreg_db/management/commands/import_video_with_classification.py +367 -0
- endoreg_db/management/commands/init_default_ai_model.py +112 -0
- endoreg_db/management/commands/load_ai_model_data.py +77 -0
- endoreg_db/management/commands/load_ai_model_label_data.py +59 -0
- endoreg_db/management/commands/load_base_db_data.py +192 -0
- endoreg_db/management/commands/load_center_data.py +68 -0
- endoreg_db/management/commands/load_contraindication_data.py +41 -0
- endoreg_db/management/commands/load_disease_classification_choices_data.py +41 -0
- endoreg_db/management/commands/load_disease_classification_data.py +41 -0
- endoreg_db/management/commands/load_disease_data.py +62 -0
- endoreg_db/management/commands/load_distribution_data.py +66 -0
- endoreg_db/management/commands/load_endoscope_data.py +68 -0
- endoreg_db/management/commands/load_event_data.py +41 -0
- endoreg_db/management/commands/load_examination_data.py +75 -0
- endoreg_db/management/commands/load_examination_indication_data.py +86 -0
- endoreg_db/management/commands/load_finding_data.py +128 -0
- endoreg_db/management/commands/load_gender_data.py +44 -0
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +132 -0
- endoreg_db/management/commands/load_information_source.py +51 -0
- endoreg_db/management/commands/load_lab_value_data.py +50 -0
- endoreg_db/management/commands/load_medication_data.py +103 -0
- endoreg_db/management/commands/load_name_data.py +37 -0
- endoreg_db/management/commands/load_organ_data.py +43 -0
- endoreg_db/management/commands/load_pdf_type_data.py +61 -0
- endoreg_db/management/commands/load_profession_data.py +44 -0
- endoreg_db/management/commands/load_qualification_data.py +59 -0
- endoreg_db/management/commands/load_report_reader_flag_data.py +46 -0
- endoreg_db/management/commands/load_requirement_data.py +180 -0
- endoreg_db/management/commands/load_risk_data.py +56 -0
- endoreg_db/management/commands/load_shift_data.py +60 -0
- endoreg_db/management/commands/load_tag_data.py +57 -0
- endoreg_db/management/commands/load_unit_data.py +46 -0
- endoreg_db/management/commands/load_user_groups.py +28 -0
- endoreg_db/management/commands/register_ai_model.py +64 -0
- endoreg_db/management/commands/reset_celery_schedule.py +9 -0
- endoreg_db/management/commands/setup_endoreg_db.py +381 -0
- endoreg_db/management/commands/start_filewatcher.py +106 -0
- endoreg_db/management/commands/storage_management.py +548 -0
- endoreg_db/management/commands/summarize_db_content.py +189 -0
- endoreg_db/management/commands/validate_video.py +204 -0
- endoreg_db/management/commands/validate_video_files.py +161 -0
- endoreg_db/management/commands/video_validation.py +22 -0
- endoreg_db/mermaid/Overall_flow_patient_finding_intervention.md +10 -0
- endoreg_db/mermaid/anonymized_image_annotation.md +20 -0
- endoreg_db/mermaid/binary_classification_annotation.md +50 -0
- endoreg_db/mermaid/classification.md +8 -0
- endoreg_db/mermaid/examination.md +8 -0
- endoreg_db/mermaid/findings.md +7 -0
- endoreg_db/mermaid/image_classification.md +28 -0
- endoreg_db/mermaid/interventions.md +8 -0
- endoreg_db/mermaid/morphology.md +8 -0
- endoreg_db/mermaid/patient_creation.md +14 -0
- endoreg_db/mermaid/video_segmentation_annotation.md +17 -0
- endoreg_db/migrations/0001_initial.py +1857 -0
- endoreg_db/migrations/0002_add_video_correction_models.py +52 -0
- endoreg_db/migrations/0003_add_center_display_name.py +30 -0
- endoreg_db/migrations/__init__.py +0 -0
- endoreg_db/models/__init__.py +359 -0
- endoreg_db/models/administration/__init__.py +116 -0
- endoreg_db/models/administration/ai/__init__.py +9 -0
- endoreg_db/models/administration/ai/active_model.py +35 -0
- endoreg_db/models/administration/ai/ai_model.py +156 -0
- endoreg_db/models/administration/ai/model_type.py +41 -0
- endoreg_db/models/administration/case/__init__.py +19 -0
- endoreg_db/models/administration/case/case.py +114 -0
- endoreg_db/models/administration/case/case_template/__init__.py +15 -0
- endoreg_db/models/administration/case/case_template/case_template.py +125 -0
- endoreg_db/models/administration/case/case_template/case_template_rule.py +269 -0
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +86 -0
- endoreg_db/models/administration/case/case_template/case_template_type.py +26 -0
- endoreg_db/models/administration/center/__init__.py +13 -0
- endoreg_db/models/administration/center/center.py +67 -0
- endoreg_db/models/administration/center/center_product.py +64 -0
- endoreg_db/models/administration/center/center_resource.py +49 -0
- endoreg_db/models/administration/center/center_shift.py +88 -0
- endoreg_db/models/administration/center/center_waste.py +30 -0
- endoreg_db/models/administration/permissions/__init__.py +44 -0
- endoreg_db/models/administration/person/__init__.py +24 -0
- endoreg_db/models/administration/person/employee/__init__.py +3 -0
- endoreg_db/models/administration/person/employee/employee.py +35 -0
- endoreg_db/models/administration/person/employee/employee_qualification.py +39 -0
- endoreg_db/models/administration/person/employee/employee_type.py +42 -0
- endoreg_db/models/administration/person/examiner/__init__.py +4 -0
- endoreg_db/models/administration/person/examiner/examiner.py +54 -0
- endoreg_db/models/administration/person/names/__init__.py +0 -0
- endoreg_db/models/administration/person/names/first_name.py +18 -0
- endoreg_db/models/administration/person/names/last_name.py +19 -0
- endoreg_db/models/administration/person/patient/__init__.py +5 -0
- endoreg_db/models/administration/person/patient/patient.py +460 -0
- endoreg_db/models/administration/person/person.py +31 -0
- endoreg_db/models/administration/person/profession/__init__.py +24 -0
- endoreg_db/models/administration/person/user/__init__.py +5 -0
- endoreg_db/models/administration/person/user/portal_user_information.py +37 -0
- endoreg_db/models/administration/product/__init__.py +14 -0
- endoreg_db/models/administration/product/product.py +97 -0
- endoreg_db/models/administration/product/product_group.py +39 -0
- endoreg_db/models/administration/product/product_material.py +54 -0
- endoreg_db/models/administration/product/product_weight.py +47 -0
- endoreg_db/models/administration/product/reference_product.py +130 -0
- endoreg_db/models/administration/qualification/__init__.py +7 -0
- endoreg_db/models/administration/qualification/qualification.py +37 -0
- endoreg_db/models/administration/qualification/qualification_type.py +35 -0
- endoreg_db/models/administration/shift/__init__.py +9 -0
- endoreg_db/models/administration/shift/scheduled_days.py +69 -0
- endoreg_db/models/administration/shift/shift.py +51 -0
- endoreg_db/models/administration/shift/shift_type.py +108 -0
- endoreg_db/models/label/__init__.py +24 -0
- endoreg_db/models/label/annotation/__init__.py +12 -0
- endoreg_db/models/label/annotation/image_classification.py +84 -0
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +66 -0
- endoreg_db/models/label/label.py +83 -0
- endoreg_db/models/label/label_set.py +53 -0
- endoreg_db/models/label/label_type.py +29 -0
- endoreg_db/models/label/label_video_segment/__init__.py +3 -0
- endoreg_db/models/label/label_video_segment/_create_from_video.py +41 -0
- endoreg_db/models/label/label_video_segment/label_video_segment.py +511 -0
- endoreg_db/models/label/video_segmentation_label.py +31 -0
- endoreg_db/models/label/video_segmentation_labelset.py +27 -0
- endoreg_db/models/media/__init__.py +16 -0
- endoreg_db/models/media/frame/__init__.py +3 -0
- endoreg_db/models/media/frame/frame.py +111 -0
- endoreg_db/models/media/pdf/__init__.py +11 -0
- endoreg_db/models/media/pdf/raw_pdf.py +757 -0
- endoreg_db/models/media/pdf/report_file.py +162 -0
- endoreg_db/models/media/pdf/report_reader/__init__.py +7 -0
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +77 -0
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +20 -0
- endoreg_db/models/media/video/__init__.py +8 -0
- endoreg_db/models/media/video/create_from_file.py +358 -0
- endoreg_db/models/media/video/pipe_1.py +213 -0
- endoreg_db/models/media/video/pipe_2.py +105 -0
- endoreg_db/models/media/video/refactor_plan.md +0 -0
- endoreg_db/models/media/video/video_file.py +825 -0
- endoreg_db/models/media/video/video_file_ai.py +443 -0
- endoreg_db/models/media/video/video_file_anonymize.py +349 -0
- endoreg_db/models/media/video/video_file_frames/__init__.py +47 -0
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +22 -0
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +23 -0
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +104 -0
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +174 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +28 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +20 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +34 -0
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +27 -0
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +129 -0
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +141 -0
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +65 -0
- endoreg_db/models/media/video/video_file_frames.py +0 -0
- endoreg_db/models/media/video/video_file_io.py +168 -0
- endoreg_db/models/media/video/video_file_meta/__init__.py +22 -0
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +45 -0
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +39 -0
- endoreg_db/models/media/video/video_file_meta/get_fps.py +147 -0
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +143 -0
- endoreg_db/models/media/video/video_file_meta/text_meta.py +134 -0
- endoreg_db/models/media/video/video_file_meta/video_meta.py +70 -0
- endoreg_db/models/media/video/video_file_segments.py +209 -0
- endoreg_db/models/media/video/video_metadata.py +65 -0
- endoreg_db/models/media/video/video_processing.py +152 -0
- endoreg_db/models/medical/__init__.py +146 -0
- endoreg_db/models/medical/contraindication/__init__.py +17 -0
- endoreg_db/models/medical/disease.py +156 -0
- endoreg_db/models/medical/event.py +137 -0
- endoreg_db/models/medical/examination/__init__.py +9 -0
- endoreg_db/models/medical/examination/examination.py +148 -0
- endoreg_db/models/medical/examination/examination_indication.py +278 -0
- endoreg_db/models/medical/examination/examination_time.py +49 -0
- endoreg_db/models/medical/examination/examination_time_type.py +41 -0
- endoreg_db/models/medical/examination/examination_type.py +48 -0
- endoreg_db/models/medical/finding/__init__.py +18 -0
- endoreg_db/models/medical/finding/finding.py +96 -0
- endoreg_db/models/medical/finding/finding_classification.py +142 -0
- endoreg_db/models/medical/finding/finding_intervention.py +52 -0
- endoreg_db/models/medical/finding/finding_type.py +35 -0
- endoreg_db/models/medical/hardware/__init__.py +8 -0
- endoreg_db/models/medical/hardware/endoscope.py +65 -0
- endoreg_db/models/medical/hardware/endoscopy_processor.py +182 -0
- endoreg_db/models/medical/laboratory/__init__.py +5 -0
- endoreg_db/models/medical/laboratory/lab_value.py +419 -0
- endoreg_db/models/medical/medication/__init__.py +19 -0
- endoreg_db/models/medical/medication/medication.py +31 -0
- endoreg_db/models/medical/medication/medication_indication.py +50 -0
- endoreg_db/models/medical/medication/medication_indication_type.py +39 -0
- endoreg_db/models/medical/medication/medication_intake_time.py +44 -0
- endoreg_db/models/medical/medication/medication_schedule.py +45 -0
- endoreg_db/models/medical/organ/__init__.py +35 -0
- endoreg_db/models/medical/patient/__init__.py +56 -0
- endoreg_db/models/medical/patient/medication_examples.py +38 -0
- endoreg_db/models/medical/patient/patient_disease.py +63 -0
- endoreg_db/models/medical/patient/patient_event.py +75 -0
- endoreg_db/models/medical/patient/patient_examination.py +249 -0
- endoreg_db/models/medical/patient/patient_examination_indication.py +44 -0
- endoreg_db/models/medical/patient/patient_finding.py +357 -0
- endoreg_db/models/medical/patient/patient_finding_classification.py +207 -0
- endoreg_db/models/medical/patient/patient_finding_intervention.py +40 -0
- endoreg_db/models/medical/patient/patient_lab_sample.py +148 -0
- endoreg_db/models/medical/patient/patient_lab_value.py +222 -0
- endoreg_db/models/medical/patient/patient_medication.py +104 -0
- endoreg_db/models/medical/patient/patient_medication_schedule.py +136 -0
- endoreg_db/models/medical/risk/__init__.py +7 -0
- endoreg_db/models/medical/risk/risk.py +72 -0
- endoreg_db/models/medical/risk/risk_type.py +51 -0
- endoreg_db/models/metadata/__init__.py +19 -0
- endoreg_db/models/metadata/frame_ocr_result.py +0 -0
- endoreg_db/models/metadata/model_meta.py +206 -0
- endoreg_db/models/metadata/model_meta_logic.py +343 -0
- endoreg_db/models/metadata/pdf_meta.py +89 -0
- endoreg_db/models/metadata/sensitive_meta.py +288 -0
- endoreg_db/models/metadata/sensitive_meta_logic.py +1048 -0
- endoreg_db/models/metadata/video_meta.py +332 -0
- endoreg_db/models/metadata/video_prediction_logic.py +190 -0
- endoreg_db/models/metadata/video_prediction_meta.py +270 -0
- endoreg_db/models/other/__init__.py +40 -0
- endoreg_db/models/other/distribution/__init__.py +44 -0
- endoreg_db/models/other/distribution/base_value_distribution.py +20 -0
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -0
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +32 -0
- endoreg_db/models/other/distribution/numeric_value_distribution.py +125 -0
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +22 -0
- endoreg_db/models/other/emission/__init__.py +5 -0
- endoreg_db/models/other/emission/emission_factor.py +94 -0
- endoreg_db/models/other/gender.py +27 -0
- endoreg_db/models/other/information_source.py +159 -0
- endoreg_db/models/other/material.py +28 -0
- endoreg_db/models/other/resource.py +22 -0
- endoreg_db/models/other/tag.py +27 -0
- endoreg_db/models/other/transport_route.py +33 -0
- endoreg_db/models/other/unit.py +32 -0
- endoreg_db/models/other/waste.py +27 -0
- endoreg_db/models/requirement/__init__.py +11 -0
- endoreg_db/models/requirement/requirement.py +767 -0
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +6 -0
- endoreg_db/models/requirement/requirement_evaluation/get_values.py +40 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +9 -0
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +95 -0
- endoreg_db/models/requirement/requirement_operator.py +176 -0
- endoreg_db/models/requirement/requirement_set.py +287 -0
- endoreg_db/models/rule/__init__.py +13 -0
- endoreg_db/models/rule/rule.py +27 -0
- endoreg_db/models/rule/rule_applicator.py +224 -0
- endoreg_db/models/rule/rule_attribute_dtype.py +17 -0
- endoreg_db/models/rule/rule_type.py +20 -0
- endoreg_db/models/rule/ruleset.py +17 -0
- endoreg_db/models/state/__init__.py +12 -0
- endoreg_db/models/state/abstract.py +11 -0
- endoreg_db/models/state/audit_ledger.py +150 -0
- endoreg_db/models/state/label_video_segment.py +22 -0
- endoreg_db/models/state/raw_pdf.py +187 -0
- endoreg_db/models/state/sensitive_meta.py +46 -0
- endoreg_db/models/state/video.py +232 -0
- endoreg_db/models/upload_job.py +99 -0
- endoreg_db/models/utils.py +135 -0
- endoreg_db/queries/__init__.py +5 -0
- endoreg_db/queries/annotations/__init__.py +3 -0
- endoreg_db/queries/annotations/legacy.py +158 -0
- endoreg_db/queries/sanity/__init_.py +0 -0
- endoreg_db/renames.yml +8 -0
- endoreg_db/root_urls.py +9 -0
- endoreg_db/schemas/__init__.py +0 -0
- endoreg_db/schemas/examination_evaluation.py +27 -0
- endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +775 -0
- endoreg_db/serializers/__init__.py +118 -0
- endoreg_db/serializers/_old/raw_pdf_meta_validation.py +223 -0
- endoreg_db/serializers/_old/raw_video_meta_validation.py +179 -0
- endoreg_db/serializers/_old/video.py +71 -0
- endoreg_db/serializers/administration/__init__.py +14 -0
- endoreg_db/serializers/administration/ai/__init__.py +10 -0
- endoreg_db/serializers/administration/ai/active_model.py +10 -0
- endoreg_db/serializers/administration/ai/ai_model.py +18 -0
- endoreg_db/serializers/administration/ai/model_type.py +10 -0
- endoreg_db/serializers/administration/center.py +9 -0
- endoreg_db/serializers/administration/gender.py +9 -0
- endoreg_db/serializers/anonymization.py +69 -0
- endoreg_db/serializers/evaluation/examination_evaluation.py +1 -0
- endoreg_db/serializers/examination/__init__.py +10 -0
- endoreg_db/serializers/examination/base.py +46 -0
- endoreg_db/serializers/examination/dropdown.py +21 -0
- endoreg_db/serializers/examination_serializer.py +12 -0
- endoreg_db/serializers/finding/__init__.py +5 -0
- endoreg_db/serializers/finding/finding.py +54 -0
- endoreg_db/serializers/finding_classification/__init__.py +7 -0
- endoreg_db/serializers/finding_classification/choice.py +19 -0
- endoreg_db/serializers/finding_classification/classification.py +13 -0
- endoreg_db/serializers/label/__init__.py +7 -0
- endoreg_db/serializers/label/image_classification_annotation.py +62 -0
- endoreg_db/serializers/label/label.py +15 -0
- endoreg_db/serializers/label_video_segment/__init__.py +7 -0
- endoreg_db/serializers/label_video_segment/_lvs_create.py +149 -0
- endoreg_db/serializers/label_video_segment/_lvs_update.py +138 -0
- endoreg_db/serializers/label_video_segment/_lvs_validate.py +149 -0
- endoreg_db/serializers/label_video_segment/label_video_segment.py +344 -0
- endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +99 -0
- endoreg_db/serializers/label_video_segment/label_video_segment_update.py +163 -0
- endoreg_db/serializers/meta/__init__.py +19 -0
- endoreg_db/serializers/meta/pdf_file_meta_extraction.py +115 -0
- endoreg_db/serializers/meta/report_meta.py +53 -0
- endoreg_db/serializers/meta/sensitive_meta_detail.py +162 -0
- endoreg_db/serializers/meta/sensitive_meta_update.py +148 -0
- endoreg_db/serializers/meta/sensitive_meta_verification.py +59 -0
- endoreg_db/serializers/meta/video_meta.py +39 -0
- endoreg_db/serializers/misc/__init__.py +14 -0
- endoreg_db/serializers/misc/file_overview.py +182 -0
- endoreg_db/serializers/misc/sensitive_patient_data.py +120 -0
- endoreg_db/serializers/misc/stats.py +33 -0
- endoreg_db/serializers/misc/translatable_field_mix_in.py +44 -0
- endoreg_db/serializers/misc/upload_job.py +71 -0
- endoreg_db/serializers/patient/__init__.py +11 -0
- endoreg_db/serializers/patient/patient.py +86 -0
- endoreg_db/serializers/patient/patient_dropdown.py +27 -0
- endoreg_db/serializers/patient_examination/__init__.py +7 -0
- endoreg_db/serializers/patient_examination/patient_examination.py +141 -0
- endoreg_db/serializers/patient_finding/__init__.py +15 -0
- endoreg_db/serializers/patient_finding/patient_finding.py +31 -0
- endoreg_db/serializers/patient_finding/patient_finding_classification.py +39 -0
- endoreg_db/serializers/patient_finding/patient_finding_detail.py +53 -0
- endoreg_db/serializers/patient_finding/patient_finding_intervention.py +26 -0
- endoreg_db/serializers/patient_finding/patient_finding_list.py +41 -0
- endoreg_db/serializers/patient_finding/patient_finding_write.py +126 -0
- endoreg_db/serializers/pdf/__init__.py +5 -0
- endoreg_db/serializers/pdf/anony_text_validation.py +85 -0
- endoreg_db/serializers/report/__init__.py +9 -0
- endoreg_db/serializers/report/mixins.py +45 -0
- endoreg_db/serializers/report/report.py +105 -0
- endoreg_db/serializers/report/report_list.py +22 -0
- endoreg_db/serializers/report/secure_file_url.py +26 -0
- endoreg_db/serializers/requirements/requirement_schema.py +25 -0
- endoreg_db/serializers/requirements/requirement_sets.py +29 -0
- endoreg_db/serializers/sensitive_meta_serializer.py +282 -0
- endoreg_db/serializers/video/__init__.py +7 -0
- endoreg_db/serializers/video/segmentation.py +263 -0
- endoreg_db/serializers/video/video_file_brief.py +10 -0
- endoreg_db/serializers/video/video_file_detail.py +83 -0
- endoreg_db/serializers/video/video_file_list.py +67 -0
- endoreg_db/serializers/video/video_metadata.py +105 -0
- endoreg_db/serializers/video/video_processing_history.py +153 -0
- endoreg_db/serializers/video_examination.py +198 -0
- endoreg_db/services/__init__.py +5 -0
- endoreg_db/services/anonymization.py +223 -0
- endoreg_db/services/examination_evaluation.py +149 -0
- endoreg_db/services/finding_description_service.py +0 -0
- endoreg_db/services/lookup_service.py +411 -0
- endoreg_db/services/lookup_store.py +266 -0
- endoreg_db/services/pdf_import.py +1382 -0
- endoreg_db/services/polling_coordinator.py +288 -0
- endoreg_db/services/pseudonym_service.py +89 -0
- endoreg_db/services/requirements_object.py +147 -0
- endoreg_db/services/segment_sync.py +155 -0
- endoreg_db/services/storage_aware_video_processor.py +344 -0
- endoreg_db/services/video_import.py +1259 -0
- endoreg_db/tasks/upload_tasks.py +207 -0
- endoreg_db/tasks/video_ingest.py +157 -0
- endoreg_db/tasks/video_processing_tasks.py +327 -0
- endoreg_db/templates/admin/patient_finding_intervention.html +253 -0
- endoreg_db/templates/admin/start_examination.html +12 -0
- endoreg_db/templates/timeline.html +176 -0
- endoreg_db/urls/__init__.py +83 -0
- endoreg_db/urls/anonymization.py +32 -0
- endoreg_db/urls/auth.py +16 -0
- endoreg_db/urls/classification.py +39 -0
- endoreg_db/urls/examination.py +54 -0
- endoreg_db/urls/files.py +6 -0
- endoreg_db/urls/label_video_segment_validate.py +33 -0
- endoreg_db/urls/label_video_segments.py +46 -0
- endoreg_db/urls/media.py +227 -0
- endoreg_db/urls/patient.py +19 -0
- endoreg_db/urls/report.py +48 -0
- endoreg_db/urls/requirements.py +13 -0
- endoreg_db/urls/sensitive_meta.py +0 -0
- endoreg_db/urls/stats.py +46 -0
- endoreg_db/urls/upload.py +20 -0
- endoreg_db/urls/video.py +61 -0
- endoreg_db/urls.py +9 -0
- endoreg_db/utils/__init__.py +88 -0
- endoreg_db/utils/ai/__init__.py +9 -0
- endoreg_db/utils/ai/get.py +5 -0
- endoreg_db/utils/ai/inference_dataset.py +52 -0
- endoreg_db/utils/ai/multilabel_classification_net.py +159 -0
- endoreg_db/utils/ai/postprocess.py +63 -0
- endoreg_db/utils/ai/predict.py +291 -0
- endoreg_db/utils/ai/preprocess.py +68 -0
- endoreg_db/utils/calc_duration_seconds.py +24 -0
- endoreg_db/utils/case_generator/__init__.py +0 -0
- endoreg_db/utils/case_generator/case_generator.py +159 -0
- endoreg_db/utils/case_generator/lab_sample_factory.py +33 -0
- endoreg_db/utils/case_generator/utils.py +30 -0
- endoreg_db/utils/check_video_files.py +148 -0
- endoreg_db/utils/cropping.py +29 -0
- endoreg_db/utils/dataloader.py +175 -0
- endoreg_db/utils/dates.py +60 -0
- endoreg_db/utils/env.py +33 -0
- endoreg_db/utils/extract_specific_frames.py +72 -0
- endoreg_db/utils/file_operations.py +58 -0
- endoreg_db/utils/fix_video_path_direct.py +141 -0
- endoreg_db/utils/frame_anonymization_utils.py +463 -0
- endoreg_db/utils/hashs.py +153 -0
- endoreg_db/utils/links/__init__.py +0 -0
- endoreg_db/utils/links/requirement_link.py +193 -0
- endoreg_db/utils/mime_types.py +0 -0
- endoreg_db/utils/names.py +76 -0
- endoreg_db/utils/ocr.py +190 -0
- endoreg_db/utils/parse_and_generate_yaml.py +46 -0
- endoreg_db/utils/paths.py +95 -0
- endoreg_db/utils/permissions.py +143 -0
- endoreg_db/utils/pipelines/Readme.md +235 -0
- endoreg_db/utils/pipelines/__init__.py +0 -0
- endoreg_db/utils/pipelines/process_video_dir.py +120 -0
- endoreg_db/utils/product/__init__.py +0 -0
- endoreg_db/utils/product/sum_emissions.py +20 -0
- endoreg_db/utils/product/sum_weights.py +18 -0
- endoreg_db/utils/pydantic_models/__init__.py +6 -0
- endoreg_db/utils/pydantic_models/db_config.py +57 -0
- endoreg_db/utils/requirement_helpers.py +0 -0
- endoreg_db/utils/requirement_operator_logic/__init__.py +0 -0
- endoreg_db/utils/requirement_operator_logic/lab_value_operators.py +578 -0
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +368 -0
- endoreg_db/utils/setup_config.py +177 -0
- endoreg_db/utils/translation.py +27 -0
- endoreg_db/utils/uuid.py +4 -0
- endoreg_db/utils/validate_endo_roi.py +19 -0
- endoreg_db/utils/validate_subcategory_dict.py +91 -0
- endoreg_db/utils/validate_video_detailed.py +357 -0
- endoreg_db/utils/video/__init__.py +26 -0
- endoreg_db/utils/video/extract_frames.py +88 -0
- endoreg_db/utils/video/ffmpeg_wrapper.py +835 -0
- endoreg_db/utils/video/names.py +42 -0
- endoreg_db/utils/video/streaming_processor.py +312 -0
- endoreg_db/utils/video/video_splitter.py +94 -0
- endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +238 -0
- endoreg_db/views/__init__.py +274 -0
- endoreg_db/views/anonymization/__init__.py +27 -0
- endoreg_db/views/anonymization/media_management.py +454 -0
- endoreg_db/views/anonymization/overview.py +216 -0
- endoreg_db/views/anonymization/validate.py +107 -0
- endoreg_db/views/auth/__init__.py +13 -0
- endoreg_db/views/auth/keycloak.py +113 -0
- endoreg_db/views/examination/__init__.py +33 -0
- endoreg_db/views/examination/examination.py +37 -0
- endoreg_db/views/examination/examination_manifest_cache.py +26 -0
- endoreg_db/views/examination/get_finding_classification_choices.py +59 -0
- endoreg_db/views/examination/get_finding_classifications.py +36 -0
- endoreg_db/views/examination/get_findings.py +41 -0
- endoreg_db/views/examination/get_instruments.py +18 -0
- endoreg_db/views/examination/get_interventions.py +14 -0
- endoreg_db/views/finding/__init__.py +9 -0
- endoreg_db/views/finding/finding.py +112 -0
- endoreg_db/views/finding/get_classifications.py +14 -0
- endoreg_db/views/finding/get_interventions.py +17 -0
- endoreg_db/views/finding_classification/__init__.py +13 -0
- endoreg_db/views/finding_classification/base.py +0 -0
- endoreg_db/views/finding_classification/finding_classification.py +42 -0
- endoreg_db/views/finding_classification/get_classification_choices.py +55 -0
- endoreg_db/views/label/__init__.py +5 -0
- endoreg_db/views/label/label.py +15 -0
- endoreg_db/views/label_video_segment/__init__.py +16 -0
- endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +44 -0
- endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +50 -0
- endoreg_db/views/label_video_segment/label_video_segment.py +77 -0
- endoreg_db/views/label_video_segment/label_video_segment_by_label.py +174 -0
- endoreg_db/views/label_video_segment/label_video_segment_detail.py +73 -0
- endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +46 -0
- endoreg_db/views/label_video_segment/validate.py +226 -0
- endoreg_db/views/media/__init__.py +45 -0
- endoreg_db/views/media/pdf_media.py +388 -0
- endoreg_db/views/media/segments.py +71 -0
- endoreg_db/views/media/sensitive_metadata.py +314 -0
- endoreg_db/views/media/video_media.py +272 -0
- endoreg_db/views/media/video_segments.py +524 -0
- endoreg_db/views/meta/__init__.py +15 -0
- endoreg_db/views/meta/available_files_list.py +146 -0
- endoreg_db/views/meta/report_meta.py +53 -0
- endoreg_db/views/meta/sensitive_meta_detail.py +148 -0
- endoreg_db/views/meta/sensitive_meta_list.py +104 -0
- endoreg_db/views/meta/sensitive_meta_verification.py +71 -0
- endoreg_db/views/misc/__init__.py +63 -0
- endoreg_db/views/misc/center.py +13 -0
- endoreg_db/views/misc/csrf.py +7 -0
- endoreg_db/views/misc/gender.py +14 -0
- endoreg_db/views/misc/secure_file_serving_view.py +80 -0
- endoreg_db/views/misc/secure_file_url_view.py +84 -0
- endoreg_db/views/misc/secure_url_validate.py +79 -0
- endoreg_db/views/misc/stats.py +220 -0
- endoreg_db/views/misc/translation.py +182 -0
- endoreg_db/views/misc/upload_views.py +240 -0
- endoreg_db/views/patient/__init__.py +5 -0
- endoreg_db/views/patient/patient.py +210 -0
- endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +164 -0
- endoreg_db/views/patient_examination/__init__.py +11 -0
- endoreg_db/views/patient_examination/patient_examination.py +140 -0
- endoreg_db/views/patient_examination/patient_examination_create.py +63 -0
- endoreg_db/views/patient_examination/patient_examination_detail.py +66 -0
- endoreg_db/views/patient_examination/patient_examination_list.py +68 -0
- endoreg_db/views/patient_examination/video.py +194 -0
- endoreg_db/views/patient_finding/__init__.py +7 -0
- endoreg_db/views/patient_finding/base.py +0 -0
- endoreg_db/views/patient_finding/patient_finding.py +64 -0
- endoreg_db/views/patient_finding/patient_finding_optimized.py +259 -0
- endoreg_db/views/patient_finding_classification/__init__.py +5 -0
- endoreg_db/views/patient_finding_classification/pfc_create.py +67 -0
- endoreg_db/views/patient_finding_location/__init__.py +5 -0
- endoreg_db/views/patient_finding_location/pfl_create.py +70 -0
- endoreg_db/views/patient_finding_morphology/__init__.py +5 -0
- endoreg_db/views/patient_finding_morphology/pfm_create.py +70 -0
- endoreg_db/views/pdf/__init__.py +8 -0
- endoreg_db/views/pdf/pdf_stream.py +186 -0
- endoreg_db/views/pdf/reimport.py +177 -0
- endoreg_db/views/report/__init__.py +9 -0
- endoreg_db/views/report/report_list.py +112 -0
- endoreg_db/views/report/report_with_secure_url.py +28 -0
- endoreg_db/views/report/start_examination.py +7 -0
- endoreg_db/views/requirement/__init__.py +10 -0
- endoreg_db/views/requirement/evaluate.py +279 -0
- endoreg_db/views/requirement/lookup.py +367 -0
- endoreg_db/views/requirement/lookup_store.py +252 -0
- endoreg_db/views/requirement_lookup/lookup.py +0 -0
- endoreg_db/views/requirement_lookup/lookup_store.py +0 -0
- endoreg_db/views/stats/__init__.py +13 -0
- endoreg_db/views/stats/stats_views.py +229 -0
- endoreg_db/views/video/__init__.py +59 -0
- endoreg_db/views/video/correction.py +530 -0
- endoreg_db/views/video/reimport.py +195 -0
- endoreg_db/views/video/segmentation.py +274 -0
- endoreg_db/views/video/task_status.py +49 -0
- endoreg_db/views/video/timeline.py +46 -0
- endoreg_db/views/video/video_analyze.py +52 -0
- endoreg_db/views/video/video_apply_mask.py +48 -0
- endoreg_db/views/video/video_correction.py +21 -0
- endoreg_db/views/video/video_download_processed.py +58 -0
- endoreg_db/views/video/video_examination_viewset.py +242 -0
- endoreg_db/views/video/video_meta.py +29 -0
- endoreg_db/views/video/video_processing_history.py +24 -0
- endoreg_db/views/video/video_remove_frames.py +48 -0
- endoreg_db/views/video/video_stream.py +306 -0
- endoreg_db/views.py +0 -0
- endoreg_db-0.8.6.4.dist-info/METADATA +383 -0
- endoreg_db-0.8.6.4.dist-info/RECORD +793 -0
- endoreg_db-0.8.6.4.dist-info/WHEEL +4 -0
- endoreg_db-0.8.6.4.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
from ...utils import DOCUMENT_DIR, STORAGE_DIR
|
|
2
|
+
from django.db import models
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from ...administration import (
|
|
7
|
+
Center,
|
|
8
|
+
Patient,
|
|
9
|
+
)
|
|
10
|
+
from ...medical import (
|
|
11
|
+
PatientExamination,
|
|
12
|
+
)
|
|
13
|
+
from ...metadata import SensitiveMeta
|
|
14
|
+
|
|
15
|
+
class DocumentTypeManager(models.Manager):
|
|
16
|
+
"""
|
|
17
|
+
Custom manager for DocumentType.
|
|
18
|
+
"""
|
|
19
|
+
def get_by_natural_key(self, name):
|
|
20
|
+
return self.get(name=name)
|
|
21
|
+
|
|
22
|
+
class DocumentType(models.Model):
|
|
23
|
+
"""
|
|
24
|
+
Represents the type of a document.
|
|
25
|
+
"""
|
|
26
|
+
name = models.CharField(max_length=255, unique=True)
|
|
27
|
+
description = models.TextField(blank=True, null=True)
|
|
28
|
+
|
|
29
|
+
objects = DocumentTypeManager()
|
|
30
|
+
|
|
31
|
+
def natural_key(self):
|
|
32
|
+
return (self.name,)
|
|
33
|
+
|
|
34
|
+
def __str__(self):
|
|
35
|
+
return str(self.name)
|
|
36
|
+
|
|
37
|
+
class Meta:
|
|
38
|
+
verbose_name = "Document Type"
|
|
39
|
+
verbose_name_plural = "Document Types"
|
|
40
|
+
|
|
41
|
+
class AbstractDocument(models.Model):
|
|
42
|
+
"""
|
|
43
|
+
Abstract base class for documents.
|
|
44
|
+
"""
|
|
45
|
+
meta = models.JSONField(blank=True, null=True)
|
|
46
|
+
text = models.TextField(blank=True, null=True)
|
|
47
|
+
date = models.DateField(blank=True, null=True)
|
|
48
|
+
time = models.TimeField(blank=True, null=True)
|
|
49
|
+
file = models.FileField(
|
|
50
|
+
upload_to=DOCUMENT_DIR.relative_to(STORAGE_DIR),
|
|
51
|
+
blank=True,
|
|
52
|
+
null=True,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
center = models.ForeignKey(
|
|
56
|
+
"Center",
|
|
57
|
+
on_delete=models.SET_NULL,
|
|
58
|
+
blank=True,
|
|
59
|
+
null=True,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
type = models.ForeignKey(
|
|
63
|
+
DocumentType,
|
|
64
|
+
on_delete=models.SET_NULL,
|
|
65
|
+
blank=True,
|
|
66
|
+
null=True,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
if TYPE_CHECKING:
|
|
70
|
+
center: "Center"
|
|
71
|
+
type: "DocumentType"
|
|
72
|
+
|
|
73
|
+
class Meta:
|
|
74
|
+
abstract = True
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class AbstractExaminationReport(AbstractDocument):
|
|
80
|
+
"""
|
|
81
|
+
Abstract base class for examination reports.
|
|
82
|
+
"""
|
|
83
|
+
patient = models.ForeignKey(
|
|
84
|
+
"Patient", on_delete=models.DO_NOTHING, blank=True, null=True
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
patient_examination = models.ForeignKey(
|
|
88
|
+
"PatientExamination",
|
|
89
|
+
on_delete=models.SET_NULL,
|
|
90
|
+
blank=True,
|
|
91
|
+
null=True,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
examiners = models.ManyToManyField(
|
|
95
|
+
"Examiner",
|
|
96
|
+
blank=True,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
sensitive_meta = models.ForeignKey(
|
|
100
|
+
"SensitiveMeta",
|
|
101
|
+
on_delete=models.SET_NULL,
|
|
102
|
+
null=True,
|
|
103
|
+
blank=True
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if TYPE_CHECKING:
|
|
107
|
+
center: "Center"
|
|
108
|
+
type: "DocumentType"
|
|
109
|
+
patient: "Patient"
|
|
110
|
+
patient_examination: "PatientExamination"
|
|
111
|
+
sensitive_meta: "SensitiveMeta"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class Meta:
|
|
115
|
+
abstract = True
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def get_or_create_examiner(self, examiner_first_name, examiner_last_name):
|
|
119
|
+
raise NotImplementedError("Subclasses must implement this method.")
|
|
120
|
+
|
|
121
|
+
def set_examination_date_and_time(self, report_meta=None):
|
|
122
|
+
raise NotImplementedError("Subclasses must implement this method.")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class AnonymExaminationReport(AbstractExaminationReport):
|
|
127
|
+
|
|
128
|
+
def get_or_create_examiner(self, examiner_first_name:str, examiner_last_name:str):
|
|
129
|
+
from ...administration.person import Examiner
|
|
130
|
+
|
|
131
|
+
examiner_center = self.center
|
|
132
|
+
|
|
133
|
+
examiner, created = Examiner.objects.get_or_create(
|
|
134
|
+
first_name=examiner_first_name,
|
|
135
|
+
last_name=examiner_last_name,
|
|
136
|
+
center=examiner_center,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return examiner, created
|
|
140
|
+
|
|
141
|
+
def set_examination_date_and_time(self, report_meta=None):
|
|
142
|
+
#TODO
|
|
143
|
+
if not report_meta:
|
|
144
|
+
report_meta = self.meta
|
|
145
|
+
# examination_date_str = report_meta["examination_date"]
|
|
146
|
+
# examination_time_str = report_meta["examination_time"]
|
|
147
|
+
|
|
148
|
+
# if examination_date_str:
|
|
149
|
+
# # TODO: get django DateField compatible date from string (e.g. "2021-01-01")
|
|
150
|
+
# self.date = date.fromisoformat(examination_date_str)
|
|
151
|
+
# if examination_time_str:
|
|
152
|
+
# # TODO: get django TimeField compatible time from string (e.g. "12:00")
|
|
153
|
+
# self.time = time.fromisoformat(examination_time_str)
|
|
154
|
+
|
|
155
|
+
class AnonymHistologyReport(AbstractExaminationReport):
|
|
156
|
+
"""
|
|
157
|
+
Represents a histology report.
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def get_or_create_examiner(self, examiner_first_name, examiner_last_name):
|
|
162
|
+
raise NotImplementedError("Subclasses must implement this method.")
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# ReportReaderConfig Class
|
|
2
|
+
# Description: This class is used to store the configuration of the ReportReader
|
|
3
|
+
|
|
4
|
+
# PATIENT_INFO_LINE_FLAG = "Patient: "
|
|
5
|
+
# ENDOSCOPE_INFO_LINE_FLAG = "Gerät: "
|
|
6
|
+
# EXAMINER_INFO_LINE_FLAG = "1. Unters.:"
|
|
7
|
+
# CUT_OFF_BELOW_LINE_FLAG = "________________"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# CUT_OFF_ABOVE_LINE_FLAGS = [
|
|
11
|
+
# ENDOSCOPE_INFO_LINE_FLAG,
|
|
12
|
+
# EXAMINER_INFO_LINE_FLAG,
|
|
13
|
+
# ]
|
|
14
|
+
|
|
15
|
+
# CUT_OFF_BELOW_LINE_FLAGS = [
|
|
16
|
+
# CUT_OFF_BELOW_LINE_FLAG
|
|
17
|
+
# ]
|
|
18
|
+
|
|
19
|
+
from django.db import models
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
from typing import TYPE_CHECKING
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from .report_reader_flag import ReportReaderFlag
|
|
25
|
+
from ....administration.person import FirstName, LastName
|
|
26
|
+
from ....administration.center import Center
|
|
27
|
+
from ....metadata import PdfType
|
|
28
|
+
|
|
29
|
+
class ReportReaderConfig(models.Model):
|
|
30
|
+
"""
|
|
31
|
+
Configuration settings for parsing PDF reports (ReportReader).
|
|
32
|
+
|
|
33
|
+
Stores locale, name lists, date format, and flags used to identify key information lines
|
|
34
|
+
and text sections to ignore.
|
|
35
|
+
"""
|
|
36
|
+
locale = models.CharField(default="de_DE", max_length=10)
|
|
37
|
+
first_names = models.ManyToManyField('FirstName', related_name='report_reader_configs')
|
|
38
|
+
last_names = models.ManyToManyField('LastName', related_name='report_reader_configs')
|
|
39
|
+
text_date_format = models.CharField(default = "%d.%m.%Y", max_length=10)
|
|
40
|
+
patient_info_line_flag = models.ForeignKey("ReportReaderFlag", related_name='report_reader_configs_patient_info_line', on_delete=models.CASCADE)
|
|
41
|
+
endoscope_info_line_flag = models.ForeignKey("ReportReaderFlag", related_name='report_reader_configs_endoscope_info_line', on_delete=models.CASCADE)
|
|
42
|
+
examiner_info_line_flag = models.ForeignKey("ReportReaderFlag", related_name='report_reader_configs_examiner_info_line', on_delete=models.CASCADE)
|
|
43
|
+
cut_off_below = models.ManyToManyField("ReportReaderFlag", related_name='report_reader_configs_cut_off_below')
|
|
44
|
+
cut_off_above = models.ManyToManyField("ReportReaderFlag", related_name='report_reader_configs_cut_off_above')
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
first_names: models.QuerySet["FirstName"]
|
|
48
|
+
last_names: models.QuerySet["LastName"]
|
|
49
|
+
patient_info_line_flag: "ReportReaderFlag"
|
|
50
|
+
endoscope_info_line_flag: "ReportReaderFlag"
|
|
51
|
+
examiner_info_line_flag: "ReportReaderFlag"
|
|
52
|
+
cut_off_below: models.QuerySet["ReportReaderFlag"]
|
|
53
|
+
cut_off_above: models.QuerySet["ReportReaderFlag"]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def __str__(self):
|
|
57
|
+
"""Returns a string representation including the locale and primary key."""
|
|
58
|
+
_str = f"ReportReaderConfig: {self.locale} (id: {self.pk}\n"
|
|
59
|
+
return _str
|
|
60
|
+
|
|
61
|
+
def update_names_by_center(self, center:"Center", save = True):
|
|
62
|
+
"""Updates the first and last name lists based on the names associated with a Center."""
|
|
63
|
+
self.first_names.set(center.first_names.all())
|
|
64
|
+
self.last_names.set(center.last_names.all())
|
|
65
|
+
if save:
|
|
66
|
+
self.save()
|
|
67
|
+
|
|
68
|
+
def update_flags_by_pdf_type(self, pdf_type:"PdfType", save = True):
|
|
69
|
+
"""Updates the line identification flags based on a specific PdfType."""
|
|
70
|
+
self.patient_info_line_flag = pdf_type.patient_info_line_flag
|
|
71
|
+
self.endoscope_info_line_flag = pdf_type.endoscope_info_line_flag
|
|
72
|
+
self.examiner_info_line_flag = pdf_type.examiner_info_line_flag
|
|
73
|
+
self.cut_off_below.set(pdf_type.cut_off_below.all())
|
|
74
|
+
self.cut_off_above.set(pdf_type.cut_off_above.all())
|
|
75
|
+
if save:
|
|
76
|
+
self.save()
|
|
77
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Django model for the report reader flag
|
|
2
|
+
# have name and value
|
|
3
|
+
# name is natural key
|
|
4
|
+
|
|
5
|
+
from django.db import models
|
|
6
|
+
|
|
7
|
+
class ReportReaderFlagManager(models.Manager):
|
|
8
|
+
def get_by_natural_key(self, name):
|
|
9
|
+
return self.get(name=name)
|
|
10
|
+
|
|
11
|
+
class ReportReaderFlag(models.Model):
|
|
12
|
+
objects = ReportReaderFlagManager()
|
|
13
|
+
name = models.CharField(max_length=255, unique=True)
|
|
14
|
+
value = models.CharField(max_length=255)
|
|
15
|
+
|
|
16
|
+
def natural_key(self):
|
|
17
|
+
return (self.name,)
|
|
18
|
+
|
|
19
|
+
def __str__(self):
|
|
20
|
+
return self.name
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
import logging
|
|
3
|
+
import uuid
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import TYPE_CHECKING, Optional, Type
|
|
6
|
+
|
|
7
|
+
# Import the new exceptions from the correct path
|
|
8
|
+
from endoreg_db.exceptions import InsufficientStorageError, TranscodingError
|
|
9
|
+
from ...utils import VIDEO_DIR, TMP_VIDEO_DIR
|
|
10
|
+
from importlib import import_module
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from endoreg_db.models import VideoFile
|
|
14
|
+
|
|
15
|
+
from ....utils.video.ffmpeg_wrapper import transcode_videofile_if_required
|
|
16
|
+
from ....utils.hashs import get_video_hash
|
|
17
|
+
from ....utils.file_operations import get_uuid_filename
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def check_storage_capacity(src_path: Path, dst_root: Path, safety_margin: float = 1.2) -> None:
|
|
23
|
+
"""
|
|
24
|
+
Check if there's enough storage space before starting operations.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
src_path: Source file path
|
|
28
|
+
dst_root: Destination root directory
|
|
29
|
+
safety_margin: Safety factor (1.2 = 20% extra space required)
|
|
30
|
+
|
|
31
|
+
Raises:
|
|
32
|
+
InsufficientStorageError: If insufficient storage space
|
|
33
|
+
"""
|
|
34
|
+
try:
|
|
35
|
+
src_size = src_path.stat().st_size
|
|
36
|
+
required_space = int(src_size * safety_margin)
|
|
37
|
+
|
|
38
|
+
# Check free space on destination
|
|
39
|
+
free_space = shutil.disk_usage(dst_root).free
|
|
40
|
+
|
|
41
|
+
if free_space < required_space:
|
|
42
|
+
raise InsufficientStorageError(
|
|
43
|
+
f"Insufficient storage space. Required: {required_space/1e9:.1f} GB, "
|
|
44
|
+
f"Available: {free_space/1e9:.1f} GB on {dst_root}",
|
|
45
|
+
required_space=required_space,
|
|
46
|
+
available_space=free_space
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
logger.info(f"Storage check passed: {free_space/1e9:.1f} GB available, "
|
|
50
|
+
f"{required_space/1e9:.1f} GB required")
|
|
51
|
+
|
|
52
|
+
except OSError as e:
|
|
53
|
+
logger.warning(f"Could not check storage capacity: {e}")
|
|
54
|
+
# Don't fail the operation, just log the warning
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
|
|
58
|
+
"""
|
|
59
|
+
Atomically copy file from src to dst, preserving the source file.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
src_path: Source file path
|
|
63
|
+
dst_path: Destination file path
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
True if successful
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
InsufficientStorageError: If not enough space for the operation
|
|
70
|
+
OSError: For other file system errors
|
|
71
|
+
"""
|
|
72
|
+
try:
|
|
73
|
+
# Check space before copy
|
|
74
|
+
src_size = src_path.stat().st_size
|
|
75
|
+
free_space = shutil.disk_usage(dst_path.parent).free
|
|
76
|
+
|
|
77
|
+
if free_space < src_size * 1.1: # 10% safety margin
|
|
78
|
+
raise InsufficientStorageError(
|
|
79
|
+
f"Insufficient space for copy operation. Required: {src_size/1e9:.1f} GB, "
|
|
80
|
+
f"Available: {free_space/1e9:.1f} GB",
|
|
81
|
+
required_space=src_size,
|
|
82
|
+
available_space=free_space
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Use a temporary name during copy for atomicity
|
|
86
|
+
temp_dst = dst_path.with_suffix(dst_path.suffix + '.tmp')
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
shutil.copy2(str(src_path), str(temp_dst))
|
|
90
|
+
temp_dst.rename(dst_path)
|
|
91
|
+
logger.debug(f"Copy successful: {src_path} -> {dst_path}")
|
|
92
|
+
return True
|
|
93
|
+
except Exception:
|
|
94
|
+
# Clean up temp file if copy failed
|
|
95
|
+
if temp_dst.exists():
|
|
96
|
+
temp_dst.unlink(missing_ok=True)
|
|
97
|
+
raise
|
|
98
|
+
|
|
99
|
+
except Exception as e:
|
|
100
|
+
logger.error(f"Copy operation failed: {src_path} -> {dst_path}: {e}")
|
|
101
|
+
raise
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def atomic_move_with_fallback(src_path: Path, dst_path: Path) -> bool:
|
|
105
|
+
"""
|
|
106
|
+
Atomically move file from src to dst, with fallback to copy+remove.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
src_path: Source file path
|
|
110
|
+
dst_path: Destination file path
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
True if successful
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
InsufficientStorageError: If not enough space for the operation
|
|
117
|
+
OSError: For other file system errors
|
|
118
|
+
"""
|
|
119
|
+
try:
|
|
120
|
+
# First try atomic move (same filesystem)
|
|
121
|
+
try:
|
|
122
|
+
src_path.rename(dst_path)
|
|
123
|
+
logger.debug(f"Atomic move successful: {src_path} -> {dst_path}")
|
|
124
|
+
return True
|
|
125
|
+
except OSError as e:
|
|
126
|
+
if e.errno == 18: # Cross-device link
|
|
127
|
+
logger.debug("Cross-device move detected, falling back to copy+remove")
|
|
128
|
+
else:
|
|
129
|
+
raise
|
|
130
|
+
|
|
131
|
+
# Check space before cross-filesystem copy
|
|
132
|
+
src_size = src_path.stat().st_size
|
|
133
|
+
free_space = shutil.disk_usage(dst_path.parent).free
|
|
134
|
+
|
|
135
|
+
if free_space < src_size * 1.1: # 10% safety margin
|
|
136
|
+
raise InsufficientStorageError(
|
|
137
|
+
f"Insufficient space for copy operation. Required: {src_size/1e9:.1f} GB, "
|
|
138
|
+
f"Available: {free_space/1e9:.1f} GB",
|
|
139
|
+
required_space=src_size,
|
|
140
|
+
available_space=free_space
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Fallback to copy+remove for cross-filesystem moves
|
|
144
|
+
logger.info(f"Copying file (cross-filesystem): {src_path} -> {dst_path}")
|
|
145
|
+
|
|
146
|
+
# Use a temporary name during copy for atomicity
|
|
147
|
+
temp_dst = dst_path.with_suffix(dst_path.suffix + '.tmp')
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
shutil.copy2(str(src_path), str(temp_dst))
|
|
151
|
+
temp_dst.rename(dst_path)
|
|
152
|
+
src_path.unlink() # Remove source only after successful copy
|
|
153
|
+
logger.debug(f"Copy+remove successful: {src_path} -> {dst_path}")
|
|
154
|
+
return True
|
|
155
|
+
|
|
156
|
+
except OSError as e:
|
|
157
|
+
# Clean up temp file on failure
|
|
158
|
+
if temp_dst.exists():
|
|
159
|
+
temp_dst.unlink(missing_ok=True)
|
|
160
|
+
# Re-raise with better context
|
|
161
|
+
if e.errno == 28: # No space left on device
|
|
162
|
+
raise InsufficientStorageError(
|
|
163
|
+
f"No space left on device during copy: {e}",
|
|
164
|
+
required_space=src_path.stat().st_size,
|
|
165
|
+
available_space=shutil.disk_usage(dst_path.parent).free
|
|
166
|
+
)
|
|
167
|
+
raise
|
|
168
|
+
|
|
169
|
+
except Exception as e:
|
|
170
|
+
logger.error(f"Failed to move {src_path} -> {dst_path}: {e}")
|
|
171
|
+
raise
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _get_data_paths():
|
|
175
|
+
"""Return the current data_paths mapping (supports patched instances in tests)."""
|
|
176
|
+
utils_module = import_module("endoreg_db.utils")
|
|
177
|
+
return getattr(utils_module, "data_paths")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _get_path(mapping, key, default):
|
|
181
|
+
"""Access mapping by key using __getitem__ so MagicMocks with side effects work."""
|
|
182
|
+
if mapping is None:
|
|
183
|
+
return default
|
|
184
|
+
try:
|
|
185
|
+
return mapping[key]
|
|
186
|
+
except (KeyError, TypeError):
|
|
187
|
+
return default
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _create_from_file(
|
|
191
|
+
cls_model: Type["VideoFile"],
|
|
192
|
+
file_path: Path,
|
|
193
|
+
center_name: str,
|
|
194
|
+
processor_name: Optional[str] = None,
|
|
195
|
+
video_dir: Path = VIDEO_DIR,
|
|
196
|
+
save: bool = True,
|
|
197
|
+
delete_source: bool = False,
|
|
198
|
+
**kwargs
|
|
199
|
+
) -> "VideoFile":
|
|
200
|
+
"""
|
|
201
|
+
Creates a VideoFile instance from a given video file path with improved error handling.
|
|
202
|
+
|
|
203
|
+
Raises:
|
|
204
|
+
InsufficientStorageError: When not enough disk space
|
|
205
|
+
TranscodingError: When video transcoding fails
|
|
206
|
+
ValueError: When required objects (Center, Processor) not found
|
|
207
|
+
RuntimeError: For other processing errors
|
|
208
|
+
"""
|
|
209
|
+
from endoreg_db.models.administration.center.center import Center
|
|
210
|
+
from endoreg_db.models.medical.hardware import EndoscopyProcessor
|
|
211
|
+
|
|
212
|
+
original_file_name = file_path.name
|
|
213
|
+
original_suffix = file_path.suffix
|
|
214
|
+
final_storage_path = None
|
|
215
|
+
transcoded_file_path = None
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
# Ensure we operate under the canonical video path root
|
|
219
|
+
data_paths = _get_data_paths()
|
|
220
|
+
resolved_video_dir = _get_path(data_paths, "video", video_dir)
|
|
221
|
+
video_dir = Path(resolved_video_dir)
|
|
222
|
+
storage_root_default = Path(video_dir).parent
|
|
223
|
+
resolved_storage_root = _get_path(data_paths, "storage", storage_root_default)
|
|
224
|
+
storage_root = Path(resolved_storage_root)
|
|
225
|
+
storage_root.mkdir(parents=True, exist_ok=True)
|
|
226
|
+
|
|
227
|
+
# Check storage capacity before starting any work
|
|
228
|
+
check_storage_capacity(file_path, storage_root)
|
|
229
|
+
|
|
230
|
+
# 1. Transcode if necessary
|
|
231
|
+
logger.debug("Checking transcoding requirement for %s", file_path)
|
|
232
|
+
temp_transcode_dir = TMP_VIDEO_DIR / 'transcoding'
|
|
233
|
+
temp_transcode_dir.mkdir(parents=True, exist_ok=True)
|
|
234
|
+
|
|
235
|
+
# Use a unique name for the potential transcoded file
|
|
236
|
+
temp_transcoded_output_path = temp_transcode_dir / f"{uuid.uuid4()}{original_suffix}"
|
|
237
|
+
|
|
238
|
+
try:
|
|
239
|
+
transcoded_file_path = transcode_videofile_if_required(
|
|
240
|
+
input_path=file_path,
|
|
241
|
+
output_path=temp_transcoded_output_path
|
|
242
|
+
)
|
|
243
|
+
if transcoded_file_path is None:
|
|
244
|
+
raise TranscodingError(f"Transcoding check/process failed for {file_path}")
|
|
245
|
+
except Exception as e:
|
|
246
|
+
raise TranscodingError(f"Video transcoding failed: {e}") from e
|
|
247
|
+
|
|
248
|
+
logger.debug("Using file for hashing: %s", transcoded_file_path)
|
|
249
|
+
|
|
250
|
+
# 2. Calculate hash (this will be the raw_video_hash)
|
|
251
|
+
video_hash = get_video_hash(transcoded_file_path)
|
|
252
|
+
if not video_hash:
|
|
253
|
+
raise ValueError(f"Could not calculate video hash for {transcoded_file_path}")
|
|
254
|
+
logger.info("Calculated raw video hash: %s for %s", video_hash, original_file_name)
|
|
255
|
+
|
|
256
|
+
# 3. Check if hash already exists
|
|
257
|
+
if cls_model.check_hash_exists(video_hash=video_hash):
|
|
258
|
+
existing_video = cls_model.objects.get(video_hash=video_hash)
|
|
259
|
+
logger.warning("Video with hash %s already exists (UUID: %s)", video_hash, existing_video.uuid)
|
|
260
|
+
|
|
261
|
+
# Check if the existing video has a valid file
|
|
262
|
+
existing_raw_path = existing_video.get_raw_file_path()
|
|
263
|
+
if existing_video.has_raw and existing_raw_path and existing_raw_path.exists():
|
|
264
|
+
logger.warning("Video with hash %s already exists and file is present. Returning existing instance.", video_hash)
|
|
265
|
+
# Clean up transcoded file if it was created temporarily
|
|
266
|
+
if transcoded_file_path != file_path and transcoded_file_path.exists():
|
|
267
|
+
transcoded_file_path.unlink(missing_ok=True)
|
|
268
|
+
return existing_video
|
|
269
|
+
|
|
270
|
+
logger.warning("Video with hash %s exists but file is missing. Deleting orphaned record.", video_hash)
|
|
271
|
+
existing_video.delete()
|
|
272
|
+
|
|
273
|
+
# 4. Generate UUID and final storage path
|
|
274
|
+
new_file_name, uuid_val = get_uuid_filename(transcoded_file_path)
|
|
275
|
+
final_storage_path = video_dir / new_file_name
|
|
276
|
+
final_storage_path.parent.mkdir(parents=True, exist_ok=True)
|
|
277
|
+
|
|
278
|
+
# 5. Move or Copy the file to final storage using improved method
|
|
279
|
+
try:
|
|
280
|
+
if delete_source and transcoded_file_path == file_path:
|
|
281
|
+
logger.debug("Moving original file %s to %s", file_path, final_storage_path)
|
|
282
|
+
atomic_move_with_fallback(file_path, final_storage_path)
|
|
283
|
+
elif delete_source and transcoded_file_path != file_path:
|
|
284
|
+
logger.debug("Moving transcoded file %s to %s", transcoded_file_path, final_storage_path)
|
|
285
|
+
atomic_move_with_fallback(transcoded_file_path, final_storage_path)
|
|
286
|
+
else:
|
|
287
|
+
logger.debug("Copying file %s to %s", transcoded_file_path, final_storage_path)
|
|
288
|
+
atomic_copy_with_fallback(transcoded_file_path, final_storage_path)
|
|
289
|
+
if transcoded_file_path != file_path and transcoded_file_path.exists():
|
|
290
|
+
logger.debug("Cleaning up temporary transcoded file %s", transcoded_file_path)
|
|
291
|
+
transcoded_file_path.unlink(missing_ok=True)
|
|
292
|
+
except InsufficientStorageError:
|
|
293
|
+
# Re-raise storage errors as-is
|
|
294
|
+
raise
|
|
295
|
+
except Exception as e:
|
|
296
|
+
raise RuntimeError(f"Failed to move file to final storage: {e}") from e
|
|
297
|
+
|
|
298
|
+
# 6. Verify hash after move/copy
|
|
299
|
+
final_hash = get_video_hash(final_storage_path)
|
|
300
|
+
if final_hash != video_hash:
|
|
301
|
+
logger.error("Hash mismatch after file operation! Expected %s, got %s", video_hash, final_hash)
|
|
302
|
+
final_storage_path.unlink(missing_ok=True)
|
|
303
|
+
raise RuntimeError(f"Hash mismatch after file operation for {final_storage_path}")
|
|
304
|
+
|
|
305
|
+
# 7. Get related objects
|
|
306
|
+
try:
|
|
307
|
+
center = Center.objects.get(name=center_name)
|
|
308
|
+
processor = EndoscopyProcessor.objects.get(name=processor_name) if processor_name else None
|
|
309
|
+
logger.debug("Found Center: %s, Processor: %s", center.name, processor.name if processor else "None")
|
|
310
|
+
except Center.DoesNotExist as e:
|
|
311
|
+
logger.error("Center '%s' not found", center_name)
|
|
312
|
+
if final_storage_path and final_storage_path.exists():
|
|
313
|
+
final_storage_path.unlink(missing_ok=True)
|
|
314
|
+
raise ValueError(f"Center '{center_name}' not found.") from e
|
|
315
|
+
except EndoscopyProcessor.DoesNotExist as e:
|
|
316
|
+
logger.error("Processor '%s' not found", processor_name)
|
|
317
|
+
if final_storage_path and final_storage_path.exists():
|
|
318
|
+
final_storage_path.unlink(missing_ok=True)
|
|
319
|
+
raise ValueError(f"Processor '{processor_name}' not found.") from e
|
|
320
|
+
|
|
321
|
+
# 8. Create the VideoFile instance
|
|
322
|
+
logger.info("Creating new VideoFile instance with UUID: %s", uuid_val)
|
|
323
|
+
# Store FileField path relative to storage root including the videos prefix
|
|
324
|
+
storage_base = Path(_get_path(data_paths, "storage", final_storage_path.parent))
|
|
325
|
+
relative_name = (final_storage_path.relative_to(storage_base)).as_posix()
|
|
326
|
+
video = cls_model(
|
|
327
|
+
uuid=uuid_val,
|
|
328
|
+
raw_file=relative_name,
|
|
329
|
+
processed_file=None,
|
|
330
|
+
center=center,
|
|
331
|
+
processor=processor,
|
|
332
|
+
original_file_name=original_file_name,
|
|
333
|
+
video_hash=video_hash,
|
|
334
|
+
processed_video_hash=None,
|
|
335
|
+
suffix=original_suffix,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
# 9. Save the instance if requested
|
|
339
|
+
if save:
|
|
340
|
+
logger.info("Saving new VideoFile instance (UUID: %s)", uuid_val)
|
|
341
|
+
video.save()
|
|
342
|
+
logger.info("Successfully created VideoFile PK %s (UUID: %s)", video.pk, video.uuid)
|
|
343
|
+
|
|
344
|
+
return video
|
|
345
|
+
|
|
346
|
+
except (InsufficientStorageError, TranscodingError, ValueError):
|
|
347
|
+
# Re-raise these specific errors as-is
|
|
348
|
+
raise
|
|
349
|
+
except Exception as e:
|
|
350
|
+
logger.error("Failed to create VideoFile from %s: (%s) %s", file_path, type(e).__name__, e, exc_info=True)
|
|
351
|
+
# Clean up any created files
|
|
352
|
+
if final_storage_path and final_storage_path.exists():
|
|
353
|
+
logger.warning("Cleaning up orphaned file: %s", final_storage_path)
|
|
354
|
+
final_storage_path.unlink(missing_ok=True)
|
|
355
|
+
if transcoded_file_path and transcoded_file_path != file_path and transcoded_file_path.exists():
|
|
356
|
+
logger.warning("Cleaning up orphaned transcoded file: %s", transcoded_file_path)
|
|
357
|
+
transcoded_file_path.unlink(missing_ok=True)
|
|
358
|
+
raise RuntimeError(f"Video processing failed: {e}") from e
|