endoreg-db 0.8.6.1__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 (360) 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_center_data.py +12 -12
  117. endoreg_db/management/commands/load_requirement_data.py +60 -31
  118. endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
  119. endoreg_db/management/commands/setup_endoreg_db.py +3 -3
  120. endoreg_db/management/commands/storage_management.py +271 -203
  121. endoreg_db/migrations/0001_initial.py +1799 -1300
  122. endoreg_db/migrations/0002_requirementset_depends_on.py +18 -0
  123. endoreg_db/migrations/_old/0001_initial.py +1857 -0
  124. endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +68 -0
  125. endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +77 -0
  126. endoreg_db/migrations/_old/0005_merge_20251111_1003.py +14 -0
  127. endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +68 -0
  128. endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +89 -0
  129. endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +27 -0
  130. endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +21 -0
  131. endoreg_db/models/__init__.py +78 -123
  132. endoreg_db/models/administration/__init__.py +21 -42
  133. endoreg_db/models/administration/ai/active_model.py +2 -2
  134. endoreg_db/models/administration/ai/ai_model.py +7 -6
  135. endoreg_db/models/administration/case/__init__.py +1 -15
  136. endoreg_db/models/administration/case/case.py +3 -3
  137. endoreg_db/models/administration/case/case_template/__init__.py +2 -14
  138. endoreg_db/models/administration/case/case_template/case_template.py +2 -124
  139. endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
  140. endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
  141. endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
  142. endoreg_db/models/administration/center/center.py +33 -19
  143. endoreg_db/models/administration/center/center_product.py +12 -9
  144. endoreg_db/models/administration/center/center_resource.py +25 -19
  145. endoreg_db/models/administration/center/center_shift.py +21 -17
  146. endoreg_db/models/administration/center/center_waste.py +16 -8
  147. endoreg_db/models/administration/person/__init__.py +2 -0
  148. endoreg_db/models/administration/person/employee/employee.py +10 -5
  149. endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
  150. endoreg_db/models/administration/person/employee/employee_type.py +12 -6
  151. endoreg_db/models/administration/person/examiner/examiner.py +13 -11
  152. endoreg_db/models/administration/person/patient/__init__.py +2 -0
  153. endoreg_db/models/administration/person/patient/patient.py +103 -100
  154. endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
  155. endoreg_db/models/administration/person/person.py +4 -0
  156. endoreg_db/models/administration/person/profession/__init__.py +8 -4
  157. endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
  158. endoreg_db/models/administration/product/product.py +20 -15
  159. endoreg_db/models/administration/product/product_material.py +17 -18
  160. endoreg_db/models/administration/product/product_weight.py +12 -8
  161. endoreg_db/models/administration/product/reference_product.py +23 -55
  162. endoreg_db/models/administration/qualification/qualification.py +7 -3
  163. endoreg_db/models/administration/qualification/qualification_type.py +7 -3
  164. endoreg_db/models/administration/shift/scheduled_days.py +8 -5
  165. endoreg_db/models/administration/shift/shift.py +16 -12
  166. endoreg_db/models/administration/shift/shift_type.py +23 -31
  167. endoreg_db/models/label/__init__.py +7 -8
  168. endoreg_db/models/label/annotation/image_classification.py +10 -9
  169. endoreg_db/models/label/annotation/video_segmentation_annotation.py +8 -5
  170. endoreg_db/models/label/label.py +15 -15
  171. endoreg_db/models/label/label_set.py +19 -6
  172. endoreg_db/models/label/label_type.py +1 -1
  173. endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
  174. endoreg_db/models/label/label_video_segment/label_video_segment.py +76 -102
  175. endoreg_db/models/label/video_segmentation_label.py +4 -0
  176. endoreg_db/models/label/video_segmentation_labelset.py +4 -3
  177. endoreg_db/models/media/frame/frame.py +22 -22
  178. endoreg_db/models/media/pdf/raw_pdf.py +110 -182
  179. endoreg_db/models/media/pdf/report_file.py +25 -29
  180. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +30 -46
  181. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
  182. endoreg_db/models/media/video/__init__.py +1 -0
  183. endoreg_db/models/media/video/create_from_file.py +48 -56
  184. endoreg_db/models/media/video/pipe_2.py +8 -9
  185. endoreg_db/models/media/video/video_file.py +150 -108
  186. endoreg_db/models/media/video/video_file_ai.py +288 -74
  187. endoreg_db/models/media/video/video_file_anonymize.py +38 -38
  188. endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
  189. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
  190. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
  191. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
  192. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
  193. endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
  194. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
  195. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
  196. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
  197. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
  198. endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
  199. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
  200. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
  201. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
  202. endoreg_db/models/media/video/video_file_io.py +109 -62
  203. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
  204. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
  205. endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
  206. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
  207. endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
  208. endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
  209. endoreg_db/models/media/video/video_file_segments.py +24 -17
  210. endoreg_db/models/media/video/video_metadata.py +19 -35
  211. endoreg_db/models/media/video/video_processing.py +96 -95
  212. endoreg_db/models/medical/contraindication/__init__.py +13 -3
  213. endoreg_db/models/medical/disease.py +22 -16
  214. endoreg_db/models/medical/event.py +31 -18
  215. endoreg_db/models/medical/examination/__init__.py +13 -6
  216. endoreg_db/models/medical/examination/examination.py +17 -18
  217. endoreg_db/models/medical/examination/examination_indication.py +26 -25
  218. endoreg_db/models/medical/examination/examination_time.py +16 -6
  219. endoreg_db/models/medical/examination/examination_time_type.py +9 -6
  220. endoreg_db/models/medical/examination/examination_type.py +3 -4
  221. endoreg_db/models/medical/finding/finding.py +38 -39
  222. endoreg_db/models/medical/finding/finding_classification.py +37 -48
  223. endoreg_db/models/medical/finding/finding_intervention.py +27 -22
  224. endoreg_db/models/medical/finding/finding_type.py +13 -12
  225. endoreg_db/models/medical/hardware/endoscope.py +20 -26
  226. endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
  227. endoreg_db/models/medical/laboratory/lab_value.py +62 -91
  228. endoreg_db/models/medical/medication/medication.py +22 -10
  229. endoreg_db/models/medical/medication/medication_indication.py +29 -3
  230. endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
  231. endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
  232. endoreg_db/models/medical/medication/medication_schedule.py +27 -16
  233. endoreg_db/models/medical/organ/__init__.py +15 -12
  234. endoreg_db/models/medical/patient/medication_examples.py +1 -5
  235. endoreg_db/models/medical/patient/patient_disease.py +20 -23
  236. endoreg_db/models/medical/patient/patient_event.py +19 -22
  237. endoreg_db/models/medical/patient/patient_examination.py +48 -54
  238. endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
  239. endoreg_db/models/medical/patient/patient_finding.py +122 -139
  240. endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
  241. endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
  242. endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
  243. endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
  244. endoreg_db/models/medical/patient/patient_medication.py +27 -38
  245. endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
  246. endoreg_db/models/medical/risk/risk.py +7 -6
  247. endoreg_db/models/medical/risk/risk_type.py +8 -5
  248. endoreg_db/models/metadata/model_meta.py +60 -29
  249. endoreg_db/models/metadata/model_meta_logic.py +125 -18
  250. endoreg_db/models/metadata/pdf_meta.py +19 -24
  251. endoreg_db/models/metadata/sensitive_meta.py +102 -85
  252. endoreg_db/models/metadata/sensitive_meta_logic.py +192 -173
  253. endoreg_db/models/metadata/video_meta.py +51 -31
  254. endoreg_db/models/metadata/video_prediction_logic.py +16 -23
  255. endoreg_db/models/metadata/video_prediction_meta.py +29 -33
  256. endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
  257. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
  258. endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
  259. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
  260. endoreg_db/models/other/emission/emission_factor.py +18 -8
  261. endoreg_db/models/other/gender.py +10 -5
  262. endoreg_db/models/other/information_source.py +25 -25
  263. endoreg_db/models/other/material.py +9 -5
  264. endoreg_db/models/other/resource.py +6 -4
  265. endoreg_db/models/other/tag.py +10 -5
  266. endoreg_db/models/other/transport_route.py +13 -8
  267. endoreg_db/models/other/unit.py +10 -6
  268. endoreg_db/models/other/waste.py +6 -5
  269. endoreg_db/models/requirement/requirement.py +580 -272
  270. endoreg_db/models/requirement/requirement_error.py +85 -0
  271. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
  272. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
  273. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
  274. endoreg_db/models/requirement/requirement_operator.py +36 -33
  275. endoreg_db/models/requirement/requirement_set.py +74 -57
  276. endoreg_db/models/state/__init__.py +4 -4
  277. endoreg_db/models/state/abstract.py +2 -2
  278. endoreg_db/models/state/anonymization.py +12 -0
  279. endoreg_db/models/state/audit_ledger.py +46 -47
  280. endoreg_db/models/state/label_video_segment.py +9 -0
  281. endoreg_db/models/state/raw_pdf.py +40 -46
  282. endoreg_db/models/state/sensitive_meta.py +6 -2
  283. endoreg_db/models/state/video.py +58 -53
  284. endoreg_db/models/upload_job.py +32 -55
  285. endoreg_db/models/utils.py +1 -2
  286. endoreg_db/root_urls.py +21 -2
  287. endoreg_db/serializers/__init__.py +0 -2
  288. endoreg_db/serializers/anonymization.py +18 -10
  289. endoreg_db/serializers/meta/report_meta.py +1 -1
  290. endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
  291. endoreg_db/serializers/misc/file_overview.py +11 -99
  292. endoreg_db/serializers/requirements/requirement_sets.py +92 -22
  293. endoreg_db/serializers/video/segmentation.py +2 -1
  294. endoreg_db/serializers/video/video_processing_history.py +20 -5
  295. endoreg_db/services/anonymization.py +75 -73
  296. endoreg_db/services/lookup_service.py +37 -24
  297. endoreg_db/services/pdf_import.py +166 -68
  298. endoreg_db/services/storage_aware_video_processor.py +140 -114
  299. endoreg_db/services/video_import.py +193 -283
  300. endoreg_db/urls/__init__.py +7 -20
  301. endoreg_db/urls/media.py +108 -67
  302. endoreg_db/urls/root_urls.py +29 -0
  303. endoreg_db/utils/__init__.py +15 -5
  304. endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
  305. endoreg_db/utils/case_generator/__init__.py +3 -0
  306. endoreg_db/utils/dataloader.py +88 -16
  307. endoreg_db/utils/defaults/set_default_center.py +32 -0
  308. endoreg_db/utils/names.py +22 -16
  309. endoreg_db/utils/permissions.py +2 -1
  310. endoreg_db/utils/pipelines/process_video_dir.py +1 -1
  311. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +414 -127
  312. endoreg_db/utils/setup_config.py +8 -5
  313. endoreg_db/utils/storage.py +115 -0
  314. endoreg_db/utils/validate_endo_roi.py +8 -2
  315. endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
  316. endoreg_db/views/__init__.py +0 -10
  317. endoreg_db/views/anonymization/media_management.py +198 -163
  318. endoreg_db/views/anonymization/overview.py +4 -1
  319. endoreg_db/views/anonymization/validate.py +174 -40
  320. endoreg_db/views/media/__init__.py +2 -0
  321. endoreg_db/views/media/pdf_media.py +131 -152
  322. endoreg_db/views/media/sensitive_metadata.py +46 -6
  323. endoreg_db/views/media/video_media.py +89 -82
  324. endoreg_db/views/media/video_segments.py +2 -3
  325. endoreg_db/views/meta/sensitive_meta_detail.py +0 -63
  326. endoreg_db/views/patient/patient.py +5 -4
  327. endoreg_db/views/pdf/pdf_stream.py +20 -21
  328. endoreg_db/views/pdf/reimport.py +11 -32
  329. endoreg_db/views/requirement/evaluate.py +188 -187
  330. endoreg_db/views/requirement/lookup.py +17 -3
  331. endoreg_db/views/requirement/requirement_utils.py +89 -0
  332. endoreg_db/views/video/__init__.py +0 -2
  333. endoreg_db/views/video/correction.py +2 -2
  334. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/METADATA +7 -3
  335. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/RECORD +341 -245
  336. endoreg_db/models/administration/permissions/__init__.py +0 -44
  337. endoreg_db/models/media/video/video_file_frames.py +0 -0
  338. endoreg_db/models/metadata/frame_ocr_result.py +0 -0
  339. endoreg_db/models/rule/__init__.py +0 -13
  340. endoreg_db/models/rule/rule.py +0 -27
  341. endoreg_db/models/rule/rule_applicator.py +0 -224
  342. endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
  343. endoreg_db/models/rule/rule_type.py +0 -20
  344. endoreg_db/models/rule/ruleset.py +0 -17
  345. endoreg_db/serializers/video/video_metadata.py +0 -105
  346. endoreg_db/urls/report.py +0 -48
  347. endoreg_db/urls/video.py +0 -61
  348. endoreg_db/utils/case_generator/case_generator.py +0 -159
  349. endoreg_db/utils/case_generator/utils.py +0 -30
  350. endoreg_db/views/report/__init__.py +0 -9
  351. endoreg_db/views/report/report_list.py +0 -112
  352. endoreg_db/views/report/report_with_secure_url.py +0 -28
  353. endoreg_db/views/report/start_examination.py +0 -7
  354. endoreg_db/views.py +0 -0
  355. /endoreg_db/data/{requirement_set → _examples/requirement_set}/endoscopy_bleeding_risk.yaml +0 -0
  356. /endoreg_db/migrations/{0002_add_video_correction_models.py → _old/0002_add_video_correction_models.py} +0 -0
  357. /endoreg_db/migrations/{0003_add_center_display_name.py → _old/0003_add_center_display_name.py} +0 -0
  358. /endoreg_db/{models/media/video/refactor_plan.md → views/pdf/pdf_stream_views.py} +0 -0
  359. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/WHEEL +0 -0
  360. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,31 +1,33 @@
1
1
  # endoreg_db/services/anonymization.py
2
+ import logging
2
3
  from pathlib import Path
4
+ from typing import Optional
5
+
3
6
  from django.db import transaction
4
- from django.conf import settings
5
- from endoreg_db.models import VideoFile, RawPdfFile
6
- from endoreg_db.services.video_import import VideoImportService
7
+
8
+ from endoreg_db.models import RawPdfFile, VideoFile
7
9
  from endoreg_db.services.pdf_import import PdfImportService
10
+ from endoreg_db.services.video_import import VideoImportService
8
11
  from endoreg_db.utils.paths import STORAGE_DIR
9
- import logging
12
+ from endoreg_db.utils.storage import ensure_local_file, file_exists
10
13
 
11
14
  logger = logging.getLogger(__name__)
12
15
 
16
+
13
17
  class AnonymizationService:
14
18
  """
15
19
  Orchestrates long‑running anonymization tasks so the view only
16
20
  does HTTP <-> Service translation.
17
21
  """
18
-
19
- def __init__(self, project_root: Path = None):
22
+
23
+ def __init__(self, project_root: Optional[Path] = None):
20
24
  """
21
25
  Initialize the AnonymizationService with service instances.
22
-
26
+
23
27
  Args:
24
28
  project_root: Path to the project root. If None, uses settings.BASE_DIR
25
29
  """
26
- if project_root is None:
27
- project_root = STORAGE_DIR
28
-
30
+ self.project_root: Path = project_root or STORAGE_DIR
29
31
  self.video_service = VideoImportService()
30
32
  self.pdf_service = PdfImportService()
31
33
 
@@ -34,7 +36,7 @@ class AnonymizationService:
34
36
  def get_status(file_id: int):
35
37
  """
36
38
  Retrieve the anonymization status and media type for a file by its ID.
37
-
39
+
38
40
  Returns:
39
41
  dict or None: A dictionary containing the file's media type and anonymization status if found, or None if no matching file exists.
40
42
  """
@@ -43,7 +45,7 @@ class AnonymizationService:
43
45
  return {
44
46
  "mediaType": "video",
45
47
  "anonymizationStatus": vf.state.anonymization_status if vf.state else "not_started",
46
- "fileExists": bool(vf.raw_file and hasattr(vf.raw_file, 'path')),
48
+ "fileExists": file_exists(vf.raw_file),
47
49
  "uuid": str(vf.uuid) if vf.uuid else None,
48
50
  }
49
51
 
@@ -52,7 +54,7 @@ class AnonymizationService:
52
54
  return {
53
55
  "mediaType": "pdf",
54
56
  "anonymizationStatus": pdf.state.anonymization_status if pdf.state else "not_started",
55
- "fileExists": bool(pdf.file and hasattr(pdf.file, 'path')),
57
+ "fileExists": file_exists(pdf.file),
56
58
  "hash": pdf.pdf_hash,
57
59
  }
58
60
  return None
@@ -62,10 +64,10 @@ class AnonymizationService:
62
64
  def start(self, file_id: int):
63
65
  """
64
66
  Start anonymization process for a file by its ID.
65
-
67
+
66
68
  Args:
67
69
  file_id: The ID of the file to anonymize
68
-
70
+
69
71
  Returns:
70
72
  str or None: Media type if successful, None if file not found
71
73
  """
@@ -74,45 +76,42 @@ class AnonymizationService:
74
76
  if vf:
75
77
  try:
76
78
  logger.info(f"Starting video anonymization for VideoFile ID: {file_id}")
77
-
79
+
78
80
  # Check if already processed
79
81
  if vf.state and vf.state.anonymized:
80
82
  logger.info(f"VideoFile {file_id} already anonymized, skipping")
81
83
  return "video"
82
-
84
+
83
85
  # Get file path
84
86
  file_path = vf.get_raw_file_path()
85
87
  if not file_path or not Path(file_path).exists():
86
88
  logger.error(f"Raw file not found for VideoFile {file_id}: {file_path}")
87
89
  return None
88
-
90
+
89
91
  # Get processor name
90
92
  processor_name = None
91
93
  if vf.video_meta and vf.video_meta.processor:
92
94
  processor_name = vf.video_meta.processor.name
93
- elif hasattr(vf, 'processor') and vf.processor:
95
+ elif hasattr(vf, "processor") and vf.processor:
94
96
  processor_name = vf.processor.name
95
-
97
+
96
98
  # Get center name
97
99
  center_name = vf.center.name if vf.center else "unknown_center"
98
-
100
+
99
101
  # Mark as started
100
102
  if vf.state:
101
103
  vf.state.processing_started = True
102
104
  vf.state.save(update_fields=["processing_started"])
103
-
105
+
104
106
  # Use VideoImportService for anonymization
107
+ safe_processor_name = processor_name or "unknown_processor"
105
108
  self.video_service.import_and_anonymize(
106
- file_path=file_path,
107
- center_name=center_name,
108
- processor_name=processor_name,
109
- save_video=True,
110
- delete_source=False
109
+ file_path=file_path, center_name=center_name, processor_name=safe_processor_name, save_video=True, delete_source=False
111
110
  )
112
-
111
+
113
112
  logger.info(f"Video anonymization completed for VideoFile ID: {file_id}")
114
113
  return "video"
115
-
114
+
116
115
  except Exception as e:
117
116
  logger.error(f"Failed to anonymize VideoFile {file_id}: {e}")
118
117
  # Mark as failed if state exists
@@ -126,51 +125,48 @@ class AnonymizationService:
126
125
  if pdf:
127
126
  try:
128
127
  logger.info(f"Starting PDF processing for RawPdfFile ID: {file_id}")
129
-
128
+
130
129
  # Check if already processed
131
- if pdf.state and getattr(pdf.state, 'anonymized', False):
130
+ if pdf.state and getattr(pdf.state, "anonymized", False):
132
131
  logger.info(f"RawPdfFile {file_id} already processed, skipping")
133
132
  return "pdf"
134
-
135
- # Get file path
136
- if not pdf.file or not hasattr(pdf.file, 'path'):
133
+
134
+ file_field = pdf.file
135
+ if not file_field or not file_field.name:
137
136
  logger.error(f"PDF file not found for RawPdfFile {file_id}")
138
137
  return None
139
-
140
- file_path = Path(pdf.file.path)
141
- if not file_path.exists():
142
- logger.error(f"PDF file does not exist: {file_path}")
138
+
139
+ if not file_exists(file_field):
140
+ logger.error("PDF file missing from storage for RawPdfFile %s", file_id)
143
141
  return None
144
-
142
+
145
143
  # Get center name
146
144
  center_name = pdf.center.name if pdf.center else "unknown_center"
147
-
145
+
148
146
  # Mark as started
149
147
  if pdf.state:
150
148
  pdf.state.processing_started = True
151
149
  pdf.state.save(update_fields=["processing_started"])
152
- elif pdf.sensitive_meta:
150
+ elif pdf.sensitive_meta and hasattr(pdf.sensitive_meta, "anonymization_started"):
153
151
  pdf.sensitive_meta.anonymization_started = True
154
152
  pdf.sensitive_meta.save(update_fields=["anonymization_started"])
155
-
156
-
157
- # Use PdfImportService for processing
158
- # Use PdfImportService for processing
159
- self.pdf_service.import_and_anonymize(
160
- file_path=file_path,
161
- center_name=center_name,
162
- )
163
-
153
+
154
+ with ensure_local_file(file_field) as local_path:
155
+ self.pdf_service.import_and_anonymize(
156
+ file_path=local_path,
157
+ center_name=center_name,
158
+ )
159
+
164
160
  logger.info(f"PDF processing completed for RawPdfFile ID: {file_id}")
165
161
  return "pdf"
166
-
162
+
167
163
  except Exception as e:
168
164
  logger.error(f"Failed to process RawPdfFile {file_id}: {e}")
169
165
  # Mark as failed if state exists
170
- if pdf.state:
166
+ if pdf.state and hasattr(pdf.state, "processing_failed"):
171
167
  pdf.state.processing_failed = True
172
168
  pdf.state.save(update_fields=["processing_failed"])
173
- elif pdf.sensitive_meta:
169
+ elif pdf.sensitive_meta and hasattr(pdf.sensitive_meta, "processing_failed"):
174
170
  pdf.sensitive_meta.processing_failed = True
175
171
  pdf.sensitive_meta.save(update_fields=["processing_failed"])
176
172
  raise
@@ -183,41 +179,47 @@ class AnonymizationService:
183
179
  def validate(file_id: int):
184
180
  vf = VideoFile.objects.select_related("state").filter(pk=file_id).first()
185
181
  if vf:
186
- vf.state.mark_anonymization_validated()
182
+ state = vf.state or vf.get_or_create_state()
183
+ if hasattr(state, "mark_anonymization_validated"):
184
+ state.mark_anonymization_validated()
187
185
  return "video"
188
186
 
189
187
  pdf = RawPdfFile.objects.select_related("state").filter(pk=file_id).first()
190
188
  if pdf:
191
- pdf.state.mark_anonymization_validated()
189
+ state = pdf.state or pdf.get_or_create_state()
190
+ if hasattr(state, "mark_anonymization_validated"):
191
+ state.mark_anonymization_validated()
192
192
  return "pdf"
193
193
 
194
194
  return None
195
-
195
+
196
+ @staticmethod
196
197
  def list_items():
197
198
  video_files = VideoFile.objects.select_related("state").all()
198
199
  pdf_files = RawPdfFile.objects.select_related("state").all() # was sensitive_meta
199
200
 
200
201
  data = []
201
202
  for vf in video_files:
202
- data.append({
203
- "id": vf.id,
204
- "mediaType": "video",
205
- "anonymizationStatus": vf.state.anonymization_status if vf.state else "not_started",
206
- "createdAt": vf.date_created,
207
- "updatedAt": vf.date_modified,
208
- })
209
-
210
-
203
+ data.append(
204
+ {
205
+ "id": vf.pk,
206
+ "mediaType": "video",
207
+ "anonymizationStatus": vf.state.anonymization_status if vf.state else "not_started",
208
+ "createdAt": vf.date_created,
209
+ "updatedAt": vf.date_modified,
210
+ }
211
+ )
211
212
 
212
213
  for pdf in pdf_files:
213
- data.append({
214
- "id": pdf.id,
215
- "mediaType": "pdf",
216
- "anonymizationStatus": pdf.state.anonymization_status if pdf.state else "not_started",
217
- "createdAt": pdf.date_created,
218
- "updatedAt": pdf.date_modified,
219
- })
214
+ data.append(
215
+ {
216
+ "id": pdf.pk,
217
+ "mediaType": "pdf",
218
+ "anonymizationStatus": pdf.state.anonymization_status if pdf.state else "not_started",
219
+ "createdAt": pdf.date_created,
220
+ "updatedAt": pdf.date_modified,
221
+ }
222
+ )
220
223
  return data
221
224
 
222
-
223
225
  return data
@@ -24,9 +24,10 @@ Architecture:
24
24
  # services/lookup_service.py
25
25
  from __future__ import annotations
26
26
 
27
- from typing import Any, Dict, List
27
+ import logging
28
+ from typing import Any, Dict, List, Optional
28
29
 
29
- from django.db.models import Prefetch
30
+ from django.db.models import Prefetch, QuerySet
30
31
 
31
32
  from endoreg_db.models.medical.examination import ExaminationRequirementSet
32
33
  from endoreg_db.models.medical.patient.patient_examination import PatientExamination
@@ -88,31 +89,43 @@ def load_patient_exam_for_eval(pk: int) -> PatientExamination:
88
89
  )
89
90
 
90
91
 
91
- 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:
92
95
  """
93
- Get all requirement sets applicable to a patient examination.
94
-
95
- This function resolves requirement sets through the examination's requirement set links.
96
- It follows the relationship: PatientExamination → Examination → ExaminationRequirementSet → RequirementSet
96
+ Retrieve all RequirementSets linked to a PatientExamination's examination.
97
97
 
98
98
  Args:
99
- pe: PatientExamination instance to get requirement sets for
99
+ pe: PatientExamination instance
100
+ user_tags: Optional list of tag names to filter requirement sets
100
101
 
101
102
  Returns:
102
- List of RequirementSet instances applicable to the examination, with related data prefetched
103
+ QuerySet of RequirementSet instances
103
104
  """
104
- exam = pe.examination
105
- if not exam:
106
- return []
107
- return list(
108
- RequirementSet.objects.filter(reqset_exam_links__examinations=exam)
109
- .select_related("requirement_set_type")
110
- .prefetch_related("requirements")
111
- .distinct()
112
- )
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
113
116
 
117
+ qs = RequirementSet.objects.filter(pk__in=req_sets)
114
118
 
115
- 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]:
116
129
  """
117
130
  Build the initial lookup dictionary for a patient examination.
118
131
 
@@ -153,7 +166,7 @@ def build_initial_lookup(pe: PatientExamination) -> Dict[str, Any]:
153
166
  required_findings: List[int] = [] # fill by scanning requirements below
154
167
 
155
168
  # Requirement sets: ids + meta
156
- rs_objs = requirement_sets_for_patient_exam(pe)
169
+ rs_objs = requirement_sets_for_patient_exam(pe, user_tags=user_tags)
157
170
  requirement_sets = [
158
171
  {
159
172
  "id": rs.id,
@@ -202,7 +215,9 @@ def build_initial_lookup(pe: PatientExamination) -> Dict[str, Any]:
202
215
  }
203
216
 
204
217
 
205
- def create_lookup_token_for_pe(pe_id: int) -> str:
218
+ def create_lookup_token_for_pe(
219
+ pe_id: int, user_tags: Optional[List[str]] = None
220
+ ) -> str:
206
221
  """
207
222
  Create a lookup token for a patient examination.
208
223
 
@@ -220,7 +235,7 @@ def create_lookup_token_for_pe(pe_id: int) -> str:
220
235
  Exception: For any other errors during initialization
221
236
  """
222
237
  pe = load_patient_exam_for_eval(pe_id)
223
- token = LookupStore().init(build_initial_lookup(pe))
238
+ token = LookupStore().init(build_initial_lookup(pe, user_tags=user_tags))
224
239
  return token
225
240
 
226
241
 
@@ -255,8 +270,6 @@ def recompute_lookup(token: str) -> Dict[str, Any]:
255
270
  Raises:
256
271
  ValueError: If lookup data is invalid or patient examination not found
257
272
  """
258
- import logging
259
-
260
273
  logger = logging.getLogger(__name__)
261
274
 
262
275
  store = LookupStore(token=token)