endoreg-db 0.8.9.2__py3-none-any.whl → 0.8.9.10__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 +10 -5
- endoreg_db/apps.py +4 -7
- endoreg_db/authz/auth.py +1 -0
- endoreg_db/authz/backends.py +1 -1
- endoreg_db/authz/management/commands/list_routes.py +2 -0
- endoreg_db/authz/middleware.py +8 -7
- endoreg_db/authz/permissions.py +21 -10
- endoreg_db/authz/policy.py +14 -19
- endoreg_db/authz/views_auth.py +14 -10
- endoreg_db/codemods/rename_datetime_fields.py +8 -1
- endoreg_db/exceptions.py +5 -2
- endoreg_db/forms/__init__.py +0 -1
- endoreg_db/forms/examination_form.py +4 -3
- endoreg_db/forms/patient_finding_intervention_form.py +30 -8
- endoreg_db/forms/patient_form.py +9 -13
- endoreg_db/forms/questionnaires/__init__.py +1 -1
- endoreg_db/forms/settings/__init__.py +4 -1
- endoreg_db/forms/unit.py +2 -1
- endoreg_db/helpers/count_db.py +17 -14
- endoreg_db/helpers/default_objects.py +2 -1
- endoreg_db/helpers/download_segmentation_model.py +4 -3
- endoreg_db/helpers/interact.py +0 -5
- endoreg_db/helpers/test_video_helper.py +33 -25
- endoreg_db/import_files/__init__.py +1 -1
- endoreg_db/import_files/context/__init__.py +1 -1
- endoreg_db/import_files/context/default_sensitive_meta.py +11 -9
- endoreg_db/import_files/context/ensure_center.py +4 -4
- endoreg_db/import_files/context/file_lock.py +3 -3
- endoreg_db/import_files/context/import_context.py +11 -12
- endoreg_db/import_files/context/validate_directories.py +1 -0
- endoreg_db/import_files/file_storage/create_report_file.py +57 -34
- endoreg_db/import_files/file_storage/create_video_file.py +64 -35
- endoreg_db/import_files/file_storage/sensitive_meta_storage.py +5 -2
- endoreg_db/import_files/file_storage/state_management.py +89 -122
- endoreg_db/import_files/file_storage/storage.py +5 -1
- endoreg_db/import_files/processing/report_processing/report_anonymization.py +24 -19
- endoreg_db/import_files/processing/sensitive_meta_adapter.py +3 -3
- endoreg_db/import_files/processing/video_processing/video_anonymization.py +18 -18
- endoreg_db/import_files/pseudonymization/k_anonymity.py +8 -9
- endoreg_db/import_files/pseudonymization/k_pseudonymity.py +16 -5
- endoreg_db/import_files/report_import_service.py +36 -30
- endoreg_db/import_files/video_import_service.py +27 -23
- endoreg_db/logger_conf.py +56 -40
- endoreg_db/management/__init__.py +1 -1
- endoreg_db/management/commands/__init__.py +1 -1
- endoreg_db/management/commands/check_auth.py +45 -38
- endoreg_db/management/commands/create_model_meta_from_huggingface.py +53 -2
- endoreg_db/management/commands/create_multilabel_model_meta.py +54 -19
- endoreg_db/management/commands/fix_missing_patient_data.py +105 -71
- endoreg_db/management/commands/fix_video_paths.py +75 -54
- endoreg_db/management/commands/import_report.py +1 -3
- endoreg_db/management/commands/list_routes.py +2 -0
- endoreg_db/management/commands/load_ai_model_data.py +8 -2
- endoreg_db/management/commands/load_ai_model_label_data.py +0 -1
- endoreg_db/management/commands/load_center_data.py +3 -3
- endoreg_db/management/commands/load_distribution_data.py +35 -38
- endoreg_db/management/commands/load_endoscope_data.py +0 -3
- endoreg_db/management/commands/load_examination_data.py +20 -4
- endoreg_db/management/commands/load_finding_data.py +18 -3
- endoreg_db/management/commands/load_gender_data.py +17 -24
- endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +95 -85
- endoreg_db/management/commands/load_information_source.py +0 -3
- endoreg_db/management/commands/load_lab_value_data.py +14 -3
- endoreg_db/management/commands/load_legacy_data.py +303 -0
- endoreg_db/management/commands/load_name_data.py +1 -2
- endoreg_db/management/commands/load_pdf_type_data.py +4 -8
- endoreg_db/management/commands/load_profession_data.py +0 -1
- endoreg_db/management/commands/load_report_reader_flag_data.py +0 -4
- endoreg_db/management/commands/load_requirement_data.py +6 -2
- endoreg_db/management/commands/load_unit_data.py +0 -4
- endoreg_db/management/commands/load_user_groups.py +5 -7
- endoreg_db/management/commands/model_input.py +169 -0
- endoreg_db/management/commands/register_ai_model.py +22 -16
- endoreg_db/management/commands/setup_endoreg_db.py +110 -32
- endoreg_db/management/commands/storage_management.py +14 -8
- endoreg_db/management/commands/summarize_db_content.py +154 -63
- endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
- endoreg_db/management/commands/validate_video_files.py +82 -50
- endoreg_db/management/commands/video_validation.py +4 -6
- endoreg_db/migrations/0001_initial.py +112 -63
- endoreg_db/models/__init__.py +8 -0
- endoreg_db/models/administration/ai/active_model.py +5 -5
- endoreg_db/models/administration/ai/ai_model.py +41 -18
- endoreg_db/models/administration/ai/model_type.py +1 -0
- endoreg_db/models/administration/case/case.py +22 -22
- endoreg_db/models/administration/center/__init__.py +5 -5
- endoreg_db/models/administration/center/center.py +6 -2
- endoreg_db/models/administration/center/center_resource.py +18 -4
- endoreg_db/models/administration/center/center_shift.py +3 -1
- endoreg_db/models/administration/center/center_waste.py +6 -2
- endoreg_db/models/administration/person/__init__.py +1 -1
- endoreg_db/models/administration/person/employee/__init__.py +1 -1
- endoreg_db/models/administration/person/employee/employee_type.py +3 -1
- endoreg_db/models/administration/person/examiner/__init__.py +1 -1
- endoreg_db/models/administration/person/examiner/examiner.py +10 -2
- endoreg_db/models/administration/person/names/first_name.py +6 -4
- endoreg_db/models/administration/person/names/last_name.py +4 -3
- endoreg_db/models/administration/person/patient/__init__.py +1 -1
- endoreg_db/models/administration/person/patient/patient.py +0 -1
- endoreg_db/models/administration/person/patient/patient_external_id.py +0 -1
- endoreg_db/models/administration/person/person.py +1 -1
- endoreg_db/models/administration/product/__init__.py +7 -6
- endoreg_db/models/administration/product/product.py +6 -2
- endoreg_db/models/administration/product/product_group.py +9 -7
- endoreg_db/models/administration/product/product_material.py +9 -2
- endoreg_db/models/administration/product/reference_product.py +64 -15
- endoreg_db/models/administration/qualification/qualification.py +3 -1
- endoreg_db/models/administration/shift/shift.py +3 -1
- endoreg_db/models/administration/shift/shift_type.py +12 -4
- endoreg_db/models/aidataset/__init__.py +5 -0
- endoreg_db/models/aidataset/aidataset.py +193 -0
- endoreg_db/models/label/__init__.py +1 -1
- endoreg_db/models/label/label.py +10 -2
- endoreg_db/models/label/label_set.py +3 -1
- endoreg_db/models/label/label_video_segment/_create_from_video.py +6 -2
- endoreg_db/models/label/label_video_segment/label_video_segment.py +148 -44
- endoreg_db/models/media/__init__.py +12 -5
- endoreg_db/models/media/frame/__init__.py +1 -1
- endoreg_db/models/media/frame/frame.py +34 -8
- endoreg_db/models/media/pdf/__init__.py +2 -1
- endoreg_db/models/media/pdf/raw_pdf.py +11 -4
- endoreg_db/models/media/pdf/report_file.py +6 -2
- endoreg_db/models/media/pdf/report_reader/__init__.py +3 -3
- endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +15 -5
- endoreg_db/models/media/video/create_from_file.py +20 -41
- endoreg_db/models/media/video/pipe_1.py +75 -30
- endoreg_db/models/media/video/pipe_2.py +37 -12
- endoreg_db/models/media/video/video_file.py +36 -24
- endoreg_db/models/media/video/video_file_ai.py +235 -70
- endoreg_db/models/media/video/video_file_anonymize.py +240 -65
- endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -1
- endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +3 -1
- endoreg_db/models/media/video/video_file_frames/_delete_frames.py +30 -9
- endoreg_db/models/media/video/video_file_frames/_extract_frames.py +95 -29
- endoreg_db/models/media/video/video_file_frames/_get_frame.py +13 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -1
- endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +15 -3
- endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +15 -3
- endoreg_db/models/media/video/video_file_frames/_get_frames.py +7 -2
- endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +109 -23
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +111 -27
- endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +46 -13
- endoreg_db/models/media/video/video_file_io.py +85 -33
- endoreg_db/models/media/video/video_file_meta/__init__.py +6 -6
- endoreg_db/models/media/video/video_file_meta/get_crop_template.py +17 -4
- endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +28 -7
- endoreg_db/models/media/video/video_file_meta/get_fps.py +46 -13
- endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +81 -20
- endoreg_db/models/media/video/video_file_meta/text_meta.py +61 -20
- endoreg_db/models/media/video/video_file_meta/video_meta.py +40 -12
- endoreg_db/models/media/video/video_file_segments.py +118 -27
- endoreg_db/models/media/video/video_metadata.py +25 -6
- endoreg_db/models/media/video/video_processing.py +54 -15
- endoreg_db/models/medical/__init__.py +3 -13
- endoreg_db/models/medical/contraindication/__init__.py +3 -1
- endoreg_db/models/medical/disease.py +18 -6
- endoreg_db/models/medical/event.py +6 -2
- endoreg_db/models/medical/examination/__init__.py +5 -1
- endoreg_db/models/medical/examination/examination.py +22 -6
- endoreg_db/models/medical/examination/examination_indication.py +23 -7
- endoreg_db/models/medical/examination/examination_time.py +6 -2
- endoreg_db/models/medical/finding/__init__.py +3 -1
- endoreg_db/models/medical/finding/finding.py +37 -12
- endoreg_db/models/medical/finding/finding_classification.py +27 -8
- endoreg_db/models/medical/finding/finding_intervention.py +19 -6
- endoreg_db/models/medical/finding/finding_type.py +3 -1
- endoreg_db/models/medical/hardware/__init__.py +1 -1
- endoreg_db/models/medical/hardware/endoscope.py +14 -2
- endoreg_db/models/medical/laboratory/__init__.py +1 -1
- endoreg_db/models/medical/laboratory/lab_value.py +139 -39
- endoreg_db/models/medical/medication/__init__.py +7 -3
- endoreg_db/models/medical/medication/medication.py +3 -1
- endoreg_db/models/medical/medication/medication_indication.py +3 -1
- endoreg_db/models/medical/medication/medication_indication_type.py +11 -3
- endoreg_db/models/medical/medication/medication_intake_time.py +3 -1
- endoreg_db/models/medical/medication/medication_schedule.py +3 -1
- endoreg_db/models/medical/patient/__init__.py +2 -10
- endoreg_db/models/medical/patient/medication_examples.py +3 -14
- endoreg_db/models/medical/patient/patient_disease.py +17 -5
- endoreg_db/models/medical/patient/patient_event.py +12 -4
- endoreg_db/models/medical/patient/patient_examination.py +52 -15
- endoreg_db/models/medical/patient/patient_examination_indication.py +15 -4
- endoreg_db/models/medical/patient/patient_finding.py +105 -29
- endoreg_db/models/medical/patient/patient_finding_classification.py +41 -12
- endoreg_db/models/medical/patient/patient_finding_intervention.py +11 -3
- endoreg_db/models/medical/patient/patient_lab_sample.py +6 -2
- endoreg_db/models/medical/patient/patient_lab_value.py +42 -10
- endoreg_db/models/medical/patient/patient_medication.py +25 -7
- endoreg_db/models/medical/patient/patient_medication_schedule.py +34 -10
- endoreg_db/models/metadata/model_meta.py +40 -12
- endoreg_db/models/metadata/model_meta_logic.py +51 -16
- endoreg_db/models/metadata/sensitive_meta.py +65 -28
- endoreg_db/models/metadata/sensitive_meta_logic.py +28 -26
- endoreg_db/models/metadata/video_meta.py +146 -39
- endoreg_db/models/metadata/video_prediction_logic.py +70 -21
- endoreg_db/models/metadata/video_prediction_meta.py +80 -27
- endoreg_db/models/operation_log.py +63 -0
- endoreg_db/models/other/__init__.py +10 -10
- endoreg_db/models/other/distribution/__init__.py +9 -7
- endoreg_db/models/other/distribution/base_value_distribution.py +3 -1
- endoreg_db/models/other/distribution/date_value_distribution.py +19 -5
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +3 -1
- endoreg_db/models/other/distribution/numeric_value_distribution.py +34 -9
- endoreg_db/models/other/emission/__init__.py +1 -1
- endoreg_db/models/other/emission/emission_factor.py +9 -3
- endoreg_db/models/other/information_source.py +15 -5
- endoreg_db/models/other/material.py +3 -1
- endoreg_db/models/other/transport_route.py +3 -1
- endoreg_db/models/other/unit.py +6 -2
- endoreg_db/models/report/report.py +0 -1
- endoreg_db/models/requirement/requirement.py +84 -27
- endoreg_db/models/requirement/requirement_error.py +5 -6
- endoreg_db/models/requirement/requirement_evaluation/__init__.py +1 -1
- endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +8 -8
- endoreg_db/models/requirement/requirement_evaluation/get_values.py +3 -3
- endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +24 -8
- endoreg_db/models/requirement/requirement_operator.py +28 -8
- endoreg_db/models/requirement/requirement_set.py +34 -11
- endoreg_db/models/state/__init__.py +1 -0
- endoreg_db/models/state/audit_ledger.py +9 -2
- endoreg_db/models/{media → state}/processing_history/__init__.py +1 -3
- endoreg_db/models/state/processing_history/processing_history.py +136 -0
- endoreg_db/models/state/raw_pdf.py +0 -1
- endoreg_db/models/state/video.py +2 -4
- endoreg_db/models/utils.py +4 -2
- endoreg_db/queries/__init__.py +2 -6
- endoreg_db/queries/annotations/__init__.py +1 -3
- endoreg_db/queries/annotations/legacy.py +37 -26
- endoreg_db/root_urls.py +3 -4
- endoreg_db/schemas/examination_evaluation.py +3 -0
- endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +249 -163
- endoreg_db/serializers/__init__.py +2 -8
- endoreg_db/serializers/administration/__init__.py +1 -2
- endoreg_db/serializers/administration/ai/__init__.py +0 -1
- endoreg_db/serializers/administration/ai/active_model.py +3 -1
- endoreg_db/serializers/administration/ai/ai_model.py +5 -3
- endoreg_db/serializers/administration/ai/model_type.py +3 -1
- endoreg_db/serializers/administration/center.py +7 -2
- endoreg_db/serializers/administration/gender.py +4 -2
- endoreg_db/serializers/anonymization.py +13 -13
- endoreg_db/serializers/evaluation/examination_evaluation.py +0 -1
- endoreg_db/serializers/examination/__init__.py +1 -1
- endoreg_db/serializers/examination/base.py +12 -13
- endoreg_db/serializers/examination/dropdown.py +6 -7
- endoreg_db/serializers/examination_serializer.py +3 -6
- endoreg_db/serializers/finding/__init__.py +1 -1
- endoreg_db/serializers/finding/finding.py +14 -7
- endoreg_db/serializers/finding_classification/__init__.py +3 -3
- endoreg_db/serializers/finding_classification/choice.py +3 -3
- endoreg_db/serializers/finding_classification/classification.py +2 -4
- endoreg_db/serializers/label_video_segment/__init__.py +5 -3
- endoreg_db/serializers/{label → label_video_segment}/image_classification_annotation.py +5 -5
- endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
- endoreg_db/serializers/{label → label_video_segment/label}/label.py +1 -1
- endoreg_db/serializers/label_video_segment/label_video_segment.py +338 -228
- endoreg_db/serializers/meta/__init__.py +1 -2
- endoreg_db/serializers/meta/sensitive_meta_detail.py +28 -13
- endoreg_db/serializers/meta/sensitive_meta_update.py +51 -46
- endoreg_db/serializers/meta/sensitive_meta_verification.py +19 -16
- endoreg_db/serializers/misc/__init__.py +2 -2
- endoreg_db/serializers/misc/file_overview.py +11 -7
- endoreg_db/serializers/misc/stats.py +10 -8
- endoreg_db/serializers/misc/translatable_field_mix_in.py +6 -6
- endoreg_db/serializers/misc/upload_job.py +32 -29
- endoreg_db/serializers/patient/__init__.py +2 -1
- endoreg_db/serializers/patient/patient.py +32 -15
- endoreg_db/serializers/patient/patient_dropdown.py +11 -3
- endoreg_db/serializers/patient_examination/__init__.py +1 -1
- endoreg_db/serializers/patient_examination/patient_examination.py +67 -40
- endoreg_db/serializers/patient_finding/__init__.py +1 -1
- endoreg_db/serializers/patient_finding/patient_finding.py +2 -1
- endoreg_db/serializers/patient_finding/patient_finding_classification.py +17 -9
- endoreg_db/serializers/patient_finding/patient_finding_detail.py +26 -17
- endoreg_db/serializers/patient_finding/patient_finding_intervention.py +7 -5
- endoreg_db/serializers/patient_finding/patient_finding_list.py +10 -11
- endoreg_db/serializers/patient_finding/patient_finding_write.py +36 -27
- endoreg_db/serializers/pdf/__init__.py +1 -3
- endoreg_db/serializers/requirements/requirement_schema.py +1 -6
- endoreg_db/serializers/sensitive_meta_serializer.py +100 -81
- endoreg_db/serializers/video/__init__.py +2 -2
- endoreg_db/serializers/video/{segmentation.py → video_file.py} +66 -47
- endoreg_db/serializers/video/video_file_brief.py +6 -2
- endoreg_db/serializers/video/video_file_detail.py +36 -23
- endoreg_db/serializers/video/video_file_list.py +4 -2
- endoreg_db/serializers/video/video_processing_history.py +54 -50
- endoreg_db/services/__init__.py +1 -1
- endoreg_db/services/anonymization.py +2 -2
- endoreg_db/services/examination_evaluation.py +40 -17
- endoreg_db/services/model_meta_from_hf.py +76 -0
- endoreg_db/services/polling_coordinator.py +101 -70
- endoreg_db/services/pseudonym_service.py +27 -22
- endoreg_db/services/report_import.py +6 -3
- endoreg_db/services/segment_sync.py +75 -59
- endoreg_db/services/video_import.py +6 -7
- endoreg_db/urls/__init__.py +2 -2
- endoreg_db/urls/ai.py +7 -25
- endoreg_db/urls/anonymization.py +61 -15
- endoreg_db/urls/auth.py +4 -4
- endoreg_db/urls/classification.py +4 -9
- endoreg_db/urls/examination.py +27 -18
- endoreg_db/urls/media.py +27 -34
- endoreg_db/urls/patient.py +11 -7
- endoreg_db/urls/requirements.py +3 -1
- endoreg_db/urls/root_urls.py +2 -3
- endoreg_db/urls/stats.py +24 -16
- endoreg_db/urls/upload.py +3 -11
- endoreg_db/utils/__init__.py +14 -15
- endoreg_db/utils/ai/__init__.py +1 -1
- endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
- endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
- endoreg_db/utils/ai/get.py +2 -1
- endoreg_db/utils/ai/inference_dataset.py +14 -15
- endoreg_db/utils/ai/model_training/config.py +117 -0
- endoreg_db/utils/ai/model_training/dataset.py +74 -0
- endoreg_db/utils/ai/model_training/losses.py +68 -0
- endoreg_db/utils/ai/model_training/metrics.py +78 -0
- endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
- endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
- endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
- endoreg_db/utils/ai/multilabel_classification_net.py +21 -6
- endoreg_db/utils/ai/predict.py +4 -4
- endoreg_db/utils/ai/preprocess.py +19 -11
- endoreg_db/utils/calc_duration_seconds.py +4 -4
- endoreg_db/utils/case_generator/lab_sample_factory.py +3 -4
- endoreg_db/utils/check_video_files.py +74 -47
- endoreg_db/utils/cropping.py +10 -9
- endoreg_db/utils/dataloader.py +11 -3
- endoreg_db/utils/dates.py +3 -4
- endoreg_db/utils/defaults/set_default_center.py +7 -6
- endoreg_db/utils/env.py +6 -2
- endoreg_db/utils/extract_specific_frames.py +24 -9
- endoreg_db/utils/file_operations.py +30 -18
- endoreg_db/utils/fix_video_path_direct.py +57 -41
- endoreg_db/utils/frame_anonymization_utils.py +157 -157
- endoreg_db/utils/hashs.py +3 -18
- endoreg_db/utils/links/requirement_link.py +96 -52
- endoreg_db/utils/ocr.py +30 -25
- endoreg_db/utils/operation_log.py +61 -0
- endoreg_db/utils/parse_and_generate_yaml.py +12 -13
- endoreg_db/utils/paths.py +6 -6
- endoreg_db/utils/permissions.py +40 -24
- endoreg_db/utils/pipelines/process_video_dir.py +50 -26
- endoreg_db/utils/product/sum_emissions.py +5 -3
- endoreg_db/utils/product/sum_weights.py +4 -2
- endoreg_db/utils/pydantic_models/__init__.py +3 -4
- endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +207 -107
- endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +252 -65
- endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +27 -10
- endoreg_db/utils/setup_config.py +21 -5
- endoreg_db/utils/storage.py +3 -1
- endoreg_db/utils/translation.py +19 -15
- endoreg_db/utils/uuid.py +1 -0
- endoreg_db/utils/validate_endo_roi.py +12 -4
- endoreg_db/utils/validate_subcategory_dict.py +26 -24
- endoreg_db/utils/validate_video_detailed.py +207 -149
- endoreg_db/utils/video/__init__.py +7 -3
- endoreg_db/utils/video/extract_frames.py +30 -18
- endoreg_db/utils/video/names.py +11 -6
- endoreg_db/utils/video/streaming_processor.py +175 -101
- endoreg_db/utils/video/video_splitter.py +30 -19
- endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +59 -50
- endoreg_db/views/__init__.py +0 -20
- endoreg_db/views/anonymization/__init__.py +6 -2
- endoreg_db/views/anonymization/media_management.py +2 -6
- endoreg_db/views/anonymization/overview.py +34 -1
- endoreg_db/views/anonymization/validate.py +79 -18
- endoreg_db/views/auth/__init__.py +1 -1
- endoreg_db/views/auth/keycloak.py +16 -14
- endoreg_db/views/examination/__init__.py +12 -15
- endoreg_db/views/examination/examination.py +5 -5
- endoreg_db/views/examination/examination_manifest_cache.py +5 -5
- endoreg_db/views/examination/get_finding_classification_choices.py +8 -5
- endoreg_db/views/examination/get_finding_classifications.py +9 -7
- endoreg_db/views/examination/get_findings.py +8 -10
- endoreg_db/views/examination/get_instruments.py +3 -2
- endoreg_db/views/examination/get_interventions.py +1 -1
- endoreg_db/views/finding/__init__.py +2 -2
- endoreg_db/views/finding/finding.py +58 -54
- endoreg_db/views/finding/get_classifications.py +1 -1
- endoreg_db/views/finding/get_interventions.py +1 -1
- endoreg_db/views/finding_classification/__init__.py +5 -5
- endoreg_db/views/finding_classification/finding_classification.py +5 -6
- endoreg_db/views/finding_classification/get_classification_choices.py +3 -4
- endoreg_db/views/media/__init__.py +13 -13
- endoreg_db/views/media/pdf_media.py +9 -9
- endoreg_db/views/media/sensitive_metadata.py +10 -7
- endoreg_db/views/media/video_media.py +4 -4
- endoreg_db/views/meta/__init__.py +1 -1
- endoreg_db/views/meta/sensitive_meta_list.py +20 -22
- endoreg_db/views/meta/sensitive_meta_verification.py +14 -11
- endoreg_db/views/misc/__init__.py +6 -34
- endoreg_db/views/misc/center.py +2 -1
- endoreg_db/views/misc/csrf.py +2 -1
- endoreg_db/views/misc/gender.py +2 -1
- endoreg_db/views/misc/stats.py +141 -106
- endoreg_db/views/patient/__init__.py +1 -3
- endoreg_db/views/patient/patient.py +141 -99
- endoreg_db/views/patient_examination/__init__.py +5 -5
- endoreg_db/views/patient_examination/patient_examination.py +43 -42
- endoreg_db/views/patient_examination/patient_examination_create.py +10 -15
- endoreg_db/views/patient_examination/patient_examination_detail.py +12 -15
- endoreg_db/views/patient_examination/patient_examination_list.py +21 -17
- endoreg_db/views/patient_examination/video.py +114 -80
- endoreg_db/views/patient_finding/__init__.py +1 -1
- endoreg_db/views/patient_finding/patient_finding.py +17 -10
- endoreg_db/views/patient_finding/patient_finding_optimized.py +127 -95
- endoreg_db/views/patient_finding_classification/__init__.py +1 -1
- endoreg_db/views/patient_finding_classification/pfc_create.py +35 -27
- endoreg_db/views/report/reimport.py +1 -1
- endoreg_db/views/report/report_stream.py +5 -8
- endoreg_db/views/requirement/__init__.py +2 -1
- endoreg_db/views/requirement/evaluate.py +7 -9
- endoreg_db/views/requirement/lookup.py +2 -3
- endoreg_db/views/requirement/lookup_store.py +0 -1
- endoreg_db/views/requirement/requirement_utils.py +2 -4
- endoreg_db/views/stats/__init__.py +4 -4
- endoreg_db/views/stats/stats_views.py +152 -115
- endoreg_db/views/video/__init__.py +18 -27
- endoreg_db/views/{ai → video/ai}/__init__.py +2 -2
- endoreg_db/views/{ai → video/ai}/label.py +20 -16
- endoreg_db/views/video/correction.py +5 -6
- endoreg_db/views/video/reimport.py +134 -99
- endoreg_db/views/video/segments_crud.py +134 -44
- endoreg_db/views/video/video_apply_mask.py +13 -12
- endoreg_db/views/video/video_correction.py +2 -1
- endoreg_db/views/video/video_download_processed.py +15 -15
- endoreg_db/views/video/video_meta_stats.py +7 -6
- endoreg_db/views/video/video_processing_history.py +3 -2
- endoreg_db/views/video/video_remove_frames.py +13 -12
- endoreg_db/views/video/video_stream.py +110 -82
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +434 -431
- endoreg_db/management/commands/import_fallback_video.py +0 -203
- endoreg_db/management/commands/import_video.py +0 -422
- endoreg_db/management/commands/import_video_with_classification.py +0 -367
- endoreg_db/models/media/processing_history/processing_history.py +0 -96
- endoreg_db/serializers/label/__init__.py +0 -7
- endoreg_db/serializers/label_video_segment/_lvs_create.py +0 -149
- endoreg_db/serializers/label_video_segment/_lvs_update.py +0 -138
- endoreg_db/serializers/label_video_segment/_lvs_validate.py +0 -149
- endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +0 -99
- endoreg_db/serializers/label_video_segment/label_video_segment_update.py +0 -163
- endoreg_db/services/__old/pdf_import.py +0 -1487
- endoreg_db/services/__old/video_import.py +0 -1306
- endoreg_db/tasks/upload_tasks.py +0 -216
- endoreg_db/tasks/video_ingest.py +0 -161
- endoreg_db/tasks/video_processing_tasks.py +0 -327
- endoreg_db/views/misc/translation.py +0 -182
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, List, Optional, Callable, Dict, Any
|
|
2
|
-
import re
|
|
2
|
+
import re # Added import
|
|
3
3
|
from endoreg_db.models.medical.patient.patient_lab_value import PatientLabValue
|
|
4
4
|
from endoreg_db.models.requirement.requirement import Requirement
|
|
5
5
|
from datetime import datetime, timedelta
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
|
-
from endoreg_db.utils.links.requirement_link import RequirementLinks
|
|
8
|
+
from endoreg_db.utils.links.requirement_link import RequirementLinks # Added import
|
|
9
9
|
# from endoreg_db.models.requirement.requirement_operator import RequirementOperator # No longer directly used here
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
def get_latest_patient_lab_value(
|
|
13
|
+
patient_lab_values: List[PatientLabValue], lab_value_name: str
|
|
14
|
+
) -> Optional[PatientLabValue]:
|
|
12
15
|
"""
|
|
13
16
|
Retrieves the most recent PatientLabValue for a specific lab_value_name.
|
|
14
17
|
"""
|
|
15
18
|
relevant_values = [
|
|
16
|
-
plv
|
|
19
|
+
plv
|
|
20
|
+
for plv in patient_lab_values
|
|
21
|
+
if plv.lab_value and plv.lab_value.name == lab_value_name
|
|
17
22
|
]
|
|
18
23
|
if not relevant_values:
|
|
19
24
|
return None
|
|
20
25
|
return max(relevant_values, key=lambda plv: plv.datetime)
|
|
21
26
|
|
|
27
|
+
|
|
22
28
|
def get_patient_lab_values_in_timeframe(
|
|
23
29
|
patient_lab_values: List[PatientLabValue],
|
|
24
30
|
lab_value_name: str,
|
|
@@ -32,7 +38,9 @@ def get_patient_lab_values_in_timeframe(
|
|
|
32
38
|
days_max: e.g., 0 for today (end of timeframe)
|
|
33
39
|
"""
|
|
34
40
|
relevant_values = [
|
|
35
|
-
plv
|
|
41
|
+
plv
|
|
42
|
+
for plv in patient_lab_values
|
|
43
|
+
if plv.lab_value and plv.lab_value.name == lab_value_name
|
|
36
44
|
]
|
|
37
45
|
if not relevant_values:
|
|
38
46
|
return []
|
|
@@ -57,78 +65,90 @@ def get_patient_lab_values_in_timeframe(
|
|
|
57
65
|
|
|
58
66
|
|
|
59
67
|
def lab_latest_numeric_increased(
|
|
60
|
-
input_links: "RequirementLinks",
|
|
68
|
+
input_links: "RequirementLinks", # Changed
|
|
61
69
|
requirement: Requirement,
|
|
62
|
-
operator_kwargs: Dict[str, Any]
|
|
70
|
+
operator_kwargs: Dict[str, Any],
|
|
63
71
|
) -> bool:
|
|
64
72
|
"""
|
|
65
73
|
Returns True if the latest numeric lab value for all required lab values is above the normal maximum range; otherwise returns False.
|
|
66
|
-
|
|
74
|
+
|
|
67
75
|
Returns False if any required lab value is missing, the latest value is unavailable, or the value does not exceed the normal maximum.
|
|
68
76
|
"""
|
|
69
77
|
patient_lab_values = input_links.patient_lab_values
|
|
70
78
|
if not requirement.lab_values.exists():
|
|
71
79
|
return False
|
|
72
80
|
for lab_value_model in requirement.lab_values.all():
|
|
73
|
-
latest_plv = get_latest_patient_lab_value(
|
|
81
|
+
latest_plv = get_latest_patient_lab_value(
|
|
82
|
+
patient_lab_values, lab_value_model.name
|
|
83
|
+
)
|
|
74
84
|
if not (latest_plv and latest_plv.value is not None and latest_plv.lab_value):
|
|
75
85
|
return False
|
|
76
86
|
patient_context = input_links.get_first_patient()
|
|
77
87
|
normal_range = latest_plv.lab_value.get_normal_range(
|
|
78
88
|
age=patient_context.age() if patient_context else None,
|
|
79
|
-
gender=patient_context.gender if patient_context else None
|
|
89
|
+
gender=patient_context.gender if patient_context else None,
|
|
80
90
|
)
|
|
81
91
|
if normal_range.get("max") is None or latest_plv.value <= normal_range["max"]:
|
|
82
92
|
return False
|
|
83
93
|
return True
|
|
84
94
|
|
|
95
|
+
|
|
85
96
|
def lab_latest_numeric_decreased(
|
|
86
|
-
input_links: "RequirementLinks",
|
|
97
|
+
input_links: "RequirementLinks", # Changed
|
|
87
98
|
requirement: Requirement,
|
|
88
|
-
operator_kwargs: Dict[str, Any]
|
|
99
|
+
operator_kwargs: Dict[str, Any],
|
|
89
100
|
) -> bool:
|
|
90
101
|
"""
|
|
91
102
|
Returns True if the latest numeric lab value for all required lab values is below the normal minimum range.
|
|
92
|
-
|
|
103
|
+
|
|
93
104
|
Returns False if any latest value is missing, lacks a normal range, or is not below the minimum.
|
|
94
105
|
"""
|
|
95
106
|
patient_lab_values = input_links.patient_lab_values
|
|
96
|
-
if not requirement.lab_values.exists():
|
|
107
|
+
if not requirement.lab_values.exists(): # Changed
|
|
97
108
|
return False
|
|
98
109
|
for lab_value_model in requirement.lab_values.all():
|
|
99
|
-
latest_plv = get_latest_patient_lab_value(
|
|
100
|
-
|
|
110
|
+
latest_plv = get_latest_patient_lab_value(
|
|
111
|
+
patient_lab_values, lab_value_model.name
|
|
112
|
+
)
|
|
113
|
+
if not (
|
|
114
|
+
latest_plv and latest_plv.value is not None and latest_plv.lab_value
|
|
115
|
+
): # Added check for latest_plv.lab_value
|
|
101
116
|
return False
|
|
102
117
|
patient_context = input_links.get_first_patient()
|
|
103
118
|
normal_range = latest_plv.lab_value.get_normal_range(
|
|
104
|
-
age=patient_context.age() if patient_context else None,
|
|
105
|
-
gender=patient_context.gender if patient_context else None
|
|
119
|
+
age=patient_context.age() if patient_context else None,
|
|
120
|
+
gender=patient_context.gender if patient_context else None,
|
|
106
121
|
)
|
|
107
122
|
if normal_range.get("min") is None or latest_plv.value >= normal_range["min"]:
|
|
108
123
|
return False
|
|
109
124
|
return True
|
|
110
125
|
|
|
126
|
+
|
|
111
127
|
def lab_latest_numeric_normal(
|
|
112
|
-
input_links: "RequirementLinks",
|
|
128
|
+
input_links: "RequirementLinks", # Changed
|
|
113
129
|
requirement: Requirement,
|
|
114
|
-
operator_kwargs: Dict[str, Any]
|
|
130
|
+
operator_kwargs: Dict[str, Any],
|
|
115
131
|
) -> bool:
|
|
116
132
|
"""
|
|
117
133
|
Returns True if the latest numeric lab value for all required lab values is within the normal range.
|
|
118
|
-
|
|
134
|
+
|
|
119
135
|
Returns False if any latest value is missing, lacks a normal range, or falls outside the normal range.
|
|
120
136
|
"""
|
|
121
137
|
patient_lab_values = input_links.patient_lab_values
|
|
122
|
-
if not requirement.lab_values.exists():
|
|
138
|
+
if not requirement.lab_values.exists(): # Changed
|
|
123
139
|
return False
|
|
124
140
|
for lab_value_model in requirement.lab_values.all():
|
|
125
|
-
latest_plv = get_latest_patient_lab_value(
|
|
126
|
-
|
|
141
|
+
latest_plv = get_latest_patient_lab_value(
|
|
142
|
+
patient_lab_values, lab_value_model.name
|
|
143
|
+
)
|
|
144
|
+
if not (
|
|
145
|
+
latest_plv and latest_plv.value is not None and latest_plv.lab_value
|
|
146
|
+
): # Added check for latest_plv.lab_value
|
|
127
147
|
return False
|
|
128
148
|
patient_context = input_links.get_first_patient()
|
|
129
149
|
normal_range = latest_plv.lab_value.get_normal_range(
|
|
130
|
-
age=patient_context.age() if patient_context else None,
|
|
131
|
-
gender=patient_context.gender if patient_context else None
|
|
150
|
+
age=patient_context.age() if patient_context else None,
|
|
151
|
+
gender=patient_context.gender if patient_context else None,
|
|
132
152
|
)
|
|
133
153
|
min_val = normal_range.get("min")
|
|
134
154
|
max_val = normal_range.get("max")
|
|
@@ -138,54 +158,66 @@ def lab_latest_numeric_normal(
|
|
|
138
158
|
return False
|
|
139
159
|
return True
|
|
140
160
|
|
|
161
|
+
|
|
141
162
|
def lab_latest_numeric_lower_than_value(
|
|
142
|
-
input_links: "RequirementLinks",
|
|
163
|
+
input_links: "RequirementLinks", # Changed
|
|
143
164
|
requirement: Requirement,
|
|
144
|
-
operator_kwargs: Dict[str, Any]
|
|
165
|
+
operator_kwargs: Dict[str, Any],
|
|
145
166
|
) -> bool:
|
|
146
167
|
"""
|
|
147
168
|
Returns True if the latest numeric lab value for all required lab values is lower than the specified threshold.
|
|
148
|
-
|
|
169
|
+
|
|
149
170
|
Returns False if any latest value is missing or not below the requirement's numeric value.
|
|
150
171
|
"""
|
|
151
172
|
patient_lab_values = input_links.patient_lab_values
|
|
152
|
-
if
|
|
173
|
+
if (
|
|
174
|
+
not requirement.lab_values.exists() or requirement.numeric_value is None
|
|
175
|
+
): # Changed
|
|
153
176
|
return False
|
|
154
177
|
for lab_value_model in requirement.lab_values.all():
|
|
155
|
-
latest_plv = get_latest_patient_lab_value(
|
|
178
|
+
latest_plv = get_latest_patient_lab_value(
|
|
179
|
+
patient_lab_values, lab_value_model.name
|
|
180
|
+
)
|
|
156
181
|
if not (latest_plv and latest_plv.value is not None):
|
|
157
182
|
return False
|
|
158
183
|
if not (latest_plv.value < requirement.numeric_value):
|
|
159
184
|
return False
|
|
160
185
|
return True
|
|
161
186
|
|
|
187
|
+
|
|
162
188
|
def lab_latest_numeric_greater_than_value(
|
|
163
|
-
input_links: "RequirementLinks",
|
|
189
|
+
input_links: "RequirementLinks", # Changed
|
|
164
190
|
requirement: Requirement,
|
|
165
|
-
operator_kwargs: Dict[str, Any]
|
|
191
|
+
operator_kwargs: Dict[str, Any],
|
|
166
192
|
) -> bool:
|
|
167
193
|
"""
|
|
168
194
|
Returns True if the latest numeric lab value for all required lab values is greater than the specified threshold.
|
|
169
|
-
|
|
195
|
+
|
|
170
196
|
Returns False if any latest value is missing or not greater than the requirement's numeric value.
|
|
171
197
|
"""
|
|
172
198
|
patient_lab_values = input_links.patient_lab_values
|
|
173
|
-
if
|
|
199
|
+
if (
|
|
200
|
+
not requirement.lab_values.exists() or requirement.numeric_value is None
|
|
201
|
+
): # Changed
|
|
174
202
|
return False
|
|
175
203
|
for lab_value_model in requirement.lab_values.all():
|
|
176
|
-
latest_plv = get_latest_patient_lab_value(
|
|
204
|
+
latest_plv = get_latest_patient_lab_value(
|
|
205
|
+
patient_lab_values, lab_value_model.name
|
|
206
|
+
)
|
|
177
207
|
if not (latest_plv and latest_plv.value is not None):
|
|
178
208
|
return False
|
|
179
209
|
if not (latest_plv.value > requirement.numeric_value):
|
|
180
210
|
return False
|
|
181
211
|
return True
|
|
182
212
|
|
|
213
|
+
|
|
183
214
|
# --- Operators with timeframe ---
|
|
184
215
|
|
|
216
|
+
|
|
185
217
|
def lab_latest_numeric_increased_factor_in_timeframe(
|
|
186
|
-
input_links: "RequirementLinks",
|
|
218
|
+
input_links: "RequirementLinks", # Changed
|
|
187
219
|
requirement: Requirement,
|
|
188
|
-
operator_kwargs: Dict[str, Any]
|
|
220
|
+
operator_kwargs: Dict[str, Any],
|
|
189
221
|
) -> bool:
|
|
190
222
|
"""
|
|
191
223
|
Checks if the numeric lab value has increased by a certain factor within a timeframe.
|
|
@@ -197,21 +229,29 @@ def lab_latest_numeric_increased_factor_in_timeframe(
|
|
|
197
229
|
More sophisticated checks (e.g., sustained increase, comparison to earliest value in overall history) might require different logic.
|
|
198
230
|
"""
|
|
199
231
|
patient_lab_values = input_links.patient_lab_values
|
|
200
|
-
if (
|
|
201
|
-
requirement.
|
|
202
|
-
requirement.
|
|
203
|
-
requirement.
|
|
232
|
+
if (
|
|
233
|
+
not requirement.lab_values.exists()
|
|
234
|
+
or requirement.numeric_value is None
|
|
235
|
+
or requirement.numeric_value_min is None
|
|
236
|
+
or requirement.numeric_value_max is None
|
|
237
|
+
):
|
|
204
238
|
return False
|
|
205
239
|
|
|
206
240
|
factor = requirement.numeric_value
|
|
207
|
-
days_min = int(requirement.numeric_value_min)
|
|
208
|
-
days_max = int(requirement.numeric_value_max)
|
|
241
|
+
days_min = int(requirement.numeric_value_min) # Start of timeframe
|
|
242
|
+
days_max = int(requirement.numeric_value_max) # End of timeframe
|
|
209
243
|
|
|
210
244
|
for lab_value_model in requirement.lab_values.all():
|
|
211
245
|
# Get all values for this lab type, not just within the timeframe initially
|
|
212
246
|
all_lab_values_for_type = sorted(
|
|
213
|
-
[
|
|
214
|
-
|
|
247
|
+
[
|
|
248
|
+
plv
|
|
249
|
+
for plv in patient_lab_values
|
|
250
|
+
if plv.lab_value
|
|
251
|
+
and plv.lab_value.name == lab_value_model.name
|
|
252
|
+
and plv.value is not None
|
|
253
|
+
],
|
|
254
|
+
key=lambda plv: plv.datetime,
|
|
215
255
|
)
|
|
216
256
|
|
|
217
257
|
if not all_lab_values_for_type:
|
|
@@ -224,10 +264,11 @@ def lab_latest_numeric_increased_factor_in_timeframe(
|
|
|
224
264
|
if plv.datetime.date() <= start_of_timeframe_date:
|
|
225
265
|
reference_plv = plv
|
|
226
266
|
break
|
|
227
|
-
|
|
228
|
-
if reference_plv is None and all_lab_values_for_type: # if no value before timeframe, use earliest available
|
|
229
|
-
reference_plv = all_lab_values_for_type[0]
|
|
230
267
|
|
|
268
|
+
if (
|
|
269
|
+
reference_plv is None and all_lab_values_for_type
|
|
270
|
+
): # if no value before timeframe, use earliest available
|
|
271
|
+
reference_plv = all_lab_values_for_type[0]
|
|
231
272
|
|
|
232
273
|
if reference_plv and reference_plv.value is not None:
|
|
233
274
|
reference_value = reference_plv.value
|
|
@@ -236,14 +277,17 @@ def lab_latest_numeric_increased_factor_in_timeframe(
|
|
|
236
277
|
patient_lab_values, lab_value_model.name, days_min, days_max
|
|
237
278
|
)
|
|
238
279
|
for plv_in_frame in values_in_timeframe:
|
|
239
|
-
if plv_in_frame.value is not None and plv_in_frame.value > (
|
|
240
|
-
|
|
280
|
+
if plv_in_frame.value is not None and plv_in_frame.value > (
|
|
281
|
+
reference_value * factor
|
|
282
|
+
):
|
|
283
|
+
return True # Found a value increased by the factor
|
|
241
284
|
return False
|
|
242
285
|
|
|
286
|
+
|
|
243
287
|
def lab_latest_numeric_decreased_factor_in_timeframe(
|
|
244
288
|
input_links: "RequirementLinks",
|
|
245
289
|
requirement: Requirement,
|
|
246
|
-
operator_kwargs: Dict[str, Any]
|
|
290
|
+
operator_kwargs: Dict[str, Any],
|
|
247
291
|
) -> bool:
|
|
248
292
|
"""
|
|
249
293
|
Checks if the numeric lab value has decreased by a certain factor within a timeframe.
|
|
@@ -251,10 +295,12 @@ def lab_latest_numeric_decreased_factor_in_timeframe(
|
|
|
251
295
|
Compares values in timeframe to the value at the start of (or just before) the timeframe.
|
|
252
296
|
"""
|
|
253
297
|
patient_lab_values = input_links.patient_lab_values
|
|
254
|
-
if (
|
|
255
|
-
requirement.
|
|
256
|
-
requirement.
|
|
257
|
-
requirement.
|
|
298
|
+
if (
|
|
299
|
+
not requirement.lab_values.exists()
|
|
300
|
+
or requirement.numeric_value is None
|
|
301
|
+
or requirement.numeric_value_min is None
|
|
302
|
+
or requirement.numeric_value_max is None
|
|
303
|
+
):
|
|
258
304
|
return False
|
|
259
305
|
|
|
260
306
|
factor = requirement.numeric_value
|
|
@@ -263,8 +309,14 @@ def lab_latest_numeric_decreased_factor_in_timeframe(
|
|
|
263
309
|
|
|
264
310
|
for lab_value_model in requirement.lab_values.all():
|
|
265
311
|
all_lab_values_for_type = sorted(
|
|
266
|
-
[
|
|
267
|
-
|
|
312
|
+
[
|
|
313
|
+
plv
|
|
314
|
+
for plv in patient_lab_values
|
|
315
|
+
if plv.lab_value
|
|
316
|
+
and plv.lab_value.name == lab_value_model.name
|
|
317
|
+
and plv.value is not None
|
|
318
|
+
],
|
|
319
|
+
key=lambda plv: plv.datetime,
|
|
268
320
|
)
|
|
269
321
|
if not all_lab_values_for_type:
|
|
270
322
|
continue
|
|
@@ -280,29 +332,36 @@ def lab_latest_numeric_decreased_factor_in_timeframe(
|
|
|
280
332
|
|
|
281
333
|
if reference_plv and reference_plv.value is not None:
|
|
282
334
|
reference_value = reference_plv.value
|
|
283
|
-
if
|
|
284
|
-
|
|
335
|
+
if (
|
|
336
|
+
reference_value == 0
|
|
337
|
+
): # Avoid division by zero or issues with zero reference
|
|
338
|
+
continue
|
|
285
339
|
values_in_timeframe = get_patient_lab_values_in_timeframe(
|
|
286
340
|
patient_lab_values, lab_value_model.name, days_min, days_max
|
|
287
341
|
)
|
|
288
342
|
for plv_in_frame in values_in_timeframe:
|
|
289
|
-
if plv_in_frame.value is not None and plv_in_frame.value < (
|
|
343
|
+
if plv_in_frame.value is not None and plv_in_frame.value < (
|
|
344
|
+
reference_value / factor
|
|
345
|
+
): # Decreased by factor
|
|
290
346
|
return True
|
|
291
347
|
return False
|
|
292
348
|
|
|
349
|
+
|
|
293
350
|
def lab_latest_numeric_normal_in_timeframe(
|
|
294
351
|
input_links: "RequirementLinks",
|
|
295
352
|
requirement: Requirement,
|
|
296
|
-
operator_kwargs: Dict[str, Any]
|
|
353
|
+
operator_kwargs: Dict[str, Any],
|
|
297
354
|
) -> bool:
|
|
298
355
|
"""
|
|
299
356
|
Checks if any numeric lab value within a timeframe is within its normal range.
|
|
300
357
|
Timeframe in requirement.numeric_value_min/max.
|
|
301
358
|
"""
|
|
302
359
|
patient_lab_values = input_links.patient_lab_values
|
|
303
|
-
if (
|
|
304
|
-
requirement.
|
|
305
|
-
requirement.
|
|
360
|
+
if (
|
|
361
|
+
not requirement.lab_values.exists()
|
|
362
|
+
or requirement.numeric_value_min is None
|
|
363
|
+
or requirement.numeric_value_max is None
|
|
364
|
+
):
|
|
306
365
|
return False
|
|
307
366
|
|
|
308
367
|
days_min = int(requirement.numeric_value_min)
|
|
@@ -317,7 +376,7 @@ def lab_latest_numeric_normal_in_timeframe(
|
|
|
317
376
|
if plv.value is not None and plv.lab_value:
|
|
318
377
|
normal_range = plv.lab_value.get_normal_range(
|
|
319
378
|
age=patient_context.age() if patient_context else None,
|
|
320
|
-
gender=patient_context.gender if patient_context else None
|
|
379
|
+
gender=patient_context.gender if patient_context else None,
|
|
321
380
|
)
|
|
322
381
|
min_val = normal_range.get("min")
|
|
323
382
|
max_val = normal_range.get("max")
|
|
@@ -326,20 +385,23 @@ def lab_latest_numeric_normal_in_timeframe(
|
|
|
326
385
|
return True
|
|
327
386
|
return False
|
|
328
387
|
|
|
388
|
+
|
|
329
389
|
def lab_latest_numeric_lower_than_value_in_timeframe(
|
|
330
390
|
input_links: "RequirementLinks",
|
|
331
391
|
requirement: Requirement,
|
|
332
|
-
operator_kwargs: Dict[str, Any]
|
|
392
|
+
operator_kwargs: Dict[str, Any],
|
|
333
393
|
) -> bool:
|
|
334
394
|
"""
|
|
335
395
|
Checks if any numeric lab value within a timeframe is lower than requirement.numeric_value.
|
|
336
396
|
Timeframe in requirement.numeric_value_min/max.
|
|
337
397
|
"""
|
|
338
398
|
patient_lab_values = input_links.patient_lab_values
|
|
339
|
-
if (
|
|
340
|
-
requirement.
|
|
341
|
-
requirement.
|
|
342
|
-
requirement.
|
|
399
|
+
if (
|
|
400
|
+
not requirement.lab_values.exists()
|
|
401
|
+
or requirement.numeric_value is None
|
|
402
|
+
or requirement.numeric_value_min is None
|
|
403
|
+
or requirement.numeric_value_max is None
|
|
404
|
+
):
|
|
343
405
|
return False
|
|
344
406
|
|
|
345
407
|
threshold = requirement.numeric_value
|
|
@@ -355,20 +417,23 @@ def lab_latest_numeric_lower_than_value_in_timeframe(
|
|
|
355
417
|
return True
|
|
356
418
|
return False
|
|
357
419
|
|
|
420
|
+
|
|
358
421
|
def lab_latest_numeric_greater_than_value_in_timeframe(
|
|
359
422
|
input_links: "RequirementLinks",
|
|
360
423
|
requirement: Requirement,
|
|
361
|
-
operator_kwargs: Dict[str, Any]
|
|
424
|
+
operator_kwargs: Dict[str, Any],
|
|
362
425
|
) -> bool:
|
|
363
426
|
"""
|
|
364
427
|
Checks if any numeric lab value within a timeframe is greater than requirement.numeric_value.
|
|
365
428
|
Timeframe in requirement.numeric_value_min/max.
|
|
366
429
|
"""
|
|
367
430
|
patient_lab_values = input_links.patient_lab_values
|
|
368
|
-
if (
|
|
369
|
-
requirement.
|
|
370
|
-
requirement.
|
|
371
|
-
requirement.
|
|
431
|
+
if (
|
|
432
|
+
not requirement.lab_values.exists()
|
|
433
|
+
or requirement.numeric_value is None
|
|
434
|
+
or requirement.numeric_value_min is None
|
|
435
|
+
or requirement.numeric_value_max is None
|
|
436
|
+
):
|
|
372
437
|
return False
|
|
373
438
|
|
|
374
439
|
threshold = requirement.numeric_value
|
|
@@ -384,13 +449,15 @@ def lab_latest_numeric_greater_than_value_in_timeframe(
|
|
|
384
449
|
return True
|
|
385
450
|
return False
|
|
386
451
|
|
|
452
|
+
|
|
387
453
|
# --- Categorical Operators ---
|
|
388
454
|
# Assuming PatientLabValue has a 'value_string' attribute for categorical results.
|
|
389
455
|
|
|
456
|
+
|
|
390
457
|
def lab_latest_categorical_match(
|
|
391
458
|
input_links: "RequirementLinks",
|
|
392
459
|
requirement: Requirement,
|
|
393
|
-
operator_kwargs: Dict[str, Any]
|
|
460
|
+
operator_kwargs: Dict[str, Any],
|
|
394
461
|
) -> bool:
|
|
395
462
|
"""
|
|
396
463
|
Checks if the latest categorical lab value matches requirement.string_value.
|
|
@@ -401,17 +468,24 @@ def lab_latest_categorical_match(
|
|
|
401
468
|
|
|
402
469
|
match_string = requirement.string_value
|
|
403
470
|
for lab_value_model in requirement.lab_values.all():
|
|
404
|
-
latest_plv = get_latest_patient_lab_value(
|
|
471
|
+
latest_plv = get_latest_patient_lab_value(
|
|
472
|
+
patient_lab_values, lab_value_model.name
|
|
473
|
+
)
|
|
405
474
|
# Ensure latest_plv has value_str attribute
|
|
406
|
-
if
|
|
475
|
+
if (
|
|
476
|
+
latest_plv
|
|
477
|
+
and hasattr(latest_plv, "value_str")
|
|
478
|
+
and latest_plv.value_str is not None
|
|
479
|
+
): # Changed value_string to value_str
|
|
407
480
|
if latest_plv.value_str == match_string:
|
|
408
481
|
return True
|
|
409
482
|
return False
|
|
410
483
|
|
|
484
|
+
|
|
411
485
|
def lab_latest_categorical_match_substring(
|
|
412
486
|
input_links: "RequirementLinks",
|
|
413
487
|
requirement: Requirement,
|
|
414
|
-
operator_kwargs: Dict[str, Any]
|
|
488
|
+
operator_kwargs: Dict[str, Any],
|
|
415
489
|
) -> bool:
|
|
416
490
|
"""
|
|
417
491
|
Checks if requirement.string_value is a substring of the latest categorical lab value.
|
|
@@ -422,16 +496,23 @@ def lab_latest_categorical_match_substring(
|
|
|
422
496
|
|
|
423
497
|
substring = requirement.string_value
|
|
424
498
|
for lab_value_model in requirement.lab_values.all():
|
|
425
|
-
latest_plv = get_latest_patient_lab_value(
|
|
426
|
-
|
|
499
|
+
latest_plv = get_latest_patient_lab_value(
|
|
500
|
+
patient_lab_values, lab_value_model.name
|
|
501
|
+
)
|
|
502
|
+
if (
|
|
503
|
+
latest_plv
|
|
504
|
+
and hasattr(latest_plv, "value_str")
|
|
505
|
+
and latest_plv.value_str is not None
|
|
506
|
+
): # Changed value_string to value_str
|
|
427
507
|
if substring in latest_plv.value_str:
|
|
428
508
|
return True
|
|
429
509
|
return False
|
|
430
510
|
|
|
511
|
+
|
|
431
512
|
def lab_latest_categorical_match_regex(
|
|
432
513
|
input_links: "RequirementLinks",
|
|
433
514
|
requirement: Requirement,
|
|
434
|
-
operator_kwargs: Dict[str, Any]
|
|
515
|
+
operator_kwargs: Dict[str, Any],
|
|
435
516
|
) -> bool:
|
|
436
517
|
"""
|
|
437
518
|
Checks if the latest categorical lab value matches regex in requirement.string_value.
|
|
@@ -444,31 +525,41 @@ def lab_latest_categorical_match_regex(
|
|
|
444
525
|
try:
|
|
445
526
|
compiled_regex = re.compile(regex_pattern)
|
|
446
527
|
except re.error:
|
|
447
|
-
return False
|
|
528
|
+
return False # Invalid regex
|
|
448
529
|
|
|
449
530
|
for lab_value_model in requirement.lab_values.all():
|
|
450
|
-
latest_plv = get_latest_patient_lab_value(
|
|
451
|
-
|
|
531
|
+
latest_plv = get_latest_patient_lab_value(
|
|
532
|
+
patient_lab_values, lab_value_model.name
|
|
533
|
+
)
|
|
534
|
+
if (
|
|
535
|
+
latest_plv
|
|
536
|
+
and hasattr(latest_plv, "value_str")
|
|
537
|
+
and latest_plv.value_str is not None
|
|
538
|
+
): # Changed value_string to value_str
|
|
452
539
|
if compiled_regex.search(latest_plv.value_str):
|
|
453
540
|
return True
|
|
454
541
|
return False
|
|
455
542
|
|
|
543
|
+
|
|
456
544
|
# --- Categorical Operators with Timeframe ---
|
|
457
545
|
|
|
546
|
+
|
|
458
547
|
def lab_latest_categorical_match_in_timeframe(
|
|
459
548
|
input_links: "RequirementLinks",
|
|
460
549
|
requirement: Requirement,
|
|
461
|
-
operator_kwargs: Dict[str, Any]
|
|
550
|
+
operator_kwargs: Dict[str, Any],
|
|
462
551
|
) -> bool:
|
|
463
552
|
"""
|
|
464
553
|
Checks if any categorical lab value in timeframe matches requirement.string_value.
|
|
465
554
|
Timeframe in requirement.numeric_value_min/max.
|
|
466
555
|
"""
|
|
467
556
|
patient_lab_values = input_links.patient_lab_values
|
|
468
|
-
if (
|
|
469
|
-
requirement.
|
|
470
|
-
requirement.
|
|
471
|
-
requirement.
|
|
557
|
+
if (
|
|
558
|
+
not requirement.lab_values.exists()
|
|
559
|
+
or requirement.string_value is None
|
|
560
|
+
or requirement.numeric_value_min is None
|
|
561
|
+
or requirement.numeric_value_max is None
|
|
562
|
+
):
|
|
472
563
|
return False
|
|
473
564
|
|
|
474
565
|
match_string = requirement.string_value
|
|
@@ -480,25 +571,30 @@ def lab_latest_categorical_match_in_timeframe(
|
|
|
480
571
|
patient_lab_values, lab_value_model.name, days_min, days_max
|
|
481
572
|
)
|
|
482
573
|
for plv in values_in_timeframe:
|
|
483
|
-
if
|
|
574
|
+
if (
|
|
575
|
+
hasattr(plv, "value_str") and plv.value_str is not None
|
|
576
|
+
): # Changed value_string to value_str
|
|
484
577
|
if plv.value_str == match_string:
|
|
485
578
|
return True
|
|
486
579
|
return False
|
|
487
580
|
|
|
581
|
+
|
|
488
582
|
def lab_latest_categorical_match_substring_in_timeframe(
|
|
489
583
|
input_links: "RequirementLinks",
|
|
490
584
|
requirement: Requirement,
|
|
491
|
-
operator_kwargs: Dict[str, Any]
|
|
585
|
+
operator_kwargs: Dict[str, Any],
|
|
492
586
|
) -> bool:
|
|
493
587
|
"""
|
|
494
588
|
Checks if requirement.string_value is substring of any categorical lab value in timeframe.
|
|
495
589
|
Timeframe in requirement.numeric_value_min/max.
|
|
496
590
|
"""
|
|
497
591
|
patient_lab_values = input_links.patient_lab_values
|
|
498
|
-
if (
|
|
499
|
-
requirement.
|
|
500
|
-
requirement.
|
|
501
|
-
requirement.
|
|
592
|
+
if (
|
|
593
|
+
not requirement.lab_values.exists()
|
|
594
|
+
or requirement.string_value is None
|
|
595
|
+
or requirement.numeric_value_min is None
|
|
596
|
+
or requirement.numeric_value_max is None
|
|
597
|
+
):
|
|
502
598
|
return False
|
|
503
599
|
|
|
504
600
|
substring = requirement.string_value
|
|
@@ -510,25 +606,30 @@ def lab_latest_categorical_match_substring_in_timeframe(
|
|
|
510
606
|
patient_lab_values, lab_value_model.name, days_min, days_max
|
|
511
607
|
)
|
|
512
608
|
for plv in values_in_timeframe:
|
|
513
|
-
if
|
|
609
|
+
if (
|
|
610
|
+
hasattr(plv, "value_str") and plv.value_str is not None
|
|
611
|
+
): # Changed value_string to value_str
|
|
514
612
|
if substring in plv.value_str:
|
|
515
613
|
return True
|
|
516
614
|
return False
|
|
517
615
|
|
|
616
|
+
|
|
518
617
|
def lab_latest_categorical_match_regex_in_timeframe(
|
|
519
618
|
input_links: "RequirementLinks",
|
|
520
619
|
requirement: Requirement,
|
|
521
|
-
operator_kwargs: Dict[str, Any]
|
|
620
|
+
operator_kwargs: Dict[str, Any],
|
|
522
621
|
) -> bool:
|
|
523
622
|
"""
|
|
524
623
|
Checks if any categorical lab value in timeframe matches regex in requirement.string_value.
|
|
525
624
|
Timeframe in requirement.numeric_value_min/max.
|
|
526
625
|
"""
|
|
527
626
|
patient_lab_values = input_links.patient_lab_values
|
|
528
|
-
if (
|
|
529
|
-
requirement.
|
|
530
|
-
requirement.
|
|
531
|
-
requirement.
|
|
627
|
+
if (
|
|
628
|
+
not requirement.lab_values.exists()
|
|
629
|
+
or requirement.string_value is None
|
|
630
|
+
or requirement.numeric_value_min is None
|
|
631
|
+
or requirement.numeric_value_max is None
|
|
632
|
+
):
|
|
532
633
|
return False
|
|
533
634
|
|
|
534
635
|
regex_pattern = requirement.string_value
|
|
@@ -545,7 +646,9 @@ def lab_latest_categorical_match_regex_in_timeframe(
|
|
|
545
646
|
patient_lab_values, lab_value_model.name, days_min, days_max
|
|
546
647
|
)
|
|
547
648
|
for plv in values_in_timeframe:
|
|
548
|
-
if
|
|
649
|
+
if (
|
|
650
|
+
hasattr(plv, "value_str") and plv.value_str is not None
|
|
651
|
+
): # Changed value_string to value_str
|
|
549
652
|
if compiled_regex.search(plv.value_str):
|
|
550
653
|
return True
|
|
551
654
|
return False
|
|
@@ -558,17 +661,14 @@ LAB_VALUE_OPERATOR_FUNCTIONS: Dict[str, Callable] = {
|
|
|
558
661
|
"lab_latest_numeric_normal": lab_latest_numeric_normal,
|
|
559
662
|
"lab_latest_numeric_lower_than_value": lab_latest_numeric_lower_than_value,
|
|
560
663
|
"lab_latest_numeric_greater_than_value": lab_latest_numeric_greater_than_value,
|
|
561
|
-
|
|
562
664
|
# Aliases for backward compatibility, pointing to timeframe versions
|
|
563
665
|
"lab_latest_numeric_increased_factor": lab_latest_numeric_increased_factor_in_timeframe,
|
|
564
666
|
"lab_latest_numeric_decreased_factor": lab_latest_numeric_decreased_factor_in_timeframe,
|
|
565
|
-
|
|
566
667
|
"lab_latest_numeric_increased_factor_in_timeframe": lab_latest_numeric_increased_factor_in_timeframe,
|
|
567
668
|
"lab_latest_numeric_decreased_factor_in_timeframe": lab_latest_numeric_decreased_factor_in_timeframe,
|
|
568
669
|
"lab_latest_numeric_normal_in_timeframe": lab_latest_numeric_normal_in_timeframe,
|
|
569
670
|
"lab_latest_numeric_lower_than_value_in_timeframe": lab_latest_numeric_lower_than_value_in_timeframe,
|
|
570
671
|
"lab_latest_numeric_greater_than_value_in_timeframe": lab_latest_numeric_greater_than_value_in_timeframe,
|
|
571
|
-
|
|
572
672
|
"lab_latest_categorical_match": lab_latest_categorical_match,
|
|
573
673
|
"lab_latest_categorical_match_substring": lab_latest_categorical_match_substring,
|
|
574
674
|
"lab_latest_categorical_match_regex": lab_latest_categorical_match_regex,
|