endoreg-db 0.8.8.9__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 (453) 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 +146 -83
  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/migrations/__init__.py +0 -0
  82. endoreg_db/models/__init__.py +8 -0
  83. endoreg_db/models/administration/ai/active_model.py +5 -5
  84. endoreg_db/models/administration/ai/ai_model.py +41 -18
  85. endoreg_db/models/administration/ai/model_type.py +1 -0
  86. endoreg_db/models/administration/case/case.py +22 -22
  87. endoreg_db/models/administration/center/__init__.py +5 -5
  88. endoreg_db/models/administration/center/center.py +6 -2
  89. endoreg_db/models/administration/center/center_resource.py +18 -4
  90. endoreg_db/models/administration/center/center_shift.py +3 -1
  91. endoreg_db/models/administration/center/center_waste.py +6 -2
  92. endoreg_db/models/administration/person/__init__.py +1 -1
  93. endoreg_db/models/administration/person/employee/__init__.py +1 -1
  94. endoreg_db/models/administration/person/employee/employee_type.py +3 -1
  95. endoreg_db/models/administration/person/examiner/__init__.py +1 -1
  96. endoreg_db/models/administration/person/examiner/examiner.py +10 -2
  97. endoreg_db/models/administration/person/names/first_name.py +6 -4
  98. endoreg_db/models/administration/person/names/last_name.py +4 -3
  99. endoreg_db/models/administration/person/patient/__init__.py +1 -1
  100. endoreg_db/models/administration/person/patient/patient.py +0 -1
  101. endoreg_db/models/administration/person/patient/patient_external_id.py +0 -1
  102. endoreg_db/models/administration/person/person.py +1 -1
  103. endoreg_db/models/administration/product/__init__.py +7 -6
  104. endoreg_db/models/administration/product/product.py +6 -2
  105. endoreg_db/models/administration/product/product_group.py +9 -7
  106. endoreg_db/models/administration/product/product_material.py +9 -2
  107. endoreg_db/models/administration/product/reference_product.py +64 -15
  108. endoreg_db/models/administration/qualification/qualification.py +3 -1
  109. endoreg_db/models/administration/shift/shift.py +3 -1
  110. endoreg_db/models/administration/shift/shift_type.py +12 -4
  111. endoreg_db/models/aidataset/__init__.py +5 -0
  112. endoreg_db/models/aidataset/aidataset.py +193 -0
  113. endoreg_db/models/label/__init__.py +1 -1
  114. endoreg_db/models/label/label.py +10 -2
  115. endoreg_db/models/label/label_set.py +3 -1
  116. endoreg_db/models/label/label_video_segment/_create_from_video.py +6 -2
  117. endoreg_db/models/label/label_video_segment/label_video_segment.py +148 -44
  118. endoreg_db/models/media/__init__.py +12 -5
  119. endoreg_db/models/media/frame/__init__.py +1 -1
  120. endoreg_db/models/media/frame/frame.py +34 -8
  121. endoreg_db/models/media/pdf/__init__.py +2 -1
  122. endoreg_db/models/media/pdf/raw_pdf.py +11 -4
  123. endoreg_db/models/media/pdf/report_file.py +6 -2
  124. endoreg_db/models/media/pdf/report_reader/__init__.py +3 -3
  125. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +15 -5
  126. endoreg_db/models/media/video/create_from_file.py +20 -41
  127. endoreg_db/models/media/video/pipe_1.py +75 -30
  128. endoreg_db/models/media/video/pipe_2.py +37 -12
  129. endoreg_db/models/media/video/video_file.py +36 -24
  130. endoreg_db/models/media/video/video_file_ai.py +235 -70
  131. endoreg_db/models/media/video/video_file_anonymize.py +240 -65
  132. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -1
  133. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +3 -1
  134. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +30 -9
  135. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +95 -29
  136. endoreg_db/models/media/video/video_file_frames/_get_frame.py +13 -3
  137. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -1
  138. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +15 -3
  139. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +15 -3
  140. endoreg_db/models/media/video/video_file_frames/_get_frames.py +7 -2
  141. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +109 -23
  142. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +111 -27
  143. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +46 -13
  144. endoreg_db/models/media/video/video_file_io.py +85 -33
  145. endoreg_db/models/media/video/video_file_meta/__init__.py +6 -6
  146. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +17 -4
  147. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +28 -7
  148. endoreg_db/models/media/video/video_file_meta/get_fps.py +46 -13
  149. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +81 -20
  150. endoreg_db/models/media/video/video_file_meta/text_meta.py +61 -20
  151. endoreg_db/models/media/video/video_file_meta/video_meta.py +40 -12
  152. endoreg_db/models/media/video/video_file_segments.py +118 -27
  153. endoreg_db/models/media/video/video_metadata.py +25 -6
  154. endoreg_db/models/media/video/video_processing.py +54 -15
  155. endoreg_db/models/medical/__init__.py +3 -13
  156. endoreg_db/models/medical/contraindication/__init__.py +3 -1
  157. endoreg_db/models/medical/disease.py +18 -6
  158. endoreg_db/models/medical/event.py +6 -2
  159. endoreg_db/models/medical/examination/__init__.py +5 -1
  160. endoreg_db/models/medical/examination/examination.py +22 -6
  161. endoreg_db/models/medical/examination/examination_indication.py +23 -7
  162. endoreg_db/models/medical/examination/examination_time.py +6 -2
  163. endoreg_db/models/medical/finding/__init__.py +3 -1
  164. endoreg_db/models/medical/finding/finding.py +37 -12
  165. endoreg_db/models/medical/finding/finding_classification.py +27 -8
  166. endoreg_db/models/medical/finding/finding_intervention.py +19 -6
  167. endoreg_db/models/medical/finding/finding_type.py +3 -1
  168. endoreg_db/models/medical/hardware/__init__.py +1 -1
  169. endoreg_db/models/medical/hardware/endoscope.py +14 -2
  170. endoreg_db/models/medical/laboratory/__init__.py +1 -1
  171. endoreg_db/models/medical/laboratory/lab_value.py +139 -39
  172. endoreg_db/models/medical/medication/__init__.py +7 -3
  173. endoreg_db/models/medical/medication/medication.py +3 -1
  174. endoreg_db/models/medical/medication/medication_indication.py +3 -1
  175. endoreg_db/models/medical/medication/medication_indication_type.py +11 -3
  176. endoreg_db/models/medical/medication/medication_intake_time.py +3 -1
  177. endoreg_db/models/medical/medication/medication_schedule.py +3 -1
  178. endoreg_db/models/medical/patient/__init__.py +2 -10
  179. endoreg_db/models/medical/patient/medication_examples.py +3 -14
  180. endoreg_db/models/medical/patient/patient_disease.py +17 -5
  181. endoreg_db/models/medical/patient/patient_event.py +12 -4
  182. endoreg_db/models/medical/patient/patient_examination.py +52 -15
  183. endoreg_db/models/medical/patient/patient_examination_indication.py +15 -4
  184. endoreg_db/models/medical/patient/patient_finding.py +105 -29
  185. endoreg_db/models/medical/patient/patient_finding_classification.py +41 -12
  186. endoreg_db/models/medical/patient/patient_finding_intervention.py +11 -3
  187. endoreg_db/models/medical/patient/patient_lab_sample.py +6 -2
  188. endoreg_db/models/medical/patient/patient_lab_value.py +42 -10
  189. endoreg_db/models/medical/patient/patient_medication.py +25 -7
  190. endoreg_db/models/medical/patient/patient_medication_schedule.py +34 -10
  191. endoreg_db/models/metadata/model_meta.py +40 -12
  192. endoreg_db/models/metadata/model_meta_logic.py +51 -16
  193. endoreg_db/models/metadata/sensitive_meta.py +65 -28
  194. endoreg_db/models/metadata/sensitive_meta_logic.py +28 -26
  195. endoreg_db/models/metadata/video_meta.py +146 -39
  196. endoreg_db/models/metadata/video_prediction_logic.py +70 -21
  197. endoreg_db/models/metadata/video_prediction_meta.py +80 -27
  198. endoreg_db/models/operation_log.py +63 -0
  199. endoreg_db/models/other/__init__.py +10 -10
  200. endoreg_db/models/other/distribution/__init__.py +9 -7
  201. endoreg_db/models/other/distribution/base_value_distribution.py +3 -1
  202. endoreg_db/models/other/distribution/date_value_distribution.py +19 -5
  203. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +3 -1
  204. endoreg_db/models/other/distribution/numeric_value_distribution.py +34 -9
  205. endoreg_db/models/other/emission/__init__.py +1 -1
  206. endoreg_db/models/other/emission/emission_factor.py +9 -3
  207. endoreg_db/models/other/information_source.py +15 -5
  208. endoreg_db/models/other/material.py +3 -1
  209. endoreg_db/models/other/transport_route.py +3 -1
  210. endoreg_db/models/other/unit.py +6 -2
  211. endoreg_db/models/report/report.py +0 -1
  212. endoreg_db/models/requirement/requirement.py +84 -27
  213. endoreg_db/models/requirement/requirement_error.py +5 -6
  214. endoreg_db/models/requirement/requirement_evaluation/__init__.py +1 -1
  215. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +8 -8
  216. endoreg_db/models/requirement/requirement_evaluation/get_values.py +3 -3
  217. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +24 -8
  218. endoreg_db/models/requirement/requirement_operator.py +28 -8
  219. endoreg_db/models/requirement/requirement_set.py +34 -11
  220. endoreg_db/models/state/__init__.py +1 -0
  221. endoreg_db/models/state/audit_ledger.py +9 -2
  222. endoreg_db/models/{media → state}/processing_history/__init__.py +1 -3
  223. endoreg_db/models/state/processing_history/processing_history.py +136 -0
  224. endoreg_db/models/state/raw_pdf.py +0 -1
  225. endoreg_db/models/state/video.py +2 -3
  226. endoreg_db/models/utils.py +4 -2
  227. endoreg_db/queries/__init__.py +2 -6
  228. endoreg_db/queries/annotations/__init__.py +1 -3
  229. endoreg_db/queries/annotations/legacy.py +37 -26
  230. endoreg_db/root_urls.py +3 -4
  231. endoreg_db/schemas/examination_evaluation.py +3 -0
  232. endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +249 -163
  233. endoreg_db/serializers/__init__.py +2 -8
  234. endoreg_db/serializers/administration/__init__.py +1 -2
  235. endoreg_db/serializers/administration/ai/__init__.py +0 -1
  236. endoreg_db/serializers/administration/ai/active_model.py +3 -1
  237. endoreg_db/serializers/administration/ai/ai_model.py +5 -3
  238. endoreg_db/serializers/administration/ai/model_type.py +3 -1
  239. endoreg_db/serializers/administration/center.py +7 -2
  240. endoreg_db/serializers/administration/gender.py +4 -2
  241. endoreg_db/serializers/anonymization.py +13 -13
  242. endoreg_db/serializers/evaluation/examination_evaluation.py +0 -1
  243. endoreg_db/serializers/examination/__init__.py +1 -1
  244. endoreg_db/serializers/examination/base.py +12 -13
  245. endoreg_db/serializers/examination/dropdown.py +6 -7
  246. endoreg_db/serializers/examination_serializer.py +3 -6
  247. endoreg_db/serializers/finding/__init__.py +1 -1
  248. endoreg_db/serializers/finding/finding.py +14 -7
  249. endoreg_db/serializers/finding_classification/__init__.py +3 -3
  250. endoreg_db/serializers/finding_classification/choice.py +3 -3
  251. endoreg_db/serializers/finding_classification/classification.py +2 -4
  252. endoreg_db/serializers/label_video_segment/__init__.py +5 -3
  253. endoreg_db/serializers/{label → label_video_segment}/image_classification_annotation.py +5 -5
  254. endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
  255. endoreg_db/serializers/{label → label_video_segment/label}/label.py +1 -1
  256. endoreg_db/serializers/label_video_segment/label_video_segment.py +338 -228
  257. endoreg_db/serializers/meta/__init__.py +1 -2
  258. endoreg_db/serializers/meta/sensitive_meta_detail.py +28 -13
  259. endoreg_db/serializers/meta/sensitive_meta_update.py +51 -46
  260. endoreg_db/serializers/meta/sensitive_meta_verification.py +19 -16
  261. endoreg_db/serializers/misc/__init__.py +2 -2
  262. endoreg_db/serializers/misc/file_overview.py +11 -7
  263. endoreg_db/serializers/misc/stats.py +10 -8
  264. endoreg_db/serializers/misc/translatable_field_mix_in.py +6 -6
  265. endoreg_db/serializers/misc/upload_job.py +32 -29
  266. endoreg_db/serializers/patient/__init__.py +2 -1
  267. endoreg_db/serializers/patient/patient.py +32 -15
  268. endoreg_db/serializers/patient/patient_dropdown.py +11 -3
  269. endoreg_db/serializers/patient_examination/__init__.py +1 -1
  270. endoreg_db/serializers/patient_examination/patient_examination.py +67 -40
  271. endoreg_db/serializers/patient_finding/__init__.py +1 -1
  272. endoreg_db/serializers/patient_finding/patient_finding.py +2 -1
  273. endoreg_db/serializers/patient_finding/patient_finding_classification.py +17 -9
  274. endoreg_db/serializers/patient_finding/patient_finding_detail.py +26 -17
  275. endoreg_db/serializers/patient_finding/patient_finding_intervention.py +7 -5
  276. endoreg_db/serializers/patient_finding/patient_finding_list.py +10 -11
  277. endoreg_db/serializers/patient_finding/patient_finding_write.py +36 -27
  278. endoreg_db/serializers/pdf/__init__.py +1 -3
  279. endoreg_db/serializers/requirements/requirement_schema.py +1 -6
  280. endoreg_db/serializers/sensitive_meta_serializer.py +100 -81
  281. endoreg_db/serializers/video/__init__.py +2 -2
  282. endoreg_db/serializers/video/{segmentation.py → video_file.py} +66 -47
  283. endoreg_db/serializers/video/video_file_brief.py +6 -2
  284. endoreg_db/serializers/video/video_file_detail.py +36 -23
  285. endoreg_db/serializers/video/video_file_list.py +4 -2
  286. endoreg_db/serializers/video/video_processing_history.py +54 -50
  287. endoreg_db/services/__init__.py +1 -1
  288. endoreg_db/services/anonymization.py +2 -2
  289. endoreg_db/services/examination_evaluation.py +40 -17
  290. endoreg_db/services/model_meta_from_hf.py +76 -0
  291. endoreg_db/services/polling_coordinator.py +101 -70
  292. endoreg_db/services/pseudonym_service.py +27 -22
  293. endoreg_db/services/report_import.py +6 -3
  294. endoreg_db/services/segment_sync.py +75 -59
  295. endoreg_db/services/video_import.py +6 -7
  296. endoreg_db/urls/__init__.py +2 -2
  297. endoreg_db/urls/ai.py +7 -25
  298. endoreg_db/urls/anonymization.py +61 -15
  299. endoreg_db/urls/auth.py +4 -4
  300. endoreg_db/urls/classification.py +4 -9
  301. endoreg_db/urls/examination.py +27 -18
  302. endoreg_db/urls/media.py +27 -34
  303. endoreg_db/urls/patient.py +11 -7
  304. endoreg_db/urls/requirements.py +3 -1
  305. endoreg_db/urls/root_urls.py +2 -3
  306. endoreg_db/urls/stats.py +24 -16
  307. endoreg_db/urls/upload.py +3 -11
  308. endoreg_db/utils/__init__.py +14 -15
  309. endoreg_db/utils/ai/__init__.py +1 -1
  310. endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
  311. endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
  312. endoreg_db/utils/ai/get.py +2 -1
  313. endoreg_db/utils/ai/inference_dataset.py +14 -15
  314. endoreg_db/utils/ai/model_training/config.py +117 -0
  315. endoreg_db/utils/ai/model_training/dataset.py +74 -0
  316. endoreg_db/utils/ai/model_training/losses.py +68 -0
  317. endoreg_db/utils/ai/model_training/metrics.py +78 -0
  318. endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
  319. endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
  320. endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
  321. endoreg_db/utils/ai/multilabel_classification_net.py +21 -6
  322. endoreg_db/utils/ai/predict.py +4 -4
  323. endoreg_db/utils/ai/preprocess.py +19 -11
  324. endoreg_db/utils/calc_duration_seconds.py +4 -4
  325. endoreg_db/utils/case_generator/lab_sample_factory.py +3 -4
  326. endoreg_db/utils/check_video_files.py +74 -47
  327. endoreg_db/utils/cropping.py +10 -9
  328. endoreg_db/utils/dataloader.py +11 -3
  329. endoreg_db/utils/dates.py +3 -4
  330. endoreg_db/utils/defaults/set_default_center.py +7 -6
  331. endoreg_db/utils/env.py +6 -2
  332. endoreg_db/utils/extract_specific_frames.py +24 -9
  333. endoreg_db/utils/file_operations.py +30 -18
  334. endoreg_db/utils/fix_video_path_direct.py +57 -41
  335. endoreg_db/utils/frame_anonymization_utils.py +157 -157
  336. endoreg_db/utils/hashs.py +3 -18
  337. endoreg_db/utils/links/requirement_link.py +96 -52
  338. endoreg_db/utils/ocr.py +30 -25
  339. endoreg_db/utils/operation_log.py +61 -0
  340. endoreg_db/utils/parse_and_generate_yaml.py +12 -13
  341. endoreg_db/utils/paths.py +6 -6
  342. endoreg_db/utils/permissions.py +40 -24
  343. endoreg_db/utils/pipelines/process_video_dir.py +50 -26
  344. endoreg_db/utils/product/sum_emissions.py +5 -3
  345. endoreg_db/utils/product/sum_weights.py +4 -2
  346. endoreg_db/utils/pydantic_models/__init__.py +3 -4
  347. endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +207 -107
  348. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +252 -65
  349. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +27 -10
  350. endoreg_db/utils/setup_config.py +21 -5
  351. endoreg_db/utils/storage.py +3 -1
  352. endoreg_db/utils/translation.py +19 -15
  353. endoreg_db/utils/uuid.py +1 -0
  354. endoreg_db/utils/validate_endo_roi.py +12 -4
  355. endoreg_db/utils/validate_subcategory_dict.py +26 -24
  356. endoreg_db/utils/validate_video_detailed.py +207 -149
  357. endoreg_db/utils/video/__init__.py +7 -3
  358. endoreg_db/utils/video/extract_frames.py +30 -18
  359. endoreg_db/utils/video/ffmpeg_wrapper.py +217 -52
  360. endoreg_db/utils/video/names.py +11 -6
  361. endoreg_db/utils/video/streaming_processor.py +175 -101
  362. endoreg_db/utils/video/video_splitter.py +30 -19
  363. endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +59 -50
  364. endoreg_db/views/__init__.py +0 -20
  365. endoreg_db/views/anonymization/__init__.py +6 -2
  366. endoreg_db/views/anonymization/media_management.py +2 -6
  367. endoreg_db/views/anonymization/overview.py +34 -1
  368. endoreg_db/views/anonymization/validate.py +79 -18
  369. endoreg_db/views/auth/__init__.py +1 -1
  370. endoreg_db/views/auth/keycloak.py +16 -14
  371. endoreg_db/views/examination/__init__.py +12 -15
  372. endoreg_db/views/examination/examination.py +5 -5
  373. endoreg_db/views/examination/examination_manifest_cache.py +5 -5
  374. endoreg_db/views/examination/get_finding_classification_choices.py +8 -5
  375. endoreg_db/views/examination/get_finding_classifications.py +9 -7
  376. endoreg_db/views/examination/get_findings.py +8 -10
  377. endoreg_db/views/examination/get_instruments.py +3 -2
  378. endoreg_db/views/examination/get_interventions.py +1 -1
  379. endoreg_db/views/finding/__init__.py +2 -2
  380. endoreg_db/views/finding/finding.py +58 -54
  381. endoreg_db/views/finding/get_classifications.py +1 -1
  382. endoreg_db/views/finding/get_interventions.py +1 -1
  383. endoreg_db/views/finding_classification/__init__.py +5 -5
  384. endoreg_db/views/finding_classification/finding_classification.py +5 -6
  385. endoreg_db/views/finding_classification/get_classification_choices.py +3 -4
  386. endoreg_db/views/media/__init__.py +13 -13
  387. endoreg_db/views/media/pdf_media.py +9 -9
  388. endoreg_db/views/media/sensitive_metadata.py +10 -7
  389. endoreg_db/views/media/video_media.py +4 -4
  390. endoreg_db/views/meta/__init__.py +1 -1
  391. endoreg_db/views/meta/sensitive_meta_list.py +20 -22
  392. endoreg_db/views/meta/sensitive_meta_verification.py +14 -11
  393. endoreg_db/views/misc/__init__.py +6 -34
  394. endoreg_db/views/misc/center.py +2 -1
  395. endoreg_db/views/misc/csrf.py +2 -1
  396. endoreg_db/views/misc/gender.py +2 -1
  397. endoreg_db/views/misc/stats.py +141 -106
  398. endoreg_db/views/patient/__init__.py +1 -3
  399. endoreg_db/views/patient/patient.py +141 -99
  400. endoreg_db/views/patient_examination/__init__.py +5 -5
  401. endoreg_db/views/patient_examination/patient_examination.py +43 -42
  402. endoreg_db/views/patient_examination/patient_examination_create.py +10 -15
  403. endoreg_db/views/patient_examination/patient_examination_detail.py +12 -15
  404. endoreg_db/views/patient_examination/patient_examination_list.py +21 -17
  405. endoreg_db/views/patient_examination/video.py +114 -80
  406. endoreg_db/views/patient_finding/__init__.py +1 -1
  407. endoreg_db/views/patient_finding/patient_finding.py +17 -10
  408. endoreg_db/views/patient_finding/patient_finding_optimized.py +127 -95
  409. endoreg_db/views/patient_finding_classification/__init__.py +1 -1
  410. endoreg_db/views/patient_finding_classification/pfc_create.py +35 -27
  411. endoreg_db/views/report/reimport.py +1 -1
  412. endoreg_db/views/report/report_stream.py +5 -8
  413. endoreg_db/views/requirement/__init__.py +2 -1
  414. endoreg_db/views/requirement/evaluate.py +7 -9
  415. endoreg_db/views/requirement/lookup.py +2 -3
  416. endoreg_db/views/requirement/lookup_store.py +0 -1
  417. endoreg_db/views/requirement/requirement_utils.py +2 -4
  418. endoreg_db/views/stats/__init__.py +4 -4
  419. endoreg_db/views/stats/stats_views.py +152 -115
  420. endoreg_db/views/video/__init__.py +18 -27
  421. endoreg_db/views/{ai → video/ai}/__init__.py +2 -2
  422. endoreg_db/views/{ai → video/ai}/label.py +20 -16
  423. endoreg_db/views/video/correction.py +5 -6
  424. endoreg_db/views/video/reimport.py +134 -99
  425. endoreg_db/views/video/segments_crud.py +134 -44
  426. endoreg_db/views/video/video_apply_mask.py +13 -12
  427. endoreg_db/views/video/video_correction.py +2 -1
  428. endoreg_db/views/video/video_download_processed.py +15 -15
  429. endoreg_db/views/video/video_meta_stats.py +7 -6
  430. endoreg_db/views/video/video_processing_history.py +3 -2
  431. endoreg_db/views/video/video_remove_frames.py +13 -12
  432. endoreg_db/views/video/video_stream.py +110 -82
  433. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
  434. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +436 -433
  435. endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +0 -119
  436. endoreg_db/management/commands/import_fallback_video.py +0 -203
  437. endoreg_db/management/commands/import_video.py +0 -422
  438. endoreg_db/management/commands/import_video_with_classification.py +0 -367
  439. endoreg_db/models/media/processing_history/processing_history.py +0 -96
  440. endoreg_db/serializers/label/__init__.py +0 -7
  441. endoreg_db/serializers/label_video_segment/_lvs_create.py +0 -149
  442. endoreg_db/serializers/label_video_segment/_lvs_update.py +0 -138
  443. endoreg_db/serializers/label_video_segment/_lvs_validate.py +0 -149
  444. endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +0 -99
  445. endoreg_db/serializers/label_video_segment/label_video_segment_update.py +0 -163
  446. endoreg_db/services/__old/pdf_import.py +0 -1487
  447. endoreg_db/services/__old/video_import.py +0 -1306
  448. endoreg_db/tasks/upload_tasks.py +0 -216
  449. endoreg_db/tasks/video_ingest.py +0 -161
  450. endoreg_db/tasks/video_processing_tasks.py +0 -327
  451. endoreg_db/views/misc/translation.py +0 -182
  452. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
  453. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
@@ -3,7 +3,6 @@ from subprocess import run
3
3
  from typing import TYPE_CHECKING, Dict, List, Tuple, Union, cast
4
4
 
5
5
  from django.db import models
6
- from pydantic import BaseModel
7
6
 
8
7
  from endoreg_db.utils.links.requirement_link import RequirementLinks
9
8
 
@@ -124,9 +123,13 @@ class Requirement(models.Model):
124
123
 
125
124
  @property
126
125
  def operator_instructions_parsed(self):
127
- from endoreg_db.models.requirement.requirement_operator import RequirementOperator
126
+ from endoreg_db.models.requirement.requirement_operator import (
127
+ RequirementOperator,
128
+ )
128
129
 
129
- instructions = RequirementOperator.parse_instructions(self.operator_instructions)
130
+ instructions = RequirementOperator.parse_instructions(
131
+ self.operator_instructions
132
+ )
130
133
  return instructions
131
134
 
132
135
  numeric_value = models.FloatField(
@@ -268,7 +271,9 @@ class Requirement(models.Model):
268
271
  )
269
272
 
270
273
  if TYPE_CHECKING:
271
- requirement_types = cast(models.manager.RelatedManager["RequirementType"], requirement_types)
274
+ requirement_types = cast(
275
+ models.manager.RelatedManager["RequirementType"], requirement_types
276
+ )
272
277
  operator = models.ForeignKey["RequirementOperator"]
273
278
  # requirement_sets = cast(models.manager.RelatedManager["RequirementSet"], requirement_sets)
274
279
  examinations = cast(models.manager.RelatedManager["Examination"], examinations)
@@ -292,7 +297,9 @@ class Requirement(models.Model):
292
297
  models.manager.RelatedManager["FindingClassificationChoice"],
293
298
  finding_classification_choices,
294
299
  )
295
- finding_interventions = cast(models.manager.RelatedManager["FindingIntervention"], finding_interventions)
300
+ finding_interventions = cast(
301
+ models.manager.RelatedManager["FindingIntervention"], finding_interventions
302
+ )
296
303
  medications = cast(models.manager.RelatedManager["Medication"], medications)
297
304
  medication_indications = cast(
298
305
  models.manager.RelatedManager["MedicationIndication"],
@@ -302,7 +309,9 @@ class Requirement(models.Model):
302
309
  models.manager.RelatedManager["MedicationIntakeTime"],
303
310
  medication_intake_times,
304
311
  )
305
- medication_schedules = cast(models.manager.RelatedManager["MedicationSchedule"], medication_schedules)
312
+ medication_schedules = cast(
313
+ models.manager.RelatedManager["MedicationSchedule"], medication_schedules
314
+ )
306
315
  genders = cast(models.manager.RelatedManager["Gender"], genders)
307
316
 
308
317
  def natural_key(self):
@@ -370,18 +379,32 @@ class Requirement(models.Model):
370
379
  # requirement_sets is not part of RequirementLinks (avoids circular import); collect other related models
371
380
  models_dict = RequirementLinks(
372
381
  examinations=[_ for _ in self.examinations.all() if _ is not None],
373
- examination_indications=[_ for _ in self.examination_indications.all() if _ is not None],
382
+ examination_indications=[
383
+ _ for _ in self.examination_indications.all() if _ is not None
384
+ ],
374
385
  lab_values=[_ for _ in self.lab_values.all() if _ is not None],
375
386
  diseases=[_ for _ in self.diseases.all() if _ is not None],
376
- disease_classification_choices=[_ for _ in self.disease_classification_choices.all() if _ is not None],
387
+ disease_classification_choices=[
388
+ _ for _ in self.disease_classification_choices.all() if _ is not None
389
+ ],
377
390
  events=[_ for _ in self.events.all() if _ is not None],
378
391
  findings=[_ for _ in self.findings.all() if _ is not None],
379
- finding_classifications=[_ for _ in self.finding_classifications.all() if _ is not None],
380
- finding_classification_choices=[_ for _ in self.finding_classification_choices.all() if _ is not None],
381
- finding_interventions=[_ for _ in self.finding_interventions.all() if _ is not None],
392
+ finding_classifications=[
393
+ _ for _ in self.finding_classifications.all() if _ is not None
394
+ ],
395
+ finding_classification_choices=[
396
+ _ for _ in self.finding_classification_choices.all() if _ is not None
397
+ ],
398
+ finding_interventions=[
399
+ _ for _ in self.finding_interventions.all() if _ is not None
400
+ ],
382
401
  medications=[_ for _ in self.medications.all() if _ is not None],
383
- medication_indications=[_ for _ in self.medication_indications.all() if _ is not None],
384
- medication_intake_times=[_ for _ in self.medication_intake_times.all() if _ is not None],
402
+ medication_indications=[
403
+ _ for _ in self.medication_indications.all() if _ is not None
404
+ ],
405
+ medication_intake_times=[
406
+ _ for _ in self.medication_intake_times.all() if _ is not None
407
+ ],
385
408
  )
386
409
  return models_dict
387
410
 
@@ -457,7 +480,9 @@ class Requirement(models.Model):
457
480
  - bei ungültigem Modus
458
481
  - bei komplett falschen Input-Typen / fehlender .links-Struktur
459
482
  """
460
- from endoreg_db.models.requirement.requirement_error import RequirementEvaluationError
483
+ from endoreg_db.models.requirement.requirement_error import (
484
+ RequirementEvaluationError,
485
+ )
461
486
 
462
487
  # --- Mode validieren -------------------------------------------------
463
488
  if mode not in ["strict", "loose"]:
@@ -520,7 +545,11 @@ class Requirement(models.Model):
520
545
  "Für diese Voraussetzung müssen alle passenden Einträge vorliegen, aber es wurden keine entsprechenden Datensätze gefunden.",
521
546
  )
522
547
  if queryset_mode == "min_count":
523
- required = queryset_min_count if queryset_min_count is not None else 1
548
+ required = (
549
+ queryset_min_count
550
+ if queryset_min_count is not None
551
+ else 1
552
+ )
524
553
  if required > 0:
525
554
  return (
526
555
  False,
@@ -534,7 +563,9 @@ class Requirement(models.Model):
534
563
  queryset_item_count = 0
535
564
 
536
565
  for item in _input:
537
- if not hasattr(item, "links") or not isinstance(item.links, RequirementLinks):
566
+ if not hasattr(item, "links") or not isinstance(
567
+ item.links, RequirementLinks
568
+ ):
538
569
  raise RequirementEvaluationError(
539
570
  requirement=self,
540
571
  code="MISSING_LINKS_ATTR",
@@ -557,7 +588,9 @@ class Requirement(models.Model):
557
588
  aggregated_input_links_data[link_key] = []
558
589
  aggregated_input_links_data[link_key].extend(link_list)
559
590
 
560
- per_item_args = tuple(item if arg is _input else arg for arg in args)
591
+ per_item_args = tuple(
592
+ item if arg is _input else arg for arg in args
593
+ )
561
594
  op_kwargs = kwargs.copy()
562
595
  op_kwargs["requirement"] = self
563
596
  op_kwargs["original_input_args"] = per_item_args
@@ -580,7 +613,11 @@ class Requirement(models.Model):
580
613
  exc,
581
614
  )
582
615
  item_operator_results.append(False)
583
- item_result = evaluate_result_list_func(item_operator_results) if item_operator_results else True
616
+ item_result = (
617
+ evaluate_result_list_func(item_operator_results)
618
+ if item_operator_results
619
+ else True
620
+ )
584
621
  else:
585
622
  # keine Operatoren -> Bedingung erfüllt, wenn Requirement selbst keine Bedingungen hat
586
623
  item_result = not requirement_has_conditions
@@ -599,7 +636,9 @@ class Requirement(models.Model):
599
636
  "Für diese Voraussetzung müssen alle relevanten Einträge die Bedingung erfüllen.",
600
637
  )
601
638
  elif queryset_mode == "min_count":
602
- required = queryset_min_count if queryset_min_count is not None else 1
639
+ required = (
640
+ queryset_min_count if queryset_min_count is not None else 1
641
+ )
603
642
  if queryset_true_count < max(required, 0):
604
643
  return (
605
644
  False,
@@ -612,18 +651,28 @@ class Requirement(models.Model):
612
651
  raise RequirementEvaluationError(
613
652
  requirement=self,
614
653
  code="INVALID_INPUT_TYPE",
615
- technical_message=(f"Input type {type(_input)} is not among expected models: {self.expected_models} nor a QuerySet of expected models."),
616
- user_message=("Diese Voraussetzung wurde mit einem nicht passenden Datentyp aufgerufen und kann aktuell nicht korrekt geprüft werden."),
654
+ technical_message=(
655
+ f"Input type {type(_input)} is not among expected models: {self.expected_models} nor a QuerySet of expected models."
656
+ ),
657
+ user_message=(
658
+ "Diese Voraussetzung wurde mit einem nicht passenden Datentyp aufgerufen und kann aktuell nicht korrekt geprüft werden."
659
+ ),
617
660
  meta={"input_type": str(type(_input))},
618
661
  )
619
662
 
620
663
  # Einzelinstanz erwarteten Typs
621
- if not hasattr(_input, "links") or not isinstance(_input.links, RequirementLinks):
664
+ if not hasattr(_input, "links") or not isinstance(
665
+ _input.links, RequirementLinks
666
+ ):
622
667
  raise RequirementEvaluationError(
623
668
  requirement=self,
624
669
  code="MISSING_LINKS_ATTR",
625
- technical_message=(f"Input {_input} of type {type(_input)} does not have a valid .links attribute of type RequirementLinks."),
626
- user_message=("Für die Auswertung dieser Voraussetzung fehlen die intern benötigten Verknüpfungsinformationen."),
670
+ technical_message=(
671
+ f"Input {_input} of type {type(_input)} does not have a valid .links attribute of type RequirementLinks."
672
+ ),
673
+ user_message=(
674
+ "Für die Auswertung dieser Voraussetzung fehlen die intern benötigten Verknüpfungsinformationen."
675
+ ),
627
676
  meta={"input_type": str(type(_input))},
628
677
  )
629
678
 
@@ -640,7 +689,9 @@ class Requirement(models.Model):
640
689
  # Deduplizieren der aggregierten Links
641
690
  for key in aggregated_input_links_data:
642
691
  try:
643
- aggregated_input_links_data[key] = list(dict.fromkeys(aggregated_input_links_data[key]))
692
+ aggregated_input_links_data[key] = list(
693
+ dict.fromkeys(aggregated_input_links_data[key])
694
+ )
644
695
  except TypeError:
645
696
  # Fallback für nicht-hashbare Items
646
697
  tmp: list = []
@@ -699,7 +750,9 @@ class Requirement(models.Model):
699
750
  **op_kwargs,
700
751
  )
701
752
  operator_results.append(operator_result)
702
- operator_details.append(f"{operator.name}: {'erfüllt' if operator_result else 'nicht erfüllt'}")
753
+ operator_details.append(
754
+ f"{operator.name}: {'erfüllt' if operator_result else 'nicht erfüllt'}"
755
+ )
703
756
  except Exception as e:
704
757
  operator_results.append(False)
705
758
  operator_details.append(f"{operator.name}: technischer Fehler ({e})")
@@ -718,7 +771,11 @@ class Requirement(models.Model):
718
771
  elif len(operator_results) == 1:
719
772
  details = operator_details[0]
720
773
  else:
721
- failed_details = [detail for detail, result in zip(operator_details, operator_results) if not result]
774
+ failed_details = [
775
+ detail
776
+ for detail, result in zip(operator_details, operator_results)
777
+ if not result
778
+ ]
722
779
  if failed_details:
723
780
  details = "; ".join(failed_details)
724
781
  else:
@@ -1,5 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Optional, Any, Mapping, TYPE_CHECKING
3
+
3
4
  if TYPE_CHECKING:
4
5
  from endoreg_db.models.requirement.requirement import Requirement
5
6
 
@@ -14,13 +15,13 @@ class RequirementEvaluationErrorContext:
14
15
  - user_message: optional pre-formatted text for UI
15
16
  - meta: optional arbitrary payload for logging / debugging
16
17
  """
18
+
17
19
  requirement: "Requirement"
18
20
  code: str
19
21
  technical_message: str
20
22
  user_message: Optional[str] = None
21
23
  description: Optional[str] = None
22
24
  meta: Optional[Mapping[str, Any]] = None
23
-
24
25
 
25
26
 
26
27
  class RequirementEvaluationError(Exception):
@@ -36,7 +37,7 @@ class RequirementEvaluationError(Exception):
36
37
 
37
38
  def __init__(
38
39
  self,
39
- requirement: "Requirement",
40
+ requirement: "Requirement",
40
41
  code: str,
41
42
  technical_message: str,
42
43
  user_message: Optional[str] = None,
@@ -52,18 +53,16 @@ class RequirementEvaluationError(Exception):
52
53
  )
53
54
  # Base Exception message = technical message
54
55
  super().__init__(technical_message, *args)
55
-
56
-
57
56
 
58
57
  @property
59
- def requirement(self) -> "Requirement":
58
+ def requirement(self) -> "Requirement":
60
59
  return self.context.requirement
61
60
 
62
61
  @property
63
62
  def requirement_name(self) -> str:
64
63
  # This is the DB name, *not* the internal Python repr
65
64
  return getattr(self.context.requirement, "name", "unknown")
66
-
65
+
67
66
  @property
68
67
  def requirement_description(self) -> str:
69
68
  return getattr(self.context.requirement, "description")
@@ -3,4 +3,4 @@
3
3
 
4
4
  __all__ = [
5
5
  # "get_operator_function"
6
- ]
6
+ ]
@@ -8,6 +8,7 @@ logger = logging.getLogger(__name__)
8
8
 
9
9
  RequirementStatus = Literal["PASSED", "FAILED", "BLOCKED", "ERROR"]
10
10
 
11
+
11
12
  def topologically_sort_requirement_sets(
12
13
  sets: Iterable[RequirementSet],
13
14
  ) -> List[RequirementSet]:
@@ -44,8 +45,6 @@ def topologically_sort_requirement_sets(
44
45
  return [id_map[sid] for sid in ordered_ids]
45
46
 
46
47
 
47
-
48
-
49
48
  def evaluate_requirement_sets_with_dependencies(
50
49
  sets: Iterable[RequirementSet],
51
50
  *args,
@@ -145,9 +144,7 @@ def evaluate_requirement_sets_with_dependencies(
145
144
  req_set.id,
146
145
  req.id,
147
146
  )
148
- msg = (
149
- f"Technischer Fehler bei der Auswertung von '{req.name}': {exc}"
150
- )
147
+ msg = f"Technischer Fehler bei der Auswertung von '{req.name}': {exc}"
151
148
  set_results[set_id][req.id] = ("ERROR", msg)
152
149
 
153
150
  # derive set status
@@ -161,7 +158,9 @@ def evaluate_requirement_sets_with_dependencies(
161
158
 
162
159
  return set_results
163
160
 
164
- #TODO Remove when sure that no per requirement evaluation will happen. Needs the depends on attribute for the reatuirements.
161
+
162
+ # TODO Remove when sure that no per requirement evaluation will happen. Needs the depends on attribute for the reatuirements.
163
+
165
164
 
166
165
  def topologically_sort_requirements(
167
166
  requirements: Iterable[Requirement],
@@ -200,6 +199,7 @@ def topologically_sort_requirements(
200
199
 
201
200
  return [id_map[rid] for rid in ordered_ids]
202
201
 
202
+
203
203
  def evaluate_requirements_with_dependencies(
204
204
  requirements: Iterable[Requirement],
205
205
  *args,
@@ -252,7 +252,7 @@ def evaluate_requirements_with_dependencies(
252
252
  met = False
253
253
  results[req.id] = (
254
254
  "FAILED",
255
- f"Nachtragebedarf bei der Auswertung von '{req.name}': {exc}"
255
+ f"Nachtragebedarf bei der Auswertung von '{req.name}': {exc}",
256
256
  )
257
257
  except Exception as exc:
258
258
  met = False
@@ -265,4 +265,4 @@ def evaluate_requirements_with_dependencies(
265
265
  status: RequirementStatus = "PASSED" if met else "FAILED"
266
266
  results[req.id] = (status, details)
267
267
 
268
- return results
268
+ return results
@@ -8,6 +8,7 @@ if TYPE_CHECKING:
8
8
  Requirement,
9
9
  )
10
10
 
11
+
11
12
  def get_values_from_kwargs(
12
13
  requirement: "Requirement",
13
14
  patient: Optional["Patient"] = None,
@@ -16,9 +17,9 @@ def get_values_from_kwargs(
16
17
  ) -> dict:
17
18
  """
18
19
  Aggregates and validates input values required for evaluating a requirement.
19
-
20
+
20
21
  Checks the requirement's types to ensure that necessary parameters such as `patient` or `patient_examination` are provided when required. Raises a ValueError if a required parameter is missing. Returns a dictionary containing the validated inputs and any additional keyword arguments.
21
-
22
+
22
23
  Returns:
23
24
  A dictionary with keys for 'patient', 'patient_examination', and any extra keyword arguments.
24
25
  """
@@ -37,4 +38,3 @@ def get_values_from_kwargs(
37
38
 
38
39
  # Prepare and return the extracted values
39
40
  return {"patient": patient, "patient_examination": patient_examination, **kwargs}
40
-
@@ -58,7 +58,9 @@ class DataModelEntry(BaseModel):
58
58
  @field_validator("model")
59
59
  @classmethod
60
60
  def ensure_model_subclass(cls, value: type[models.Model]) -> type[models.Model]:
61
- if not issubclass(value, models.Model): # Defensive: ensure provided class is a Django model
61
+ if not issubclass(
62
+ value, models.Model
63
+ ): # Defensive: ensure provided class is a Django model
62
64
  raise TypeError(f"{value!r} is not a Django model class")
63
65
  return value
64
66
 
@@ -90,32 +92,46 @@ class DataModelRegistry(BaseModel):
90
92
  DATA_MODEL_REGISTRY = DataModelRegistry(
91
93
  entries=(
92
94
  DataModelEntry(name="disease", model=Disease),
93
- DataModelEntry(name="disease_classification_choice", model=DiseaseClassificationChoice),
95
+ DataModelEntry(
96
+ name="disease_classification_choice", model=DiseaseClassificationChoice
97
+ ),
94
98
  DataModelEntry(name="disease_classification", model=DiseaseClassification),
95
99
  DataModelEntry(name="event", model=Event),
96
100
  DataModelEntry(name="event_classification", model=EventClassification),
97
- DataModelEntry(name="event_classification_choice", model=EventClassificationChoice),
101
+ DataModelEntry(
102
+ name="event_classification_choice", model=EventClassificationChoice
103
+ ),
98
104
  DataModelEntry(name="examination", model=Examination),
99
105
  DataModelEntry(name="examination_indication", model=ExaminationIndication),
100
106
  DataModelEntry(name="finding", model=Finding),
101
107
  DataModelEntry(name="finding_intervention", model=FindingIntervention),
102
108
  DataModelEntry(name="finding_classification", model=FindingClassification),
103
- DataModelEntry(name="finding_classification_choice", model=FindingClassificationChoice),
109
+ DataModelEntry(
110
+ name="finding_classification_choice", model=FindingClassificationChoice
111
+ ),
104
112
  DataModelEntry(name="lab_value", model=LabValue),
105
113
  DataModelEntry(name="patient_disease", model=PatientDisease),
106
114
  DataModelEntry(name="patient_event", model=PatientEvent),
107
115
  DataModelEntry(name="patient_examination", model=PatientExamination),
108
116
  DataModelEntry(name="patient_finding", model=PatientFinding),
109
- DataModelEntry(name="patient_finding_intervention", model=PatientFindingIntervention),
110
- DataModelEntry(name="patient_finding_classification", model=PatientFindingClassification),
117
+ DataModelEntry(
118
+ name="patient_finding_intervention", model=PatientFindingIntervention
119
+ ),
120
+ DataModelEntry(
121
+ name="patient_finding_classification", model=PatientFindingClassification
122
+ ),
111
123
  DataModelEntry(name="patient_lab_value", model=PatientLabValue),
112
124
  DataModelEntry(name="patient_lab_sample", model=PatientLabSample),
113
125
  DataModelEntry(name="patient", model=Patient),
114
126
  DataModelEntry(name="patient_medication", model=PatientMedication),
115
- DataModelEntry(name="patient_medication_schedule", model=PatientMedicationSchedule),
127
+ DataModelEntry(
128
+ name="patient_medication_schedule", model=PatientMedicationSchedule
129
+ ),
116
130
  DataModelEntry(name="gender", model=Gender),
117
131
  ),
118
132
  )
119
133
 
120
134
  data_model_dict: Dict[str, type[models.Model]] = DATA_MODEL_REGISTRY.as_mapping()
121
- data_model_dict_reverse: Dict[type[models.Model], str] = DATA_MODEL_REGISTRY.as_reverse_mapping()
135
+ data_model_dict_reverse: Dict[type[models.Model], str] = (
136
+ DATA_MODEL_REGISTRY.as_reverse_mapping()
137
+ )
@@ -4,7 +4,9 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Union
4
4
  from django.db import models
5
5
  from pydantic import BaseModel
6
6
 
7
- from endoreg_db.utils.requirement_operator_logic.new_operator_logic import REQUIREMENT_OPERATORS, model_attribute_set_any
7
+ from endoreg_db.utils.requirement_operator_logic.new_operator_logic import (
8
+ REQUIREMENT_OPERATORS,
9
+ )
8
10
 
9
11
  # see how operator evaluation function is fetched, add to docs #TODO
10
12
  # endoreg_db/utils/requirement_operator_logic/model_evaluators.py
@@ -55,12 +57,16 @@ def _parse_operator_instructions(raw: str):
55
57
  key, value = _attribute.split(":", 1)
56
58
  kwargs[key.strip()] = value.strip()
57
59
  else:
58
- raise ValueError(f"Invalid keyword argument format in target_attributes: '{entry}'. Expected format is '$key:value'.")
60
+ raise ValueError(
61
+ f"Invalid keyword argument format in target_attributes: '{entry}'. Expected format is '$key:value'."
62
+ )
59
63
  elif _prefix == "@":
60
64
  # Positional argument
61
65
  args.append(_attribute)
62
66
  else:
63
- raise ValueError(f"Invalid prefix '{_prefix}' in target_attributes entry: '{entry}'. Valid prefixes are {valid_prefixes}.")
67
+ raise ValueError(
68
+ f"Invalid prefix '{_prefix}' in target_attributes entry: '{entry}'. Valid prefixes are {valid_prefixes}."
69
+ )
64
70
  return OperatorInstructions(
65
71
  input_targets=input_targets,
66
72
  requirement_targets=input_targets,
@@ -72,7 +78,9 @@ def _parse_operator_instructions(raw: str):
72
78
  def _validate_operator_instructions(instance: "Requirement") -> bool:
73
79
  """Ensures requirement fixtures declare at least one target attribute."""
74
80
  if not instance.operator_instructions_parsed:
75
- raise ValueError(f"Requirement '{instance.name}' must declare at least one target attribute.")
81
+ raise ValueError(
82
+ f"Requirement '{instance.name}' must declare at least one target attribute."
83
+ )
76
84
  return True
77
85
 
78
86
 
@@ -101,7 +109,9 @@ class RequirementOperator(models.Model):
101
109
 
102
110
  name = models.CharField(max_length=100, unique=True)
103
111
  description = models.TextField(blank=True, null=True)
104
- evaluation_function_name = models.CharField(max_length=255, blank=True, null=True) # Added field
112
+ evaluation_function_name = models.CharField(
113
+ max_length=255, blank=True, null=True
114
+ ) # Added field
105
115
 
106
116
  objects = RequirementOperatorManager()
107
117
 
@@ -151,10 +161,18 @@ class RequirementOperator(models.Model):
151
161
  def get_operator_function(self) -> Callable[..., bool]:
152
162
  _operator_function = REQUIREMENT_OPERATORS.get(self.name)
153
163
  if not _operator_function:
154
- raise ValueError(f"Operator function for '{self.name}' not found in REQUIREMENT_OPERATORS.")
164
+ raise ValueError(
165
+ f"Operator function for '{self.name}' not found in REQUIREMENT_OPERATORS."
166
+ )
155
167
  return _operator_function
156
168
 
157
- def evaluate(self, operator_instructions: "OperatorInstructions", requirement: "Requirement", input_obj: Any, **kwargs) -> bool:
169
+ def evaluate(
170
+ self,
171
+ operator_instructions: "OperatorInstructions",
172
+ requirement: "Requirement",
173
+ input_obj: Any,
174
+ **kwargs,
175
+ ) -> bool:
158
176
  """ """
159
177
  eval_result: bool = False
160
178
  requirement_links: "RequirementLinks" = requirement.links
@@ -162,6 +180,8 @@ class RequirementOperator(models.Model):
162
180
  operator_function = self.get_operator_function()
163
181
 
164
182
  input_model = type(input_obj)
165
- assert input_model in expected_input_models, f"Input model {input_model} not in expected models {expected_input_models}"
183
+ assert input_model in expected_input_models, (
184
+ f"Input model {input_model} not in expected models {expected_input_models}"
185
+ )
166
186
 
167
187
  return eval_result
@@ -83,7 +83,7 @@ class RequirementSet(models.Model):
83
83
 
84
84
  name = models.CharField(max_length=100, unique=True)
85
85
  description = models.TextField(blank=True, null=True)
86
-
86
+
87
87
  depends_on = models.ManyToManyField(
88
88
  "self",
89
89
  symmetrical=False,
@@ -94,7 +94,7 @@ class RequirementSet(models.Model):
94
94
  "bevor dieses Set geprüft wird ('after')."
95
95
  ),
96
96
  )
97
-
97
+
98
98
  requirements = models.ManyToManyField(
99
99
  "Requirement",
100
100
  blank=True,
@@ -135,17 +135,31 @@ class RequirementSet(models.Model):
135
135
  if TYPE_CHECKING:
136
136
  from typing import Optional, cast
137
137
 
138
- from endoreg_db.models import ExaminationRequirementSet, InformationSource, Requirement, Tag
138
+ from endoreg_db.models import (
139
+ ExaminationRequirementSet,
140
+ InformationSource,
141
+ Requirement,
142
+ Tag,
143
+ )
139
144
 
140
145
  tags = cast(models.manager.RelatedManager["Tag"], tags)
141
146
  requirements = cast(models.manager.RelatedManager["Requirement"], requirements)
142
- links_to_sets = cast(models.manager.RelatedManager["RequirementSet"], links_to_sets)
143
- reqset_exam_links = cast(models.manager.RelatedManager["ExaminationRequirementSet"], reqset_exam_links)
144
- information_sources = cast(models.manager.RelatedManager["InformationSource"], information_sources)
147
+ links_to_sets = cast(
148
+ models.manager.RelatedManager["RequirementSet"], links_to_sets
149
+ )
150
+ reqset_exam_links = cast(
151
+ models.manager.RelatedManager["ExaminationRequirementSet"],
152
+ reqset_exam_links,
153
+ )
154
+ information_sources = cast(
155
+ models.manager.RelatedManager["InformationSource"], information_sources
156
+ )
145
157
  requirement_set_type: models.ForeignKey["RequirementSetType | None"]
146
158
 
147
159
  @property
148
- def links_from_sets(self) -> "models.manager.RelatedManager[RequirementSet]": ...
160
+ def links_from_sets(
161
+ self,
162
+ ) -> "models.manager.RelatedManager[RequirementSet]": ...
149
163
 
150
164
  def natural_key(self):
151
165
  """Return the natural key as a tuple containing the instance's name."""
@@ -175,7 +189,9 @@ class RequirementSet(models.Model):
175
189
  results = []
176
190
  for requirement in self.requirements.all():
177
191
  # Get the appropriate input for this specific requirement
178
- evaluation_input = self._get_evaluation_input_for_requirement(requirement, input_object)
192
+ evaluation_input = self._get_evaluation_input_for_requirement(
193
+ requirement, input_object
194
+ )
179
195
  result = requirement.evaluate(evaluation_input, mode=mode)
180
196
  results.append(result)
181
197
  return results
@@ -199,7 +215,9 @@ class RequirementSet(models.Model):
199
215
  return input_object
200
216
 
201
217
  # Import here to avoid circular imports
202
- from endoreg_db.models.medical.patient.patient_examination import PatientExamination
218
+ from endoreg_db.models.medical.patient.patient_examination import (
219
+ PatientExamination,
220
+ )
203
221
  from endoreg_db.models.medical.patient.patient_finding import PatientFinding
204
222
 
205
223
  # Handle PatientExamination -> PatientFinding conversion
@@ -239,7 +257,10 @@ class RequirementSet(models.Model):
239
257
 
240
258
  If the requirement set type is defined and matches a known type, returns the corresponding function from REQUIREMENT_SET_TYPE_FUNCTION_LOOKUP. Returns None if no matching function is found.
241
259
  """
242
- if self.requirement_set_type and self.requirement_set_type.name in REQUIREMENT_SET_TYPE_FUNCTION_LOOKUP:
260
+ if (
261
+ self.requirement_set_type
262
+ and self.requirement_set_type.name in REQUIREMENT_SET_TYPE_FUNCTION_LOOKUP
263
+ ):
243
264
  return REQUIREMENT_SET_TYPE_FUNCTION_LOOKUP[self.requirement_set_type.name]
244
265
  return None
245
266
 
@@ -260,7 +281,9 @@ class RequirementSet(models.Model):
260
281
 
261
282
  results = evaluate_r_results + evaluate_rs_results
262
283
 
263
- eval_result = self.eval_function(results) if self.eval_function else all(results)
284
+ eval_result = (
285
+ self.eval_function(results) if self.eval_function else all(results)
286
+ )
264
287
 
265
288
  return eval_result
266
289
 
@@ -3,6 +3,7 @@ from .raw_pdf import RawPdfState
3
3
  from .sensitive_meta import SensitiveMetaState
4
4
  from .video import VideoState
5
5
  from .anonymization import AnonymizationState
6
+
6
7
  __all__ = [
7
8
  "SensitiveMetaState",
8
9
  "VideoState",
@@ -127,7 +127,12 @@ class AuditLedger(models.Model):
127
127
  Returns:
128
128
  The count of unique object primary keys matching the specified type and action.
129
129
  """
130
- return AuditLedger.objects.filter(object_type=object_type, action=action).values("object_pk").distinct().count()
130
+ return (
131
+ AuditLedger.objects.filter(object_type=object_type, action=action)
132
+ .values("object_pk")
133
+ .distinct()
134
+ .count()
135
+ )
131
136
 
132
137
  def collect_counters(self):
133
138
  """
@@ -140,7 +145,9 @@ class AuditLedger(models.Model):
140
145
  return {
141
146
  "totalCases": AuditLedger._distinct("VideoFile", "created"),
142
147
  "totalVideos": AuditLedger._distinct("VideoFile", "created"),
143
- "totalAnnotations": AuditLedger.objects.filter(action="annotation_added").count(),
148
+ "totalAnnotations": AuditLedger.objects.filter(
149
+ action="annotation_added"
150
+ ).count(),
144
151
  "totalAnonymizations": AuditLedger._distinct("VideoFile", "anonymized"),
145
152
  "totalImages": AuditLedger._distinct("Image", "created"),
146
153
  "videosCompleted": AuditLedger._distinct("VideoFile", "validated"),
@@ -1,5 +1,3 @@
1
1
  from .processing_history import ProcessingHistory
2
2
 
3
- __all__ = [
4
- "ProcessingHistory"
5
- ]
3
+ __all__ = ["ProcessingHistory"]