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.

Files changed (503) hide show
  1. endoreg_db/authz/auth.py +74 -0
  2. endoreg_db/authz/backends.py +168 -0
  3. endoreg_db/authz/management/commands/list_routes.py +18 -0
  4. endoreg_db/authz/middleware.py +83 -0
  5. endoreg_db/authz/permissions.py +127 -0
  6. endoreg_db/authz/policy.py +218 -0
  7. endoreg_db/authz/views_auth.py +66 -0
  8. endoreg_db/config/env.py +13 -8
  9. endoreg_db/data/__init__.py +2 -11
  10. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
  11. endoreg_db/data/event_classification/data.yaml +4 -0
  12. endoreg_db/data/event_classification_choice/data.yaml +9 -0
  13. endoreg_db/data/examination/examinations/data.yaml +114 -14
  14. endoreg_db/data/examination/time-type/data.yaml +0 -3
  15. endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
  16. endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
  17. endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
  18. endoreg_db/data/finding/00_generic.yaml +35 -0
  19. endoreg_db/data/finding/00_generic_complication.yaml +9 -0
  20. endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
  21. endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
  22. endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
  23. endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
  24. endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
  25. endoreg_db/data/finding_classification/00_generic.yaml +44 -0
  26. endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
  27. endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
  28. endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
  29. endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
  30. endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
  31. endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
  32. endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
  33. endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
  34. endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
  35. endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
  36. endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
  37. endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
  38. endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
  39. endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
  40. endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
  41. endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
  42. endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
  43. endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
  44. endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
  45. endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
  46. endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
  47. endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
  48. endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
  49. endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
  50. endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
  51. endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
  52. endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
  53. endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
  54. endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
  55. endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
  56. endoreg_db/data/finding_type/data.yaml +8 -12
  57. endoreg_db/data/requirement/01_patient_data.yaml +93 -0
  58. endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
  59. endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
  60. endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
  61. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
  62. endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
  63. endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
  64. endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
  65. endoreg_db/data/requirement_set/_old_ +109 -0
  66. endoreg_db/data/requirement_set_type/data.yaml +21 -0
  67. endoreg_db/data/setup_config.yaml +4 -4
  68. endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
  69. endoreg_db/exceptions.py +4 -2
  70. endoreg_db/forms/examination_form.py +1 -1
  71. endoreg_db/helpers/data_loader.py +125 -53
  72. endoreg_db/helpers/default_objects.py +116 -81
  73. endoreg_db/import_files/__init__.py +27 -0
  74. endoreg_db/import_files/context/__init__.py +7 -0
  75. endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
  76. endoreg_db/import_files/context/ensure_center.py +17 -0
  77. endoreg_db/import_files/context/file_lock.py +66 -0
  78. endoreg_db/import_files/context/import_context.py +43 -0
  79. endoreg_db/import_files/context/validate_directories.py +56 -0
  80. endoreg_db/import_files/file_storage/__init__.py +15 -0
  81. endoreg_db/import_files/file_storage/create_report_file.py +76 -0
  82. endoreg_db/import_files/file_storage/create_video_file.py +75 -0
  83. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
  84. endoreg_db/import_files/file_storage/state_management.py +400 -0
  85. endoreg_db/import_files/file_storage/storage.py +36 -0
  86. endoreg_db/import_files/import_service.md +26 -0
  87. endoreg_db/import_files/processing/__init__.py +11 -0
  88. endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
  89. endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
  90. endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
  91. endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
  92. endoreg_db/import_files/pseudonymization/fake.py +52 -0
  93. endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
  94. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
  95. endoreg_db/import_files/report_import_service.py +141 -0
  96. endoreg_db/import_files/video_import_service.py +150 -0
  97. endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
  98. endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
  99. endoreg_db/management/commands/import_report.py +130 -65
  100. endoreg_db/management/commands/import_video.py +9 -10
  101. endoreg_db/management/commands/import_video_with_classification.py +2 -2
  102. endoreg_db/management/commands/list_routes.py +18 -0
  103. endoreg_db/management/commands/load_ai_model_data.py +5 -5
  104. endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
  105. endoreg_db/management/commands/load_base_db_data.py +5 -134
  106. endoreg_db/management/commands/load_center_data.py +12 -12
  107. endoreg_db/management/commands/load_contraindication_data.py +14 -16
  108. endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
  109. endoreg_db/management/commands/load_disease_classification_data.py +15 -18
  110. endoreg_db/management/commands/load_disease_data.py +25 -28
  111. endoreg_db/management/commands/load_endoscope_data.py +20 -27
  112. endoreg_db/management/commands/load_event_data.py +14 -16
  113. endoreg_db/management/commands/load_examination_data.py +31 -44
  114. endoreg_db/management/commands/load_examination_indication_data.py +20 -21
  115. endoreg_db/management/commands/load_finding_data.py +52 -80
  116. endoreg_db/management/commands/load_information_source.py +21 -23
  117. endoreg_db/management/commands/load_lab_value_data.py +17 -26
  118. endoreg_db/management/commands/load_medication_data.py +13 -12
  119. endoreg_db/management/commands/load_organ_data.py +15 -19
  120. endoreg_db/management/commands/load_pdf_type_data.py +19 -18
  121. endoreg_db/management/commands/load_profession_data.py +14 -17
  122. endoreg_db/management/commands/load_qualification_data.py +20 -23
  123. endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
  124. endoreg_db/management/commands/load_requirement_data.py +62 -39
  125. endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
  126. endoreg_db/management/commands/load_risk_data.py +7 -6
  127. endoreg_db/management/commands/load_shift_data.py +20 -23
  128. endoreg_db/management/commands/load_tag_data.py +8 -11
  129. endoreg_db/management/commands/load_unit_data.py +17 -19
  130. endoreg_db/management/commands/setup_endoreg_db.py +3 -3
  131. endoreg_db/management/commands/start_filewatcher.py +46 -37
  132. endoreg_db/management/commands/storage_management.py +271 -203
  133. endoreg_db/management/commands/validate_video_files.py +1 -5
  134. endoreg_db/migrations/0001_initial.py +297 -250
  135. endoreg_db/models/__init__.py +78 -123
  136. endoreg_db/models/administration/__init__.py +21 -42
  137. endoreg_db/models/administration/ai/active_model.py +2 -2
  138. endoreg_db/models/administration/ai/ai_model.py +7 -6
  139. endoreg_db/models/administration/case/__init__.py +1 -15
  140. endoreg_db/models/administration/case/case.py +3 -3
  141. endoreg_db/models/administration/case/case_template/__init__.py +2 -14
  142. endoreg_db/models/administration/case/case_template/case_template.py +2 -124
  143. endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
  144. endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
  145. endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
  146. endoreg_db/models/administration/center/center.py +33 -19
  147. endoreg_db/models/administration/center/center_product.py +12 -9
  148. endoreg_db/models/administration/center/center_resource.py +25 -19
  149. endoreg_db/models/administration/center/center_shift.py +21 -17
  150. endoreg_db/models/administration/center/center_waste.py +16 -8
  151. endoreg_db/models/administration/person/__init__.py +2 -0
  152. endoreg_db/models/administration/person/employee/employee.py +10 -5
  153. endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
  154. endoreg_db/models/administration/person/employee/employee_type.py +12 -6
  155. endoreg_db/models/administration/person/examiner/examiner.py +13 -11
  156. endoreg_db/models/administration/person/patient/__init__.py +2 -0
  157. endoreg_db/models/administration/person/patient/patient.py +129 -100
  158. endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
  159. endoreg_db/models/administration/person/person.py +4 -0
  160. endoreg_db/models/administration/person/profession/__init__.py +8 -4
  161. endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
  162. endoreg_db/models/administration/product/product.py +20 -15
  163. endoreg_db/models/administration/product/product_material.py +17 -18
  164. endoreg_db/models/administration/product/product_weight.py +12 -8
  165. endoreg_db/models/administration/product/reference_product.py +23 -55
  166. endoreg_db/models/administration/qualification/qualification.py +7 -3
  167. endoreg_db/models/administration/qualification/qualification_type.py +7 -3
  168. endoreg_db/models/administration/shift/scheduled_days.py +8 -5
  169. endoreg_db/models/administration/shift/shift.py +16 -12
  170. endoreg_db/models/administration/shift/shift_type.py +23 -31
  171. endoreg_db/models/label/__init__.py +8 -9
  172. endoreg_db/models/label/annotation/image_classification.py +10 -9
  173. endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
  174. endoreg_db/models/label/label.py +15 -15
  175. endoreg_db/models/label/label_set.py +19 -6
  176. endoreg_db/models/label/label_type.py +1 -1
  177. endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
  178. endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
  179. endoreg_db/models/label/video_segmentation_label.py +4 -0
  180. endoreg_db/models/label/video_segmentation_labelset.py +4 -3
  181. endoreg_db/models/media/frame/frame.py +22 -22
  182. endoreg_db/models/media/pdf/raw_pdf.py +194 -194
  183. endoreg_db/models/media/pdf/report_file.py +25 -29
  184. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
  185. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
  186. endoreg_db/models/media/processing_history/__init__.py +5 -0
  187. endoreg_db/models/media/processing_history/processing_history.py +96 -0
  188. endoreg_db/models/media/video/__init__.py +1 -0
  189. endoreg_db/models/media/video/create_from_file.py +139 -77
  190. endoreg_db/models/media/video/pipe_2.py +8 -9
  191. endoreg_db/models/media/video/video_file.py +174 -112
  192. endoreg_db/models/media/video/video_file_ai.py +288 -74
  193. endoreg_db/models/media/video/video_file_anonymize.py +38 -38
  194. endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
  195. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
  196. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
  197. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
  198. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
  199. endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
  200. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
  201. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
  202. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
  203. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
  204. endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
  205. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
  206. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
  207. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
  208. endoreg_db/models/media/video/video_file_io.py +113 -61
  209. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
  210. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
  211. endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
  212. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
  213. endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
  214. endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
  215. endoreg_db/models/media/video/video_file_segments.py +24 -17
  216. endoreg_db/models/media/video/video_metadata.py +19 -35
  217. endoreg_db/models/media/video/video_processing.py +96 -95
  218. endoreg_db/models/medical/contraindication/README.md +1 -0
  219. endoreg_db/models/medical/contraindication/__init__.py +13 -3
  220. endoreg_db/models/medical/disease.py +22 -16
  221. endoreg_db/models/medical/event.py +31 -18
  222. endoreg_db/models/medical/examination/__init__.py +13 -6
  223. endoreg_db/models/medical/examination/examination.py +39 -20
  224. endoreg_db/models/medical/examination/examination_indication.py +30 -95
  225. endoreg_db/models/medical/examination/examination_time.py +23 -8
  226. endoreg_db/models/medical/examination/examination_time_type.py +9 -6
  227. endoreg_db/models/medical/examination/examination_type.py +3 -4
  228. endoreg_db/models/medical/finding/finding.py +32 -40
  229. endoreg_db/models/medical/finding/finding_classification.py +42 -72
  230. endoreg_db/models/medical/finding/finding_intervention.py +25 -22
  231. endoreg_db/models/medical/finding/finding_type.py +13 -12
  232. endoreg_db/models/medical/hardware/endoscope.py +26 -26
  233. endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
  234. endoreg_db/models/medical/laboratory/lab_value.py +62 -91
  235. endoreg_db/models/medical/medication/medication.py +22 -10
  236. endoreg_db/models/medical/medication/medication_indication.py +29 -3
  237. endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
  238. endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
  239. endoreg_db/models/medical/medication/medication_schedule.py +27 -16
  240. endoreg_db/models/medical/organ/__init__.py +15 -12
  241. endoreg_db/models/medical/patient/medication_examples.py +6 -6
  242. endoreg_db/models/medical/patient/patient_disease.py +20 -23
  243. endoreg_db/models/medical/patient/patient_event.py +19 -22
  244. endoreg_db/models/medical/patient/patient_examination.py +48 -54
  245. endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
  246. endoreg_db/models/medical/patient/patient_finding.py +122 -139
  247. endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
  248. endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
  249. endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
  250. endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
  251. endoreg_db/models/medical/patient/patient_medication.py +27 -38
  252. endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
  253. endoreg_db/models/medical/risk/risk.py +7 -6
  254. endoreg_db/models/medical/risk/risk_type.py +8 -5
  255. endoreg_db/models/metadata/model_meta.py +60 -29
  256. endoreg_db/models/metadata/model_meta_logic.py +125 -18
  257. endoreg_db/models/metadata/pdf_meta.py +31 -24
  258. endoreg_db/models/metadata/sensitive_meta.py +105 -85
  259. endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
  260. endoreg_db/models/metadata/video_meta.py +51 -31
  261. endoreg_db/models/metadata/video_prediction_logic.py +16 -23
  262. endoreg_db/models/metadata/video_prediction_meta.py +29 -33
  263. endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
  264. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
  265. endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
  266. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
  267. endoreg_db/models/other/emission/emission_factor.py +18 -8
  268. endoreg_db/models/other/gender.py +10 -5
  269. endoreg_db/models/other/information_source.py +50 -29
  270. endoreg_db/models/other/material.py +9 -5
  271. endoreg_db/models/other/resource.py +6 -4
  272. endoreg_db/models/other/tag.py +10 -5
  273. endoreg_db/models/other/transport_route.py +13 -8
  274. endoreg_db/models/other/unit.py +10 -6
  275. endoreg_db/models/other/waste.py +6 -5
  276. endoreg_db/models/report/report.py +6 -0
  277. endoreg_db/models/requirement/requirement.py +329 -361
  278. endoreg_db/models/requirement/requirement_error.py +85 -0
  279. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
  280. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
  281. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
  282. endoreg_db/models/requirement/requirement_operator.py +103 -112
  283. endoreg_db/models/requirement/requirement_set.py +74 -57
  284. endoreg_db/models/state/__init__.py +4 -4
  285. endoreg_db/models/state/abstract.py +2 -2
  286. endoreg_db/models/state/anonymization.py +12 -0
  287. endoreg_db/models/state/audit_ledger.py +49 -51
  288. endoreg_db/models/state/label_video_segment.py +9 -0
  289. endoreg_db/models/state/raw_pdf.py +101 -68
  290. endoreg_db/models/state/sensitive_meta.py +6 -2
  291. endoreg_db/models/state/video.py +110 -90
  292. endoreg_db/models/upload_job.py +35 -34
  293. endoreg_db/models/utils.py +28 -25
  294. endoreg_db/queries/__init__.py +3 -1
  295. endoreg_db/root_urls.py +21 -2
  296. endoreg_db/schemas/examination_evaluation.py +1 -1
  297. endoreg_db/serializers/__init__.py +2 -10
  298. endoreg_db/serializers/anonymization.py +18 -10
  299. endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
  300. endoreg_db/serializers/meta/__init__.py +1 -6
  301. endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
  302. endoreg_db/serializers/misc/file_overview.py +11 -99
  303. endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
  304. endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
  305. endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
  306. endoreg_db/serializers/requirements/requirement_sets.py +92 -22
  307. endoreg_db/serializers/video/segmentation.py +2 -1
  308. endoreg_db/serializers/video/video_file_list.py +65 -34
  309. endoreg_db/serializers/video/video_processing_history.py +20 -5
  310. endoreg_db/services/__old/pdf_import.py +1487 -0
  311. endoreg_db/services/__old/video_import.py +1306 -0
  312. endoreg_db/services/anonymization.py +128 -89
  313. endoreg_db/services/lookup_service.py +65 -52
  314. endoreg_db/services/lookup_store.py +2 -2
  315. endoreg_db/services/pdf_import.py +0 -1382
  316. endoreg_db/services/report_import.py +10 -0
  317. endoreg_db/services/video_import.py +6 -1255
  318. endoreg_db/tasks/upload_tasks.py +79 -70
  319. endoreg_db/tasks/video_ingest.py +8 -4
  320. endoreg_db/urls/__init__.py +5 -32
  321. endoreg_db/urls/ai.py +32 -0
  322. endoreg_db/urls/media.py +121 -83
  323. endoreg_db/urls/root_urls.py +29 -0
  324. endoreg_db/utils/__init__.py +15 -5
  325. endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
  326. endoreg_db/utils/case_generator/__init__.py +3 -0
  327. endoreg_db/utils/dataloader.py +142 -40
  328. endoreg_db/utils/defaults/set_default_center.py +32 -0
  329. endoreg_db/utils/names.py +22 -16
  330. endoreg_db/utils/paths.py +110 -46
  331. endoreg_db/utils/permissions.py +2 -1
  332. endoreg_db/utils/pipelines/Readme.md +1 -1
  333. endoreg_db/utils/pipelines/process_video_dir.py +1 -1
  334. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
  335. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
  336. endoreg_db/utils/setup_config.py +8 -5
  337. endoreg_db/utils/storage.py +115 -0
  338. endoreg_db/utils/validate_endo_roi.py +8 -2
  339. endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
  340. endoreg_db/views/__init__.py +85 -183
  341. endoreg_db/views/ai/__init__.py +8 -0
  342. endoreg_db/views/ai/label.py +155 -0
  343. endoreg_db/views/anonymization/media_management.py +202 -166
  344. endoreg_db/views/anonymization/overview.py +99 -67
  345. endoreg_db/views/anonymization/validate.py +182 -44
  346. endoreg_db/views/media/__init__.py +7 -20
  347. endoreg_db/views/media/pdf_media.py +197 -174
  348. endoreg_db/views/media/sensitive_metadata.py +193 -138
  349. endoreg_db/views/media/video_media.py +89 -82
  350. endoreg_db/views/meta/__init__.py +0 -8
  351. endoreg_db/views/misc/__init__.py +1 -7
  352. endoreg_db/views/misc/upload_views.py +94 -93
  353. endoreg_db/views/patient/patient.py +5 -4
  354. endoreg_db/views/report/__init__.py +5 -7
  355. endoreg_db/views/{pdf → report}/reimport.py +22 -22
  356. endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
  357. endoreg_db/views/requirement/evaluate.py +188 -187
  358. endoreg_db/views/requirement/lookup.py +17 -3
  359. endoreg_db/views/requirement/lookup_store.py +22 -90
  360. endoreg_db/views/requirement/requirement_utils.py +89 -0
  361. endoreg_db/views/video/__init__.py +23 -24
  362. endoreg_db/views/video/correction.py +201 -172
  363. endoreg_db/views/video/reimport.py +1 -1
  364. endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
  365. endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
  366. endoreg_db/views/video/video_stream.py +7 -8
  367. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
  368. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
  369. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
  370. endoreg_db/data/finding/anatomy_colon.yaml +0 -128
  371. endoreg_db/data/finding/colonoscopy.yaml +0 -40
  372. endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
  373. endoreg_db/data/finding/complication.yaml +0 -16
  374. endoreg_db/data/finding/data.yaml +0 -105
  375. endoreg_db/data/finding/examination_setting.yaml +0 -16
  376. endoreg_db/data/finding/medication_related.yaml +0 -18
  377. endoreg_db/data/finding/outcome.yaml +0 -12
  378. endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
  379. endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
  380. endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
  381. endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  382. endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  383. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
  384. endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  385. endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
  386. endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
  387. endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
  388. endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
  389. endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
  390. endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
  391. endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
  392. endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
  393. endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
  394. endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
  395. endoreg_db/data/finding_classification/medication_related.yaml +0 -23
  396. endoreg_db/data/finding_classification/visualized.yaml +0 -33
  397. endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  398. endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  399. endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  400. endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  401. endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  402. endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  403. endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  404. endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  405. endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
  406. endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  407. endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
  408. endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
  409. endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  410. endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
  411. endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
  412. endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  413. endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  414. endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
  415. endoreg_db/data/requirement/age.yaml +0 -26
  416. endoreg_db/data/requirement/gender.yaml +0 -25
  417. endoreg_db/management/commands/init_default_ai_model.py +0 -112
  418. endoreg_db/management/commands/reset_celery_schedule.py +0 -9
  419. endoreg_db/management/commands/validate_video.py +0 -204
  420. endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
  421. endoreg_db/migrations/0003_add_center_display_name.py +0 -30
  422. endoreg_db/models/administration/permissions/__init__.py +0 -44
  423. endoreg_db/models/rule/__init__.py +0 -13
  424. endoreg_db/models/rule/rule.py +0 -27
  425. endoreg_db/models/rule/rule_applicator.py +0 -224
  426. endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
  427. endoreg_db/models/rule/rule_type.py +0 -20
  428. endoreg_db/models/rule/ruleset.py +0 -17
  429. endoreg_db/renames.yml +0 -8
  430. endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
  431. endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
  432. endoreg_db/serializers/_old/video.py +0 -71
  433. endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
  434. endoreg_db/serializers/meta/report_meta.py +0 -53
  435. endoreg_db/serializers/report/__init__.py +0 -9
  436. endoreg_db/serializers/report/mixins.py +0 -45
  437. endoreg_db/serializers/report/report.py +0 -105
  438. endoreg_db/serializers/report/report_list.py +0 -22
  439. endoreg_db/serializers/report/secure_file_url.py +0 -26
  440. endoreg_db/serializers/video/video_metadata.py +0 -105
  441. endoreg_db/services/requirements_object.py +0 -147
  442. endoreg_db/services/storage_aware_video_processor.py +0 -344
  443. endoreg_db/urls/files.py +0 -6
  444. endoreg_db/urls/label_video_segment_validate.py +0 -33
  445. endoreg_db/urls/label_video_segments.py +0 -46
  446. endoreg_db/urls/report.py +0 -48
  447. endoreg_db/urls/video.py +0 -61
  448. endoreg_db/utils/case_generator/case_generator.py +0 -159
  449. endoreg_db/utils/case_generator/utils.py +0 -30
  450. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
  451. endoreg_db/views/label/__init__.py +0 -5
  452. endoreg_db/views/label/label.py +0 -15
  453. endoreg_db/views/label_video_segment/__init__.py +0 -16
  454. endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
  455. endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
  456. endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
  457. endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
  458. endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
  459. endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
  460. endoreg_db/views/label_video_segment/validate.py +0 -226
  461. endoreg_db/views/media/segments.py +0 -71
  462. endoreg_db/views/meta/available_files_list.py +0 -146
  463. endoreg_db/views/meta/report_meta.py +0 -53
  464. endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
  465. endoreg_db/views/misc/secure_file_serving_view.py +0 -80
  466. endoreg_db/views/misc/secure_file_url_view.py +0 -84
  467. endoreg_db/views/misc/secure_url_validate.py +0 -79
  468. endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
  469. endoreg_db/views/patient_finding_location/__init__.py +0 -5
  470. endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
  471. endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
  472. endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
  473. endoreg_db/views/pdf/__init__.py +0 -8
  474. endoreg_db/views/report/report_list.py +0 -112
  475. endoreg_db/views/report/report_with_secure_url.py +0 -28
  476. endoreg_db/views/report/start_examination.py +0 -7
  477. endoreg_db/views/video/segmentation.py +0 -274
  478. endoreg_db/views/video/task_status.py +0 -49
  479. endoreg_db/views/video/timeline.py +0 -46
  480. endoreg_db/views/video/video_analyze.py +0 -52
  481. endoreg_db/views.py +0 -0
  482. /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
  483. /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
  484. /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
  485. /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
  486. /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
  487. /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
  488. /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
  489. /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
  490. /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
  491. /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
  492. /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
  493. /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
  494. /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
  495. /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
  496. /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
  497. /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
  498. /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
  499. /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
  500. /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
  501. /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
  502. /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
  503. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/licenses/LICENSE +0 -0
@@ -1,24 +1,89 @@
1
+ from logging import getLogger # Added logger
2
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Union
3
+
1
4
  from django.db import models
2
- from typing import TYPE_CHECKING, List
3
- from logging import getLogger # Added logger
5
+ from pydantic import BaseModel
6
+
7
+ from endoreg_db.utils.requirement_operator_logic.new_operator_logic import REQUIREMENT_OPERATORS, model_attribute_set_any
4
8
 
5
9
  # see how operator evaluation function is fetched, add to docs #TODO
6
10
  # endoreg_db/utils/requirement_operator_logic/model_evaluators.py
7
11
 
8
12
  if TYPE_CHECKING:
9
13
  from endoreg_db.utils.links.requirement_link import RequirementLinks
10
- from .requirement import Requirement # Added Requirement import for type hint
11
14
 
12
- logger = getLogger(__name__) # Added logger instance
15
+ from .requirement import Requirement # Added Requirement import for type hint
16
+
17
+ logger = getLogger(__name__) # Added logger instance
18
+
19
+
20
+ class OperatorInstructions(BaseModel):
21
+ input_targets: List[str] = []
22
+ requirement_targets: List[str] = []
23
+ kwargs: Dict[str, Union[str, int, float, bool]] = {}
24
+ args: List[Union[str, int, float, bool]] = []
25
+
26
+
27
+ def _parse_operator_instructions(raw: str):
28
+ target_attributes_list = [_.strip() for _ in raw.split(";") if _.strip()]
29
+
30
+ input_targets = []
31
+ kwargs: Dict[str, Union[str, int, float, bool]] = {}
32
+ args: List[Union[str, int, float, bool]] = []
33
+
34
+ valid_prefixes = [
35
+ "!", # Requirement target
36
+ "?", # Input target
37
+ "$", # Keyword argument, keyword and value separated by ":"
38
+ "@", # Positional argument
39
+ ]
40
+
41
+ for entry in target_attributes_list:
42
+ _prefix = entry[0]
43
+
44
+ if _prefix in valid_prefixes:
45
+ _attribute = entry[1:].strip()
46
+ if _prefix == "!":
47
+ # Requirement target
48
+ input_targets.append(_attribute)
49
+ elif _prefix == "?":
50
+ # Input target
51
+ input_targets.append(_attribute)
52
+ elif _prefix == "$":
53
+ # Keyword argument
54
+ if ":" in _attribute:
55
+ key, value = _attribute.split(":", 1)
56
+ kwargs[key.strip()] = value.strip()
57
+ else:
58
+ raise ValueError(f"Invalid keyword argument format in target_attributes: '{entry}'. Expected format is '$key:value'.")
59
+ elif _prefix == "@":
60
+ # Positional argument
61
+ args.append(_attribute)
62
+ else:
63
+ raise ValueError(f"Invalid prefix '{_prefix}' in target_attributes entry: '{entry}'. Valid prefixes are {valid_prefixes}.")
64
+ return OperatorInstructions(
65
+ input_targets=input_targets,
66
+ requirement_targets=input_targets,
67
+ kwargs=kwargs,
68
+ args=args,
69
+ )
70
+
71
+
72
+ def _validate_operator_instructions(instance: "Requirement") -> bool:
73
+ """Ensures requirement fixtures declare at least one target attribute."""
74
+ if not instance.operator_instructions_parsed:
75
+ raise ValueError(f"Requirement '{instance.name}' must declare at least one target attribute.")
76
+ return True
77
+
13
78
 
14
79
  class RequirementOperatorManager(models.Manager):
15
80
  def get_by_natural_key(self, name):
16
81
  """
17
82
  Retrieves a RequirementOperator instance by its unique name.
18
-
83
+
19
84
  Args:
20
85
  name: The unique name of the RequirementOperator.
21
-
86
+
22
87
  Returns:
23
88
  The RequirementOperator instance with the specified name.
24
89
  """
@@ -36,7 +101,7 @@ class RequirementOperator(models.Model):
36
101
 
37
102
  name = models.CharField(max_length=100, unique=True)
38
103
  description = models.TextField(blank=True, null=True)
39
- evaluation_function_name = models.CharField(max_length=255, blank=True, null=True) # Added field
104
+ evaluation_function_name = models.CharField(max_length=255, blank=True, null=True) # Added field
40
105
 
41
106
  objects = RequirementOperatorManager()
42
107
 
@@ -45,30 +110,34 @@ class RequirementOperator(models.Model):
45
110
 
46
111
  requirements: models.QuerySet[Requirement]
47
112
 
48
- @property
49
- def operator_evaluation_models(self):
113
+ @classmethod
114
+ def parse_instructions(cls, raw: str) -> OperatorInstructions:
50
115
  """
51
- Returns a dictionary of operator evaluation models for this requirement operator.
52
-
53
- This property dynamically imports and provides access to the available operator evaluation models.
116
+ Parses the raw target attributes string into structured operator instructions.
117
+
118
+ Args:
119
+ raw: The raw target attributes string.
120
+
121
+ Returns:
122
+ An OperatorInstructions instance containing parsed input targets, requirement targets, kwargs, and args.
54
123
  """
55
- from .requirement_evaluation.operator_evaluation_models import operator_evaluation_models
56
- return operator_evaluation_models
57
-
124
+ return _parse_operator_instructions(raw)
125
+
58
126
  @property
59
127
  def data_model_dict(self):
60
128
  """
61
129
  Returns the dictionary of data models used for requirement evaluation.
62
-
130
+
63
131
  This property dynamically imports and provides access to the data model dictionary relevant to requirement operators.
64
132
  """
65
133
  from .requirement_evaluation.requirement_type_parser import data_model_dict
134
+
66
135
  return data_model_dict
67
136
 
68
137
  def natural_key(self):
69
138
  """
70
139
  Returns a tuple containing the operator's name as its natural key.
71
-
140
+
72
141
  The natural key uniquely identifies the requirement operator for serialization and deserialization purposes.
73
142
  """
74
143
  return (self.name,)
@@ -78,99 +147,21 @@ class RequirementOperator(models.Model):
78
147
  Returns the name of the requirement operator as its string representation.
79
148
  """
80
149
  return str(self.name)
81
-
82
- def evaluate(self, requirement_links: "RequirementLinks", input_links: "RequirementLinks", **kwargs) -> bool: # Changed signature
83
-
84
- """
85
- Evaluates the requirement operator against the provided requirement links and input_links.
86
-
87
- Args:
88
- requirement_links: The RequirementLinks object from the Requirement model.
89
- input_links: The aggregated RequirementLinks object from the input arguments.
90
- **kwargs: Additional keyword arguments for specific operator logic.
91
- For lab value operators, this includes 'requirement' (the Requirement model instance).
92
- The 'requirement' instance is now passed for all operators.
93
150
 
94
- Returns:
95
- True if the condition defined by the operator is met, False otherwise.
96
-
97
- Raises:
98
- NotImplementedError: If the evaluation logic for the operator's name is not implemented.
99
- """
100
- # kwargs should contain 'requirement' (the Requirement instance) passed from Requirement.evaluate()
101
- if self.evaluation_function_name:
102
- eval_func = getattr(self, self.evaluation_function_name, None)
103
- if eval_func and callable(eval_func):
104
- return eval_func(requirement_links=requirement_links, input_links=input_links, **kwargs)
105
- else:
106
- logger.error(
107
- f"Evaluation function '{self.evaluation_function_name}' "
108
- f"not found or not callable on {self.__class__.__name__} "
109
- f"for operator '{self.name}'."
110
- )
111
- raise NotImplementedError(
112
- f"Evaluation function '{self.evaluation_function_name}' "
113
- f"not implemented correctly for operator '{self.name}'."
114
- )
115
- else:
116
- # Fallback to the central dispatcher if no specific function name is provided
117
- from endoreg_db.utils.requirement_operator_logic.model_evaluators import dispatch_operator_evaluation
118
- return dispatch_operator_evaluation(
119
- operator_name=self.name,
120
- requirement_links=requirement_links,
121
- input_links=input_links,
122
- operator_instance=self, # Pass the operator instance
123
- **kwargs
124
- )
125
-
126
- from ..medical.patient.patient_medication import PatientMedication # Added
127
- from ..medical.medication import MedicationSchedule as MedicationScheduleTemplate # Added with alias
128
-
129
- def _evaluate_patient_medication_schedule_matches_template(
130
- self,
131
- requirement_links: "RequirementLinks",
132
- input_links: "RequirementLinks",
133
- requirement: "Requirement", # Added requirement
134
- **kwargs,
135
- ) -> bool:
136
- """
137
- Checks if any PatientMedication in the input PatientMedicationSchedule
138
- matches the profile (medication, dose, unit, intake times)
139
- of any MedicationSchedule template linked to the requirement.
140
- """
141
- # Get MedicationSchedule templates from the requirement
142
- req_schedule_templates = requirement_links.medication_schedules
143
- if not req_schedule_templates:
144
- # If the requirement doesn't specify any templates to match against,
145
- # it's ambiguous. Consider this a non-match.
146
- return False
147
-
148
- # Get PatientMedication instances from the input (derived from PatientMedicationSchedule.links)
149
- input_patient_medications = input_links.patient_medications
150
- if not input_patient_medications:
151
- # If the input schedule has no medications, it cannot match any template.
152
- return False
153
-
154
- for pm_instance in input_patient_medications:
155
- pm_intake_times_set = set(pm_instance.intake_times.all())
156
- for schedule_template in req_schedule_templates:
157
- template_intake_times_set = set(schedule_template.intake_times.all())
158
-
159
- # Check for profile match
160
- medication_match = pm_instance.medication == schedule_template.medication
161
- dose_match = pm_instance.dosage == schedule_template.dose
162
- unit_match = pm_instance.unit == schedule_template.unit
163
- intake_times_match = pm_intake_times_set == template_intake_times_set
164
-
165
- # Debugging output (optional, can be removed)
166
- # print(f"Comparing PM ID {pm_instance.id} with Template {schedule_template.name}:")
167
- # print(f" Medication: {pm_instance.medication} vs {schedule_template.medication} -> {medication_match}")
168
- # print(f" Dose: {pm_instance.dosage} vs {schedule_template.dose} -> {dose_match}")
169
- # print(f" Unit: {pm_instance.unit} vs {schedule_template.unit} -> {unit_match}")
170
- # print(f" Intake Times: {pm_intake_times_set} vs {template_intake_times_set} -> {intake_times_match}")
171
-
172
-
173
- if medication_match and dose_match and unit_match and intake_times_match:
174
- return True # Found a match
175
-
176
- return False # No PatientMedication matched any template
151
+ def get_operator_function(self) -> Callable[..., bool]:
152
+ _operator_function = REQUIREMENT_OPERATORS.get(self.name)
153
+ if not _operator_function:
154
+ raise ValueError(f"Operator function for '{self.name}' not found in REQUIREMENT_OPERATORS.")
155
+ return _operator_function
156
+
157
+ def evaluate(self, operator_instructions: "OperatorInstructions", requirement: "Requirement", input_obj: Any, **kwargs) -> bool:
158
+ """ """
159
+ eval_result: bool = False
160
+ requirement_links: "RequirementLinks" = requirement.links
161
+ expected_input_models = requirement.expected_models
162
+ operator_function = self.get_operator_function()
163
+
164
+ input_model = type(input_obj)
165
+ assert input_model in expected_input_models, f"Input model {input_model} not in expected models {expected_input_models}"
166
+
167
+ return eval_result
@@ -1,6 +1,6 @@
1
- from django.db import models
2
1
  from typing import TYPE_CHECKING, List
3
2
 
3
+ from django.db import models
4
4
 
5
5
  REQUIREMENT_SET_TYPE_FUNCTION_LOOKUP = {
6
6
  "all": all,
@@ -11,6 +11,7 @@ REQUIREMENT_SET_TYPE_FUNCTION_LOOKUP = {
11
11
  "at_most_1": lambda x: sum(1 for item in x if item) <= 1,
12
12
  }
13
13
 
14
+
14
15
  class RequirementSetTypeManager(models.Manager):
15
16
  """
16
17
  Manager for RequirementSetType with custom query methods.
@@ -19,10 +20,10 @@ class RequirementSetTypeManager(models.Manager):
19
20
  def get_by_natural_key(self, name: str) -> "RequirementSetType":
20
21
  """
21
22
  Retrieves a RequirementSetType instance using its natural key.
22
-
23
+
23
24
  Args:
24
25
  name (str): The unique name that serves as the natural key.
25
-
26
+
26
27
  Returns:
27
28
  RequirementSetType: The matching RequirementSetType instance.
28
29
  """
@@ -50,7 +51,7 @@ class RequirementSetType(models.Model):
50
51
  def natural_key(self):
51
52
  """
52
53
  Return the natural key tuple for the instance.
53
-
54
+
54
55
  Returns:
55
56
  tuple: A one-element tuple containing the instance's name, used as its natural key.
56
57
  """
@@ -61,10 +62,10 @@ class RequirementSetManager(models.Manager):
61
62
  def get_by_natural_key(self, name):
62
63
  """
63
64
  Retrieves a model instance by its natural key.
64
-
65
+
65
66
  Args:
66
67
  name: The natural key value, typically corresponding to the model's unique name.
67
-
68
+
68
69
  Returns:
69
70
  The model instance whose name matches the provided natural key.
70
71
  """
@@ -82,53 +83,69 @@ class RequirementSet(models.Model):
82
83
 
83
84
  name = models.CharField(max_length=100, unique=True)
84
85
  description = models.TextField(blank=True, null=True)
85
- requirements = models.ManyToManyField( # type: ignore[assignment]
86
+
87
+ depends_on = models.ManyToManyField(
88
+ "self",
89
+ symmetrical=False,
90
+ related_name="dependents",
91
+ blank=True,
92
+ help_text=(
93
+ "Andere RequirementSets, die zuerst erfüllt sein müssen, "
94
+ "bevor dieses Set geprüft wird ('after')."
95
+ ),
96
+ )
97
+
98
+ requirements = models.ManyToManyField(
86
99
  "Requirement",
87
100
  blank=True,
88
101
  related_name="requirement_sets",
89
102
  )
90
- links_to_sets = models.ManyToManyField( # type: ignore[assignment]
103
+ links_to_sets = models.ManyToManyField(
91
104
  "RequirementSet",
92
105
  blank=True,
93
106
  related_name="links_from_sets",
94
107
  )
95
- requirement_set_type = models.ForeignKey( # type: ignore[assignment]
108
+ requirement_set_type = models.ForeignKey(
96
109
  "RequirementSetType",
97
110
  on_delete=models.CASCADE,
98
111
  related_name="requirement_sets",
99
112
  blank=True,
100
113
  null=True,
101
114
  )
102
- information_sources = models.ManyToManyField( # type: ignore[assignment]
115
+ information_sources = models.ManyToManyField(
103
116
  "InformationSource",
104
117
  related_name="requirement_sets",
105
118
  blank=True,
106
119
  )
107
-
108
- reqset_exam_links = models.ManyToManyField( # type: ignore[assignment]
120
+
121
+ reqset_exam_links = models.ManyToManyField(
109
122
  "ExaminationRequirementSet",
110
123
  related_name="requirement_set",
111
124
  blank=True,
112
125
  )
113
-
114
- tags = models.ManyToManyField( # type: ignore[assignment]
126
+
127
+ tags = models.ManyToManyField(
115
128
  "Tag",
116
129
  related_name="requirement_sets",
117
130
  blank=True,
118
131
  )
119
-
132
+
120
133
  objects = RequirementSetManager()
121
134
 
122
135
  if TYPE_CHECKING:
123
- from endoreg_db.models import Tag, Requirement, InformationSource
124
- from typing import Optional
136
+ from typing import Optional, cast
137
+
138
+ from endoreg_db.models import ExaminationRequirementSet, InformationSource, Requirement, Tag
139
+
140
+ tags = cast(models.manager.RelatedManager["Tag"], tags)
141
+ requirements = cast(models.manager.RelatedManager["Requirement"], requirements)
142
+ links_to_sets = cast(models.manager.RelatedManager["RequirementSet"], links_to_sets)
143
+ reqset_exam_links = cast(models.manager.RelatedManager["ExaminationRequirementSet"], reqset_exam_links)
144
+ information_sources = cast(models.manager.RelatedManager["InformationSource"], information_sources)
145
+ requirement_set_type: models.ForeignKey["RequirementSetType | None"]
125
146
 
126
- tags: "models.ManyToManyField[Tag]"
127
- requirements: "models.Manager[Requirement]"
128
- information_sources: "models.Manager[InformationSource]"
129
- requirement_set_type: Optional[RequirementSetType]
130
- links_to_sets: "models.Manager[RequirementSet]"
131
- links_from_sets: "models.Manager[RequirementSet]"
147
+ @property
148
+ def links_from_sets(self) -> "models.manager.RelatedManager[RequirementSet]": ...
132
149
 
133
150
  def natural_key(self):
134
151
  """Return the natural key as a tuple containing the instance's name."""
@@ -139,19 +156,19 @@ class RequirementSet(models.Model):
139
156
  Returns the name of the requirement set as its string representation.
140
157
  """
141
158
  return str(self.name)
142
-
159
+
143
160
  def evaluate_requirements(self, input_object, mode="loose") -> List[bool]:
144
161
  """
145
162
  Evaluates all requirements in the set against the provided input object.
146
-
163
+
147
164
  Intelligently selects the appropriate input data for each requirement based on its expected model types.
148
- For example, if a requirement expects PatientFinding but receives a PatientExamination,
165
+ For example, if a requirement expects PatientFinding but receives a PatientExamination,
149
166
  it will use the examination's patient_findings instead.
150
-
167
+
151
168
  Args:
152
169
  input_object: The object to be evaluated by each requirement.
153
170
  mode: Optional evaluation mode passed to each requirement (default is "loose").
154
-
171
+
155
172
  Returns:
156
173
  A list of boolean values indicating whether each requirement is satisfied.
157
174
  """
@@ -162,36 +179,39 @@ class RequirementSet(models.Model):
162
179
  result = requirement.evaluate(evaluation_input, mode=mode)
163
180
  results.append(result)
164
181
  return results
165
-
182
+
166
183
  def _get_evaluation_input_for_requirement(self, requirement, input_object):
167
184
  """
168
185
  Determines the appropriate input object for evaluating a specific requirement.
169
-
186
+
170
187
  Args:
171
188
  requirement: The requirement to be evaluated
172
189
  input_object: The original input object
173
-
190
+
174
191
  Returns:
175
192
  The most appropriate input object for the requirement evaluation
176
193
  """
177
194
  expected_models = requirement.expected_models
178
-
195
+
179
196
  # If the input object is already one of the expected models, use it directly
180
197
  for expected_model in expected_models:
181
198
  if isinstance(input_object, expected_model):
182
199
  return input_object
183
-
200
+
184
201
  # Import here to avoid circular imports
185
202
  from endoreg_db.models.medical.patient.patient_examination import PatientExamination
186
203
  from endoreg_db.models.medical.patient.patient_finding import PatientFinding
187
-
204
+
188
205
  # Handle PatientExamination -> PatientFinding conversion
189
206
  if isinstance(input_object, PatientExamination):
190
- # If requirement expects PatientFinding, return the examination's findings
207
+ # If the requirement expects PatientFinding instances, scope queryset to relevant findings
191
208
  if PatientFinding in expected_models:
192
- return input_object.patient_findings.all()
209
+ findings_qs = input_object.patient_findings.all()
210
+ required_findings = list(requirement.findings.all())
211
+ if required_findings:
212
+ findings_qs = findings_qs.filter(finding__in=required_findings)
213
+ return findings_qs
193
214
 
194
-
195
215
  # Handle other model conversions as needed in the future
196
216
  # For now, return the original input object as fallback
197
217
  return input_object
@@ -199,7 +219,7 @@ class RequirementSet(models.Model):
199
219
  def evaluate_requirement_sets(self, input_object) -> List[bool]:
200
220
  """
201
221
  Evaluates all linked requirement sets against the provided input object.
202
-
222
+
203
223
  Returns:
204
224
  A list of boolean values indicating whether each linked requirement set is satisfied.
205
225
  """
@@ -211,12 +231,12 @@ class RequirementSet(models.Model):
211
231
  result = linked_set.evaluate(input_object)
212
232
  results.append(result)
213
233
  return results
214
-
234
+
215
235
  @property
216
236
  def eval_function(self):
217
237
  """
218
238
  Returns the evaluation function associated with this requirement set's type.
219
-
239
+
220
240
  If the requirement set type is defined and matches a known type, returns the corresponding function from REQUIREMENT_SET_TYPE_FUNCTION_LOOKUP. Returns None if no matching function is found.
221
241
  """
222
242
  if self.requirement_set_type and self.requirement_set_type.name in REQUIREMENT_SET_TYPE_FUNCTION_LOOKUP:
@@ -226,12 +246,12 @@ class RequirementSet(models.Model):
226
246
  def evaluate(self, input_object):
227
247
  """
228
248
  Evaluates whether the input object satisfies this requirement set.
229
-
249
+
230
250
  Combines the evaluation results of all direct requirements and linked requirement sets, then applies the set's evaluation function (such as all, any, none, etc.) to determine if the input object meets the overall criteria.
231
-
251
+
232
252
  Args:
233
253
  input_object: The object to be evaluated against the requirements and linked sets.
234
-
254
+
235
255
  Returns:
236
256
  True if the input object satisfies the requirement set according to its evaluation logic; otherwise, False.
237
257
  """
@@ -243,45 +263,42 @@ class RequirementSet(models.Model):
243
263
  eval_result = self.eval_function(results) if self.eval_function else all(results)
244
264
 
245
265
  return eval_result
246
-
266
+
247
267
  @property
248
268
  def all_linked_sets(self):
249
269
  """
250
270
  Returns all linked requirement sets, including those linked to the current set and those linked to any of its linked sets.
251
-
271
+
252
272
  Uses recursive traversal with cycle detection to safely handle circular relationships.
253
273
  Eliminates duplicates by tracking visited sets.
254
-
274
+
255
275
  Returns:
256
276
  List[RequirementSet]: A list of all linked requirement sets.
257
277
  """
258
278
  visited = set()
259
- result:List["RequirementSet"] = []
260
-
261
- def _collect_linked_sets(requirement_set:"RequirementSet"):
279
+ result: List["RequirementSet"] = []
280
+
281
+ def _collect_linked_sets(requirement_set: "RequirementSet"):
262
282
  """
263
283
  Recursively collect linked sets while avoiding cycles and duplicates.
264
-
284
+
265
285
  Args:
266
286
  requirement_set: The RequirementSet to process
267
287
  """
268
288
  # Use the primary key to track visited sets (avoids issues with object comparison)
269
289
  if requirement_set.pk in visited:
270
290
  return
271
-
291
+
272
292
  visited.add(requirement_set.pk)
273
-
293
+
274
294
  # Process all directly linked sets
275
295
  for linked_set in requirement_set.links_to_sets.all():
276
296
  if linked_set.pk not in visited:
277
297
  result.append(linked_set)
278
298
  # Recursively process the linked set's links
279
299
  _collect_linked_sets(linked_set)
280
-
300
+
281
301
  # Start the recursive collection from this instance
282
302
  _collect_linked_sets(self)
283
-
284
- return result
285
-
286
-
287
303
 
304
+ return result
@@ -1,12 +1,12 @@
1
- from .sensitive_meta import SensitiveMetaState
2
- from .video import VideoState, AnonymizationStatus
3
1
  from .label_video_segment import LabelVideoSegmentState
4
2
  from .raw_pdf import RawPdfState
5
-
3
+ from .sensitive_meta import SensitiveMetaState
4
+ from .video import VideoState
5
+ from .anonymization import AnonymizationState
6
6
  __all__ = [
7
7
  "SensitiveMetaState",
8
8
  "VideoState",
9
9
  "LabelVideoSegmentState",
10
- "AnonymizationStatus",
10
+ "AnonymizationState",
11
11
  "RawPdfState",
12
12
  ]
@@ -1,11 +1,11 @@
1
1
  from django.db import models
2
2
 
3
+
3
4
  class AbstractState(models.Model):
4
5
  """Abstract base class for all states."""
5
6
 
6
7
  created_at = models.DateTimeField(auto_now_add=True)
7
8
  updated_at = models.DateTimeField(auto_now=True)
8
9
 
9
-
10
10
  class Meta:
11
- abstract = True
11
+ abstract = True
@@ -0,0 +1,12 @@
1
+ from enum import Enum
2
+
3
+
4
+ class AnonymizationState(str, Enum):
5
+ NOT_STARTED = "not_started"
6
+ EXTRACTING_FRAMES = "extracting_frames"
7
+ PROCESSING_ANONYMIZING = "processing_anonymization"
8
+ DONE_PROCESSING_ANONYMIZATION = "done_processing_anonymization"
9
+ VALIDATED = "validated"
10
+ FAILED = "failed"
11
+ STARTED = "started"
12
+ ANONYMIZED = "anonymized"