endoreg-db 0.8.8.0__py3-none-any.whl → 0.8.9.2__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 (402) hide show
  1. endoreg_db/data/__init__.py +22 -8
  2. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +0 -1
  3. endoreg_db/data/examination/examinations/data.yaml +114 -14
  4. endoreg_db/data/examination/time-type/data.yaml +0 -3
  5. endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
  6. endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
  7. endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
  8. endoreg_db/data/finding/00_generic.yaml +35 -0
  9. endoreg_db/data/finding/00_generic_complication.yaml +9 -0
  10. endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
  11. endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
  12. endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
  13. endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
  14. endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
  15. endoreg_db/data/finding_classification/00_generic.yaml +44 -0
  16. endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
  17. endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
  18. endoreg_db/data/finding_classification/{colonoscopy_bowel_preparation.yaml → 02_colonoscopy_baseline.yaml} +35 -20
  19. endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
  20. endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
  21. endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
  22. endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
  23. endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
  24. endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
  25. endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
  26. endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
  27. endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
  28. endoreg_db/data/{_examples/finding_classification_choice/colonoscopy_not_complete_reason.yaml → finding_classification_choice/02_colonoscopy_generic.yaml} +1 -1
  29. endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
  30. endoreg_db/data/{_examples/finding_classification_choice/colonoscopy_location.yaml → finding_classification_choice/02_colonoscopy_location.yaml} +23 -4
  31. endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
  32. endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
  33. endoreg_db/data/{_examples/finding_classification_choice/colon_lesion_paris.yaml → finding_classification_choice/02_colonoscopy_polyp_morphology.yaml} +26 -8
  34. endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
  35. endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
  36. endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
  37. endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
  38. endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
  39. endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
  40. endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
  41. endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
  42. endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
  43. endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
  44. endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
  45. endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
  46. endoreg_db/data/finding_type/data.yaml +8 -12
  47. endoreg_db/data/requirement/01_patient_data.yaml +93 -0
  48. endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
  49. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +0 -2
  50. endoreg_db/data/requirement_set/90_coloreg.yaml +20 -8
  51. endoreg_db/exceptions.py +0 -1
  52. endoreg_db/forms/examination_form.py +1 -1
  53. endoreg_db/helpers/data_loader.py +124 -52
  54. endoreg_db/helpers/default_objects.py +116 -81
  55. endoreg_db/import_files/__init__.py +27 -0
  56. endoreg_db/import_files/context/__init__.py +7 -0
  57. endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
  58. endoreg_db/import_files/context/ensure_center.py +17 -0
  59. endoreg_db/import_files/context/file_lock.py +66 -0
  60. endoreg_db/import_files/context/import_context.py +43 -0
  61. endoreg_db/import_files/context/validate_directories.py +56 -0
  62. endoreg_db/import_files/file_storage/__init__.py +15 -0
  63. endoreg_db/import_files/file_storage/create_report_file.py +76 -0
  64. endoreg_db/import_files/file_storage/create_video_file.py +75 -0
  65. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
  66. endoreg_db/import_files/file_storage/state_management.py +496 -0
  67. endoreg_db/import_files/file_storage/storage.py +36 -0
  68. endoreg_db/import_files/import_service.md +26 -0
  69. endoreg_db/import_files/processing/__init__.py +11 -0
  70. endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
  71. endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
  72. endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
  73. endoreg_db/import_files/pseudonymization/fake.py +52 -0
  74. endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
  75. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
  76. endoreg_db/import_files/pseudonymization/pseudonymize.py +0 -0
  77. endoreg_db/import_files/report_import_service.py +141 -0
  78. endoreg_db/import_files/video_import_service.py +150 -0
  79. endoreg_db/management/commands/import_report.py +130 -65
  80. endoreg_db/management/commands/import_video_with_classification.py +1 -1
  81. endoreg_db/management/commands/load_ai_model_data.py +5 -5
  82. endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
  83. endoreg_db/management/commands/load_base_db_data.py +5 -134
  84. endoreg_db/management/commands/load_contraindication_data.py +14 -16
  85. endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
  86. endoreg_db/management/commands/load_disease_classification_data.py +15 -18
  87. endoreg_db/management/commands/load_disease_data.py +25 -28
  88. endoreg_db/management/commands/load_endoscope_data.py +20 -27
  89. endoreg_db/management/commands/load_event_data.py +14 -16
  90. endoreg_db/management/commands/load_examination_data.py +31 -44
  91. endoreg_db/management/commands/load_examination_indication_data.py +20 -21
  92. endoreg_db/management/commands/load_finding_data.py +52 -80
  93. endoreg_db/management/commands/load_information_source.py +21 -23
  94. endoreg_db/management/commands/load_lab_value_data.py +17 -26
  95. endoreg_db/management/commands/load_medication_data.py +13 -12
  96. endoreg_db/management/commands/load_organ_data.py +15 -19
  97. endoreg_db/management/commands/load_pdf_type_data.py +19 -18
  98. endoreg_db/management/commands/load_profession_data.py +14 -17
  99. endoreg_db/management/commands/load_qualification_data.py +20 -23
  100. endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
  101. endoreg_db/management/commands/load_requirement_data.py +14 -20
  102. endoreg_db/management/commands/load_risk_data.py +7 -6
  103. endoreg_db/management/commands/load_shift_data.py +20 -23
  104. endoreg_db/management/commands/load_tag_data.py +8 -11
  105. endoreg_db/management/commands/load_unit_data.py +17 -19
  106. endoreg_db/management/commands/start_filewatcher.py +46 -37
  107. endoreg_db/management/commands/validate_video_files.py +1 -5
  108. endoreg_db/migrations/0001_initial.py +1360 -1812
  109. endoreg_db/models/administration/person/patient/patient.py +72 -46
  110. endoreg_db/models/label/__init__.py +2 -2
  111. endoreg_db/models/label/annotation/video_segmentation_annotation.py +18 -26
  112. endoreg_db/models/label/label_video_segment/label_video_segment.py +23 -1
  113. endoreg_db/models/media/pdf/raw_pdf.py +136 -64
  114. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +34 -10
  115. endoreg_db/models/media/processing_history/__init__.py +5 -0
  116. endoreg_db/models/media/processing_history/processing_history.py +96 -0
  117. endoreg_db/models/media/video/create_from_file.py +101 -31
  118. endoreg_db/models/media/video/video_file.py +125 -105
  119. endoreg_db/models/media/video/video_file_io.py +31 -26
  120. endoreg_db/models/medical/contraindication/README.md +1 -0
  121. endoreg_db/models/medical/examination/examination.py +28 -8
  122. endoreg_db/models/medical/examination/examination_indication.py +13 -79
  123. endoreg_db/models/medical/examination/examination_time.py +8 -3
  124. endoreg_db/models/medical/finding/finding.py +5 -12
  125. endoreg_db/models/medical/finding/finding_classification.py +18 -37
  126. endoreg_db/models/medical/finding/finding_intervention.py +7 -9
  127. endoreg_db/models/medical/hardware/endoscope.py +6 -0
  128. endoreg_db/models/medical/patient/medication_examples.py +5 -1
  129. endoreg_db/models/medical/patient/patient_finding.py +1 -1
  130. endoreg_db/models/metadata/pdf_meta.py +22 -10
  131. endoreg_db/models/metadata/sensitive_meta.py +3 -0
  132. endoreg_db/models/metadata/sensitive_meta_logic.py +200 -124
  133. endoreg_db/models/other/information_source.py +27 -6
  134. endoreg_db/models/report/__init__.py +0 -0
  135. endoreg_db/models/report/images.py +0 -0
  136. endoreg_db/models/report/report.py +6 -0
  137. endoreg_db/models/requirement/requirement.py +59 -399
  138. endoreg_db/models/requirement/requirement_operator.py +86 -98
  139. endoreg_db/models/state/audit_ledger.py +4 -5
  140. endoreg_db/models/state/raw_pdf.py +69 -30
  141. endoreg_db/models/state/video.py +65 -49
  142. endoreg_db/models/upload_job.py +33 -9
  143. endoreg_db/models/utils.py +27 -23
  144. endoreg_db/queries/__init__.py +3 -1
  145. endoreg_db/schemas/examination_evaluation.py +1 -1
  146. endoreg_db/serializers/__init__.py +2 -8
  147. endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
  148. endoreg_db/serializers/meta/__init__.py +1 -6
  149. endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
  150. endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
  151. endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
  152. endoreg_db/serializers/video/video_file_list.py +65 -34
  153. endoreg_db/services/__old/pdf_import.py +1487 -0
  154. endoreg_db/services/__old/video_import.py +1306 -0
  155. endoreg_db/services/anonymization.py +63 -26
  156. endoreg_db/services/lookup_service.py +28 -28
  157. endoreg_db/services/lookup_store.py +2 -2
  158. endoreg_db/services/pdf_import.py +0 -1480
  159. endoreg_db/services/report_import.py +10 -0
  160. endoreg_db/services/video_import.py +6 -1165
  161. endoreg_db/tasks/upload_tasks.py +79 -70
  162. endoreg_db/tasks/video_ingest.py +8 -4
  163. endoreg_db/urls/__init__.py +0 -14
  164. endoreg_db/urls/ai.py +32 -0
  165. endoreg_db/urls/media.py +21 -24
  166. endoreg_db/utils/dataloader.py +87 -57
  167. endoreg_db/utils/paths.py +110 -46
  168. endoreg_db/utils/pipelines/Readme.md +1 -1
  169. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
  170. endoreg_db/utils/video/ffmpeg_wrapper.py +217 -52
  171. endoreg_db/views/__init__.py +85 -173
  172. endoreg_db/views/ai/__init__.py +8 -0
  173. endoreg_db/views/ai/label.py +155 -0
  174. endoreg_db/views/anonymization/media_management.py +8 -7
  175. endoreg_db/views/anonymization/overview.py +97 -68
  176. endoreg_db/views/anonymization/validate.py +25 -21
  177. endoreg_db/views/media/__init__.py +5 -20
  178. endoreg_db/views/media/pdf_media.py +109 -65
  179. endoreg_db/views/media/sensitive_metadata.py +163 -148
  180. endoreg_db/views/meta/__init__.py +0 -8
  181. endoreg_db/views/misc/__init__.py +1 -7
  182. endoreg_db/views/misc/upload_views.py +94 -93
  183. endoreg_db/views/report/__init__.py +7 -0
  184. endoreg_db/views/{pdf → report}/reimport.py +45 -24
  185. endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +40 -32
  186. endoreg_db/views/requirement/lookup_store.py +22 -90
  187. endoreg_db/views/video/__init__.py +23 -22
  188. endoreg_db/views/video/correction.py +201 -172
  189. endoreg_db/views/video/reimport.py +1 -1
  190. endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +75 -37
  191. endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
  192. endoreg_db/views/video/video_stream.py +7 -8
  193. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.9.2.dist-info}/METADATA +2 -2
  194. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.9.2.dist-info}/RECORD +217 -335
  195. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.9.2.dist-info}/WHEEL +1 -1
  196. endoreg_db/data/_examples/disease.yaml +0 -55
  197. endoreg_db/data/_examples/disease_classification.yaml +0 -13
  198. endoreg_db/data/_examples/disease_classification_choice.yaml +0 -62
  199. endoreg_db/data/_examples/event.yaml +0 -64
  200. endoreg_db/data/_examples/examination.yaml +0 -72
  201. endoreg_db/data/_examples/finding/anatomy_colon.yaml +0 -128
  202. endoreg_db/data/_examples/finding/colonoscopy.yaml +0 -40
  203. endoreg_db/data/_examples/finding/colonoscopy_bowel_prep.yaml +0 -56
  204. endoreg_db/data/_examples/finding/complication.yaml +0 -16
  205. endoreg_db/data/_examples/finding/data.yaml +0 -105
  206. endoreg_db/data/_examples/finding/examination_setting.yaml +0 -16
  207. endoreg_db/data/_examples/finding/medication_related.yaml +0 -18
  208. endoreg_db/data/_examples/finding/outcome.yaml +0 -12
  209. endoreg_db/data/_examples/finding_classification/colonoscopy_bowel_preparation.yaml +0 -68
  210. endoreg_db/data/_examples/finding_classification/colonoscopy_jnet.yaml +0 -22
  211. endoreg_db/data/_examples/finding_classification/colonoscopy_kudo.yaml +0 -25
  212. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  213. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  214. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_size.yaml +0 -68
  215. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  216. endoreg_db/data/_examples/finding_classification/colonoscopy_location.yaml +0 -80
  217. endoreg_db/data/_examples/finding_classification/colonoscopy_lst.yaml +0 -21
  218. endoreg_db/data/_examples/finding_classification/colonoscopy_nice.yaml +0 -20
  219. endoreg_db/data/_examples/finding_classification/colonoscopy_paris.yaml +0 -26
  220. endoreg_db/data/_examples/finding_classification/colonoscopy_sano.yaml +0 -22
  221. endoreg_db/data/_examples/finding_classification/colonoscopy_summary.yaml +0 -53
  222. endoreg_db/data/_examples/finding_classification/complication_generic.yaml +0 -25
  223. endoreg_db/data/_examples/finding_classification/examination_setting_generic.yaml +0 -40
  224. endoreg_db/data/_examples/finding_classification/histology_colo.yaml +0 -51
  225. endoreg_db/data/_examples/finding_classification/intervention_required.yaml +0 -26
  226. endoreg_db/data/_examples/finding_classification/medication_related.yaml +0 -23
  227. endoreg_db/data/_examples/finding_classification/visualized.yaml +0 -33
  228. endoreg_db/data/_examples/finding_classification_choice/bowel_preparation.yaml +0 -78
  229. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  230. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  231. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  232. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  233. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  234. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  235. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  236. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  237. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_size.yaml +0 -82
  238. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  239. endoreg_db/data/_examples/finding_classification_choice/complication_generic_types.yaml +0 -15
  240. endoreg_db/data/_examples/finding_classification_choice/examination_setting_generic_types.yaml +0 -15
  241. endoreg_db/data/_examples/finding_classification_choice/histology.yaml +0 -24
  242. endoreg_db/data/_examples/finding_classification_choice/histology_polyp.yaml +0 -20
  243. endoreg_db/data/_examples/finding_classification_choice/outcome.yaml +0 -19
  244. endoreg_db/data/_examples/finding_classification_choice/yes_no_na.yaml +0 -11
  245. endoreg_db/data/_examples/finding_classification_type/colonoscopy_basic.yaml +0 -48
  246. endoreg_db/data/_examples/finding_intervention/endoscopy.yaml +0 -43
  247. endoreg_db/data/_examples/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  248. endoreg_db/data/_examples/finding_intervention/endoscopy_egd.yaml +0 -128
  249. endoreg_db/data/_examples/finding_intervention/endoscopy_ercp.yaml +0 -32
  250. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  251. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  252. endoreg_db/data/_examples/finding_intervention_type/endoscopy.yaml +0 -15
  253. endoreg_db/data/_examples/finding_type/data.yaml +0 -43
  254. endoreg_db/data/_examples/requirement/age.yaml +0 -26
  255. endoreg_db/data/_examples/requirement/gender.yaml +0 -25
  256. endoreg_db/data/_examples/requirement_set/01_endoscopy_generic.yaml +0 -48
  257. endoreg_db/data/_examples/requirement_set/colonoscopy_austria_screening.yaml +0 -57
  258. endoreg_db/data/_examples/requirement_set/endoscopy_bleeding_risk.yaml +0 -52
  259. endoreg_db/data/_examples/yaml_examples.xlsx +0 -0
  260. endoreg_db/data/finding/anatomy_colon.yaml +0 -128
  261. endoreg_db/data/finding/colonoscopy.yaml +0 -40
  262. endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
  263. endoreg_db/data/finding/complication.yaml +0 -16
  264. endoreg_db/data/finding/data.yaml +0 -105
  265. endoreg_db/data/finding/examination_setting.yaml +0 -16
  266. endoreg_db/data/finding/medication_related.yaml +0 -18
  267. endoreg_db/data/finding/outcome.yaml +0 -12
  268. endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
  269. endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
  270. endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  271. endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  272. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -38
  273. endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  274. endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -49
  275. endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
  276. endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
  277. endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
  278. endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
  279. endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
  280. endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
  281. endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
  282. endoreg_db/data/finding_classification/histology_colo.yaml +0 -43
  283. endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
  284. endoreg_db/data/finding_classification/medication_related.yaml +0 -23
  285. endoreg_db/data/finding_classification/visualized.yaml +0 -33
  286. endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  287. endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  288. endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  289. endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  290. endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  291. endoreg_db/data/finding_classification_choice/colon_lesion_paris.yaml +0 -57
  292. endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  293. endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  294. endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  295. endoreg_db/data/finding_classification_choice/colonoscopy_location.yaml +0 -229
  296. endoreg_db/data/finding_classification_choice/colonoscopy_not_complete_reason.yaml +0 -19
  297. endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
  298. endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  299. endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
  300. endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
  301. endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  302. endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
  303. endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
  304. endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  305. endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  306. endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
  307. endoreg_db/data/requirement/age.yaml +0 -26
  308. endoreg_db/data/requirement/colonoscopy_baseline_austria.yaml +0 -45
  309. endoreg_db/data/requirement/disease_cardiovascular.yaml +0 -79
  310. endoreg_db/data/requirement/disease_classification_choice_cardiovascular.yaml +0 -41
  311. endoreg_db/data/requirement/disease_hepatology.yaml +0 -12
  312. endoreg_db/data/requirement/disease_misc.yaml +0 -12
  313. endoreg_db/data/requirement/disease_renal.yaml +0 -96
  314. endoreg_db/data/requirement/endoscopy_bleeding_risk.yaml +0 -59
  315. endoreg_db/data/requirement/event_cardiology.yaml +0 -251
  316. endoreg_db/data/requirement/event_requirements.yaml +0 -145
  317. endoreg_db/data/requirement/finding_colon_polyp.yaml +0 -50
  318. endoreg_db/data/requirement/gender.yaml +0 -25
  319. endoreg_db/data/requirement/lab_value.yaml +0 -441
  320. endoreg_db/data/requirement/medication.yaml +0 -93
  321. endoreg_db/data/requirement_operator/age.yaml +0 -13
  322. endoreg_db/data/requirement_operator/lab_operators.yaml +0 -129
  323. endoreg_db/data/requirement_operator/model_operators.yaml +0 -96
  324. endoreg_db/management/commands/init_default_ai_model.py +0 -112
  325. endoreg_db/management/commands/reset_celery_schedule.py +0 -9
  326. endoreg_db/management/commands/validate_video.py +0 -204
  327. endoreg_db/migrations/0002_requirementset_depends_on.py +0 -18
  328. endoreg_db/migrations/_old/0001_initial.py +0 -1857
  329. endoreg_db/migrations/_old/0002_add_video_correction_models.py +0 -52
  330. endoreg_db/migrations/_old/0003_add_center_display_name.py +0 -30
  331. endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +0 -68
  332. endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +0 -77
  333. endoreg_db/migrations/_old/0005_merge_20251111_1003.py +0 -14
  334. endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +0 -68
  335. endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +0 -89
  336. endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +0 -27
  337. endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +0 -21
  338. endoreg_db/renames.yml +0 -8
  339. endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
  340. endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
  341. endoreg_db/serializers/_old/video.py +0 -71
  342. endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
  343. endoreg_db/serializers/meta/report_meta.py +0 -53
  344. endoreg_db/serializers/report/__init__.py +0 -9
  345. endoreg_db/serializers/report/mixins.py +0 -45
  346. endoreg_db/serializers/report/report.py +0 -105
  347. endoreg_db/serializers/report/report_list.py +0 -22
  348. endoreg_db/serializers/report/secure_file_url.py +0 -26
  349. endoreg_db/services/requirements_object.py +0 -147
  350. endoreg_db/services/storage_aware_video_processor.py +0 -370
  351. endoreg_db/urls/files.py +0 -6
  352. endoreg_db/urls/label_video_segment_validate.py +0 -33
  353. endoreg_db/urls/label_video_segments.py +0 -46
  354. endoreg_db/views/label/__init__.py +0 -5
  355. endoreg_db/views/label/label.py +0 -15
  356. endoreg_db/views/label_video_segment/__init__.py +0 -16
  357. endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
  358. endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
  359. endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
  360. endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
  361. endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
  362. endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
  363. endoreg_db/views/label_video_segment/validate.py +0 -226
  364. endoreg_db/views/media/segments.py +0 -71
  365. endoreg_db/views/meta/available_files_list.py +0 -146
  366. endoreg_db/views/meta/report_meta.py +0 -53
  367. endoreg_db/views/meta/sensitive_meta_detail.py +0 -85
  368. endoreg_db/views/misc/secure_file_serving_view.py +0 -80
  369. endoreg_db/views/misc/secure_file_url_view.py +0 -84
  370. endoreg_db/views/misc/secure_url_validate.py +0 -79
  371. endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
  372. endoreg_db/views/patient_finding_location/__init__.py +0 -5
  373. endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
  374. endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
  375. endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
  376. endoreg_db/views/pdf/__init__.py +0 -8
  377. endoreg_db/views/video/segmentation.py +0 -274
  378. endoreg_db/views/video/task_status.py +0 -49
  379. endoreg_db/views/video/timeline.py +0 -46
  380. endoreg_db/views/video/video_analyze.py +0 -52
  381. /endoreg_db/data/requirement/{colon_polyp_intervention.yaml → old/colon_polyp_intervention.yaml} +0 -0
  382. /endoreg_db/data/{_examples/requirement → requirement/old}/colonoscopy_baseline_austria.yaml +0 -0
  383. /endoreg_db/data/requirement/{coloreg_colon_polyp.yaml → old/coloreg_colon_polyp.yaml} +0 -0
  384. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_cardiovascular.yaml +0 -0
  385. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_classification_choice_cardiovascular.yaml +0 -0
  386. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_hepatology.yaml +0 -0
  387. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_misc.yaml +0 -0
  388. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_renal.yaml +0 -0
  389. /endoreg_db/data/{_examples/requirement → requirement/old}/endoscopy_bleeding_risk.yaml +0 -0
  390. /endoreg_db/data/{_examples/requirement → requirement/old}/event_cardiology.yaml +0 -0
  391. /endoreg_db/data/{_examples/requirement → requirement/old}/event_requirements.yaml +0 -0
  392. /endoreg_db/data/{_examples/requirement → requirement/old}/finding_colon_polyp.yaml +0 -0
  393. /endoreg_db/{urls/sensitive_meta.py → data/requirement/old/gender.yaml} +0 -0
  394. /endoreg_db/data/{_examples/requirement → requirement/old}/lab_value.yaml +0 -0
  395. /endoreg_db/data/{_examples/requirement → requirement/old}/medication.yaml +0 -0
  396. /endoreg_db/data/{_examples/requirement_operator → requirement_operator/_old}/age.yaml +0 -0
  397. /endoreg_db/data/{_examples/requirement_operator → requirement_operator/_old}/lab_operators.yaml +0 -0
  398. /endoreg_db/data/{_examples/requirement_operator → requirement_operator/_old}/model_operators.yaml +0 -0
  399. /endoreg_db/{views/pdf/pdf_stream_views.py → import_files/pseudonymization/__init__.py} +0 -0
  400. /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
  401. /endoreg_db/utils/requirement_operator_logic/{model_evaluators.py → _old/model_evaluators.py} +0 -0
  402. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.9.2.dist-info}/licenses/LICENSE +0 -0
@@ -11,22 +11,25 @@ from django.core.validators import FileExtensionValidator
11
11
  from django.db import models
12
12
  from django.db.models import F
13
13
  from django.db.models.fields.files import FieldFile
14
- from librosa import frames_to_samples
15
- from pandas.core import frame
16
14
 
17
15
  from endoreg_db.utils.calc_duration_seconds import _calc_duration_vf
18
16
  from endoreg_db.utils.video.ffmpeg_wrapper import assemble_video_from_frames
19
17
 
20
18
  from ...label import Label, LabelVideoSegment
21
19
  from ...state import VideoState
22
- from ...utils import ANONYM_VIDEO_DIR, VIDEO_DIR
20
+ from endoreg_db.utils.paths import ANONYM_VIDEO_DIR, SENSITIVE_VIDEO_DIR
23
21
 
24
22
  # --- Import model-specific function modules ---
25
23
  from .create_from_file import _create_from_file
26
24
  from .pipe_1 import _pipe_1, _test_after_pipe_1
27
25
  from .pipe_2 import _pipe_2
28
26
  from .video_file_ai import _extract_text_from_video_frames, _predict_video_pipeline
29
- from .video_file_anonymize import _anonymize, _censor_outside_frames, _cleanup_raw_assets, _create_anonymized_frame_files
27
+ from .video_file_anonymize import (
28
+ _anonymize,
29
+ _censor_outside_frames,
30
+ _cleanup_raw_assets,
31
+ _create_anonymized_frame_files,
32
+ )
30
33
  from .video_file_frames import (
31
34
  _bulk_create_frames,
32
35
  _create_frame_object,
@@ -85,7 +88,6 @@ if TYPE_CHECKING:
85
88
  VideoImportMeta,
86
89
  VideoMeta,
87
90
  VideoState,
88
- SensitiveMeta
89
91
  )
90
92
 
91
93
 
@@ -115,7 +117,7 @@ class VideoFile(models.Model):
115
117
  objects = VideoQuerySet.as_manager()
116
118
 
117
119
  raw_file = models.FileField(
118
- upload_to=VIDEO_DIR.name, # Use .name for relative path
120
+ upload_to=SENSITIVE_VIDEO_DIR.name, # Use .name for relative path
119
121
  validators=[FileExtensionValidator(allowed_extensions=["mp4"])],
120
122
  null=True,
121
123
  blank=True,
@@ -127,7 +129,9 @@ class VideoFile(models.Model):
127
129
  blank=True,
128
130
  )
129
131
 
130
- video_hash = models.CharField(max_length=255, unique=True, help_text="Hash of the raw video file.")
132
+ video_hash = models.CharField(
133
+ max_length=255, unique=True, help_text="Hash of the raw video file."
134
+ )
131
135
  processed_video_hash = models.CharField(
132
136
  max_length=255,
133
137
  unique=True,
@@ -144,7 +148,9 @@ class VideoFile(models.Model):
144
148
  related_name="video_file",
145
149
  )
146
150
  center = models.ForeignKey("Center", on_delete=models.PROTECT)
147
- processor = models.ForeignKey("EndoscopyProcessor", on_delete=models.PROTECT, blank=True, null=True)
151
+ processor = models.ForeignKey(
152
+ "EndoscopyProcessor", on_delete=models.PROTECT, blank=True, null=True
153
+ )
148
154
  video_meta = models.OneToOneField(
149
155
  "VideoMeta",
150
156
  on_delete=models.SET_NULL,
@@ -166,7 +172,9 @@ class VideoFile(models.Model):
166
172
  null=True,
167
173
  related_name="video_files",
168
174
  )
169
- ai_model_meta = models.ForeignKey("ModelMeta", on_delete=models.SET_NULL, blank=True, null=True)
175
+ ai_model_meta = models.ForeignKey(
176
+ "ModelMeta", on_delete=models.SET_NULL, blank=True, null=True
177
+ )
170
178
  state = models.OneToOneField(
171
179
  "VideoState",
172
180
  on_delete=models.SET_NULL,
@@ -174,7 +182,9 @@ class VideoFile(models.Model):
174
182
  blank=True,
175
183
  related_name="video_file",
176
184
  )
177
- import_meta = models.OneToOneField("VideoImportMeta", on_delete=models.CASCADE, blank=True, null=True)
185
+ import_meta = models.OneToOneField(
186
+ "VideoImportMeta", on_delete=models.CASCADE, blank=True, null=True
187
+ )
178
188
 
179
189
  original_file_name = models.CharField(max_length=255, blank=True, null=True)
180
190
  uploaded_at = models.DateTimeField(auto_now_add=True)
@@ -291,7 +301,9 @@ class VideoFile(models.Model):
291
301
  bulk_create_frames = _bulk_create_frames
292
302
 
293
303
  # Define new methods that call the helper functions
294
- def extract_specific_frame_range(self, start_frame: int, end_frame: int, overwrite: bool = False, **kwargs) -> bool:
304
+ def extract_specific_frame_range(
305
+ self, start_frame: int, end_frame: int, overwrite: bool = False, **kwargs
306
+ ) -> bool:
295
307
  """
296
308
  Extract frames from the video within the specified frame range.
297
309
 
@@ -314,9 +326,13 @@ class VideoFile(models.Model):
314
326
 
315
327
  # Log if unexpected kwargs are passed, beyond those used by the helper
316
328
  expected_helper_kwargs = {"quality", "ext", "verbose"}
317
- unexpected_kwargs = {k: v for k, v in kwargs.items() if k not in expected_helper_kwargs}
329
+ unexpected_kwargs = {
330
+ k: v for k, v in kwargs.items() if k not in expected_helper_kwargs
331
+ }
318
332
  if unexpected_kwargs:
319
- logger.warning(f"Unexpected keyword arguments for extract_specific_frame_range, will be ignored by helper: {unexpected_kwargs}")
333
+ logger.warning(
334
+ f"Unexpected keyword arguments for extract_specific_frame_range, will be ignored by helper: {unexpected_kwargs}"
335
+ )
320
336
 
321
337
  return _extract_frame_range_helper(
322
338
  video=self,
@@ -332,7 +348,9 @@ class VideoFile(models.Model):
332
348
  """
333
349
  Deletes frame files for a specific range [start_frame, end_frame).
334
350
  """
335
- _delete_frame_range_helper(video=self, start_frame=start_frame, end_frame=end_frame)
351
+ _delete_frame_range_helper(
352
+ video=self, start_frame=start_frame, end_frame=end_frame
353
+ )
336
354
 
337
355
  delete_with_file = _delete_with_file
338
356
  get_base_frame_dir = _get_base_frame_dir
@@ -387,7 +405,9 @@ class VideoFile(models.Model):
387
405
  if isinstance(raw, FieldFile) and raw.name:
388
406
  return raw
389
407
 
390
- raise ValueError("No active file available. VideoFile has neither raw nor processed file.")
408
+ raise ValueError(
409
+ "No active file available. VideoFile has neither raw nor processed file."
410
+ )
391
411
 
392
412
  @property
393
413
  def active_file_path(self) -> Path:
@@ -406,10 +426,14 @@ class VideoFile(models.Model):
406
426
  elif active is self.raw_file:
407
427
  path = _get_raw_file_path(self)
408
428
  else:
409
- raise ValueError("No active file path available. VideoFile has neither raw nor processed file.")
429
+ raise ValueError(
430
+ "No active file path available. VideoFile has neither raw nor processed file."
431
+ )
410
432
 
411
433
  if path is None:
412
- raise ValueError("Active file path could not be resolved. VideoFile raw file is missing.")
434
+ raise ValueError(
435
+ "Active file path could not be resolved. VideoFile raw file is missing."
436
+ )
413
437
  return path
414
438
 
415
439
  @property
@@ -426,7 +450,9 @@ class VideoFile(models.Model):
426
450
  self.uuid,
427
451
  exc,
428
452
  )
429
- raise ValueError("Active file URL could not be resolved for this VideoFile.") from exc
453
+ raise ValueError(
454
+ "Active file URL could not be resolved for this VideoFile."
455
+ ) from exc
430
456
 
431
457
  if not url:
432
458
  raise ValueError("Active file URL is empty for this VideoFile.")
@@ -434,7 +460,9 @@ class VideoFile(models.Model):
434
460
  return str(url)
435
461
 
436
462
  @classmethod
437
- def create_from_file(cls, file_path: Union[str, Path], center_name: str, **kwargs) -> Optional["VideoFile"]:
463
+ def create_from_file(
464
+ cls, file_path: Union[str, Path], center_name: str, **kwargs
465
+ ) -> Optional["VideoFile"]:
438
466
  # Ensure file_path is a Path object
439
467
  if isinstance(file_path, str):
440
468
  file_path = Path(file_path)
@@ -443,7 +471,9 @@ class VideoFile(models.Model):
443
471
  try:
444
472
  center_name = os.environ["CENTER_NAME"]
445
473
  except KeyError:
446
- logger.error("Center name must be provided to create VideoFile from file. You can set CENTER_NAME in environment variables.")
474
+ logger.error(
475
+ "Center name must be provided to create VideoFile from file. You can set CENTER_NAME in environment variables."
476
+ )
447
477
  return None
448
478
  return _create_from_file(cls, file_path, center_name=center_name, **kwargs)
449
479
 
@@ -503,7 +533,9 @@ class VideoFile(models.Model):
503
533
  # Delete file storage
504
534
  if self.raw_file and self.raw_file.storage.exists(self.raw_file.name):
505
535
  self.raw_file.storage.delete(self.raw_file.name)
506
- if self.processed_file and self.processed_file.storage.exists(self.processed_file.name):
536
+ if self.processed_file and self.processed_file.storage.exists(
537
+ self.processed_file.name
538
+ ):
507
539
  self.processed_file.storage.delete(self.processed_file.name)
508
540
 
509
541
  # Use proper database connection
@@ -530,7 +562,9 @@ class VideoFile(models.Model):
530
562
  logger.error(f"Error deleting VideoFile {self.uuid}: {e}")
531
563
  raise
532
564
 
533
- def validate_metadata_annotation(self, extracted_data_dict: Optional[dict] = None) -> bool:
565
+ def validate_metadata_annotation(
566
+ self, extracted_data_dict: Optional[dict] = None
567
+ ) -> bool:
534
568
  """
535
569
  Validate the metadata of the VideoFile instance.
536
570
 
@@ -543,12 +577,9 @@ class VideoFile(models.Model):
543
577
  video is preserved as the final validated output.
544
578
  """
545
579
 
546
- if not self.sensitive_meta:
547
- # Ensure a SensitiveMeta exists so validation can proceed.
548
- self.sensitive_meta = self.get_or_create_sensitive_meta()
549
580
  # CRITICAL FIX: Delete RAW video file, not the processed (anonymized) one
550
581
  # CRITICAL: Update metadata BEFORE deleting raw video
551
- if extracted_data_dict:
582
+ if extracted_data_dict and self.sensitive_meta:
552
583
  self.sensitive_meta.update_from_dict(extracted_data_dict)
553
584
  else:
554
585
  return False
@@ -564,7 +595,9 @@ class VideoFile(models.Model):
564
595
  # Clear the raw_file field in database (use delete() to avoid save issues)
565
596
  if self.raw_file:
566
597
  self.raw_file.delete(save=False)
567
- logger.info(f"Raw video deleted for {self.uuid}. Anonymized video preserved.")
598
+ logger.info(
599
+ f"Raw video deleted for {self.uuid}. Anonymized video preserved."
600
+ )
568
601
  else:
569
602
  logger.warning(
570
603
  "Raw video file not found for deletion during validation %s.",
@@ -576,10 +609,14 @@ class VideoFile(models.Model):
576
609
  self.get_or_create_state().mark_anonymization_validated(save=True)
577
610
  # Save the VideoFile instance to persist changes
578
611
  self.save()
579
- logger.info(f"Metadata annotation validated and saved for video {self.uuid}.")
612
+ logger.info(
613
+ f"Metadata annotation validated and saved for video {self.uuid}."
614
+ )
580
615
  return True
581
616
  else:
582
- logger.error(f"Failed to validate metadata annotation for video {self.uuid}.")
617
+ logger.error(
618
+ f"Failed to validate metadata annotation for video {self.uuid}."
619
+ )
583
620
  return False
584
621
 
585
622
  def initialize(self):
@@ -600,7 +637,6 @@ class VideoFile(models.Model):
600
637
  # Create a new state if it doesn't exist
601
638
  self.state = self.get_or_create_state()
602
639
 
603
- self.sensitive_meta = self.get_or_create_sensitive_meta()
604
640
  self.save()
605
641
  # Initialize frames based on the video specs
606
642
  self.initialize_frames()
@@ -613,7 +649,9 @@ class VideoFile(models.Model):
613
649
  """
614
650
  active_path = self.active_file_path
615
651
  file_name = active_path.name if active_path else "No file"
616
- state = "Processed" if self.is_processed else ("Raw" if self.has_raw else "No File")
652
+ state = (
653
+ "Processed" if self.is_processed else ("Raw" if self.has_raw else "No File")
654
+ )
617
655
  return f"VideoFile ({state}): {file_name} (UUID: {self.uuid})"
618
656
 
619
657
  # --- Convenience state/meta helpers used in tests and admin workflows ---
@@ -622,6 +660,11 @@ class VideoFile(models.Model):
622
660
  Mark this video's processing state as having its sensitive meta fully processed.
623
661
  This proxies to the related VideoState and persists by default.
624
662
  """
663
+ sm = self.sensitive_meta
664
+ from endoreg_db.models.metadata.sensitive_meta import SensitiveMeta
665
+
666
+ if not isinstance(sm, SensitiveMeta):
667
+ raise AttributeError()
625
668
  state = self.get_or_create_state()
626
669
  state.mark_sensitive_meta_processed(save=save)
627
670
  return self
@@ -631,8 +674,13 @@ class VideoFile(models.Model):
631
674
  Mark the associated SensitiveMeta as verified by setting both DOB and names as verified.
632
675
  Ensures the SensitiveMeta and its state exist.
633
676
  """
634
- sm = self.get_or_create_sensitive_meta()
677
+ sm = self.sensitive_meta
635
678
  # Use SensitiveMeta methods to update underlying SensitiveMetaState
679
+ from endoreg_db.models.metadata.sensitive_meta import SensitiveMeta
680
+
681
+ if not isinstance(sm, SensitiveMeta):
682
+ raise AttributeError()
683
+
636
684
  sm.mark_dob_verified()
637
685
  sm.mark_names_verified()
638
686
  return self
@@ -671,66 +719,9 @@ class VideoFile(models.Model):
671
719
 
672
720
  return state
673
721
 
674
- def get_or_create_sensitive_meta(self) -> "SensitiveMeta":
675
- """
676
- Retrieve the associated SensitiveMeta instance for this video, creating and assigning one if it does not exist.
677
-
678
- **Two-Phase Patient Data Pattern:**
679
- This method implements a two-phase approach to handle incomplete patient data:
680
-
681
- **Phase 1: Initial Creation (with defaults)**
682
- - Creates SensitiveMeta with default patient data to prevent hash calculation errors
683
- - Default values: patient_first_name="Patient", patient_last_name="Unknown", patient_dob=1990-01-01
684
- - Allows video import to proceed even without extracted patient data
685
- - Temporary hash and pseudo-entities are created
686
-
687
- **Phase 2: Update (with extracted data)**
688
- - Real patient data is extracted later (e.g., from video OCR via lx_anonymizer)
689
- - update_from_dict() is called with actual patient information
690
- - Hash is recalculated automatically using real data
691
- - Correct pseudo-entities are created/linked based on new hash
692
-
693
- **Example workflow:**
694
- ```python
695
- # Phase 1: Video creation
696
- video = VideoFile.create_from_file_initialized(...)
697
- video.initialize() # Calls this method
698
- # → SensitiveMeta created with defaults
699
- # → Hash: sha256("Patient Unknown 1990-01-01...")
700
-
701
- # Phase 2: Frame cleaning extracts real data
702
- extracted = {"patient_first_name": "Max", "patient_last_name": "Mustermann", ...}
703
- video.sensitive_meta.update_from_dict(extracted)
704
- # → Hash: sha256("Max Mustermann 1985-03-15...") (RECALCULATED)
705
- ```
706
-
707
- Returns:
708
- SensitiveMeta: The related SensitiveMeta instance.
709
-
710
- See Also:
711
- - sensitive_meta_logic.perform_save_logic() for hash calculation details
712
- - sensitive_meta_logic.update_sensitive_meta_from_dict() for update mechanism
713
- """
714
- from datetime import date as dt_date
715
-
716
- from endoreg_db.models import SensitiveMeta
717
-
718
- if self.sensitive_meta is None:
719
- # Use create_from_dict with default patient data
720
- # to prevent "First name is required to calculate patient hash" error
721
- default_data = {
722
- "patient_first_name": "Patient",
723
- "patient_last_name": "Unknown",
724
- "patient_dob": dt_date(1990, 1, 1),
725
- "examination_date": dt_date.today(),
726
- "center": self.center,
727
- }
728
- self.sensitive_meta = SensitiveMeta.create_from_dict(default_data)
729
- self.save(update_fields=["sensitive_meta"])
730
- # Do not mark state as processed here; it will be set after extraction/validation steps
731
- return self.sensitive_meta
732
-
733
- def get_outside_segments(self, only_validated: bool = False) -> models.QuerySet["LabelVideoSegment"]:
722
+ def get_outside_segments(
723
+ self, only_validated: bool = False
724
+ ) -> models.QuerySet["LabelVideoSegment"]:
734
725
  """
735
726
  Return all video segments labeled as "outside" for this video.
736
727
 
@@ -762,7 +753,9 @@ class VideoFile(models.Model):
762
753
  return self.label_video_segments.none()
763
754
 
764
755
  @classmethod
765
- def create_video_without_outside_frames(cls, instance: "VideoFile", only_validated: bool = False) -> bool:
756
+ def create_video_without_outside_frames(
757
+ cls, instance: "VideoFile", only_validated: bool = False
758
+ ) -> bool:
766
759
  """
767
760
  Creates a new video by excluding frames that belong to 'outside' segments.
768
761
 
@@ -775,40 +768,64 @@ class VideoFile(models.Model):
775
768
  video = instance
776
769
 
777
770
  if not video:
778
- logger.warning("No processed video file available for VideoFile %s.", cls.uuid)
771
+ logger.warning(
772
+ "No processed video file available for VideoFile %s.", cls.uuid
773
+ )
779
774
  return False
780
775
  try:
781
- extracted = video.extract_frames(quality=2, overwrite=False, ext="jpg", verbose=False, from_processed=True)
776
+ extracted = video.extract_frames(
777
+ quality=2,
778
+ overwrite=False,
779
+ ext="jpg",
780
+ verbose=False,
781
+ from_processed=True,
782
+ )
782
783
  assert extracted is True
783
784
  except AssertionError:
784
- # Use default anonymization here
785
- video.anonymize
786
- extracted = video.extract_frames(quality=2, overwrite=False, ext="jpg", verbose=False, from_processed=True)
785
+ extracted = video.extract_frames(
786
+ quality=2,
787
+ overwrite=False,
788
+ ext="jpg",
789
+ verbose=False,
790
+ from_processed=True,
791
+ )
787
792
  assert extracted is True
788
793
  try:
789
794
  # Step 1: Get the "outside" labeled frames
790
795
  censored = _censor_outside_frames(video)
791
796
  frames = [instance.get_frame_dir_path()]
792
797
  assert len(frames) != 0
793
- fps = video.fps if video.fps else 120.0 # Default to 30 FPS if fps is not set
798
+ fps = (
799
+ video.fps if video.fps else 120.0
800
+ ) # Default to 30 FPS if fps is not set
801
+ assert censored is True
794
802
  assert fps is not None
795
803
  assert video.width is not None
796
804
  assert video.height is not None
805
+ # assert isinstance(frames, list[Path]) #TODO improve TypeCheck
797
806
 
798
807
  # Step 2: Reassemble the video with frames excluding the 'outside' labeled frames
799
808
  output_video_path = Path(f"/path/to/output/{cls.uuid}_filtered.mp4")
800
809
  fps = cls.fps if cls.fps else 30.0 # Default to 30 FPS if fps is not set
801
- new_video_file = assemble_video_from_frames(frames, output_video_path, fps, width=video.width, height=video.height)
810
+ new_video_file = assemble_video_from_frames(
811
+ frames, output_video_path, fps, width=video.width, height=video.height
812
+ )
802
813
  video.processed_file = new_video_file
803
814
  return True
804
815
  except AssertionError as ae:
805
- logger.error(f"Assertion error while creating video without 'outside' frames for VideoFile {cls.uuid}: {ae}", exc_info=True)
816
+ logger.error(
817
+ f"Assertion error while creating video without 'outside' frames for VideoFile {cls.uuid}: {ae}",
818
+ exc_info=True,
819
+ )
806
820
  return False
807
821
  except Label.DoesNotExist:
808
822
  logger.warning("Outside label not found in the database.")
809
823
  return False
810
824
  except Exception as e:
811
- logger.error(f"Error creating video without 'outside' frames for VideoFile {cls.uuid}: {e}", exc_info=True)
825
+ logger.error(
826
+ f"Error creating video without 'outside' frames for VideoFile {cls.uuid}: {e}",
827
+ exc_info=True,
828
+ )
812
829
  return False
813
830
 
814
831
  @classmethod
@@ -828,7 +845,9 @@ class VideoFile(models.Model):
828
845
  int: The count of VideoFile records, excluding this instance, where the modification timestamp matches the creation timestamp.
829
846
  """
830
847
  return (
831
- VideoFile.objects.filter(date_modified=F("date_created")) # compare the two fields in SQL
848
+ VideoFile.objects.filter(
849
+ date_modified=F("date_created")
850
+ ) # compare the two fields in SQL
832
851
  .exclude(pk=self.pk) # exclude this instance
833
852
  .count() # run a fast COUNT(*) on the filtered set
834
853
  )
@@ -851,7 +870,8 @@ class VideoFile(models.Model):
851
870
  raise ValueError("FPS must be set and greater than zero.")
852
871
  return frame_number / fps
853
872
 
854
- def get_video_by_id(self, video_id: int) -> "VideoFile":
873
+ @staticmethod
874
+ def get_video_by_pk(pk: int) -> "VideoFile":
855
875
  """
856
876
  Retrieve a VideoFile instance by its primary key (ID).
857
877
 
@@ -864,4 +884,4 @@ class VideoFile(models.Model):
864
884
  Raises:
865
885
  VideoFile.DoesNotExist: If no VideoFile with the given ID exists.
866
886
  """
867
- return self.objects.get(pk=video_id)
887
+ return VideoFile.objects.get(pk=video_id)
@@ -6,9 +6,9 @@ from typing import TYPE_CHECKING, Iterator, Optional
6
6
  from django.db import transaction
7
7
 
8
8
  from ....utils import delete_field_file, ensure_local_file, storage_file_exists
9
- from ...utils import (
9
+ from endoreg_db.utils.paths import (
10
10
  ANONYM_VIDEO_DIR,
11
- VIDEO_DIR,
11
+ SENSITIVE_VIDEO_DIR,
12
12
  data_paths,
13
13
  )
14
14
 
@@ -23,36 +23,41 @@ def _get_raw_file_path(video: "VideoFile") -> Optional[Path]:
23
23
  if not (video.has_raw and video.raw_file.name):
24
24
  return None
25
25
 
26
- # raw_file.name is a relative storage path like 'videos/<filename>'
27
- raw_rel = Path(video.raw_file.name)
26
+ # 1) Canonical: use Django's storage path
27
+ try:
28
+ direct_path = Path(video.raw_file.path)
29
+ if direct_path.is_file():
30
+ return direct_path.resolve()
31
+ else:
32
+ logger.debug(
33
+ "raw_file.path for video %s is not a regular file: %s",
34
+ video.uuid,
35
+ direct_path,
36
+ )
37
+ except Exception as exc:
38
+ logger.debug(
39
+ "Could not access raw_file.path for video %s: %s",
40
+ video.uuid,
41
+ exc,
42
+ )
28
43
 
29
- # If it already contains the video directory name, keep the tail
30
- rel_name = raw_rel.name if raw_rel.parent.name == VIDEO_DIR.name else raw_rel
31
- full_path = data_paths["video"] / rel_name
44
+ # 2) Fallback: use just the filename and search in known dirs
45
+ raw_rel = Path(video.raw_file.name)
46
+ filename = raw_rel.name # strip any (possibly wrong) prefix
32
47
 
33
- if full_path.exists():
34
- return full_path.resolve()
48
+ candidates = [
49
+ data_paths["import_video"] / filename,
50
+ data_paths["sensitive_video"] / filename,
51
+ ]
35
52
 
36
- sensitive_path = data_paths["video"] / "sensitive" / rel_name
37
- if sensitive_path.exists():
38
- return sensitive_path.resolve()
39
53
 
40
- if storage_file_exists(video.raw_file):
41
- try:
42
- direct_path = Path(video.raw_file.path)
43
- if direct_path.exists():
44
- return direct_path.resolve()
45
- except Exception as exc:
46
- logger.debug(
47
- "Could not access direct raw_file.path for video %s: %s",
48
- video.uuid,
49
- exc,
50
- )
54
+ for candidate in candidates:
55
+ if candidate.is_file():
56
+ return candidate.resolve()
51
57
 
52
58
  logger.warning(
53
- "Raw video file '%s' not found under %s or via stored FileField path for video %s.",
54
- rel_name,
55
- data_paths["video"],
59
+ "Raw video file '%s' not found in import/sensitive paths or via stored FileField path for video %s.",
60
+ video.raw_file.name,
56
61
  video.uuid,
57
62
  )
58
63
  return None
@@ -0,0 +1 @@
1
+ not yet properly implemented
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, List
1
+ from typing import TYPE_CHECKING, List, cast
2
2
 
3
3
  from django.db import models
4
4
 
@@ -28,20 +28,40 @@ class Examination(models.Model):
28
28
  name = models.CharField(max_length=100, unique=True)
29
29
  examination_types = models.ManyToManyField("ExaminationType", blank=True)
30
30
  description = models.TextField(blank=True, null=True)
31
+ indications = models.ManyToManyField(
32
+ "ExaminationIndication",
33
+ related_name="examinations",
34
+ blank=True,
35
+ )
36
+ examination_times = models.ManyToManyField(
37
+ "ExaminationTime",
38
+ related_name="examinations",
39
+ blank=True,
40
+ )
41
+
42
+ findings = models.ManyToManyField(
43
+ "Finding",
44
+ blank=True,
45
+ related_name="examinations",
46
+ )
47
+ information_sources = models.ManyToManyField(
48
+ "InformationSource",
49
+ related_name="examinations",
50
+ blank=True,
51
+ )
31
52
 
32
53
  objects = ExaminationManager()
33
54
 
34
55
  if TYPE_CHECKING:
35
- from endoreg_db.models import ExaminationIndication, Finding, FindingClassification
56
+ from endoreg_db.models import ExaminationIndication, ExaminationTime, Finding, FindingClassification, InformationSource
36
57
 
37
- @property
38
- def finding_classifications(self) -> "models.manager.RelatedManager[FindingClassification]": ...
58
+ indications = cast("models.manager.RelatedManager[ExaminationIndication]", indications)
59
+ examination_times = cast("models.manager.RelatedManager[ExaminationTime]", examination_times)
60
+ findings = cast("models.manager.RelatedManager[Finding]", findings)
61
+ information_sources = cast("models.manager.RelatedManager[InformationSource]", information_sources)
39
62
 
40
63
  @property
41
- def indications(self) -> "models.manager.RelatedManager[ExaminationIndication]": ...
42
-
43
- @property
44
- def findings(self) -> "models.manager.RelatedManager[Finding]": ...
64
+ def finding_classifications(self) -> "models.manager.RelatedManager[FindingClassification]": ...
45
65
 
46
66
  @property
47
67
  def exam_reqset_links(self) -> "models.manager.RelatedManager[ExaminationRequirementSet]": ...