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,28 +1,27 @@
1
1
  import random
2
+ import shutil
3
+ from datetime import date
4
+ from logging import getLogger
5
+ from pathlib import Path
2
6
  from typing import Optional
7
+
8
+ from django.conf import settings # Import settings
9
+ from django.core.files.storage import default_storage # Import default storage
10
+ from django.db.models.fields.files import FieldFile
11
+
3
12
  from endoreg_db.models import (
4
- Center,
5
- Gender,
6
- Patient,
13
+ AiModel,
14
+ Center,
15
+ EndoscopyProcessor,
7
16
  Examination,
8
17
  ExaminationIndication,
9
- RawPdfFile,
10
- EndoscopyProcessor,
11
- ModelMeta,
18
+ Gender,
12
19
  InformationSource,
13
- AiModel,
14
- )
15
- from logging import getLogger
16
- from datetime import date
17
- import shutil
18
- from pathlib import Path
19
- from django.conf import settings # Import settings
20
- from django.core.files.storage import default_storage # Import default storage
21
- from django.db.models.fields.files import FieldFile
22
-
23
- from endoreg_db.utils import (
24
- create_mock_patient_name,
20
+ ModelMeta,
21
+ Patient,
22
+ RawPdfFile,
25
23
  )
24
+ from endoreg_db.utils import create_mock_patient_name
26
25
 
27
26
  logger = getLogger("default_objects")
28
27
 
@@ -32,7 +31,7 @@ DEFAULT_ENDOSCOPE_NAME = "test_endoscope"
32
31
  DEFAULT_ENDOSCOPY_PROCESSOR_NAME = "olympus_cv_1500"
33
32
 
34
33
  DEFAULT_EGD_PATH = Path("tests/assets/lux-gastro-report.pdf")
35
- DEFAULT_GENDERS = ["male","female","unknown"]
34
+ DEFAULT_GENDERS = ["male", "female", "unknown"]
36
35
  DEFAULT_EXAMINATIONS = ["colonoscopy"]
37
36
  DEFAULT_INDICATIONS = [
38
37
  "colonoscopy",
@@ -51,60 +50,70 @@ DEFAULT_PATIENT_LAST_NAME = "TestLast"
51
50
  DEFAULT_PATIENT_GENDER_NAME = "female"
52
51
  DEFAULT_PATIENT_BIRTH_DATE = date(1970, 1, 1)
53
52
 
53
+
54
54
  def get_information_source_prediction():
55
55
  """
56
56
  Retrieves the InformationSource object with the name "prediction".
57
-
57
+
58
58
  Loads information source data if needed and returns the corresponding InformationSource instance. Raises a ValueError if the object is not found or is not an InformationSource.
59
59
  """
60
60
  from .data_loader import load_information_source
61
+
61
62
  load_information_source()
62
63
  source = InformationSource.objects.get(name="prediction")
63
64
  if not isinstance(source, InformationSource):
64
65
  raise ValueError("No InformationSource found in the database.")
65
66
  return source
66
67
 
67
- def get_latest_segmentation_model(model_name:str=DEFAULT_SEGMENTATION_MODEL_NAME) -> ModelMeta:
68
68
 
69
+ def get_latest_segmentation_model(
70
+ model_name: str = DEFAULT_SEGMENTATION_MODEL_NAME,
71
+ ) -> ModelMeta:
69
72
  """
70
73
  Retrieves the latest metadata for a segmentation model by name.
71
-
74
+
72
75
  Loads necessary data and returns the most recent ModelMeta instance for the specified AI model. If no metadata exists, attempts to initialize it automatically; if initialization fails, raises a ValueError with instructions for manual setup.
73
-
76
+
74
77
  Args:
75
78
  model_name: The name of the segmentation model to retrieve.
76
-
79
+
77
80
  Returns:
78
81
  The latest ModelMeta instance for the specified model.
79
-
82
+
80
83
  Raises:
81
84
  ValueError: If the AI model does not exist, or if model metadata cannot be found or initialized.
82
85
  """
83
86
  from .data_loader import (
84
- load_center_data,
85
- load_ai_model_label_data,
86
87
  load_ai_model_data,
88
+ load_ai_model_label_data,
89
+ load_center_data,
87
90
  )
91
+
88
92
  load_center_data()
89
93
  load_ai_model_label_data()
90
94
  load_ai_model_data()
91
-
95
+
92
96
  try:
93
97
  ai_model = AiModel.objects.get(name=model_name)
94
98
  except AiModel.DoesNotExist:
95
- raise ValueError(f"AI model '{model_name}' not found. Run 'python manage.py load_ai_model_data' first.")
96
-
99
+ raise ValueError(
100
+ f"AI model '{model_name}' not found. Run 'python manage.py load_ai_model_data' first."
101
+ )
102
+
97
103
  try:
98
104
  latest_meta = ai_model.get_latest_version()
99
105
  return latest_meta
100
106
  except ValueError as e:
101
107
  if "No model metadata found" in str(e):
102
- logger.warning(f"No ModelMeta found for {model_name}. Attempting to initialize default model metadata...")
103
-
108
+ logger.warning(
109
+ f"No ModelMeta found for {model_name}. Attempting to initialize default model metadata..."
110
+ )
111
+
104
112
  # Try to initialize the default model metadata
105
113
  try:
106
114
  from django.core.management import call_command
107
- call_command('init_default_ai_model')
115
+
116
+ call_command("init_default_ai_model")
108
117
  # Try again after initialization
109
118
  latest_meta = ai_model.get_latest_version()
110
119
  return latest_meta
@@ -116,17 +125,18 @@ def get_latest_segmentation_model(model_name:str=DEFAULT_SEGMENTATION_MODEL_NAME
116
125
  ) from e
117
126
  else:
118
127
  raise
119
-
128
+
120
129
 
121
130
  def get_default_gender() -> Gender:
122
131
  """
123
132
  Retrieves the Gender object representing the default "unknown" gender.
124
-
133
+
125
134
  Returns:
126
135
  The Gender instance with the name "unknown".
127
136
  """
128
137
  return Gender.objects.get(name=DEFAULT_GENDER)
129
138
 
139
+
130
140
  def get_gender_m_or_f() -> Gender:
131
141
  """
132
142
  Returns a randomly selected Gender object representing either male or female.
@@ -134,36 +144,40 @@ def get_gender_m_or_f() -> Gender:
134
144
  gender_name = random.choice(["male", "female"])
135
145
  return Gender.objects.get(name=gender_name)
136
146
 
147
+
137
148
  def get_random_gender() -> Gender:
138
149
  """
139
150
  Returns a randomly selected Gender object from the available default genders.
140
151
  """
141
152
  gender_name = random.choice(DEFAULT_GENDERS)
142
- return Gender.objects.get(name=gender_name) # Fetch and return the Gender object
153
+ return Gender.objects.get(name=gender_name) # Fetch and return the Gender object
154
+
143
155
 
144
156
  def get_default_processor() -> EndoscopyProcessor:
145
157
  """
146
158
  Retrieves the default EndoscopyProcessor object by its predefined name.
147
-
159
+
148
160
  Raises:
149
161
  ValueError: If no EndoscopyProcessor with the default name exists.
150
-
162
+
151
163
  Returns:
152
164
  The EndoscopyProcessor instance with the default name.
153
165
  """
154
166
  processor = EndoscopyProcessor.objects.get(name=DEFAULT_ENDOSCOPY_PROCESSOR_NAME)
155
167
  if not isinstance(processor, EndoscopyProcessor):
156
- raise ValueError(f"No EndoscopyProcessor found with name {DEFAULT_ENDOSCOPY_PROCESSOR_NAME}")
168
+ raise ValueError(
169
+ f"No EndoscopyProcessor found with name {DEFAULT_ENDOSCOPY_PROCESSOR_NAME}"
170
+ )
157
171
  return processor
158
172
 
159
173
 
160
174
  def get_default_center() -> Center:
161
175
  """
162
176
  Retrieves the default Center object with the predefined name.
163
-
177
+
164
178
  Raises:
165
179
  ValueError: If no Center with the default name exists.
166
-
180
+
167
181
  Returns:
168
182
  The Center instance with the default name.
169
183
  """
@@ -172,9 +186,10 @@ def get_default_center() -> Center:
172
186
  )
173
187
  if not isinstance(center, Center):
174
188
  raise ValueError(f"No Center found with name {DEFAULT_CENTER_NAME}")
175
-
189
+
176
190
  return center
177
191
 
192
+
178
193
  def generate_patient(**kwargs) -> Patient:
179
194
  """Create a Patient with deterministic defaults unless ``randomize=True`` is supplied."""
180
195
 
@@ -193,9 +208,14 @@ def generate_patient(**kwargs) -> Patient:
193
208
  last_name = kwargs.get("last_name")
194
209
  if first_name is None or last_name is None:
195
210
  if randomize:
196
- generated_first, generated_last = create_mock_patient_name(gender=gender.name)
211
+ generated_first, generated_last = create_mock_patient_name(
212
+ gender=gender.name
213
+ )
197
214
  else:
198
- generated_first, generated_last = DEFAULT_PATIENT_FIRST_NAME, DEFAULT_PATIENT_LAST_NAME
215
+ generated_first, generated_last = (
216
+ DEFAULT_PATIENT_FIRST_NAME,
217
+ DEFAULT_PATIENT_LAST_NAME,
218
+ )
199
219
  first_name = first_name or generated_first
200
220
  last_name = last_name or generated_last
201
221
 
@@ -217,16 +237,17 @@ def generate_patient(**kwargs) -> Patient:
217
237
  first_name=first_name,
218
238
  last_name=last_name,
219
239
  dob=dob,
220
- center = center,
221
- gender = gender,
240
+ center=center,
241
+ gender=gender,
222
242
  )
223
243
 
224
244
  return patient
225
-
245
+
246
+
226
247
  def get_random_default_examination():
227
248
  """
228
249
  Retrieves a random Examination object from the default examination names.
229
-
250
+
230
251
  Returns:
231
252
  Examination: A randomly selected Examination instance from the defaults.
232
253
  """
@@ -235,29 +256,33 @@ def get_random_default_examination():
235
256
  examination = Examination.objects.get(name=examination_name)
236
257
  return examination
237
258
 
259
+
238
260
  def get_random_default_examination_indication():
239
261
  """
240
262
  Returns a random ExaminationIndication object from the default indications list.
241
-
263
+
242
264
  Selects a random indication name from the predefined defaults and retrieves the corresponding ExaminationIndication instance from the database.
243
265
  """
244
266
  examination_indication = random.choice(DEFAULT_INDICATIONS)
245
267
  all_examination_indications = ExaminationIndication.objects.all()
246
268
  try:
247
- examination_indication = ExaminationIndication.objects.get(name=examination_indication)
248
-
269
+ examination_indication = ExaminationIndication.objects.get(
270
+ name=examination_indication
271
+ )
272
+
249
273
  except Exception as e:
250
274
  logger.info(f"examination_indication: {examination_indication}")
251
275
  logger.info(f"all_examination_indications: {all_examination_indications}")
252
276
  raise e
253
277
  return examination_indication
254
278
 
279
+
255
280
  def get_default_egd_pdf():
256
281
  """
257
- Creates and processes a default EGD PDF file for testing purposes.
258
-
259
- This function copies a default EGD PDF to a temporary location, creates a RawPdfFile instance from it, processes the file to generate associated metadata, and ensures cleanup of the temporary file. The resulting RawPdfFile instance is returned for use in tests.
260
-
282
+ Creates and processes a default EGD report file for testing purposes.
283
+
284
+ This function copies a default EGD report to a temporary location, creates a RawPdfFile instance from it, processes the file to generate associated metadata, and ensures cleanup of the temporary file. The resulting RawPdfFile instance is returned for use in tests.
285
+
261
286
  Returns:
262
287
  RawPdfFile: The created and processed RawPdfFile instance.
263
288
  """
@@ -277,44 +302,48 @@ def get_default_egd_pdf():
277
302
  pdf_file = None
278
303
  file_field: Optional[FieldFile] = None
279
304
  try:
280
- # Create the PDF record using the temporary file.
305
+ # Create the report record using the temporary file.
281
306
  # delete_source=True will ensure temp_file_path is deleted by create_from_file
282
307
  pdf_file = RawPdfFile.create_from_file(
283
308
  file_path=temp_file_path,
284
309
  center_name=center_name,
285
- save=True, # save=True is default and handled internally now
310
+ save=True, # save=True is default and handled internally now
286
311
  delete_source=True,
287
312
  )
288
313
 
289
314
  if pdf_file is None:
290
- raise RuntimeError("Failed to create PDF file object")
291
-
315
+ raise RuntimeError("Failed to create report file object")
316
+
292
317
  # Use storage API to check existence
293
318
  file_field = pdf_file.file
294
319
  if not isinstance(file_field, FieldFile):
295
320
  raise RuntimeError("RawPdfFile.file did not return a FieldFile instance")
296
321
  if not default_storage.exists(file_field.path):
297
- raise RuntimeError(f"PDF file does not exist in storage at {file_field.path}")
298
-
322
+ raise RuntimeError(
323
+ f"report file does not exist in storage at {file_field.path}"
324
+ )
325
+
299
326
  # Check that the source temp file was deleted
300
327
  if temp_file_path.exists():
301
- raise RuntimeError(f"Temporary source file {temp_file_path} still exists after creation")
328
+ raise RuntimeError(
329
+ f"Temporary source file {temp_file_path} still exists after creation"
330
+ )
302
331
 
303
332
  # Prepare a minimal report_meta for SensitiveMeta creation
304
333
  default_report_meta = {
305
334
  "patient_first_name": "DefaultFirstName",
306
335
  "patient_last_name": "DefaultLastName",
307
- "patient_dob": date(1980, 1, 1), # Pass date object directly
308
- "examination_date": date(2024, 1, 1), # Pass date object directly
336
+ "patient_dob": date(1980, 1, 1), # Pass date object directly
337
+ "examination_date": date(2024, 1, 1), # Pass date object directly
309
338
  # center_name will be added by process_file using pdf_file.center.name
310
339
  }
311
340
 
312
341
  # Call process_file to create SensitiveMeta and extract other info
313
342
  pdf_file.process_file(
314
- text="Default PDF text content.",
315
- anonymized_text="Default anonymized PDF text content.",
343
+ text="Default report text content.",
344
+ anonymized_text="Default anonymized report text content.",
316
345
  report_meta=default_report_meta,
317
- verbose=False
346
+ verbose=False,
318
347
  )
319
348
  # process_file calls sensitive_meta.save() and self.save() (for RawPdfFile)
320
349
 
@@ -322,40 +351,46 @@ def get_default_egd_pdf():
322
351
  # Clean up temp file in case of error before deletion could occur
323
352
  if temp_file_path.exists():
324
353
  temp_file_path.unlink()
325
- raise e # Re-raise the exception
354
+ raise e # Re-raise the exception
326
355
 
327
356
  # pdf_file.file.path might fail if storage doesn't support direct paths (like S3)
328
357
  # Prefer using storage API for checks. Logging path if available.
329
358
  if file_field is not None:
330
359
  try:
331
- logger.info(f"PDF file created: {file_field.name}, Path: {file_field.path}")
360
+ logger.info(
361
+ f"report file created: {file_field.name}, Path: {file_field.path}"
362
+ )
332
363
  except NotImplementedError:
333
- logger.info(f"PDF file created: {file_field.name}, Path: (Not available from storage)")
334
-
364
+ logger.info(
365
+ f"report file created: {file_field.name}, Path: (Not available from storage)"
366
+ )
335
367
 
336
368
  return pdf_file
337
369
 
370
+
338
371
  def get_default_video_file():
339
372
  """
340
373
  Creates and returns a VideoFile instance using a randomly selected EGD examination video.
341
-
374
+
342
375
  Loads all necessary data dependencies, selects a random video file for the 'egd' examination, and initializes a VideoFile object with the default center and processor names. The original video file is retained after creation.
343
-
376
+
344
377
  Returns:
345
378
  VideoFile: The created and initialized VideoFile instance.
346
379
  """
347
- from .test_video_helper import get_random_video_path_by_examination_alias
348
380
  from endoreg_db.models import VideoFile
381
+
349
382
  from .data_loader import (
383
+ load_ai_model_data,
384
+ load_ai_model_label_data,
385
+ load_center_data,
350
386
  load_disease_data,
387
+ load_endoscope_data,
351
388
  load_event_data,
352
- load_information_source,
353
389
  load_examination_data,
354
- load_center_data,
355
- load_endoscope_data,
356
- load_ai_model_label_data,
357
- load_ai_model_data,
390
+ load_information_source,
358
391
  )
392
+ from .test_video_helper import get_random_video_path_by_examination_alias
393
+
359
394
  load_disease_data()
360
395
  load_event_data()
361
396
  load_information_source()
@@ -365,14 +400,14 @@ def get_default_video_file():
365
400
  load_ai_model_label_data()
366
401
  load_ai_model_data()
367
402
  video_path = get_random_video_path_by_examination_alias(
368
- examination_alias='egd', is_anonymous=False
403
+ examination_alias="egd", is_anonymous=False
369
404
  )
370
405
 
371
406
  video_file = VideoFile.create_from_file_initialized(
372
407
  file_path=video_path,
373
408
  center_name=DEFAULT_CENTER_NAME, # Pass center name as expected by _create_from_file
374
409
  delete_source=False, # Keep the original asset for other tests
375
- processor_name = DEFAULT_ENDOSCOPY_PROCESSOR_NAME,
410
+ processor_name=DEFAULT_ENDOSCOPY_PROCESSOR_NAME,
376
411
  )
377
412
 
378
413
  return video_file
@@ -0,0 +1,27 @@
1
+ # Re-export context helpers
2
+ from .context.file_lock import file_lock
3
+ from .context.default_sensitive_meta import default_sensitive_meta # if needed
4
+ from .context.import_context import ImportContext # if needed
5
+ from .context.validate_directories import validate_directories # if needed
6
+
7
+ # Re-export storage helpers
8
+ from .file_storage import create_report_file
9
+ from .file_storage import create_video_file
10
+ from .file_storage import sensitive_meta_storage
11
+
12
+ # Re-export import services
13
+ from .report_import_service import ReportImportService
14
+ from .video_import_service import VideoImportService
15
+
16
+ # Public API
17
+ __all__ = [
18
+ "file_lock",
19
+ "create_report_file",
20
+ "create_video_file",
21
+ "sensitive_meta_storage",
22
+ "ReportImportService",
23
+ "VideoImportService",
24
+ "ImportContext",
25
+ "validate_directories",
26
+ "default_sensitive_meta"
27
+ ]
@@ -0,0 +1,7 @@
1
+ from .file_lock import file_lock
2
+ from .import_context import ImportContext
3
+
4
+ __all__ = [
5
+ "file_lock",
6
+ "ImportContext",
7
+ ]
@@ -0,0 +1,81 @@
1
+ # endoreg_db/import_files/processing/create_sensitive_meta.py
2
+
3
+ import os
4
+ import logging
5
+ from datetime import date
6
+ from typing import Optional, Union
7
+
8
+ from endoreg_db.models.media import RawPdfFile, VideoFile
9
+ from endoreg_db.models.metadata.sensitive_meta import SensitiveMeta # adjust path
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ DEFAULT_PATIENT_FIRST_NAME = "unknown"
14
+ DEFAULT_PATIENT_LAST_NAME = "unknown"
15
+ DEFAULT_CENTER_NAME = "endoreg_db_demo"
16
+ # DEFAULT_PATIENT_DOB can be a fixed date or None to let logic.generate_random_dob handle it
17
+ DEFAULT_PATIENT_DOB = date(1970, 1, 1)
18
+
19
+
20
+ def default_sensitive_meta(instance: Union[RawPdfFile, VideoFile]) -> SensitiveMeta | None:
21
+ """
22
+ Ensure the given instance has a minimal SensitiveMeta attached.
23
+
24
+ Called after text extraction + merging; only creates meta if none exists.
25
+ """
26
+ if instance is None:
27
+ logger.warning(
28
+ "No instance available for ensuring default patient data"
29
+ )
30
+ return
31
+
32
+
33
+ if instance.sensitive_meta:
34
+ # Already has meta; nothing to do
35
+ return
36
+
37
+ logger.info(
38
+ "No SensitiveMeta found for report %s, creating default",
39
+ getattr(instance, "pdf_hash", instance.pk),
40
+ )
41
+ if not isinstance(instance.center.name, str):
42
+ try:
43
+ center_name = os.environ.get("DEFAULT_CENTER_NAME")
44
+ assert center_name is not None
45
+ instance.center.name = center_name
46
+ except AssertionError as e:
47
+ logger.debug(f"{e}Center name is not set! You can set it in .env under DEFAULT_CENTER_NAME using default from default_sensitive_meta")
48
+ instance.center.name = DEFAULT_CENTER_NAME
49
+ instance.center.get_by_name(DEFAULT_CENTER_NAME)
50
+
51
+ default_data = {
52
+ "patient_first_name": DEFAULT_PATIENT_FIRST_NAME,
53
+ "patient_last_name": DEFAULT_PATIENT_LAST_NAME,
54
+ "patient_dob": DEFAULT_PATIENT_DOB,
55
+ "examination_date": date.today(),
56
+ "center_name": (
57
+ instance.center.name
58
+ if getattr(instance, "center", None) is not None
59
+ else DEFAULT_CENTER_NAME
60
+ ),
61
+ # optional: link file_path for debugging/tracing
62
+ "file_path": str(instance.file_path) if getattr(instance, "file_path", None) else None,
63
+ }
64
+
65
+ try:
66
+ meta = SensitiveMeta.create_from_dict(default_data)
67
+ instance.sensitive_meta = meta
68
+ instance.save(update_fields=["sensitive_meta"])
69
+ logger.info(
70
+ "Created default SensitiveMeta for report %s",
71
+ getattr(instance, "pdf_hash", instance.pk),
72
+ )
73
+ return meta
74
+ except Exception as e:
75
+ logger.error(
76
+ "Failed to create default SensitiveMeta for report %s: %s",
77
+ getattr(instance, "pdf_hash", instance.pk),
78
+ e,
79
+ )
80
+ return None
81
+
@@ -0,0 +1,17 @@
1
+ from typing import Union, Optional
2
+ import os
3
+
4
+ from endoreg_db.models import Center
5
+ from endoreg_db.models.media import RawPdfFile, VideoFile
6
+
7
+
8
+ def ensure_center(instance: Union[RawPdfFile, VideoFile], center: Optional[str]) -> Center:
9
+ if not isinstance(instance.center, Center):
10
+ raise AssertionError
11
+ if not isinstance(instance.center.name, str):
12
+ raise AssertionError
13
+ assert isinstance(instance.center.get_by_name(center), Center)
14
+ if not instance.center.get_by_name(center).name ==instance.center.name:
15
+ raise AssertionError
16
+ return instance.center
17
+
@@ -0,0 +1,66 @@
1
+ from contextlib import contextmanager
2
+ from pathlib import Path
3
+ import os
4
+ import time
5
+ from logging import getLogger
6
+ import errno
7
+ import shutil
8
+ from typing import Generator, Any
9
+
10
+ logger = getLogger(__name__)
11
+
12
+ STALE_LOCK_SECONDS = 6000
13
+ MAX_LOCK_WAIT_SECONDS = 90
14
+
15
+
16
+ @contextmanager
17
+ def file_lock(path: Path) -> Generator[None, Any, None]:
18
+ """
19
+ Create a file lock to prevent duplicate processing of the same file.
20
+
21
+ Lock is created *next to* the source file: "<path>.lock".
22
+ """
23
+ lock_path = Path(str(path) + ".lock")
24
+ fd = None
25
+ try:
26
+ deadline = time.time() + MAX_LOCK_WAIT_SECONDS
27
+ while True:
28
+ try:
29
+ fd = os.open(lock_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o644)
30
+ break
31
+ except FileExistsError:
32
+ age = None
33
+ try:
34
+ st = os.stat(lock_path)
35
+ age = time.time() - st.st_mtime
36
+ except FileNotFoundError:
37
+ age = None
38
+
39
+ if age is not None and age > STALE_LOCK_SECONDS:
40
+ try:
41
+ logger.warning(
42
+ "Stale lock detected for %s (age %.0fs). Reclaiming lock...",
43
+ path,
44
+ age,
45
+ )
46
+ lock_path.unlink()
47
+ except Exception as e:
48
+ logger.warning("Failed to remove stale lock %s: %s", lock_path, e)
49
+ continue
50
+
51
+ if time.time() >= deadline:
52
+ raise ValueError(f"File already being processed: {path}")
53
+ time.sleep(1.0)
54
+
55
+ os.write(fd, b"lock")
56
+ os.close(fd)
57
+ fd = None
58
+ yield
59
+ finally:
60
+ try:
61
+ if fd is not None:
62
+ os.close(fd)
63
+ if lock_path.exists():
64
+ lock_path.unlink()
65
+ except OSError:
66
+ pass
@@ -0,0 +1,43 @@
1
+ from dataclasses import dataclass, field
2
+ from pathlib import Path
3
+ from typing import Optional, Dict, Any, Union
4
+
5
+ from lx_anonymizer.sensitive_meta_interface import SensitiveMeta
6
+ from endoreg_db.models.media import RawPdfFile, VideoFile
7
+
8
+
9
+ @dataclass
10
+ class ImportContext:
11
+ """
12
+ Tracking the import success and reasons of failure.
13
+ """
14
+
15
+ # core import parameters
16
+ file_path: Path
17
+ center_name: str
18
+ processor_name: str = "olympus-cv-500"
19
+ delete_source: bool = True
20
+ retry: bool = False
21
+ import_completed: bool = False
22
+ error_reason: str = ""
23
+
24
+ # paths
25
+ original_path: Optional[Path] = None
26
+ quarantine_path: Optional[Path] = None
27
+ sensitive_path: Optional[Path] = None
28
+ anonymized_path: Optional[Path] = None
29
+
30
+ # associated objects
31
+ current_report: Optional[RawPdfFile] = None
32
+ current_video: Optional[VideoFile] = None
33
+ current_meta: Optional[SensitiveMeta] = None
34
+ instance: Optional[Union[RawPdfFile, VideoFile]] = None
35
+
36
+ file_type: str = "undefined"
37
+
38
+
39
+ # processing metadata
40
+ file_hash: str = ""
41
+ original_text: Optional[str] = None
42
+ anonymized_text: Optional[str] = None
43
+ extracted_metadata: Dict[str, Any] = field(default_factory=dict)