endoreg-db 0.8.6.1__py3-none-any.whl → 0.8.8.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of endoreg-db might be problematic. Click here for more details.

Files changed (503) hide show
  1. endoreg_db/authz/auth.py +74 -0
  2. endoreg_db/authz/backends.py +168 -0
  3. endoreg_db/authz/management/commands/list_routes.py +18 -0
  4. endoreg_db/authz/middleware.py +83 -0
  5. endoreg_db/authz/permissions.py +127 -0
  6. endoreg_db/authz/policy.py +218 -0
  7. endoreg_db/authz/views_auth.py +66 -0
  8. endoreg_db/config/env.py +13 -8
  9. endoreg_db/data/__init__.py +2 -11
  10. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
  11. endoreg_db/data/event_classification/data.yaml +4 -0
  12. endoreg_db/data/event_classification_choice/data.yaml +9 -0
  13. endoreg_db/data/examination/examinations/data.yaml +114 -14
  14. endoreg_db/data/examination/time-type/data.yaml +0 -3
  15. endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
  16. endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
  17. endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
  18. endoreg_db/data/finding/00_generic.yaml +35 -0
  19. endoreg_db/data/finding/00_generic_complication.yaml +9 -0
  20. endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
  21. endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
  22. endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
  23. endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
  24. endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
  25. endoreg_db/data/finding_classification/00_generic.yaml +44 -0
  26. endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
  27. endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
  28. endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
  29. endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
  30. endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
  31. endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
  32. endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
  33. endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
  34. endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
  35. endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
  36. endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
  37. endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
  38. endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
  39. endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
  40. endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
  41. endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
  42. endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
  43. endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
  44. endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
  45. endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
  46. endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
  47. endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
  48. endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
  49. endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
  50. endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
  51. endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
  52. endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
  53. endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
  54. endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
  55. endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
  56. endoreg_db/data/finding_type/data.yaml +8 -12
  57. endoreg_db/data/requirement/01_patient_data.yaml +93 -0
  58. endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
  59. endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
  60. endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
  61. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
  62. endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
  63. endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
  64. endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
  65. endoreg_db/data/requirement_set/_old_ +109 -0
  66. endoreg_db/data/requirement_set_type/data.yaml +21 -0
  67. endoreg_db/data/setup_config.yaml +4 -4
  68. endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
  69. endoreg_db/exceptions.py +4 -2
  70. endoreg_db/forms/examination_form.py +1 -1
  71. endoreg_db/helpers/data_loader.py +125 -53
  72. endoreg_db/helpers/default_objects.py +116 -81
  73. endoreg_db/import_files/__init__.py +27 -0
  74. endoreg_db/import_files/context/__init__.py +7 -0
  75. endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
  76. endoreg_db/import_files/context/ensure_center.py +17 -0
  77. endoreg_db/import_files/context/file_lock.py +66 -0
  78. endoreg_db/import_files/context/import_context.py +43 -0
  79. endoreg_db/import_files/context/validate_directories.py +56 -0
  80. endoreg_db/import_files/file_storage/__init__.py +15 -0
  81. endoreg_db/import_files/file_storage/create_report_file.py +76 -0
  82. endoreg_db/import_files/file_storage/create_video_file.py +75 -0
  83. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
  84. endoreg_db/import_files/file_storage/state_management.py +400 -0
  85. endoreg_db/import_files/file_storage/storage.py +36 -0
  86. endoreg_db/import_files/import_service.md +26 -0
  87. endoreg_db/import_files/processing/__init__.py +11 -0
  88. endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
  89. endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
  90. endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
  91. endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
  92. endoreg_db/import_files/pseudonymization/fake.py +52 -0
  93. endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
  94. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
  95. endoreg_db/import_files/report_import_service.py +141 -0
  96. endoreg_db/import_files/video_import_service.py +150 -0
  97. endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
  98. endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
  99. endoreg_db/management/commands/import_report.py +130 -65
  100. endoreg_db/management/commands/import_video.py +9 -10
  101. endoreg_db/management/commands/import_video_with_classification.py +2 -2
  102. endoreg_db/management/commands/list_routes.py +18 -0
  103. endoreg_db/management/commands/load_ai_model_data.py +5 -5
  104. endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
  105. endoreg_db/management/commands/load_base_db_data.py +5 -134
  106. endoreg_db/management/commands/load_center_data.py +12 -12
  107. endoreg_db/management/commands/load_contraindication_data.py +14 -16
  108. endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
  109. endoreg_db/management/commands/load_disease_classification_data.py +15 -18
  110. endoreg_db/management/commands/load_disease_data.py +25 -28
  111. endoreg_db/management/commands/load_endoscope_data.py +20 -27
  112. endoreg_db/management/commands/load_event_data.py +14 -16
  113. endoreg_db/management/commands/load_examination_data.py +31 -44
  114. endoreg_db/management/commands/load_examination_indication_data.py +20 -21
  115. endoreg_db/management/commands/load_finding_data.py +52 -80
  116. endoreg_db/management/commands/load_information_source.py +21 -23
  117. endoreg_db/management/commands/load_lab_value_data.py +17 -26
  118. endoreg_db/management/commands/load_medication_data.py +13 -12
  119. endoreg_db/management/commands/load_organ_data.py +15 -19
  120. endoreg_db/management/commands/load_pdf_type_data.py +19 -18
  121. endoreg_db/management/commands/load_profession_data.py +14 -17
  122. endoreg_db/management/commands/load_qualification_data.py +20 -23
  123. endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
  124. endoreg_db/management/commands/load_requirement_data.py +62 -39
  125. endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
  126. endoreg_db/management/commands/load_risk_data.py +7 -6
  127. endoreg_db/management/commands/load_shift_data.py +20 -23
  128. endoreg_db/management/commands/load_tag_data.py +8 -11
  129. endoreg_db/management/commands/load_unit_data.py +17 -19
  130. endoreg_db/management/commands/setup_endoreg_db.py +3 -3
  131. endoreg_db/management/commands/start_filewatcher.py +46 -37
  132. endoreg_db/management/commands/storage_management.py +271 -203
  133. endoreg_db/management/commands/validate_video_files.py +1 -5
  134. endoreg_db/migrations/0001_initial.py +297 -250
  135. endoreg_db/models/__init__.py +78 -123
  136. endoreg_db/models/administration/__init__.py +21 -42
  137. endoreg_db/models/administration/ai/active_model.py +2 -2
  138. endoreg_db/models/administration/ai/ai_model.py +7 -6
  139. endoreg_db/models/administration/case/__init__.py +1 -15
  140. endoreg_db/models/administration/case/case.py +3 -3
  141. endoreg_db/models/administration/case/case_template/__init__.py +2 -14
  142. endoreg_db/models/administration/case/case_template/case_template.py +2 -124
  143. endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
  144. endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
  145. endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
  146. endoreg_db/models/administration/center/center.py +33 -19
  147. endoreg_db/models/administration/center/center_product.py +12 -9
  148. endoreg_db/models/administration/center/center_resource.py +25 -19
  149. endoreg_db/models/administration/center/center_shift.py +21 -17
  150. endoreg_db/models/administration/center/center_waste.py +16 -8
  151. endoreg_db/models/administration/person/__init__.py +2 -0
  152. endoreg_db/models/administration/person/employee/employee.py +10 -5
  153. endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
  154. endoreg_db/models/administration/person/employee/employee_type.py +12 -6
  155. endoreg_db/models/administration/person/examiner/examiner.py +13 -11
  156. endoreg_db/models/administration/person/patient/__init__.py +2 -0
  157. endoreg_db/models/administration/person/patient/patient.py +129 -100
  158. endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
  159. endoreg_db/models/administration/person/person.py +4 -0
  160. endoreg_db/models/administration/person/profession/__init__.py +8 -4
  161. endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
  162. endoreg_db/models/administration/product/product.py +20 -15
  163. endoreg_db/models/administration/product/product_material.py +17 -18
  164. endoreg_db/models/administration/product/product_weight.py +12 -8
  165. endoreg_db/models/administration/product/reference_product.py +23 -55
  166. endoreg_db/models/administration/qualification/qualification.py +7 -3
  167. endoreg_db/models/administration/qualification/qualification_type.py +7 -3
  168. endoreg_db/models/administration/shift/scheduled_days.py +8 -5
  169. endoreg_db/models/administration/shift/shift.py +16 -12
  170. endoreg_db/models/administration/shift/shift_type.py +23 -31
  171. endoreg_db/models/label/__init__.py +8 -9
  172. endoreg_db/models/label/annotation/image_classification.py +10 -9
  173. endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
  174. endoreg_db/models/label/label.py +15 -15
  175. endoreg_db/models/label/label_set.py +19 -6
  176. endoreg_db/models/label/label_type.py +1 -1
  177. endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
  178. endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
  179. endoreg_db/models/label/video_segmentation_label.py +4 -0
  180. endoreg_db/models/label/video_segmentation_labelset.py +4 -3
  181. endoreg_db/models/media/frame/frame.py +22 -22
  182. endoreg_db/models/media/pdf/raw_pdf.py +194 -194
  183. endoreg_db/models/media/pdf/report_file.py +25 -29
  184. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
  185. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
  186. endoreg_db/models/media/processing_history/__init__.py +5 -0
  187. endoreg_db/models/media/processing_history/processing_history.py +96 -0
  188. endoreg_db/models/media/video/__init__.py +1 -0
  189. endoreg_db/models/media/video/create_from_file.py +139 -77
  190. endoreg_db/models/media/video/pipe_2.py +8 -9
  191. endoreg_db/models/media/video/video_file.py +174 -112
  192. endoreg_db/models/media/video/video_file_ai.py +288 -74
  193. endoreg_db/models/media/video/video_file_anonymize.py +38 -38
  194. endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
  195. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
  196. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
  197. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
  198. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
  199. endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
  200. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
  201. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
  202. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
  203. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
  204. endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
  205. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
  206. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
  207. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
  208. endoreg_db/models/media/video/video_file_io.py +113 -61
  209. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
  210. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
  211. endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
  212. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
  213. endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
  214. endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
  215. endoreg_db/models/media/video/video_file_segments.py +24 -17
  216. endoreg_db/models/media/video/video_metadata.py +19 -35
  217. endoreg_db/models/media/video/video_processing.py +96 -95
  218. endoreg_db/models/medical/contraindication/README.md +1 -0
  219. endoreg_db/models/medical/contraindication/__init__.py +13 -3
  220. endoreg_db/models/medical/disease.py +22 -16
  221. endoreg_db/models/medical/event.py +31 -18
  222. endoreg_db/models/medical/examination/__init__.py +13 -6
  223. endoreg_db/models/medical/examination/examination.py +39 -20
  224. endoreg_db/models/medical/examination/examination_indication.py +30 -95
  225. endoreg_db/models/medical/examination/examination_time.py +23 -8
  226. endoreg_db/models/medical/examination/examination_time_type.py +9 -6
  227. endoreg_db/models/medical/examination/examination_type.py +3 -4
  228. endoreg_db/models/medical/finding/finding.py +32 -40
  229. endoreg_db/models/medical/finding/finding_classification.py +42 -72
  230. endoreg_db/models/medical/finding/finding_intervention.py +25 -22
  231. endoreg_db/models/medical/finding/finding_type.py +13 -12
  232. endoreg_db/models/medical/hardware/endoscope.py +26 -26
  233. endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
  234. endoreg_db/models/medical/laboratory/lab_value.py +62 -91
  235. endoreg_db/models/medical/medication/medication.py +22 -10
  236. endoreg_db/models/medical/medication/medication_indication.py +29 -3
  237. endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
  238. endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
  239. endoreg_db/models/medical/medication/medication_schedule.py +27 -16
  240. endoreg_db/models/medical/organ/__init__.py +15 -12
  241. endoreg_db/models/medical/patient/medication_examples.py +6 -6
  242. endoreg_db/models/medical/patient/patient_disease.py +20 -23
  243. endoreg_db/models/medical/patient/patient_event.py +19 -22
  244. endoreg_db/models/medical/patient/patient_examination.py +48 -54
  245. endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
  246. endoreg_db/models/medical/patient/patient_finding.py +122 -139
  247. endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
  248. endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
  249. endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
  250. endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
  251. endoreg_db/models/medical/patient/patient_medication.py +27 -38
  252. endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
  253. endoreg_db/models/medical/risk/risk.py +7 -6
  254. endoreg_db/models/medical/risk/risk_type.py +8 -5
  255. endoreg_db/models/metadata/model_meta.py +60 -29
  256. endoreg_db/models/metadata/model_meta_logic.py +125 -18
  257. endoreg_db/models/metadata/pdf_meta.py +31 -24
  258. endoreg_db/models/metadata/sensitive_meta.py +105 -85
  259. endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
  260. endoreg_db/models/metadata/video_meta.py +51 -31
  261. endoreg_db/models/metadata/video_prediction_logic.py +16 -23
  262. endoreg_db/models/metadata/video_prediction_meta.py +29 -33
  263. endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
  264. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
  265. endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
  266. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
  267. endoreg_db/models/other/emission/emission_factor.py +18 -8
  268. endoreg_db/models/other/gender.py +10 -5
  269. endoreg_db/models/other/information_source.py +50 -29
  270. endoreg_db/models/other/material.py +9 -5
  271. endoreg_db/models/other/resource.py +6 -4
  272. endoreg_db/models/other/tag.py +10 -5
  273. endoreg_db/models/other/transport_route.py +13 -8
  274. endoreg_db/models/other/unit.py +10 -6
  275. endoreg_db/models/other/waste.py +6 -5
  276. endoreg_db/models/report/report.py +6 -0
  277. endoreg_db/models/requirement/requirement.py +329 -361
  278. endoreg_db/models/requirement/requirement_error.py +85 -0
  279. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
  280. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
  281. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
  282. endoreg_db/models/requirement/requirement_operator.py +103 -112
  283. endoreg_db/models/requirement/requirement_set.py +74 -57
  284. endoreg_db/models/state/__init__.py +4 -4
  285. endoreg_db/models/state/abstract.py +2 -2
  286. endoreg_db/models/state/anonymization.py +12 -0
  287. endoreg_db/models/state/audit_ledger.py +49 -51
  288. endoreg_db/models/state/label_video_segment.py +9 -0
  289. endoreg_db/models/state/raw_pdf.py +101 -68
  290. endoreg_db/models/state/sensitive_meta.py +6 -2
  291. endoreg_db/models/state/video.py +110 -90
  292. endoreg_db/models/upload_job.py +35 -34
  293. endoreg_db/models/utils.py +28 -25
  294. endoreg_db/queries/__init__.py +3 -1
  295. endoreg_db/root_urls.py +21 -2
  296. endoreg_db/schemas/examination_evaluation.py +1 -1
  297. endoreg_db/serializers/__init__.py +2 -10
  298. endoreg_db/serializers/anonymization.py +18 -10
  299. endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
  300. endoreg_db/serializers/meta/__init__.py +1 -6
  301. endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
  302. endoreg_db/serializers/misc/file_overview.py +11 -99
  303. endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
  304. endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
  305. endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
  306. endoreg_db/serializers/requirements/requirement_sets.py +92 -22
  307. endoreg_db/serializers/video/segmentation.py +2 -1
  308. endoreg_db/serializers/video/video_file_list.py +65 -34
  309. endoreg_db/serializers/video/video_processing_history.py +20 -5
  310. endoreg_db/services/__old/pdf_import.py +1487 -0
  311. endoreg_db/services/__old/video_import.py +1306 -0
  312. endoreg_db/services/anonymization.py +128 -89
  313. endoreg_db/services/lookup_service.py +65 -52
  314. endoreg_db/services/lookup_store.py +2 -2
  315. endoreg_db/services/pdf_import.py +0 -1382
  316. endoreg_db/services/report_import.py +10 -0
  317. endoreg_db/services/video_import.py +6 -1255
  318. endoreg_db/tasks/upload_tasks.py +79 -70
  319. endoreg_db/tasks/video_ingest.py +8 -4
  320. endoreg_db/urls/__init__.py +5 -32
  321. endoreg_db/urls/ai.py +32 -0
  322. endoreg_db/urls/media.py +121 -83
  323. endoreg_db/urls/root_urls.py +29 -0
  324. endoreg_db/utils/__init__.py +15 -5
  325. endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
  326. endoreg_db/utils/case_generator/__init__.py +3 -0
  327. endoreg_db/utils/dataloader.py +142 -40
  328. endoreg_db/utils/defaults/set_default_center.py +32 -0
  329. endoreg_db/utils/names.py +22 -16
  330. endoreg_db/utils/paths.py +110 -46
  331. endoreg_db/utils/permissions.py +2 -1
  332. endoreg_db/utils/pipelines/Readme.md +1 -1
  333. endoreg_db/utils/pipelines/process_video_dir.py +1 -1
  334. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
  335. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
  336. endoreg_db/utils/setup_config.py +8 -5
  337. endoreg_db/utils/storage.py +115 -0
  338. endoreg_db/utils/validate_endo_roi.py +8 -2
  339. endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
  340. endoreg_db/views/__init__.py +85 -183
  341. endoreg_db/views/ai/__init__.py +8 -0
  342. endoreg_db/views/ai/label.py +155 -0
  343. endoreg_db/views/anonymization/media_management.py +202 -166
  344. endoreg_db/views/anonymization/overview.py +99 -67
  345. endoreg_db/views/anonymization/validate.py +182 -44
  346. endoreg_db/views/media/__init__.py +7 -20
  347. endoreg_db/views/media/pdf_media.py +197 -174
  348. endoreg_db/views/media/sensitive_metadata.py +193 -138
  349. endoreg_db/views/media/video_media.py +89 -82
  350. endoreg_db/views/meta/__init__.py +0 -8
  351. endoreg_db/views/misc/__init__.py +1 -7
  352. endoreg_db/views/misc/upload_views.py +94 -93
  353. endoreg_db/views/patient/patient.py +5 -4
  354. endoreg_db/views/report/__init__.py +5 -7
  355. endoreg_db/views/{pdf → report}/reimport.py +22 -22
  356. endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
  357. endoreg_db/views/requirement/evaluate.py +188 -187
  358. endoreg_db/views/requirement/lookup.py +17 -3
  359. endoreg_db/views/requirement/lookup_store.py +22 -90
  360. endoreg_db/views/requirement/requirement_utils.py +89 -0
  361. endoreg_db/views/video/__init__.py +23 -24
  362. endoreg_db/views/video/correction.py +201 -172
  363. endoreg_db/views/video/reimport.py +1 -1
  364. endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
  365. endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
  366. endoreg_db/views/video/video_stream.py +7 -8
  367. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
  368. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
  369. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
  370. endoreg_db/data/finding/anatomy_colon.yaml +0 -128
  371. endoreg_db/data/finding/colonoscopy.yaml +0 -40
  372. endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
  373. endoreg_db/data/finding/complication.yaml +0 -16
  374. endoreg_db/data/finding/data.yaml +0 -105
  375. endoreg_db/data/finding/examination_setting.yaml +0 -16
  376. endoreg_db/data/finding/medication_related.yaml +0 -18
  377. endoreg_db/data/finding/outcome.yaml +0 -12
  378. endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
  379. endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
  380. endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
  381. endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  382. endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  383. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
  384. endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  385. endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
  386. endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
  387. endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
  388. endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
  389. endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
  390. endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
  391. endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
  392. endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
  393. endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
  394. endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
  395. endoreg_db/data/finding_classification/medication_related.yaml +0 -23
  396. endoreg_db/data/finding_classification/visualized.yaml +0 -33
  397. endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  398. endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  399. endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  400. endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  401. endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  402. endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  403. endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  404. endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  405. endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
  406. endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  407. endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
  408. endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
  409. endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  410. endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
  411. endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
  412. endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  413. endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  414. endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
  415. endoreg_db/data/requirement/age.yaml +0 -26
  416. endoreg_db/data/requirement/gender.yaml +0 -25
  417. endoreg_db/management/commands/init_default_ai_model.py +0 -112
  418. endoreg_db/management/commands/reset_celery_schedule.py +0 -9
  419. endoreg_db/management/commands/validate_video.py +0 -204
  420. endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
  421. endoreg_db/migrations/0003_add_center_display_name.py +0 -30
  422. endoreg_db/models/administration/permissions/__init__.py +0 -44
  423. endoreg_db/models/rule/__init__.py +0 -13
  424. endoreg_db/models/rule/rule.py +0 -27
  425. endoreg_db/models/rule/rule_applicator.py +0 -224
  426. endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
  427. endoreg_db/models/rule/rule_type.py +0 -20
  428. endoreg_db/models/rule/ruleset.py +0 -17
  429. endoreg_db/renames.yml +0 -8
  430. endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
  431. endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
  432. endoreg_db/serializers/_old/video.py +0 -71
  433. endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
  434. endoreg_db/serializers/meta/report_meta.py +0 -53
  435. endoreg_db/serializers/report/__init__.py +0 -9
  436. endoreg_db/serializers/report/mixins.py +0 -45
  437. endoreg_db/serializers/report/report.py +0 -105
  438. endoreg_db/serializers/report/report_list.py +0 -22
  439. endoreg_db/serializers/report/secure_file_url.py +0 -26
  440. endoreg_db/serializers/video/video_metadata.py +0 -105
  441. endoreg_db/services/requirements_object.py +0 -147
  442. endoreg_db/services/storage_aware_video_processor.py +0 -344
  443. endoreg_db/urls/files.py +0 -6
  444. endoreg_db/urls/label_video_segment_validate.py +0 -33
  445. endoreg_db/urls/label_video_segments.py +0 -46
  446. endoreg_db/urls/report.py +0 -48
  447. endoreg_db/urls/video.py +0 -61
  448. endoreg_db/utils/case_generator/case_generator.py +0 -159
  449. endoreg_db/utils/case_generator/utils.py +0 -30
  450. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
  451. endoreg_db/views/label/__init__.py +0 -5
  452. endoreg_db/views/label/label.py +0 -15
  453. endoreg_db/views/label_video_segment/__init__.py +0 -16
  454. endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
  455. endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
  456. endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
  457. endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
  458. endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
  459. endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
  460. endoreg_db/views/label_video_segment/validate.py +0 -226
  461. endoreg_db/views/media/segments.py +0 -71
  462. endoreg_db/views/meta/available_files_list.py +0 -146
  463. endoreg_db/views/meta/report_meta.py +0 -53
  464. endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
  465. endoreg_db/views/misc/secure_file_serving_view.py +0 -80
  466. endoreg_db/views/misc/secure_file_url_view.py +0 -84
  467. endoreg_db/views/misc/secure_url_validate.py +0 -79
  468. endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
  469. endoreg_db/views/patient_finding_location/__init__.py +0 -5
  470. endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
  471. endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
  472. endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
  473. endoreg_db/views/pdf/__init__.py +0 -8
  474. endoreg_db/views/report/report_list.py +0 -112
  475. endoreg_db/views/report/report_with_secure_url.py +0 -28
  476. endoreg_db/views/report/start_examination.py +0 -7
  477. endoreg_db/views/video/segmentation.py +0 -274
  478. endoreg_db/views/video/task_status.py +0 -49
  479. endoreg_db/views/video/timeline.py +0 -46
  480. endoreg_db/views/video/video_analyze.py +0 -52
  481. endoreg_db/views.py +0 -0
  482. /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
  483. /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
  484. /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
  485. /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
  486. /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
  487. /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
  488. /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
  489. /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
  490. /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
  491. /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
  492. /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
  493. /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
  494. /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
  495. /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
  496. /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
  497. /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
  498. /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
  499. /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
  500. /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
  501. /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
  502. /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
  503. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/licenses/LICENSE +0 -0
@@ -1,70 +1,73 @@
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
+ from endoreg_db.utils.paths import IMPORT_VIDEO_DIR, SENSITIVE_VIDEO_DIR, TRANSCODING_DIR
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from endoreg_db.models import VideoFile
14
14
 
15
- from ....utils.video.ffmpeg_wrapper import transcode_videofile_if_required
16
- from ....utils.hashs import get_video_hash
15
+ import endoreg_db.utils.paths as path_utils
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
 
21
22
 
22
- def check_storage_capacity(src_path: Path, dst_root: Path, safety_margin: float = 1.2) -> None:
23
+ def check_storage_capacity(
24
+ src_path: Path, dst_root: Path, safety_margin: float = 1.2
25
+ ) -> None:
23
26
  """
24
27
  Check if there's enough storage space before starting operations.
25
-
28
+
26
29
  Args:
27
30
  src_path: Source file path
28
31
  dst_root: Destination root directory
29
32
  safety_margin: Safety factor (1.2 = 20% extra space required)
30
-
33
+
31
34
  Raises:
32
35
  InsufficientStorageError: If insufficient storage space
33
36
  """
34
37
  try:
35
38
  src_size = src_path.stat().st_size
36
39
  required_space = int(src_size * safety_margin)
37
-
40
+
38
41
  # Check free space on destination
39
42
  free_space = shutil.disk_usage(dst_root).free
40
-
43
+
41
44
  if free_space < required_space:
42
45
  raise InsufficientStorageError(
43
- f"Insufficient storage space. Required: {required_space/1e9:.1f} GB, "
44
- f"Available: {free_space/1e9:.1f} GB on {dst_root}",
46
+ f"Insufficient storage space. Required: {required_space / 1e9:.1f} GB, Available: {free_space / 1e9:.1f} GB on {dst_root}",
45
47
  required_space=required_space,
46
- available_space=free_space
48
+ available_space=free_space,
47
49
  )
48
-
49
- logger.info(f"Storage check passed: {free_space/1e9:.1f} GB available, "
50
- f"{required_space/1e9:.1f} GB required")
51
-
50
+
51
+ logger.info(
52
+ f"Storage check passed: {free_space / 1e9:.1f} GB available, {required_space / 1e9:.1f} GB required"
53
+ )
54
+
52
55
  except OSError as e:
53
56
  logger.warning(f"Could not check storage capacity: {e}")
54
57
  # Don't fail the operation, just log the warning
55
58
 
56
59
 
57
- def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
60
+ def atomic_copy_with_fallback(src_path: Path = IMPORT_VIDEO_DIR, dst_path: Path = SENSITIVE_VIDEO_DIR) -> bool:
58
61
  """
59
62
  Atomically copy file from src to dst, preserving the source file.
60
-
63
+
61
64
  Args:
62
65
  src_path: Source file path
63
66
  dst_path: Destination file path
64
-
67
+
65
68
  Returns:
66
69
  True if successful
67
-
70
+
68
71
  Raises:
69
72
  InsufficientStorageError: If not enough space for the operation
70
73
  OSError: For other file system errors
@@ -73,18 +76,17 @@ def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
73
76
  # Check space before copy
74
77
  src_size = src_path.stat().st_size
75
78
  free_space = shutil.disk_usage(dst_path.parent).free
76
-
79
+
77
80
  if free_space < src_size * 1.1: # 10% safety margin
78
81
  raise InsufficientStorageError(
79
- f"Insufficient space for copy operation. Required: {src_size/1e9:.1f} GB, "
80
- f"Available: {free_space/1e9:.1f} GB",
82
+ f"Insufficient space for copy operation. Required: {src_size / 1e9:.1f} GB, Available: {free_space / 1e9:.1f} GB",
81
83
  required_space=src_size,
82
- available_space=free_space
84
+ available_space=free_space,
83
85
  )
84
-
86
+
85
87
  # Use a temporary name during copy for atomicity
86
- temp_dst = dst_path.with_suffix(dst_path.suffix + '.tmp')
87
-
88
+ temp_dst = dst_path.with_suffix(dst_path.suffix + ".tmp")
89
+
88
90
  try:
89
91
  shutil.copy2(str(src_path), str(temp_dst))
90
92
  temp_dst.rename(dst_path)
@@ -95,7 +97,7 @@ def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
95
97
  if temp_dst.exists():
96
98
  temp_dst.unlink(missing_ok=True)
97
99
  raise
98
-
100
+
99
101
  except Exception as e:
100
102
  logger.error(f"Copy operation failed: {src_path} -> {dst_path}: {e}")
101
103
  raise
@@ -104,14 +106,14 @@ def atomic_copy_with_fallback(src_path: Path, dst_path: Path) -> bool:
104
106
  def atomic_move_with_fallback(src_path: Path, dst_path: Path) -> bool:
105
107
  """
106
108
  Atomically move file from src to dst, with fallback to copy+remove.
107
-
109
+
108
110
  Args:
109
111
  src_path: Source file path
110
112
  dst_path: Destination file path
111
-
113
+
112
114
  Returns:
113
115
  True if successful
114
-
116
+
115
117
  Raises:
116
118
  InsufficientStorageError: If not enough space for the operation
117
119
  OSError: For other file system errors
@@ -127,32 +129,31 @@ def atomic_move_with_fallback(src_path: Path, dst_path: Path) -> bool:
127
129
  logger.debug("Cross-device move detected, falling back to copy+remove")
128
130
  else:
129
131
  raise
130
-
132
+
131
133
  # Check space before cross-filesystem copy
132
134
  src_size = src_path.stat().st_size
133
135
  free_space = shutil.disk_usage(dst_path.parent).free
134
-
136
+
135
137
  if free_space < src_size * 1.1: # 10% safety margin
136
138
  raise InsufficientStorageError(
137
- f"Insufficient space for copy operation. Required: {src_size/1e9:.1f} GB, "
138
- f"Available: {free_space/1e9:.1f} GB",
139
+ f"Insufficient space for copy operation. Required: {src_size / 1e9:.1f} GB, Available: {free_space / 1e9:.1f} GB",
139
140
  required_space=src_size,
140
- available_space=free_space
141
+ available_space=free_space,
141
142
  )
142
-
143
+
143
144
  # Fallback to copy+remove for cross-filesystem moves
144
145
  logger.info(f"Copying file (cross-filesystem): {src_path} -> {dst_path}")
145
-
146
+
146
147
  # Use a temporary name during copy for atomicity
147
- temp_dst = dst_path.with_suffix(dst_path.suffix + '.tmp')
148
-
148
+ temp_dst = dst_path.with_suffix(dst_path.suffix + ".tmp")
149
+
149
150
  try:
150
151
  shutil.copy2(str(src_path), str(temp_dst))
151
152
  temp_dst.rename(dst_path)
152
153
  src_path.unlink() # Remove source only after successful copy
153
154
  logger.debug(f"Copy+remove successful: {src_path} -> {dst_path}")
154
155
  return True
155
-
156
+
156
157
  except OSError as e:
157
158
  # Clean up temp file on failure
158
159
  if temp_dst.exists():
@@ -162,10 +163,10 @@ def atomic_move_with_fallback(src_path: Path, dst_path: Path) -> bool:
162
163
  raise InsufficientStorageError(
163
164
  f"No space left on device during copy: {e}",
164
165
  required_space=src_path.stat().st_size,
165
- available_space=shutil.disk_usage(dst_path.parent).free
166
+ available_space=shutil.disk_usage(dst_path.parent).free,
166
167
  )
167
168
  raise
168
-
169
+
169
170
  except Exception as e:
170
171
  logger.error(f"Failed to move {src_path} -> {dst_path}: {e}")
171
172
  raise
@@ -192,14 +193,14 @@ def _create_from_file(
192
193
  file_path: Path,
193
194
  center_name: str,
194
195
  processor_name: Optional[str] = None,
195
- video_dir: Path = VIDEO_DIR,
196
+ video_dir: Path = IMPORT_VIDEO_DIR,
196
197
  save: bool = True,
197
198
  delete_source: bool = False,
198
- **kwargs
199
+ **kwargs,
199
200
  ) -> "VideoFile":
200
201
  """
201
202
  Creates a VideoFile instance from a given video file path with improved error handling.
202
-
203
+
203
204
  Raises:
204
205
  InsufficientStorageError: When not enough disk space
205
206
  TranscodingError: When video transcoding fails
@@ -208,7 +209,7 @@ def _create_from_file(
208
209
  """
209
210
  from endoreg_db.models.administration.center.center import Center
210
211
  from endoreg_db.models.medical.hardware import EndoscopyProcessor
211
-
212
+
212
213
  original_file_name = file_path.name
213
214
  original_suffix = file_path.suffix
214
215
  final_storage_path = None
@@ -223,25 +224,28 @@ def _create_from_file(
223
224
  resolved_storage_root = _get_path(data_paths, "storage", storage_root_default)
224
225
  storage_root = Path(resolved_storage_root)
225
226
  storage_root.mkdir(parents=True, exist_ok=True)
226
-
227
+
227
228
  # Check storage capacity before starting any work
228
229
  check_storage_capacity(file_path, storage_root)
229
230
 
230
231
  # 1. Transcode if necessary
231
232
  logger.debug("Checking transcoding requirement for %s", file_path)
232
- temp_transcode_dir = TMP_VIDEO_DIR / 'transcoding'
233
+ temp_transcode_dir = TRANSCODING_DIR
233
234
  temp_transcode_dir.mkdir(parents=True, exist_ok=True)
234
-
235
+
235
236
  # Use a unique name for the potential transcoded file
236
- temp_transcoded_output_path = temp_transcode_dir / f"{uuid.uuid4()}{original_suffix}"
237
+ temp_transcoded_output_path = (
238
+ temp_transcode_dir / f"{uuid.uuid4()}{original_suffix}"
239
+ )
237
240
 
238
241
  try:
239
242
  transcoded_file_path = transcode_videofile_if_required(
240
- input_path=file_path,
241
- output_path=temp_transcoded_output_path
243
+ input_path=file_path, output_path=temp_transcoded_output_path
242
244
  )
243
245
  if transcoded_file_path is None:
244
- raise TranscodingError(f"Transcoding check/process failed for {file_path}")
246
+ raise TranscodingError(
247
+ f"Transcoding check/process failed for {file_path}"
248
+ )
245
249
  except Exception as e:
246
250
  raise TranscodingError(f"Video transcoding failed: {e}") from e
247
251
 
@@ -250,24 +254,42 @@ def _create_from_file(
250
254
  # 2. Calculate hash (this will be the raw_video_hash)
251
255
  video_hash = get_video_hash(transcoded_file_path)
252
256
  if not video_hash:
253
- raise ValueError(f"Could not calculate video hash for {transcoded_file_path}")
254
- logger.info("Calculated raw video hash: %s for %s", video_hash, original_file_name)
257
+ raise ValueError(
258
+ f"Could not calculate video hash for {transcoded_file_path}"
259
+ )
260
+ logger.info(
261
+ "Calculated raw video hash: %s for %s", video_hash, original_file_name
262
+ )
255
263
 
256
264
  # 3. Check if hash already exists
257
265
  if cls_model.check_hash_exists(video_hash=video_hash):
258
266
  existing_video = cls_model.objects.get(video_hash=video_hash)
259
- logger.warning("Video with hash %s already exists (UUID: %s)", video_hash, existing_video.uuid)
260
-
267
+ logger.warning(
268
+ "Video with hash %s already exists (UUID: %s)",
269
+ video_hash,
270
+ existing_video.uuid,
271
+ )
272
+
261
273
  # Check if the existing video has a valid file
262
274
  existing_raw_path = existing_video.get_raw_file_path()
263
- if existing_video.has_raw and existing_raw_path and existing_raw_path.exists():
264
- logger.warning("Video with hash %s already exists and file is present. Returning existing instance.", video_hash)
275
+ if (
276
+ existing_video.has_raw
277
+ and existing_raw_path
278
+ and existing_raw_path.exists()
279
+ ):
280
+ logger.warning(
281
+ "Video with hash %s already exists and file is present. Returning existing instance.",
282
+ video_hash,
283
+ )
265
284
  # Clean up transcoded file if it was created temporarily
266
285
  if transcoded_file_path != file_path and transcoded_file_path.exists():
267
286
  transcoded_file_path.unlink(missing_ok=True)
268
287
  return existing_video
269
288
 
270
- logger.warning("Video with hash %s exists but file is missing. Deleting orphaned record.", video_hash)
289
+ logger.warning(
290
+ "Video with hash %s exists but file is missing. Deleting orphaned record.",
291
+ video_hash,
292
+ )
271
293
  existing_video.delete()
272
294
 
273
295
  # 4. Generate UUID and final storage path
@@ -278,16 +300,26 @@ def _create_from_file(
278
300
  # 5. Move or Copy the file to final storage using improved method
279
301
  try:
280
302
  if delete_source and transcoded_file_path == file_path:
281
- logger.debug("Moving original file %s to %s", file_path, final_storage_path)
303
+ logger.debug(
304
+ "Moving original file %s to %s", file_path, final_storage_path
305
+ )
282
306
  atomic_move_with_fallback(file_path, final_storage_path)
283
307
  elif delete_source and transcoded_file_path != file_path:
284
- logger.debug("Moving transcoded file %s to %s", transcoded_file_path, final_storage_path)
308
+ logger.debug(
309
+ "Moving transcoded file %s to %s",
310
+ transcoded_file_path,
311
+ final_storage_path,
312
+ )
285
313
  atomic_move_with_fallback(transcoded_file_path, final_storage_path)
286
314
  else:
287
- logger.debug("Copying file %s to %s", transcoded_file_path, final_storage_path)
315
+ logger.debug(
316
+ "Copying file %s to %s", transcoded_file_path, final_storage_path
317
+ )
288
318
  atomic_copy_with_fallback(transcoded_file_path, final_storage_path)
289
319
  if transcoded_file_path != file_path and transcoded_file_path.exists():
290
- logger.debug("Cleaning up temporary transcoded file %s", transcoded_file_path)
320
+ logger.debug(
321
+ "Cleaning up temporary transcoded file %s", transcoded_file_path
322
+ )
291
323
  transcoded_file_path.unlink(missing_ok=True)
292
324
  except InsufficientStorageError:
293
325
  # Re-raise storage errors as-is
@@ -298,15 +330,29 @@ def _create_from_file(
298
330
  # 6. Verify hash after move/copy
299
331
  final_hash = get_video_hash(final_storage_path)
300
332
  if final_hash != video_hash:
301
- logger.error("Hash mismatch after file operation! Expected %s, got %s", video_hash, final_hash)
333
+ logger.error(
334
+ "Hash mismatch after file operation! Expected %s, got %s",
335
+ video_hash,
336
+ final_hash,
337
+ )
302
338
  final_storage_path.unlink(missing_ok=True)
303
- raise RuntimeError(f"Hash mismatch after file operation for {final_storage_path}")
339
+ raise RuntimeError(
340
+ f"Hash mismatch after file operation for {final_storage_path}"
341
+ )
304
342
 
305
343
  # 7. Get related objects
306
344
  try:
307
345
  center = Center.objects.get(name=center_name)
308
- processor = EndoscopyProcessor.objects.get(name=processor_name) if processor_name else None
309
- logger.debug("Found Center: %s, Processor: %s", center.name, processor.name if processor else "None")
346
+ processor = (
347
+ EndoscopyProcessor.objects.get(name=processor_name)
348
+ if processor_name
349
+ else None
350
+ )
351
+ logger.debug(
352
+ "Found Center: %s, Processor: %s",
353
+ center.name,
354
+ processor.name if processor else "None",
355
+ )
310
356
  except Center.DoesNotExist as e:
311
357
  logger.error("Center '%s' not found", center_name)
312
358
  if final_storage_path and final_storage_path.exists():
@@ -321,8 +367,10 @@ def _create_from_file(
321
367
  # 8. Create the VideoFile instance
322
368
  logger.info("Creating new VideoFile instance with UUID: %s", uuid_val)
323
369
  # Store FileField path relative to storage root including the videos prefix
324
- storage_base = Path(_get_path(data_paths, "storage", final_storage_path.parent))
325
- relative_name = (final_storage_path.relative_to(storage_base)).as_posix()
370
+ # TODO Review removal, since this is now newly handled by path_utils
371
+ #storage_base = Path(_get_path(data_paths, "storage", final_storage_path.parent))
372
+
373
+ relative_name = path_utils.to_storage_relative(final_storage_path)
326
374
  video = cls_model(
327
375
  uuid=uuid_val,
328
376
  raw_file=relative_name,
@@ -339,7 +387,9 @@ def _create_from_file(
339
387
  if save:
340
388
  logger.info("Saving new VideoFile instance (UUID: %s)", uuid_val)
341
389
  video.save()
342
- logger.info("Successfully created VideoFile PK %s (UUID: %s)", video.pk, video.uuid)
390
+ logger.info(
391
+ "Successfully created VideoFile PK %s (UUID: %s)", video.pk, video.uuid
392
+ )
343
393
 
344
394
  return video
345
395
 
@@ -347,12 +397,24 @@ def _create_from_file(
347
397
  # Re-raise these specific errors as-is
348
398
  raise
349
399
  except Exception as e:
350
- logger.error("Failed to create VideoFile from %s: (%s) %s", file_path, type(e).__name__, e, exc_info=True)
400
+ logger.error(
401
+ "Failed to create VideoFile from %s: (%s) %s",
402
+ file_path,
403
+ type(e).__name__,
404
+ e,
405
+ exc_info=True,
406
+ )
351
407
  # Clean up any created files
352
408
  if final_storage_path and final_storage_path.exists():
353
409
  logger.warning("Cleaning up orphaned file: %s", final_storage_path)
354
410
  final_storage_path.unlink(missing_ok=True)
355
- if transcoded_file_path and transcoded_file_path != file_path and transcoded_file_path.exists():
356
- logger.warning("Cleaning up orphaned transcoded file: %s", transcoded_file_path)
411
+ if (
412
+ transcoded_file_path
413
+ and transcoded_file_path != file_path
414
+ and transcoded_file_path.exists()
415
+ ):
416
+ logger.warning(
417
+ "Cleaning up orphaned transcoded file: %s", transcoded_file_path
418
+ )
357
419
  transcoded_file_path.unlink(missing_ok=True)
358
- raise RuntimeError(f"Video processing failed: {e}") from e
420
+ 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