endoreg-db 0.8.8.0__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 (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 +400 -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/processing/video_processing/video_cleanup_on_error.py +119 -0
  74. endoreg_db/import_files/pseudonymization/fake.py +52 -0
  75. endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
  76. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -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 +64 -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/views/__init__.py +85 -173
  171. endoreg_db/views/ai/__init__.py +8 -0
  172. endoreg_db/views/ai/label.py +155 -0
  173. endoreg_db/views/anonymization/media_management.py +8 -7
  174. endoreg_db/views/anonymization/overview.py +97 -68
  175. endoreg_db/views/anonymization/validate.py +25 -21
  176. endoreg_db/views/media/__init__.py +5 -20
  177. endoreg_db/views/media/pdf_media.py +109 -65
  178. endoreg_db/views/media/sensitive_metadata.py +163 -148
  179. endoreg_db/views/meta/__init__.py +0 -8
  180. endoreg_db/views/misc/__init__.py +1 -7
  181. endoreg_db/views/misc/upload_views.py +94 -93
  182. endoreg_db/views/report/__init__.py +7 -0
  183. endoreg_db/views/{pdf → report}/reimport.py +45 -24
  184. endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +40 -32
  185. endoreg_db/views/requirement/lookup_store.py +22 -90
  186. endoreg_db/views/video/__init__.py +23 -22
  187. endoreg_db/views/video/correction.py +201 -172
  188. endoreg_db/views/video/reimport.py +1 -1
  189. endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +75 -37
  190. endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
  191. endoreg_db/views/video/video_stream.py +7 -8
  192. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +2 -2
  193. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +217 -335
  194. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
  195. endoreg_db/data/_examples/disease.yaml +0 -55
  196. endoreg_db/data/_examples/disease_classification.yaml +0 -13
  197. endoreg_db/data/_examples/disease_classification_choice.yaml +0 -62
  198. endoreg_db/data/_examples/event.yaml +0 -64
  199. endoreg_db/data/_examples/examination.yaml +0 -72
  200. endoreg_db/data/_examples/finding/anatomy_colon.yaml +0 -128
  201. endoreg_db/data/_examples/finding/colonoscopy.yaml +0 -40
  202. endoreg_db/data/_examples/finding/colonoscopy_bowel_prep.yaml +0 -56
  203. endoreg_db/data/_examples/finding/complication.yaml +0 -16
  204. endoreg_db/data/_examples/finding/data.yaml +0 -105
  205. endoreg_db/data/_examples/finding/examination_setting.yaml +0 -16
  206. endoreg_db/data/_examples/finding/medication_related.yaml +0 -18
  207. endoreg_db/data/_examples/finding/outcome.yaml +0 -12
  208. endoreg_db/data/_examples/finding_classification/colonoscopy_bowel_preparation.yaml +0 -68
  209. endoreg_db/data/_examples/finding_classification/colonoscopy_jnet.yaml +0 -22
  210. endoreg_db/data/_examples/finding_classification/colonoscopy_kudo.yaml +0 -25
  211. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  212. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  213. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_size.yaml +0 -68
  214. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  215. endoreg_db/data/_examples/finding_classification/colonoscopy_location.yaml +0 -80
  216. endoreg_db/data/_examples/finding_classification/colonoscopy_lst.yaml +0 -21
  217. endoreg_db/data/_examples/finding_classification/colonoscopy_nice.yaml +0 -20
  218. endoreg_db/data/_examples/finding_classification/colonoscopy_paris.yaml +0 -26
  219. endoreg_db/data/_examples/finding_classification/colonoscopy_sano.yaml +0 -22
  220. endoreg_db/data/_examples/finding_classification/colonoscopy_summary.yaml +0 -53
  221. endoreg_db/data/_examples/finding_classification/complication_generic.yaml +0 -25
  222. endoreg_db/data/_examples/finding_classification/examination_setting_generic.yaml +0 -40
  223. endoreg_db/data/_examples/finding_classification/histology_colo.yaml +0 -51
  224. endoreg_db/data/_examples/finding_classification/intervention_required.yaml +0 -26
  225. endoreg_db/data/_examples/finding_classification/medication_related.yaml +0 -23
  226. endoreg_db/data/_examples/finding_classification/visualized.yaml +0 -33
  227. endoreg_db/data/_examples/finding_classification_choice/bowel_preparation.yaml +0 -78
  228. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  229. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  230. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  231. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  232. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  233. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  234. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  235. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  236. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_size.yaml +0 -82
  237. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  238. endoreg_db/data/_examples/finding_classification_choice/complication_generic_types.yaml +0 -15
  239. endoreg_db/data/_examples/finding_classification_choice/examination_setting_generic_types.yaml +0 -15
  240. endoreg_db/data/_examples/finding_classification_choice/histology.yaml +0 -24
  241. endoreg_db/data/_examples/finding_classification_choice/histology_polyp.yaml +0 -20
  242. endoreg_db/data/_examples/finding_classification_choice/outcome.yaml +0 -19
  243. endoreg_db/data/_examples/finding_classification_choice/yes_no_na.yaml +0 -11
  244. endoreg_db/data/_examples/finding_classification_type/colonoscopy_basic.yaml +0 -48
  245. endoreg_db/data/_examples/finding_intervention/endoscopy.yaml +0 -43
  246. endoreg_db/data/_examples/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  247. endoreg_db/data/_examples/finding_intervention/endoscopy_egd.yaml +0 -128
  248. endoreg_db/data/_examples/finding_intervention/endoscopy_ercp.yaml +0 -32
  249. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  250. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  251. endoreg_db/data/_examples/finding_intervention_type/endoscopy.yaml +0 -15
  252. endoreg_db/data/_examples/finding_type/data.yaml +0 -43
  253. endoreg_db/data/_examples/requirement/age.yaml +0 -26
  254. endoreg_db/data/_examples/requirement/gender.yaml +0 -25
  255. endoreg_db/data/_examples/requirement_set/01_endoscopy_generic.yaml +0 -48
  256. endoreg_db/data/_examples/requirement_set/colonoscopy_austria_screening.yaml +0 -57
  257. endoreg_db/data/_examples/requirement_set/endoscopy_bleeding_risk.yaml +0 -52
  258. endoreg_db/data/_examples/yaml_examples.xlsx +0 -0
  259. endoreg_db/data/finding/anatomy_colon.yaml +0 -128
  260. endoreg_db/data/finding/colonoscopy.yaml +0 -40
  261. endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
  262. endoreg_db/data/finding/complication.yaml +0 -16
  263. endoreg_db/data/finding/data.yaml +0 -105
  264. endoreg_db/data/finding/examination_setting.yaml +0 -16
  265. endoreg_db/data/finding/medication_related.yaml +0 -18
  266. endoreg_db/data/finding/outcome.yaml +0 -12
  267. endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
  268. endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
  269. endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  270. endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  271. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -38
  272. endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  273. endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -49
  274. endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
  275. endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
  276. endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
  277. endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
  278. endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
  279. endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
  280. endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
  281. endoreg_db/data/finding_classification/histology_colo.yaml +0 -43
  282. endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
  283. endoreg_db/data/finding_classification/medication_related.yaml +0 -23
  284. endoreg_db/data/finding_classification/visualized.yaml +0 -33
  285. endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  286. endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  287. endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  288. endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  289. endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  290. endoreg_db/data/finding_classification_choice/colon_lesion_paris.yaml +0 -57
  291. endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  292. endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  293. endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  294. endoreg_db/data/finding_classification_choice/colonoscopy_location.yaml +0 -229
  295. endoreg_db/data/finding_classification_choice/colonoscopy_not_complete_reason.yaml +0 -19
  296. endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
  297. endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  298. endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
  299. endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
  300. endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  301. endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
  302. endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
  303. endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  304. endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  305. endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
  306. endoreg_db/data/requirement/age.yaml +0 -26
  307. endoreg_db/data/requirement/colonoscopy_baseline_austria.yaml +0 -45
  308. endoreg_db/data/requirement/disease_cardiovascular.yaml +0 -79
  309. endoreg_db/data/requirement/disease_classification_choice_cardiovascular.yaml +0 -41
  310. endoreg_db/data/requirement/disease_hepatology.yaml +0 -12
  311. endoreg_db/data/requirement/disease_misc.yaml +0 -12
  312. endoreg_db/data/requirement/disease_renal.yaml +0 -96
  313. endoreg_db/data/requirement/endoscopy_bleeding_risk.yaml +0 -59
  314. endoreg_db/data/requirement/event_cardiology.yaml +0 -251
  315. endoreg_db/data/requirement/event_requirements.yaml +0 -145
  316. endoreg_db/data/requirement/finding_colon_polyp.yaml +0 -50
  317. endoreg_db/data/requirement/gender.yaml +0 -25
  318. endoreg_db/data/requirement/lab_value.yaml +0 -441
  319. endoreg_db/data/requirement/medication.yaml +0 -93
  320. endoreg_db/data/requirement_operator/age.yaml +0 -13
  321. endoreg_db/data/requirement_operator/lab_operators.yaml +0 -129
  322. endoreg_db/data/requirement_operator/model_operators.yaml +0 -96
  323. endoreg_db/management/commands/init_default_ai_model.py +0 -112
  324. endoreg_db/management/commands/reset_celery_schedule.py +0 -9
  325. endoreg_db/management/commands/validate_video.py +0 -204
  326. endoreg_db/migrations/0002_requirementset_depends_on.py +0 -18
  327. endoreg_db/migrations/_old/0001_initial.py +0 -1857
  328. endoreg_db/migrations/_old/0002_add_video_correction_models.py +0 -52
  329. endoreg_db/migrations/_old/0003_add_center_display_name.py +0 -30
  330. endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +0 -68
  331. endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +0 -77
  332. endoreg_db/migrations/_old/0005_merge_20251111_1003.py +0 -14
  333. endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +0 -68
  334. endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +0 -89
  335. endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +0 -27
  336. endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +0 -21
  337. endoreg_db/renames.yml +0 -8
  338. endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
  339. endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
  340. endoreg_db/serializers/_old/video.py +0 -71
  341. endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
  342. endoreg_db/serializers/meta/report_meta.py +0 -53
  343. endoreg_db/serializers/report/__init__.py +0 -9
  344. endoreg_db/serializers/report/mixins.py +0 -45
  345. endoreg_db/serializers/report/report.py +0 -105
  346. endoreg_db/serializers/report/report_list.py +0 -22
  347. endoreg_db/serializers/report/secure_file_url.py +0 -26
  348. endoreg_db/services/requirements_object.py +0 -147
  349. endoreg_db/services/storage_aware_video_processor.py +0 -370
  350. endoreg_db/urls/files.py +0 -6
  351. endoreg_db/urls/label_video_segment_validate.py +0 -33
  352. endoreg_db/urls/label_video_segments.py +0 -46
  353. endoreg_db/views/label/__init__.py +0 -5
  354. endoreg_db/views/label/label.py +0 -15
  355. endoreg_db/views/label_video_segment/__init__.py +0 -16
  356. endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
  357. endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
  358. endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
  359. endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
  360. endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
  361. endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
  362. endoreg_db/views/label_video_segment/validate.py +0 -226
  363. endoreg_db/views/media/segments.py +0 -71
  364. endoreg_db/views/meta/available_files_list.py +0 -146
  365. endoreg_db/views/meta/report_meta.py +0 -53
  366. endoreg_db/views/meta/sensitive_meta_detail.py +0 -85
  367. endoreg_db/views/misc/secure_file_serving_view.py +0 -80
  368. endoreg_db/views/misc/secure_file_url_view.py +0 -84
  369. endoreg_db/views/misc/secure_url_validate.py +0 -79
  370. endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
  371. endoreg_db/views/patient_finding_location/__init__.py +0 -5
  372. endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
  373. endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
  374. endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
  375. endoreg_db/views/pdf/__init__.py +0 -8
  376. endoreg_db/views/video/segmentation.py +0 -274
  377. endoreg_db/views/video/task_status.py +0 -49
  378. endoreg_db/views/video/timeline.py +0 -46
  379. endoreg_db/views/video/video_analyze.py +0 -52
  380. /endoreg_db/data/requirement/{colon_polyp_intervention.yaml → old/colon_polyp_intervention.yaml} +0 -0
  381. /endoreg_db/data/{_examples/requirement → requirement/old}/colonoscopy_baseline_austria.yaml +0 -0
  382. /endoreg_db/data/requirement/{coloreg_colon_polyp.yaml → old/coloreg_colon_polyp.yaml} +0 -0
  383. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_cardiovascular.yaml +0 -0
  384. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_classification_choice_cardiovascular.yaml +0 -0
  385. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_hepatology.yaml +0 -0
  386. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_misc.yaml +0 -0
  387. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_renal.yaml +0 -0
  388. /endoreg_db/data/{_examples/requirement → requirement/old}/endoscopy_bleeding_risk.yaml +0 -0
  389. /endoreg_db/data/{_examples/requirement → requirement/old}/event_cardiology.yaml +0 -0
  390. /endoreg_db/data/{_examples/requirement → requirement/old}/event_requirements.yaml +0 -0
  391. /endoreg_db/data/{_examples/requirement → requirement/old}/finding_colon_polyp.yaml +0 -0
  392. /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
  393. /endoreg_db/data/{_examples/requirement → requirement/old}/lab_value.yaml +0 -0
  394. /endoreg_db/data/{_examples/requirement → requirement/old}/medication.yaml +0 -0
  395. /endoreg_db/data/{_examples/requirement_operator → requirement_operator/_old}/age.yaml +0 -0
  396. /endoreg_db/data/{_examples/requirement_operator → requirement_operator/_old}/lab_operators.yaml +0 -0
  397. /endoreg_db/data/{_examples/requirement_operator → requirement_operator/_old}/model_operators.yaml +0 -0
  398. /endoreg_db/{urls/sensitive_meta.py → import_files/pseudonymization/__init__.py} +0 -0
  399. /endoreg_db/{views/pdf/pdf_stream_views.py → import_files/pseudonymization/pseudonymize.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.8.9.dist-info}/licenses/LICENSE +0 -0
@@ -1,8 +1,39 @@
1
1
  import os
2
+ from datetime import UTC, datetime
3
+
2
4
  import yaml
3
5
  from django.core.exceptions import ObjectDoesNotExist
4
6
  from django.db import OperationalError, transaction
5
7
 
8
+ from endoreg_db.utils.paths import STORAGE_DIR
9
+
10
+ _WARNING_LOG_PATH = None
11
+
12
+
13
+ def _get_warning_log_path():
14
+ """Return the path used for warning logs, creating it on first access."""
15
+ global _WARNING_LOG_PATH
16
+ if _WARNING_LOG_PATH is None:
17
+ log_dir = STORAGE_DIR / "logs"
18
+ log_dir.mkdir(parents=True, exist_ok=True)
19
+ timestamp = datetime.now(UTC).strftime("%Y%m%d-%H%M%S")
20
+ _WARNING_LOG_PATH = log_dir / f"dataloader_warnings_{timestamp}.log"
21
+ return _WARNING_LOG_PATH
22
+
23
+
24
+ def _record_warning(command, message, verbose, context):
25
+ """Write a warning to stdout (when verbose) and append it to the log file."""
26
+ prefix = f"[{context}] " if context else ""
27
+ full_message = f"{prefix}{message}"
28
+
29
+ if verbose:
30
+ command.stdout.write(command.style.WARNING(full_message))
31
+
32
+ log_path = _get_warning_log_path()
33
+ with open(log_path, "a", encoding="utf-8") as log_file:
34
+ log_file.write(f"{datetime.now(UTC).isoformat()}Z {full_message}\n")
35
+
36
+
6
37
  def load_model_data_from_yaml(command, model_name, metadata, verbose):
7
38
  """
8
39
  Load model data from YAML files.
@@ -15,6 +46,10 @@ def load_model_data_from_yaml(command, model_name, metadata, verbose):
15
46
  """
16
47
  if verbose:
17
48
  command.stdout.write(f"Start loading {model_name}")
49
+
50
+ warning_log_path = _get_warning_log_path()
51
+ if verbose:
52
+ command.stdout.write(f"Warning log file: {warning_log_path}")
18
53
  model = metadata["model"]
19
54
  dir_path = metadata["dir"]
20
55
  foreign_keys = metadata["foreign_keys"]
@@ -29,7 +64,14 @@ def load_model_data_from_yaml(command, model_name, metadata, verbose):
29
64
  yaml_data = yaml.safe_load(file)
30
65
 
31
66
  load_data_with_foreign_keys(
32
- command, model, yaml_data, foreign_keys, foreign_key_models, validators, verbose
67
+ command,
68
+ model,
69
+ yaml_data,
70
+ foreign_keys,
71
+ foreign_key_models,
72
+ validators,
73
+ verbose,
74
+ log_context=model_name or model.__name__,
33
75
  )
34
76
 
35
77
 
@@ -41,10 +83,11 @@ def load_data_with_foreign_keys(
41
83
  foreign_key_models,
42
84
  validators,
43
85
  verbose,
86
+ log_context=None,
44
87
  ):
45
88
  """
46
89
  Load YAML data into Django model instances with FK and M2M support.
47
-
90
+
48
91
  Processes each YAML entry to create or update a model instance. For each entry, the
49
92
  function extracts field data and uses the presence of a 'name' field to decide whether
50
93
  to update an existing instance or create a new one. Foreign key fields listed in
@@ -52,7 +95,7 @@ def load_data_with_foreign_keys(
52
95
  contains a list, it is treated as a many-to-many relationship and the corresponding
53
96
  objects are set after the instance is saved. Missing or unresolved foreign keys trigger
54
97
  warnings if verbose output is enabled.
55
-
98
+
56
99
  Parameters:
57
100
  model: The Django model class representing the data.
58
101
  yaml_data: A list of dictionaries representing YAML entries.
@@ -62,7 +105,10 @@ def load_data_with_foreign_keys(
62
105
  validator receives a shallow copy of the entry's field dictionary along with
63
106
  the original entry and model for context.
64
107
  verbose: If True, prints detailed output and warnings during processing.
108
+ log_context: Label that identifies the source dataset inside the warning log.
65
109
  """
110
+ context_label = log_context or getattr(model, "__name__", "dataloader")
111
+
66
112
  for entry in yaml_data:
67
113
  raw_fields = entry.get("fields", {})
68
114
 
@@ -72,30 +118,21 @@ def load_data_with_foreign_keys(
72
118
  fields = dict(raw_fields)
73
119
  name = fields.pop("name", None)
74
120
 
75
-
76
121
  if getattr(model, "_meta", None) and model._meta.model_name == "requirement":
77
122
  requirement_types = fields.get("requirement_types", [])
78
- operators = fields.get("operators", [])
79
-
123
+
80
124
  if not requirement_types:
81
- raise ValueError(
82
- f"Requirement '{name}' must define at least one requirement_types entry."
83
- )
84
- if not operators:
85
- raise ValueError(
86
- f"Requirement '{name}' must define at least one operators entry."
87
- )
88
-
125
+ raise ValueError(f"Requirement '{name}' must define at least one requirement_types entry.")
126
+
89
127
  ####################
90
- #TODO REMOVE AFTER TRANSLATION SUPPORT IS ADDED
91
- SKIP_NAMES=[
128
+ # TODO REMOVE AFTER TRANSLATION SUPPORT IS ADDED
129
+ SKIP_NAMES = [
92
130
  "name_de", # German name, not used
93
131
  "name_en", # English name, not used
94
132
  "description_de", # German description
95
133
  "description_en", # English description
96
134
  ]
97
135
 
98
-
99
136
  # Remove fields that are not needed
100
137
  for skip_name in SKIP_NAMES:
101
138
  if skip_name in fields:
@@ -115,12 +152,12 @@ def load_data_with_foreign_keys(
115
152
 
116
153
  # Ensure the foreign key exists
117
154
  if target_keys is None:
118
- if verbose:
119
- command.stdout.write(
120
- command.style.WARNING(
121
- f"Foreign key {fk_field} not found in fields"
122
- )
123
- )
155
+ _record_warning(
156
+ command,
157
+ f"Foreign key {fk_field} not found in fields",
158
+ verbose,
159
+ context_label,
160
+ )
124
161
  continue # Skip if no foreign key provided
125
162
 
126
163
  # Process many-to-many fields or foreign keys
@@ -130,20 +167,17 @@ def load_data_with_foreign_keys(
130
167
  try:
131
168
  obj = fk_model.objects.get_by_natural_key(key)
132
169
  except ObjectDoesNotExist:
133
- if verbose:
134
- command.stdout.write(
135
- command.style.WARNING(
136
- f"{fk_model.__name__} with key {key} not found"
137
- )
138
- )
170
+ _record_warning(
171
+ command,
172
+ f"{fk_model.__name__} with key {key} not found",
173
+ verbose,
174
+ context_label,
175
+ )
139
176
  continue
140
177
  related_objects.append(obj)
141
178
  m2m_relationships[fk_field] = related_objects
142
179
  else: # Single foreign key relationship
143
- if (
144
- model.__name__ == "ModelMeta"
145
- and fk_field == "labelset"
146
- ):
180
+ if model.__name__ == "ModelMeta" and fk_field == "labelset":
147
181
  labelset_version = fields.pop("labelset_version", None)
148
182
 
149
183
  if isinstance(target_keys, (tuple, list)):
@@ -154,10 +188,12 @@ def load_data_with_foreign_keys(
154
188
  labelset_name = target_keys
155
189
 
156
190
  if not labelset_name:
157
- if verbose:
158
- command.stdout.write(
159
- command.style.WARNING("LabelSet name missing for ModelMeta entry")
160
- )
191
+ _record_warning(
192
+ command,
193
+ "LabelSet name missing for ModelMeta entry",
194
+ verbose,
195
+ context_label,
196
+ )
161
197
  continue
162
198
 
163
199
  queryset = fk_model.objects.filter(name=labelset_name)
@@ -170,24 +206,24 @@ def load_data_with_foreign_keys(
170
206
 
171
207
  obj = queryset.order_by("-version").first()
172
208
  if obj is None:
173
- if verbose:
174
- command.stdout.write(
175
- command.style.WARNING(
176
- f"LabelSet '{labelset_name}' (version={labelset_version}) not found"
177
- )
178
- )
209
+ _record_warning(
210
+ command,
211
+ f"LabelSet '{labelset_name}' (version={labelset_version}) not found",
212
+ verbose,
213
+ context_label,
214
+ )
179
215
  continue
180
216
  fields[fk_field] = obj
181
217
  else:
182
218
  try:
183
219
  obj = fk_model.objects.get_by_natural_key(target_keys)
184
220
  except ObjectDoesNotExist:
185
- if verbose:
186
- command.stdout.write(
187
- command.style.WARNING(
188
- f"{fk_model.__name__} with key {target_keys} not found"
189
- )
190
- )
221
+ _record_warning(
222
+ command,
223
+ f"{fk_model.__name__} with key {target_keys} not found",
224
+ verbose,
225
+ context_label,
226
+ )
191
227
  continue
192
228
  fields[fk_field] = obj
193
229
 
@@ -229,9 +265,7 @@ def load_data_with_foreign_keys(
229
265
  obj, created = _save_instance()
230
266
 
231
267
  if created and verbose:
232
- command.stdout.write(
233
- command.style.SUCCESS(f"Created {model.__name__} {name}")
234
- )
268
+ command.stdout.write(command.style.SUCCESS(f"Created {model.__name__} {name}"))
235
269
  elif verbose:
236
270
  pass
237
271
 
@@ -240,8 +274,4 @@ def load_data_with_foreign_keys(
240
274
  if related_objs: # Only set if there are objects to set
241
275
  getattr(obj, field_name).set(related_objs)
242
276
  if verbose:
243
- command.stdout.write(
244
- command.style.SUCCESS(
245
- f"Set {len(related_objs)} {field_name} for {model.__name__} {name}"
246
- )
247
- )
277
+ command.stdout.write(command.style.SUCCESS(f"Set {len(related_objs)} {field_name} for {model.__name__} {name}"))
endoreg_db/utils/paths.py CHANGED
@@ -7,89 +7,153 @@ It provides a unified dictionary 'data_paths' for accessing all path objects.
7
7
 
8
8
  from logging import getLogger
9
9
 
10
- from sphinx.search import no
11
10
  logger = getLogger(__name__)
12
11
 
13
- from pathlib import Path
14
- from typing import Dict
15
12
  import os
13
+ from pathlib import Path
14
+ from typing import Dict, Union
15
+
16
16
  # Alternative approach using env_path helper, deprecated since monorepo setup. Alright for single install, env is always preferred.
17
- #from endoreg_db.config.env import env_path
17
+ # from endoreg_db.config.env import env_path
18
18
 
19
- STORAGE_DIR = Path(os.getenv("STORAGE_DIR", "storage"))
19
+ STORAGE_DIR = Path(os.getenv("STORAGE_DIR", "internal_storage"))
20
20
 
21
21
  storage_dir_env = os.getenv("STORAGE_DIR")
22
22
  if storage_dir_env is None:
23
23
  raise RuntimeError("STORAGE_DIR environment variable is not set.")
24
- storage_dir_str = Path(storage_dir_env)
25
- STORAGE_DIR = storage_dir_str
24
+ storage_dir = Path(storage_dir_env)
25
+ STORAGE_DIR = storage_dir
26
26
  if not STORAGE_DIR.exists():
27
27
  STORAGE_DIR.mkdir(parents=True, exist_ok=True)
28
28
 
29
+
29
30
  PREFIX_RAW = "raw_"
31
+ io_dir_env = Path(os.getenv("IO_DIR", "data"))
32
+ io_dir = Path(io_dir_env)
33
+ IO_DIR = io_dir
34
+ if not STORAGE_DIR.exists():
35
+ STORAGE_DIR.mkdir(parents=True, exist_ok=True)
36
+
37
+
38
+ # Data dropoff folders - These can be external, determined by IO_DIR (Default: set to desktop root folder of OS)
39
+
30
40
  IMPORT_DIR_NAME = "import"
31
41
  EXPORT_DIR_NAME = "export"
32
42
 
33
- VIDEO_DIR_NAME = "videos"
34
- ANONYM_VIDEO_DIR_NAME = "anonym_videos" # Added for processed videos
43
+ IMPORT_DIR = IO_DIR / IMPORT_DIR_NAME # data/import
44
+ EXPORT_DIR = IO_DIR / EXPORT_DIR_NAME # data/export
45
+
46
+
47
+ IMPORT_VIDEO_DIR_NAME = "video_import"
48
+ REPORT_IMPORT_DIR_NAME = "report_import"
49
+
50
+ VIDEO_EXPORT_DIR_NAME = "video_export"
51
+ REPORT_EXPORT_DIR_NAME = "report_export"
52
+
53
+
54
+ IMPORT_VIDEO_DIR = IMPORT_DIR / IMPORT_VIDEO_DIR_NAME
55
+ IMPORT_REPORT_DIR = IMPORT_DIR / REPORT_IMPORT_DIR_NAME
56
+
57
+
58
+ VIDEO_EXPORT_DIR = EXPORT_DIR / VIDEO_EXPORT_DIR_NAME
59
+ REPORT_EXPORT_DIR = EXPORT_DIR / REPORT_EXPORT_DIR_NAME
60
+
61
+ # Document Dir
62
+
63
+ DOCUMENT_DIR = STORAGE_DIR / "documents"
64
+
65
+ # After initial import, files will remain here.
66
+
67
+ TRANSCODING_DIR = STORAGE_DIR /"temp"
68
+
69
+ SENSITIVE_VIDEO_DIR_NAME = "sensitive_videos"
70
+ SENSITIVE_REPORT_DIR_NAME = "sensitive_reports"
71
+ ANONYM_VIDEO_DIR_NAME = "processed_videos_final"
72
+ ANONYM_REPORT_DIR_NAME = "processed_reports_final"
73
+
74
+ RAW_FRAME_DIR_NAME = f"{PREFIX_RAW}frames"
35
75
  FRAME_DIR_NAME = "frames"
36
- PDF_DIR_NAME = "pdfs" # Changed from reports
37
76
  WEIGHTS_DIR_NAME = "model_weights"
38
77
  EXAMINATION_DIR_NAME = "examinations"
39
78
 
40
- RAW_VIDEO_DIR_NAME = f"{PREFIX_RAW}videos"
41
- RAW_FRAME_DIR_NAME = f"{PREFIX_RAW}frames"
42
- RAW_PDF_DIR_NAME = f"{PREFIX_RAW}pdfs" # Changed from reports
43
-
44
79
  # Define data subdirectories under STORAGE_DIR
45
- VIDEO_DIR = STORAGE_DIR / VIDEO_DIR_NAME
46
- ANONYM_VIDEO_DIR = STORAGE_DIR / ANONYM_VIDEO_DIR_NAME # Added
80
+ ANONYM_VIDEO_DIR = STORAGE_DIR / ANONYM_VIDEO_DIR_NAME
81
+ SENSITIVE_VIDEO_DIR = STORAGE_DIR / SENSITIVE_VIDEO_DIR_NAME
82
+ ANONYM_REPORT_DIR = STORAGE_DIR / ANONYM_REPORT_DIR_NAME
83
+ SENSITIVE_REPORT_DIR = STORAGE_DIR / SENSITIVE_REPORT_DIR_NAME
84
+
47
85
  FRAME_DIR = STORAGE_DIR / FRAME_DIR_NAME
48
- PDF_DIR = STORAGE_DIR / PDF_DIR_NAME # Changed
86
+
87
+
49
88
  WEIGHTS_DIR = STORAGE_DIR / WEIGHTS_DIR_NAME
50
- RAW_VIDEO_DIR = STORAGE_DIR / RAW_VIDEO_DIR_NAME
51
89
  RAW_FRAME_DIR = STORAGE_DIR / RAW_FRAME_DIR_NAME
52
- RAW_PDF_DIR = STORAGE_DIR / RAW_PDF_DIR_NAME # Changed
53
90
 
54
- IMPORT_DIR = STORAGE_DIR / IMPORT_DIR_NAME
55
- VIDEO_IMPORT_DIR = IMPORT_DIR / VIDEO_DIR_NAME
56
- FRAME_IMPORT_DIR = IMPORT_DIR / FRAME_DIR_NAME
57
- PDF_IMPORT_DIR = IMPORT_DIR / PDF_DIR_NAME # Changed
58
91
  WEIGHTS_IMPORT_DIR = IMPORT_DIR / WEIGHTS_DIR_NAME
92
+ WEIGHTS_EXPORT_DIR = EXPORT_DIR / WEIGHTS_DIR_NAME
93
+
94
+ FRAME_IMPORT_DIR = IMPORT_DIR / FRAME_DIR_NAME
59
95
 
60
- EXPORT_DIR = STORAGE_DIR / EXPORT_DIR_NAME
96
+ FRAME_EXPORT_DIR = EXPORT_DIR / FRAME_DIR_NAME
61
97
 
62
- data_paths:Dict[str,Path] = {
98
+
99
+ data_paths: Dict[str, Path] = {
63
100
  "storage": STORAGE_DIR,
64
- "video": VIDEO_DIR,
65
- "anonym_video": ANONYM_VIDEO_DIR, # Added
66
- "frame": FRAME_DIR,
67
- "pdf": PDF_DIR, # Changed
68
101
  "import": IMPORT_DIR,
69
- "video_import": VIDEO_IMPORT_DIR,
70
- "frame_import": FRAME_IMPORT_DIR,
71
- "pdf_import": PDF_IMPORT_DIR, # Changed
72
- "raw_video": RAW_VIDEO_DIR,
102
+ "import_video": IMPORT_VIDEO_DIR,
103
+ "sensitive_video": SENSITIVE_VIDEO_DIR,
104
+ "sensitive_report": SENSITIVE_REPORT_DIR,
105
+ "anonym_video": ANONYM_VIDEO_DIR,
106
+ "anonym_report": ANONYM_REPORT_DIR,
107
+ "import_frame": FRAME_IMPORT_DIR,
108
+ "import_report": IMPORT_REPORT_DIR,
73
109
  "raw_frame": RAW_FRAME_DIR,
74
- "raw_pdf": RAW_PDF_DIR, # Changed
75
110
  "weights": WEIGHTS_DIR,
76
111
  "weights_import": WEIGHTS_IMPORT_DIR,
77
112
  "export": EXPORT_DIR,
78
- "video_export": EXPORT_DIR / VIDEO_DIR_NAME,
79
- "anonym_video_export": EXPORT_DIR / ANONYM_VIDEO_DIR_NAME, # Added
80
- "frame_export": EXPORT_DIR / FRAME_DIR_NAME,
81
- "pdf_export": EXPORT_DIR / PDF_DIR_NAME, # Changed
113
+ "report_export": REPORT_EXPORT_DIR,
114
+ "video_export": VIDEO_EXPORT_DIR,
115
+ "frame_export": FRAME_EXPORT_DIR,
82
116
  "weights_export": EXPORT_DIR / WEIGHTS_DIR_NAME,
83
- "examination_export": EXPORT_DIR / EXAMINATION_DIR_NAME,
84
- "raw_video_export": EXPORT_DIR / RAW_VIDEO_DIR_NAME,
85
- "raw_frame_export": EXPORT_DIR / RAW_FRAME_DIR_NAME,
86
- "raw_pdf_export": EXPORT_DIR / RAW_PDF_DIR_NAME, # Changed
117
+ "transcoding": TRANSCODING_DIR,
118
+ "frame": FRAME_DIR,
119
+ "documents": DOCUMENT_DIR
87
120
  }
88
121
 
89
122
  logger.info(f"Storage directory: {STORAGE_DIR.resolve()}")
90
123
  logger.info(f"Export directory: {EXPORT_DIR.resolve()}")
91
124
 
92
- # for key, path in data_paths.items():
93
- # path.mkdir(parents=True, exist_ok=True)
94
-
95
- # logger.info(f"{key.capitalize()} directory: {path.resolve()}")
125
+ for key, path in data_paths.items():
126
+ path.mkdir(parents=True, exist_ok=True)
127
+
128
+ logger.info(f"{key.capitalize()} directory: {path.resolve()}")
129
+
130
+
131
+ def to_storage_relative(path: Union[str, Path]) -> str:
132
+ """
133
+ Return a path string relative to STORAGE_DIR, suitable for Django FileField.name.
134
+
135
+ - If `path` is inside STORAGE_DIR (absolute or contains STORAGE_DIR as prefix),
136
+ we strip the STORAGE_DIR prefix and return the relative part.
137
+ - If `path` is outside STORAGE_DIR, we return it as a string unchanged
138
+ (caller can decide what to do).
139
+ """
140
+ # Normalize input to Path
141
+ p = Path(path)
142
+
143
+ # Resolve absolute path for comparison
144
+ storage_root = STORAGE_DIR.resolve()
145
+
146
+ if not p.is_absolute():
147
+ # Resolve relative path against current working directory
148
+ # (in tests, cwd should be project root, so this still lands under STORAGE_DIR)
149
+ p = p.resolve()
150
+
151
+ try:
152
+ rel = p.relative_to(storage_root)
153
+ except ValueError:
154
+ # Not under STORAGE_DIR – probably already a relative name or external.
155
+ # In that case, just return the string representation as-is.
156
+ return str(path)
157
+
158
+ # Use POSIX-style separators for Django FileField
159
+ return rel.as_posix()
@@ -154,7 +154,7 @@ At this point in the pipeline:
154
154
  `VideoFile.processed_file`
155
155
  - Video hash is calculated and saved in:
156
156
  `VideoFile.processed_video_hash`
157
- - `VideoState.anonymized = True`
157
+ - `VideoState.state.anonymization_status.mark_anonymized()`
158
158
 
159
159
  ---
160
160
 
@@ -0,0 +1,97 @@
1
+ from typing import TYPE_CHECKING, Any, Dict, Tuple, Union
2
+
3
+ if TYPE_CHECKING:
4
+ from endoreg_db.models import Patient, PatientExamination, Requirement
5
+ from endoreg_db.models.requirement.requirement_operator import OperatorInstructions, RequirementOperator
6
+
7
+
8
+ def fetch_input_target(input_object: Union["Patient", "PatientExamination"], operator_instructions: "OperatorInstructions") -> Tuple[str, Any]:
9
+ input_target_names = operator_instructions.input_targets
10
+
11
+ # Iterate over targets and stop with first successful fetch
12
+ for input_target in input_target_names:
13
+ # separate input_target using "." for nested attributes
14
+ attributes = input_target.split(".")
15
+ current_value = input_object
16
+ try:
17
+ for attr in attributes:
18
+ current_value = getattr(current_value, attr)
19
+ return (input_target, current_value)
20
+ except AttributeError:
21
+ continue # Try next input target
22
+
23
+ raise AttributeError(f"None of the input targets {input_target_names} could be resolved on the input object.")
24
+
25
+
26
+ def fetch_requirement_targets(
27
+ requirement: "Requirement",
28
+ operator_instructions: "OperatorInstructions",
29
+ ):
30
+ attribute_target_names = operator_instructions.requirement_targets
31
+ target_values = {}
32
+
33
+ for target_name in attribute_target_names:
34
+ try:
35
+ target_value = getattr(requirement, target_name)
36
+ target_values[target_name] = target_value
37
+ except AttributeError:
38
+ raise AttributeError(f"Requirement does not have attribute '{target_name}'.")
39
+ target_values[target_name] = target_value
40
+
41
+ return target_values
42
+
43
+
44
+ def model_attribute_set_any(
45
+ input_object: Any,
46
+ operator_instructions: "OperatorInstructions",
47
+ requirement: "Requirement",
48
+ ) -> bool:
49
+ input_target_name, input_value = fetch_input_target(input_object, operator_instructions)
50
+
51
+ if not input_value:
52
+ return False
53
+ else:
54
+ return True
55
+
56
+
57
+ def model_attribute_numeric_in_range(
58
+ input_object: Any,
59
+ operator_instructions: "OperatorInstructions",
60
+ requirement: "Requirement",
61
+ ) -> bool:
62
+ input_target_name, input_value = fetch_input_target(input_object, operator_instructions)
63
+
64
+ # make sure, input_value is numeric
65
+ try:
66
+ numeric_value = float(input_value)
67
+ except (TypeError, ValueError):
68
+ raise ValueError(f"Input value for target '{input_target_name}' is not numeric: {input_value}")
69
+
70
+ _min = requirement.numeric_value_min
71
+ _max = requirement.numeric_value_max
72
+
73
+ assert _min is not None and _max is not None, "Numeric range requires both min and max values to be set."
74
+
75
+ return_value = _min <= numeric_value <= _max
76
+ return return_value
77
+
78
+
79
+ def model_attribute_is_among_values(
80
+ input_object: Any,
81
+ operator_instructions: "OperatorInstructions",
82
+ requirement: "Requirement",
83
+ ) -> bool:
84
+ input_target_name, input_value = fetch_input_target(input_object, operator_instructions)
85
+ target_values = fetch_requirement_targets(requirement, operator_instructions)
86
+
87
+ for target_name, target_values in target_values.items():
88
+ if input_value in target_values:
89
+ return True
90
+ return False
91
+
92
+
93
+ REQUIREMENT_OPERATORS = {
94
+ "model_attribute_set_any": model_attribute_set_any,
95
+ "model_attribute_numeric_in_range": model_attribute_numeric_in_range,
96
+ "model_attribute_is_among_values": model_attribute_is_among_values,
97
+ }