endoreg-db 0.8.6.1__py3-none-any.whl → 0.8.8.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/authz/auth.py +74 -0
- endoreg_db/authz/backends.py +168 -0
- endoreg_db/authz/management/commands/list_routes.py +18 -0
- endoreg_db/authz/middleware.py +83 -0
- endoreg_db/authz/permissions.py +127 -0
- endoreg_db/authz/policy.py +218 -0
- endoreg_db/authz/views_auth.py +66 -0
- endoreg_db/config/env.py +13 -8
- endoreg_db/data/__init__.py +2 -11
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
- endoreg_db/data/event_classification/data.yaml +4 -0
- endoreg_db/data/event_classification_choice/data.yaml +9 -0
- endoreg_db/data/examination/examinations/data.yaml +114 -14
- endoreg_db/data/examination/time-type/data.yaml +0 -3
- endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
- endoreg_db/data/finding/00_generic.yaml +35 -0
- endoreg_db/data/finding/00_generic_complication.yaml +9 -0
- endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
- endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
- endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
- endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
- endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
- endoreg_db/data/finding_classification/00_generic.yaml +44 -0
- endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
- endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
- endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
- endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
- endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
- endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
- endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
- endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
- endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
- endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
- endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
- endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
- endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
- endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
- endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
- endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
- endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
- endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
- endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
- endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
- endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
- endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
- endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
- endoreg_db/data/finding_type/data.yaml +8 -12
- endoreg_db/data/requirement/01_patient_data.yaml +93 -0
- endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
- endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
- endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
- endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
- endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
- endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
- endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
- endoreg_db/data/requirement_set/_old_ +109 -0
- endoreg_db/data/requirement_set_type/data.yaml +21 -0
- endoreg_db/data/setup_config.yaml +4 -4
- endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
- endoreg_db/exceptions.py +4 -2
- endoreg_db/forms/examination_form.py +1 -1
- endoreg_db/helpers/data_loader.py +125 -53
- endoreg_db/helpers/default_objects.py +116 -81
- endoreg_db/import_files/__init__.py +27 -0
- endoreg_db/import_files/context/__init__.py +7 -0
- endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
- endoreg_db/import_files/context/ensure_center.py +17 -0
- endoreg_db/import_files/context/file_lock.py +66 -0
- endoreg_db/import_files/context/import_context.py +43 -0
- endoreg_db/import_files/context/validate_directories.py +56 -0
- endoreg_db/import_files/file_storage/__init__.py +15 -0
- endoreg_db/import_files/file_storage/create_report_file.py +76 -0
- endoreg_db/import_files/file_storage/create_video_file.py +75 -0
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
- endoreg_db/import_files/file_storage/state_management.py +400 -0
- endoreg_db/import_files/file_storage/storage.py +36 -0
- endoreg_db/import_files/import_service.md +26 -0
- endoreg_db/import_files/processing/__init__.py +11 -0
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
- endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
- endoreg_db/import_files/pseudonymization/fake.py +52 -0
- endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
- endoreg_db/import_files/report_import_service.py +141 -0
- endoreg_db/import_files/video_import_service.py +150 -0
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
- endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
- endoreg_db/management/commands/import_report.py +130 -65
- endoreg_db/management/commands/import_video.py +9 -10
- endoreg_db/management/commands/import_video_with_classification.py +2 -2
- endoreg_db/management/commands/list_routes.py +18 -0
- endoreg_db/management/commands/load_ai_model_data.py +5 -5
- endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
- endoreg_db/management/commands/load_base_db_data.py +5 -134
- endoreg_db/management/commands/load_center_data.py +12 -12
- endoreg_db/management/commands/load_contraindication_data.py +14 -16
- endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
- endoreg_db/management/commands/load_disease_classification_data.py +15 -18
- endoreg_db/management/commands/load_disease_data.py +25 -28
- endoreg_db/management/commands/load_endoscope_data.py +20 -27
- endoreg_db/management/commands/load_event_data.py +14 -16
- endoreg_db/management/commands/load_examination_data.py +31 -44
- endoreg_db/management/commands/load_examination_indication_data.py +20 -21
- endoreg_db/management/commands/load_finding_data.py +52 -80
- endoreg_db/management/commands/load_information_source.py +21 -23
- endoreg_db/management/commands/load_lab_value_data.py +17 -26
- endoreg_db/management/commands/load_medication_data.py +13 -12
- endoreg_db/management/commands/load_organ_data.py +15 -19
- endoreg_db/management/commands/load_pdf_type_data.py +19 -18
- endoreg_db/management/commands/load_profession_data.py +14 -17
- endoreg_db/management/commands/load_qualification_data.py +20 -23
- endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
- endoreg_db/management/commands/load_requirement_data.py +62 -39
- endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
- endoreg_db/management/commands/load_risk_data.py +7 -6
- endoreg_db/management/commands/load_shift_data.py +20 -23
- endoreg_db/management/commands/load_tag_data.py +8 -11
- endoreg_db/management/commands/load_unit_data.py +17 -19
- endoreg_db/management/commands/setup_endoreg_db.py +3 -3
- endoreg_db/management/commands/start_filewatcher.py +46 -37
- endoreg_db/management/commands/storage_management.py +271 -203
- endoreg_db/management/commands/validate_video_files.py +1 -5
- endoreg_db/migrations/0001_initial.py +297 -250
- endoreg_db/models/__init__.py +78 -123
- endoreg_db/models/administration/__init__.py +21 -42
- endoreg_db/models/administration/ai/active_model.py +2 -2
- endoreg_db/models/administration/ai/ai_model.py +7 -6
- endoreg_db/models/administration/case/__init__.py +1 -15
- endoreg_db/models/administration/case/case.py +3 -3
- endoreg_db/models/administration/case/case_template/__init__.py +2 -14
- endoreg_db/models/administration/case/case_template/case_template.py +2 -124
- endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
- endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
- endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
- endoreg_db/models/administration/center/center.py +33 -19
- endoreg_db/models/administration/center/center_product.py +12 -9
- endoreg_db/models/administration/center/center_resource.py +25 -19
- endoreg_db/models/administration/center/center_shift.py +21 -17
- endoreg_db/models/administration/center/center_waste.py +16 -8
- endoreg_db/models/administration/person/__init__.py +2 -0
- endoreg_db/models/administration/person/employee/employee.py +10 -5
- endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
- endoreg_db/models/administration/person/employee/employee_type.py +12 -6
- endoreg_db/models/administration/person/examiner/examiner.py +13 -11
- endoreg_db/models/administration/person/patient/__init__.py +2 -0
- endoreg_db/models/administration/person/patient/patient.py +129 -100
- endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
- endoreg_db/models/administration/person/person.py +4 -0
- endoreg_db/models/administration/person/profession/__init__.py +8 -4
- endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
- endoreg_db/models/administration/product/product.py +20 -15
- endoreg_db/models/administration/product/product_material.py +17 -18
- endoreg_db/models/administration/product/product_weight.py +12 -8
- endoreg_db/models/administration/product/reference_product.py +23 -55
- endoreg_db/models/administration/qualification/qualification.py +7 -3
- endoreg_db/models/administration/qualification/qualification_type.py +7 -3
- endoreg_db/models/administration/shift/scheduled_days.py +8 -5
- endoreg_db/models/administration/shift/shift.py +16 -12
- endoreg_db/models/administration/shift/shift_type.py +23 -31
- endoreg_db/models/label/__init__.py +8 -9
- endoreg_db/models/label/annotation/image_classification.py +10 -9
- endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
- endoreg_db/models/label/label.py +15 -15
- endoreg_db/models/label/label_set.py +19 -6
- endoreg_db/models/label/label_type.py +1 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
- endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
- endoreg_db/models/label/video_segmentation_label.py +4 -0
- endoreg_db/models/label/video_segmentation_labelset.py +4 -3
- endoreg_db/models/media/frame/frame.py +22 -22
- endoreg_db/models/media/pdf/raw_pdf.py +194 -194
- endoreg_db/models/media/pdf/report_file.py +25 -29
- endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
- endoreg_db/models/media/processing_history/__init__.py +5 -0
- endoreg_db/models/media/processing_history/processing_history.py +96 -0
- endoreg_db/models/media/video/__init__.py +1 -0
- endoreg_db/models/media/video/create_from_file.py +139 -77
- endoreg_db/models/media/video/pipe_2.py +8 -9
- endoreg_db/models/media/video/video_file.py +174 -112
- endoreg_db/models/media/video/video_file_ai.py +288 -74
- endoreg_db/models/media/video/video_file_anonymize.py +38 -38
- endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
- endoreg_db/models/media/video/video_file_io.py +113 -61
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
- endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
- endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
- endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
- endoreg_db/models/media/video/video_file_segments.py +24 -17
- endoreg_db/models/media/video/video_metadata.py +19 -35
- endoreg_db/models/media/video/video_processing.py +96 -95
- endoreg_db/models/medical/contraindication/README.md +1 -0
- endoreg_db/models/medical/contraindication/__init__.py +13 -3
- endoreg_db/models/medical/disease.py +22 -16
- endoreg_db/models/medical/event.py +31 -18
- endoreg_db/models/medical/examination/__init__.py +13 -6
- endoreg_db/models/medical/examination/examination.py +39 -20
- endoreg_db/models/medical/examination/examination_indication.py +30 -95
- endoreg_db/models/medical/examination/examination_time.py +23 -8
- endoreg_db/models/medical/examination/examination_time_type.py +9 -6
- endoreg_db/models/medical/examination/examination_type.py +3 -4
- endoreg_db/models/medical/finding/finding.py +32 -40
- endoreg_db/models/medical/finding/finding_classification.py +42 -72
- endoreg_db/models/medical/finding/finding_intervention.py +25 -22
- endoreg_db/models/medical/finding/finding_type.py +13 -12
- endoreg_db/models/medical/hardware/endoscope.py +26 -26
- endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
- endoreg_db/models/medical/laboratory/lab_value.py +62 -91
- endoreg_db/models/medical/medication/medication.py +22 -10
- endoreg_db/models/medical/medication/medication_indication.py +29 -3
- endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
- endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
- endoreg_db/models/medical/medication/medication_schedule.py +27 -16
- endoreg_db/models/medical/organ/__init__.py +15 -12
- endoreg_db/models/medical/patient/medication_examples.py +6 -6
- endoreg_db/models/medical/patient/patient_disease.py +20 -23
- endoreg_db/models/medical/patient/patient_event.py +19 -22
- endoreg_db/models/medical/patient/patient_examination.py +48 -54
- endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
- endoreg_db/models/medical/patient/patient_finding.py +122 -139
- endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
- endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
- endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
- endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
- endoreg_db/models/medical/patient/patient_medication.py +27 -38
- endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
- endoreg_db/models/medical/risk/risk.py +7 -6
- endoreg_db/models/medical/risk/risk_type.py +8 -5
- endoreg_db/models/metadata/model_meta.py +60 -29
- endoreg_db/models/metadata/model_meta_logic.py +125 -18
- endoreg_db/models/metadata/pdf_meta.py +31 -24
- endoreg_db/models/metadata/sensitive_meta.py +105 -85
- endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
- endoreg_db/models/metadata/video_meta.py +51 -31
- endoreg_db/models/metadata/video_prediction_logic.py +16 -23
- endoreg_db/models/metadata/video_prediction_meta.py +29 -33
- endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
- endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
- endoreg_db/models/other/emission/emission_factor.py +18 -8
- endoreg_db/models/other/gender.py +10 -5
- endoreg_db/models/other/information_source.py +50 -29
- endoreg_db/models/other/material.py +9 -5
- endoreg_db/models/other/resource.py +6 -4
- endoreg_db/models/other/tag.py +10 -5
- endoreg_db/models/other/transport_route.py +13 -8
- endoreg_db/models/other/unit.py +10 -6
- endoreg_db/models/other/waste.py +6 -5
- endoreg_db/models/report/report.py +6 -0
- endoreg_db/models/requirement/requirement.py +329 -361
- endoreg_db/models/requirement/requirement_error.py +85 -0
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
- endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
- endoreg_db/models/requirement/requirement_operator.py +103 -112
- endoreg_db/models/requirement/requirement_set.py +74 -57
- endoreg_db/models/state/__init__.py +4 -4
- endoreg_db/models/state/abstract.py +2 -2
- endoreg_db/models/state/anonymization.py +12 -0
- endoreg_db/models/state/audit_ledger.py +49 -51
- endoreg_db/models/state/label_video_segment.py +9 -0
- endoreg_db/models/state/raw_pdf.py +101 -68
- endoreg_db/models/state/sensitive_meta.py +6 -2
- endoreg_db/models/state/video.py +110 -90
- endoreg_db/models/upload_job.py +35 -34
- endoreg_db/models/utils.py +28 -25
- endoreg_db/queries/__init__.py +3 -1
- endoreg_db/root_urls.py +21 -2
- endoreg_db/schemas/examination_evaluation.py +1 -1
- endoreg_db/serializers/__init__.py +2 -10
- endoreg_db/serializers/anonymization.py +18 -10
- endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
- endoreg_db/serializers/meta/__init__.py +1 -6
- endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
- endoreg_db/serializers/misc/file_overview.py +11 -99
- endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
- endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
- endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
- endoreg_db/serializers/requirements/requirement_sets.py +92 -22
- endoreg_db/serializers/video/segmentation.py +2 -1
- endoreg_db/serializers/video/video_file_list.py +65 -34
- endoreg_db/serializers/video/video_processing_history.py +20 -5
- endoreg_db/services/__old/pdf_import.py +1487 -0
- endoreg_db/services/__old/video_import.py +1306 -0
- endoreg_db/services/anonymization.py +128 -89
- endoreg_db/services/lookup_service.py +65 -52
- endoreg_db/services/lookup_store.py +2 -2
- endoreg_db/services/pdf_import.py +0 -1382
- endoreg_db/services/report_import.py +10 -0
- endoreg_db/services/video_import.py +6 -1255
- endoreg_db/tasks/upload_tasks.py +79 -70
- endoreg_db/tasks/video_ingest.py +8 -4
- endoreg_db/urls/__init__.py +5 -32
- endoreg_db/urls/ai.py +32 -0
- endoreg_db/urls/media.py +121 -83
- endoreg_db/urls/root_urls.py +29 -0
- endoreg_db/utils/__init__.py +15 -5
- endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
- endoreg_db/utils/case_generator/__init__.py +3 -0
- endoreg_db/utils/dataloader.py +142 -40
- endoreg_db/utils/defaults/set_default_center.py +32 -0
- endoreg_db/utils/names.py +22 -16
- endoreg_db/utils/paths.py +110 -46
- endoreg_db/utils/permissions.py +2 -1
- endoreg_db/utils/pipelines/Readme.md +1 -1
- endoreg_db/utils/pipelines/process_video_dir.py +1 -1
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
- endoreg_db/utils/setup_config.py +8 -5
- endoreg_db/utils/storage.py +115 -0
- endoreg_db/utils/validate_endo_roi.py +8 -2
- endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
- endoreg_db/views/__init__.py +85 -183
- endoreg_db/views/ai/__init__.py +8 -0
- endoreg_db/views/ai/label.py +155 -0
- endoreg_db/views/anonymization/media_management.py +202 -166
- endoreg_db/views/anonymization/overview.py +99 -67
- endoreg_db/views/anonymization/validate.py +182 -44
- endoreg_db/views/media/__init__.py +7 -20
- endoreg_db/views/media/pdf_media.py +197 -174
- endoreg_db/views/media/sensitive_metadata.py +193 -138
- endoreg_db/views/media/video_media.py +89 -82
- endoreg_db/views/meta/__init__.py +0 -8
- endoreg_db/views/misc/__init__.py +1 -7
- endoreg_db/views/misc/upload_views.py +94 -93
- endoreg_db/views/patient/patient.py +5 -4
- endoreg_db/views/report/__init__.py +5 -7
- endoreg_db/views/{pdf → report}/reimport.py +22 -22
- endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
- endoreg_db/views/requirement/evaluate.py +188 -187
- endoreg_db/views/requirement/lookup.py +17 -3
- endoreg_db/views/requirement/lookup_store.py +22 -90
- endoreg_db/views/requirement/requirement_utils.py +89 -0
- endoreg_db/views/video/__init__.py +23 -24
- endoreg_db/views/video/correction.py +201 -172
- endoreg_db/views/video/reimport.py +1 -1
- endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
- endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
- endoreg_db/views/video/video_stream.py +7 -8
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
- endoreg_db/data/finding/anatomy_colon.yaml +0 -128
- endoreg_db/data/finding/colonoscopy.yaml +0 -40
- endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
- endoreg_db/data/finding/complication.yaml +0 -16
- endoreg_db/data/finding/data.yaml +0 -105
- endoreg_db/data/finding/examination_setting.yaml +0 -16
- endoreg_db/data/finding/medication_related.yaml +0 -18
- endoreg_db/data/finding/outcome.yaml +0 -12
- endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
- endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
- endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
- endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
- endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
- endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
- endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
- endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
- endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
- endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
- endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
- endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
- endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
- endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
- endoreg_db/data/finding_classification/medication_related.yaml +0 -23
- endoreg_db/data/finding_classification/visualized.yaml +0 -33
- endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
- endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
- endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
- endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
- endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
- endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
- endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
- endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
- endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
- endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
- endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
- endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
- endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
- endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
- endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
- endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
- endoreg_db/data/requirement/age.yaml +0 -26
- endoreg_db/data/requirement/gender.yaml +0 -25
- endoreg_db/management/commands/init_default_ai_model.py +0 -112
- endoreg_db/management/commands/reset_celery_schedule.py +0 -9
- endoreg_db/management/commands/validate_video.py +0 -204
- endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
- endoreg_db/migrations/0003_add_center_display_name.py +0 -30
- endoreg_db/models/administration/permissions/__init__.py +0 -44
- endoreg_db/models/rule/__init__.py +0 -13
- endoreg_db/models/rule/rule.py +0 -27
- endoreg_db/models/rule/rule_applicator.py +0 -224
- endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
- endoreg_db/models/rule/rule_type.py +0 -20
- endoreg_db/models/rule/ruleset.py +0 -17
- endoreg_db/renames.yml +0 -8
- endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
- endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
- endoreg_db/serializers/_old/video.py +0 -71
- endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
- endoreg_db/serializers/meta/report_meta.py +0 -53
- endoreg_db/serializers/report/__init__.py +0 -9
- endoreg_db/serializers/report/mixins.py +0 -45
- endoreg_db/serializers/report/report.py +0 -105
- endoreg_db/serializers/report/report_list.py +0 -22
- endoreg_db/serializers/report/secure_file_url.py +0 -26
- endoreg_db/serializers/video/video_metadata.py +0 -105
- endoreg_db/services/requirements_object.py +0 -147
- endoreg_db/services/storage_aware_video_processor.py +0 -344
- endoreg_db/urls/files.py +0 -6
- endoreg_db/urls/label_video_segment_validate.py +0 -33
- endoreg_db/urls/label_video_segments.py +0 -46
- endoreg_db/urls/report.py +0 -48
- endoreg_db/urls/video.py +0 -61
- endoreg_db/utils/case_generator/case_generator.py +0 -159
- endoreg_db/utils/case_generator/utils.py +0 -30
- endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
- endoreg_db/views/label/__init__.py +0 -5
- endoreg_db/views/label/label.py +0 -15
- endoreg_db/views/label_video_segment/__init__.py +0 -16
- endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
- endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
- endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
- endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
- endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
- endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
- endoreg_db/views/label_video_segment/validate.py +0 -226
- endoreg_db/views/media/segments.py +0 -71
- endoreg_db/views/meta/available_files_list.py +0 -146
- endoreg_db/views/meta/report_meta.py +0 -53
- endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
- endoreg_db/views/misc/secure_file_serving_view.py +0 -80
- endoreg_db/views/misc/secure_file_url_view.py +0 -84
- endoreg_db/views/misc/secure_url_validate.py +0 -79
- endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
- endoreg_db/views/patient_finding_location/__init__.py +0 -5
- endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
- endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
- endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
- endoreg_db/views/pdf/__init__.py +0 -8
- endoreg_db/views/report/report_list.py +0 -112
- endoreg_db/views/report/report_with_secure_url.py +0 -28
- endoreg_db/views/report/start_examination.py +0 -7
- endoreg_db/views/video/segmentation.py +0 -274
- endoreg_db/views/video/task_status.py +0 -49
- endoreg_db/views/video/timeline.py +0 -46
- endoreg_db/views/video/video_analyze.py +0 -52
- endoreg_db/views.py +0 -0
- /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
- /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
- /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
- /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
- /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
- /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
- /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
- /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
- /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
- /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
- /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
- /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
- /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
- /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
- /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
- {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,52 +1,55 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, cast
|
|
2
|
+
|
|
1
3
|
from django.db import models
|
|
2
4
|
|
|
5
|
+
|
|
3
6
|
class FindingInterventionManager(models.Manager):
|
|
4
7
|
def get_by_natural_key(self, name):
|
|
5
8
|
return self.get(name=name)
|
|
6
|
-
|
|
9
|
+
|
|
10
|
+
|
|
7
11
|
class FindingIntervention(models.Model):
|
|
8
12
|
name = models.CharField(max_length=100, unique=True)
|
|
9
13
|
description = models.TextField(blank=True, null=True)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
intervention_types = models.ManyToManyField("FindingInterventionType", blank=True, related_name="interventions")
|
|
15
|
+
information_sources = models.ManyToManyField(
|
|
16
|
+
"InformationSource",
|
|
17
|
+
related_name="finding_interventions",
|
|
13
18
|
blank=True,
|
|
14
|
-
related_name='interventions'
|
|
15
19
|
)
|
|
20
|
+
objects = FindingInterventionManager()
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
blank=True,
|
|
20
|
-
related_name='required_by_finding_interventions'
|
|
21
|
-
)
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from endoreg_db.models import Contraindication, FindingInterventionType, InformationSource, LabValue
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
blank=True,
|
|
26
|
-
related_name='contraindicating_finding_interventions'
|
|
27
|
-
)
|
|
25
|
+
intervention_types = cast(models.manager.RelatedManager["FindingInterventionType"], intervention_types)
|
|
26
|
+
information_sources = cast(models.manager.RelatedManager["InformationSource"], information_sources)
|
|
28
27
|
|
|
29
|
-
objects = FindingInterventionManager()
|
|
30
|
-
|
|
31
28
|
def natural_key(self):
|
|
32
29
|
return (self.name,)
|
|
33
|
-
|
|
30
|
+
|
|
34
31
|
def __str__(self):
|
|
35
32
|
return str(self.name)
|
|
36
|
-
|
|
33
|
+
|
|
37
34
|
|
|
38
35
|
class FindingInterventionTypeManager(models.Manager):
|
|
39
36
|
def get_by_natural_key(self, name):
|
|
40
37
|
return self.get(name=name)
|
|
41
|
-
|
|
38
|
+
|
|
39
|
+
|
|
42
40
|
class FindingInterventionType(models.Model):
|
|
43
41
|
name = models.CharField(max_length=100, unique=True)
|
|
44
42
|
description = models.TextField(blank=True, null=True)
|
|
45
43
|
|
|
46
44
|
objects = FindingInterventionTypeManager()
|
|
47
|
-
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def interventions(self) -> "models.manager.RelatedManager[FindingIntervention]": ...
|
|
50
|
+
|
|
48
51
|
def natural_key(self):
|
|
49
52
|
return (self.name,)
|
|
50
|
-
|
|
53
|
+
|
|
51
54
|
def __str__(self):
|
|
52
55
|
return str(self.name)
|
|
@@ -1,35 +1,36 @@
|
|
|
1
|
-
from django.db import models
|
|
2
1
|
from typing import TYPE_CHECKING
|
|
3
2
|
|
|
3
|
+
from django.db import models
|
|
4
|
+
|
|
5
|
+
|
|
4
6
|
class FindingTypeManager(models.Manager):
|
|
5
7
|
def get_by_natural_key(self, name):
|
|
6
8
|
"""
|
|
7
9
|
Retrieve a FindingType instance by its unique name for natural key deserialization.
|
|
8
|
-
|
|
10
|
+
|
|
9
11
|
Parameters:
|
|
10
12
|
name (str): The unique name of the FindingType to retrieve.
|
|
11
|
-
|
|
13
|
+
|
|
12
14
|
Returns:
|
|
13
15
|
FindingType: The instance matching the given name.
|
|
14
16
|
"""
|
|
15
17
|
return self.get(name=name)
|
|
16
|
-
|
|
18
|
+
|
|
19
|
+
|
|
17
20
|
class FindingType(models.Model):
|
|
18
|
-
name = models.CharField(max_length=100, unique=True)
|
|
21
|
+
name = models.CharField(max_length=100, unique=True)
|
|
19
22
|
description = models.TextField(blank=True, null=True)
|
|
20
23
|
|
|
21
24
|
objects = FindingTypeManager()
|
|
22
25
|
|
|
23
26
|
if TYPE_CHECKING:
|
|
24
|
-
from endoreg_db.models import
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
finding_classifications
|
|
28
|
-
morphology_classifications: models.QuerySet['FindingMorphologyClassification']
|
|
29
|
-
|
|
27
|
+
from endoreg_db.models import Examination, Finding, FindingClassification
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def finding_classifications(self) -> "models.manager.RelatedManager[FindingClassification]": ...
|
|
30
31
|
|
|
31
32
|
def natural_key(self):
|
|
32
33
|
return (self.name,)
|
|
33
|
-
|
|
34
|
+
|
|
34
35
|
def __str__(self):
|
|
35
36
|
return self.name
|
|
@@ -1,34 +1,26 @@
|
|
|
1
|
-
from django.db import models#
|
|
2
1
|
from typing import TYPE_CHECKING
|
|
3
2
|
|
|
3
|
+
from django.db import models #
|
|
4
|
+
|
|
5
|
+
|
|
4
6
|
class EndoscopeManager(models.Manager):
|
|
5
7
|
def get_by_natural_key(self, name, sn):
|
|
6
8
|
return self.get(name=name, sn=sn)
|
|
7
9
|
|
|
10
|
+
|
|
8
11
|
class Endoscope(models.Model):
|
|
9
12
|
objects = EndoscopeManager()
|
|
10
13
|
|
|
11
|
-
name = models.CharField(max_length=255)
|
|
14
|
+
name = models.CharField(max_length=255)
|
|
12
15
|
sn = models.CharField(max_length=255)
|
|
13
|
-
center = models.ForeignKey(
|
|
14
|
-
|
|
15
|
-
blank=True,
|
|
16
|
-
null=True,
|
|
17
|
-
on_delete=models.CASCADE,
|
|
18
|
-
related_name='endoscopes'
|
|
19
|
-
)
|
|
20
|
-
endoscope_type = models.ForeignKey(
|
|
21
|
-
'EndoscopeType',
|
|
22
|
-
blank=True,
|
|
23
|
-
null=True,
|
|
24
|
-
on_delete=models.CASCADE,
|
|
25
|
-
related_name='endoscopes'
|
|
26
|
-
)
|
|
16
|
+
center = models.ForeignKey("Center", blank=True, null=True, on_delete=models.CASCADE, related_name="endoscopes")
|
|
17
|
+
endoscope_type = models.ForeignKey("EndoscopeType", blank=True, null=True, on_delete=models.CASCADE, related_name="endoscopes")
|
|
27
18
|
|
|
28
19
|
if TYPE_CHECKING:
|
|
29
|
-
from endoreg_db.models
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
from endoreg_db.models import Center
|
|
21
|
+
|
|
22
|
+
center: models.ForeignKey["Center|None"]
|
|
23
|
+
endoscope_type: models.ForeignKey["EndoscopeType|None"]
|
|
32
24
|
|
|
33
25
|
def natural_key(self):
|
|
34
26
|
return (self.name, self.sn)
|
|
@@ -37,14 +29,22 @@ class Endoscope(models.Model):
|
|
|
37
29
|
return str(self.name)
|
|
38
30
|
|
|
39
31
|
class Meta:
|
|
40
|
-
ordering = [
|
|
41
|
-
verbose_name =
|
|
42
|
-
verbose_name_plural =
|
|
32
|
+
ordering = ["name"]
|
|
33
|
+
verbose_name = "Endoscope"
|
|
34
|
+
verbose_name_plural = "Endoscopes"
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def center_safe(self) -> "Center":
|
|
38
|
+
if self.center is None:
|
|
39
|
+
raise ValueError("Endoscope has no associated center.")
|
|
40
|
+
return self.center
|
|
41
|
+
|
|
43
42
|
|
|
44
43
|
class EndoscopeTypeManager(models.Manager):
|
|
45
44
|
def get_by_natural_key(self, name):
|
|
46
45
|
return self.get(name=name)
|
|
47
46
|
|
|
47
|
+
|
|
48
48
|
class EndoscopeType(models.Model):
|
|
49
49
|
objects = EndoscopeTypeManager()
|
|
50
50
|
|
|
@@ -55,11 +55,11 @@ class EndoscopeType(models.Model):
|
|
|
55
55
|
|
|
56
56
|
def natural_key(self) -> tuple[str]:
|
|
57
57
|
return (self.name,)
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
def __str__(self):
|
|
60
60
|
return str(self.name)
|
|
61
61
|
|
|
62
62
|
class Meta:
|
|
63
|
-
ordering = [
|
|
64
|
-
verbose_name =
|
|
65
|
-
verbose_name_plural =
|
|
63
|
+
ordering = ["name"]
|
|
64
|
+
verbose_name = "Endoscope Type"
|
|
65
|
+
verbose_name_plural = "Endoscope Types"
|
|
@@ -72,8 +72,8 @@ class EndoscopyProcessor(models.Model):
|
|
|
72
72
|
return (self.name,)
|
|
73
73
|
|
|
74
74
|
@classmethod
|
|
75
|
-
def get_by_name(
|
|
76
|
-
return
|
|
75
|
+
def get_by_name(cls, name):
|
|
76
|
+
return cls.objects.get(name=name)
|
|
77
77
|
|
|
78
78
|
def __str__(self) -> str:
|
|
79
79
|
if self.name is None:
|
|
@@ -1,27 +1,31 @@
|
|
|
1
|
-
from django.db import models
|
|
2
1
|
import warnings
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
2
|
+
from typing import TYPE_CHECKING, Optional
|
|
3
|
+
|
|
4
|
+
from django.db import models
|
|
4
5
|
|
|
5
6
|
if TYPE_CHECKING:
|
|
6
|
-
from endoreg_db.models
|
|
7
|
-
from ...other.distribution import (
|
|
8
|
-
SingleCategoricalValueDistribution,
|
|
9
|
-
NumericValueDistribution,
|
|
10
|
-
MultipleCategoricalValueDistribution,
|
|
7
|
+
from endoreg_db.models import (
|
|
11
8
|
DateValueDistribution,
|
|
9
|
+
Gender,
|
|
10
|
+
MultipleCategoricalValueDistribution,
|
|
11
|
+
NumericValueDistribution,
|
|
12
|
+
Patient,
|
|
13
|
+
SingleCategoricalValueDistribution,
|
|
14
|
+
Unit,
|
|
12
15
|
)
|
|
13
|
-
from ...administration.person.patient import Patient # Added Patient for type hinting
|
|
14
16
|
|
|
15
17
|
LANG = "de"
|
|
16
18
|
|
|
17
19
|
from pydantic import BaseModel, ConfigDict
|
|
18
20
|
|
|
21
|
+
|
|
19
22
|
class CommonLabValues(BaseModel):
|
|
20
23
|
"""
|
|
21
24
|
A Pydantic model representing a lookup for common lab values.
|
|
22
25
|
It is used to provide a structured way to access common lab values like
|
|
23
26
|
hemoglobin, creatinine, and others
|
|
24
27
|
"""
|
|
28
|
+
|
|
25
29
|
hb: "LabValue"
|
|
26
30
|
wbc: "LabValue"
|
|
27
31
|
plt: "LabValue"
|
|
@@ -32,31 +36,27 @@ class CommonLabValues(BaseModel):
|
|
|
32
36
|
inr: "LabValue"
|
|
33
37
|
crp: "LabValue"
|
|
34
38
|
|
|
35
|
-
model_config = ConfigDict(
|
|
36
|
-
|
|
37
|
-
arbitrary_types_allowed = True
|
|
38
|
-
)
|
|
39
|
+
model_config = ConfigDict(from_attributes=True, arbitrary_types_allowed=True)
|
|
40
|
+
|
|
39
41
|
|
|
40
42
|
class LabValueManager(models.Manager):
|
|
41
43
|
def get_by_natural_key(self, name):
|
|
42
44
|
"""
|
|
43
45
|
Retrieves a LabValue instance by its unique name.
|
|
44
|
-
|
|
46
|
+
|
|
45
47
|
Args:
|
|
46
48
|
name: The unique name of the LabValue.
|
|
47
|
-
|
|
49
|
+
|
|
48
50
|
Returns:
|
|
49
51
|
The LabValue instance with the specified name.
|
|
50
52
|
"""
|
|
51
53
|
return self.get(name=name)
|
|
52
|
-
|
|
54
|
+
|
|
53
55
|
|
|
54
56
|
class LabValue(models.Model):
|
|
55
|
-
name = models.CharField(max_length=255, unique=True)
|
|
57
|
+
name = models.CharField(max_length=255, unique=True)
|
|
56
58
|
abbreviation = models.CharField(max_length=10, blank=True, null=True)
|
|
57
|
-
default_unit = models.ForeignKey(
|
|
58
|
-
"Unit", on_delete=models.CASCADE, blank=True, null=True
|
|
59
|
-
)
|
|
59
|
+
default_unit = models.ForeignKey("Unit", on_delete=models.CASCADE, blank=True, null=True)
|
|
60
60
|
numeric_precision = models.IntegerField(default=3)
|
|
61
61
|
default_single_categorical_value_distribution = models.ForeignKey(
|
|
62
62
|
"SingleCategoricalValueDistribution",
|
|
@@ -91,23 +91,22 @@ class LabValue(models.Model):
|
|
|
91
91
|
normal_range_gender_dependent = models.BooleanField(default=False)
|
|
92
92
|
normal_range_special_case = models.BooleanField(default=False)
|
|
93
93
|
bound_adjustment_factor = models.FloatField(
|
|
94
|
-
default=0.1,
|
|
95
|
-
help_text="Factor for adjusting bounds when generating increased/decreased values, e.g., 0.1 for 10%."
|
|
94
|
+
default=0.1, help_text="Factor for adjusting bounds when generating increased/decreased values, e.g., 0.1 for 10%."
|
|
96
95
|
)
|
|
97
96
|
objects = LabValueManager()
|
|
98
97
|
|
|
99
98
|
if TYPE_CHECKING:
|
|
100
|
-
default_unit: "Unit"
|
|
101
|
-
default_single_categorical_value_distribution: "SingleCategoricalValueDistribution"
|
|
102
|
-
default_numerical_value_distribution: "NumericValueDistribution"
|
|
103
|
-
default_multiple_categorical_value_distribution: "MultipleCategoricalValueDistribution"
|
|
104
|
-
default_date_value_distribution: "DateValueDistribution"
|
|
99
|
+
default_unit: models.ForeignKey["Unit|None"]
|
|
100
|
+
default_single_categorical_value_distribution: models.ForeignKey["SingleCategoricalValueDistribution|None"]
|
|
101
|
+
default_numerical_value_distribution: models.ForeignKey["NumericValueDistribution|None"]
|
|
102
|
+
default_multiple_categorical_value_distribution: models.ForeignKey["MultipleCategoricalValueDistribution|None"]
|
|
103
|
+
default_date_value_distribution: models.ForeignKey["DateValueDistribution|None"]
|
|
105
104
|
|
|
106
105
|
@classmethod
|
|
107
106
|
def get_common_lab_values(cls):
|
|
108
107
|
"""
|
|
109
108
|
Retrieves a structured set of common laboratory values as a CommonLabValues instance.
|
|
110
|
-
|
|
109
|
+
|
|
111
110
|
Returns:
|
|
112
111
|
A CommonLabValues Pydantic model populated with LabValue objects for hemoglobin, white blood cells, platelets, creatinine, sodium, potassium, glucose, international normalized ratio, and C-reactive protein.
|
|
113
112
|
"""
|
|
@@ -122,10 +121,9 @@ class LabValue(models.Model):
|
|
|
122
121
|
k=cls.objects.get(name="potassium"),
|
|
123
122
|
glc=cls.objects.get(name="glucose"),
|
|
124
123
|
inr=cls.objects.get(name="international_normalized_ratio"),
|
|
125
|
-
crp=cls.objects.get(name="c_reactive_protein")
|
|
124
|
+
crp=cls.objects.get(name="c_reactive_protein"),
|
|
126
125
|
)
|
|
127
126
|
|
|
128
|
-
|
|
129
127
|
def natural_key(self):
|
|
130
128
|
"""Returns a tuple containing the unique name of this lab value instance."""
|
|
131
129
|
return (self.name,)
|
|
@@ -160,13 +158,13 @@ class LabValue(models.Model):
|
|
|
160
158
|
warnings.warn("No default distribution set for lab value")
|
|
161
159
|
return None
|
|
162
160
|
|
|
163
|
-
def get_normal_range(self, age: int = None, gender=None):
|
|
161
|
+
def get_normal_range(self, age: Optional[int] = None, gender: Optional["Gender"] = None):
|
|
164
162
|
"""
|
|
165
163
|
Returns the normal range for this lab value, considering age and gender dependencies.
|
|
166
|
-
|
|
164
|
+
|
|
167
165
|
If the normal range is gender-dependent, attempts to use the provided gender; defaults to "male" if gender is missing or unknown. Falls back to general min/max values if gender-specific data is unavailable. Issues warnings for unimplemented age-dependent or special case ranges, and when min or max values cannot be determined. Returns a dictionary with keys "min" and "max", which may be None if the range is not defined.
|
|
168
166
|
"""
|
|
169
|
-
from
|
|
167
|
+
from endoreg_db.models import Gender
|
|
170
168
|
|
|
171
169
|
assert isinstance(age, int) or age is None
|
|
172
170
|
assert isinstance(gender, Gender) or gender is None
|
|
@@ -181,20 +179,15 @@ class LabValue(models.Model):
|
|
|
181
179
|
|
|
182
180
|
gender_name_to_use = None
|
|
183
181
|
if gender_dependent:
|
|
184
|
-
if gender and hasattr(gender,
|
|
182
|
+
if gender and hasattr(gender, "name") and gender.name:
|
|
185
183
|
gender_name_to_use = gender.name
|
|
186
184
|
if gender_name_to_use not in current_range_source:
|
|
187
185
|
warnings.warn(
|
|
188
|
-
f"Normal range for gender '{gender_name_to_use}' not found for LabValue '{self.name}'. "
|
|
189
|
-
f"Defaulting to 'male' range.",
|
|
190
|
-
UserWarning
|
|
186
|
+
f"Normal range for gender '{gender_name_to_use}' not found for LabValue '{self.name}'. Defaulting to 'male' range.", UserWarning
|
|
191
187
|
)
|
|
192
188
|
gender_name_to_use = "male"
|
|
193
189
|
else:
|
|
194
|
-
warnings.warn(
|
|
195
|
-
f"Gender not provided for gender-dependent LabValue '{self.name}'. Defaulting to 'male' range.",
|
|
196
|
-
UserWarning
|
|
197
|
-
)
|
|
190
|
+
warnings.warn(f"Gender not provided for gender-dependent LabValue '{self.name}'. Defaulting to 'male' range.", UserWarning)
|
|
198
191
|
gender_name_to_use = "male"
|
|
199
192
|
|
|
200
193
|
# Attempt gender-specific lookup
|
|
@@ -204,9 +197,8 @@ class LabValue(models.Model):
|
|
|
204
197
|
max_value = gender_specific_data.get("max")
|
|
205
198
|
else:
|
|
206
199
|
warnings.warn(
|
|
207
|
-
f"No gender-specific data found for '{gender_name_to_use}' in LabValue '{self.name}'. "
|
|
208
|
-
|
|
209
|
-
UserWarning
|
|
200
|
+
f"No gender-specific data found for '{gender_name_to_use}' in LabValue '{self.name}'. Falling back to general range if available.",
|
|
201
|
+
UserWarning,
|
|
210
202
|
)
|
|
211
203
|
|
|
212
204
|
# Fallback to general min/max if needed
|
|
@@ -229,16 +221,14 @@ class LabValue(models.Model):
|
|
|
229
221
|
if min_value is None:
|
|
230
222
|
context_parts = []
|
|
231
223
|
if gender_dependent:
|
|
232
|
-
gender_repr =
|
|
224
|
+
gender_repr = gender.name if gender and hasattr(gender, "name") else "None"
|
|
233
225
|
if gender_name_to_use and gender_name_to_use != gender_repr:
|
|
234
226
|
gender_repr = f"{gender_repr} (lookup attempted for: {gender_name_to_use})"
|
|
235
227
|
context_parts.append(f"gender: {gender_repr}")
|
|
236
228
|
if age_dependent:
|
|
237
229
|
context_parts.append(f"age: {age}")
|
|
238
230
|
|
|
239
|
-
warning_message =
|
|
240
|
-
f"Could not determine a 'min' normal range for LabValue '{self.name}'"
|
|
241
|
-
)
|
|
231
|
+
warning_message = f"Could not determine a 'min' normal range for LabValue '{self.name}'"
|
|
242
232
|
if context_parts:
|
|
243
233
|
warning_message += f" with context ({', '.join(context_parts)})."
|
|
244
234
|
else:
|
|
@@ -248,7 +238,7 @@ class LabValue(models.Model):
|
|
|
248
238
|
|
|
249
239
|
return {"min": min_value, "max": max_value}
|
|
250
240
|
|
|
251
|
-
def get_increased_value(self, patient: "Patient" = None):
|
|
241
|
+
def get_increased_value(self, patient: Optional["Patient"] = None): # -> Any | None:
|
|
252
242
|
"""
|
|
253
243
|
Returns a value that is considered increased for this lab value.
|
|
254
244
|
It prioritizes sampling from a numerical distribution if available,
|
|
@@ -263,19 +253,17 @@ class LabValue(models.Model):
|
|
|
263
253
|
if patient:
|
|
264
254
|
# Attempt to sample above the upper bound, or a high value if no bound
|
|
265
255
|
for _ in range(10): # Try a few times to get a value if bounds are restrictive
|
|
266
|
-
generated_value = self.default_numerical_value_distribution.generate_value(
|
|
267
|
-
lab_value=self, patient=patient
|
|
268
|
-
)
|
|
256
|
+
generated_value = self.default_numerical_value_distribution.generate_value(lab_value=self, patient=patient)
|
|
269
257
|
if upper_bound is not None:
|
|
270
258
|
if generated_value > upper_bound:
|
|
271
259
|
return generated_value
|
|
272
260
|
# Heuristic for "high" if no upper_bound, compare against mean + stddev
|
|
273
|
-
elif
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
261
|
+
elif (
|
|
262
|
+
hasattr(self.default_numerical_value_distribution, "mean")
|
|
263
|
+
and hasattr(self.default_numerical_value_distribution, "stddev")
|
|
264
|
+
and self.default_numerical_value_distribution.mean is not None
|
|
265
|
+
and self.default_numerical_value_distribution.stddev is not None
|
|
266
|
+
and generated_value > (self.default_numerical_value_distribution.mean + self.default_numerical_value_distribution.stddev)
|
|
279
267
|
):
|
|
280
268
|
return generated_value
|
|
281
269
|
# Fallback if sampling fails to produce a clearly increased value
|
|
@@ -290,23 +278,19 @@ class LabValue(models.Model):
|
|
|
290
278
|
if upper_bound is not None:
|
|
291
279
|
return upper_bound + (abs(upper_bound * self.bound_adjustment_factor) if upper_bound != 0 else 1)
|
|
292
280
|
else:
|
|
293
|
-
warnings.warn(
|
|
294
|
-
f"Cannot determine an increased value for {self.name} without an upper normal range or patient context for distribution."
|
|
295
|
-
)
|
|
281
|
+
warnings.warn(f"Cannot determine an increased value for {self.name} without an upper normal range or patient context for distribution.")
|
|
296
282
|
return None
|
|
297
283
|
|
|
298
284
|
elif upper_bound is not None:
|
|
299
285
|
return upper_bound + (abs(upper_bound * self.bound_adjustment_factor) if upper_bound != 0 else 1)
|
|
300
286
|
else:
|
|
301
|
-
warnings.warn(
|
|
302
|
-
f"Cannot determine an increased value for {self.name} without a numerical distribution or an upper normal range."
|
|
303
|
-
)
|
|
287
|
+
warnings.warn(f"Cannot determine an increased value for {self.name} without a numerical distribution or an upper normal range.")
|
|
304
288
|
return None
|
|
305
289
|
|
|
306
|
-
def get_normal_value(self, patient: "Patient" = None):
|
|
290
|
+
def get_normal_value(self, patient: Optional["Patient"] = None):
|
|
307
291
|
"""
|
|
308
292
|
Returns a value considered normal for this lab value.
|
|
309
|
-
|
|
293
|
+
|
|
310
294
|
If a numerical distribution and patient context are available, attempts to generate a value within the normal range. Falls back to the midpoint of the normal range or to available bounds if sampling fails or context is insufficient. Returns None if neither a normal range nor a distribution is available.
|
|
311
295
|
"""
|
|
312
296
|
_age = patient.age() if patient else None
|
|
@@ -318,9 +302,7 @@ class LabValue(models.Model):
|
|
|
318
302
|
if self.default_numerical_value_distribution:
|
|
319
303
|
if patient:
|
|
320
304
|
for _ in range(10): # Try a few times
|
|
321
|
-
generated_value = self.default_numerical_value_distribution.generate_value(
|
|
322
|
-
lab_value=self, patient=patient
|
|
323
|
-
)
|
|
305
|
+
generated_value = self.default_numerical_value_distribution.generate_value(lab_value=self, patient=patient)
|
|
324
306
|
if lower_bound is not None and upper_bound is not None:
|
|
325
307
|
if lower_bound <= generated_value <= upper_bound:
|
|
326
308
|
return generated_value
|
|
@@ -346,10 +328,7 @@ class LabValue(models.Model):
|
|
|
346
328
|
elif upper_bound is not None:
|
|
347
329
|
return upper_bound
|
|
348
330
|
else:
|
|
349
|
-
warnings.warn(
|
|
350
|
-
f"Cannot determine a normal value for {self.name} without a normal range or patient context for distribution.",
|
|
351
|
-
UserWarning
|
|
352
|
-
)
|
|
331
|
+
warnings.warn(f"Cannot determine a normal value for {self.name} without a normal range or patient context for distribution.", UserWarning)
|
|
353
332
|
return None
|
|
354
333
|
|
|
355
334
|
elif lower_bound is not None and upper_bound is not None:
|
|
@@ -359,12 +338,10 @@ class LabValue(models.Model):
|
|
|
359
338
|
elif upper_bound is not None: # Only max is defined
|
|
360
339
|
return upper_bound
|
|
361
340
|
else:
|
|
362
|
-
warnings.warn(
|
|
363
|
-
f"Cannot determine a normal value for {self.name} without a numerical distribution or a normal range."
|
|
364
|
-
)
|
|
341
|
+
warnings.warn(f"Cannot determine a normal value for {self.name} without a numerical distribution or a normal range.")
|
|
365
342
|
return None
|
|
366
343
|
|
|
367
|
-
def get_decreased_value(self, patient: "Patient" = None):
|
|
344
|
+
def get_decreased_value(self, patient: Optional["Patient"] = None):
|
|
368
345
|
"""
|
|
369
346
|
Returns a value that is considered decreased for this lab value.
|
|
370
347
|
It prioritizes sampling from a numerical distribution if available,
|
|
@@ -378,19 +355,17 @@ class LabValue(models.Model):
|
|
|
378
355
|
if self.default_numerical_value_distribution:
|
|
379
356
|
if patient:
|
|
380
357
|
for _ in range(10): # Try a few times
|
|
381
|
-
generated_value = self.default_numerical_value_distribution.generate_value(
|
|
382
|
-
lab_value=self, patient=patient
|
|
383
|
-
)
|
|
358
|
+
generated_value = self.default_numerical_value_distribution.generate_value(lab_value=self, patient=patient)
|
|
384
359
|
if lower_bound is not None:
|
|
385
360
|
if generated_value < lower_bound:
|
|
386
361
|
return generated_value
|
|
387
362
|
# Heuristic for "low" if no lower_bound, compare against mean - stddev
|
|
388
|
-
elif
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
363
|
+
elif (
|
|
364
|
+
hasattr(self.default_numerical_value_distribution, "mean")
|
|
365
|
+
and hasattr(self.default_numerical_value_distribution, "stddev")
|
|
366
|
+
and self.default_numerical_value_distribution.mean is not None
|
|
367
|
+
and self.default_numerical_value_distribution.stddev is not None
|
|
368
|
+
and generated_value < (self.default_numerical_value_distribution.mean - self.default_numerical_value_distribution.stddev)
|
|
394
369
|
):
|
|
395
370
|
return generated_value
|
|
396
371
|
# Fallback
|
|
@@ -405,15 +380,11 @@ class LabValue(models.Model):
|
|
|
405
380
|
if lower_bound is not None:
|
|
406
381
|
return lower_bound - (abs(lower_bound * self.bound_adjustment_factor) if lower_bound != 0 else 1)
|
|
407
382
|
else:
|
|
408
|
-
warnings.warn(
|
|
409
|
-
f"Cannot determine a decreased value for {self.name} without a lower normal range or patient context for distribution."
|
|
410
|
-
)
|
|
383
|
+
warnings.warn(f"Cannot determine a decreased value for {self.name} without a lower normal range or patient context for distribution.")
|
|
411
384
|
return None
|
|
412
385
|
|
|
413
386
|
elif lower_bound is not None:
|
|
414
387
|
return lower_bound - (abs(lower_bound * self.bound_adjustment_factor) if lower_bound != 0 else 1)
|
|
415
388
|
else:
|
|
416
|
-
warnings.warn(
|
|
417
|
-
f"Cannot determine a decreased value for {self.name} without a numerical distribution or a lower normal range."
|
|
418
|
-
)
|
|
389
|
+
warnings.warn(f"Cannot determine a decreased value for {self.name} without a numerical distribution or a lower normal range.")
|
|
419
390
|
return None
|
|
@@ -1,31 +1,43 @@
|
|
|
1
|
-
|
|
1
|
+
"""Model for the medication."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
2
5
|
from django.db import models
|
|
3
6
|
|
|
4
7
|
|
|
5
8
|
class MedicationManager(models.Manager):
|
|
6
|
-
|
|
9
|
+
"""Manager for the medication model."""
|
|
10
|
+
|
|
7
11
|
def get_by_natural_key(self, name):
|
|
8
|
-
|
|
12
|
+
"""Retrieve a medication by its natural key."""
|
|
9
13
|
return self.get(name=name)
|
|
10
14
|
|
|
15
|
+
|
|
11
16
|
class Medication(models.Model):
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
"""Model representing a medication."""
|
|
18
|
+
|
|
19
|
+
name = models.CharField(max_length=255, unique=True)
|
|
20
|
+
adapt_to_renal_function = models.BooleanField(default=False)
|
|
15
21
|
adapt_to_hepatic_function = models.BooleanField(default=False)
|
|
16
22
|
adapt_to_indication = models.BooleanField(default=False)
|
|
17
23
|
adapt_to_age = models.BooleanField(default=False)
|
|
18
24
|
adapt_to_weight = models.BooleanField(default=False)
|
|
19
25
|
adapt_to_risk = models.BooleanField(default=False)
|
|
20
|
-
default_unit = models.ForeignKey(
|
|
21
|
-
|
|
26
|
+
default_unit = models.ForeignKey("Unit", on_delete=models.CASCADE)
|
|
22
27
|
|
|
23
28
|
objects = MedicationManager()
|
|
24
29
|
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from endoreg_db.models import MedicationSchedule, Unit
|
|
32
|
+
|
|
33
|
+
default_unit: models.ForeignKey["Unit"]
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def medication_schedules(self) -> "models.manager.RelatedManager[MedicationSchedule]": ...
|
|
37
|
+
|
|
25
38
|
def natural_key(self):
|
|
26
|
-
|
|
39
|
+
"""Return the natural key for the medication."""
|
|
27
40
|
return (self.name,)
|
|
28
41
|
|
|
29
42
|
def __str__(self):
|
|
30
43
|
return str(self.name)
|
|
31
|
-
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Model for medication indication."""
|
|
2
2
|
|
|
3
|
+
from typing import TYPE_CHECKING, cast
|
|
4
|
+
|
|
3
5
|
from django.db import models
|
|
4
6
|
|
|
5
7
|
|
|
@@ -25,11 +27,35 @@ class MedicationIndication(models.Model):
|
|
|
25
27
|
)
|
|
26
28
|
diseases = models.ManyToManyField("Disease")
|
|
27
29
|
events = models.ManyToManyField("Event")
|
|
28
|
-
disease_classification_choices = models.ManyToManyField(
|
|
29
|
-
"DiseaseClassificationChoice"
|
|
30
|
-
)
|
|
30
|
+
disease_classification_choices = models.ManyToManyField("DiseaseClassificationChoice")
|
|
31
31
|
sources = models.ManyToManyField("InformationSource")
|
|
32
32
|
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
from endoreg_db.models import (
|
|
35
|
+
Disease,
|
|
36
|
+
DiseaseClassificationChoice,
|
|
37
|
+
Event,
|
|
38
|
+
InformationSource,
|
|
39
|
+
MedicationIndicationType,
|
|
40
|
+
MedicationSchedule,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
indication_type: models.ForeignKey["MedicationIndicationType"]
|
|
44
|
+
medication_schedules = cast(
|
|
45
|
+
"models.manager.RelatedManager[MedicationSchedule]",
|
|
46
|
+
medication_schedules,
|
|
47
|
+
)
|
|
48
|
+
diseases = cast("models.manager.RelatedManager[Disease]", diseases)
|
|
49
|
+
events = cast("models.manager.RelatedManager[Event]", events)
|
|
50
|
+
disease_classification_choices = cast(
|
|
51
|
+
"models.manager.RelatedManager[DiseaseClassificationChoice]",
|
|
52
|
+
disease_classification_choices,
|
|
53
|
+
)
|
|
54
|
+
sources = cast(
|
|
55
|
+
"models.manager.RelatedManager[InformationSource]",
|
|
56
|
+
sources,
|
|
57
|
+
)
|
|
58
|
+
|
|
33
59
|
def get_indication_links(self) -> dict:
|
|
34
60
|
"""Return a dictionary of all linked objects for this medication indication."""
|
|
35
61
|
links = {
|