endoreg-db 0.8.9.2__py3-none-any.whl → 0.8.9.10__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 (450) hide show
  1. endoreg_db/admin.py +10 -5
  2. endoreg_db/apps.py +4 -7
  3. endoreg_db/authz/auth.py +1 -0
  4. endoreg_db/authz/backends.py +1 -1
  5. endoreg_db/authz/management/commands/list_routes.py +2 -0
  6. endoreg_db/authz/middleware.py +8 -7
  7. endoreg_db/authz/permissions.py +21 -10
  8. endoreg_db/authz/policy.py +14 -19
  9. endoreg_db/authz/views_auth.py +14 -10
  10. endoreg_db/codemods/rename_datetime_fields.py +8 -1
  11. endoreg_db/exceptions.py +5 -2
  12. endoreg_db/forms/__init__.py +0 -1
  13. endoreg_db/forms/examination_form.py +4 -3
  14. endoreg_db/forms/patient_finding_intervention_form.py +30 -8
  15. endoreg_db/forms/patient_form.py +9 -13
  16. endoreg_db/forms/questionnaires/__init__.py +1 -1
  17. endoreg_db/forms/settings/__init__.py +4 -1
  18. endoreg_db/forms/unit.py +2 -1
  19. endoreg_db/helpers/count_db.py +17 -14
  20. endoreg_db/helpers/default_objects.py +2 -1
  21. endoreg_db/helpers/download_segmentation_model.py +4 -3
  22. endoreg_db/helpers/interact.py +0 -5
  23. endoreg_db/helpers/test_video_helper.py +33 -25
  24. endoreg_db/import_files/__init__.py +1 -1
  25. endoreg_db/import_files/context/__init__.py +1 -1
  26. endoreg_db/import_files/context/default_sensitive_meta.py +11 -9
  27. endoreg_db/import_files/context/ensure_center.py +4 -4
  28. endoreg_db/import_files/context/file_lock.py +3 -3
  29. endoreg_db/import_files/context/import_context.py +11 -12
  30. endoreg_db/import_files/context/validate_directories.py +1 -0
  31. endoreg_db/import_files/file_storage/create_report_file.py +57 -34
  32. endoreg_db/import_files/file_storage/create_video_file.py +64 -35
  33. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +5 -2
  34. endoreg_db/import_files/file_storage/state_management.py +89 -122
  35. endoreg_db/import_files/file_storage/storage.py +5 -1
  36. endoreg_db/import_files/processing/report_processing/report_anonymization.py +24 -19
  37. endoreg_db/import_files/processing/sensitive_meta_adapter.py +3 -3
  38. endoreg_db/import_files/processing/video_processing/video_anonymization.py +18 -18
  39. endoreg_db/import_files/pseudonymization/k_anonymity.py +8 -9
  40. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +16 -5
  41. endoreg_db/import_files/report_import_service.py +36 -30
  42. endoreg_db/import_files/video_import_service.py +27 -23
  43. endoreg_db/logger_conf.py +56 -40
  44. endoreg_db/management/__init__.py +1 -1
  45. endoreg_db/management/commands/__init__.py +1 -1
  46. endoreg_db/management/commands/check_auth.py +45 -38
  47. endoreg_db/management/commands/create_model_meta_from_huggingface.py +53 -2
  48. endoreg_db/management/commands/create_multilabel_model_meta.py +54 -19
  49. endoreg_db/management/commands/fix_missing_patient_data.py +105 -71
  50. endoreg_db/management/commands/fix_video_paths.py +75 -54
  51. endoreg_db/management/commands/import_report.py +1 -3
  52. endoreg_db/management/commands/list_routes.py +2 -0
  53. endoreg_db/management/commands/load_ai_model_data.py +8 -2
  54. endoreg_db/management/commands/load_ai_model_label_data.py +0 -1
  55. endoreg_db/management/commands/load_center_data.py +3 -3
  56. endoreg_db/management/commands/load_distribution_data.py +35 -38
  57. endoreg_db/management/commands/load_endoscope_data.py +0 -3
  58. endoreg_db/management/commands/load_examination_data.py +20 -4
  59. endoreg_db/management/commands/load_finding_data.py +18 -3
  60. endoreg_db/management/commands/load_gender_data.py +17 -24
  61. endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +95 -85
  62. endoreg_db/management/commands/load_information_source.py +0 -3
  63. endoreg_db/management/commands/load_lab_value_data.py +14 -3
  64. endoreg_db/management/commands/load_legacy_data.py +303 -0
  65. endoreg_db/management/commands/load_name_data.py +1 -2
  66. endoreg_db/management/commands/load_pdf_type_data.py +4 -8
  67. endoreg_db/management/commands/load_profession_data.py +0 -1
  68. endoreg_db/management/commands/load_report_reader_flag_data.py +0 -4
  69. endoreg_db/management/commands/load_requirement_data.py +6 -2
  70. endoreg_db/management/commands/load_unit_data.py +0 -4
  71. endoreg_db/management/commands/load_user_groups.py +5 -7
  72. endoreg_db/management/commands/model_input.py +169 -0
  73. endoreg_db/management/commands/register_ai_model.py +22 -16
  74. endoreg_db/management/commands/setup_endoreg_db.py +110 -32
  75. endoreg_db/management/commands/storage_management.py +14 -8
  76. endoreg_db/management/commands/summarize_db_content.py +154 -63
  77. endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
  78. endoreg_db/management/commands/validate_video_files.py +82 -50
  79. endoreg_db/management/commands/video_validation.py +4 -6
  80. endoreg_db/migrations/0001_initial.py +112 -63
  81. endoreg_db/models/__init__.py +8 -0
  82. endoreg_db/models/administration/ai/active_model.py +5 -5
  83. endoreg_db/models/administration/ai/ai_model.py +41 -18
  84. endoreg_db/models/administration/ai/model_type.py +1 -0
  85. endoreg_db/models/administration/case/case.py +22 -22
  86. endoreg_db/models/administration/center/__init__.py +5 -5
  87. endoreg_db/models/administration/center/center.py +6 -2
  88. endoreg_db/models/administration/center/center_resource.py +18 -4
  89. endoreg_db/models/administration/center/center_shift.py +3 -1
  90. endoreg_db/models/administration/center/center_waste.py +6 -2
  91. endoreg_db/models/administration/person/__init__.py +1 -1
  92. endoreg_db/models/administration/person/employee/__init__.py +1 -1
  93. endoreg_db/models/administration/person/employee/employee_type.py +3 -1
  94. endoreg_db/models/administration/person/examiner/__init__.py +1 -1
  95. endoreg_db/models/administration/person/examiner/examiner.py +10 -2
  96. endoreg_db/models/administration/person/names/first_name.py +6 -4
  97. endoreg_db/models/administration/person/names/last_name.py +4 -3
  98. endoreg_db/models/administration/person/patient/__init__.py +1 -1
  99. endoreg_db/models/administration/person/patient/patient.py +0 -1
  100. endoreg_db/models/administration/person/patient/patient_external_id.py +0 -1
  101. endoreg_db/models/administration/person/person.py +1 -1
  102. endoreg_db/models/administration/product/__init__.py +7 -6
  103. endoreg_db/models/administration/product/product.py +6 -2
  104. endoreg_db/models/administration/product/product_group.py +9 -7
  105. endoreg_db/models/administration/product/product_material.py +9 -2
  106. endoreg_db/models/administration/product/reference_product.py +64 -15
  107. endoreg_db/models/administration/qualification/qualification.py +3 -1
  108. endoreg_db/models/administration/shift/shift.py +3 -1
  109. endoreg_db/models/administration/shift/shift_type.py +12 -4
  110. endoreg_db/models/aidataset/__init__.py +5 -0
  111. endoreg_db/models/aidataset/aidataset.py +193 -0
  112. endoreg_db/models/label/__init__.py +1 -1
  113. endoreg_db/models/label/label.py +10 -2
  114. endoreg_db/models/label/label_set.py +3 -1
  115. endoreg_db/models/label/label_video_segment/_create_from_video.py +6 -2
  116. endoreg_db/models/label/label_video_segment/label_video_segment.py +148 -44
  117. endoreg_db/models/media/__init__.py +12 -5
  118. endoreg_db/models/media/frame/__init__.py +1 -1
  119. endoreg_db/models/media/frame/frame.py +34 -8
  120. endoreg_db/models/media/pdf/__init__.py +2 -1
  121. endoreg_db/models/media/pdf/raw_pdf.py +11 -4
  122. endoreg_db/models/media/pdf/report_file.py +6 -2
  123. endoreg_db/models/media/pdf/report_reader/__init__.py +3 -3
  124. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +15 -5
  125. endoreg_db/models/media/video/create_from_file.py +20 -41
  126. endoreg_db/models/media/video/pipe_1.py +75 -30
  127. endoreg_db/models/media/video/pipe_2.py +37 -12
  128. endoreg_db/models/media/video/video_file.py +36 -24
  129. endoreg_db/models/media/video/video_file_ai.py +235 -70
  130. endoreg_db/models/media/video/video_file_anonymize.py +240 -65
  131. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -1
  132. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +3 -1
  133. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +30 -9
  134. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +95 -29
  135. endoreg_db/models/media/video/video_file_frames/_get_frame.py +13 -3
  136. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -1
  137. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +15 -3
  138. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +15 -3
  139. endoreg_db/models/media/video/video_file_frames/_get_frames.py +7 -2
  140. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +109 -23
  141. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +111 -27
  142. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +46 -13
  143. endoreg_db/models/media/video/video_file_io.py +85 -33
  144. endoreg_db/models/media/video/video_file_meta/__init__.py +6 -6
  145. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +17 -4
  146. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +28 -7
  147. endoreg_db/models/media/video/video_file_meta/get_fps.py +46 -13
  148. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +81 -20
  149. endoreg_db/models/media/video/video_file_meta/text_meta.py +61 -20
  150. endoreg_db/models/media/video/video_file_meta/video_meta.py +40 -12
  151. endoreg_db/models/media/video/video_file_segments.py +118 -27
  152. endoreg_db/models/media/video/video_metadata.py +25 -6
  153. endoreg_db/models/media/video/video_processing.py +54 -15
  154. endoreg_db/models/medical/__init__.py +3 -13
  155. endoreg_db/models/medical/contraindication/__init__.py +3 -1
  156. endoreg_db/models/medical/disease.py +18 -6
  157. endoreg_db/models/medical/event.py +6 -2
  158. endoreg_db/models/medical/examination/__init__.py +5 -1
  159. endoreg_db/models/medical/examination/examination.py +22 -6
  160. endoreg_db/models/medical/examination/examination_indication.py +23 -7
  161. endoreg_db/models/medical/examination/examination_time.py +6 -2
  162. endoreg_db/models/medical/finding/__init__.py +3 -1
  163. endoreg_db/models/medical/finding/finding.py +37 -12
  164. endoreg_db/models/medical/finding/finding_classification.py +27 -8
  165. endoreg_db/models/medical/finding/finding_intervention.py +19 -6
  166. endoreg_db/models/medical/finding/finding_type.py +3 -1
  167. endoreg_db/models/medical/hardware/__init__.py +1 -1
  168. endoreg_db/models/medical/hardware/endoscope.py +14 -2
  169. endoreg_db/models/medical/laboratory/__init__.py +1 -1
  170. endoreg_db/models/medical/laboratory/lab_value.py +139 -39
  171. endoreg_db/models/medical/medication/__init__.py +7 -3
  172. endoreg_db/models/medical/medication/medication.py +3 -1
  173. endoreg_db/models/medical/medication/medication_indication.py +3 -1
  174. endoreg_db/models/medical/medication/medication_indication_type.py +11 -3
  175. endoreg_db/models/medical/medication/medication_intake_time.py +3 -1
  176. endoreg_db/models/medical/medication/medication_schedule.py +3 -1
  177. endoreg_db/models/medical/patient/__init__.py +2 -10
  178. endoreg_db/models/medical/patient/medication_examples.py +3 -14
  179. endoreg_db/models/medical/patient/patient_disease.py +17 -5
  180. endoreg_db/models/medical/patient/patient_event.py +12 -4
  181. endoreg_db/models/medical/patient/patient_examination.py +52 -15
  182. endoreg_db/models/medical/patient/patient_examination_indication.py +15 -4
  183. endoreg_db/models/medical/patient/patient_finding.py +105 -29
  184. endoreg_db/models/medical/patient/patient_finding_classification.py +41 -12
  185. endoreg_db/models/medical/patient/patient_finding_intervention.py +11 -3
  186. endoreg_db/models/medical/patient/patient_lab_sample.py +6 -2
  187. endoreg_db/models/medical/patient/patient_lab_value.py +42 -10
  188. endoreg_db/models/medical/patient/patient_medication.py +25 -7
  189. endoreg_db/models/medical/patient/patient_medication_schedule.py +34 -10
  190. endoreg_db/models/metadata/model_meta.py +40 -12
  191. endoreg_db/models/metadata/model_meta_logic.py +51 -16
  192. endoreg_db/models/metadata/sensitive_meta.py +65 -28
  193. endoreg_db/models/metadata/sensitive_meta_logic.py +28 -26
  194. endoreg_db/models/metadata/video_meta.py +146 -39
  195. endoreg_db/models/metadata/video_prediction_logic.py +70 -21
  196. endoreg_db/models/metadata/video_prediction_meta.py +80 -27
  197. endoreg_db/models/operation_log.py +63 -0
  198. endoreg_db/models/other/__init__.py +10 -10
  199. endoreg_db/models/other/distribution/__init__.py +9 -7
  200. endoreg_db/models/other/distribution/base_value_distribution.py +3 -1
  201. endoreg_db/models/other/distribution/date_value_distribution.py +19 -5
  202. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +3 -1
  203. endoreg_db/models/other/distribution/numeric_value_distribution.py +34 -9
  204. endoreg_db/models/other/emission/__init__.py +1 -1
  205. endoreg_db/models/other/emission/emission_factor.py +9 -3
  206. endoreg_db/models/other/information_source.py +15 -5
  207. endoreg_db/models/other/material.py +3 -1
  208. endoreg_db/models/other/transport_route.py +3 -1
  209. endoreg_db/models/other/unit.py +6 -2
  210. endoreg_db/models/report/report.py +0 -1
  211. endoreg_db/models/requirement/requirement.py +84 -27
  212. endoreg_db/models/requirement/requirement_error.py +5 -6
  213. endoreg_db/models/requirement/requirement_evaluation/__init__.py +1 -1
  214. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +8 -8
  215. endoreg_db/models/requirement/requirement_evaluation/get_values.py +3 -3
  216. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +24 -8
  217. endoreg_db/models/requirement/requirement_operator.py +28 -8
  218. endoreg_db/models/requirement/requirement_set.py +34 -11
  219. endoreg_db/models/state/__init__.py +1 -0
  220. endoreg_db/models/state/audit_ledger.py +9 -2
  221. endoreg_db/models/{media → state}/processing_history/__init__.py +1 -3
  222. endoreg_db/models/state/processing_history/processing_history.py +136 -0
  223. endoreg_db/models/state/raw_pdf.py +0 -1
  224. endoreg_db/models/state/video.py +2 -4
  225. endoreg_db/models/utils.py +4 -2
  226. endoreg_db/queries/__init__.py +2 -6
  227. endoreg_db/queries/annotations/__init__.py +1 -3
  228. endoreg_db/queries/annotations/legacy.py +37 -26
  229. endoreg_db/root_urls.py +3 -4
  230. endoreg_db/schemas/examination_evaluation.py +3 -0
  231. endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +249 -163
  232. endoreg_db/serializers/__init__.py +2 -8
  233. endoreg_db/serializers/administration/__init__.py +1 -2
  234. endoreg_db/serializers/administration/ai/__init__.py +0 -1
  235. endoreg_db/serializers/administration/ai/active_model.py +3 -1
  236. endoreg_db/serializers/administration/ai/ai_model.py +5 -3
  237. endoreg_db/serializers/administration/ai/model_type.py +3 -1
  238. endoreg_db/serializers/administration/center.py +7 -2
  239. endoreg_db/serializers/administration/gender.py +4 -2
  240. endoreg_db/serializers/anonymization.py +13 -13
  241. endoreg_db/serializers/evaluation/examination_evaluation.py +0 -1
  242. endoreg_db/serializers/examination/__init__.py +1 -1
  243. endoreg_db/serializers/examination/base.py +12 -13
  244. endoreg_db/serializers/examination/dropdown.py +6 -7
  245. endoreg_db/serializers/examination_serializer.py +3 -6
  246. endoreg_db/serializers/finding/__init__.py +1 -1
  247. endoreg_db/serializers/finding/finding.py +14 -7
  248. endoreg_db/serializers/finding_classification/__init__.py +3 -3
  249. endoreg_db/serializers/finding_classification/choice.py +3 -3
  250. endoreg_db/serializers/finding_classification/classification.py +2 -4
  251. endoreg_db/serializers/label_video_segment/__init__.py +5 -3
  252. endoreg_db/serializers/{label → label_video_segment}/image_classification_annotation.py +5 -5
  253. endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
  254. endoreg_db/serializers/{label → label_video_segment/label}/label.py +1 -1
  255. endoreg_db/serializers/label_video_segment/label_video_segment.py +338 -228
  256. endoreg_db/serializers/meta/__init__.py +1 -2
  257. endoreg_db/serializers/meta/sensitive_meta_detail.py +28 -13
  258. endoreg_db/serializers/meta/sensitive_meta_update.py +51 -46
  259. endoreg_db/serializers/meta/sensitive_meta_verification.py +19 -16
  260. endoreg_db/serializers/misc/__init__.py +2 -2
  261. endoreg_db/serializers/misc/file_overview.py +11 -7
  262. endoreg_db/serializers/misc/stats.py +10 -8
  263. endoreg_db/serializers/misc/translatable_field_mix_in.py +6 -6
  264. endoreg_db/serializers/misc/upload_job.py +32 -29
  265. endoreg_db/serializers/patient/__init__.py +2 -1
  266. endoreg_db/serializers/patient/patient.py +32 -15
  267. endoreg_db/serializers/patient/patient_dropdown.py +11 -3
  268. endoreg_db/serializers/patient_examination/__init__.py +1 -1
  269. endoreg_db/serializers/patient_examination/patient_examination.py +67 -40
  270. endoreg_db/serializers/patient_finding/__init__.py +1 -1
  271. endoreg_db/serializers/patient_finding/patient_finding.py +2 -1
  272. endoreg_db/serializers/patient_finding/patient_finding_classification.py +17 -9
  273. endoreg_db/serializers/patient_finding/patient_finding_detail.py +26 -17
  274. endoreg_db/serializers/patient_finding/patient_finding_intervention.py +7 -5
  275. endoreg_db/serializers/patient_finding/patient_finding_list.py +10 -11
  276. endoreg_db/serializers/patient_finding/patient_finding_write.py +36 -27
  277. endoreg_db/serializers/pdf/__init__.py +1 -3
  278. endoreg_db/serializers/requirements/requirement_schema.py +1 -6
  279. endoreg_db/serializers/sensitive_meta_serializer.py +100 -81
  280. endoreg_db/serializers/video/__init__.py +2 -2
  281. endoreg_db/serializers/video/{segmentation.py → video_file.py} +66 -47
  282. endoreg_db/serializers/video/video_file_brief.py +6 -2
  283. endoreg_db/serializers/video/video_file_detail.py +36 -23
  284. endoreg_db/serializers/video/video_file_list.py +4 -2
  285. endoreg_db/serializers/video/video_processing_history.py +54 -50
  286. endoreg_db/services/__init__.py +1 -1
  287. endoreg_db/services/anonymization.py +2 -2
  288. endoreg_db/services/examination_evaluation.py +40 -17
  289. endoreg_db/services/model_meta_from_hf.py +76 -0
  290. endoreg_db/services/polling_coordinator.py +101 -70
  291. endoreg_db/services/pseudonym_service.py +27 -22
  292. endoreg_db/services/report_import.py +6 -3
  293. endoreg_db/services/segment_sync.py +75 -59
  294. endoreg_db/services/video_import.py +6 -7
  295. endoreg_db/urls/__init__.py +2 -2
  296. endoreg_db/urls/ai.py +7 -25
  297. endoreg_db/urls/anonymization.py +61 -15
  298. endoreg_db/urls/auth.py +4 -4
  299. endoreg_db/urls/classification.py +4 -9
  300. endoreg_db/urls/examination.py +27 -18
  301. endoreg_db/urls/media.py +27 -34
  302. endoreg_db/urls/patient.py +11 -7
  303. endoreg_db/urls/requirements.py +3 -1
  304. endoreg_db/urls/root_urls.py +2 -3
  305. endoreg_db/urls/stats.py +24 -16
  306. endoreg_db/urls/upload.py +3 -11
  307. endoreg_db/utils/__init__.py +14 -15
  308. endoreg_db/utils/ai/__init__.py +1 -1
  309. endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
  310. endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
  311. endoreg_db/utils/ai/get.py +2 -1
  312. endoreg_db/utils/ai/inference_dataset.py +14 -15
  313. endoreg_db/utils/ai/model_training/config.py +117 -0
  314. endoreg_db/utils/ai/model_training/dataset.py +74 -0
  315. endoreg_db/utils/ai/model_training/losses.py +68 -0
  316. endoreg_db/utils/ai/model_training/metrics.py +78 -0
  317. endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
  318. endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
  319. endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
  320. endoreg_db/utils/ai/multilabel_classification_net.py +21 -6
  321. endoreg_db/utils/ai/predict.py +4 -4
  322. endoreg_db/utils/ai/preprocess.py +19 -11
  323. endoreg_db/utils/calc_duration_seconds.py +4 -4
  324. endoreg_db/utils/case_generator/lab_sample_factory.py +3 -4
  325. endoreg_db/utils/check_video_files.py +74 -47
  326. endoreg_db/utils/cropping.py +10 -9
  327. endoreg_db/utils/dataloader.py +11 -3
  328. endoreg_db/utils/dates.py +3 -4
  329. endoreg_db/utils/defaults/set_default_center.py +7 -6
  330. endoreg_db/utils/env.py +6 -2
  331. endoreg_db/utils/extract_specific_frames.py +24 -9
  332. endoreg_db/utils/file_operations.py +30 -18
  333. endoreg_db/utils/fix_video_path_direct.py +57 -41
  334. endoreg_db/utils/frame_anonymization_utils.py +157 -157
  335. endoreg_db/utils/hashs.py +3 -18
  336. endoreg_db/utils/links/requirement_link.py +96 -52
  337. endoreg_db/utils/ocr.py +30 -25
  338. endoreg_db/utils/operation_log.py +61 -0
  339. endoreg_db/utils/parse_and_generate_yaml.py +12 -13
  340. endoreg_db/utils/paths.py +6 -6
  341. endoreg_db/utils/permissions.py +40 -24
  342. endoreg_db/utils/pipelines/process_video_dir.py +50 -26
  343. endoreg_db/utils/product/sum_emissions.py +5 -3
  344. endoreg_db/utils/product/sum_weights.py +4 -2
  345. endoreg_db/utils/pydantic_models/__init__.py +3 -4
  346. endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +207 -107
  347. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +252 -65
  348. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +27 -10
  349. endoreg_db/utils/setup_config.py +21 -5
  350. endoreg_db/utils/storage.py +3 -1
  351. endoreg_db/utils/translation.py +19 -15
  352. endoreg_db/utils/uuid.py +1 -0
  353. endoreg_db/utils/validate_endo_roi.py +12 -4
  354. endoreg_db/utils/validate_subcategory_dict.py +26 -24
  355. endoreg_db/utils/validate_video_detailed.py +207 -149
  356. endoreg_db/utils/video/__init__.py +7 -3
  357. endoreg_db/utils/video/extract_frames.py +30 -18
  358. endoreg_db/utils/video/names.py +11 -6
  359. endoreg_db/utils/video/streaming_processor.py +175 -101
  360. endoreg_db/utils/video/video_splitter.py +30 -19
  361. endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +59 -50
  362. endoreg_db/views/__init__.py +0 -20
  363. endoreg_db/views/anonymization/__init__.py +6 -2
  364. endoreg_db/views/anonymization/media_management.py +2 -6
  365. endoreg_db/views/anonymization/overview.py +34 -1
  366. endoreg_db/views/anonymization/validate.py +79 -18
  367. endoreg_db/views/auth/__init__.py +1 -1
  368. endoreg_db/views/auth/keycloak.py +16 -14
  369. endoreg_db/views/examination/__init__.py +12 -15
  370. endoreg_db/views/examination/examination.py +5 -5
  371. endoreg_db/views/examination/examination_manifest_cache.py +5 -5
  372. endoreg_db/views/examination/get_finding_classification_choices.py +8 -5
  373. endoreg_db/views/examination/get_finding_classifications.py +9 -7
  374. endoreg_db/views/examination/get_findings.py +8 -10
  375. endoreg_db/views/examination/get_instruments.py +3 -2
  376. endoreg_db/views/examination/get_interventions.py +1 -1
  377. endoreg_db/views/finding/__init__.py +2 -2
  378. endoreg_db/views/finding/finding.py +58 -54
  379. endoreg_db/views/finding/get_classifications.py +1 -1
  380. endoreg_db/views/finding/get_interventions.py +1 -1
  381. endoreg_db/views/finding_classification/__init__.py +5 -5
  382. endoreg_db/views/finding_classification/finding_classification.py +5 -6
  383. endoreg_db/views/finding_classification/get_classification_choices.py +3 -4
  384. endoreg_db/views/media/__init__.py +13 -13
  385. endoreg_db/views/media/pdf_media.py +9 -9
  386. endoreg_db/views/media/sensitive_metadata.py +10 -7
  387. endoreg_db/views/media/video_media.py +4 -4
  388. endoreg_db/views/meta/__init__.py +1 -1
  389. endoreg_db/views/meta/sensitive_meta_list.py +20 -22
  390. endoreg_db/views/meta/sensitive_meta_verification.py +14 -11
  391. endoreg_db/views/misc/__init__.py +6 -34
  392. endoreg_db/views/misc/center.py +2 -1
  393. endoreg_db/views/misc/csrf.py +2 -1
  394. endoreg_db/views/misc/gender.py +2 -1
  395. endoreg_db/views/misc/stats.py +141 -106
  396. endoreg_db/views/patient/__init__.py +1 -3
  397. endoreg_db/views/patient/patient.py +141 -99
  398. endoreg_db/views/patient_examination/__init__.py +5 -5
  399. endoreg_db/views/patient_examination/patient_examination.py +43 -42
  400. endoreg_db/views/patient_examination/patient_examination_create.py +10 -15
  401. endoreg_db/views/patient_examination/patient_examination_detail.py +12 -15
  402. endoreg_db/views/patient_examination/patient_examination_list.py +21 -17
  403. endoreg_db/views/patient_examination/video.py +114 -80
  404. endoreg_db/views/patient_finding/__init__.py +1 -1
  405. endoreg_db/views/patient_finding/patient_finding.py +17 -10
  406. endoreg_db/views/patient_finding/patient_finding_optimized.py +127 -95
  407. endoreg_db/views/patient_finding_classification/__init__.py +1 -1
  408. endoreg_db/views/patient_finding_classification/pfc_create.py +35 -27
  409. endoreg_db/views/report/reimport.py +1 -1
  410. endoreg_db/views/report/report_stream.py +5 -8
  411. endoreg_db/views/requirement/__init__.py +2 -1
  412. endoreg_db/views/requirement/evaluate.py +7 -9
  413. endoreg_db/views/requirement/lookup.py +2 -3
  414. endoreg_db/views/requirement/lookup_store.py +0 -1
  415. endoreg_db/views/requirement/requirement_utils.py +2 -4
  416. endoreg_db/views/stats/__init__.py +4 -4
  417. endoreg_db/views/stats/stats_views.py +152 -115
  418. endoreg_db/views/video/__init__.py +18 -27
  419. endoreg_db/views/{ai → video/ai}/__init__.py +2 -2
  420. endoreg_db/views/{ai → video/ai}/label.py +20 -16
  421. endoreg_db/views/video/correction.py +5 -6
  422. endoreg_db/views/video/reimport.py +134 -99
  423. endoreg_db/views/video/segments_crud.py +134 -44
  424. endoreg_db/views/video/video_apply_mask.py +13 -12
  425. endoreg_db/views/video/video_correction.py +2 -1
  426. endoreg_db/views/video/video_download_processed.py +15 -15
  427. endoreg_db/views/video/video_meta_stats.py +7 -6
  428. endoreg_db/views/video/video_processing_history.py +3 -2
  429. endoreg_db/views/video/video_remove_frames.py +13 -12
  430. endoreg_db/views/video/video_stream.py +110 -82
  431. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
  432. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +434 -431
  433. endoreg_db/management/commands/import_fallback_video.py +0 -203
  434. endoreg_db/management/commands/import_video.py +0 -422
  435. endoreg_db/management/commands/import_video_with_classification.py +0 -367
  436. endoreg_db/models/media/processing_history/processing_history.py +0 -96
  437. endoreg_db/serializers/label/__init__.py +0 -7
  438. endoreg_db/serializers/label_video_segment/_lvs_create.py +0 -149
  439. endoreg_db/serializers/label_video_segment/_lvs_update.py +0 -138
  440. endoreg_db/serializers/label_video_segment/_lvs_validate.py +0 -149
  441. endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +0 -99
  442. endoreg_db/serializers/label_video_segment/label_video_segment_update.py +0 -163
  443. endoreg_db/services/__old/pdf_import.py +0 -1487
  444. endoreg_db/services/__old/video_import.py +0 -1306
  445. endoreg_db/tasks/upload_tasks.py +0 -216
  446. endoreg_db/tasks/video_ingest.py +0 -161
  447. endoreg_db/tasks/video_processing_tasks.py +0 -327
  448. endoreg_db/views/misc/translation.py +0 -182
  449. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
  450. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
endoreg_db/admin.py CHANGED
@@ -11,6 +11,7 @@ from endoreg_db.models import (
11
11
  FindingIntervention, # Import Finding Interventions
12
12
  PatientFindingIntervention,
13
13
  )
14
+
14
15
  # from endoreg_db.forms.patient_finding_intervention_form import (
15
16
  # PatientFindingInterventionForm,
16
17
  # )
@@ -29,7 +30,7 @@ class PatientAdmin(admin.ModelAdmin):
29
30
  @admin.register(Examination)
30
31
  class ExaminationAdmin(admin.ModelAdmin):
31
32
  list_display = ("id", "name")
32
- search_fields = ("name", )
33
+ search_fields = ("name",)
33
34
  list_filter = ("name",)
34
35
  ordering = ("name",)
35
36
 
@@ -45,9 +46,13 @@ class PatientFindingInterventionAdmin(admin.ModelAdmin):
45
46
  "patients": Patient.objects.all(),
46
47
  "examinations": Examination.objects.all(),
47
48
  "findings": Finding.objects.all(),
48
- "locations": FindingClassification.objects.filter(classification_types__name__iexact="location"),
49
+ "locations": FindingClassification.objects.filter(
50
+ classification_types__name__iexact="location"
51
+ ),
49
52
  "location_choices": FindingClassificationChoice.objects.none(),
50
- "morphologies": FindingClassification.objects.filter(classification_types__name__iexact="morphology"),
53
+ "morphologies": FindingClassification.objects.filter(
54
+ classification_types__name__iexact="morphology"
55
+ ),
51
56
  "morphology_choices": FindingClassificationChoice.objects.none(),
52
57
  "finding_interventions": FindingIntervention.objects.all(),
53
58
  }
@@ -56,7 +61,7 @@ class PatientFindingInterventionAdmin(admin.ModelAdmin):
56
61
  def get_location_choices_json(self, request):
57
62
  """
58
63
  Handles AJAX requests to retrieve location classification choices as JSON.
59
-
64
+
60
65
  Expects a "location" parameter in the GET request and returns a list of matching FindingClassificationChoice objects with their IDs and names. Returns an error message with appropriate HTTP status if the parameter is missing or an exception occurs.
61
66
  """
62
67
  location_id = request.GET.get("location")
@@ -67,7 +72,7 @@ class PatientFindingInterventionAdmin(admin.ModelAdmin):
67
72
  choices = list(
68
73
  FindingClassificationChoice.objects.filter(
69
74
  classifications__id=location_id,
70
- classifications__classification_types__name__iexact="location"
75
+ classifications__classification_types__name__iexact="location",
71
76
  ).values("id", "name")
72
77
  )
73
78
  if not choices:
endoreg_db/apps.py CHANGED
@@ -2,17 +2,14 @@ from django.apps import AppConfig
2
2
 
3
3
 
4
4
  class EndoregDbConfig(AppConfig):
5
- default_auto_field = 'django.db.models.BigAutoField'
6
- name = 'endoreg_db'
7
-
5
+ default_auto_field = "django.db.models.BigAutoField"
6
+ name = "endoreg_db"
7
+
8
8
  def ready(self):
9
9
  """
10
10
  Performs application startup tasks when the Django app is fully loaded.
11
-
11
+
12
12
  This method imports media-related model modules to ensure they are registered
13
13
  and ready for use when the application starts.
14
14
  """
15
- import endoreg_db.models.media.video
16
- import endoreg_db.models.media.frame
17
- import endoreg_db.models.media.pdf
18
15
  pass
endoreg_db/authz/auth.py CHANGED
@@ -8,6 +8,7 @@ from rest_framework import authentication, exceptions
8
8
 
9
9
  User = get_user_model()
10
10
 
11
+
11
12
  class KeycloakJWTAuthentication(authentication.BaseAuthentication):
12
13
  """
13
14
  Verifies Bearer JWTs against Keycloak JWKS.
@@ -115,7 +115,7 @@ class KeycloakOIDCBackend(OIDCAuthenticationBackend):
115
115
  # Keep user profile in sync with IdP data (safe truncation to field max length)
116
116
  user.email = claims.get("email", user.email)
117
117
  user.first_name = (claims.get("given_name") or user.first_name)[:150]
118
- user.last_name = (claims.get("family_name") or user.last_name)[:150]
118
+ user.last_name = (claims.get("family_name") or user.last_name)[:150]
119
119
  user.save(update_fields=["email", "first_name", "last_name"])
120
120
 
121
121
  # Keep roles (groups) in sync on every login
@@ -1,6 +1,7 @@
1
1
  from django.core.management.base import BaseCommand
2
2
  from django.urls import get_resolver, URLPattern, URLResolver
3
3
 
4
+
4
5
  def iter_patterns(prefix, patterns):
5
6
  for p in patterns:
6
7
  if isinstance(p, URLPattern):
@@ -8,6 +9,7 @@ def iter_patterns(prefix, patterns):
8
9
  elif isinstance(p, URLResolver):
9
10
  yield from iter_patterns(prefix, p.url_patterns)
10
11
 
12
+
11
13
  class Command(BaseCommand):
12
14
  help = "List all URL names (useful to fill policy.py)"
13
15
 
@@ -20,13 +20,11 @@
20
20
  # though using a relative path from request.get_full_path() is already safe.
21
21
 
22
22
  from django.shortcuts import redirect
23
- from django.conf import settings
24
- from urllib.parse import urlencode
25
23
 
26
24
  # Any URL path that starts with one of these prefixes is considered "protected" for browser UX.
27
25
  # You can add more prefixes if you want the same login-redirect behavior elsewhere
28
26
  # (e.g., PROTECTED_PREFIXES = ("/api/", "/reports/", "/dashboard/")).
29
- #PROTECTED_PREFIXES = ("/api/",)
27
+ # PROTECTED_PREFIXES = ("/api/",)
30
28
 
31
29
  # Protect the SPA shell too (everything except static/assets/oidc)
32
30
  PROTECTED_PREFIXES = ("/",) # catch-all; we'll skip known public paths below
@@ -36,10 +34,11 @@ PUBLIC_PREFIXES = (
36
34
  "/assets/",
37
35
  "/media/",
38
36
  "/favicon.ico",
39
- "/oidc/", # OIDC endpoints must stay public
40
- "/__vite", # if Vite dev assets ever used
37
+ "/oidc/", # OIDC endpoints must stay public
38
+ "/__vite", # if Vite dev assets ever used
41
39
  )
42
40
 
41
+
43
42
  class LoginRequiredForAPIsMiddleware:
44
43
  """
45
44
  For browser traffic:
@@ -51,7 +50,8 @@ class LoginRequiredForAPIsMiddleware:
51
50
 
52
51
  """
53
52
 
54
- def __init__(self, get_response): self.get_response = get_response
53
+ def __init__(self, get_response):
54
+ self.get_response = get_response
55
55
 
56
56
  def __call__(self, request):
57
57
  # request.path is the URL path without scheme/host/query (e.g., "/api/patients/").
@@ -76,8 +76,9 @@ class LoginRequiredForAPIsMiddleware:
76
76
  if not request.user.is_authenticated:
77
77
  from django.conf import settings
78
78
  from urllib.parse import urlencode
79
+
79
80
  params = urlencode({"next": request.get_full_path()})
80
81
  return redirect(f"{settings.LOGIN_URL}?{params}")
81
82
 
82
83
  # 4) Authenticated → pass through
83
- return self.get_response(request)
84
+ return self.get_response(request)
@@ -29,11 +29,12 @@ from rest_framework.permissions import BasePermission
29
29
  from django.contrib.auth.models import AnonymousUser
30
30
  from django.utils.functional import cached_property
31
31
  from endoreg_db.utils.permissions import is_debug_mode
32
- from .policy import REQUIRED_ROLES, DEFAULT_ROLE_BY_METHOD, satisfies, get_needed_role
32
+ from .policy import REQUIRED_ROLES, satisfies, get_needed_role
33
33
  import logging
34
34
 
35
35
  logger = logging.getLogger(__name__)
36
36
 
37
+
37
38
  def _normalized_route_name(request, view) -> str:
38
39
  """
39
40
  Return a stable, de-namespaced route name, e.g. 'patient-list'.
@@ -51,6 +52,7 @@ def _normalized_route_name(request, view) -> str:
51
52
  return url_name
52
53
  return view.__class__.__name__
53
54
 
55
+
54
56
  def _route_name(request, view):
55
57
  """
56
58
  Resolve a stable name for the current endpoint.
@@ -95,8 +97,12 @@ class PolicyPermission(BasePermission):
95
97
 
96
98
  # 1) DEBUG bypass
97
99
  if is_debug_mode():
98
- logger.info("RBAC BYPASS (DEBUG): route=%s method=%s user=%s",
99
- route, method, getattr(getattr(request, "user", None), "username", "anon"))
100
+ logger.info(
101
+ "RBAC BYPASS (DEBUG): route=%s method=%s user=%s",
102
+ route,
103
+ method,
104
+ getattr(getattr(request, "user", None), "username", "anon"),
105
+ )
100
106
  return True
101
107
 
102
108
  # 2) Must be authenticated
@@ -108,11 +114,12 @@ class PolicyPermission(BasePermission):
108
114
  # 3) Determine needed role
109
115
  needed = get_needed_role(route, method)
110
116
  if not needed:
111
- logger.info(
112
- "RBAC DENY (NO ROLE): route=%s method=%s reason=no mapping",
113
- route, method
114
- )
115
- return False
117
+ logger.info(
118
+ "RBAC DENY (NO ROLE): route=%s method=%s reason=no mapping",
119
+ route,
120
+ method,
121
+ )
122
+ return False
116
123
 
117
124
  # 4) Collect roles and decide
118
125
  user_roles = set(user.groups.values_list("name", flat=True))
@@ -120,8 +127,12 @@ class PolicyPermission(BasePermission):
120
127
 
121
128
  logger.info(
122
129
  "RBAC DECISION: route=%s method=%s need=%s user=%s roles=%s => %s",
123
- route, method, needed, getattr(user, "username", "anon"),
124
- sorted(user_roles), "ALLOW" if allowed else "DENY"
130
+ route,
131
+ method,
132
+ needed,
133
+ getattr(user, "username", "anon"),
134
+ sorted(user_roles),
135
+ "ALLOW" if allowed else "DENY",
125
136
  )
126
137
 
127
138
  return allowed
@@ -52,7 +52,7 @@ RESOURCE_ROLES = {
52
52
  "read": "video:read",
53
53
  "write": "video:write",
54
54
  },
55
- #anonymization resource
55
+ # anonymization resource
56
56
  "anonymization": {
57
57
  "read": "anonymization:read",
58
58
  "write": "anonymization:write",
@@ -75,20 +75,15 @@ RESOURCE_ROLES = {
75
75
  # exactly that "name"
76
76
  ROUTE_RESOURCE = {
77
77
  # Patients
78
- "patient-list": "patient", # /api/patients/
79
- "patient-detail": "patient", # /api/patients/{id}/
80
-
78
+ "patient-list": "patient", # /api/patients/
79
+ "patient-detail": "patient", # /api/patients/{id}/
81
80
  # Custom patient helper
82
81
  "check_pe_exist": "patient",
83
-
84
82
  # Example for videos (if you have these ViewSets registered)
85
- "videos-list": "video",
83
+ "videos-list": "video",
86
84
  "videos-detail": "video",
87
-
88
85
  "anonymization_items_overview": "anonymization",
89
86
  # Add more mappings as your API grows
90
-
91
-
92
87
  }
93
88
 
94
89
  # ------------------------------------------------------------
@@ -108,7 +103,6 @@ REQUIRED_ROLES: RouteRoles = {
108
103
  # "patient-detail": {
109
104
  # "DELETE": "admin", # admin role in Keycloak
110
105
  # },
111
-
112
106
  # Example: a special helper route that you always want read-only patients role:
113
107
  # "check_pe_exist": "patient:read",
114
108
  }
@@ -125,21 +119,21 @@ REQUIRED_ROLES: RouteRoles = {
125
119
  # If you move fully to resource-based roles, you can leave this as None
126
120
  # or a generic "data:read"/"data:write" depending on your preference.
127
121
  DEFAULT_ROLE_BY_METHOD = {
128
- "GET": "data:read",
129
- "HEAD": "data:read",
122
+ "GET": "data:read",
123
+ "HEAD": "data:read",
130
124
  "OPTIONS": "data:read",
131
- "POST": "data:write",
132
- "PUT": "data:write",
133
- "PATCH": "data:write",
134
- "DELETE": "data:write",
125
+ "POST": "data:write",
126
+ "PUT": "data:write",
127
+ "PATCH": "data:write",
128
+ "DELETE": "data:write",
135
129
  }
136
130
 
137
131
 
138
-
139
132
  # ------------------------------------------------------------
140
133
  # Role satisfaction rule
141
134
  # ------------------------------------------------------------
142
135
 
136
+
143
137
  def satisfies(user_roles: set[str], needed: str) -> bool:
144
138
  """
145
139
  Return True if user_roles satisfy the needed role.
@@ -160,8 +154,8 @@ def satisfies(user_roles: set[str], needed: str) -> bool:
160
154
  """
161
155
  if not needed:
162
156
  return False
163
-
164
- # Global override: any user with role "endoregdb_user" passes all checks
157
+
158
+ # Global override: any user with role "endoregdb_user" passes all checks
165
159
  if "endoregdb_user" in user_roles:
166
160
  return True
167
161
 
@@ -182,6 +176,7 @@ def satisfies(user_roles: set[str], needed: str) -> bool:
182
176
  # Helper: compute which role is needed for a given route + method
183
177
  # ------------------------------------------------------------
184
178
 
179
+
185
180
  def get_needed_role(route_name: str, method: str) -> str | None:
186
181
  """
187
182
  Compute the required role for a given route + HTTP method.
@@ -4,7 +4,7 @@ from rest_framework.decorators import api_view, permission_classes
4
4
  from rest_framework.permissions import IsAuthenticated
5
5
  from rest_framework.response import Response
6
6
 
7
- from .policy import REQUIRED_ROLES, DEFAULT_ROLE_BY_METHOD, satisfies, get_needed_role
7
+ from .policy import satisfies, get_needed_role
8
8
 
9
9
  # Map frontend page keys → (DRF route name, HTTP method)
10
10
  #
@@ -40,7 +40,7 @@ def auth_bootstrap(request):
40
40
  method = method.upper()
41
41
 
42
42
  # Look up which role is needed for this route/method
43
- #needed = REQUIRED_ROLES.get(route_name) or DEFAULT_ROLE_BY_METHOD.get(method)
43
+ # needed = REQUIRED_ROLES.get(route_name) or DEFAULT_ROLE_BY_METHOD.get(method)
44
44
  needed = get_needed_role(route_name, method)
45
45
 
46
46
  if not needed:
@@ -48,7 +48,9 @@ def auth_bootstrap(request):
48
48
  capabilities[cap_key] = {"read": False, "write": False}
49
49
  continue
50
50
 
51
- allowed = satisfies(roles, needed) # uses your existing rule: write ⇒ read, etc.
51
+ allowed = satisfies(
52
+ roles, needed
53
+ ) # uses your existing rule: write ⇒ read, etc.
52
54
 
53
55
  # For UI pages we usually only care about "read"
54
56
  capabilities[cap_key] = {
@@ -56,11 +58,13 @@ def auth_bootstrap(request):
56
58
  "write": False, # or bool(allowed) if this page allows writes in UI
57
59
  }
58
60
 
59
- return Response({
60
- "user": {
61
- "username": user.username,
61
+ return Response(
62
+ {
63
+ "user": {
64
+ "username": user.username,
65
+ "roles": sorted(roles),
66
+ },
62
67
  "roles": sorted(roles),
63
- },
64
- "roles": sorted(roles),
65
- "capabilities": capabilities,
66
- })
68
+ "capabilities": capabilities,
69
+ }
70
+ )
@@ -1,7 +1,9 @@
1
1
  # endoreg_db/codemods/rename_datetime_fields.py
2
2
  from bowler import Query
3
3
  from pathlib import Path
4
- import argparse, yaml, sys
4
+ import argparse
5
+ import yaml
6
+ import sys
5
7
 
6
8
  # Paths
7
9
  BASE = Path(__file__).resolve().parents[1] # .../endoreg_db
@@ -9,6 +11,7 @@ RENAMES_YML = BASE / "renames.yml"
9
11
  DEFAULT_TARGETS = ["endoreg_db/models"] # safer default
10
12
  EXCLUDE_DIR_NAMES = {"migrations", "__pycache__"}
11
13
 
14
+
12
15
  def load_renames():
13
16
  if not RENAMES_YML.exists():
14
17
  print(f"ERROR: renames.yml not found at {RENAMES_YML}", file=sys.stderr)
@@ -19,6 +22,7 @@ def load_renames():
19
22
  sys.exit(2)
20
23
  return data
21
24
 
25
+
22
26
  def iter_python_targets(paths):
23
27
  """Yield *.py files under given paths, excluding migrations and caches."""
24
28
  for p in map(Path, paths):
@@ -31,10 +35,12 @@ def iter_python_targets(paths):
31
35
  continue
32
36
  yield str(f)
33
37
 
38
+
34
39
  def build_query(files):
35
40
  # Bowler can take a list of files; we’ve already filtered them
36
41
  return Query(list(files))
37
42
 
43
+
38
44
  def main(argv=None):
39
45
  parser = argparse.ArgumentParser(
40
46
  description="Rename legacy datetime fields to standardized names."
@@ -88,5 +94,6 @@ def main(argv=None):
88
94
  )
89
95
  return 0
90
96
 
97
+
91
98
  if __name__ == "__main__":
92
99
  raise SystemExit(main())
endoreg_db/exceptions.py CHANGED
@@ -1,21 +1,24 @@
1
1
  import logging
2
+
2
3
  logger = logging.getLogger(__name__)
3
4
 
4
5
 
5
6
  class InsufficientStorageError(Exception):
6
7
  """Raised when there's not enough disk space for an operation."""
7
-
8
+
8
9
  def __init__(self, message, required_space=None, available_space=None):
9
10
  super().__init__(message)
10
11
  self.required_space = required_space
11
12
  self.available_space = available_space
12
-
13
+
13
14
 
14
15
  class TranscodingError(Exception):
15
16
  """Raised when video transcoding fails."""
17
+
16
18
  pass
17
19
 
18
20
 
19
21
  class VideoProcessingError(Exception):
20
22
  """Base class for video processing errors."""
23
+
21
24
  pass
@@ -2,4 +2,3 @@ from .unit import Unit
2
2
  from .settings import ActiveModelForm
3
3
  from .questionnaires import *
4
4
  from .patient_form import PatientForm
5
-
@@ -1,11 +1,12 @@
1
1
  from django import forms
2
2
  from endoreg_db.models.medical import Examination
3
3
 
4
+
4
5
  class ExaminationForm(forms.ModelForm):
5
6
  class Meta:
6
7
  model = Examination
7
- fields = '__all__'
8
+ fields = "__all__"
8
9
  widgets = {
9
- 'date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
10
- 'time': forms.TimeInput(attrs={'type': 'time', 'class': 'form-control'}),
10
+ "date": forms.DateInput(attrs={"type": "date", "class": "form-control"}),
11
+ "time": forms.TimeInput(attrs={"type": "time", "class": "form-control"}),
11
12
  }
@@ -1,18 +1,40 @@
1
1
  from django import forms
2
2
  from endoreg_db.models import (
3
- Patient, PatientExamination, Finding,
4
- FindingClassification, FindingClassificationChoice,
5
- FindingIntervention, PatientFindingIntervention
3
+ Patient,
4
+ PatientExamination,
5
+ Finding,
6
+ FindingClassification,
7
+ FindingClassificationChoice,
8
+ FindingIntervention,
9
+ PatientFindingIntervention,
6
10
  )
7
11
 
12
+
8
13
  class PatientFindingInterventionForm(forms.ModelForm):
9
14
  patient = forms.ModelChoiceField(queryset=Patient.objects.all(), required=True)
10
- examination = forms.ModelChoiceField(queryset=PatientExamination.objects.none(), required=True)
15
+ examination = forms.ModelChoiceField(
16
+ queryset=PatientExamination.objects.none(), required=True
17
+ )
11
18
  finding = forms.ModelChoiceField(queryset=Finding.objects.none(), required=True)
12
- classification = forms.ModelChoiceField(queryset=FindingClassification.objects.none(), required=True)
13
- classification_choice = forms.ModelChoiceField(queryset=FindingClassificationChoice.objects.none(), required=True)
14
- interventions = forms.ModelMultipleChoiceField(queryset=FindingIntervention.objects.none(), widget=forms.CheckboxSelectMultiple, required=True)
19
+ classification = forms.ModelChoiceField(
20
+ queryset=FindingClassification.objects.none(), required=True
21
+ )
22
+ classification_choice = forms.ModelChoiceField(
23
+ queryset=FindingClassificationChoice.objects.none(), required=True
24
+ )
25
+ interventions = forms.ModelMultipleChoiceField(
26
+ queryset=FindingIntervention.objects.none(),
27
+ widget=forms.CheckboxSelectMultiple,
28
+ required=True,
29
+ )
15
30
 
16
31
  class Meta:
17
32
  model = PatientFindingIntervention
18
- fields = ["patient", "examination", "finding", "classification", "classification_choice", "interventions"]
33
+ fields = [
34
+ "patient",
35
+ "examination",
36
+ "finding",
37
+ "classification",
38
+ "classification_choice",
39
+ "interventions",
40
+ ]
@@ -1,27 +1,23 @@
1
1
  from django import forms
2
2
  from django.forms import ModelForm, Select
3
- from endoreg_db.models import (
4
- Patient,
5
- Gender,
6
- Center
7
- )
3
+ from endoreg_db.models import Patient, Gender, Center
8
4
 
9
5
 
10
6
  class PatientForm(ModelForm):
11
7
  gender = forms.ModelChoiceField(
12
- queryset=Gender.objects.all(),
13
- empty_label="Select Gender",
14
- widget=Select(attrs={'class': 'form-control'})
8
+ queryset=Gender.objects.all(),
9
+ empty_label="Select Gender",
10
+ widget=Select(attrs={"class": "form-control"}),
15
11
  )
16
12
  center = forms.ModelChoiceField(
17
- queryset=Center.objects.all(),
18
- empty_label="Select Center",
19
- widget=Select(attrs={'class': 'form-control'})
13
+ queryset=Center.objects.all(),
14
+ empty_label="Select Center",
15
+ widget=Select(attrs={"class": "form-control"}),
20
16
  )
21
17
 
22
18
  class Meta:
23
19
  model = Patient
24
- fields = '__all__'
20
+ fields = "__all__"
25
21
  widgets = {
26
- 'dob': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
22
+ "dob": forms.DateInput(attrs={"type": "date", "class": "form-control"}),
27
23
  }
@@ -1 +1 @@
1
- # from .tto_questionnaire import TtoQuestionnaireForm, TtoQuestionnaireCreate
1
+ # from .tto_questionnaire import TtoQuestionnaireForm, TtoQuestionnaireCreate
@@ -2,7 +2,10 @@
2
2
  from django import forms
3
3
  from endoreg_db.models import ActiveModel
4
4
 
5
+
5
6
  class ActiveModelForm(forms.ModelForm):
6
7
  class Meta:
7
8
  model = ActiveModel
8
- fields = ["model_meta"] # Or list the specific fields you want to include in the form.
9
+ fields = [
10
+ "model_meta"
11
+ ] # Or list the specific fields you want to include in the form.
endoreg_db/forms/unit.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from django import forms
2
2
  from ..models import Unit
3
3
 
4
+
4
5
  class UnitForm(forms.Form):
5
6
  class Meta:
6
- model = Unit
7
+ model = Unit
@@ -1,29 +1,30 @@
1
- # endoreg_db/helpers/count_db.py
1
+ # endoreg_db/helpers/count_db.py
2
2
  from endoreg_db.models.state.audit_ledger import AuditLedger
3
3
 
4
+
4
5
  def _distinct(object_type: str, action: str):
5
6
  """
6
7
  Returns the count of distinct primary keys for records in AuditLedger filtered by object type and action.
7
-
8
+
8
9
  Args:
9
10
  object_type: The type of object to filter by.
10
11
  action: The action to filter by.
11
-
12
+
12
13
  Returns:
13
14
  The number of unique object primary keys matching the specified type and action.
14
15
  """
15
16
  return (
16
- AuditLedger.objects
17
- .filter(object_type=object_type, action=action)
18
- .values('object_pk')
17
+ AuditLedger.objects.filter(object_type=object_type, action=action)
18
+ .values("object_pk")
19
19
  .distinct()
20
20
  .count()
21
21
  )
22
22
 
23
+
23
24
  def collect_counters():
24
25
  """
25
26
  Returns a dictionary with statistical counts for cases, videos, annotations, anonymizations, images, and video statuses.
26
-
27
+
27
28
  The returned dictionary includes:
28
29
  - "totalCases": Count of distinct created video files.
29
30
  - "totalVideos": Count of distinct created video files.
@@ -34,12 +35,14 @@ def collect_counters():
34
35
  - "videosAnonym": Count of distinct video files that have been anonymized.
35
36
  """
36
37
  return {
37
- #TODO @maxhild can we remove the totalCases key?
38
+ # TODO @maxhild can we remove the totalCases key?
38
39
  # "totalCases": _distinct("VideoFile", "created"),
39
- "totalVideos": _distinct("VideoFile", "created"),
40
- "totalAnnotations": AuditLedger.objects.filter(action="annotation_added").count(),
41
- "totalAnonymizations": _distinct("VideoFile", "anonymized"),
42
- "totalImages": _distinct("Image", "created"),
43
- "videosCompleted": _distinct("VideoFile", "validated"),
44
- "videosAnonym": _distinct("VideoFile", "anonymized"),
40
+ "totalVideos": _distinct("VideoFile", "created"),
41
+ "totalAnnotations": AuditLedger.objects.filter(
42
+ action="annotation_added"
43
+ ).count(),
44
+ "totalAnonymizations": _distinct("VideoFile", "anonymized"),
45
+ "totalImages": _distinct("Image", "created"),
46
+ "videosCompleted": _distinct("VideoFile", "validated"),
47
+ "videosAnonym": _distinct("VideoFile", "anonymized"),
45
48
  }
@@ -8,7 +8,7 @@ from typing import Optional
8
8
  from django.conf import settings # Import settings
9
9
  from django.core.files.storage import default_storage # Import default storage
10
10
  from django.db.models.fields.files import FieldFile
11
-
11
+ from endoreg_db.utils.file_operations import sha256_file
12
12
  from endoreg_db.models import (
13
13
  AiModel,
14
14
  Center,
@@ -408,6 +408,7 @@ def get_default_video_file():
408
408
  center_name=DEFAULT_CENTER_NAME, # Pass center name as expected by _create_from_file
409
409
  delete_source=False, # Keep the original asset for other tests
410
410
  processor_name=DEFAULT_ENDOSCOPY_PROCESSOR_NAME,
411
+ video_hash=sha256_file(video_path),
411
412
  )
412
413
 
413
414
  return video_file