endoreg-db 0.8.4.4__py3-none-any.whl → 0.8.8.0__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 (372) 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 +8 -31
  10. endoreg_db/data/_examples/disease.yaml +55 -0
  11. endoreg_db/data/_examples/disease_classification.yaml +13 -0
  12. endoreg_db/data/_examples/disease_classification_choice.yaml +62 -0
  13. endoreg_db/data/_examples/event.yaml +64 -0
  14. endoreg_db/data/_examples/examination.yaml +72 -0
  15. endoreg_db/data/_examples/finding/anatomy_colon.yaml +128 -0
  16. endoreg_db/data/_examples/finding/colonoscopy.yaml +40 -0
  17. endoreg_db/data/_examples/finding/colonoscopy_bowel_prep.yaml +56 -0
  18. endoreg_db/data/_examples/finding/complication.yaml +16 -0
  19. endoreg_db/data/_examples/finding/data.yaml +105 -0
  20. endoreg_db/data/_examples/finding/examination_setting.yaml +16 -0
  21. endoreg_db/data/_examples/finding/medication_related.yaml +18 -0
  22. endoreg_db/data/_examples/finding/outcome.yaml +12 -0
  23. endoreg_db/data/_examples/finding_classification/colonoscopy_bowel_preparation.yaml +68 -0
  24. endoreg_db/data/_examples/finding_classification/colonoscopy_jnet.yaml +22 -0
  25. endoreg_db/data/_examples/finding_classification/colonoscopy_kudo.yaml +25 -0
  26. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
  27. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
  28. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_size.yaml +68 -0
  29. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
  30. endoreg_db/data/_examples/finding_classification/colonoscopy_location.yaml +80 -0
  31. endoreg_db/data/_examples/finding_classification/colonoscopy_lst.yaml +21 -0
  32. endoreg_db/data/_examples/finding_classification/colonoscopy_nice.yaml +20 -0
  33. endoreg_db/data/_examples/finding_classification/colonoscopy_paris.yaml +26 -0
  34. endoreg_db/data/_examples/finding_classification/colonoscopy_sano.yaml +22 -0
  35. endoreg_db/data/_examples/finding_classification/colonoscopy_summary.yaml +53 -0
  36. endoreg_db/data/_examples/finding_classification/complication_generic.yaml +25 -0
  37. endoreg_db/data/_examples/finding_classification/examination_setting_generic.yaml +40 -0
  38. endoreg_db/data/_examples/finding_classification/histology_colo.yaml +51 -0
  39. endoreg_db/data/_examples/finding_classification/intervention_required.yaml +26 -0
  40. endoreg_db/data/_examples/finding_classification/medication_related.yaml +23 -0
  41. endoreg_db/data/_examples/finding_classification/visualized.yaml +33 -0
  42. endoreg_db/data/_examples/finding_classification_choice/bowel_preparation.yaml +78 -0
  43. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
  44. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
  45. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
  46. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_lst.yaml +15 -0
  47. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_nice.yaml +17 -0
  48. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_paris.yaml +57 -0
  49. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
  50. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_sano.yaml +14 -0
  51. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
  52. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_location.yaml +229 -0
  53. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
  54. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_size.yaml +82 -0
  55. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
  56. endoreg_db/data/_examples/finding_classification_choice/complication_generic_types.yaml +15 -0
  57. endoreg_db/data/_examples/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
  58. endoreg_db/data/_examples/finding_classification_choice/histology.yaml +24 -0
  59. endoreg_db/data/_examples/finding_classification_choice/histology_polyp.yaml +20 -0
  60. endoreg_db/data/_examples/finding_classification_choice/outcome.yaml +19 -0
  61. endoreg_db/data/_examples/finding_classification_choice/yes_no_na.yaml +11 -0
  62. endoreg_db/data/_examples/finding_classification_type/colonoscopy_basic.yaml +48 -0
  63. endoreg_db/data/_examples/finding_intervention/endoscopy.yaml +43 -0
  64. endoreg_db/data/_examples/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
  65. endoreg_db/data/_examples/finding_intervention/endoscopy_egd.yaml +128 -0
  66. endoreg_db/data/_examples/finding_intervention/endoscopy_ercp.yaml +32 -0
  67. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_lower.yaml +9 -0
  68. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_upper.yaml +36 -0
  69. endoreg_db/data/_examples/finding_intervention_type/endoscopy.yaml +15 -0
  70. endoreg_db/data/_examples/finding_type/data.yaml +43 -0
  71. endoreg_db/data/_examples/requirement/age.yaml +26 -0
  72. endoreg_db/data/_examples/requirement/colonoscopy_baseline_austria.yaml +45 -0
  73. endoreg_db/data/_examples/requirement/disease_cardiovascular.yaml +79 -0
  74. endoreg_db/data/_examples/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
  75. endoreg_db/data/_examples/requirement/disease_hepatology.yaml +12 -0
  76. endoreg_db/data/_examples/requirement/disease_misc.yaml +12 -0
  77. endoreg_db/data/_examples/requirement/disease_renal.yaml +96 -0
  78. endoreg_db/data/_examples/requirement/endoscopy_bleeding_risk.yaml +59 -0
  79. endoreg_db/data/_examples/requirement/event_cardiology.yaml +251 -0
  80. endoreg_db/data/_examples/requirement/event_requirements.yaml +145 -0
  81. endoreg_db/data/_examples/requirement/finding_colon_polyp.yaml +50 -0
  82. endoreg_db/data/_examples/requirement/gender.yaml +25 -0
  83. endoreg_db/data/_examples/requirement/lab_value.yaml +441 -0
  84. endoreg_db/data/_examples/requirement/medication.yaml +93 -0
  85. endoreg_db/data/_examples/requirement_operator/age.yaml +13 -0
  86. endoreg_db/data/_examples/requirement_operator/lab_operators.yaml +129 -0
  87. endoreg_db/data/_examples/requirement_operator/model_operators.yaml +96 -0
  88. endoreg_db/data/_examples/requirement_set/01_endoscopy_generic.yaml +48 -0
  89. endoreg_db/data/_examples/requirement_set/colonoscopy_austria_screening.yaml +57 -0
  90. endoreg_db/data/_examples/yaml_examples.xlsx +0 -0
  91. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +4 -3
  92. endoreg_db/data/event_classification/data.yaml +4 -0
  93. endoreg_db/data/event_classification_choice/data.yaml +9 -0
  94. endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +43 -70
  95. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +22 -52
  96. endoreg_db/data/finding_classification/colonoscopy_location.yaml +31 -62
  97. endoreg_db/data/finding_classification/histology_colo.yaml +28 -36
  98. endoreg_db/data/requirement/colon_polyp_intervention.yaml +49 -0
  99. endoreg_db/data/requirement/coloreg_colon_polyp.yaml +49 -0
  100. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +31 -12
  101. endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
  102. endoreg_db/data/requirement_set/02_endoscopy_bleeding_risk.yaml +46 -0
  103. endoreg_db/data/requirement_set/90_coloreg.yaml +178 -0
  104. endoreg_db/data/requirement_set/_old_ +109 -0
  105. endoreg_db/data/requirement_set_type/data.yaml +21 -0
  106. endoreg_db/data/setup_config.yaml +4 -4
  107. endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
  108. endoreg_db/exceptions.py +5 -2
  109. endoreg_db/helpers/data_loader.py +1 -1
  110. endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
  111. endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
  112. endoreg_db/management/commands/import_video.py +9 -10
  113. endoreg_db/management/commands/import_video_with_classification.py +1 -1
  114. endoreg_db/management/commands/init_default_ai_model.py +1 -1
  115. endoreg_db/management/commands/list_routes.py +18 -0
  116. endoreg_db/management/commands/load_ai_model_data.py +2 -1
  117. endoreg_db/management/commands/load_center_data.py +12 -12
  118. endoreg_db/management/commands/load_requirement_data.py +60 -31
  119. endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
  120. endoreg_db/management/commands/setup_endoreg_db.py +14 -10
  121. endoreg_db/management/commands/storage_management.py +271 -203
  122. endoreg_db/migrations/0001_initial.py +1799 -1300
  123. endoreg_db/migrations/0002_requirementset_depends_on.py +18 -0
  124. endoreg_db/migrations/_old/0001_initial.py +1857 -0
  125. endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +68 -0
  126. endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +77 -0
  127. endoreg_db/migrations/_old/0005_merge_20251111_1003.py +14 -0
  128. endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +68 -0
  129. endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +89 -0
  130. endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +27 -0
  131. endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +21 -0
  132. endoreg_db/models/__init__.py +78 -123
  133. endoreg_db/models/administration/__init__.py +21 -42
  134. endoreg_db/models/administration/ai/active_model.py +2 -2
  135. endoreg_db/models/administration/ai/ai_model.py +7 -6
  136. endoreg_db/models/administration/case/__init__.py +1 -15
  137. endoreg_db/models/administration/case/case.py +3 -3
  138. endoreg_db/models/administration/case/case_template/__init__.py +2 -14
  139. endoreg_db/models/administration/case/case_template/case_template.py +2 -124
  140. endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
  141. endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
  142. endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
  143. endoreg_db/models/administration/center/center.py +33 -19
  144. endoreg_db/models/administration/center/center_product.py +12 -9
  145. endoreg_db/models/administration/center/center_resource.py +25 -19
  146. endoreg_db/models/administration/center/center_shift.py +21 -17
  147. endoreg_db/models/administration/center/center_waste.py +16 -8
  148. endoreg_db/models/administration/person/__init__.py +2 -0
  149. endoreg_db/models/administration/person/employee/employee.py +10 -5
  150. endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
  151. endoreg_db/models/administration/person/employee/employee_type.py +12 -6
  152. endoreg_db/models/administration/person/examiner/examiner.py +13 -11
  153. endoreg_db/models/administration/person/patient/__init__.py +2 -0
  154. endoreg_db/models/administration/person/patient/patient.py +103 -100
  155. endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
  156. endoreg_db/models/administration/person/person.py +4 -0
  157. endoreg_db/models/administration/person/profession/__init__.py +8 -4
  158. endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
  159. endoreg_db/models/administration/product/product.py +20 -15
  160. endoreg_db/models/administration/product/product_material.py +17 -18
  161. endoreg_db/models/administration/product/product_weight.py +12 -8
  162. endoreg_db/models/administration/product/reference_product.py +23 -55
  163. endoreg_db/models/administration/qualification/qualification.py +7 -3
  164. endoreg_db/models/administration/qualification/qualification_type.py +7 -3
  165. endoreg_db/models/administration/shift/scheduled_days.py +8 -5
  166. endoreg_db/models/administration/shift/shift.py +16 -12
  167. endoreg_db/models/administration/shift/shift_type.py +23 -31
  168. endoreg_db/models/label/__init__.py +7 -8
  169. endoreg_db/models/label/annotation/image_classification.py +10 -9
  170. endoreg_db/models/label/annotation/video_segmentation_annotation.py +8 -5
  171. endoreg_db/models/label/label.py +15 -15
  172. endoreg_db/models/label/label_set.py +19 -6
  173. endoreg_db/models/label/label_type.py +1 -1
  174. endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
  175. endoreg_db/models/label/label_video_segment/label_video_segment.py +76 -102
  176. endoreg_db/models/label/video_segmentation_label.py +4 -0
  177. endoreg_db/models/label/video_segmentation_labelset.py +4 -3
  178. endoreg_db/models/media/frame/frame.py +22 -22
  179. endoreg_db/models/media/pdf/raw_pdf.py +249 -177
  180. endoreg_db/models/media/pdf/report_file.py +25 -29
  181. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +30 -46
  182. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
  183. endoreg_db/models/media/video/__init__.py +1 -0
  184. endoreg_db/models/media/video/create_from_file.py +48 -56
  185. endoreg_db/models/media/video/pipe_1.py +30 -33
  186. endoreg_db/models/media/video/pipe_2.py +8 -9
  187. endoreg_db/models/media/video/video_file.py +359 -204
  188. endoreg_db/models/media/video/video_file_ai.py +288 -74
  189. endoreg_db/models/media/video/video_file_anonymize.py +38 -38
  190. endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
  191. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
  192. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
  193. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
  194. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
  195. endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
  196. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
  197. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
  198. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
  199. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
  200. endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
  201. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
  202. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
  203. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
  204. endoreg_db/models/media/video/video_file_io.py +109 -62
  205. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
  206. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
  207. endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
  208. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
  209. endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
  210. endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
  211. endoreg_db/models/media/video/video_file_segments.py +24 -17
  212. endoreg_db/models/media/video/video_metadata.py +19 -35
  213. endoreg_db/models/media/video/video_processing.py +96 -95
  214. endoreg_db/models/medical/contraindication/__init__.py +13 -3
  215. endoreg_db/models/medical/disease.py +22 -16
  216. endoreg_db/models/medical/event.py +31 -18
  217. endoreg_db/models/medical/examination/__init__.py +13 -6
  218. endoreg_db/models/medical/examination/examination.py +17 -18
  219. endoreg_db/models/medical/examination/examination_indication.py +26 -25
  220. endoreg_db/models/medical/examination/examination_time.py +16 -6
  221. endoreg_db/models/medical/examination/examination_time_type.py +9 -6
  222. endoreg_db/models/medical/examination/examination_type.py +3 -4
  223. endoreg_db/models/medical/finding/finding.py +38 -39
  224. endoreg_db/models/medical/finding/finding_classification.py +37 -48
  225. endoreg_db/models/medical/finding/finding_intervention.py +27 -22
  226. endoreg_db/models/medical/finding/finding_type.py +13 -12
  227. endoreg_db/models/medical/hardware/endoscope.py +20 -26
  228. endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
  229. endoreg_db/models/medical/laboratory/lab_value.py +62 -91
  230. endoreg_db/models/medical/medication/medication.py +22 -10
  231. endoreg_db/models/medical/medication/medication_indication.py +29 -3
  232. endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
  233. endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
  234. endoreg_db/models/medical/medication/medication_schedule.py +27 -16
  235. endoreg_db/models/medical/organ/__init__.py +15 -12
  236. endoreg_db/models/medical/patient/medication_examples.py +1 -5
  237. endoreg_db/models/medical/patient/patient_disease.py +20 -23
  238. endoreg_db/models/medical/patient/patient_event.py +19 -22
  239. endoreg_db/models/medical/patient/patient_examination.py +48 -54
  240. endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
  241. endoreg_db/models/medical/patient/patient_finding.py +122 -139
  242. endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
  243. endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
  244. endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
  245. endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
  246. endoreg_db/models/medical/patient/patient_medication.py +27 -38
  247. endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
  248. endoreg_db/models/medical/risk/risk.py +7 -6
  249. endoreg_db/models/medical/risk/risk_type.py +8 -5
  250. endoreg_db/models/metadata/model_meta.py +60 -29
  251. endoreg_db/models/metadata/model_meta_logic.py +139 -18
  252. endoreg_db/models/metadata/pdf_meta.py +19 -24
  253. endoreg_db/models/metadata/sensitive_meta.py +102 -85
  254. endoreg_db/models/metadata/sensitive_meta_logic.py +383 -43
  255. endoreg_db/models/metadata/video_meta.py +51 -31
  256. endoreg_db/models/metadata/video_prediction_logic.py +16 -23
  257. endoreg_db/models/metadata/video_prediction_meta.py +29 -33
  258. endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
  259. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
  260. endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
  261. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
  262. endoreg_db/models/other/emission/emission_factor.py +18 -8
  263. endoreg_db/models/other/gender.py +10 -5
  264. endoreg_db/models/other/information_source.py +25 -25
  265. endoreg_db/models/other/material.py +9 -5
  266. endoreg_db/models/other/resource.py +6 -4
  267. endoreg_db/models/other/tag.py +10 -5
  268. endoreg_db/models/other/transport_route.py +13 -8
  269. endoreg_db/models/other/unit.py +10 -6
  270. endoreg_db/models/other/waste.py +6 -5
  271. endoreg_db/models/requirement/requirement.py +580 -272
  272. endoreg_db/models/requirement/requirement_error.py +85 -0
  273. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
  274. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
  275. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
  276. endoreg_db/models/requirement/requirement_operator.py +36 -33
  277. endoreg_db/models/requirement/requirement_set.py +74 -57
  278. endoreg_db/models/state/__init__.py +4 -4
  279. endoreg_db/models/state/abstract.py +2 -2
  280. endoreg_db/models/state/anonymization.py +12 -0
  281. endoreg_db/models/state/audit_ledger.py +46 -47
  282. endoreg_db/models/state/label_video_segment.py +9 -0
  283. endoreg_db/models/state/raw_pdf.py +40 -46
  284. endoreg_db/models/state/sensitive_meta.py +6 -2
  285. endoreg_db/models/state/video.py +58 -53
  286. endoreg_db/models/upload_job.py +32 -55
  287. endoreg_db/models/utils.py +1 -2
  288. endoreg_db/root_urls.py +21 -2
  289. endoreg_db/serializers/__init__.py +26 -57
  290. endoreg_db/serializers/anonymization.py +18 -10
  291. endoreg_db/serializers/meta/report_meta.py +1 -1
  292. endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
  293. endoreg_db/serializers/misc/__init__.py +1 -1
  294. endoreg_db/serializers/misc/file_overview.py +33 -91
  295. endoreg_db/serializers/misc/{vop_patient_data.py → sensitive_patient_data.py} +1 -1
  296. endoreg_db/serializers/requirements/requirement_sets.py +92 -22
  297. endoreg_db/serializers/video/segmentation.py +2 -1
  298. endoreg_db/serializers/video/video_processing_history.py +20 -5
  299. endoreg_db/serializers/video_examination.py +198 -0
  300. endoreg_db/services/anonymization.py +75 -73
  301. endoreg_db/services/lookup_service.py +256 -73
  302. endoreg_db/services/lookup_store.py +174 -30
  303. endoreg_db/services/pdf_import.py +711 -310
  304. endoreg_db/services/storage_aware_video_processor.py +140 -114
  305. endoreg_db/services/video_import.py +266 -117
  306. endoreg_db/urls/__init__.py +27 -27
  307. endoreg_db/urls/label_video_segments.py +2 -0
  308. endoreg_db/urls/media.py +108 -66
  309. endoreg_db/urls/root_urls.py +29 -0
  310. endoreg_db/utils/__init__.py +15 -5
  311. endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
  312. endoreg_db/utils/case_generator/__init__.py +3 -0
  313. endoreg_db/utils/dataloader.py +88 -16
  314. endoreg_db/utils/defaults/set_default_center.py +32 -0
  315. endoreg_db/utils/names.py +22 -16
  316. endoreg_db/utils/permissions.py +2 -1
  317. endoreg_db/utils/pipelines/process_video_dir.py +1 -1
  318. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +414 -127
  319. endoreg_db/utils/setup_config.py +8 -5
  320. endoreg_db/utils/storage.py +115 -0
  321. endoreg_db/utils/validate_endo_roi.py +8 -2
  322. endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
  323. endoreg_db/views/__init__.py +5 -12
  324. endoreg_db/views/anonymization/media_management.py +198 -163
  325. endoreg_db/views/anonymization/overview.py +4 -1
  326. endoreg_db/views/anonymization/validate.py +174 -40
  327. endoreg_db/views/media/__init__.py +2 -0
  328. endoreg_db/views/media/pdf_media.py +131 -150
  329. endoreg_db/views/media/sensitive_metadata.py +46 -6
  330. endoreg_db/views/media/video_media.py +89 -82
  331. endoreg_db/views/media/video_segments.py +187 -260
  332. endoreg_db/views/meta/sensitive_meta_detail.py +0 -63
  333. endoreg_db/views/patient/patient.py +5 -4
  334. endoreg_db/views/pdf/__init__.py +5 -8
  335. endoreg_db/views/pdf/pdf_stream.py +186 -0
  336. endoreg_db/views/pdf/pdf_stream_views.py +0 -127
  337. endoreg_db/views/pdf/reimport.py +86 -91
  338. endoreg_db/views/requirement/evaluate.py +188 -187
  339. endoreg_db/views/requirement/lookup.py +186 -288
  340. endoreg_db/views/requirement/requirement_utils.py +89 -0
  341. endoreg_db/views/video/__init__.py +0 -4
  342. endoreg_db/views/video/correction.py +2 -2
  343. endoreg_db/views/video/video_examination_viewset.py +202 -289
  344. {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/METADATA +7 -3
  345. {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/RECORD +350 -255
  346. endoreg_db/models/administration/permissions/__init__.py +0 -44
  347. endoreg_db/models/media/video/refactor_plan.md +0 -0
  348. endoreg_db/models/media/video/video_file_frames.py +0 -0
  349. endoreg_db/models/metadata/frame_ocr_result.py +0 -0
  350. endoreg_db/models/rule/__init__.py +0 -13
  351. endoreg_db/models/rule/rule.py +0 -27
  352. endoreg_db/models/rule/rule_applicator.py +0 -224
  353. endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
  354. endoreg_db/models/rule/rule_type.py +0 -20
  355. endoreg_db/models/rule/ruleset.py +0 -17
  356. endoreg_db/serializers/video/video_metadata.py +0 -105
  357. endoreg_db/urls/report.py +0 -48
  358. endoreg_db/urls/video.py +0 -61
  359. endoreg_db/utils/case_generator/case_generator.py +0 -159
  360. endoreg_db/utils/case_generator/utils.py +0 -30
  361. endoreg_db/views/pdf/pdf_media.py +0 -239
  362. endoreg_db/views/report/__init__.py +0 -9
  363. endoreg_db/views/report/report_list.py +0 -112
  364. endoreg_db/views/report/report_with_secure_url.py +0 -28
  365. endoreg_db/views/report/start_examination.py +0 -7
  366. endoreg_db/views/video/video_media.py +0 -158
  367. endoreg_db/views.py +0 -0
  368. /endoreg_db/data/{requirement_set → _examples/requirement_set}/endoscopy_bleeding_risk.yaml +0 -0
  369. /endoreg_db/migrations/{0002_add_video_correction_models.py → _old/0002_add_video_correction_models.py} +0 -0
  370. /endoreg_db/migrations/{0003_add_center_display_name.py → _old/0003_add_center_display_name.py} +0 -0
  371. {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/WHEEL +0 -0
  372. {endoreg_db-0.8.4.4.dist-info → endoreg_db-0.8.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,35 +1,82 @@
1
+ """
2
+ Lookup Service Module
3
+
4
+ This module provides server-side evaluation and lookup functionality for patient examinations.
5
+ It handles requirement set evaluation, finding availability, and status computation for
6
+ medical examination workflows.
7
+
8
+ The lookup system uses a token-based approach where client sessions are stored in Django cache,
9
+ allowing for efficient state management and recomputation of derived data.
10
+
11
+ Key Components:
12
+ - PatientExamination loading with optimized prefetching
13
+ - Requirement set resolution and evaluation
14
+ - Status computation for requirements and requirement sets
15
+ - Suggested actions for unsatisfied requirements
16
+ - Cache-based session management
17
+
18
+ Architecture:
19
+ 1. LookupStore: Handles cache-based session storage
20
+ 2. lookup_service: Core business logic for evaluation
21
+ 3. LookupViewSet: Django REST API endpoints
22
+ """
23
+
1
24
  # services/lookup_service.py
2
25
  from __future__ import annotations
3
- from typing import Dict, Any, List
4
- from django.db.models import Prefetch
5
- from endoreg_db.models.medical.patient.patient_examination import PatientExamination
26
+
27
+ import logging
28
+ from typing import Any, Dict, List, Optional
29
+
30
+ from django.db.models import Prefetch, QuerySet
31
+
6
32
  from endoreg_db.models.medical.examination import ExaminationRequirementSet
33
+ from endoreg_db.models.medical.patient.patient_examination import PatientExamination
7
34
  from endoreg_db.models.requirement.requirement_set import RequirementSet
35
+
8
36
  from .lookup_store import LookupStore
9
37
 
10
38
 
11
39
  def load_patient_exam_for_eval(pk: int) -> PatientExamination:
12
40
  """
13
- Fetch PatientExamination with everything needed for evaluation,
14
- following the *Examination → ExaminationRequirementSet → RequirementSet* graph.
41
+ Load a PatientExamination with all related data needed for evaluation.
42
+
43
+ This function performs optimized database queries to fetch a PatientExamination
44
+ along with all related objects required for requirement evaluation, including:
45
+ - Patient and examination details
46
+ - Patient findings
47
+ - Examination requirement sets and their requirements
48
+ - Nested requirement set relationships
49
+
50
+ The query uses select_related and prefetch_related to minimize database hits
51
+ and ensure all data is available for evaluation without additional queries.
52
+
53
+ Args:
54
+ pk: Primary key of the PatientExamination to load
55
+
56
+ Returns:
57
+ PatientExamination: Fully loaded instance with all related data prefetched
58
+
59
+ Raises:
60
+ PatientExamination.DoesNotExist: If no examination exists with the given pk
15
61
  """
16
62
  return (
17
- PatientExamination.objects
18
- .select_related("patient", "examination")
63
+ PatientExamination.objects.select_related("patient", "examination")
19
64
  .prefetch_related(
20
65
  "patient_findings",
21
66
  # Prefetch ERS groups on the Examination…
22
67
  Prefetch(
23
68
  "examination__exam_reqset_links",
24
- queryset=ExaminationRequirementSet.objects.only("id", "name", "enabled_by_default"),
69
+ queryset=ExaminationRequirementSet.objects.only(
70
+ "id", "name", "enabled_by_default"
71
+ ),
25
72
  ),
26
73
  # …and the RequirementSets reachable via those ERS groups.
27
74
  Prefetch(
28
75
  "examination__exam_reqset_links__requirement_set",
29
76
  queryset=(
30
- RequirementSet.objects
31
- .select_related("requirement_set_type")
32
- .prefetch_related(
77
+ RequirementSet.objects.select_related(
78
+ "requirement_set_type"
79
+ ).prefetch_related(
33
80
  "requirements",
34
81
  "links_to_sets",
35
82
  "links_to_sets__requirements",
@@ -42,33 +89,84 @@ def load_patient_exam_for_eval(pk: int) -> PatientExamination:
42
89
  )
43
90
 
44
91
 
45
- def requirement_sets_for_patient_exam(pe: PatientExamination) -> List[RequirementSet]:
92
+ def requirement_sets_for_patient_exam(
93
+ pe: PatientExamination, user_tags: Optional[List[str]] = None
94
+ ) -> QuerySet:
46
95
  """
47
- Correctly resolve RequirementSets for a PE via ERS hub:
48
- RequirementSet.objects.filter(reqset_exam_links__examinations=exam)
96
+ Retrieve all RequirementSets linked to a PatientExamination's examination.
97
+
98
+ Args:
99
+ pe: PatientExamination instance
100
+ user_tags: Optional list of tag names to filter requirement sets
101
+
102
+ Returns:
103
+ QuerySet of RequirementSet instances
49
104
  """
50
- exam = pe.examination
51
- if not exam:
52
- return []
53
- return list(
54
- RequirementSet.objects
55
- .filter(reqset_exam_links__examinations=exam)
56
- .select_related("requirement_set_type")
57
- .prefetch_related("requirements")
58
- .distinct()
59
- )
105
+ if not pe or not pe.examination:
106
+ from endoreg_db.models import RequirementSet
107
+
108
+ return RequirementSet.objects.none()
109
+
110
+ # Start with examination-linked requirement sets
111
+ req_sets = pe.examination.exam_reqset_links.select_related(
112
+ "requirement_set"
113
+ ).values_list("requirement_set", flat=True)
114
+
115
+ from endoreg_db.models import RequirementSet
116
+
117
+ qs = RequirementSet.objects.filter(pk__in=req_sets)
60
118
 
61
- def build_initial_lookup(pe: PatientExamination) -> Dict[str, Any]:
119
+ # Apply tag filtering if provided
120
+ if user_tags:
121
+ qs = qs.filter(tags__name__in=user_tags).distinct()
122
+
123
+ return qs
124
+
125
+
126
+ def build_initial_lookup(
127
+ pe: PatientExamination, user_tags: Optional[List[str]] = None
128
+ ) -> Dict[str, Any]:
62
129
  """
63
- Build the initial lookup dict you will return to the client.
64
- Keep keys small and stable; values must be JSON-serializable.
130
+ Build the initial lookup dictionary for a patient examination.
131
+
132
+ This function creates the base lookup data structure that will be stored in cache
133
+ and used by the client for requirement evaluation. It includes:
134
+
135
+ - Available findings for the examination type
136
+ - Required findings based on requirement defaults
137
+ - Requirement sets metadata
138
+ - Default findings and classification choices per requirement
139
+ - Empty placeholders for dynamic data (status, suggestions, etc.)
140
+
141
+ The returned dictionary is JSON-serializable and contains stable keys that
142
+ won't change between versions.
143
+
144
+ Args:
145
+ pe: PatientExamination instance to build lookup for
146
+
147
+ Returns:
148
+ Dictionary containing initial lookup data with the following keys:
149
+ - patient_examination_id: ID of the patient examination
150
+ - requirement_sets: List of available requirement sets with metadata
151
+ - availableFindings: List of finding IDs available for the examination
152
+ - requiredFindings: List of finding IDs that are required by defaults
153
+ - requirementDefaults: Default findings per requirement
154
+ - classificationChoices: Available classification choices per requirement
155
+ - requirementsBySet: Empty dict (populated on selection)
156
+ - requirementStatus: Empty dict (computed on evaluation)
157
+ - requirementSetStatus: Empty dict (computed on evaluation)
158
+ - suggestedActions: Empty dict (computed on evaluation)
65
159
  """
66
160
  # Available + required findings
67
- available_findings = [f.id for f in pe.examination.get_available_findings()] if pe.examination else []
161
+ available_findings = (
162
+ [f.id for f in pe.examination.get_available_findings()]
163
+ if pe.examination
164
+ else []
165
+ )
68
166
  required_findings: List[int] = [] # fill by scanning requirements below
69
167
 
70
168
  # Requirement sets: ids + meta
71
- rs_objs = requirement_sets_for_patient_exam(pe)
169
+ rs_objs = requirement_sets_for_patient_exam(pe, user_tags=user_tags)
72
170
  requirement_sets = [
73
171
  {
74
172
  "id": rs.id,
@@ -90,9 +188,13 @@ def build_initial_lookup(pe: PatientExamination) -> Dict[str, Any]:
90
188
  choices = getattr(req, "classification_choices", lambda pe: [])(pe)
91
189
  if defaults:
92
190
  req_defaults[str(req.id)] = defaults # list of {finding_id, payload...}
93
- required_findings.extend([d.get("finding_id") for d in defaults if "finding_id" in d])
191
+ required_findings.extend(
192
+ [d.get("finding_id") for d in defaults if "finding_id" in d]
193
+ )
94
194
  if choices:
95
- cls_choices[str(req.id)] = choices # list of {classification_id, label, ...}
195
+ cls_choices[str(req.id)] = (
196
+ choices # list of {classification_id, label, ...}
197
+ )
96
198
 
97
199
  # De-dup required
98
200
  required_findings = sorted(set(required_findings))
@@ -112,62 +214,129 @@ def build_initial_lookup(pe: PatientExamination) -> Dict[str, Any]:
112
214
  # You can add "selectedRequirementSetIds" as the user makes choices
113
215
  }
114
216
 
115
- def create_lookup_token_for_pe(pe_id: int) -> str:
217
+
218
+ def create_lookup_token_for_pe(
219
+ pe_id: int, user_tags: Optional[List[str]] = None
220
+ ) -> str:
221
+ """
222
+ Create a lookup token for a patient examination.
223
+
224
+ This function initializes a new lookup session for the given patient examination
225
+ by building the initial lookup data and storing it in the cache via LookupStore.
226
+
227
+ Args:
228
+ pe_id: Primary key of the PatientExamination
229
+
230
+ Returns:
231
+ String token that can be used to access the lookup session
232
+
233
+ Raises:
234
+ PatientExamination.DoesNotExist: If examination doesn't exist
235
+ Exception: For any other errors during initialization
236
+ """
116
237
  pe = load_patient_exam_for_eval(pe_id)
117
- token = LookupStore().init(build_initial_lookup(pe))
238
+ token = LookupStore().init(build_initial_lookup(pe, user_tags=user_tags))
118
239
  return token
119
240
 
241
+
120
242
  def recompute_lookup(token: str) -> Dict[str, Any]:
121
- import logging
243
+ """
244
+ Recompute derived lookup data based on current patient examination state and user selections.
245
+
246
+ This function performs the core evaluation logic for the lookup system. It:
247
+
248
+ 1. Validates and recovers corrupted lookup data
249
+ 2. Loads the current PatientExamination state from database
250
+ 3. Evaluates requirements against the current examination state
251
+ 4. Computes status for individual requirements and requirement sets
252
+ 5. Generates suggested actions for unsatisfied requirements
253
+ 6. Updates the cache with new derived data (idempotent)
254
+
255
+ The function includes reentrancy protection to prevent concurrent recomputation
256
+ of the same token.
257
+
258
+ Args:
259
+ token: Lookup session token
260
+
261
+ Returns:
262
+ Dictionary of updates containing:
263
+ - requirementsBySet: Requirements grouped by selected requirement sets
264
+ - requirementStatus: Boolean status for each requirement
265
+ - requirementSetStatus: Boolean status for each requirement set
266
+ - requirementDefaults: Default findings per requirement
267
+ - classificationChoices: Available choices per requirement
268
+ - suggestedActions: UI actions to satisfy unsatisfied requirements
269
+
270
+ Raises:
271
+ ValueError: If lookup data is invalid or patient examination not found
272
+ """
122
273
  logger = logging.getLogger(__name__)
123
-
274
+
124
275
  store = LookupStore(token=token)
125
-
276
+
126
277
  # Simple reentrancy guard using data
127
278
  data = store.get_all()
128
- if data.get('_recomputing'):
279
+ if data.get("_recomputing"):
129
280
  logger.warning(f"Recompute already in progress for token {token}, skipping")
130
281
  return {}
131
-
132
- store.set('_recomputing', True)
133
-
282
+
283
+ store.set("_recomputing", True)
284
+
134
285
  try:
135
286
  # First validate and attempt to recover corrupted data
136
287
  validated_data = store.validate_and_recover_data(token)
137
288
  if validated_data is None:
138
289
  logger.error(f"No lookup data found for token {token}")
139
290
  raise ValueError(f"No lookup data found for token {token}")
140
-
291
+
141
292
  data = validated_data
142
- logger.debug(f"Recomputing lookup for token {token}, data keys: {list(data.keys())}")
143
-
293
+ logger.debug(
294
+ f"Recomputing lookup for token {token}, data keys: {list(data.keys())}"
295
+ )
296
+
144
297
  # Check if required data exists
145
298
  if "patient_examination_id" not in data:
146
- logger.error(f"Invalid lookup data for token {token}: missing patient_examination_id. Data: {data}")
147
- raise ValueError(f"Invalid lookup data for token {token}: missing patient_examination_id")
148
-
299
+ logger.error(
300
+ f"Invalid lookup data for token {token}: missing patient_examination_id. Data: {data}"
301
+ )
302
+ raise ValueError(
303
+ f"Invalid lookup data for token {token}: missing patient_examination_id"
304
+ )
305
+
149
306
  if not data.get("patient_examination_id"):
150
- logger.error(f"Invalid lookup data for token {token}: patient_examination_id is empty. Data: {data}")
151
- raise ValueError(f"Invalid lookup data for token {token}: patient_examination_id is empty")
307
+ logger.error(
308
+ f"Invalid lookup data for token {token}: patient_examination_id is empty. Data: {data}"
309
+ )
310
+ raise ValueError(
311
+ f"Invalid lookup data for token {token}: patient_examination_id is empty"
312
+ )
152
313
 
153
314
  pe_id = data["patient_examination_id"]
154
315
  logger.debug(f"Loading patient examination {pe_id} for token {token}")
155
-
316
+
156
317
  try:
157
318
  pe = load_patient_exam_for_eval(pe_id)
158
319
  except Exception as e:
159
- logger.error(f"Failed to load patient examination {pe_id} for token {token}: {e}")
320
+ logger.error(
321
+ f"Failed to load patient examination {pe_id} for token {token}: {e}"
322
+ )
160
323
  raise ValueError(f"Failed to load patient examination {pe_id}: {e}")
161
324
 
162
325
  selected_rs_ids: List[int] = data.get("selectedRequirementSetIds", [])
163
- logger.debug(f"Selected requirement set IDs for token {token}: {selected_rs_ids}")
164
-
165
- rs_objs = [rs for rs in requirement_sets_for_patient_exam(pe) if rs.id in selected_rs_ids]
326
+ logger.debug(
327
+ f"Selected requirement set IDs for token {token}: {selected_rs_ids}"
328
+ )
329
+
330
+ rs_objs = [
331
+ rs
332
+ for rs in requirement_sets_for_patient_exam(pe)
333
+ if rs.id in selected_rs_ids
334
+ ]
166
335
  logger.debug(f"Found {len(rs_objs)} requirement set objects for token {token}")
167
336
 
168
337
  # 1) requirements grouped by set (already prefetched in load func)
169
338
  requirements_by_set = {
170
- rs.id: [ {"id": r.id, "name": r.name} for r in rs.requirements.all() ]
339
+ rs.id: [{"id": r.id, "name": r.name} for r in rs.requirements.all()]
171
340
  for rs in rs_objs
172
341
  }
173
342
 
@@ -180,7 +349,9 @@ def recompute_lookup(token: str) -> Dict[str, Any]:
180
349
  ok = bool(r.evaluate(pe, mode="strict")) # or "loose" if you prefer
181
350
  requirement_status[str(r.id)] = ok
182
351
  req_results.append(ok)
183
- set_status[str(rs.id)] = rs.eval_function(req_results) if rs.eval_function else all(req_results)
352
+ set_status[str(rs.id)] = (
353
+ rs.eval_function(req_results) if rs.eval_function else all(req_results)
354
+ )
184
355
 
185
356
  # 3) suggestions per requirement (defaults + classification choices you already expose)
186
357
  suggested_actions: Dict[str, List[Dict[str, Any]]] = {}
@@ -189,8 +360,12 @@ def recompute_lookup(token: str) -> Dict[str, Any]:
189
360
 
190
361
  for rs in rs_objs:
191
362
  for r in rs.requirements.all():
192
- defaults = getattr(r, "default_findings", lambda pe: [])(pe) # [{finding_id, payload...}]
193
- choices = getattr(r, "classification_choices", lambda pe: [])(pe) # [{classification_id, label,...}]
363
+ defaults = getattr(r, "default_findings", lambda pe: [])(
364
+ pe
365
+ ) # [{finding_id, payload...}]
366
+ choices = getattr(r, "classification_choices", lambda pe: [])(
367
+ pe
368
+ ) # [{classification_id, label,...}]
194
369
  if defaults:
195
370
  req_defaults[str(r.id)] = defaults
196
371
  if choices:
@@ -200,15 +375,19 @@ def recompute_lookup(token: str) -> Dict[str, Any]:
200
375
  # turn default proposals into explicit UI actions
201
376
  acts = []
202
377
  for d in defaults or []:
203
- acts.append({
204
- "type": "add_finding",
205
- "finding_id": d.get("finding_id"),
206
- "classification_ids": d.get("classification_ids") or [],
207
- "note": "default"
208
- })
378
+ acts.append(
379
+ {
380
+ "type": "add_finding",
381
+ "finding_id": d.get("finding_id"),
382
+ "classification_ids": d.get("classification_ids") or [],
383
+ "note": "default",
384
+ }
385
+ )
209
386
  # If r expects patient edits, add an edit action hint
210
387
  if "PatientExamination" in [m.__name__ for m in r.expected_models]:
211
- acts.append({"type": "edit_patient", "fields": ["gender", "dob"]}) # example
388
+ acts.append(
389
+ {"type": "edit_patient", "fields": ["gender", "dob"]}
390
+ ) # example
212
391
  if acts:
213
392
  suggested_actions[str(r.id)] = acts
214
393
 
@@ -220,22 +399,26 @@ def recompute_lookup(token: str) -> Dict[str, Any]:
220
399
  "requirementsBySet": requirements_by_set,
221
400
  "requirementStatus": requirement_status,
222
401
  "requirementSetStatus": set_status,
223
- "requirementDefaults": req_defaults, # keep your existing key
224
- "classificationChoices": cls_choices, # keep your existing key
225
- "suggestedActions": suggested_actions, # new
402
+ "requirementDefaults": req_defaults, # keep your existing key
403
+ "classificationChoices": cls_choices, # keep your existing key
404
+ "suggestedActions": suggested_actions, # new
226
405
  }
227
-
228
- logger.debug(f"Updating store for token {token} with {len(updates)} update keys")
229
-
406
+
407
+ logger.debug(
408
+ f"Updating store for token {token} with {len(updates)} update keys"
409
+ )
410
+
230
411
  # Only write if changed (idempotent)
231
412
  prev_derived = store.get_many(list(updates.keys()))
232
413
  if prev_derived != updates:
233
414
  store.set_many(updates) # <-- does NOT call recompute
234
415
  logger.debug(f"Derived data changed, updated store for token {token}")
235
416
  else:
236
- logger.debug(f"Derived data unchanged, skipping store update for token {token}")
237
-
417
+ logger.debug(
418
+ f"Derived data unchanged, skipping store update for token {token}"
419
+ )
420
+
238
421
  store.mark_recompute_done()
239
422
  return updates
240
423
  finally:
241
- store.set('_recomputing', False)
424
+ store.set("_recomputing", False)