endoreg-db 0.4.5__py3-none-any.whl → 0.8.6.3__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.
Files changed (846) hide show
  1. endoreg_db/admin.py +90 -1
  2. endoreg_db/api_urls.py +4 -0
  3. endoreg_db/apps.py +12 -0
  4. endoreg_db/assets/dummy_model.ckpt +1 -0
  5. endoreg_db/codemods/readme.md +88 -0
  6. endoreg_db/codemods/rename_datetime_fields.py +92 -0
  7. endoreg_db/config/env.py +101 -0
  8. endoreg_db/data/__init__.py +76 -4
  9. endoreg_db/data/ai_model/data.yaml +7 -0
  10. endoreg_db/data/{label → ai_model_label}/label/data.yaml +27 -1
  11. endoreg_db/data/ai_model_label/label/polyp_classification.yaml +52 -0
  12. endoreg_db/data/ai_model_label/label-set/data.yaml +40 -0
  13. endoreg_db/data/ai_model_label/label-set/polyp_classifications.yaml +25 -0
  14. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +27 -0
  15. endoreg_db/data/ai_model_video_segmentation_label/base_segmentation.yaml +176 -0
  16. endoreg_db/data/ai_model_video_segmentation_labelset/data.yaml +20 -0
  17. endoreg_db/data/center/data.yaml +40 -9
  18. endoreg_db/data/center_shift/ukw.yaml +9 -0
  19. endoreg_db/data/contraindication/bleeding.yaml +11 -0
  20. endoreg_db/data/db_summary.csv +58 -0
  21. endoreg_db/data/db_summary.xlsx +0 -0
  22. endoreg_db/data/disease/misc.yaml +1 -2
  23. endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +2 -2
  24. endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +6 -6
  25. endoreg_db/data/distribution/numeric/data.yaml +14 -0
  26. endoreg_db/data/endoscope/data.yaml +93 -0
  27. endoreg_db/data/endoscopy_processor/data.yaml +3 -0
  28. endoreg_db/data/event/cardiology.yaml +0 -13
  29. endoreg_db/data/examination/examinations/data.yaml +34 -28
  30. endoreg_db/data/examination/type/data.yaml +12 -0
  31. endoreg_db/data/examination_indication/endoscopy.yaml +424 -0
  32. endoreg_db/data/examination_indication_classification/endoscopy.yaml +160 -0
  33. endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +101 -0
  34. endoreg_db/data/examination_requirement_set/colonoscopy.yaml +15 -0
  35. endoreg_db/data/finding/anatomy_colon.yaml +128 -0
  36. endoreg_db/data/finding/colonoscopy.yaml +40 -0
  37. endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +56 -0
  38. endoreg_db/data/finding/complication.yaml +16 -0
  39. endoreg_db/data/finding/data.yaml +105 -0
  40. endoreg_db/data/finding/examination_setting.yaml +16 -0
  41. endoreg_db/data/finding/medication_related.yaml +18 -0
  42. endoreg_db/data/finding/outcome.yaml +12 -0
  43. endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +95 -0
  44. endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +22 -0
  45. endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +25 -0
  46. endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
  47. endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
  48. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +68 -0
  49. endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
  50. endoreg_db/data/finding_classification/colonoscopy_location.yaml +80 -0
  51. endoreg_db/data/finding_classification/colonoscopy_lst.yaml +21 -0
  52. endoreg_db/data/finding_classification/colonoscopy_nice.yaml +20 -0
  53. endoreg_db/data/finding_classification/colonoscopy_paris.yaml +26 -0
  54. endoreg_db/data/finding_classification/colonoscopy_sano.yaml +22 -0
  55. endoreg_db/data/finding_classification/colonoscopy_summary.yaml +53 -0
  56. endoreg_db/data/finding_classification/complication_generic.yaml +25 -0
  57. endoreg_db/data/finding_classification/examination_setting_generic.yaml +40 -0
  58. endoreg_db/data/finding_classification/histology_colo.yaml +51 -0
  59. endoreg_db/data/finding_classification/intervention_required.yaml +26 -0
  60. endoreg_db/data/finding_classification/medication_related.yaml +23 -0
  61. endoreg_db/data/finding_classification/visualized.yaml +33 -0
  62. endoreg_db/data/finding_classification_choice/bowel_preparation.yaml +78 -0
  63. endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
  64. endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
  65. endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
  66. endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +15 -0
  67. endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +17 -0
  68. endoreg_db/data/finding_classification_choice/colon_lesion_paris.yaml +57 -0
  69. endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
  70. endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +14 -0
  71. endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
  72. endoreg_db/data/finding_classification_choice/colonoscopy_location.yaml +229 -0
  73. endoreg_db/data/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
  74. endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +82 -0
  75. endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
  76. endoreg_db/data/finding_classification_choice/complication_generic_types.yaml +15 -0
  77. endoreg_db/data/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
  78. endoreg_db/data/finding_classification_choice/histology.yaml +24 -0
  79. endoreg_db/data/finding_classification_choice/histology_polyp.yaml +20 -0
  80. endoreg_db/data/finding_classification_choice/outcome.yaml +19 -0
  81. endoreg_db/data/finding_classification_choice/yes_no_na.yaml +11 -0
  82. endoreg_db/data/finding_classification_type/colonoscopy_basic.yaml +48 -0
  83. endoreg_db/data/finding_intervention/endoscopy.yaml +43 -0
  84. endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
  85. endoreg_db/data/finding_intervention/endoscopy_egd.yaml +128 -0
  86. endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +32 -0
  87. endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +9 -0
  88. endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +36 -0
  89. endoreg_db/data/finding_intervention_type/endoscopy.yaml +15 -0
  90. endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +79 -0
  91. endoreg_db/data/finding_type/data.yaml +43 -0
  92. endoreg_db/data/gender/data.yaml +24 -0
  93. endoreg_db/data/information_source/annotation.yaml +6 -0
  94. endoreg_db/data/information_source/endoscopy_guidelines.yaml +7 -0
  95. endoreg_db/data/information_source/prediction.yaml +7 -0
  96. endoreg_db/data/information_source_type/data.yaml +8 -0
  97. endoreg_db/data/lab_value/cardiac_enzymes.yaml +7 -1
  98. endoreg_db/data/lab_value/coagulation.yaml +6 -1
  99. endoreg_db/data/lab_value/electrolytes.yaml +39 -1
  100. endoreg_db/data/lab_value/gastrointestinal_function.yaml +12 -0
  101. endoreg_db/data/lab_value/hematology.yaml +17 -2
  102. endoreg_db/data/lab_value/hormones.yaml +6 -0
  103. endoreg_db/data/lab_value/lipids.yaml +12 -3
  104. endoreg_db/data/lab_value/misc.yaml +48 -2
  105. endoreg_db/data/lab_value/renal_function.yaml +2 -1
  106. endoreg_db/data/lx_client_tag/base.yaml +54 -0
  107. endoreg_db/data/lx_client_type/base.yaml +30 -0
  108. endoreg_db/data/lx_permission/base.yaml +24 -0
  109. endoreg_db/data/lx_permission/endoreg.yaml +52 -0
  110. endoreg_db/data/medication/anticoagulation.yaml +5 -5
  111. endoreg_db/data/medication/tah.yaml +5 -5
  112. endoreg_db/data/medication_indication/anticoagulation.yaml +48 -53
  113. endoreg_db/data/medication_intake_time/base.yaml +4 -4
  114. endoreg_db/data/names_first/first_names.yaml +54 -0
  115. endoreg_db/data/names_last/last_names.yaml +51 -0
  116. endoreg_db/data/network_device/data.yaml +30 -0
  117. endoreg_db/data/organ/data.yaml +29 -0
  118. endoreg_db/data/pdf_type/data.yaml +27 -9
  119. endoreg_db/data/qualification/endoscopy.yaml +36 -0
  120. endoreg_db/data/qualification/m2.yaml +39 -0
  121. endoreg_db/data/qualification/outpatient_clinic.yaml +35 -0
  122. endoreg_db/data/qualification/sonography.yaml +36 -0
  123. endoreg_db/data/qualification_type/base.yaml +29 -0
  124. endoreg_db/data/report_reader_flag/rkh-histology-generic.yaml +10 -0
  125. endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +4 -0
  126. endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +5 -0
  127. endoreg_db/data/requirement/age.yaml +26 -0
  128. endoreg_db/data/requirement/colonoscopy_baseline_austria.yaml +45 -0
  129. endoreg_db/data/requirement/disease_cardiovascular.yaml +79 -0
  130. endoreg_db/data/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
  131. endoreg_db/data/requirement/disease_hepatology.yaml +12 -0
  132. endoreg_db/data/requirement/disease_misc.yaml +12 -0
  133. endoreg_db/data/requirement/disease_renal.yaml +96 -0
  134. endoreg_db/data/requirement/endoscopy_bleeding_risk.yaml +59 -0
  135. endoreg_db/data/requirement/event_cardiology.yaml +251 -0
  136. endoreg_db/data/requirement/event_requirements.yaml +145 -0
  137. endoreg_db/data/requirement/finding_colon_polyp.yaml +50 -0
  138. endoreg_db/data/requirement/gender.yaml +25 -0
  139. endoreg_db/data/requirement/lab_value.yaml +441 -0
  140. endoreg_db/data/requirement/medication.yaml +93 -0
  141. endoreg_db/data/requirement_operator/age.yaml +13 -0
  142. endoreg_db/data/requirement_operator/lab_operators.yaml +129 -0
  143. endoreg_db/data/requirement_operator/model_operators.yaml +96 -0
  144. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +48 -0
  145. endoreg_db/data/requirement_set/colonoscopy_austria_screening.yaml +57 -0
  146. endoreg_db/data/requirement_set/endoscopy_bleeding_risk.yaml +52 -0
  147. endoreg_db/data/requirement_set_type/data.yaml +20 -0
  148. endoreg_db/data/requirement_type/requirement_types.yaml +165 -0
  149. endoreg_db/data/risk/bleeding.yaml +26 -0
  150. endoreg_db/data/risk/thrombosis.yaml +37 -0
  151. endoreg_db/data/risk_type/data.yaml +27 -0
  152. endoreg_db/data/setup_config.yaml +38 -0
  153. endoreg_db/data/shift/endoscopy.yaml +21 -0
  154. endoreg_db/data/shift_type/base.yaml +35 -0
  155. endoreg_db/data/tag/requirement_set_tags.yaml +11 -0
  156. endoreg_db/data/unit/concentration.yaml +23 -0
  157. endoreg_db/data/unit/time.yaml +36 -1
  158. endoreg_db/exceptions.py +19 -0
  159. endoreg_db/forms/__init__.py +3 -1
  160. endoreg_db/forms/examination_form.py +11 -0
  161. endoreg_db/forms/patient_finding_intervention_form.py +18 -0
  162. endoreg_db/forms/patient_form.py +27 -0
  163. endoreg_db/forms/questionnaires/__init__.py +1 -1
  164. endoreg_db/forms/questionnaires/tto_questionnaire.py +19 -19
  165. endoreg_db/helpers/count_db.py +45 -0
  166. endoreg_db/helpers/data_loader.py +208 -0
  167. endoreg_db/helpers/default_objects.py +378 -0
  168. endoreg_db/helpers/download_segmentation_model.py +31 -0
  169. endoreg_db/helpers/interact.py +6 -0
  170. endoreg_db/helpers/test_video_helper.py +119 -0
  171. endoreg_db/logger_conf.py +140 -0
  172. endoreg_db/management/__init__.py +1 -0
  173. endoreg_db/management/commands/__init__.py +1 -0
  174. endoreg_db/management/commands/anonymize_video.py +0 -0
  175. endoreg_db/management/commands/check_auth.py +125 -0
  176. endoreg_db/management/commands/create_model_meta_from_huggingface.py +115 -0
  177. endoreg_db/management/commands/create_multilabel_model_meta.py +214 -0
  178. endoreg_db/management/commands/fix_missing_patient_data.py +172 -0
  179. endoreg_db/management/commands/fix_video_paths.py +165 -0
  180. endoreg_db/management/commands/import_fallback_video.py +203 -0
  181. endoreg_db/management/commands/import_report.py +298 -0
  182. endoreg_db/management/commands/import_video.py +423 -0
  183. endoreg_db/management/commands/import_video_with_classification.py +367 -0
  184. endoreg_db/management/commands/init_default_ai_model.py +112 -0
  185. endoreg_db/management/commands/load_ai_model_data.py +58 -26
  186. endoreg_db/management/commands/load_ai_model_label_data.py +59 -0
  187. endoreg_db/management/commands/load_base_db_data.py +174 -118
  188. endoreg_db/management/commands/load_center_data.py +46 -21
  189. endoreg_db/management/commands/{load_logging_data.py → load_contraindication_data.py} +4 -2
  190. endoreg_db/management/commands/load_disease_data.py +29 -7
  191. endoreg_db/management/commands/{load_endoscope_type_data.py → load_endoscope_data.py} +30 -7
  192. endoreg_db/management/commands/load_examination_indication_data.py +86 -0
  193. endoreg_db/management/commands/load_finding_data.py +128 -0
  194. endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +0 -1
  195. endoreg_db/management/commands/load_information_source.py +13 -7
  196. endoreg_db/management/commands/load_lab_value_data.py +3 -3
  197. endoreg_db/management/commands/load_medication_data.py +83 -21
  198. endoreg_db/management/commands/load_name_data.py +37 -0
  199. endoreg_db/management/commands/{load_medication_intake_time_data.py → load_organ_data.py} +7 -5
  200. endoreg_db/management/commands/load_qualification_data.py +59 -0
  201. endoreg_db/management/commands/load_requirement_data.py +180 -0
  202. endoreg_db/management/commands/load_risk_data.py +56 -0
  203. endoreg_db/management/commands/load_shift_data.py +60 -0
  204. endoreg_db/management/commands/load_tag_data.py +57 -0
  205. endoreg_db/management/commands/register_ai_model.py +1 -1
  206. endoreg_db/management/commands/setup_endoreg_db.py +381 -0
  207. endoreg_db/management/commands/start_filewatcher.py +106 -0
  208. endoreg_db/management/commands/storage_management.py +548 -0
  209. endoreg_db/management/commands/summarize_db_content.py +189 -0
  210. endoreg_db/management/commands/validate_video.py +204 -0
  211. endoreg_db/management/commands/validate_video_files.py +161 -0
  212. endoreg_db/management/commands/video_validation.py +22 -0
  213. endoreg_db/mermaid/Overall_flow_patient_finding_intervention.md +10 -0
  214. endoreg_db/mermaid/anonymized_image_annotation.md +20 -0
  215. endoreg_db/mermaid/binary_classification_annotation.md +50 -0
  216. endoreg_db/mermaid/classification.md +8 -0
  217. endoreg_db/mermaid/examination.md +8 -0
  218. endoreg_db/mermaid/findings.md +7 -0
  219. endoreg_db/mermaid/image_classification.md +28 -0
  220. endoreg_db/mermaid/interventions.md +8 -0
  221. endoreg_db/mermaid/morphology.md +8 -0
  222. endoreg_db/mermaid/patient_creation.md +14 -0
  223. endoreg_db/mermaid/video_segmentation_annotation.md +17 -0
  224. endoreg_db/migrations/0001_initial.py +1234 -944
  225. endoreg_db/migrations/0002_add_video_correction_models.py +52 -0
  226. endoreg_db/migrations/0003_add_center_display_name.py +30 -0
  227. endoreg_db/models/__init__.py +339 -53
  228. endoreg_db/models/administration/__init__.py +116 -0
  229. endoreg_db/models/administration/ai/__init__.py +9 -0
  230. endoreg_db/models/administration/ai/active_model.py +35 -0
  231. endoreg_db/models/administration/ai/ai_model.py +156 -0
  232. endoreg_db/models/{ai_model → administration/ai}/model_type.py +19 -4
  233. endoreg_db/models/administration/case/__init__.py +19 -0
  234. endoreg_db/models/administration/case/case.py +114 -0
  235. endoreg_db/models/{case_template → administration/case/case_template}/__init__.py +10 -1
  236. endoreg_db/models/{case_template → administration/case/case_template}/case_template.py +60 -16
  237. endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule.py +6 -13
  238. endoreg_db/models/{case_template → administration/case/case_template}/case_template_rule_value.py +21 -8
  239. endoreg_db/models/{case_template → administration/case/case_template}/case_template_type.py +1 -3
  240. endoreg_db/models/{center → administration/center}/__init__.py +9 -0
  241. endoreg_db/models/administration/center/center.py +67 -0
  242. endoreg_db/models/administration/center/center_product.py +64 -0
  243. endoreg_db/models/administration/center/center_resource.py +49 -0
  244. endoreg_db/models/administration/center/center_shift.py +88 -0
  245. endoreg_db/models/administration/center/center_waste.py +30 -0
  246. endoreg_db/models/administration/permissions/__init__.py +44 -0
  247. endoreg_db/models/administration/person/__init__.py +24 -0
  248. endoreg_db/models/administration/person/employee/__init__.py +3 -0
  249. endoreg_db/models/administration/person/employee/employee.py +35 -0
  250. endoreg_db/models/administration/person/employee/employee_qualification.py +39 -0
  251. endoreg_db/models/administration/person/employee/employee_type.py +42 -0
  252. endoreg_db/models/administration/person/examiner/__init__.py +4 -0
  253. endoreg_db/models/administration/person/examiner/examiner.py +54 -0
  254. endoreg_db/models/administration/person/names/__init__.py +0 -0
  255. endoreg_db/models/{persons → administration/person/names}/first_name.py +1 -1
  256. endoreg_db/models/{persons → administration/person/names}/last_name.py +2 -3
  257. endoreg_db/models/administration/person/patient/__init__.py +5 -0
  258. endoreg_db/models/administration/person/patient/patient.py +460 -0
  259. endoreg_db/models/administration/person/profession/__init__.py +24 -0
  260. endoreg_db/models/administration/person/user/__init__.py +5 -0
  261. endoreg_db/models/administration/person/user/portal_user_information.py +37 -0
  262. endoreg_db/models/administration/product/__init__.py +14 -0
  263. endoreg_db/models/administration/product/product.py +97 -0
  264. endoreg_db/models/administration/product/product_group.py +39 -0
  265. endoreg_db/models/administration/product/product_material.py +54 -0
  266. endoreg_db/models/{product → administration/product}/product_weight.py +21 -0
  267. endoreg_db/models/{product → administration/product}/reference_product.py +44 -13
  268. endoreg_db/models/administration/qualification/__init__.py +7 -0
  269. endoreg_db/models/administration/qualification/qualification.py +37 -0
  270. endoreg_db/models/administration/qualification/qualification_type.py +35 -0
  271. endoreg_db/models/administration/shift/__init__.py +9 -0
  272. endoreg_db/models/administration/shift/scheduled_days.py +69 -0
  273. endoreg_db/models/administration/shift/shift.py +51 -0
  274. endoreg_db/models/administration/shift/shift_type.py +108 -0
  275. endoreg_db/models/label/__init__.py +24 -1
  276. endoreg_db/models/label/annotation/__init__.py +12 -0
  277. endoreg_db/models/label/annotation/image_classification.py +84 -0
  278. endoreg_db/models/label/annotation/video_segmentation_annotation.py +66 -0
  279. endoreg_db/models/label/label.py +53 -54
  280. endoreg_db/models/label/label_set.py +53 -0
  281. endoreg_db/models/label/label_type.py +29 -0
  282. endoreg_db/models/label/label_video_segment/__init__.py +3 -0
  283. endoreg_db/models/label/label_video_segment/_create_from_video.py +41 -0
  284. endoreg_db/models/label/label_video_segment/label_video_segment.py +511 -0
  285. endoreg_db/models/label/video_segmentation_label.py +31 -0
  286. endoreg_db/models/label/video_segmentation_labelset.py +27 -0
  287. endoreg_db/models/media/__init__.py +16 -0
  288. endoreg_db/models/media/frame/__init__.py +3 -0
  289. endoreg_db/models/media/frame/frame.py +111 -0
  290. endoreg_db/models/media/pdf/__init__.py +11 -0
  291. endoreg_db/models/media/pdf/raw_pdf.py +757 -0
  292. endoreg_db/models/media/pdf/report_file.py +162 -0
  293. endoreg_db/models/media/pdf/report_reader/__init__.py +7 -0
  294. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +77 -0
  295. endoreg_db/models/media/video/__init__.py +8 -0
  296. endoreg_db/models/media/video/create_from_file.py +358 -0
  297. endoreg_db/models/media/video/pipe_1.py +213 -0
  298. endoreg_db/models/media/video/pipe_2.py +105 -0
  299. endoreg_db/models/media/video/refactor_plan.md +0 -0
  300. endoreg_db/models/media/video/video_file.py +825 -0
  301. endoreg_db/models/media/video/video_file_ai.py +443 -0
  302. endoreg_db/models/media/video/video_file_anonymize.py +349 -0
  303. endoreg_db/models/media/video/video_file_frames/__init__.py +47 -0
  304. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +22 -0
  305. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +23 -0
  306. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +104 -0
  307. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +174 -0
  308. endoreg_db/models/media/video/video_file_frames/_get_frame.py +28 -0
  309. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +27 -0
  310. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +20 -0
  311. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +27 -0
  312. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +34 -0
  313. endoreg_db/models/media/video/video_file_frames/_get_frames.py +27 -0
  314. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +129 -0
  315. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +141 -0
  316. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +65 -0
  317. endoreg_db/models/media/video/video_file_frames.py +0 -0
  318. endoreg_db/models/media/video/video_file_io.py +168 -0
  319. endoreg_db/models/media/video/video_file_meta/__init__.py +22 -0
  320. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +45 -0
  321. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +39 -0
  322. endoreg_db/models/media/video/video_file_meta/get_fps.py +147 -0
  323. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +143 -0
  324. endoreg_db/models/media/video/video_file_meta/text_meta.py +134 -0
  325. endoreg_db/models/media/video/video_file_meta/video_meta.py +70 -0
  326. endoreg_db/models/media/video/video_file_segments.py +209 -0
  327. endoreg_db/models/media/video/video_metadata.py +65 -0
  328. endoreg_db/models/media/video/video_processing.py +152 -0
  329. endoreg_db/models/medical/__init__.py +146 -0
  330. endoreg_db/models/medical/contraindication/__init__.py +17 -0
  331. endoreg_db/models/medical/disease.py +156 -0
  332. endoreg_db/models/medical/event.py +137 -0
  333. endoreg_db/models/medical/examination/__init__.py +9 -0
  334. endoreg_db/models/medical/examination/examination.py +148 -0
  335. endoreg_db/models/medical/examination/examination_indication.py +278 -0
  336. endoreg_db/models/medical/examination/examination_time.py +49 -0
  337. endoreg_db/models/medical/examination/examination_time_type.py +41 -0
  338. endoreg_db/models/medical/examination/examination_type.py +48 -0
  339. endoreg_db/models/medical/finding/__init__.py +18 -0
  340. endoreg_db/models/medical/finding/finding.py +96 -0
  341. endoreg_db/models/medical/finding/finding_classification.py +142 -0
  342. endoreg_db/models/medical/finding/finding_intervention.py +52 -0
  343. endoreg_db/models/medical/finding/finding_type.py +35 -0
  344. endoreg_db/models/medical/hardware/__init__.py +8 -0
  345. endoreg_db/models/medical/hardware/endoscope.py +65 -0
  346. endoreg_db/models/{hardware → medical/hardware}/endoscopy_processor.py +68 -29
  347. endoreg_db/models/medical/laboratory/__init__.py +5 -0
  348. endoreg_db/models/medical/laboratory/lab_value.py +419 -0
  349. endoreg_db/models/medical/medication/__init__.py +19 -0
  350. endoreg_db/models/medical/medication/medication.py +31 -0
  351. endoreg_db/models/medical/medication/medication_indication.py +50 -0
  352. endoreg_db/models/medical/medication/medication_indication_type.py +39 -0
  353. endoreg_db/models/medical/medication/medication_intake_time.py +44 -0
  354. endoreg_db/models/medical/medication/medication_schedule.py +45 -0
  355. endoreg_db/models/medical/organ/__init__.py +35 -0
  356. endoreg_db/models/medical/patient/__init__.py +56 -0
  357. endoreg_db/models/medical/patient/medication_examples.py +38 -0
  358. endoreg_db/models/medical/patient/patient_disease.py +63 -0
  359. endoreg_db/models/medical/patient/patient_event.py +75 -0
  360. endoreg_db/models/medical/patient/patient_examination.py +249 -0
  361. endoreg_db/models/medical/patient/patient_examination_indication.py +44 -0
  362. endoreg_db/models/medical/patient/patient_finding.py +357 -0
  363. endoreg_db/models/medical/patient/patient_finding_classification.py +207 -0
  364. endoreg_db/models/medical/patient/patient_finding_intervention.py +40 -0
  365. endoreg_db/models/medical/patient/patient_lab_sample.py +148 -0
  366. endoreg_db/models/{persons → medical}/patient/patient_lab_value.py +68 -22
  367. endoreg_db/models/medical/patient/patient_medication.py +104 -0
  368. endoreg_db/models/medical/patient/patient_medication_schedule.py +136 -0
  369. endoreg_db/models/medical/risk/__init__.py +7 -0
  370. endoreg_db/models/medical/risk/risk.py +72 -0
  371. endoreg_db/models/medical/risk/risk_type.py +51 -0
  372. endoreg_db/models/metadata/__init__.py +19 -0
  373. endoreg_db/models/metadata/frame_ocr_result.py +0 -0
  374. endoreg_db/models/metadata/model_meta.py +206 -0
  375. endoreg_db/models/metadata/model_meta_logic.py +343 -0
  376. endoreg_db/models/{data_file/metadata → metadata}/pdf_meta.py +32 -13
  377. endoreg_db/models/metadata/sensitive_meta.py +288 -0
  378. endoreg_db/models/metadata/sensitive_meta_logic.py +1048 -0
  379. endoreg_db/models/metadata/video_meta.py +332 -0
  380. endoreg_db/models/metadata/video_prediction_logic.py +190 -0
  381. endoreg_db/models/metadata/video_prediction_meta.py +270 -0
  382. endoreg_db/models/other/__init__.py +36 -1
  383. endoreg_db/models/other/distribution/__init__.py +44 -0
  384. endoreg_db/models/other/distribution/base_value_distribution.py +20 -0
  385. endoreg_db/models/other/distribution/date_value_distribution.py +89 -0
  386. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +32 -0
  387. endoreg_db/models/other/distribution/numeric_value_distribution.py +125 -0
  388. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +22 -0
  389. endoreg_db/models/other/emission/__init__.py +5 -0
  390. endoreg_db/models/other/emission/emission_factor.py +94 -0
  391. endoreg_db/models/{persons → other}/gender.py +8 -3
  392. endoreg_db/models/other/information_source.py +159 -0
  393. endoreg_db/models/other/material.py +14 -2
  394. endoreg_db/models/other/resource.py +6 -2
  395. endoreg_db/models/other/tag.py +27 -0
  396. endoreg_db/models/other/transport_route.py +15 -3
  397. endoreg_db/models/{unit.py → other/unit.py} +16 -6
  398. endoreg_db/models/other/waste.py +10 -3
  399. endoreg_db/models/requirement/__init__.py +11 -0
  400. endoreg_db/models/requirement/requirement.py +767 -0
  401. endoreg_db/models/requirement/requirement_evaluation/__init__.py +6 -0
  402. endoreg_db/models/requirement/requirement_evaluation/get_values.py +40 -0
  403. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +9 -0
  404. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +95 -0
  405. endoreg_db/models/requirement/requirement_operator.py +176 -0
  406. endoreg_db/models/requirement/requirement_set.py +287 -0
  407. endoreg_db/models/rule/__init__.py +13 -0
  408. endoreg_db/models/{rules → rule}/rule.py +6 -3
  409. endoreg_db/models/{rules → rule}/rule_attribute_dtype.py +0 -2
  410. endoreg_db/models/{rules → rule}/rule_type.py +0 -2
  411. endoreg_db/models/{rules → rule}/ruleset.py +0 -2
  412. endoreg_db/models/state/__init__.py +12 -0
  413. endoreg_db/models/state/abstract.py +11 -0
  414. endoreg_db/models/state/audit_ledger.py +150 -0
  415. endoreg_db/models/state/label_video_segment.py +22 -0
  416. endoreg_db/models/state/raw_pdf.py +187 -0
  417. endoreg_db/models/state/sensitive_meta.py +46 -0
  418. endoreg_db/models/state/video.py +232 -0
  419. endoreg_db/models/upload_job.py +99 -0
  420. endoreg_db/models/utils.py +135 -0
  421. endoreg_db/renames.yml +8 -0
  422. endoreg_db/root_urls.py +9 -0
  423. endoreg_db/schemas/__init__.py +0 -0
  424. endoreg_db/schemas/examination_evaluation.py +27 -0
  425. endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +775 -0
  426. endoreg_db/serializers/__init__.py +118 -10
  427. endoreg_db/serializers/_old/raw_pdf_meta_validation.py +223 -0
  428. endoreg_db/serializers/_old/raw_video_meta_validation.py +179 -0
  429. endoreg_db/serializers/_old/video.py +71 -0
  430. endoreg_db/serializers/administration/__init__.py +14 -0
  431. endoreg_db/serializers/administration/ai/__init__.py +10 -0
  432. endoreg_db/serializers/administration/ai/active_model.py +10 -0
  433. endoreg_db/serializers/administration/ai/ai_model.py +18 -0
  434. endoreg_db/serializers/administration/ai/model_type.py +10 -0
  435. endoreg_db/serializers/administration/center.py +9 -0
  436. endoreg_db/serializers/administration/gender.py +9 -0
  437. endoreg_db/serializers/anonymization.py +69 -0
  438. endoreg_db/serializers/evaluation/examination_evaluation.py +1 -0
  439. endoreg_db/serializers/examination/__init__.py +10 -0
  440. endoreg_db/serializers/examination/base.py +46 -0
  441. endoreg_db/serializers/examination/dropdown.py +21 -0
  442. endoreg_db/serializers/examination_serializer.py +12 -0
  443. endoreg_db/serializers/finding/__init__.py +5 -0
  444. endoreg_db/serializers/finding/finding.py +54 -0
  445. endoreg_db/serializers/finding_classification/__init__.py +7 -0
  446. endoreg_db/serializers/finding_classification/choice.py +19 -0
  447. endoreg_db/serializers/finding_classification/classification.py +13 -0
  448. endoreg_db/serializers/label/__init__.py +7 -0
  449. endoreg_db/serializers/label/image_classification_annotation.py +62 -0
  450. endoreg_db/serializers/label/label.py +15 -0
  451. endoreg_db/serializers/label_video_segment/__init__.py +7 -0
  452. endoreg_db/serializers/label_video_segment/_lvs_create.py +149 -0
  453. endoreg_db/serializers/label_video_segment/_lvs_update.py +138 -0
  454. endoreg_db/serializers/label_video_segment/_lvs_validate.py +149 -0
  455. endoreg_db/serializers/label_video_segment/label_video_segment.py +344 -0
  456. endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +99 -0
  457. endoreg_db/serializers/label_video_segment/label_video_segment_update.py +163 -0
  458. endoreg_db/serializers/meta/__init__.py +19 -0
  459. endoreg_db/serializers/meta/pdf_file_meta_extraction.py +115 -0
  460. endoreg_db/serializers/meta/report_meta.py +53 -0
  461. endoreg_db/serializers/meta/sensitive_meta_detail.py +162 -0
  462. endoreg_db/serializers/meta/sensitive_meta_update.py +148 -0
  463. endoreg_db/serializers/meta/sensitive_meta_verification.py +59 -0
  464. endoreg_db/serializers/meta/video_meta.py +39 -0
  465. endoreg_db/serializers/misc/__init__.py +14 -0
  466. endoreg_db/serializers/misc/file_overview.py +182 -0
  467. endoreg_db/serializers/misc/sensitive_patient_data.py +120 -0
  468. endoreg_db/serializers/misc/stats.py +33 -0
  469. endoreg_db/serializers/misc/translatable_field_mix_in.py +44 -0
  470. endoreg_db/serializers/misc/upload_job.py +71 -0
  471. endoreg_db/serializers/patient/__init__.py +11 -0
  472. endoreg_db/serializers/patient/patient.py +86 -0
  473. endoreg_db/serializers/patient/patient_dropdown.py +27 -0
  474. endoreg_db/serializers/patient_examination/__init__.py +7 -0
  475. endoreg_db/serializers/patient_examination/patient_examination.py +141 -0
  476. endoreg_db/serializers/patient_finding/__init__.py +15 -0
  477. endoreg_db/serializers/patient_finding/patient_finding.py +31 -0
  478. endoreg_db/serializers/patient_finding/patient_finding_classification.py +39 -0
  479. endoreg_db/serializers/patient_finding/patient_finding_detail.py +53 -0
  480. endoreg_db/serializers/patient_finding/patient_finding_intervention.py +26 -0
  481. endoreg_db/serializers/patient_finding/patient_finding_list.py +41 -0
  482. endoreg_db/serializers/patient_finding/patient_finding_write.py +126 -0
  483. endoreg_db/serializers/pdf/__init__.py +5 -0
  484. endoreg_db/serializers/pdf/anony_text_validation.py +85 -0
  485. endoreg_db/serializers/report/__init__.py +9 -0
  486. endoreg_db/serializers/report/mixins.py +45 -0
  487. endoreg_db/serializers/report/report.py +105 -0
  488. endoreg_db/serializers/report/report_list.py +22 -0
  489. endoreg_db/serializers/report/secure_file_url.py +26 -0
  490. endoreg_db/serializers/requirements/requirement_schema.py +25 -0
  491. endoreg_db/serializers/requirements/requirement_sets.py +29 -0
  492. endoreg_db/serializers/sensitive_meta_serializer.py +282 -0
  493. endoreg_db/serializers/video/__init__.py +7 -0
  494. endoreg_db/serializers/video/segmentation.py +263 -0
  495. endoreg_db/serializers/video/video_file_brief.py +10 -0
  496. endoreg_db/serializers/video/video_file_detail.py +83 -0
  497. endoreg_db/serializers/video/video_file_list.py +67 -0
  498. endoreg_db/serializers/video/video_metadata.py +105 -0
  499. endoreg_db/serializers/video/video_processing_history.py +153 -0
  500. endoreg_db/serializers/video_examination.py +198 -0
  501. endoreg_db/services/__init__.py +5 -0
  502. endoreg_db/services/anonymization.py +223 -0
  503. endoreg_db/services/examination_evaluation.py +149 -0
  504. endoreg_db/services/finding_description_service.py +0 -0
  505. endoreg_db/services/lookup_service.py +411 -0
  506. endoreg_db/services/lookup_store.py +266 -0
  507. endoreg_db/services/pdf_import.py +1382 -0
  508. endoreg_db/services/polling_coordinator.py +288 -0
  509. endoreg_db/services/pseudonym_service.py +89 -0
  510. endoreg_db/services/requirements_object.py +147 -0
  511. endoreg_db/services/segment_sync.py +155 -0
  512. endoreg_db/services/storage_aware_video_processor.py +344 -0
  513. endoreg_db/services/video_import.py +1259 -0
  514. endoreg_db/tasks/upload_tasks.py +207 -0
  515. endoreg_db/tasks/video_ingest.py +157 -0
  516. endoreg_db/tasks/video_processing_tasks.py +327 -0
  517. endoreg_db/templates/admin/patient_finding_intervention.html +253 -0
  518. endoreg_db/templates/admin/start_examination.html +12 -0
  519. endoreg_db/templates/timeline.html +176 -0
  520. endoreg_db/urls/__init__.py +83 -0
  521. endoreg_db/urls/anonymization.py +32 -0
  522. endoreg_db/urls/auth.py +16 -0
  523. endoreg_db/urls/classification.py +39 -0
  524. endoreg_db/urls/examination.py +54 -0
  525. endoreg_db/urls/files.py +6 -0
  526. endoreg_db/urls/label_video_segment_validate.py +33 -0
  527. endoreg_db/urls/label_video_segments.py +46 -0
  528. endoreg_db/urls/media.py +227 -0
  529. endoreg_db/urls/patient.py +19 -0
  530. endoreg_db/urls/report.py +48 -0
  531. endoreg_db/urls/requirements.py +13 -0
  532. endoreg_db/urls/sensitive_meta.py +0 -0
  533. endoreg_db/urls/stats.py +46 -0
  534. endoreg_db/urls/upload.py +20 -0
  535. endoreg_db/urls/video.py +61 -0
  536. endoreg_db/urls.py +9 -0
  537. endoreg_db/utils/__init__.py +88 -1
  538. endoreg_db/utils/ai/__init__.py +9 -0
  539. endoreg_db/{models/ai_model/utils.py → utils/ai/get.py} +1 -4
  540. endoreg_db/utils/ai/inference_dataset.py +52 -0
  541. endoreg_db/utils/ai/multilabel_classification_net.py +159 -0
  542. endoreg_db/utils/ai/postprocess.py +63 -0
  543. endoreg_db/utils/ai/predict.py +291 -0
  544. endoreg_db/utils/ai/preprocess.py +68 -0
  545. endoreg_db/utils/calc_duration_seconds.py +24 -0
  546. endoreg_db/utils/case_generator/__init__.py +0 -0
  547. endoreg_db/utils/case_generator/case_generator.py +159 -0
  548. endoreg_db/utils/case_generator/lab_sample_factory.py +33 -0
  549. endoreg_db/utils/case_generator/utils.py +30 -0
  550. endoreg_db/utils/check_video_files.py +148 -0
  551. endoreg_db/utils/dataloader.py +118 -35
  552. endoreg_db/utils/dates.py +60 -0
  553. endoreg_db/utils/env.py +33 -0
  554. endoreg_db/utils/extract_specific_frames.py +72 -0
  555. endoreg_db/utils/file_operations.py +29 -1
  556. endoreg_db/utils/fix_video_path_direct.py +141 -0
  557. endoreg_db/utils/frame_anonymization_utils.py +463 -0
  558. endoreg_db/utils/hashs.py +123 -4
  559. endoreg_db/utils/links/__init__.py +0 -0
  560. endoreg_db/utils/links/requirement_link.py +193 -0
  561. endoreg_db/utils/mime_types.py +0 -0
  562. endoreg_db/utils/names.py +76 -0
  563. endoreg_db/utils/parse_and_generate_yaml.py +46 -0
  564. endoreg_db/utils/paths.py +95 -0
  565. endoreg_db/utils/permissions.py +143 -0
  566. endoreg_db/utils/pipelines/Readme.md +235 -0
  567. endoreg_db/utils/pipelines/__init__.py +0 -0
  568. endoreg_db/utils/pipelines/process_video_dir.py +120 -0
  569. endoreg_db/utils/product/__init__.py +0 -0
  570. endoreg_db/utils/product/sum_emissions.py +20 -0
  571. endoreg_db/utils/product/sum_weights.py +18 -0
  572. endoreg_db/utils/pydantic_models/__init__.py +6 -0
  573. endoreg_db/utils/pydantic_models/db_config.py +57 -0
  574. endoreg_db/utils/requirement_helpers.py +0 -0
  575. endoreg_db/utils/requirement_operator_logic/__init__.py +0 -0
  576. endoreg_db/utils/requirement_operator_logic/lab_value_operators.py +578 -0
  577. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +368 -0
  578. endoreg_db/utils/setup_config.py +177 -0
  579. endoreg_db/utils/translation.py +27 -0
  580. endoreg_db/utils/validate_endo_roi.py +19 -0
  581. endoreg_db/utils/validate_subcategory_dict.py +91 -0
  582. endoreg_db/utils/validate_video_detailed.py +357 -0
  583. endoreg_db/utils/video/__init__.py +26 -0
  584. endoreg_db/utils/video/extract_frames.py +88 -0
  585. endoreg_db/utils/video/ffmpeg_wrapper.py +835 -0
  586. endoreg_db/utils/video/names.py +42 -0
  587. endoreg_db/utils/video/streaming_processor.py +312 -0
  588. endoreg_db/utils/video/video_splitter.py +94 -0
  589. endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +238 -0
  590. endoreg_db/views/__init__.py +274 -0
  591. endoreg_db/views/anonymization/__init__.py +27 -0
  592. endoreg_db/views/anonymization/media_management.py +454 -0
  593. endoreg_db/views/anonymization/overview.py +216 -0
  594. endoreg_db/views/anonymization/validate.py +107 -0
  595. endoreg_db/views/auth/__init__.py +13 -0
  596. endoreg_db/views/auth/keycloak.py +113 -0
  597. endoreg_db/views/examination/__init__.py +33 -0
  598. endoreg_db/views/examination/examination.py +37 -0
  599. endoreg_db/views/examination/examination_manifest_cache.py +26 -0
  600. endoreg_db/views/examination/get_finding_classification_choices.py +59 -0
  601. endoreg_db/views/examination/get_finding_classifications.py +36 -0
  602. endoreg_db/views/examination/get_findings.py +41 -0
  603. endoreg_db/views/examination/get_instruments.py +18 -0
  604. endoreg_db/views/examination/get_interventions.py +14 -0
  605. endoreg_db/views/finding/__init__.py +9 -0
  606. endoreg_db/views/finding/finding.py +112 -0
  607. endoreg_db/views/finding/get_classifications.py +14 -0
  608. endoreg_db/views/finding/get_interventions.py +17 -0
  609. endoreg_db/views/finding_classification/__init__.py +13 -0
  610. endoreg_db/views/finding_classification/base.py +0 -0
  611. endoreg_db/views/finding_classification/finding_classification.py +42 -0
  612. endoreg_db/views/finding_classification/get_classification_choices.py +55 -0
  613. endoreg_db/views/label/__init__.py +5 -0
  614. endoreg_db/views/label/label.py +15 -0
  615. endoreg_db/views/label_video_segment/__init__.py +16 -0
  616. endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +44 -0
  617. endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +50 -0
  618. endoreg_db/views/label_video_segment/label_video_segment.py +77 -0
  619. endoreg_db/views/label_video_segment/label_video_segment_by_label.py +174 -0
  620. endoreg_db/views/label_video_segment/label_video_segment_detail.py +73 -0
  621. endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +46 -0
  622. endoreg_db/views/label_video_segment/validate.py +226 -0
  623. endoreg_db/views/media/__init__.py +45 -0
  624. endoreg_db/views/media/pdf_media.py +388 -0
  625. endoreg_db/views/media/segments.py +71 -0
  626. endoreg_db/views/media/sensitive_metadata.py +314 -0
  627. endoreg_db/views/media/video_media.py +272 -0
  628. endoreg_db/views/media/video_segments.py +524 -0
  629. endoreg_db/views/meta/__init__.py +15 -0
  630. endoreg_db/views/meta/available_files_list.py +146 -0
  631. endoreg_db/views/meta/report_meta.py +53 -0
  632. endoreg_db/views/meta/sensitive_meta_detail.py +148 -0
  633. endoreg_db/views/meta/sensitive_meta_list.py +104 -0
  634. endoreg_db/views/meta/sensitive_meta_verification.py +71 -0
  635. endoreg_db/views/misc/__init__.py +63 -0
  636. endoreg_db/views/misc/center.py +13 -0
  637. endoreg_db/views/misc/csrf.py +7 -0
  638. endoreg_db/views/misc/gender.py +14 -0
  639. endoreg_db/views/misc/secure_file_serving_view.py +80 -0
  640. endoreg_db/views/misc/secure_file_url_view.py +84 -0
  641. endoreg_db/views/misc/secure_url_validate.py +79 -0
  642. endoreg_db/views/misc/stats.py +220 -0
  643. endoreg_db/views/misc/translation.py +182 -0
  644. endoreg_db/views/misc/upload_views.py +240 -0
  645. endoreg_db/views/patient/__init__.py +5 -0
  646. endoreg_db/views/patient/patient.py +210 -0
  647. endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +164 -0
  648. endoreg_db/views/patient_examination/__init__.py +11 -0
  649. endoreg_db/views/patient_examination/patient_examination.py +140 -0
  650. endoreg_db/views/patient_examination/patient_examination_create.py +63 -0
  651. endoreg_db/views/patient_examination/patient_examination_detail.py +66 -0
  652. endoreg_db/views/patient_examination/patient_examination_list.py +68 -0
  653. endoreg_db/views/patient_examination/video.py +194 -0
  654. endoreg_db/views/patient_finding/__init__.py +7 -0
  655. endoreg_db/views/patient_finding/base.py +0 -0
  656. endoreg_db/views/patient_finding/patient_finding.py +64 -0
  657. endoreg_db/views/patient_finding/patient_finding_optimized.py +259 -0
  658. endoreg_db/views/patient_finding_classification/__init__.py +5 -0
  659. endoreg_db/views/patient_finding_classification/pfc_create.py +67 -0
  660. endoreg_db/views/patient_finding_location/__init__.py +5 -0
  661. endoreg_db/views/patient_finding_location/pfl_create.py +70 -0
  662. endoreg_db/views/patient_finding_morphology/__init__.py +5 -0
  663. endoreg_db/views/patient_finding_morphology/pfm_create.py +70 -0
  664. endoreg_db/views/pdf/__init__.py +8 -0
  665. endoreg_db/views/pdf/pdf_stream.py +187 -0
  666. endoreg_db/views/pdf/reimport.py +177 -0
  667. endoreg_db/views/report/__init__.py +9 -0
  668. endoreg_db/views/report/report_list.py +112 -0
  669. endoreg_db/views/report/report_with_secure_url.py +28 -0
  670. endoreg_db/views/report/start_examination.py +7 -0
  671. endoreg_db/views/requirement/__init__.py +10 -0
  672. endoreg_db/views/requirement/evaluate.py +279 -0
  673. endoreg_db/views/requirement/lookup.py +367 -0
  674. endoreg_db/views/requirement/lookup_store.py +252 -0
  675. endoreg_db/views/requirement_lookup/lookup.py +0 -0
  676. endoreg_db/views/requirement_lookup/lookup_store.py +0 -0
  677. endoreg_db/views/stats/__init__.py +13 -0
  678. endoreg_db/views/stats/stats_views.py +229 -0
  679. endoreg_db/views/video/__init__.py +59 -0
  680. endoreg_db/views/video/correction.py +530 -0
  681. endoreg_db/views/video/reimport.py +195 -0
  682. endoreg_db/views/video/segmentation.py +274 -0
  683. endoreg_db/views/video/task_status.py +49 -0
  684. endoreg_db/views/video/timeline.py +46 -0
  685. endoreg_db/views/video/video_analyze.py +52 -0
  686. endoreg_db/views/video/video_apply_mask.py +48 -0
  687. endoreg_db/views/video/video_correction.py +21 -0
  688. endoreg_db/views/video/video_download_processed.py +58 -0
  689. endoreg_db/views/video/video_examination_viewset.py +242 -0
  690. endoreg_db/views/video/video_meta.py +29 -0
  691. endoreg_db/views/video/video_processing_history.py +24 -0
  692. endoreg_db/views/video/video_remove_frames.py +48 -0
  693. endoreg_db/views/video/video_stream.py +306 -0
  694. endoreg_db/views.py +0 -3
  695. endoreg_db-0.8.6.3.dist-info/METADATA +383 -0
  696. endoreg_db-0.8.6.3.dist-info/RECORD +793 -0
  697. {endoreg_db-0.4.5.dist-info → endoreg_db-0.8.6.3.dist-info}/WHEEL +1 -1
  698. endoreg_db/data/active_model/data.yaml +0 -3
  699. endoreg_db/data/agl_service/data.yaml +0 -19
  700. endoreg_db/data/label/label-set/data.yaml +0 -18
  701. endoreg_db/management/commands/_load_model_template.py +0 -41
  702. endoreg_db/management/commands/delete_all.py +0 -18
  703. endoreg_db/management/commands/delete_legacy_images.py +0 -19
  704. endoreg_db/management/commands/delete_legacy_videos.py +0 -17
  705. endoreg_db/management/commands/extract_legacy_video_frames.py +0 -18
  706. endoreg_db/management/commands/fetch_legacy_image_dataset.py +0 -32
  707. endoreg_db/management/commands/fix_auth_permission.py +0 -20
  708. endoreg_db/management/commands/import_legacy_images.py +0 -94
  709. endoreg_db/management/commands/import_legacy_videos.py +0 -76
  710. endoreg_db/management/commands/load_active_model_data.py +0 -45
  711. endoreg_db/management/commands/load_endoscopy_processor_data.py +0 -45
  712. endoreg_db/management/commands/load_g_play_data.py +0 -113
  713. endoreg_db/management/commands/load_label_data.py +0 -67
  714. endoreg_db/management/commands/load_medication_indication_data.py +0 -63
  715. endoreg_db/management/commands/load_medication_indication_type_data.py +0 -41
  716. endoreg_db/management/commands/load_medication_schedule_data.py +0 -55
  717. endoreg_db/management/commands/load_network_data.py +0 -57
  718. endoreg_db/migrations/0002_anonymizedimagelabel_anonymousimageannotation_and_more.py +0 -55
  719. endoreg_db/migrations/0003_anonymousimageannotation_original_image_url_and_more.py +0 -39
  720. endoreg_db/migrations/0004_alter_rawpdffile_file.py +0 -20
  721. endoreg_db/migrations/0005_uploadedfile_alter_rawpdffile_file_anonymizedfile.py +0 -40
  722. endoreg_db/migrations/0006_alter_rawpdffile_file.py +0 -20
  723. endoreg_db/migrations/0007_networkdevicelogentry_datetime_and_more.py +0 -43
  724. endoreg_db/models/ai_model/__init__.py +0 -3
  725. endoreg_db/models/ai_model/active_model.py +0 -9
  726. endoreg_db/models/ai_model/model_meta.py +0 -24
  727. endoreg_db/models/annotation/__init__.py +0 -3
  728. endoreg_db/models/annotation/anonymized_image_annotation.py +0 -60
  729. endoreg_db/models/annotation/binary_classification_annotation_task.py +0 -80
  730. endoreg_db/models/annotation/image_classification.py +0 -27
  731. endoreg_db/models/center/center.py +0 -25
  732. endoreg_db/models/center/center_product.py +0 -34
  733. endoreg_db/models/center/center_resource.py +0 -19
  734. endoreg_db/models/center/center_waste.py +0 -11
  735. endoreg_db/models/data_file/__init__.py +0 -6
  736. endoreg_db/models/data_file/base_classes/__init__.py +0 -2
  737. endoreg_db/models/data_file/base_classes/abstract_frame.py +0 -51
  738. endoreg_db/models/data_file/base_classes/abstract_video.py +0 -201
  739. endoreg_db/models/data_file/frame.py +0 -45
  740. endoreg_db/models/data_file/import_classes/__init__.py +0 -32
  741. endoreg_db/models/data_file/import_classes/processing_functions/__init__.py +0 -35
  742. endoreg_db/models/data_file/import_classes/processing_functions/pdf.py +0 -28
  743. endoreg_db/models/data_file/import_classes/processing_functions/video.py +0 -260
  744. endoreg_db/models/data_file/import_classes/raw_pdf.py +0 -188
  745. endoreg_db/models/data_file/import_classes/raw_video.py +0 -343
  746. endoreg_db/models/data_file/metadata/__init__.py +0 -3
  747. endoreg_db/models/data_file/metadata/sensitive_meta.py +0 -31
  748. endoreg_db/models/data_file/metadata/video_meta.py +0 -133
  749. endoreg_db/models/data_file/report_file.py +0 -89
  750. endoreg_db/models/data_file/video/__init__.py +0 -7
  751. endoreg_db/models/data_file/video/import_meta.py +0 -25
  752. endoreg_db/models/data_file/video/video.py +0 -25
  753. endoreg_db/models/data_file/video_segment.py +0 -107
  754. endoreg_db/models/disease.py +0 -56
  755. endoreg_db/models/emission/__init__.py +0 -1
  756. endoreg_db/models/emission/emission_factor.py +0 -20
  757. endoreg_db/models/event.py +0 -22
  758. endoreg_db/models/examination/__init__.py +0 -4
  759. endoreg_db/models/examination/examination.py +0 -26
  760. endoreg_db/models/examination/examination_time.py +0 -27
  761. endoreg_db/models/examination/examination_time_type.py +0 -24
  762. endoreg_db/models/examination/examination_type.py +0 -18
  763. endoreg_db/models/hardware/__init__.py +0 -2
  764. endoreg_db/models/hardware/endoscope.py +0 -44
  765. endoreg_db/models/information_source.py +0 -29
  766. endoreg_db/models/laboratory/__init__.py +0 -1
  767. endoreg_db/models/laboratory/lab_value.py +0 -102
  768. endoreg_db/models/legacy_data/__init__.py +0 -3
  769. endoreg_db/models/legacy_data/image.py +0 -34
  770. endoreg_db/models/logging/__init__.py +0 -4
  771. endoreg_db/models/logging/agl_service.py +0 -19
  772. endoreg_db/models/logging/base.py +0 -22
  773. endoreg_db/models/logging/log_type.py +0 -23
  774. endoreg_db/models/logging/network_device.py +0 -24
  775. endoreg_db/models/medication/__init__.py +0 -1
  776. endoreg_db/models/medication/medication.py +0 -148
  777. endoreg_db/models/network/__init__.py +0 -3
  778. endoreg_db/models/network/agl_service.py +0 -38
  779. endoreg_db/models/network/network_device.py +0 -53
  780. endoreg_db/models/network/network_device_type.py +0 -23
  781. endoreg_db/models/other/distribution.py +0 -215
  782. endoreg_db/models/patient_examination/__init__.py +0 -35
  783. endoreg_db/models/permissions/__init__.py +0 -44
  784. endoreg_db/models/persons/__init__.py +0 -7
  785. endoreg_db/models/persons/examiner/__init__.py +0 -2
  786. endoreg_db/models/persons/examiner/examiner.py +0 -16
  787. endoreg_db/models/persons/examiner/examiner_type.py +0 -2
  788. endoreg_db/models/persons/patient/__init__.py +0 -8
  789. endoreg_db/models/persons/patient/case/case.py +0 -30
  790. endoreg_db/models/persons/patient/patient.py +0 -216
  791. endoreg_db/models/persons/patient/patient_disease.py +0 -16
  792. endoreg_db/models/persons/patient/patient_event.py +0 -22
  793. endoreg_db/models/persons/patient/patient_lab_sample.py +0 -106
  794. endoreg_db/models/persons/patient/patient_medication.py +0 -44
  795. endoreg_db/models/persons/patient/patient_medication_schedule.py +0 -28
  796. endoreg_db/models/persons/portal_user_information.py +0 -27
  797. endoreg_db/models/prediction/__init__.py +0 -2
  798. endoreg_db/models/prediction/image_classification.py +0 -37
  799. endoreg_db/models/prediction/video_prediction_meta.py +0 -244
  800. endoreg_db/models/product/__init__.py +0 -5
  801. endoreg_db/models/product/product.py +0 -97
  802. endoreg_db/models/product/product_group.py +0 -19
  803. endoreg_db/models/product/product_material.py +0 -24
  804. endoreg_db/models/questionnaires/__init__.py +0 -114
  805. endoreg_db/models/quiz/__init__.py +0 -2
  806. endoreg_db/models/quiz/quiz_answer.py +0 -41
  807. endoreg_db/models/quiz/quiz_question.py +0 -54
  808. endoreg_db/models/report_reader/__init__.py +0 -2
  809. endoreg_db/models/report_reader/report_reader_config.py +0 -53
  810. endoreg_db/models/rules/__init__.py +0 -5
  811. endoreg_db/queries/get/__init__.py +0 -6
  812. endoreg_db/queries/get/center.py +0 -42
  813. endoreg_db/queries/get/model.py +0 -13
  814. endoreg_db/queries/get/patient.py +0 -14
  815. endoreg_db/queries/get/patient_examination.py +0 -20
  816. endoreg_db/queries/get/report_file.py +0 -33
  817. endoreg_db/queries/get/video.py +0 -31
  818. endoreg_db/serializers/ai_model.py +0 -19
  819. endoreg_db/serializers/annotation.py +0 -17
  820. endoreg_db/serializers/center.py +0 -11
  821. endoreg_db/serializers/examination.py +0 -33
  822. endoreg_db/serializers/frame.py +0 -13
  823. endoreg_db/serializers/hardware.py +0 -21
  824. endoreg_db/serializers/label.py +0 -22
  825. endoreg_db/serializers/patient.py +0 -10
  826. endoreg_db/serializers/prediction.py +0 -15
  827. endoreg_db/serializers/report_file.py +0 -7
  828. endoreg_db/serializers/video.py +0 -27
  829. endoreg_db/tests.py +0 -3
  830. endoreg_db/utils/legacy_ocr.py +0 -201
  831. endoreg_db/utils/video_metadata.py +0 -87
  832. endoreg_db-0.4.5.dist-info/METADATA +0 -34
  833. endoreg_db-0.4.5.dist-info/RECORD +0 -316
  834. /endoreg_db/{data/distribution/numeric/.init → api/serializers/finding_descriptions.py} +0 -0
  835. /endoreg_db/{models/persons/patient/case/__init__.py → api/views/finding_descriptions.py} +0 -0
  836. /endoreg_db/{queries/get/annotation.py → config/__init__.py} +0 -0
  837. /endoreg_db/data/{label → ai_model_label}/label-type/data.yaml +0 -0
  838. /endoreg_db/data/{model_type → ai_model_type}/data.yaml +0 -0
  839. /endoreg_db/{queries/get/prediction.py → data/shift/m2.yaml} +0 -0
  840. /endoreg_db/{queries/get/video_import_meta.py → factories/__init__.py} +0 -0
  841. /endoreg_db/{queries/get/video_prediction_meta.py → helpers/__init__.py} +0 -0
  842. /endoreg_db/management/commands/{load_report_reader_flag.py → load_report_reader_flag_data.py} +0 -0
  843. /endoreg_db/models/{persons → administration/person}/person.py +0 -0
  844. /endoreg_db/models/{report_reader → media/pdf/report_reader}/report_reader_flag.py +0 -0
  845. /endoreg_db/models/{rules → rule}/rule_applicator.py +0 -0
  846. {endoreg_db-0.4.5.dist-info → endoreg_db-0.8.6.3.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,767 @@
1
+ from django.db import models
2
+ from typing import TYPE_CHECKING, Dict, List, Union
3
+ from endoreg_db.utils.links.requirement_link import RequirementLinks
4
+ import logging
5
+ from subprocess import run
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ QuerySet = models.QuerySet
11
+
12
+ if TYPE_CHECKING:
13
+ from endoreg_db.models import (
14
+ Disease,
15
+ DiseaseClassificationChoice,
16
+ Event,
17
+ EventClassification,
18
+ EventClassificationChoice,
19
+ Examination,
20
+ ExaminationIndication,
21
+ Finding,
22
+ FindingIntervention,
23
+ FindingClassification,
24
+ FindingClassificationChoice,
25
+ FindingClassificationType,
26
+ LabValue,
27
+ Medication,
28
+ MedicationIndication,
29
+ MedicationIntakeTime, # Added MedicationIntakeTime
30
+ MedicationSchedule,
31
+ PatientDisease,
32
+ PatientEvent,
33
+ PatientExamination,
34
+ PatientFinding,
35
+ PatientFindingIntervention,
36
+ PatientFindingClassification,
37
+ PatientLabValue,
38
+ PatientMedicationSchedule, # Added PatientMedicationSchedule
39
+ RequirementOperator,
40
+ RequirementSet,
41
+ Gender
42
+ )
43
+ # from endoreg_db.utils.links.requirement_link import RequirementLinks # Already imported above
44
+
45
+
46
+ class RequirementTypeManager(models.Manager):
47
+ def get_by_natural_key(self, name):
48
+ """
49
+ Retrieve a model instance using its natural key.
50
+
51
+ Queries the database for an instance with a matching name, serving as the natural key.
52
+
53
+ Args:
54
+ name: The natural key identifying the model instance.
55
+
56
+ Returns:
57
+ The model instance matching the provided natural key.
58
+ """
59
+ return self.get(name=name)
60
+
61
+
62
+ class RequirementType(models.Model):
63
+ """
64
+ A class representing a type of requirement.
65
+
66
+ Attributes:
67
+ name (str): The name of the requirement type.
68
+ """
69
+
70
+ name = models.CharField(max_length=100, unique=True)
71
+ description = models.TextField(blank=True, null=True)
72
+
73
+ objects = RequirementTypeManager()
74
+
75
+ def natural_key(self):
76
+ """
77
+ Return the natural key for the instance as a tuple containing its name.
78
+
79
+ This tuple enables the use of natural key lookups for serialization and deserialization.
80
+ """
81
+ return (self.name,)
82
+
83
+ def __str__(self):
84
+ """Return the string representation of the requirement type's name.
85
+
86
+ Returns:
87
+ str: The name of the requirement type.
88
+ """
89
+ return str(self.name)
90
+
91
+
92
+ class RequirementManager(models.Manager):
93
+ def get_by_natural_key(self, name):
94
+ """
95
+ Retrieve an instance using its natural key.
96
+
97
+ Args:
98
+ name: The natural key used to look up the instance.
99
+
100
+ Returns:
101
+ The object whose 'name' field matches the given key.
102
+ """
103
+ return self.get(name=name)
104
+
105
+
106
+ class Requirement(models.Model):
107
+ """
108
+ A class representing a requirement.
109
+
110
+ Attributes:
111
+ name (str): The name of the requirement.
112
+ description (str): A description of the requirement.
113
+ """
114
+
115
+ name = models.CharField(max_length=100, unique=True)
116
+ description = models.TextField(blank=True, null=True)
117
+
118
+ numeric_value = models.FloatField(
119
+ blank=True,
120
+ null=True,
121
+ help_text="Numeric value for the requirement. If not set, the requirement is not used in calculations.",
122
+ )
123
+
124
+ numeric_value_min = models.FloatField(
125
+ blank=True,
126
+ null=True,
127
+ help_text="Minimum numeric value for the requirement. If not set, the requirement is not used in calculations.",
128
+ )
129
+ numeric_value_max = models.FloatField(
130
+ blank=True,
131
+ null=True,
132
+ help_text="Maximum numeric value for the requirement. If not set, the requirement is not used in calculations.",
133
+ )
134
+
135
+ string_value = models.CharField(
136
+ max_length=100,
137
+ blank=True,
138
+ null=True,
139
+ help_text="String value for the requirement. If not set, the requirement is not used in calculations.",
140
+ )
141
+
142
+ string_values = models.TextField(
143
+ blank=True,
144
+ null=True,
145
+ help_text=" ','-separated list of string values for the requirement.If not set, the requirement is not used in calculations.",
146
+ )
147
+
148
+ objects = RequirementManager()
149
+
150
+ requirement_types = models.ManyToManyField( # type: ignore[assignment]
151
+ "RequirementType",
152
+ blank=True,
153
+ related_name="linked_requirements",
154
+ )
155
+
156
+ operators = models.ManyToManyField( # type: ignore[assignment]
157
+ "RequirementOperator",
158
+ blank=True,
159
+ related_name="required_in",
160
+ )
161
+
162
+ unit = models.ForeignKey(
163
+ "Unit",
164
+ on_delete=models.CASCADE,
165
+ related_name="required_in",
166
+ blank=True,
167
+ null=True,
168
+ )
169
+
170
+ examinations = models.ManyToManyField( # type: ignore[assignment]
171
+ "Examination",
172
+ blank=True,
173
+ related_name="required_in",
174
+ )
175
+
176
+ examination_indications = models.ManyToManyField( # type: ignore[assignment]
177
+ "ExaminationIndication",
178
+ blank=True,
179
+ related_name="required_in",
180
+ )
181
+
182
+ diseases = models.ManyToManyField( # type: ignore[assignment]
183
+ "Disease",
184
+ blank=True,
185
+ related_name="required_in",
186
+ )
187
+
188
+ disease_classification_choices = models.ManyToManyField( # type: ignore[assignment]
189
+ "DiseaseClassificationChoice",
190
+ blank=True,
191
+ related_name="required_in",
192
+ )
193
+
194
+ events = models.ManyToManyField( # type: ignore[assignment]
195
+ "Event",
196
+ blank=True,
197
+ related_name="required_in",
198
+ )
199
+
200
+ lab_values = models.ManyToManyField( # type: ignore[assignment]
201
+ "LabValue",
202
+ blank=True,
203
+ related_name="required_in",
204
+ )
205
+
206
+ findings = models.ManyToManyField( # type: ignore[assignment]
207
+ "Finding",
208
+ blank=True,
209
+ related_name="required_in",
210
+ )
211
+
212
+ finding_classifications = models.ManyToManyField( # type: ignore[assignment]
213
+ "FindingClassification",
214
+ blank=True,
215
+ related_name="required_in",
216
+ )
217
+
218
+ finding_classification_choices = models.ManyToManyField( # type: ignore[assignment]
219
+ "FindingClassificationChoice",
220
+ blank=True,
221
+ related_name="required_in",
222
+ )
223
+
224
+ finding_interventions = models.ManyToManyField( # type: ignore[assignment]
225
+ "FindingIntervention",
226
+ blank=True,
227
+ related_name="required_in",
228
+ )
229
+
230
+ medications = models.ManyToManyField( # type: ignore[assignment]
231
+ "Medication",
232
+ blank=True,
233
+ related_name="required_in",
234
+ )
235
+
236
+ medication_indications = models.ManyToManyField( # type: ignore[assignment]
237
+ "MedicationIndication",
238
+ blank=True,
239
+ related_name="required_in",
240
+ )
241
+
242
+ medication_intake_times = models.ManyToManyField( # type: ignore[assignment]
243
+ "MedicationIntakeTime",
244
+ blank=True,
245
+ related_name="required_in",
246
+ )
247
+
248
+ medication_schedules = models.ManyToManyField( # type: ignore[assignment]
249
+ "MedicationSchedule",
250
+ blank=True,
251
+ related_name="required_in",
252
+ )
253
+
254
+ genders = models.ManyToManyField( # type: ignore[assignment]
255
+ "Gender",
256
+ blank=True,
257
+ related_name="required_in",
258
+ )
259
+
260
+ if TYPE_CHECKING:
261
+ requirement_types: models.QuerySet[RequirementType]
262
+ operators: models.QuerySet[RequirementOperator]
263
+ requirement_sets: models.QuerySet[RequirementSet]
264
+ examinations: models.QuerySet[Examination]
265
+ examination_indications: models.QuerySet[ExaminationIndication]
266
+ lab_values: models.QuerySet[LabValue]
267
+ diseases: models.QuerySet[Disease]
268
+ disease_classification_choices: models.QuerySet[DiseaseClassificationChoice]
269
+ events: models.QuerySet[Event]
270
+ findings: models.QuerySet[Finding]
271
+ finding_classifications: models.QuerySet[FindingClassification]
272
+ finding_classification_choices: models.QuerySet[FindingClassificationChoice]
273
+ finding_interventions: models.QuerySet[FindingIntervention]
274
+ medications: models.QuerySet[Medication]
275
+ medication_indications: models.QuerySet[MedicationIndication]
276
+ medication_intake_times: models.QuerySet[MedicationIntakeTime] # Added type hint
277
+ medication_schedules: models.QuerySet[MedicationSchedule]
278
+ genders: models.QuerySet[Gender]
279
+
280
+ def natural_key(self):
281
+ """
282
+ Returns a tuple containing the instance's name as its natural key.
283
+
284
+ This tuple provides a unique identifier for serialization purposes.
285
+ """
286
+ return (self.name,)
287
+
288
+ def __str__(self):
289
+ """Returns the name of the requirement as its string representation."""
290
+ return str(self.name)
291
+
292
+ @property
293
+ def expected_models(self) -> List[Union[
294
+ "Disease",
295
+ "DiseaseClassificationChoice",
296
+ "Event",
297
+ "EventClassification",
298
+ "EventClassificationChoice",
299
+ "Examination",
300
+ "ExaminationIndication",
301
+ "Finding",
302
+ "FindingIntervention",
303
+ "FindingClassification",
304
+ "FindingClassificationChoice",
305
+ "FindingClassificationType",
306
+ "LabValue",
307
+ "Medication",
308
+ "MedicationIndication",
309
+ "MedicationIntakeTime", # Added MedicationIntakeTime
310
+ "PatientDisease",
311
+ "PatientEvent",
312
+ "PatientExamination",
313
+ "PatientFinding",
314
+ "PatientFindingIntervention",
315
+ "PatientFindingClassification",
316
+ "PatientLabValue",
317
+ "PatientMedicationSchedule", # Added PatientMedicationSchedule
318
+ ]]:
319
+ """
320
+ Return the list of model classes that are expected as input for evaluating this requirement.
321
+
322
+ The returned models correspond to the requirement types linked to this requirement, mapped via the internal data model dictionary.
323
+ """
324
+ req_types = self.requirement_types.all()
325
+ req_type_names = [_.name for _ in req_types]
326
+
327
+ expected_models = [self.data_model_dict[_] for _ in req_type_names]
328
+ # e.g. [PatientExamination, PatientFinding]
329
+ return expected_models
330
+
331
+ @property
332
+ def links(self) -> "RequirementLinks":
333
+ """
334
+ Return a RequirementLinks object containing all non-null related model instances for this requirement.
335
+
336
+ The returned object provides structured access to all associated entities, such as examinations, diseases, findings, classifications, interventions, medications, and related choices, aggregated from the requirement's many-to-many fields.
337
+ """
338
+ # requirement_sets is not part of RequirementLinks (avoids circular import); collect other related models
339
+ models_dict = RequirementLinks(
340
+ examinations=[_ for _ in self.examinations.all() if _ is not None],
341
+ examination_indications=[_ for _ in self.examination_indications.all() if _ is not None],
342
+ lab_values=[_ for _ in self.lab_values.all() if _ is not None],
343
+ diseases=[_ for _ in self.diseases.all() if _ is not None],
344
+ disease_classification_choices=[_ for _ in self.disease_classification_choices.all() if _ is not None],
345
+ events=[_ for _ in self.events.all() if _ is not None],
346
+ findings=[_ for _ in self.findings.all() if _ is not None],
347
+ finding_classifications=[_ for _ in self.finding_classifications.all() if _ is not None],
348
+ finding_classification_choices=[_ for _ in self.finding_classification_choices.all() if _ is not None],
349
+ finding_interventions=[_ for _ in self.finding_interventions.all() if _ is not None],
350
+ medications=[_ for _ in self.medications.all() if _ is not None],
351
+ medication_indications=[_ for _ in self.medication_indications.all() if _ is not None],
352
+ medication_intake_times=[_ for _ in self.medication_intake_times.all() if _ is not None],
353
+ )
354
+ return models_dict
355
+
356
+ @property
357
+ def data_model_dict(self) -> dict:
358
+ """
359
+ Provides a mapping from requirement type names to their corresponding model classes.
360
+
361
+ Returns:
362
+ A dictionary where keys are requirement type names and values are model classes used for requirement evaluation.
363
+ """
364
+ from .requirement_evaluation.requirement_type_parser import data_model_dict
365
+ return data_model_dict
366
+
367
+ @property
368
+ def active_links(self) -> Dict[str, List]:
369
+ """Returns a dictionary of linked models containing only non-empty entries.
370
+
371
+ The returned dictionary includes only those related model lists that have at least one linked instance.
372
+ """
373
+ return self.links.active()
374
+
375
+
376
+ def evaluate(self, *args, mode:str, **kwargs):
377
+ """
378
+ Evaluates whether the requirement is satisfied for the given input models using linked operators and gender constraints.
379
+
380
+ Args:
381
+ *args: Instances or QuerySets of expected model classes to be evaluated. Each must have a `.links` property returning a `RequirementLinks` object.
382
+ mode: Evaluation mode; "strict" requires all operators to pass, "loose" requires any operator to pass.
383
+ **kwargs: Additional keyword arguments passed to operator evaluations.
384
+
385
+ Returns:
386
+ True if the requirement is satisfied according to the specified mode, linked operators, and gender restrictions; otherwise, False.
387
+
388
+ Raises:
389
+ ValueError: If an invalid mode is provided.
390
+ TypeError: If an input is not an instance or QuerySet of expected models, or lacks a valid `.links` attribute.
391
+
392
+ If the requirement specifies genders, only input containing a patient with a matching gender will be considered valid for evaluation.
393
+ """
394
+ #TODO Review, Optimize or remove
395
+ if mode not in ["strict", "loose"]:
396
+ raise ValueError(f"Invalid mode: {mode}. Use 'strict' or 'loose'.")
397
+
398
+ evaluate_result_list_func = all if mode == "strict" else any
399
+
400
+ requirement_req_links = self.links
401
+ expected_models = self.expected_models
402
+
403
+ # helpers to avoid passing a complex tuple to isinstance/issubclass which confuses type checkers
404
+ def _is_expected_instance(obj) -> bool:
405
+ for cls in expected_models:
406
+ if isinstance(cls, type):
407
+ try:
408
+ if isinstance(obj, cls):
409
+ return True
410
+ except Exception:
411
+ # cls might not be a runtime type
412
+ continue
413
+ return False
414
+
415
+ def _is_queryset_of_expected(qs) -> bool:
416
+ if not isinstance(qs, models.QuerySet) or not hasattr(qs, 'model'):
417
+ return False
418
+ for cls in expected_models:
419
+ if isinstance(cls, type):
420
+ try:
421
+ if issubclass(qs.model, cls):
422
+ return True
423
+ except Exception:
424
+ continue
425
+ return False
426
+
427
+ # Aggregate RequirementLinks from all input arguments
428
+ aggregated_input_links_data = {}
429
+ processed_inputs_count = 0
430
+
431
+ for _input in args:
432
+ # Check if the input is an instance of any of the expected model types
433
+ if not _is_expected_instance(_input):
434
+ # Allow QuerySets of expected models
435
+ if _is_queryset_of_expected(_input):
436
+ # For QuerySets, evaluate each item individually and return True if any matches
437
+ if not _input.exists(): # Skip empty querysets
438
+ continue
439
+
440
+ queryset_results = []
441
+ for item in _input:
442
+ if not hasattr(item, 'links') or not isinstance(item.links, RequirementLinks):
443
+ raise TypeError(
444
+ f"Item {item} of type {type(item)} in QuerySet does not have a valid .links attribute of type RequirementLinks."
445
+ )
446
+
447
+ # Evaluate this single item against the requirement
448
+ item_input_links = RequirementLinks(**item.links.active())
449
+
450
+ # Evaluate all operators for this single item
451
+ item_operator_results = []
452
+ for operator in self.operators.all():
453
+ try:
454
+ operator_result = operator.evaluate(
455
+ requirement_links=requirement_req_links,
456
+ input_links=item_input_links,
457
+ requirement=self,
458
+ original_input_args=args,
459
+ **kwargs
460
+ )
461
+ item_operator_results.append(operator_result)
462
+ except Exception as e:
463
+ logger.debug(f"Operator {operator.name} evaluation failed for item {item}: {e}")
464
+ item_operator_results.append(False)
465
+
466
+ # Apply evaluation mode for this single item
467
+ item_result = evaluate_result_list_func(item_operator_results) if item_operator_results else True
468
+ queryset_results.append(item_result)
469
+ processed_inputs_count += 1
470
+
471
+ # If any item in the QuerySet matches, return True for the whole QuerySet evaluation
472
+ if any(queryset_results):
473
+ return True
474
+ continue # Move to the next arg after processing queryset
475
+ else:
476
+ raise TypeError(
477
+ f"Input type {type(_input)} is not among expected models: {self.expected_models} "
478
+ f"nor a QuerySet of expected models."
479
+ )
480
+
481
+ # Process single model instance
482
+ if not hasattr(_input, 'links') or not isinstance(_input.links, RequirementLinks):
483
+ raise TypeError(
484
+ f"Input {_input} of type {type(_input)} does not have a valid .links attribute of type RequirementLinks."
485
+ )
486
+
487
+ active_input_links = _input.links.active() # Get dict of non-empty lists
488
+ for link_key, link_list in active_input_links.items():
489
+ if link_key not in aggregated_input_links_data:
490
+ aggregated_input_links_data[link_key] = []
491
+ aggregated_input_links_data[link_key].extend(link_list)
492
+ processed_inputs_count += 1
493
+
494
+ if not processed_inputs_count and args: # If args were provided but none were processable (e.g. all empty querysets)
495
+ # This situation implies no relevant data was provided for evaluation against the requirement.
496
+ # Depending on operator logic (e.g., "requires at least one matching item"), this might lead to False.
497
+ # For "models_match_any", an empty input_links will likely result in False if requirement_req_links is not empty.
498
+ pass
499
+
500
+
501
+ # Deduplicate items within each list after aggregation
502
+ for key in aggregated_input_links_data:
503
+ try:
504
+ # Using dict.fromkeys to preserve order and remove duplicates for hashable items
505
+ aggregated_input_links_data[key] = list(dict.fromkeys(aggregated_input_links_data[key]))
506
+ except TypeError:
507
+ # Fallback for non-hashable items (though Django models are hashable)
508
+ temp_list = []
509
+ for item in aggregated_input_links_data[key]:
510
+ if item not in temp_list:
511
+ temp_list.append(item)
512
+ aggregated_input_links_data[key] = temp_list
513
+
514
+ final_input_links = RequirementLinks(**aggregated_input_links_data)
515
+
516
+ # Gender strict check: if this requirement has genders, only pass if patient.gender is in the set
517
+ genders_exist = self.genders.exists()
518
+ if genders_exist:
519
+ # Import here to avoid circular import
520
+ from endoreg_db.models.administration.person.patient import Patient
521
+ patient = None
522
+ for arg in args:
523
+ if isinstance(arg, Patient):
524
+ patient = arg
525
+ break
526
+ if patient is None or patient.gender is None:
527
+ return False
528
+ if not self.genders.filter(pk=patient.gender.pk).exists():
529
+ return False
530
+
531
+ operators = self.operators.all()
532
+ if not operators.exists(): # If a requirement has no operators, its evaluation is ambiguous.
533
+ # Consider if this should be True, False, or an error.
534
+ # For now, if no operators, and mode is strict, it's vacuously true. If loose, vacuously false.
535
+ # However, typically a requirement implies some condition.
536
+ # Let's assume if no operators, it cannot be satisfied unless it also has no specific links.
537
+ # This behavior might need further refinement based on business logic.
538
+ if not requirement_req_links.active(): # No conditions in requirement
539
+ return True # Vacuously true if requirement itself is empty
540
+ return False # Cannot be satisfied if requirement has conditions but no operators to check them
541
+
542
+
543
+ operator_results = []
544
+ for operator in operators:
545
+ # Prepare kwargs for the operator, including the current Requirement instance
546
+ op_kwargs = kwargs.copy() # Start with kwargs passed to Requirement.evaluate
547
+ op_kwargs['requirement'] = self # Add the Requirement instance itself
548
+ op_kwargs['original_input_args'] = args # Add the original input arguments for operators that need them (e.g., age operators)
549
+ operator_results.append(operator.evaluate(
550
+ requirement_links=requirement_req_links,
551
+ input_links=final_input_links,
552
+ **op_kwargs
553
+ ))
554
+
555
+ is_valid = evaluate_result_list_func(operator_results)
556
+
557
+ return is_valid
558
+
559
+ def evaluate_with_details(self, *args, mode:str, **kwargs):
560
+ """
561
+ Evaluates whether the requirement is satisfied for the given input models using linked operators and gender constraints.
562
+
563
+ Args:
564
+ *args: Instances or QuerySets of expected model classes to be evaluated. Each must have a `.links` property returning a `RequirementLinks` object.
565
+ mode: Evaluation mode; "strict" requires all operators to pass, "loose" requires any operator to pass.
566
+ **kwargs: Additional keyword arguments passed to operator evaluations.
567
+
568
+ Returns:
569
+ True if the requirement is satisfied according to the specified mode, linked operators, and gender restrictions; otherwise, False.
570
+
571
+ Raises:
572
+ ValueError: If an invalid mode is provided.
573
+ TypeError: If an input is not an instance or QuerySet of expected models, or lacks a valid `.links` attribute.
574
+
575
+ If the requirement specifies genders, only input containing a patient with a matching gender will be considered valid for evaluation.
576
+ """
577
+ #TODO Review, Optimize or remove
578
+ if mode not in ["strict", "loose"]:
579
+ raise ValueError(f"Invalid mode: {mode}. Use 'strict' or 'loose'.")
580
+
581
+ evaluate_result_list_func = all if mode == "strict" else any
582
+
583
+ requirement_req_links = self.links
584
+ expected_models = self.expected_models
585
+
586
+ # helpers to avoid passing a complex tuple to isinstance/issubclass which confuses type checkers
587
+ def _is_expected_instance(obj) -> bool:
588
+ for cls in expected_models:
589
+ if isinstance(cls, type):
590
+ try:
591
+ if isinstance(obj, cls):
592
+ return True
593
+ except Exception:
594
+ # cls might not be a runtime type
595
+ continue
596
+ return False
597
+
598
+ def _is_queryset_of_expected(qs) -> bool:
599
+ if not isinstance(qs, models.QuerySet) or not hasattr(qs, 'model'):
600
+ return False
601
+ for cls in expected_models:
602
+ if isinstance(cls, type):
603
+ try:
604
+ if issubclass(qs.model, cls):
605
+ return True
606
+ except Exception:
607
+ continue
608
+ return False
609
+
610
+ # Aggregate RequirementLinks from all input arguments
611
+ aggregated_input_links_data = {}
612
+ processed_inputs_count = 0
613
+
614
+ for _input in args:
615
+ # Check if the input is an instance of any of the expected model types
616
+ if not _is_expected_instance(_input):
617
+ # Allow QuerySets of expected models
618
+ if _is_queryset_of_expected(_input):
619
+ # For QuerySets, evaluate each item individually and return True if any matches
620
+ if not _input.exists(): # Skip empty querysets
621
+ continue
622
+
623
+ queryset_results = []
624
+ for item in _input:
625
+ if not hasattr(item, 'links') or not isinstance(item.links, RequirementLinks):
626
+ raise TypeError(
627
+ f"Item {item} of type {type(item)} in QuerySet does not have a valid .links attribute of type RequirementLinks."
628
+ )
629
+
630
+ # Evaluate this single item against the requirement
631
+ item_input_links = RequirementLinks(**item.links.active())
632
+
633
+ # Evaluate all operators for this single item
634
+ item_operator_results = []
635
+ for operator in self.operators.all():
636
+ try:
637
+ operator_result = operator.evaluate(
638
+ requirement_links=requirement_req_links,
639
+ input_links=item_input_links,
640
+ requirement=self,
641
+ original_input_args=args,
642
+ **kwargs
643
+ )
644
+ item_operator_results.append(operator_result)
645
+ except Exception as e:
646
+ logger.debug(f"Operator {operator.name} evaluation failed for item {item}: {e}")
647
+ item_operator_results.append(False)
648
+
649
+ # Apply evaluation mode for this single item
650
+ item_result = evaluate_result_list_func(item_operator_results) if item_operator_results else True
651
+ queryset_results.append(item_result)
652
+ processed_inputs_count += 1
653
+
654
+ # If any item in the QuerySet matches, return True for the whole QuerySet evaluation
655
+ if any(queryset_results):
656
+ return True
657
+ continue # Move to the next arg after processing queryset
658
+ else:
659
+ raise TypeError(
660
+ f"Input type {type(_input)} is not among expected models: {self.expected_models} "
661
+ f"nor a QuerySet of expected models."
662
+ )
663
+
664
+ # Process single model instance
665
+ if not hasattr(_input, 'links') or not isinstance(_input.links, RequirementLinks):
666
+ raise TypeError(
667
+ f"Input {_input} of type {type(_input)} does not have a valid .links attribute of type RequirementLinks."
668
+ )
669
+
670
+ active_input_links = _input.links.active() # Get dict of non-empty lists
671
+ for link_key, link_list in active_input_links.items():
672
+ if link_key not in aggregated_input_links_data:
673
+ aggregated_input_links_data[link_key] = []
674
+ aggregated_input_links_data[link_key].extend(link_list)
675
+ processed_inputs_count += 1
676
+
677
+ if not processed_inputs_count and args: # If args were provided but none were processable (e.g. all empty querysets)
678
+ # This situation implies no relevant data was provided for evaluation against the requirement.
679
+ # Depending on operator logic (e.g., "requires at least one matching item"), this might lead to False.
680
+ # For "models_match_any", an empty input_links will likely result in False if requirement_req_links is not empty.
681
+ pass
682
+
683
+
684
+ # Deduplicate items within each list after aggregation
685
+ for key in aggregated_input_links_data:
686
+ try:
687
+ # Using dict.fromkeys to preserve order and remove duplicates for hashable items
688
+ aggregated_input_links_data[key] = list(dict.fromkeys(aggregated_input_links_data[key]))
689
+ except TypeError:
690
+ # Fallback for non-hashable items (though Django models are hashable)
691
+ temp_list = []
692
+ for item in aggregated_input_links_data[key]:
693
+ if item not in temp_list:
694
+ temp_list.append(item)
695
+ aggregated_input_links_data[key] = temp_list
696
+
697
+ final_input_links = RequirementLinks(**aggregated_input_links_data)
698
+
699
+ # Gender strict check: if this requirement has genders, only pass if patient.gender is in the set
700
+ genders_exist = self.genders.exists()
701
+ if genders_exist:
702
+ # Import here to avoid circular import
703
+ from endoreg_db.models.administration.person.patient import Patient
704
+ patient = None
705
+ for arg in args:
706
+ if isinstance(arg, Patient):
707
+ patient = arg
708
+ break
709
+ if patient is None or patient.gender is None:
710
+ return False
711
+ if not self.genders.filter(pk=patient.gender.pk).exists():
712
+ return False
713
+
714
+ operators = self.operators.all()
715
+ if not operators.exists(): # If a requirement has no operators, its evaluation is ambiguous.
716
+ # Consider if this should be True, False, or an error.
717
+ # For now, if no operators, and mode is strict, it's vacuously true. If loose, vacuously false.
718
+ # However, typically a requirement implies some condition.
719
+ # Let's assume if no operators, it cannot be satisfied unless it also has no specific links.
720
+ # This behavior might need further refinement based on business logic.
721
+ if not requirement_req_links.active(): # No conditions in requirement
722
+ return True # Vacuously true if requirement itself is empty
723
+ return False # Cannot be satisfied if requirement has conditions but no operators to check them
724
+
725
+
726
+ operator_results = []
727
+ operator_details = []
728
+ for operator in operators:
729
+ # Prepare kwargs for the operator, including the current Requirement instance
730
+ op_kwargs = kwargs.copy() # Start with kwargs passed to Requirement.evaluate
731
+ op_kwargs['requirement'] = self # Add the Requirement instance itself
732
+ op_kwargs['original_input_args'] = args # Add the original input arguments for operators that need them (e.g., age operators)
733
+ try:
734
+ operator_result = operator.evaluate(
735
+ requirement_links=requirement_req_links,
736
+ input_links=final_input_links,
737
+ **op_kwargs
738
+ )
739
+ operator_results.append(operator_result)
740
+ operator_details.append(f"{operator.name}: {'Passed' if operator_result else 'Failed'}")
741
+ except Exception as e:
742
+ operator_results.append(False)
743
+ operator_details.append(f"{operator.name}: {str(e)}")
744
+
745
+ is_valid = evaluate_result_list_func(operator_results)
746
+
747
+ # Create detailed feedback
748
+ if not operator_results:
749
+ details = "Keine Operatoren für die Bewertung verfügbar"
750
+ elif len(operator_results) == 1:
751
+ details = operator_details[0]
752
+ else:
753
+ failed_details = [detail for detail, result in zip(operator_details, operator_results) if not result]
754
+ if failed_details:
755
+ details = "; ".join(failed_details)
756
+ else:
757
+ details = "Alle Operatoren erfolgreich"
758
+
759
+ # Append working directory for debugging convenience
760
+ try:
761
+ cwd = run("pwd", capture_output=True, text=True).stdout.strip()
762
+ details = f"{details}\ncwd: {cwd}"
763
+ except Exception:
764
+ # non-fatal: ignore if subprocess fails
765
+ pass
766
+
767
+ return is_valid, details