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,30 +1,14 @@
1
1
  # ReportReaderConfig Class
2
- # Description: This class is used to store the configuration of the ReportReader
3
-
4
- # PATIENT_INFO_LINE_FLAG = "Patient: "
5
- # ENDOSCOPE_INFO_LINE_FLAG = "Gerät: "
6
- # EXAMINER_INFO_LINE_FLAG = "1. Unters.:"
7
- # CUT_OFF_BELOW_LINE_FLAG = "________________"
8
-
9
-
10
- # CUT_OFF_ABOVE_LINE_FLAGS = [
11
- # ENDOSCOPE_INFO_LINE_FLAG,
12
- # EXAMINER_INFO_LINE_FLAG,
13
- # ]
14
-
15
- # CUT_OFF_BELOW_LINE_FLAGS = [
16
- # CUT_OFF_BELOW_LINE_FLAG
17
- # ]
2
+ from typing import TYPE_CHECKING, cast
18
3
 
19
4
  from django.db import models
20
5
 
21
-
22
- from typing import TYPE_CHECKING
23
6
  if TYPE_CHECKING:
24
- from .report_reader_flag import ReportReaderFlag
25
- from ....administration.person import FirstName, LastName
26
7
  from ....administration.center import Center
8
+ from ....administration.person import FirstName, LastName
27
9
  from ....metadata import PdfType
10
+ from .report_reader_flag import ReportReaderFlag
11
+
28
12
 
29
13
  class ReportReaderConfig(models.Model):
30
14
  """
@@ -33,45 +17,45 @@ class ReportReaderConfig(models.Model):
33
17
  Stores locale, name lists, date format, and flags used to identify key information lines
34
18
  and text sections to ignore.
35
19
  """
20
+
36
21
  locale = models.CharField(default="de_DE", max_length=10)
37
- first_names = models.ManyToManyField('FirstName', related_name='report_reader_configs')
38
- last_names = models.ManyToManyField('LastName', related_name='report_reader_configs')
39
- text_date_format = models.CharField(default = "%d.%m.%Y", max_length=10)
40
- patient_info_line_flag = models.ForeignKey("ReportReaderFlag", related_name='report_reader_configs_patient_info_line', on_delete=models.CASCADE)
41
- endoscope_info_line_flag = models.ForeignKey("ReportReaderFlag", related_name='report_reader_configs_endoscope_info_line', on_delete=models.CASCADE)
42
- examiner_info_line_flag = models.ForeignKey("ReportReaderFlag", related_name='report_reader_configs_examiner_info_line', on_delete=models.CASCADE)
43
- cut_off_below = models.ManyToManyField("ReportReaderFlag", related_name='report_reader_configs_cut_off_below')
44
- cut_off_above = models.ManyToManyField("ReportReaderFlag", related_name='report_reader_configs_cut_off_above')
45
-
22
+ first_names = models.ManyToManyField("FirstName", related_name="report_reader_configs")
23
+ last_names = models.ManyToManyField("LastName", related_name="report_reader_configs")
24
+ text_date_format = models.CharField(default="%d.%m.%Y", max_length=10)
25
+ patient_info_line_flag = models.ForeignKey("ReportReaderFlag", related_name="report_reader_configs_patient_info_line", on_delete=models.CASCADE)
26
+ endoscope_info_line_flag = models.ForeignKey("ReportReaderFlag", related_name="report_reader_configs_endoscope_info_line", on_delete=models.CASCADE)
27
+ examiner_info_line_flag = models.ForeignKey("ReportReaderFlag", related_name="report_reader_configs_examiner_info_line", on_delete=models.CASCADE)
28
+ cut_off_below = models.ManyToManyField("ReportReaderFlag", related_name="report_reader_configs_cut_off_below")
29
+ cut_off_above = models.ManyToManyField("ReportReaderFlag", related_name="report_reader_configs_cut_off_above")
30
+
46
31
  if TYPE_CHECKING:
47
- first_names: models.QuerySet["FirstName"]
48
- last_names: models.QuerySet["LastName"]
49
- patient_info_line_flag: "ReportReaderFlag"
50
- endoscope_info_line_flag: "ReportReaderFlag"
51
- examiner_info_line_flag: "ReportReaderFlag"
52
- cut_off_below: models.QuerySet["ReportReaderFlag"]
53
- cut_off_above: models.QuerySet["ReportReaderFlag"]
54
-
32
+ patient_info_line_flag = models.ForeignKey["ReportReaderFlag"]
33
+ endoscope_info_line_flag = models.ForeignKey["ReportReaderFlag"]
34
+ examiner_info_line_flag = models.ForeignKey["ReportReaderFlag"]
35
+
36
+ first_names = cast(models.manager.RelatedManager["FirstName"], first_names)
37
+ last_names = cast(models.manager.RelatedManager["LastName"], last_names)
38
+ cut_off_below = cast(models.manager.RelatedManager["ReportReaderFlag"], cut_off_below)
39
+ cut_off_above = cast(models.manager.RelatedManager["ReportReaderFlag"], cut_off_above)
55
40
 
56
41
  def __str__(self):
57
42
  """Returns a string representation including the locale and primary key."""
58
43
  _str = f"ReportReaderConfig: {self.locale} (id: {self.pk}\n"
59
44
  return _str
60
-
61
- def update_names_by_center(self, center:"Center", save = True):
45
+
46
+ def update_names_by_center(self, center: "Center", save=True):
62
47
  """Updates the first and last name lists based on the names associated with a Center."""
63
48
  self.first_names.set(center.first_names.all())
64
49
  self.last_names.set(center.last_names.all())
65
50
  if save:
66
51
  self.save()
67
52
 
68
- def update_flags_by_pdf_type(self, pdf_type:"PdfType", save = True):
53
+ def update_flags_by_pdf_type(self, pdf_type: "PdfType", save=True):
69
54
  """Updates the line identification flags based on a specific PdfType."""
70
- self.patient_info_line_flag = pdf_type.patient_info_line_flag
71
- self.endoscope_info_line_flag = pdf_type.endoscope_info_line_flag
72
- self.examiner_info_line_flag = pdf_type.examiner_info_line_flag
73
- self.cut_off_below.set(pdf_type.cut_off_below.all())
74
- self.cut_off_above.set(pdf_type.cut_off_above.all())
55
+ self.patient_info_line_flag = pdf_type.patient_info_line
56
+ self.endoscope_info_line_flag = pdf_type.endoscope_info_line
57
+ self.examiner_info_line_flag = pdf_type.examiner_info_line
58
+ self.cut_off_below.set(pdf_type.cut_off_below_lines.all())
59
+ self.cut_off_above.set(pdf_type.cut_off_above_lines.all())
75
60
  if save:
76
61
  self.save()
77
-
@@ -1,20 +1,36 @@
1
- # Django model for the report reader flag
2
- # have name and value
3
- # name is natural key
1
+ from typing import TYPE_CHECKING
4
2
 
5
3
  from django.db import models
6
4
 
5
+ if TYPE_CHECKING:
6
+ from endoreg_db.models import ReportReaderConfig
7
+
8
+
7
9
  class ReportReaderFlagManager(models.Manager):
8
10
  def get_by_natural_key(self, name):
9
11
  return self.get(name=name)
10
-
12
+
13
+
11
14
  class ReportReaderFlag(models.Model):
12
15
  objects = ReportReaderFlagManager()
13
16
  name = models.CharField(max_length=255, unique=True)
14
17
  value = models.CharField(max_length=255)
15
-
18
+
19
+ if TYPE_CHECKING:
20
+
21
+ @property
22
+ def report_reader_configs_patient_info_line(self) -> models.QuerySet["ReportReaderConfig"]: ...
23
+ @property
24
+ def report_reader_configs_endoscope_info_line(self) -> models.QuerySet["ReportReaderConfig"]: ...
25
+ @property
26
+ def report_reader_configs_examiner_info_line(self) -> models.QuerySet["ReportReaderConfig"]: ...
27
+ @property
28
+ def report_reader_configs_cut_off_below(self) -> models.QuerySet["ReportReaderConfig"]: ...
29
+ @property
30
+ def report_reader_configs_cut_off_above(self) -> models.QuerySet["ReportReaderConfig"]: ...
31
+
16
32
  def natural_key(self):
17
33
  return (self.name,)
18
-
34
+
19
35
  def __str__(self):
20
- return self.name
36
+ return self.name
@@ -1,6 +1,7 @@
1
1
  from .video_file import VideoFile
2
2
  from .video_metadata import VideoMetadata
3
3
  from .video_processing import VideoProcessingHistory
4
+
4
5
  __all__ = [
5
6
  "VideoFile",
6
7
  "VideoMetadata",
@@ -1,20 +1,21 @@
1
- import shutil
2
1
  import logging
2
+ import shutil
3
3
  import uuid
4
+ from importlib import import_module
4
5
  from pathlib import Path
5
6
  from typing import TYPE_CHECKING, Optional, Type
6
7
 
7
8
  # Import the new exceptions from the correct path
8
9
  from endoreg_db.exceptions import InsufficientStorageError, TranscodingError
9
- from ...utils import VIDEO_DIR, TMP_VIDEO_DIR
10
- from importlib import import_module
10
+
11
+ from ...utils import TMP_VIDEO_DIR, VIDEO_DIR
11
12
 
12
13
  if TYPE_CHECKING:
13
14
  from endoreg_db.models import VideoFile
14
15
 
15
- from ....utils.video.ffmpeg_wrapper import transcode_videofile_if_required
16
- from ....utils.hashs import get_video_hash
17
16
  from ....utils.file_operations import get_uuid_filename
17
+ from ....utils.hashs import get_video_hash
18
+ from ....utils.video.ffmpeg_wrapper import transcode_videofile_if_required
18
19
 
19
20
  logger = logging.getLogger(__name__)
20
21
 
@@ -22,33 +23,31 @@ logger = logging.getLogger(__name__)
22
23
  def check_storage_capacity(src_path: Path, dst_root: Path, safety_margin: float = 1.2) -> None:
23
24
  """
24
25
  Check if there's enough storage space before starting operations.
25
-
26
+
26
27
  Args:
27
28
  src_path: Source file path
28
29
  dst_root: Destination root directory
29
30
  safety_margin: Safety factor (1.2 = 20% extra space required)
30
-
31
+
31
32
  Raises:
32
33
  InsufficientStorageError: If insufficient storage space
33
34
  """
34
35
  try:
35
36
  src_size = src_path.stat().st_size
36
37
  required_space = int(src_size * safety_margin)
37
-
38
+
38
39
  # Check free space on destination
39
40
  free_space = shutil.disk_usage(dst_root).free
40
-
41
+
41
42
  if free_space < required_space:
42
43
  raise InsufficientStorageError(
43
- f"Insufficient storage space. Required: {required_space/1e9:.1f} GB, "
44
- f"Available: {free_space/1e9:.1f} GB on {dst_root}",
44
+ f"Insufficient storage space. Required: {required_space / 1e9:.1f} GB, Available: {free_space / 1e9:.1f} GB on {dst_root}",
45
45
  required_space=required_space,
46
- available_space=free_space
46
+ available_space=free_space,
47
47
  )
48
-
49
- logger.info(f"Storage check passed: {free_space/1e9:.1f} GB available, "
50
- f"{required_space/1e9:.1f} GB required")
51
-
48
+
49
+ logger.info(f"Storage check passed: {free_space / 1e9:.1f} GB available, {required_space / 1e9:.1f} GB required")
50
+
52
51
  except OSError as e:
53
52
  logger.warning(f"Could not check storage capacity: {e}")
54
53
  # Don't fail the operation, just log the warning
@@ -57,14 +56,14 @@ def check_storage_capacity(src_path: Path, dst_root: Path, safety_margin: float
57
56
  def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
58
57
  """
59
58
  Atomically copy file from src to dst, preserving the source file.
60
-
59
+
61
60
  Args:
62
61
  src_path: Source file path
63
62
  dst_path: Destination file path
64
-
63
+
65
64
  Returns:
66
65
  True if successful
67
-
66
+
68
67
  Raises:
69
68
  InsufficientStorageError: If not enough space for the operation
70
69
  OSError: For other file system errors
@@ -73,18 +72,17 @@ def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
73
72
  # Check space before copy
74
73
  src_size = src_path.stat().st_size
75
74
  free_space = shutil.disk_usage(dst_path.parent).free
76
-
75
+
77
76
  if free_space < src_size * 1.1: # 10% safety margin
78
77
  raise InsufficientStorageError(
79
- f"Insufficient space for copy operation. Required: {src_size/1e9:.1f} GB, "
80
- f"Available: {free_space/1e9:.1f} GB",
78
+ f"Insufficient space for copy operation. Required: {src_size / 1e9:.1f} GB, Available: {free_space / 1e9:.1f} GB",
81
79
  required_space=src_size,
82
- available_space=free_space
80
+ available_space=free_space,
83
81
  )
84
-
82
+
85
83
  # Use a temporary name during copy for atomicity
86
- temp_dst = dst_path.with_suffix(dst_path.suffix + '.tmp')
87
-
84
+ temp_dst = dst_path.with_suffix(dst_path.suffix + ".tmp")
85
+
88
86
  try:
89
87
  shutil.copy2(str(src_path), str(temp_dst))
90
88
  temp_dst.rename(dst_path)
@@ -95,7 +93,7 @@ def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
95
93
  if temp_dst.exists():
96
94
  temp_dst.unlink(missing_ok=True)
97
95
  raise
98
-
96
+
99
97
  except Exception as e:
100
98
  logger.error(f"Copy operation failed: {src_path} -> {dst_path}: {e}")
101
99
  raise
@@ -104,14 +102,14 @@ def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
104
102
  def atomic_move_with_fallback(src_path: Path, dst_path: Path) -> bool:
105
103
  """
106
104
  Atomically move file from src to dst, with fallback to copy+remove.
107
-
105
+
108
106
  Args:
109
107
  src_path: Source file path
110
108
  dst_path: Destination file path
111
-
109
+
112
110
  Returns:
113
111
  True if successful
114
-
112
+
115
113
  Raises:
116
114
  InsufficientStorageError: If not enough space for the operation
117
115
  OSError: For other file system errors
@@ -127,32 +125,31 @@ def atomic_move_with_fallback(src_path: Path, dst_path: Path) -> bool:
127
125
  logger.debug("Cross-device move detected, falling back to copy+remove")
128
126
  else:
129
127
  raise
130
-
128
+
131
129
  # Check space before cross-filesystem copy
132
130
  src_size = src_path.stat().st_size
133
131
  free_space = shutil.disk_usage(dst_path.parent).free
134
-
132
+
135
133
  if free_space < src_size * 1.1: # 10% safety margin
136
134
  raise InsufficientStorageError(
137
- f"Insufficient space for copy operation. Required: {src_size/1e9:.1f} GB, "
138
- f"Available: {free_space/1e9:.1f} GB",
135
+ f"Insufficient space for copy operation. Required: {src_size / 1e9:.1f} GB, Available: {free_space / 1e9:.1f} GB",
139
136
  required_space=src_size,
140
- available_space=free_space
137
+ available_space=free_space,
141
138
  )
142
-
139
+
143
140
  # Fallback to copy+remove for cross-filesystem moves
144
141
  logger.info(f"Copying file (cross-filesystem): {src_path} -> {dst_path}")
145
-
142
+
146
143
  # Use a temporary name during copy for atomicity
147
- temp_dst = dst_path.with_suffix(dst_path.suffix + '.tmp')
148
-
144
+ temp_dst = dst_path.with_suffix(dst_path.suffix + ".tmp")
145
+
149
146
  try:
150
147
  shutil.copy2(str(src_path), str(temp_dst))
151
148
  temp_dst.rename(dst_path)
152
149
  src_path.unlink() # Remove source only after successful copy
153
150
  logger.debug(f"Copy+remove successful: {src_path} -> {dst_path}")
154
151
  return True
155
-
152
+
156
153
  except OSError as e:
157
154
  # Clean up temp file on failure
158
155
  if temp_dst.exists():
@@ -160,12 +157,10 @@ def atomic_move_with_fallback(src_path: Path, dst_path: Path) -> bool:
160
157
  # Re-raise with better context
161
158
  if e.errno == 28: # No space left on device
162
159
  raise InsufficientStorageError(
163
- f"No space left on device during copy: {e}",
164
- required_space=src_path.stat().st_size,
165
- available_space=shutil.disk_usage(dst_path.parent).free
160
+ f"No space left on device during copy: {e}", required_space=src_path.stat().st_size, available_space=shutil.disk_usage(dst_path.parent).free
166
161
  )
167
162
  raise
168
-
163
+
169
164
  except Exception as e:
170
165
  logger.error(f"Failed to move {src_path} -> {dst_path}: {e}")
171
166
  raise
@@ -195,11 +190,11 @@ def _create_from_file(
195
190
  video_dir: Path = VIDEO_DIR,
196
191
  save: bool = True,
197
192
  delete_source: bool = False,
198
- **kwargs
193
+ **kwargs,
199
194
  ) -> "VideoFile":
200
195
  """
201
196
  Creates a VideoFile instance from a given video file path with improved error handling.
202
-
197
+
203
198
  Raises:
204
199
  InsufficientStorageError: When not enough disk space
205
200
  TranscodingError: When video transcoding fails
@@ -208,7 +203,7 @@ def _create_from_file(
208
203
  """
209
204
  from endoreg_db.models.administration.center.center import Center
210
205
  from endoreg_db.models.medical.hardware import EndoscopyProcessor
211
-
206
+
212
207
  original_file_name = file_path.name
213
208
  original_suffix = file_path.suffix
214
209
  final_storage_path = None
@@ -223,23 +218,20 @@ def _create_from_file(
223
218
  resolved_storage_root = _get_path(data_paths, "storage", storage_root_default)
224
219
  storage_root = Path(resolved_storage_root)
225
220
  storage_root.mkdir(parents=True, exist_ok=True)
226
-
221
+
227
222
  # Check storage capacity before starting any work
228
223
  check_storage_capacity(file_path, storage_root)
229
224
 
230
225
  # 1. Transcode if necessary
231
226
  logger.debug("Checking transcoding requirement for %s", file_path)
232
- temp_transcode_dir = TMP_VIDEO_DIR / 'transcoding'
227
+ temp_transcode_dir = TMP_VIDEO_DIR / "transcoding"
233
228
  temp_transcode_dir.mkdir(parents=True, exist_ok=True)
234
-
229
+
235
230
  # Use a unique name for the potential transcoded file
236
231
  temp_transcoded_output_path = temp_transcode_dir / f"{uuid.uuid4()}{original_suffix}"
237
232
 
238
233
  try:
239
- transcoded_file_path = transcode_videofile_if_required(
240
- input_path=file_path,
241
- output_path=temp_transcoded_output_path
242
- )
234
+ transcoded_file_path = transcode_videofile_if_required(input_path=file_path, output_path=temp_transcoded_output_path)
243
235
  if transcoded_file_path is None:
244
236
  raise TranscodingError(f"Transcoding check/process failed for {file_path}")
245
237
  except Exception as e:
@@ -257,7 +249,7 @@ def _create_from_file(
257
249
  if cls_model.check_hash_exists(video_hash=video_hash):
258
250
  existing_video = cls_model.objects.get(video_hash=video_hash)
259
251
  logger.warning("Video with hash %s already exists (UUID: %s)", video_hash, existing_video.uuid)
260
-
252
+
261
253
  # Check if the existing video has a valid file
262
254
  existing_raw_path = existing_video.get_raw_file_path()
263
255
  if existing_video.has_raw and existing_raw_path and existing_raw_path.exists():
@@ -355,4 +347,4 @@ def _create_from_file(
355
347
  if transcoded_file_path and transcoded_file_path != file_path and transcoded_file_path.exists():
356
348
  logger.warning("Cleaning up orphaned transcoded file: %s", transcoded_file_path)
357
349
  transcoded_file_path.unlink(missing_ok=True)
358
- raise RuntimeError(f"Video processing failed: {e}") from e
350
+ raise RuntimeError(f"Video processing failed: {e}") from e
@@ -1,16 +1,16 @@
1
- from itertools import filterfalse
2
1
  import logging
3
2
  from typing import TYPE_CHECKING
4
- from django.db import transaction
5
3
 
4
+ from django.db import transaction
6
5
 
7
6
  # Configure logging
8
- logger = logging.getLogger(__name__) # Changed from "video_file"
7
+ logger = logging.getLogger(__name__) # Changed from "video_file"
9
8
 
10
9
  if TYPE_CHECKING:
11
10
  from endoreg_db.models import VideoFile, VideoState
12
11
 
13
- def _pipe_2(video_file:"VideoFile") -> bool:
12
+
13
+ def _pipe_2(video_file: "VideoFile") -> bool:
14
14
  """
15
15
  Process the given video file through pipeline 2 operations which include frame extraction,
16
16
  anonymization of the video, and deletion of sensitive meta data.
@@ -70,11 +70,10 @@ def _pipe_2(video_file:"VideoFile") -> bool:
70
70
  logger.info("Pipe 2: Anonymization complete.")
71
71
  else:
72
72
  logger.info("Pipe 2: Video already anonymized.")
73
-
74
73
 
75
74
  # --- Part 3: Final DB operations (now in its own atomic transaction) ---
76
75
  with transaction.atomic():
77
- video_file.refresh_from_db() # Ensure we have the latest video_file state for these ops
76
+ video_file.refresh_from_db() # Ensure we have the latest video_file state for these ops
78
77
 
79
78
  # Set sensitive_meta_processed True atomically
80
79
  state: "VideoState" = video_file.get_or_create_state()
@@ -86,8 +85,8 @@ def _pipe_2(video_file:"VideoFile") -> bool:
86
85
  try:
87
86
  sm_pk = video_file.sensitive_meta.pk
88
87
  video_file.sensitive_meta.delete()
89
- video_file.sensitive_meta = None # Important after SET_NULL
90
- video_file.save(update_fields=['sensitive_meta']) # Persist the null relation
88
+ video_file.sensitive_meta = None # Important after SET_NULL
89
+ video_file.save(update_fields=["sensitive_meta"]) # Persist the null relation
91
90
  logger.info("Pipe 2: Deleted sensitive meta object (PK: %s).", sm_pk)
92
91
  except Exception as e:
93
92
  logger.error("Pipe 2: Failed to delete sensitive meta object: %s", e, exc_info=True)
@@ -102,4 +101,4 @@ def _pipe_2(video_file:"VideoFile") -> bool:
102
101
  # This will catch exceptions from I/O operations if they raise,
103
102
  # or from the final transaction block, or any other unhandled error.
104
103
  logger.error(f"Pipe 2 failed for video {video_file.uuid} with unhandled exception: {e}", exc_info=True)
105
- return False
104
+ return False