endoreg-db 0.6.4__py3-none-any.whl → 0.8.2__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/admin.py +26 -26
- endoreg_db/api_urls.py +4 -0
- endoreg_db/apps.py +12 -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/env.py +101 -0
- endoreg_db/data/__init__.py +12 -0
- endoreg_db/data/ai_model/data.yaml +1 -1
- endoreg_db/data/ai_model_label/label/polyp_classification.yaml +52 -0
- endoreg_db/data/ai_model_label/label-set/data.yaml +20 -1
- endoreg_db/data/ai_model_label/label-set/polyp_classifications.yaml +25 -0
- endoreg_db/data/center/data.yaml +13 -12
- endoreg_db/data/center_shift/ukw.yaml +9 -0
- endoreg_db/data/db_summary.csv +58 -0
- endoreg_db/data/db_summary.xlsx +0 -0
- endoreg_db/data/disease/misc.yaml +1 -2
- endoreg_db/data/endoscopy_processor/data.yaml +3 -0
- endoreg_db/data/event/cardiology.yaml +0 -13
- endoreg_db/data/examination/examinations/data.yaml +14 -9
- endoreg_db/data/examination_indication/endoscopy.yaml +30 -30
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +11 -11
- 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 +3 -46
- 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_morphology_classification_choice → finding_classification_choice}/colon_lesion_circularity_default.yaml +0 -2
- 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_morphology_classification_choice → finding_classification_choice}/colon_lesion_nice.yaml +4 -7
- endoreg_db/data/{finding_morphology_classification_choice → finding_classification_choice}/colon_lesion_paris.yaml +0 -8
- endoreg_db/data/{finding_morphology_classification_choice → finding_classification_choice}/colon_lesion_planarity_default.yaml +6 -13
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +14 -0
- endoreg_db/data/{finding_morphology_classification_choice → finding_classification_choice}/colon_lesion_surface_intact_default.yaml +3 -6
- endoreg_db/data/{finding_location_classification_choice/colonoscopy.yaml → finding_classification_choice/colonoscopy_location.yaml} +11 -22
- 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_colonoscopy.yaml +8 -3
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +6 -6
- endoreg_db/data/finding_type/data.yaml +23 -10
- endoreg_db/data/gender/data.yaml +8 -1
- endoreg_db/data/information_source/annotation.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/misc.yaml +43 -0
- endoreg_db/data/medication/anticoagulation.yaml +5 -5
- endoreg_db/data/medication/tah.yaml +5 -5
- endoreg_db/data/medication_intake_time/base.yaml +4 -4
- endoreg_db/data/names_first/first_names.yaml +3 -0
- endoreg_db/data/pdf_type/data.yaml +26 -2
- 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/report_reader_flag/rkh-histology-generic.yaml +10 -0
- endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +5 -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 +6 -6
- endoreg_db/data/requirement/disease_classification_choice_cardiovascular.yaml +9 -6
- endoreg_db/data/requirement/disease_hepatology.yaml +1 -1
- endoreg_db/data/requirement/disease_misc.yaml +3 -3
- endoreg_db/data/requirement/disease_renal.yaml +18 -2
- endoreg_db/data/requirement/{colonoscopy_indications.yaml → endoscopy_bleeding_risk.yaml} +6 -3
- endoreg_db/data/requirement/event_cardiology.yaml +17 -17
- 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 +352 -31
- 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 +36 -35
- endoreg_db/data/requirement_operator/model_operators.yaml +13 -7
- 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 +42 -2
- endoreg_db/data/requirement_type/requirement_types.yaml +82 -0
- endoreg_db/data/shift/endoscopy.yaml +21 -0
- endoreg_db/data/shift_type/base.yaml +35 -0
- endoreg_db/data/tag/requirement_set_tags.yaml +11 -0
- endoreg_db/data/unit/concentration.yaml +23 -0
- endoreg_db/exceptions.py +19 -0
- endoreg_db/forms/patient_finding_intervention_form.py +4 -5
- endoreg_db/forms/patient_form.py +7 -6
- endoreg_db/forms/questionnaires/__init__.py +1 -1
- endoreg_db/forms/questionnaires/tto_questionnaire.py +19 -19
- endoreg_db/helpers/count_db.py +45 -0
- endoreg_db/helpers/data_loader.py +208 -0
- endoreg_db/helpers/default_objects.py +359 -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_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 +422 -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 +2 -7
- endoreg_db/management/commands/load_base_db_data.py +1 -0
- endoreg_db/management/commands/load_endoscope_data.py +2 -2
- endoreg_db/management/commands/load_examination_indication_data.py +2 -3
- endoreg_db/management/commands/load_finding_data.py +49 -92
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +0 -1
- endoreg_db/management/commands/load_information_source.py +13 -7
- endoreg_db/management/commands/load_name_data.py +37 -0
- endoreg_db/management/commands/load_qualification_data.py +59 -0
- endoreg_db/management/commands/load_requirement_data.py +30 -6
- endoreg_db/management/commands/load_shift_data.py +60 -0
- endoreg_db/management/commands/load_tag_data.py +57 -0
- endoreg_db/management/commands/register_ai_model.py +1 -1
- 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/migrations/0001_initial.py +625 -813
- endoreg_db/migrations/0002_add_video_correction_models.py +52 -0
- endoreg_db/models/__init__.py +270 -307
- endoreg_db/models/administration/__init__.py +116 -0
- endoreg_db/models/{ai_model → administration/ai}/__init__.py +6 -1
- endoreg_db/models/administration/ai/active_model.py +35 -0
- endoreg_db/models/administration/ai/ai_model.py +156 -0
- endoreg_db/models/{ai_model → administration/ai}/model_type.py +6 -1
- endoreg_db/models/administration/case/__init__.py +19 -0
- endoreg_db/models/administration/case/case.py +114 -0
- endoreg_db/models/{case_template → administration/case/case_template}/case_template.py +3 -3
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule.py +3 -10
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule_value.py +2 -4
- endoreg_db/models/{case_template → administration/case/case_template}/case_template_type.py +1 -3
- endoreg_db/models/{center → administration/center}/__init__.py +3 -1
- endoreg_db/models/administration/center/center.py +61 -0
- endoreg_db/models/administration/center/center_product.py +64 -0
- endoreg_db/models/{center → administration/center}/center_resource.py +19 -3
- 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/{persons → administration/person/names}/first_name.py +1 -1
- endoreg_db/models/{persons → administration/person/names}/last_name.py +2 -3
- 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/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/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/{product → administration/product}/product_weight.py +9 -0
- endoreg_db/models/{product → administration/product}/reference_product.py +26 -11
- 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 -1
- 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 +45 -74
- 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/{annotation → label}/video_segmentation_labelset.py +7 -0
- endoreg_db/models/media/__init__.py +14 -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 +608 -0
- endoreg_db/models/media/pdf/report_file.py +162 -0
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +77 -0
- endoreg_db/models/media/video/__init__.py +4 -0
- endoreg_db/models/media/video/create_from_file.py +336 -0
- endoreg_db/models/media/video/pipe_1.py +207 -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 +680 -0
- endoreg_db/models/media/video/video_file_ai.py +443 -0
- endoreg_db/models/media/video/video_file_anonymize.py +348 -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 +129 -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 +166 -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_meta.py +11 -0
- endoreg_db/models/media/video/video_file_segments.py +209 -0
- endoreg_db/models/medical/__init__.py +146 -0
- endoreg_db/models/{contraindication → medical/contraindication}/__init__.py +1 -5
- endoreg_db/models/{disease.py → medical/disease.py} +60 -52
- endoreg_db/models/{event.py → medical/event.py} +31 -54
- endoreg_db/models/{examination → medical/examination}/__init__.py +1 -1
- endoreg_db/models/medical/examination/examination.py +148 -0
- endoreg_db/models/{examination → medical/examination}/examination_indication.py +64 -35
- endoreg_db/models/{examination → medical/examination}/examination_time.py +0 -4
- endoreg_db/models/{examination → medical/examination}/examination_time_type.py +1 -8
- endoreg_db/models/{examination → medical/examination}/examination_type.py +1 -7
- 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/{finding → medical/finding}/finding_intervention.py +2 -10
- endoreg_db/models/medical/finding/finding_type.py +35 -0
- endoreg_db/models/medical/hardware/__init__.py +8 -0
- endoreg_db/models/{hardware → medical/hardware}/endoscope.py +28 -23
- endoreg_db/models/medical/laboratory/__init__.py +5 -0
- endoreg_db/models/medical/laboratory/lab_value.py +419 -0
- endoreg_db/models/{medication → medical/medication}/medication.py +1 -3
- endoreg_db/models/{medication → medical/medication}/medication_indication_type.py +8 -3
- endoreg_db/models/{medication → medical/medication}/medication_intake_time.py +21 -3
- endoreg_db/models/{medication → medical/medication}/medication_schedule.py +13 -5
- endoreg_db/models/{organ → medical/organ}/__init__.py +3 -6
- 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/{persons → medical}/patient/patient_examination_indication.py +21 -9
- endoreg_db/models/medical/patient/patient_finding.py +357 -0
- endoreg_db/models/medical/patient/patient_finding_classification.py +207 -0
- endoreg_db/models/{patient → medical/patient}/patient_finding_intervention.py +15 -1
- endoreg_db/models/medical/patient/patient_lab_sample.py +148 -0
- endoreg_db/models/{persons → medical}/patient/patient_lab_value.py +40 -15
- endoreg_db/models/medical/patient/patient_medication.py +104 -0
- endoreg_db/models/medical/patient/patient_medication_schedule.py +136 -0
- endoreg_db/models/{risk → medical/risk}/risk_type.py +0 -4
- endoreg_db/models/{data_file/metadata → metadata}/__init__.py +6 -0
- endoreg_db/models/metadata/frame_ocr_result.py +0 -0
- endoreg_db/models/metadata/model_meta.py +193 -0
- endoreg_db/models/metadata/model_meta_logic.py +236 -0
- endoreg_db/models/{data_file/metadata → metadata}/pdf_meta.py +28 -13
- endoreg_db/models/metadata/sensitive_meta.py +288 -0
- endoreg_db/models/metadata/sensitive_meta_logic.py +643 -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 +17 -0
- endoreg_db/models/other/distribution/date_value_distribution.py +0 -2
- endoreg_db/models/other/distribution/numeric_value_distribution.py +30 -2
- endoreg_db/models/{emission → other/emission}/emission_factor.py +15 -6
- endoreg_db/models/{persons → other}/gender.py +8 -3
- endoreg_db/models/other/information_source.py +159 -0
- endoreg_db/models/other/material.py +10 -2
- endoreg_db/models/other/resource.py +6 -2
- endoreg_db/models/other/tag.py +27 -0
- endoreg_db/models/other/transport_route.py +13 -2
- endoreg_db/models/{unit.py → other/unit.py} +16 -6
- endoreg_db/models/other/waste.py +10 -3
- endoreg_db/models/requirement/requirement.py +556 -114
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +4 -132
- 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 +80 -87
- endoreg_db/models/requirement/requirement_operator.py +132 -14
- endoreg_db/models/requirement/requirement_set.py +181 -21
- endoreg_db/models/rule/__init__.py +13 -0
- endoreg_db/models/{rules → rule}/rule.py +6 -3
- endoreg_db/models/{rules → rule}/rule_attribute_dtype.py +0 -2
- endoreg_db/models/{rules → rule}/rule_type.py +0 -2
- endoreg_db/models/{rules → rule}/ruleset.py +0 -2
- 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/models/video_metadata.py +66 -0
- endoreg_db/models/video_processing.py +153 -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 +147 -10
- endoreg_db/serializers/{raw_pdf_meta_validation.py → _old/raw_pdf_meta_validation.py} +3 -3
- endoreg_db/serializers/{raw_video_meta_validation.py → _old/raw_video_meta_validation.py} +18 -14
- 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 +152 -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/misc/vop_patient_data.py +120 -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/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 +241 -0
- endoreg_db/services/lookup_store.py +122 -0
- endoreg_db/services/ollama_api_docs.py +1528 -0
- endoreg_db/services/pdf_import.py +963 -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 +1118 -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/urls/__init__.py +70 -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 +44 -0
- endoreg_db/urls/media.py +229 -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/stats.py +46 -0
- endoreg_db/urls/upload.py +20 -0
- endoreg_db/urls/video.py +61 -0
- endoreg_db/urls.py +6 -283
- endoreg_db/utils/__init__.py +66 -57
- endoreg_db/utils/ai/__init__.py +9 -0
- endoreg_db/{models/ai_model/utils.py → utils/ai/get.py} +1 -4
- endoreg_db/{models/ai_model/lightning → utils/ai}/inference_dataset.py +0 -1
- endoreg_db/{models/ai_model/lightning → utils/ai}/multilabel_classification_net.py +14 -10
- endoreg_db/{models/ai_model/lightning → utils/ai}/postprocess.py +15 -5
- endoreg_db/utils/ai/predict.py +291 -0
- endoreg_db/{models/ai_model/lightning → utils/ai}/preprocess.py +1 -1
- endoreg_db/utils/calc_duration_seconds.py +24 -0
- endoreg_db/utils/case_generator/__init__.py +0 -0
- endoreg_db/utils/check_video_files.py +148 -0
- endoreg_db/utils/dataloader.py +50 -12
- endoreg_db/utils/dates.py +21 -0
- endoreg_db/utils/env.py +33 -0
- endoreg_db/utils/extract_specific_frames.py +72 -0
- endoreg_db/utils/file_operations.py +29 -1
- endoreg_db/utils/fix_video_path_direct.py +141 -0
- endoreg_db/utils/frame_anonymization_utils.py +463 -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 +2 -0
- endoreg_db/utils/paths.py +100 -82
- 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/db_config.py +1 -1
- 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/translation.py +27 -0
- endoreg_db/utils/validate_video_detailed.py +357 -0
- endoreg_db/utils/video/__init__.py +19 -6
- endoreg_db/utils/video/extract_frames.py +37 -70
- endoreg_db/utils/video/ffmpeg_wrapper.py +772 -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 +282 -2
- 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 +66 -0
- endoreg_db/views/auth/__init__.py +13 -0
- endoreg_db/views/{views.py → auth/keycloak.py} +19 -13
- 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 +386 -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 +596 -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/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 +11 -0
- endoreg_db/views/pdf/pdf_media.py +239 -0
- endoreg_db/views/pdf/pdf_stream_views.py +127 -0
- endoreg_db/views/pdf/reimport.py +161 -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 +483 -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 +64 -0
- endoreg_db/views/video/correction.py +672 -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/{views_for_timeline.py → video/timeline.py} +3 -3
- 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 +329 -0
- endoreg_db/views/video/video_media.py +158 -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_reprocess.py +40 -0
- endoreg_db/views/video/video_stream.py +306 -0
- endoreg_db-0.8.2.dist-info/METADATA +384 -0
- endoreg_db-0.8.2.dist-info/RECORD +790 -0
- endoreg_db/data/agl_service/data.yaml +0 -19
- endoreg_db/data/finding_location_classification/colonoscopy.yaml +0 -46
- endoreg_db/data/finding_morphology_classification/colonoscopy.yaml +0 -48
- endoreg_db/data/finding_morphology_classification_choice/colonoscopy_size.yaml +0 -57
- endoreg_db/management/commands/_load_model_template.py +0 -41
- endoreg_db/management/commands/delete_all.py +0 -18
- endoreg_db/management/commands/fetch_legacy_image_dataset.py +0 -32
- endoreg_db/management/commands/fix_auth_permission.py +0 -20
- endoreg_db/management/commands/load_active_model_data.py +0 -45
- endoreg_db/management/commands/load_g_play_data.py +0 -113
- endoreg_db/management/commands/load_logging_data.py +0 -39
- endoreg_db/management/commands/load_lx_data.py +0 -64
- endoreg_db/management/commands/load_medication_indication_data.py +0 -63
- endoreg_db/management/commands/load_medication_indication_type_data.py +0 -41
- endoreg_db/management/commands/load_medication_intake_time_data.py +0 -41
- endoreg_db/management/commands/load_medication_schedule_data.py +0 -55
- endoreg_db/management/commands/load_network_data.py +0 -57
- endoreg_db/migrations/0002_alter_frame_image_alter_rawframe_image.py +0 -23
- endoreg_db/migrations/0003_alter_frame_image_alter_rawframe_image.py +0 -23
- endoreg_db/migrations/0004_alter_rawvideofile_file_alter_video_file.py +0 -25
- endoreg_db/migrations/0005_rawvideofile_frame_count_and_more.py +0 -33
- endoreg_db/migrations/0006_frame_extracted_rawframe_extracted.py +0 -23
- endoreg_db/migrations/0007_rename_pseudo_patient_video_patient_and_more.py +0 -24
- endoreg_db/migrations/0008_remove_reportfile_patient_examination_and_more.py +0 -48
- endoreg_db/migrations/0009_requirementoperator_requirementsettype_and_more.py +0 -154
- endoreg_db/models/ai_model/active_model.py +0 -9
- endoreg_db/models/ai_model/ai_model.py +0 -90
- endoreg_db/models/ai_model/lightning/__init__.py +0 -3
- endoreg_db/models/ai_model/lightning/predict.py +0 -172
- endoreg_db/models/ai_model/lightning/prediction_visualizer.py +0 -55
- endoreg_db/models/ai_model/lightning/run_visualizer.py +0 -21
- endoreg_db/models/ai_model/model_meta.py +0 -240
- endoreg_db/models/annotation/__init__.py +0 -32
- endoreg_db/models/annotation/anonymized_image_annotation.py +0 -115
- endoreg_db/models/annotation/binary_classification_annotation_task.py +0 -117
- endoreg_db/models/annotation/image_classification.py +0 -86
- endoreg_db/models/annotation/video_segmentation_annotation.py +0 -52
- endoreg_db/models/case/__init__.py +0 -1
- endoreg_db/models/case/case.py +0 -34
- endoreg_db/models/center/center.py +0 -51
- endoreg_db/models/center/center_product.py +0 -33
- endoreg_db/models/center/center_waste.py +0 -16
- endoreg_db/models/data_file/__init__.py +0 -39
- endoreg_db/models/data_file/base_classes/__init__.py +0 -7
- endoreg_db/models/data_file/base_classes/abstract_frame.py +0 -98
- endoreg_db/models/data_file/base_classes/abstract_pdf.py +0 -127
- endoreg_db/models/data_file/base_classes/abstract_video.py +0 -806
- endoreg_db/models/data_file/base_classes/frame_helpers.py +0 -17
- endoreg_db/models/data_file/base_classes/prepare_bulk_frames.py +0 -19
- endoreg_db/models/data_file/base_classes/utils.py +0 -58
- endoreg_db/models/data_file/frame.py +0 -29
- endoreg_db/models/data_file/import_classes/__init__.py +0 -18
- endoreg_db/models/data_file/import_classes/processing_functions/__init__.py +0 -35
- endoreg_db/models/data_file/import_classes/processing_functions/pdf.py +0 -28
- endoreg_db/models/data_file/import_classes/processing_functions/video.py +0 -260
- endoreg_db/models/data_file/import_classes/raw_pdf.py +0 -254
- endoreg_db/models/data_file/import_classes/raw_video.py +0 -290
- endoreg_db/models/data_file/metadata/sensitive_meta.py +0 -290
- endoreg_db/models/data_file/metadata/video_meta.py +0 -199
- endoreg_db/models/data_file/report_file.py +0 -56
- endoreg_db/models/data_file/video/__init__.py +0 -11
- endoreg_db/models/data_file/video/import_meta.py +0 -25
- endoreg_db/models/data_file/video/video.py +0 -196
- endoreg_db/models/data_file/video_segment.py +0 -214
- endoreg_db/models/examination/examination.py +0 -67
- endoreg_db/models/finding/__init__.py +0 -11
- endoreg_db/models/finding/finding.py +0 -75
- endoreg_db/models/finding/finding_location_classification.py +0 -94
- endoreg_db/models/finding/finding_morphology_classification.py +0 -89
- endoreg_db/models/finding/finding_type.py +0 -22
- endoreg_db/models/hardware/__init__.py +0 -2
- endoreg_db/models/information_source.py +0 -65
- endoreg_db/models/laboratory/__init__.py +0 -1
- endoreg_db/models/laboratory/lab_value.py +0 -162
- endoreg_db/models/logging/__init__.py +0 -11
- endoreg_db/models/logging/agl_service.py +0 -19
- endoreg_db/models/logging/base.py +0 -22
- endoreg_db/models/logging/log_type.py +0 -23
- endoreg_db/models/logging/network_device.py +0 -27
- endoreg_db/models/lx/__init__.py +0 -4
- endoreg_db/models/lx/client.py +0 -57
- endoreg_db/models/lx/identity.py +0 -34
- endoreg_db/models/lx/permission.py +0 -18
- endoreg_db/models/lx/user.py +0 -16
- endoreg_db/models/network/__init__.py +0 -9
- endoreg_db/models/network/agl_service.py +0 -38
- endoreg_db/models/network/network_device.py +0 -58
- endoreg_db/models/network/network_device_type.py +0 -23
- endoreg_db/models/other/distribution.py +0 -5
- endoreg_db/models/patient/__init__.py +0 -24
- endoreg_db/models/patient/patient_examination.py +0 -182
- endoreg_db/models/patient/patient_finding.py +0 -143
- endoreg_db/models/patient/patient_finding_location.py +0 -120
- endoreg_db/models/patient/patient_finding_morphology.py +0 -166
- endoreg_db/models/permissions/__init__.py +0 -44
- endoreg_db/models/persons/__init__.py +0 -34
- endoreg_db/models/persons/examiner/__init__.py +0 -2
- endoreg_db/models/persons/examiner/examiner.py +0 -60
- endoreg_db/models/persons/examiner/examiner_type.py +0 -2
- endoreg_db/models/persons/patient/__init__.py +0 -8
- endoreg_db/models/persons/patient/patient.py +0 -389
- endoreg_db/models/persons/patient/patient_disease.py +0 -22
- endoreg_db/models/persons/patient/patient_event.py +0 -52
- endoreg_db/models/persons/patient/patient_lab_sample.py +0 -108
- endoreg_db/models/persons/patient/patient_medication.py +0 -59
- endoreg_db/models/persons/patient/patient_medication_schedule.py +0 -88
- endoreg_db/models/persons/portal_user_information.py +0 -27
- endoreg_db/models/prediction/__init__.py +0 -8
- endoreg_db/models/prediction/image_classification.py +0 -51
- endoreg_db/models/prediction/video_prediction_meta.py +0 -306
- endoreg_db/models/product/product.py +0 -110
- endoreg_db/models/product/product_group.py +0 -27
- endoreg_db/models/product/product_material.py +0 -28
- endoreg_db/models/questionnaires/__init__.py +0 -114
- endoreg_db/models/quiz/__init__.py +0 -9
- endoreg_db/models/quiz/quiz_answer.py +0 -41
- endoreg_db/models/quiz/quiz_question.py +0 -54
- endoreg_db/models/report_reader/report_reader_config.py +0 -53
- endoreg_db/models/rules/__init__.py +0 -5
- endoreg_db/queries/get/__init__.py +0 -6
- endoreg_db/queries/get/center.py +0 -42
- endoreg_db/queries/get/model.py +0 -13
- endoreg_db/queries/get/patient.py +0 -14
- endoreg_db/queries/get/patient_examination.py +0 -20
- endoreg_db/queries/get/report_file.py +0 -33
- endoreg_db/queries/get/video.py +0 -31
- endoreg_db/serializers/ai_model.py +0 -19
- endoreg_db/serializers/annotation.py +0 -14
- endoreg_db/serializers/center.py +0 -11
- endoreg_db/serializers/examination.py +0 -33
- endoreg_db/serializers/frame.py +0 -9
- endoreg_db/serializers/hardware.py +0 -21
- endoreg_db/serializers/label.py +0 -22
- endoreg_db/serializers/patient.py +0 -33
- endoreg_db/serializers/prediction.py +0 -10
- endoreg_db/serializers/raw_pdf_anony_text_validation.py +0 -137
- endoreg_db/serializers/report_file.py +0 -7
- endoreg_db/serializers/video.py +0 -20
- endoreg_db/serializers/video_segmentation.py +0 -574
- endoreg_db/tests.py +0 -3
- endoreg_db/utils/legacy_ocr.py +0 -201
- endoreg_db/utils/video/transcode_videofile.py +0 -111
- endoreg_db/views/patient_views.py +0 -90
- endoreg_db/views/raw_pdf_anony_text_validation_views.py +0 -95
- endoreg_db/views/raw_pdf_meta_validation_views.py +0 -111
- endoreg_db/views/raw_video_meta_validation_views.py +0 -148
- endoreg_db/views/report_views.py +0 -96
- endoreg_db/views/video_segmentation_views.py +0 -166
- endoreg_db-0.6.4.dist-info/METADATA +0 -161
- endoreg_db-0.6.4.dist-info/RECORD +0 -470
- /endoreg_db/{case_generator/__init__.py → api/serializers/finding_descriptions.py} +0 -0
- /endoreg_db/{queries/get/annotation.py → api/views/finding_descriptions.py} +0 -0
- /endoreg_db/{queries/get/prediction.py → data/shift/m2.yaml} +0 -0
- /endoreg_db/{queries/get/video_import_meta.py → factories/__init__.py} +0 -0
- /endoreg_db/{queries/get/video_prediction_meta.py → helpers/__init__.py} +0 -0
- /endoreg_db/models/{case_template → administration/case/case_template}/__init__.py +0 -0
- /endoreg_db/models/{persons → administration/person}/person.py +0 -0
- /endoreg_db/models/{product → administration/product}/__init__.py +0 -0
- /endoreg_db/models/{report_reader → media/pdf/report_reader}/__init__.py +0 -0
- /endoreg_db/models/{report_reader → media/pdf/report_reader}/report_reader_flag.py +0 -0
- /endoreg_db/models/{hardware → medical/hardware}/endoscopy_processor.py +0 -0
- /endoreg_db/models/{medication → medical/medication}/__init__.py +0 -0
- /endoreg_db/models/{medication → medical/medication}/medication_indication.py +0 -0
- /endoreg_db/models/{risk → medical/risk}/__init__.py +0 -0
- /endoreg_db/models/{risk → medical/risk}/risk.py +0 -0
- /endoreg_db/models/{emission → other/emission}/__init__.py +0 -0
- /endoreg_db/models/{rules → rule}/rule_applicator.py +0 -0
- /endoreg_db/{case_generator → utils/case_generator}/case_generator.py +0 -0
- /endoreg_db/{case_generator → utils/case_generator}/lab_sample_factory.py +0 -0
- /endoreg_db/{case_generator → utils/case_generator}/utils.py +0 -0
- /endoreg_db/views/{csrf.py → misc/csrf.py} +0 -0
- {endoreg_db-0.6.4.dist-info → endoreg_db-0.8.2.dist-info}/WHEEL +0 -0
- {endoreg_db-0.6.4.dist-info → endoreg_db-0.8.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,67 +1,46 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
-
from typing import TYPE_CHECKING,
|
|
2
|
+
from typing import TYPE_CHECKING, Dict, List, Union
|
|
3
|
+
from endoreg_db.utils.links.requirement_link import RequirementLinks
|
|
4
|
+
import logging
|
|
5
|
+
from subprocess import run
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
3
8
|
|
|
4
|
-
from pydantic import BaseModel
|
|
5
9
|
|
|
6
10
|
QuerySet = models.QuerySet
|
|
7
11
|
|
|
8
12
|
if TYPE_CHECKING:
|
|
9
13
|
from endoreg_db.models import (
|
|
10
|
-
RequirementOperator,
|
|
11
|
-
RequirementSet,
|
|
12
|
-
Examination,
|
|
13
|
-
ExaminationIndication,
|
|
14
|
-
LabValue,
|
|
15
14
|
Disease,
|
|
16
15
|
DiseaseClassificationChoice,
|
|
17
16
|
Event,
|
|
17
|
+
EventClassification,
|
|
18
|
+
EventClassificationChoice,
|
|
19
|
+
Examination,
|
|
20
|
+
ExaminationIndication,
|
|
18
21
|
Finding,
|
|
19
|
-
FindingMorphologyClassificationChoice,
|
|
20
|
-
FindingLocationClassificationChoice,
|
|
21
22
|
FindingIntervention,
|
|
23
|
+
FindingClassification,
|
|
24
|
+
FindingClassificationChoice,
|
|
25
|
+
FindingClassificationType,
|
|
26
|
+
LabValue,
|
|
27
|
+
Medication,
|
|
28
|
+
MedicationIndication,
|
|
29
|
+
MedicationIntakeTime, # Added MedicationIntakeTime
|
|
30
|
+
MedicationSchedule,
|
|
31
|
+
PatientDisease,
|
|
32
|
+
PatientEvent,
|
|
33
|
+
PatientExamination,
|
|
34
|
+
PatientFinding,
|
|
35
|
+
PatientFindingIntervention,
|
|
36
|
+
PatientFindingClassification,
|
|
37
|
+
PatientLabValue,
|
|
38
|
+
PatientMedicationSchedule, # Added PatientMedicationSchedule
|
|
39
|
+
RequirementOperator,
|
|
40
|
+
RequirementSet,
|
|
41
|
+
Gender
|
|
22
42
|
)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class RequirementsModelDict(BaseModel):
|
|
26
|
-
"""
|
|
27
|
-
A class representing a dictionary of models related to a requirement.
|
|
28
|
-
|
|
29
|
-
Attributes:
|
|
30
|
-
requirement_types (QuerySet[RequirementType]): A queryset of requirement types.
|
|
31
|
-
operators (QuerySet[RequirementOperator]): A queryset of operators.
|
|
32
|
-
requirement_sets (QuerySet[RequirementSet]): A queryset of requirement sets.
|
|
33
|
-
examinations (QuerySet[Examination]): A queryset of examinations.
|
|
34
|
-
examination_indications (QuerySet[ExaminationIndication]): A queryset of examination indications.
|
|
35
|
-
lab_values (QuerySet[LabValue]): A queryset of lab values.
|
|
36
|
-
diseases (QuerySet[Disease]): A queryset of diseases.
|
|
37
|
-
disease_classification_choices (QuerySet[DiseaseClassificationChoice]): A queryset of disease classification choices.
|
|
38
|
-
events (QuerySet[Event]): A queryset of events.
|
|
39
|
-
findings (QuerySet[Finding]): A queryset of findings.
|
|
40
|
-
finding_morphology_classification_choices (QuerySet[FindingMorphologyClassificationChoice]): A queryset of finding morphology classification choices.
|
|
41
|
-
finding_location_classification_choices (QuerySet[FindingLocationClassificationChoice]): A queryset of finding location classification choices.
|
|
42
|
-
finding_interventions (QuerySet[FindingIntervention]): A queryset of finding interventions.
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
model_config = {"arbitrary_types_allowed": True}
|
|
46
|
-
requirement_types: Optional[QuerySet["RequirementType"]] = None
|
|
47
|
-
operators: Optional[QuerySet["RequirementOperator"]] = None
|
|
48
|
-
requirement_sets: Optional[QuerySet["RequirementSet"]] = None
|
|
49
|
-
examinations: Optional[QuerySet["Examination"]] = None
|
|
50
|
-
examination_indications: Optional[QuerySet["ExaminationIndication"]] = None
|
|
51
|
-
lab_values: Optional[QuerySet["LabValue"]] = None
|
|
52
|
-
diseases: Optional[QuerySet["Disease"]] = None
|
|
53
|
-
disease_classification_choices: Optional[
|
|
54
|
-
QuerySet["DiseaseClassificationChoice"]
|
|
55
|
-
] = None
|
|
56
|
-
events: Optional[QuerySet["Event"]] = None
|
|
57
|
-
findings: Optional[QuerySet["Finding"]] = None
|
|
58
|
-
finding_morphology_classification_choices: Optional[
|
|
59
|
-
QuerySet["FindingMorphologyClassificationChoice"]
|
|
60
|
-
] = None
|
|
61
|
-
finding_location_classification_choices: Optional[
|
|
62
|
-
QuerySet["FindingLocationClassificationChoice"]
|
|
63
|
-
] = None
|
|
64
|
-
finding_interventions: Optional[QuerySet["FindingIntervention"]] = None
|
|
43
|
+
# from endoreg_db.utils.links.requirement_link import RequirementLinks # Already imported above
|
|
65
44
|
|
|
66
45
|
|
|
67
46
|
class RequirementTypeManager(models.Manager):
|
|
@@ -86,13 +65,9 @@ class RequirementType(models.Model):
|
|
|
86
65
|
|
|
87
66
|
Attributes:
|
|
88
67
|
name (str): The name of the requirement type.
|
|
89
|
-
name_de (str): The German name of the requirement type.
|
|
90
|
-
name_en (str): The English name of the requirement type.
|
|
91
68
|
"""
|
|
92
69
|
|
|
93
70
|
name = models.CharField(max_length=100, unique=True)
|
|
94
|
-
name_de = models.CharField(max_length=100, blank=True, null=True)
|
|
95
|
-
name_en = models.CharField(max_length=100, blank=True, null=True)
|
|
96
71
|
description = models.TextField(blank=True, null=True)
|
|
97
72
|
|
|
98
73
|
objects = RequirementTypeManager()
|
|
@@ -134,15 +109,12 @@ class Requirement(models.Model):
|
|
|
134
109
|
|
|
135
110
|
Attributes:
|
|
136
111
|
name (str): The name of the requirement.
|
|
137
|
-
name_de (str): The German name of the requirement.
|
|
138
|
-
name_en (str): The English name of the requirement.
|
|
139
112
|
description (str): A description of the requirement.
|
|
140
113
|
"""
|
|
141
114
|
|
|
142
115
|
name = models.CharField(max_length=100, unique=True)
|
|
143
|
-
name_de = models.CharField(max_length=100, blank=True, null=True)
|
|
144
|
-
name_en = models.CharField(max_length=100, blank=True, null=True)
|
|
145
116
|
description = models.TextField(blank=True, null=True)
|
|
117
|
+
|
|
146
118
|
numeric_value = models.FloatField(
|
|
147
119
|
blank=True,
|
|
148
120
|
null=True,
|
|
@@ -175,13 +147,13 @@ class Requirement(models.Model):
|
|
|
175
147
|
|
|
176
148
|
objects = RequirementManager()
|
|
177
149
|
|
|
178
|
-
requirement_types = models.ManyToManyField(
|
|
150
|
+
requirement_types = models.ManyToManyField( # type: ignore[assignment]
|
|
179
151
|
"RequirementType",
|
|
180
152
|
blank=True,
|
|
181
153
|
related_name="linked_requirements",
|
|
182
154
|
)
|
|
183
155
|
|
|
184
|
-
operators = models.ManyToManyField(
|
|
156
|
+
operators = models.ManyToManyField( # type: ignore[assignment]
|
|
185
157
|
"RequirementOperator",
|
|
186
158
|
blank=True,
|
|
187
159
|
related_name="required_in",
|
|
@@ -195,66 +167,96 @@ class Requirement(models.Model):
|
|
|
195
167
|
null=True,
|
|
196
168
|
)
|
|
197
169
|
|
|
198
|
-
examinations = models.ManyToManyField(
|
|
170
|
+
examinations = models.ManyToManyField( # type: ignore[assignment]
|
|
199
171
|
"Examination",
|
|
200
172
|
blank=True,
|
|
201
173
|
related_name="required_in",
|
|
202
174
|
)
|
|
203
175
|
|
|
204
|
-
examination_indications = models.ManyToManyField(
|
|
176
|
+
examination_indications = models.ManyToManyField( # type: ignore[assignment]
|
|
205
177
|
"ExaminationIndication",
|
|
206
178
|
blank=True,
|
|
207
179
|
related_name="required_in",
|
|
208
180
|
)
|
|
209
181
|
|
|
210
|
-
diseases = models.ManyToManyField(
|
|
182
|
+
diseases = models.ManyToManyField( # type: ignore[assignment]
|
|
211
183
|
"Disease",
|
|
212
184
|
blank=True,
|
|
213
185
|
related_name="required_in",
|
|
214
186
|
)
|
|
215
187
|
|
|
216
|
-
disease_classification_choices = models.ManyToManyField(
|
|
188
|
+
disease_classification_choices = models.ManyToManyField( # type: ignore[assignment]
|
|
217
189
|
"DiseaseClassificationChoice",
|
|
218
190
|
blank=True,
|
|
219
191
|
related_name="required_in",
|
|
220
192
|
)
|
|
221
193
|
|
|
222
|
-
events = models.ManyToManyField(
|
|
194
|
+
events = models.ManyToManyField( # type: ignore[assignment]
|
|
223
195
|
"Event",
|
|
224
196
|
blank=True,
|
|
225
197
|
related_name="required_in",
|
|
226
198
|
)
|
|
227
199
|
|
|
228
|
-
lab_values = models.ManyToManyField(
|
|
200
|
+
lab_values = models.ManyToManyField( # type: ignore[assignment]
|
|
229
201
|
"LabValue",
|
|
230
202
|
blank=True,
|
|
231
203
|
related_name="required_in",
|
|
232
204
|
)
|
|
233
205
|
|
|
234
|
-
findings = models.ManyToManyField(
|
|
206
|
+
findings = models.ManyToManyField( # type: ignore[assignment]
|
|
235
207
|
"Finding",
|
|
236
208
|
blank=True,
|
|
237
209
|
related_name="required_in",
|
|
238
210
|
)
|
|
239
211
|
|
|
240
|
-
|
|
241
|
-
"
|
|
212
|
+
finding_classifications = models.ManyToManyField( # type: ignore[assignment]
|
|
213
|
+
"FindingClassification",
|
|
242
214
|
blank=True,
|
|
243
215
|
related_name="required_in",
|
|
244
216
|
)
|
|
245
217
|
|
|
246
|
-
|
|
247
|
-
"
|
|
218
|
+
finding_classification_choices = models.ManyToManyField( # type: ignore[assignment]
|
|
219
|
+
"FindingClassificationChoice",
|
|
248
220
|
blank=True,
|
|
249
221
|
related_name="required_in",
|
|
250
222
|
)
|
|
251
223
|
|
|
252
|
-
finding_interventions = models.ManyToManyField(
|
|
224
|
+
finding_interventions = models.ManyToManyField( # type: ignore[assignment]
|
|
253
225
|
"FindingIntervention",
|
|
254
226
|
blank=True,
|
|
255
227
|
related_name="required_in",
|
|
256
228
|
)
|
|
257
229
|
|
|
230
|
+
medications = models.ManyToManyField( # type: ignore[assignment]
|
|
231
|
+
"Medication",
|
|
232
|
+
blank=True,
|
|
233
|
+
related_name="required_in",
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
medication_indications = models.ManyToManyField( # type: ignore[assignment]
|
|
237
|
+
"MedicationIndication",
|
|
238
|
+
blank=True,
|
|
239
|
+
related_name="required_in",
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
medication_intake_times = models.ManyToManyField( # type: ignore[assignment]
|
|
243
|
+
"MedicationIntakeTime",
|
|
244
|
+
blank=True,
|
|
245
|
+
related_name="required_in",
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
medication_schedules = models.ManyToManyField( # type: ignore[assignment]
|
|
249
|
+
"MedicationSchedule",
|
|
250
|
+
blank=True,
|
|
251
|
+
related_name="required_in",
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
genders = models.ManyToManyField( # type: ignore[assignment]
|
|
255
|
+
"Gender",
|
|
256
|
+
blank=True,
|
|
257
|
+
related_name="required_in",
|
|
258
|
+
)
|
|
259
|
+
|
|
258
260
|
if TYPE_CHECKING:
|
|
259
261
|
requirement_types: models.QuerySet[RequirementType]
|
|
260
262
|
operators: models.QuerySet[RequirementOperator]
|
|
@@ -266,60 +268,500 @@ class Requirement(models.Model):
|
|
|
266
268
|
disease_classification_choices: models.QuerySet[DiseaseClassificationChoice]
|
|
267
269
|
events: models.QuerySet[Event]
|
|
268
270
|
findings: models.QuerySet[Finding]
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
]
|
|
272
|
-
finding_location_classification_choices: models.QuerySet[
|
|
273
|
-
FindingLocationClassificationChoice
|
|
274
|
-
]
|
|
271
|
+
finding_classifications: models.QuerySet[FindingClassification]
|
|
272
|
+
finding_classification_choices: models.QuerySet[FindingClassificationChoice]
|
|
275
273
|
finding_interventions: models.QuerySet[FindingIntervention]
|
|
274
|
+
medications: models.QuerySet[Medication]
|
|
275
|
+
medication_indications: models.QuerySet[MedicationIndication]
|
|
276
|
+
medication_intake_times: models.QuerySet[MedicationIntakeTime] # Added type hint
|
|
277
|
+
medication_schedules: models.QuerySet[MedicationSchedule]
|
|
278
|
+
genders: models.QuerySet[Gender]
|
|
276
279
|
|
|
277
280
|
def natural_key(self):
|
|
278
281
|
"""
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
+
Returns a tuple containing the instance's name as its natural key.
|
|
283
|
+
|
|
284
|
+
This tuple provides a unique identifier for serialization purposes.
|
|
282
285
|
"""
|
|
283
286
|
return (self.name,)
|
|
284
287
|
|
|
285
288
|
def __str__(self):
|
|
286
|
-
"""
|
|
289
|
+
"""Returns the name of the requirement as its string representation."""
|
|
290
|
+
return str(self.name)
|
|
287
291
|
|
|
288
|
-
|
|
289
|
-
|
|
292
|
+
@property
|
|
293
|
+
def expected_models(self) -> List[Union[
|
|
294
|
+
"Disease",
|
|
295
|
+
"DiseaseClassificationChoice",
|
|
296
|
+
"Event",
|
|
297
|
+
"EventClassification",
|
|
298
|
+
"EventClassificationChoice",
|
|
299
|
+
"Examination",
|
|
300
|
+
"ExaminationIndication",
|
|
301
|
+
"Finding",
|
|
302
|
+
"FindingIntervention",
|
|
303
|
+
"FindingClassification",
|
|
304
|
+
"FindingClassificationChoice",
|
|
305
|
+
"FindingClassificationType",
|
|
306
|
+
"LabValue",
|
|
307
|
+
"Medication",
|
|
308
|
+
"MedicationIndication",
|
|
309
|
+
"MedicationIntakeTime", # Added MedicationIntakeTime
|
|
310
|
+
"PatientDisease",
|
|
311
|
+
"PatientEvent",
|
|
312
|
+
"PatientExamination",
|
|
313
|
+
"PatientFinding",
|
|
314
|
+
"PatientFindingIntervention",
|
|
315
|
+
"PatientFindingClassification",
|
|
316
|
+
"PatientLabValue",
|
|
317
|
+
"PatientMedicationSchedule", # Added PatientMedicationSchedule
|
|
318
|
+
]]:
|
|
290
319
|
"""
|
|
291
|
-
|
|
320
|
+
Return the list of model classes that are expected as input for evaluating this requirement.
|
|
321
|
+
|
|
322
|
+
The returned models correspond to the requirement types linked to this requirement, mapped via the internal data model dictionary.
|
|
323
|
+
"""
|
|
324
|
+
req_types = self.requirement_types.all()
|
|
325
|
+
req_type_names = [_.name for _ in req_types]
|
|
326
|
+
|
|
327
|
+
expected_models = [self.data_model_dict[_] for _ in req_type_names]
|
|
328
|
+
# e.g. [PatientExamination, PatientFinding]
|
|
329
|
+
return expected_models
|
|
292
330
|
|
|
293
|
-
|
|
331
|
+
@property
|
|
332
|
+
def links(self) -> "RequirementLinks":
|
|
294
333
|
"""
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
many-to-many field of the requirement. The resulting RequirementsModelDict
|
|
299
|
-
includes querysets for requirement types, operators, requirement sets,
|
|
300
|
-
examinations, examination indications, lab values, diseases, disease
|
|
301
|
-
classification choices, events, findings, finding morphology classification
|
|
302
|
-
choices, finding location classification choices, and finding interventions.
|
|
334
|
+
Return a RequirementLinks object containing all non-null related model instances for this requirement.
|
|
335
|
+
|
|
336
|
+
The returned object provides structured access to all associated entities, such as examinations, diseases, findings, classifications, interventions, medications, and related choices, aggregated from the requirement's many-to-many fields.
|
|
303
337
|
"""
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
338
|
+
# requirement_sets is not part of RequirementLinks (avoids circular import); collect other related models
|
|
339
|
+
models_dict = RequirementLinks(
|
|
340
|
+
examinations=[_ for _ in self.examinations.all() if _ is not None],
|
|
341
|
+
examination_indications=[_ for _ in self.examination_indications.all() if _ is not None],
|
|
342
|
+
lab_values=[_ for _ in self.lab_values.all() if _ is not None],
|
|
343
|
+
diseases=[_ for _ in self.diseases.all() if _ is not None],
|
|
344
|
+
disease_classification_choices=[_ for _ in self.disease_classification_choices.all() if _ is not None],
|
|
345
|
+
events=[_ for _ in self.events.all() if _ is not None],
|
|
346
|
+
findings=[_ for _ in self.findings.all() if _ is not None],
|
|
347
|
+
finding_classifications=[_ for _ in self.finding_classifications.all() if _ is not None],
|
|
348
|
+
finding_classification_choices=[_ for _ in self.finding_classification_choices.all() if _ is not None],
|
|
349
|
+
finding_interventions=[_ for _ in self.finding_interventions.all() if _ is not None],
|
|
350
|
+
medications=[_ for _ in self.medications.all() if _ is not None],
|
|
351
|
+
medication_indications=[_ for _ in self.medication_indications.all() if _ is not None],
|
|
352
|
+
medication_intake_times=[_ for _ in self.medication_intake_times.all() if _ is not None],
|
|
318
353
|
)
|
|
319
354
|
return models_dict
|
|
320
355
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
356
|
+
@property
|
|
357
|
+
def data_model_dict(self) -> dict:
|
|
358
|
+
"""
|
|
359
|
+
Provides a mapping from requirement type names to their corresponding model classes.
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
A dictionary where keys are requirement type names and values are model classes used for requirement evaluation.
|
|
363
|
+
"""
|
|
364
|
+
from .requirement_evaluation.requirement_type_parser import data_model_dict
|
|
365
|
+
return data_model_dict
|
|
366
|
+
|
|
367
|
+
@property
|
|
368
|
+
def active_links(self) -> Dict[str, List]:
|
|
369
|
+
"""Returns a dictionary of linked models containing only non-empty entries.
|
|
370
|
+
|
|
371
|
+
The returned dictionary includes only those related model lists that have at least one linked instance.
|
|
372
|
+
"""
|
|
373
|
+
return self.links.active()
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def evaluate(self, *args, mode:str, **kwargs):
|
|
377
|
+
"""
|
|
378
|
+
Evaluates whether the requirement is satisfied for the given input models using linked operators and gender constraints.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
*args: Instances or QuerySets of expected model classes to be evaluated. Each must have a `.links` property returning a `RequirementLinks` object.
|
|
382
|
+
mode: Evaluation mode; "strict" requires all operators to pass, "loose" requires any operator to pass.
|
|
383
|
+
**kwargs: Additional keyword arguments passed to operator evaluations.
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
True if the requirement is satisfied according to the specified mode, linked operators, and gender restrictions; otherwise, False.
|
|
387
|
+
|
|
388
|
+
Raises:
|
|
389
|
+
ValueError: If an invalid mode is provided.
|
|
390
|
+
TypeError: If an input is not an instance or QuerySet of expected models, or lacks a valid `.links` attribute.
|
|
391
|
+
|
|
392
|
+
If the requirement specifies genders, only input containing a patient with a matching gender will be considered valid for evaluation.
|
|
393
|
+
"""
|
|
394
|
+
#TODO Review, Optimize or remove
|
|
395
|
+
if mode not in ["strict", "loose"]:
|
|
396
|
+
raise ValueError(f"Invalid mode: {mode}. Use 'strict' or 'loose'.")
|
|
397
|
+
|
|
398
|
+
evaluate_result_list_func = all if mode == "strict" else any
|
|
399
|
+
|
|
400
|
+
requirement_req_links = self.links
|
|
401
|
+
expected_models = self.expected_models
|
|
402
|
+
|
|
403
|
+
# helpers to avoid passing a complex tuple to isinstance/issubclass which confuses type checkers
|
|
404
|
+
def _is_expected_instance(obj) -> bool:
|
|
405
|
+
for cls in expected_models:
|
|
406
|
+
if isinstance(cls, type):
|
|
407
|
+
try:
|
|
408
|
+
if isinstance(obj, cls):
|
|
409
|
+
return True
|
|
410
|
+
except Exception:
|
|
411
|
+
# cls might not be a runtime type
|
|
412
|
+
continue
|
|
413
|
+
return False
|
|
414
|
+
|
|
415
|
+
def _is_queryset_of_expected(qs) -> bool:
|
|
416
|
+
if not isinstance(qs, models.QuerySet) or not hasattr(qs, 'model'):
|
|
417
|
+
return False
|
|
418
|
+
for cls in expected_models:
|
|
419
|
+
if isinstance(cls, type):
|
|
420
|
+
try:
|
|
421
|
+
if issubclass(qs.model, cls):
|
|
422
|
+
return True
|
|
423
|
+
except Exception:
|
|
424
|
+
continue
|
|
425
|
+
return False
|
|
426
|
+
|
|
427
|
+
# Aggregate RequirementLinks from all input arguments
|
|
428
|
+
aggregated_input_links_data = {}
|
|
429
|
+
processed_inputs_count = 0
|
|
430
|
+
|
|
431
|
+
for _input in args:
|
|
432
|
+
# Check if the input is an instance of any of the expected model types
|
|
433
|
+
if not _is_expected_instance(_input):
|
|
434
|
+
# Allow QuerySets of expected models
|
|
435
|
+
if _is_queryset_of_expected(_input):
|
|
436
|
+
# For QuerySets, evaluate each item individually and return True if any matches
|
|
437
|
+
if not _input.exists(): # Skip empty querysets
|
|
438
|
+
continue
|
|
439
|
+
|
|
440
|
+
queryset_results = []
|
|
441
|
+
for item in _input:
|
|
442
|
+
if not hasattr(item, 'links') or not isinstance(item.links, RequirementLinks):
|
|
443
|
+
raise TypeError(
|
|
444
|
+
f"Item {item} of type {type(item)} in QuerySet does not have a valid .links attribute of type RequirementLinks."
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
# Evaluate this single item against the requirement
|
|
448
|
+
item_input_links = RequirementLinks(**item.links.active())
|
|
449
|
+
|
|
450
|
+
# Evaluate all operators for this single item
|
|
451
|
+
item_operator_results = []
|
|
452
|
+
for operator in self.operators.all():
|
|
453
|
+
try:
|
|
454
|
+
operator_result = operator.evaluate(
|
|
455
|
+
requirement_links=requirement_req_links,
|
|
456
|
+
input_links=item_input_links,
|
|
457
|
+
requirement=self,
|
|
458
|
+
original_input_args=args,
|
|
459
|
+
**kwargs
|
|
460
|
+
)
|
|
461
|
+
item_operator_results.append(operator_result)
|
|
462
|
+
except Exception as e:
|
|
463
|
+
logger.debug(f"Operator {operator.name} evaluation failed for item {item}: {e}")
|
|
464
|
+
item_operator_results.append(False)
|
|
465
|
+
|
|
466
|
+
# Apply evaluation mode for this single item
|
|
467
|
+
item_result = evaluate_result_list_func(item_operator_results) if item_operator_results else True
|
|
468
|
+
queryset_results.append(item_result)
|
|
469
|
+
processed_inputs_count += 1
|
|
470
|
+
|
|
471
|
+
# If any item in the QuerySet matches, return True for the whole QuerySet evaluation
|
|
472
|
+
if any(queryset_results):
|
|
473
|
+
return True
|
|
474
|
+
continue # Move to the next arg after processing queryset
|
|
475
|
+
else:
|
|
476
|
+
raise TypeError(
|
|
477
|
+
f"Input type {type(_input)} is not among expected models: {self.expected_models} "
|
|
478
|
+
f"nor a QuerySet of expected models."
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
# Process single model instance
|
|
482
|
+
if not hasattr(_input, 'links') or not isinstance(_input.links, RequirementLinks):
|
|
483
|
+
raise TypeError(
|
|
484
|
+
f"Input {_input} of type {type(_input)} does not have a valid .links attribute of type RequirementLinks."
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
active_input_links = _input.links.active() # Get dict of non-empty lists
|
|
488
|
+
for link_key, link_list in active_input_links.items():
|
|
489
|
+
if link_key not in aggregated_input_links_data:
|
|
490
|
+
aggregated_input_links_data[link_key] = []
|
|
491
|
+
aggregated_input_links_data[link_key].extend(link_list)
|
|
492
|
+
processed_inputs_count += 1
|
|
493
|
+
|
|
494
|
+
if not processed_inputs_count and args: # If args were provided but none were processable (e.g. all empty querysets)
|
|
495
|
+
# This situation implies no relevant data was provided for evaluation against the requirement.
|
|
496
|
+
# Depending on operator logic (e.g., "requires at least one matching item"), this might lead to False.
|
|
497
|
+
# For "models_match_any", an empty input_links will likely result in False if requirement_req_links is not empty.
|
|
498
|
+
pass
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
# Deduplicate items within each list after aggregation
|
|
502
|
+
for key in aggregated_input_links_data:
|
|
503
|
+
try:
|
|
504
|
+
# Using dict.fromkeys to preserve order and remove duplicates for hashable items
|
|
505
|
+
aggregated_input_links_data[key] = list(dict.fromkeys(aggregated_input_links_data[key]))
|
|
506
|
+
except TypeError:
|
|
507
|
+
# Fallback for non-hashable items (though Django models are hashable)
|
|
508
|
+
temp_list = []
|
|
509
|
+
for item in aggregated_input_links_data[key]:
|
|
510
|
+
if item not in temp_list:
|
|
511
|
+
temp_list.append(item)
|
|
512
|
+
aggregated_input_links_data[key] = temp_list
|
|
513
|
+
|
|
514
|
+
final_input_links = RequirementLinks(**aggregated_input_links_data)
|
|
515
|
+
|
|
516
|
+
# Gender strict check: if this requirement has genders, only pass if patient.gender is in the set
|
|
517
|
+
genders_exist = self.genders.exists()
|
|
518
|
+
if genders_exist:
|
|
519
|
+
# Import here to avoid circular import
|
|
520
|
+
from endoreg_db.models.administration.person.patient import Patient
|
|
521
|
+
patient = None
|
|
522
|
+
for arg in args:
|
|
523
|
+
if isinstance(arg, Patient):
|
|
524
|
+
patient = arg
|
|
525
|
+
break
|
|
526
|
+
if patient is None or patient.gender is None:
|
|
527
|
+
return False
|
|
528
|
+
if not self.genders.filter(pk=patient.gender.pk).exists():
|
|
529
|
+
return False
|
|
530
|
+
|
|
531
|
+
operators = self.operators.all()
|
|
532
|
+
if not operators.exists(): # If a requirement has no operators, its evaluation is ambiguous.
|
|
533
|
+
# Consider if this should be True, False, or an error.
|
|
534
|
+
# For now, if no operators, and mode is strict, it's vacuously true. If loose, vacuously false.
|
|
535
|
+
# However, typically a requirement implies some condition.
|
|
536
|
+
# Let's assume if no operators, it cannot be satisfied unless it also has no specific links.
|
|
537
|
+
# This behavior might need further refinement based on business logic.
|
|
538
|
+
if not requirement_req_links.active(): # No conditions in requirement
|
|
539
|
+
return True # Vacuously true if requirement itself is empty
|
|
540
|
+
return False # Cannot be satisfied if requirement has conditions but no operators to check them
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
operator_results = []
|
|
544
|
+
for operator in operators:
|
|
545
|
+
# Prepare kwargs for the operator, including the current Requirement instance
|
|
546
|
+
op_kwargs = kwargs.copy() # Start with kwargs passed to Requirement.evaluate
|
|
547
|
+
op_kwargs['requirement'] = self # Add the Requirement instance itself
|
|
548
|
+
op_kwargs['original_input_args'] = args # Add the original input arguments for operators that need them (e.g., age operators)
|
|
549
|
+
operator_results.append(operator.evaluate(
|
|
550
|
+
requirement_links=requirement_req_links,
|
|
551
|
+
input_links=final_input_links,
|
|
552
|
+
**op_kwargs
|
|
553
|
+
))
|
|
554
|
+
|
|
555
|
+
is_valid = evaluate_result_list_func(operator_results)
|
|
556
|
+
|
|
557
|
+
return is_valid
|
|
558
|
+
|
|
559
|
+
def evaluate_with_details(self, *args, mode:str, **kwargs):
|
|
560
|
+
"""
|
|
561
|
+
Evaluates whether the requirement is satisfied for the given input models using linked operators and gender constraints.
|
|
562
|
+
|
|
563
|
+
Args:
|
|
564
|
+
*args: Instances or QuerySets of expected model classes to be evaluated. Each must have a `.links` property returning a `RequirementLinks` object.
|
|
565
|
+
mode: Evaluation mode; "strict" requires all operators to pass, "loose" requires any operator to pass.
|
|
566
|
+
**kwargs: Additional keyword arguments passed to operator evaluations.
|
|
567
|
+
|
|
568
|
+
Returns:
|
|
569
|
+
True if the requirement is satisfied according to the specified mode, linked operators, and gender restrictions; otherwise, False.
|
|
570
|
+
|
|
571
|
+
Raises:
|
|
572
|
+
ValueError: If an invalid mode is provided.
|
|
573
|
+
TypeError: If an input is not an instance or QuerySet of expected models, or lacks a valid `.links` attribute.
|
|
574
|
+
|
|
575
|
+
If the requirement specifies genders, only input containing a patient with a matching gender will be considered valid for evaluation.
|
|
576
|
+
"""
|
|
577
|
+
#TODO Review, Optimize or remove
|
|
578
|
+
if mode not in ["strict", "loose"]:
|
|
579
|
+
raise ValueError(f"Invalid mode: {mode}. Use 'strict' or 'loose'.")
|
|
580
|
+
|
|
581
|
+
evaluate_result_list_func = all if mode == "strict" else any
|
|
582
|
+
|
|
583
|
+
requirement_req_links = self.links
|
|
584
|
+
expected_models = self.expected_models
|
|
585
|
+
|
|
586
|
+
# helpers to avoid passing a complex tuple to isinstance/issubclass which confuses type checkers
|
|
587
|
+
def _is_expected_instance(obj) -> bool:
|
|
588
|
+
for cls in expected_models:
|
|
589
|
+
if isinstance(cls, type):
|
|
590
|
+
try:
|
|
591
|
+
if isinstance(obj, cls):
|
|
592
|
+
return True
|
|
593
|
+
except Exception:
|
|
594
|
+
# cls might not be a runtime type
|
|
595
|
+
continue
|
|
596
|
+
return False
|
|
597
|
+
|
|
598
|
+
def _is_queryset_of_expected(qs) -> bool:
|
|
599
|
+
if not isinstance(qs, models.QuerySet) or not hasattr(qs, 'model'):
|
|
600
|
+
return False
|
|
601
|
+
for cls in expected_models:
|
|
602
|
+
if isinstance(cls, type):
|
|
603
|
+
try:
|
|
604
|
+
if issubclass(qs.model, cls):
|
|
605
|
+
return True
|
|
606
|
+
except Exception:
|
|
607
|
+
continue
|
|
608
|
+
return False
|
|
609
|
+
|
|
610
|
+
# Aggregate RequirementLinks from all input arguments
|
|
611
|
+
aggregated_input_links_data = {}
|
|
612
|
+
processed_inputs_count = 0
|
|
613
|
+
|
|
614
|
+
for _input in args:
|
|
615
|
+
# Check if the input is an instance of any of the expected model types
|
|
616
|
+
if not _is_expected_instance(_input):
|
|
617
|
+
# Allow QuerySets of expected models
|
|
618
|
+
if _is_queryset_of_expected(_input):
|
|
619
|
+
# For QuerySets, evaluate each item individually and return True if any matches
|
|
620
|
+
if not _input.exists(): # Skip empty querysets
|
|
621
|
+
continue
|
|
622
|
+
|
|
623
|
+
queryset_results = []
|
|
624
|
+
for item in _input:
|
|
625
|
+
if not hasattr(item, 'links') or not isinstance(item.links, RequirementLinks):
|
|
626
|
+
raise TypeError(
|
|
627
|
+
f"Item {item} of type {type(item)} in QuerySet does not have a valid .links attribute of type RequirementLinks."
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
# Evaluate this single item against the requirement
|
|
631
|
+
item_input_links = RequirementLinks(**item.links.active())
|
|
632
|
+
|
|
633
|
+
# Evaluate all operators for this single item
|
|
634
|
+
item_operator_results = []
|
|
635
|
+
for operator in self.operators.all():
|
|
636
|
+
try:
|
|
637
|
+
operator_result = operator.evaluate(
|
|
638
|
+
requirement_links=requirement_req_links,
|
|
639
|
+
input_links=item_input_links,
|
|
640
|
+
requirement=self,
|
|
641
|
+
original_input_args=args,
|
|
642
|
+
**kwargs
|
|
643
|
+
)
|
|
644
|
+
item_operator_results.append(operator_result)
|
|
645
|
+
except Exception as e:
|
|
646
|
+
logger.debug(f"Operator {operator.name} evaluation failed for item {item}: {e}")
|
|
647
|
+
item_operator_results.append(False)
|
|
648
|
+
|
|
649
|
+
# Apply evaluation mode for this single item
|
|
650
|
+
item_result = evaluate_result_list_func(item_operator_results) if item_operator_results else True
|
|
651
|
+
queryset_results.append(item_result)
|
|
652
|
+
processed_inputs_count += 1
|
|
653
|
+
|
|
654
|
+
# If any item in the QuerySet matches, return True for the whole QuerySet evaluation
|
|
655
|
+
if any(queryset_results):
|
|
656
|
+
return True
|
|
657
|
+
continue # Move to the next arg after processing queryset
|
|
658
|
+
else:
|
|
659
|
+
raise TypeError(
|
|
660
|
+
f"Input type {type(_input)} is not among expected models: {self.expected_models} "
|
|
661
|
+
f"nor a QuerySet of expected models."
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
# Process single model instance
|
|
665
|
+
if not hasattr(_input, 'links') or not isinstance(_input.links, RequirementLinks):
|
|
666
|
+
raise TypeError(
|
|
667
|
+
f"Input {_input} of type {type(_input)} does not have a valid .links attribute of type RequirementLinks."
|
|
668
|
+
)
|
|
669
|
+
|
|
670
|
+
active_input_links = _input.links.active() # Get dict of non-empty lists
|
|
671
|
+
for link_key, link_list in active_input_links.items():
|
|
672
|
+
if link_key not in aggregated_input_links_data:
|
|
673
|
+
aggregated_input_links_data[link_key] = []
|
|
674
|
+
aggregated_input_links_data[link_key].extend(link_list)
|
|
675
|
+
processed_inputs_count += 1
|
|
676
|
+
|
|
677
|
+
if not processed_inputs_count and args: # If args were provided but none were processable (e.g. all empty querysets)
|
|
678
|
+
# This situation implies no relevant data was provided for evaluation against the requirement.
|
|
679
|
+
# Depending on operator logic (e.g., "requires at least one matching item"), this might lead to False.
|
|
680
|
+
# For "models_match_any", an empty input_links will likely result in False if requirement_req_links is not empty.
|
|
681
|
+
pass
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
# Deduplicate items within each list after aggregation
|
|
685
|
+
for key in aggregated_input_links_data:
|
|
686
|
+
try:
|
|
687
|
+
# Using dict.fromkeys to preserve order and remove duplicates for hashable items
|
|
688
|
+
aggregated_input_links_data[key] = list(dict.fromkeys(aggregated_input_links_data[key]))
|
|
689
|
+
except TypeError:
|
|
690
|
+
# Fallback for non-hashable items (though Django models are hashable)
|
|
691
|
+
temp_list = []
|
|
692
|
+
for item in aggregated_input_links_data[key]:
|
|
693
|
+
if item not in temp_list:
|
|
694
|
+
temp_list.append(item)
|
|
695
|
+
aggregated_input_links_data[key] = temp_list
|
|
696
|
+
|
|
697
|
+
final_input_links = RequirementLinks(**aggregated_input_links_data)
|
|
698
|
+
|
|
699
|
+
# Gender strict check: if this requirement has genders, only pass if patient.gender is in the set
|
|
700
|
+
genders_exist = self.genders.exists()
|
|
701
|
+
if genders_exist:
|
|
702
|
+
# Import here to avoid circular import
|
|
703
|
+
from endoreg_db.models.administration.person.patient import Patient
|
|
704
|
+
patient = None
|
|
705
|
+
for arg in args:
|
|
706
|
+
if isinstance(arg, Patient):
|
|
707
|
+
patient = arg
|
|
708
|
+
break
|
|
709
|
+
if patient is None or patient.gender is None:
|
|
710
|
+
return False
|
|
711
|
+
if not self.genders.filter(pk=patient.gender.pk).exists():
|
|
712
|
+
return False
|
|
713
|
+
|
|
714
|
+
operators = self.operators.all()
|
|
715
|
+
if not operators.exists(): # If a requirement has no operators, its evaluation is ambiguous.
|
|
716
|
+
# Consider if this should be True, False, or an error.
|
|
717
|
+
# For now, if no operators, and mode is strict, it's vacuously true. If loose, vacuously false.
|
|
718
|
+
# However, typically a requirement implies some condition.
|
|
719
|
+
# Let's assume if no operators, it cannot be satisfied unless it also has no specific links.
|
|
720
|
+
# This behavior might need further refinement based on business logic.
|
|
721
|
+
if not requirement_req_links.active(): # No conditions in requirement
|
|
722
|
+
return True # Vacuously true if requirement itself is empty
|
|
723
|
+
return False # Cannot be satisfied if requirement has conditions but no operators to check them
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
operator_results = []
|
|
727
|
+
operator_details = []
|
|
728
|
+
for operator in operators:
|
|
729
|
+
# Prepare kwargs for the operator, including the current Requirement instance
|
|
730
|
+
op_kwargs = kwargs.copy() # Start with kwargs passed to Requirement.evaluate
|
|
731
|
+
op_kwargs['requirement'] = self # Add the Requirement instance itself
|
|
732
|
+
op_kwargs['original_input_args'] = args # Add the original input arguments for operators that need them (e.g., age operators)
|
|
733
|
+
try:
|
|
734
|
+
operator_result = operator.evaluate(
|
|
735
|
+
requirement_links=requirement_req_links,
|
|
736
|
+
input_links=final_input_links,
|
|
737
|
+
**op_kwargs
|
|
738
|
+
)
|
|
739
|
+
operator_results.append(operator_result)
|
|
740
|
+
operator_details.append(f"{operator.name}: {'Passed' if operator_result else 'Failed'}")
|
|
741
|
+
except Exception as e:
|
|
742
|
+
operator_results.append(False)
|
|
743
|
+
operator_details.append(f"{operator.name}: {str(e)}")
|
|
744
|
+
|
|
745
|
+
is_valid = evaluate_result_list_func(operator_results)
|
|
746
|
+
|
|
747
|
+
# Create detailed feedback
|
|
748
|
+
if not operator_results:
|
|
749
|
+
details = "Keine Operatoren für die Bewertung verfügbar"
|
|
750
|
+
elif len(operator_results) == 1:
|
|
751
|
+
details = operator_details[0]
|
|
752
|
+
else:
|
|
753
|
+
failed_details = [detail for detail, result in zip(operator_details, operator_results) if not result]
|
|
754
|
+
if failed_details:
|
|
755
|
+
details = "; ".join(failed_details)
|
|
756
|
+
else:
|
|
757
|
+
details = "Alle Operatoren erfolgreich"
|
|
758
|
+
|
|
759
|
+
# Append working directory for debugging convenience
|
|
760
|
+
try:
|
|
761
|
+
cwd = run("pwd", capture_output=True, text=True).stdout.strip()
|
|
762
|
+
details = f"{details}\ncwd: {cwd}"
|
|
763
|
+
except Exception:
|
|
764
|
+
# non-fatal: ignore if subprocess fails
|
|
765
|
+
pass
|
|
766
|
+
|
|
767
|
+
return is_valid, details
|