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
@@ -27,7 +27,11 @@ def _convert_sequences_to_db_segments(
27
27
  """
28
28
  from ...label import Label, LabelVideoSegment # Local import for models
29
29
 
30
- logger.info("Converting sequences to LabelVideoSegments for video %s, prediction meta %s", video.uuid, video_prediction_meta.pk)
30
+ logger.info(
31
+ "Converting sequences to LabelVideoSegments for video %s, prediction meta %s",
32
+ video.video_hash,
33
+ video_prediction_meta.pk,
34
+ )
31
35
  created_count = 0
32
36
  skipped_count = 0
33
37
  error_count = 0
@@ -45,14 +49,21 @@ def _convert_sequences_to_db_segments(
45
49
  try:
46
50
  label = Label.objects.get(name=label_name) # require pre-existing label
47
51
  except Exception as e:
48
- logger.error("Could not get or create Label '%s': %s", label_name, e, exc_info=True)
52
+ logger.error(
53
+ "Could not get or create Label '%s': %s", label_name, e, exc_info=True
54
+ )
49
55
  error_count += len(sequence_list)
50
56
  continue
51
57
 
52
58
  segments_to_create = []
53
59
  for start_frame, end_frame in sequence_list:
54
60
  if start_frame > end_frame or start_frame < 0:
55
- logger.warning("Skipping invalid sequence for label '%s': start=%d, end=%d", label_name, start_frame, end_frame)
61
+ logger.warning(
62
+ "Skipping invalid sequence for label '%s': start=%d, end=%d",
63
+ label_name,
64
+ start_frame,
65
+ end_frame,
66
+ )
56
67
  skipped_count += 1
57
68
  continue
58
69
 
@@ -68,19 +79,34 @@ def _convert_sequences_to_db_segments(
68
79
 
69
80
  if segments_to_create:
70
81
  try:
71
- LabelVideoSegment.objects.bulk_create(segments_to_create, ignore_conflicts=True)
82
+ LabelVideoSegment.objects.bulk_create(
83
+ segments_to_create, ignore_conflicts=True
84
+ )
72
85
  created_count += len(segments_to_create)
73
- logger.debug("Bulk created %d segments for label '%s'", len(segments_to_create), label_name)
86
+ logger.debug(
87
+ "Bulk created %d segments for label '%s'",
88
+ len(segments_to_create),
89
+ label_name,
90
+ )
74
91
  except Exception as e:
75
- logger.error("Error bulk creating segments for label '%s': %s", label_name, e, exc_info=True)
92
+ logger.error(
93
+ "Error bulk creating segments for label '%s': %s",
94
+ label_name,
95
+ e,
96
+ exc_info=True,
97
+ )
76
98
  error_count += len(segments_to_create)
77
99
 
78
- newly_created_segments = LabelVideoSegment.objects.filter(video_file=video, prediction_meta=video_prediction_meta, label__name__in=processed_labels)
100
+ newly_created_segments = LabelVideoSegment.objects.filter(
101
+ video_file=video,
102
+ prediction_meta=video_prediction_meta,
103
+ label__name__in=processed_labels,
104
+ )
79
105
 
80
106
  logger.info(
81
107
  "Attempting to create state objects for %d potentially new segments (Video: %s, PredictionMeta: %s)",
82
108
  newly_created_segments.count(),
83
- video.uuid,
109
+ video.video_hash,
84
110
  video_prediction_meta.pk,
85
111
  )
86
112
 
@@ -90,12 +116,18 @@ def _convert_sequences_to_db_segments(
90
116
  if created:
91
117
  state_created_count += 1
92
118
  except Exception as e:
93
- logger.error("Failed to get or create state for segment %s (Video: %s): %s", segment.pk, video.uuid, e, exc_info=True)
119
+ logger.error(
120
+ "Failed to get or create state for segment %s (Video: %s): %s",
121
+ segment.pk,
122
+ video.video_hash,
123
+ e,
124
+ exc_info=True,
125
+ )
94
126
  state_error_count += 1
95
127
 
96
128
  logger.info(
97
129
  "LabelVideoSegment conversion finished for video %s. Segments Created: %d, Skipped: %d, Errors: %d. States Created: %d, State Errors: %d",
98
- video.uuid,
130
+ video.video_hash,
99
131
  created_count,
100
132
  skipped_count,
101
133
  error_count,
@@ -122,7 +154,9 @@ def _sequences_to_label_video_segments(
122
154
  )
123
155
 
124
156
 
125
- def _get_outside_segments(video: "VideoFile", outside_label_name: str = "outside") -> "QuerySet[LabelVideoSegment]":
157
+ def _get_outside_segments(
158
+ video: "VideoFile", outside_label_name: str = "outside"
159
+ ) -> "QuerySet[LabelVideoSegment]":
126
160
  """Gets LabelVideoSegments marked with the 'outside' label."""
127
161
  from ...label import Label, LabelVideoSegment # Local import for models
128
162
 
@@ -133,29 +167,52 @@ def _get_outside_segments(video: "VideoFile", outside_label_name: str = "outside
133
167
  logger.warning("Label '%s' not found in the database.", outside_label_name)
134
168
  return LabelVideoSegment.objects.none()
135
169
  except AttributeError:
136
- logger.error("VideoFile instance does not have 'label_video_segments' related manager.")
170
+ logger.error(
171
+ "VideoFile instance does not have 'label_video_segments' related manager."
172
+ )
137
173
  return LabelVideoSegment.objects.none()
138
174
  except Exception as e:
139
- logger.error("Error getting '%s' segments for video %s: %s", outside_label_name, video.uuid, e, exc_info=True)
175
+ logger.error(
176
+ "Error getting '%s' segments for video %s: %s",
177
+ outside_label_name,
178
+ video.video_hash,
179
+ e,
180
+ exc_info=True,
181
+ )
140
182
  return LabelVideoSegment.objects.none()
141
183
 
142
184
 
143
- def _get_outside_frame_numbers(video: "VideoFile", outside_label_name: str = "outside") -> Set[int]:
185
+ def _get_outside_frame_numbers(
186
+ video: "VideoFile", outside_label_name: str = "outside"
187
+ ) -> Set[int]:
144
188
  """
145
189
  Gets a set of frame numbers corresponding to segments labeled as 'outside'.
146
190
  """
147
191
  outside_segments = _get_outside_segments(video, outside_label_name)
148
192
  frame_numbers = set()
149
193
  for segment in outside_segments:
150
- frame_numbers.update(range(segment.start_frame_number, segment.end_frame_number + 1))
194
+ frame_numbers.update(
195
+ range(segment.start_frame_number, segment.end_frame_number + 1)
196
+ )
151
197
  if frame_numbers:
152
- logger.info("Found %d frame numbers marked as '%s' for video %s.", len(frame_numbers), outside_label_name, video.uuid)
198
+ logger.info(
199
+ "Found %d frame numbers marked as '%s' for video %s.",
200
+ len(frame_numbers),
201
+ outside_label_name,
202
+ video.video_hash,
203
+ )
153
204
  else:
154
- logger.info("No frame numbers marked as '%s' found for video %s.", outside_label_name, video.uuid)
205
+ logger.info(
206
+ "No frame numbers marked as '%s' found for video %s.",
207
+ outside_label_name,
208
+ video.video_hash,
209
+ )
155
210
  return frame_numbers
156
211
 
157
212
 
158
- def _get_outside_frames(video: "VideoFile", outside_label_name: str = "outside") -> "QuerySet[Frame]":
213
+ def _get_outside_frames(
214
+ video: "VideoFile", outside_label_name: str = "outside"
215
+ ) -> "QuerySet[Frame]":
159
216
  """
160
217
  Gets a QuerySet of all unique Frame objects that fall within any segment
161
218
  labeled with the specified 'outside_label_name'.
@@ -168,7 +225,10 @@ def _get_outside_frames(video: "VideoFile", outside_label_name: str = "outside")
168
225
 
169
226
  q_objects: Q | None = None
170
227
  for segment in outside_segments:
171
- clause = Q(frame_number__gte=segment.start_frame_number, frame_number__lt=segment.end_frame_number)
228
+ clause = Q(
229
+ frame_number__gte=segment.start_frame_number,
230
+ frame_number__lt=segment.end_frame_number,
231
+ )
172
232
  q_objects = clause if q_objects is None else q_objects | clause
173
233
 
174
234
  if q_objects is None:
@@ -177,11 +237,18 @@ def _get_outside_frames(video: "VideoFile", outside_label_name: str = "outside")
177
237
  try:
178
238
  return video.frames.filter(q_objects).distinct().order_by("frame_number")
179
239
  except Exception as e:
180
- logger.error("Error filtering outside frames for video %s: %s", video.uuid, e, exc_info=True)
240
+ logger.error(
241
+ "Error filtering outside frames for video %s: %s",
242
+ video.video_hash,
243
+ e,
244
+ exc_info=True,
245
+ )
181
246
  return Frame.objects.none()
182
247
 
183
248
 
184
- def _get_outside_frame_paths(video: "VideoFile", outside_label_name: str = "outside") -> List["Path"]:
249
+ def _get_outside_frame_paths(
250
+ video: "VideoFile", outside_label_name: str = "outside"
251
+ ) -> List["Path"]:
185
252
  """Gets the file paths of frames that fall within 'outside' segments."""
186
253
  from pathlib import Path # Local import
187
254
 
@@ -191,16 +258,28 @@ def _get_outside_frame_paths(video: "VideoFile", outside_label_name: str = "outs
191
258
  try:
192
259
  frame_paths.append(Path(frame.relative_path))
193
260
  except Exception as e:
194
- logger.warning("Could not get path for frame %s (Number: %d): %s", frame.pk, frame.frame_number, e)
261
+ logger.warning(
262
+ "Could not get path for frame %s (Number: %d): %s",
263
+ frame.pk,
264
+ frame.frame_number,
265
+ e,
266
+ )
195
267
  ic(f"Could not get path for frame {frame.pk}: {e}")
196
268
 
197
- logger.info("Found %d frame paths within '%s' segments for video %s", len(frame_paths), outside_label_name, video.uuid)
269
+ logger.info(
270
+ "Found %d frame paths within '%s' segments for video %s",
271
+ len(frame_paths),
272
+ outside_label_name,
273
+ video.video_hash,
274
+ )
198
275
  return frame_paths
199
276
 
200
277
 
201
278
  def _label_segments_to_frame_annotations(video: "VideoFile"):
202
279
  """Generates frame annotations based on existing LabelVideoSegments."""
203
- logger.info("Generating frame annotations from segments for video %s", video.uuid)
280
+ logger.info(
281
+ "Generating frame annotations from segments for video %s", video.video_hash
282
+ )
204
283
  processed_count = 0
205
284
  try:
206
285
  for lvs in video.label_video_segments.all():
@@ -210,7 +289,19 @@ def _label_segments_to_frame_annotations(video: "VideoFile"):
210
289
  lvs.generate_annotations()
211
290
  processed_count += 1
212
291
  except Exception as e:
213
- logger.error("Error generating annotations for segment %s (Video %s): %s", lvs.pk, video.uuid, e)
214
- logger.info("Processed %d segments for frame annotations for video %s", processed_count, video.uuid)
292
+ logger.error(
293
+ "Error generating annotations for segment %s (Video %s): %s",
294
+ lvs.pk,
295
+ video.video_hash,
296
+ e,
297
+ )
298
+ logger.info(
299
+ "Processed %d segments for frame annotations for video %s",
300
+ processed_count,
301
+ video.video_hash,
302
+ )
215
303
  except AttributeError:
216
- logger.error("Could not generate frame annotations for video %s. 'label_video_segments' related manager not found.", video.uuid)
304
+ logger.error(
305
+ "Could not generate frame annotations for video %s. 'label_video_segments' related manager not found.",
306
+ video.video_hash,
307
+ )
@@ -18,15 +18,34 @@ class VideoMetadata(models.Model):
18
18
  and provides metrics for the correction UI.
19
19
  """
20
20
 
21
- video = models.OneToOneField(VideoFile, on_delete=models.CASCADE, related_name="metadata", help_text="Video file this metadata belongs to")
21
+ video = models.OneToOneField(
22
+ VideoFile,
23
+ on_delete=models.CASCADE,
24
+ related_name="metadata",
25
+ help_text="Video file this metadata belongs to",
26
+ )
22
27
 
23
28
  # Analysis Results
24
- sensitive_frame_count = models.IntegerField(null=True, blank=True, help_text="Number of frames detected as containing sensitive information")
25
- sensitive_ratio = models.FloatField(null=True, blank=True, help_text="Ratio of sensitive frames to total frames (0.0-1.0)")
26
- sensitive_frame_ids = models.TextField(null=True, blank=True, help_text="JSON array of sensitive frame indices (0-based)")
29
+ sensitive_frame_count = models.IntegerField(
30
+ null=True,
31
+ blank=True,
32
+ help_text="Number of frames detected as containing sensitive information",
33
+ )
34
+ sensitive_ratio = models.FloatField(
35
+ null=True,
36
+ blank=True,
37
+ help_text="Ratio of sensitive frames to total frames (0.0-1.0)",
38
+ )
39
+ sensitive_frame_ids = models.TextField(
40
+ null=True,
41
+ blank=True,
42
+ help_text="JSON array of sensitive frame indices (0-based)",
43
+ )
27
44
 
28
45
  # Metadata
29
- analyzed_at = models.DateTimeField(auto_now=True, help_text="Timestamp of last analysis")
46
+ analyzed_at = models.DateTimeField(
47
+ auto_now=True, help_text="Timestamp of last analysis"
48
+ )
30
49
 
31
50
  class Meta:
32
51
  db_table = "video_metadata"
@@ -34,7 +53,7 @@ class VideoMetadata(models.Model):
34
53
  verbose_name_plural = "Video Metadata"
35
54
 
36
55
  def __str__(self):
37
- return f"Metadata for {self.video.uuid} ({self.sensitive_frame_count or 0} sensitive frames)"
56
+ return f"Metadata for {self.video.video_hash} ({self.sensitive_frame_count or 0} sensitive frames)"
38
57
 
39
58
  @property
40
59
  def has_analysis(self) -> bool:
@@ -53,26 +53,57 @@ class VideoProcessingHistory(models.Model):
53
53
  (STATUS_CANCELLED, "Cancelled"),
54
54
  ]
55
55
 
56
- video = models.ForeignKey(VideoFile, on_delete=models.CASCADE, related_name="processing_history", help_text="Video file this operation was performed on")
57
-
58
- operation = models.CharField(max_length=50, choices=OPERATION_CHOICES, help_text="Type of processing operation")
59
-
60
- status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=STATUS_PENDING, help_text="Current status of the operation")
56
+ video = models.ForeignKey(
57
+ VideoFile,
58
+ on_delete=models.CASCADE,
59
+ related_name="processing_history",
60
+ help_text="Video file this operation was performed on",
61
+ )
62
+
63
+ operation = models.CharField(
64
+ max_length=50,
65
+ choices=OPERATION_CHOICES,
66
+ help_text="Type of processing operation",
67
+ )
68
+
69
+ status = models.CharField(
70
+ max_length=20,
71
+ choices=STATUS_CHOICES,
72
+ default=STATUS_PENDING,
73
+ help_text="Current status of the operation",
74
+ )
61
75
 
62
76
  # Configuration & Results
63
- config = models.JSONField(default=dict, help_text="Operation configuration (mask settings, frame list, etc.)")
77
+ config = models.JSONField(
78
+ default=dict,
79
+ help_text="Operation configuration (mask settings, frame list, etc.)",
80
+ )
64
81
 
65
- output_file = models.CharField(max_length=500, blank=True, help_text="Path to output file (relative to MEDIA_ROOT)")
82
+ output_file = models.CharField(
83
+ max_length=500,
84
+ blank=True,
85
+ help_text="Path to output file (relative to MEDIA_ROOT)",
86
+ )
66
87
 
67
- details = models.TextField(blank=True, help_text="Additional details or error messages")
88
+ details = models.TextField(
89
+ blank=True, help_text="Additional details or error messages"
90
+ )
68
91
 
69
92
  # Celery Integration
70
- task_id = models.CharField(max_length=100, blank=True, help_text="Celery task ID for progress tracking")
93
+ task_id = models.CharField(
94
+ max_length=100, blank=True, help_text="Celery task ID for progress tracking"
95
+ )
71
96
 
72
97
  # Timestamps
73
- created_at = models.DateTimeField(auto_now_add=True, help_text="When the operation was started")
98
+ created_at = models.DateTimeField(
99
+ auto_now_add=True, help_text="When the operation was started"
100
+ )
74
101
 
75
- completed_at = models.DateTimeField(null=True, blank=True, help_text="When the operation completed (success or failure)")
102
+ completed_at = models.DateTimeField(
103
+ null=True,
104
+ blank=True,
105
+ help_text="When the operation completed (success or failure)",
106
+ )
76
107
 
77
108
  class Meta:
78
109
  db_table = "video_processing_history"
@@ -89,9 +120,11 @@ class VideoProcessingHistory(models.Model):
89
120
  operation_display = getattr(self, "get_operation_display", None)
90
121
  status_display = getattr(self, "get_status_display", None)
91
122
 
92
- operation = operation_display() if callable(operation_display) else self.operation
123
+ operation = (
124
+ operation_display() if callable(operation_display) else self.operation
125
+ )
93
126
  status = status_display() if callable(status_display) else self.status
94
- return f"{operation} on {self.video.uuid} - {status}"
127
+ return f"{operation} on {self.video.video_hash} - {status}"
95
128
 
96
129
  def mark_running(self, save=True):
97
130
  """Mark operation as running."""
@@ -130,7 +163,9 @@ class VideoProcessingHistory(models.Model):
130
163
  if details:
131
164
  self.details = details
132
165
  if save:
133
- self.save(update_fields=["status", "completed_at", "output_file", "details"])
166
+ self.save(
167
+ update_fields=["status", "completed_at", "output_file", "details"]
168
+ )
134
169
 
135
170
  def mark_failure(self, error_message, save=True):
136
171
  """Mark operation as failed."""
@@ -150,4 +185,8 @@ class VideoProcessingHistory(models.Model):
150
185
  @property
151
186
  def is_complete(self) -> bool:
152
187
  """Check if operation is in a terminal state."""
153
- return self.status in [self.STATUS_SUCCESS, self.STATUS_FAILURE, self.STATUS_CANCELLED]
188
+ return self.status in [
189
+ self.STATUS_SUCCESS,
190
+ self.STATUS_FAILURE,
191
+ self.STATUS_CANCELLED,
192
+ ]
@@ -1,5 +1,5 @@
1
- from .disease import (Disease, DiseaseClassification, DiseaseClassificationChoice)
2
- from .event import (Event, EventClassification, EventClassificationChoice)
1
+ from .disease import Disease, DiseaseClassification, DiseaseClassificationChoice
2
+ from .event import Event, EventClassification, EventClassificationChoice
3
3
 
4
4
  from .contraindication import Contraindication
5
5
  from .examination import (
@@ -72,15 +72,12 @@ __all__ = [
72
72
  "Disease",
73
73
  "DiseaseClassification",
74
74
  "DiseaseClassificationChoice",
75
-
76
75
  # Event
77
76
  "Event",
78
77
  "EventClassification",
79
78
  "EventClassificationChoice",
80
-
81
79
  # Contraindication
82
80
  "Contraindication",
83
-
84
81
  # Examination
85
82
  "Examination",
86
83
  "ExaminationRequirementSet",
@@ -90,7 +87,6 @@ __all__ = [
90
87
  "ExaminationIndicationClassification",
91
88
  "ExaminationTime",
92
89
  "ExaminationTimeType",
93
-
94
90
  # Finding
95
91
  "Finding",
96
92
  "FindingClassificationType",
@@ -100,7 +96,6 @@ __all__ = [
100
96
  "FindingMorphologyClassification",
101
97
  "FindingIntervention",
102
98
  "FindingInterventionType",
103
-
104
99
  # Patient
105
100
  ## Disease
106
101
  "PatientDisease",
@@ -120,14 +115,11 @@ __all__ = [
120
115
  ## Medication
121
116
  "PatientMedication",
122
117
  "PatientMedicationSchedule",
123
-
124
118
  # Organ
125
119
  "Organ",
126
-
127
120
  # Risk
128
121
  "Risk",
129
122
  "RiskType",
130
-
131
123
  # Medication
132
124
  "Medication",
133
125
  "MedicationManager",
@@ -135,12 +127,10 @@ __all__ = [
135
127
  "MedicationIntakeTime",
136
128
  "MedicationIndicationType",
137
129
  "MedicationIndication",
138
-
139
130
  # Hardware
140
131
  "Endoscope",
141
132
  "EndoscopeType",
142
133
  "EndoscopyProcessor",
143
-
144
134
  # Laboratory
145
135
  "LabValue",
146
- ]
136
+ ]
@@ -18,7 +18,9 @@ class Contraindication(models.Model):
18
18
  from endoreg_db.models import FindingIntervention
19
19
 
20
20
  @property
21
- def contraindicating_finding_interventions(self) -> "models.manager.RelatedManager[FindingIntervention]": ...
21
+ def contraindicating_finding_interventions(
22
+ self,
23
+ ) -> "models.manager.RelatedManager[FindingIntervention]": ...
22
24
 
23
25
  def natural_key(self):
24
26
  return (self.name,)
@@ -38,7 +38,9 @@ class Disease(models.Model):
38
38
  if TYPE_CHECKING:
39
39
 
40
40
  @property
41
- def disease_classifications(self) -> models.QuerySet["DiseaseClassification"]: ...
41
+ def disease_classifications(
42
+ self,
43
+ ) -> models.QuerySet["DiseaseClassification"]: ...
42
44
 
43
45
  @property
44
46
  def patient_diseases(self) -> models.QuerySet["PatientDisease"]: ...
@@ -58,7 +60,9 @@ class Disease(models.Model):
58
60
  Returns:
59
61
  List[DiseaseClassification]: A list of related disease classification objects.
60
62
  """
61
- classifications: List[DiseaseClassification] = [_ for _ in self.disease_classifications.all()]
63
+ classifications: List[DiseaseClassification] = [
64
+ _ for _ in self.disease_classifications.all()
65
+ ]
62
66
  return classifications
63
67
 
64
68
 
@@ -85,7 +89,9 @@ class DiseaseClassification(models.Model):
85
89
 
86
90
  name = models.CharField(max_length=255, unique=True)
87
91
 
88
- disease = models.ForeignKey(Disease, on_delete=models.CASCADE, related_name="disease_classifications")
92
+ disease = models.ForeignKey(
93
+ Disease, on_delete=models.CASCADE, related_name="disease_classifications"
94
+ )
89
95
 
90
96
  objects = DiseaseClassificationManager()
91
97
 
@@ -93,7 +99,9 @@ class DiseaseClassification(models.Model):
93
99
  disease: models.ForeignKey["Disease"]
94
100
 
95
101
  @property
96
- def disease_classification_choices(self) -> models.manager.RelatedManager["DiseaseClassificationChoice"]: ...
102
+ def disease_classification_choices(
103
+ self,
104
+ ) -> models.manager.RelatedManager["DiseaseClassificationChoice"]: ...
97
105
 
98
106
  def natural_key(self):
99
107
  """Returns the natural key (name) as a tuple."""
@@ -110,7 +118,9 @@ class DiseaseClassification(models.Model):
110
118
  Returns:
111
119
  List[DiseaseClassificationChoice]: A list of related disease classification choices.
112
120
  """
113
- choices: List[DiseaseClassificationChoice] = [_ for _ in self.disease_classification_choices.all()]
121
+ choices: List[DiseaseClassificationChoice] = [
122
+ _ for _ in self.disease_classification_choices.all()
123
+ ]
114
124
  return choices
115
125
 
116
126
 
@@ -151,7 +161,9 @@ class DiseaseClassificationChoice(models.Model):
151
161
  disease_classification: models.ForeignKey["DiseaseClassification"]
152
162
 
153
163
  @property
154
- def patient_diseases(self) -> models.manager.RelatedManager["PatientDisease"]: ...
164
+ def patient_diseases(
165
+ self,
166
+ ) -> models.manager.RelatedManager["PatientDisease"]: ...
155
167
 
156
168
  def natural_key(self):
157
169
  """Returns the natural key (name) as a tuple."""
@@ -93,7 +93,9 @@ class EventClassification(models.Model):
93
93
  event: models.ForeignKey["Event"]
94
94
 
95
95
  @property
96
- def event_classification_choices(self) -> models.QuerySet["EventClassificationChoice"]: ...
96
+ def event_classification_choices(
97
+ self,
98
+ ) -> models.QuerySet["EventClassificationChoice"]: ...
97
99
 
98
100
  def natural_key(self):
99
101
  """Returns the natural key (name) as a tuple."""
@@ -105,7 +107,9 @@ class EventClassification(models.Model):
105
107
 
106
108
  def get_choices(self) -> List["EventClassificationChoice"]:
107
109
  """Retrieves all choices associated with this classification."""
108
- choices: List[EventClassificationChoice] = [_ for _ in self.event_classification_choices.all()]
110
+ choices: List[EventClassificationChoice] = [
111
+ _ for _ in self.event_classification_choices.all()
112
+ ]
109
113
  return choices
110
114
 
111
115
 
@@ -1,5 +1,9 @@
1
1
  from .examination import Examination, ExaminationRequirementSet
2
- from .examination_indication import ExaminationIndication, ExaminationIndicationClassification, ExaminationIndicationClassificationChoice
2
+ from .examination_indication import (
3
+ ExaminationIndication,
4
+ ExaminationIndicationClassification,
5
+ ExaminationIndicationClassificationChoice,
6
+ )
3
7
  from .examination_time import ExaminationTime
4
8
  from .examination_time_type import ExaminationTimeType
5
9
  from .examination_type import ExaminationType
@@ -53,18 +53,34 @@ class Examination(models.Model):
53
53
  objects = ExaminationManager()
54
54
 
55
55
  if TYPE_CHECKING:
56
- from endoreg_db.models import ExaminationIndication, ExaminationTime, Finding, FindingClassification, InformationSource
56
+ from endoreg_db.models import (
57
+ ExaminationIndication,
58
+ ExaminationTime,
59
+ Finding,
60
+ FindingClassification,
61
+ InformationSource,
62
+ )
57
63
 
58
- indications = cast("models.manager.RelatedManager[ExaminationIndication]", indications)
59
- examination_times = cast("models.manager.RelatedManager[ExaminationTime]", examination_times)
64
+ indications = cast(
65
+ "models.manager.RelatedManager[ExaminationIndication]", indications
66
+ )
67
+ examination_times = cast(
68
+ "models.manager.RelatedManager[ExaminationTime]", examination_times
69
+ )
60
70
  findings = cast("models.manager.RelatedManager[Finding]", findings)
61
- information_sources = cast("models.manager.RelatedManager[InformationSource]", information_sources)
71
+ information_sources = cast(
72
+ "models.manager.RelatedManager[InformationSource]", information_sources
73
+ )
62
74
 
63
75
  @property
64
- def finding_classifications(self) -> "models.manager.RelatedManager[FindingClassification]": ...
76
+ def finding_classifications(
77
+ self,
78
+ ) -> "models.manager.RelatedManager[FindingClassification]": ...
65
79
 
66
80
  @property
67
- def exam_reqset_links(self) -> "models.manager.RelatedManager[ExaminationRequirementSet]": ...
81
+ def exam_reqset_links(
82
+ self,
83
+ ) -> "models.manager.RelatedManager[ExaminationRequirementSet]": ...
68
84
 
69
85
  @property
70
86
  def links(self) -> "RequirementLinks":