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
@@ -1,5 +1,15 @@
1
- from endoreg_db.models import Examination, Finding, FindingClassification, PatientFinding
2
- from endoreg_db.serializers.patient_finding import PatientFindingClassificationSerializer, PatientFindingDetailSerializer, PatientFindingListSerializer, PatientFindingWriteSerializer
1
+ from endoreg_db.models import (
2
+ Examination,
3
+ Finding,
4
+ FindingClassification,
5
+ PatientFinding,
6
+ )
7
+ from endoreg_db.serializers.patient_finding import (
8
+ PatientFindingClassificationSerializer,
9
+ PatientFindingDetailSerializer,
10
+ PatientFindingListSerializer,
11
+ PatientFindingWriteSerializer,
12
+ )
3
13
 
4
14
 
5
15
  from django.db import transaction
@@ -20,30 +30,39 @@ class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
20
30
  Hochoptimiertes ViewSet für PatientFinding mit Query-Optimierung,
21
31
  Bulk-Endpoints und intelligenter Serializer-Auswahl
22
32
  """
33
+
23
34
  permission_classes = [IsAuthenticated]
24
35
  filter_backends = [DjangoFilterBackend, OrderingFilter, SearchFilter]
25
- filterset_fields = ['patient_examination__patient', 'finding', 'patient_examination__examination']
26
- ordering_fields = ['id', 'patient_examination__date_start']
27
- search_fields = ['finding__name', 'patient_examination__patient__first_name', 'patient_examination__patient__last_name']
36
+ filterset_fields = [
37
+ "patient_examination__patient",
38
+ "finding",
39
+ "patient_examination__examination",
40
+ ]
41
+ ordering_fields = ["id", "patient_examination__date_start"]
42
+ search_fields = [
43
+ "finding__name",
44
+ "patient_examination__patient__first_name",
45
+ "patient_examination__patient__last_name",
46
+ ]
28
47
 
29
48
  def get_queryset(self):
30
49
  """Optimierte QuerySet mit Prefetching basierend auf Action"""
31
50
  base_queryset = PatientFinding.objects.select_related(
32
- 'patient_examination__patient',
33
- 'patient_examination__examination',
34
- 'finding'
51
+ "patient_examination__patient",
52
+ "patient_examination__examination",
53
+ "finding",
35
54
  )
36
55
 
37
56
  # Detail-Views: fetch nested relations
38
- if self.action in ['retrieve', 'update', 'partial_update']:
57
+ if self.action in ["retrieve", "update", "partial_update"]:
39
58
  return base_queryset.prefetch_related(
40
59
  "classifications__classification",
41
60
  "classifications__choice",
42
61
  # 'locations__location_classification',
43
62
  # 'locations__location_choice',
44
- # 'morphologies__morphology_classification',
63
+ # 'morphologies__morphology_classification',
45
64
  # 'morphologies__morphology_choice',
46
- 'interventions__intervention'
65
+ "interventions__intervention",
47
66
  )
48
67
 
49
68
  # For List-Views: fetch only necessary relations
@@ -51,90 +70,90 @@ class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
51
70
 
52
71
  def get_serializer_class(self):
53
72
  """Intelligente Serializer-Auswahl basierend auf Action"""
54
- if self.action == 'list':
73
+ if self.action == "list":
55
74
  return PatientFindingListSerializer
56
- elif self.action in ['create', 'update', 'partial_update']:
75
+ elif self.action in ["create", "update", "partial_update"]:
57
76
  return PatientFindingWriteSerializer
58
77
  else:
59
78
  return PatientFindingDetailSerializer
60
79
 
61
80
  @method_decorator(cache_page(60 * 15)) # 15 Minuten Cache
62
- @method_decorator(vary_on_headers('Accept-Language'))
63
- @action(detail=False, methods=['get'])
81
+ @method_decorator(vary_on_headers("Accept-Language"))
82
+ @action(detail=False, methods=["get"])
64
83
  def examination_manifest(self, request):
65
84
  """
66
85
  Bulk-Endpoint: Liefert alle Setup-Daten für eine Examination in einem Call
67
86
  """
68
- examination_id = request.query_params.get('examination_id')
87
+ examination_id = request.query_params.get("examination_id")
69
88
  if not examination_id:
70
89
  return Response(
71
- {'error': 'examination_id parameter erforderlich'},
72
- status=status.HTTP_400_BAD_REQUEST
90
+ {"error": "examination_id parameter erforderlich"},
91
+ status=status.HTTP_400_BAD_REQUEST,
73
92
  )
74
93
 
75
94
  try:
76
95
  examination = Examination.objects.get(id=examination_id)
77
96
  except Examination.DoesNotExist:
78
97
  return Response(
79
- {'error': 'Examination nicht gefunden'},
80
- status=status.HTTP_404_NOT_FOUND
98
+ {"error": "Examination nicht gefunden"},
99
+ status=status.HTTP_404_NOT_FOUND,
81
100
  )
82
101
 
83
102
  # Alle Daten in optimierten Queries laden
84
103
  findings = examination.get_available_findings().prefetch_related(
85
- 'location_classifications__choices',
86
- 'morphology_classifications__choices'
104
+ "location_classifications__choices", "morphology_classifications__choices"
87
105
  )
88
106
 
89
107
  manifest_data = {
90
- 'examination': {
91
- 'id': examination.id,
92
- 'name': examination.name,
108
+ "examination": {
109
+ "id": examination.id,
110
+ "name": examination.name,
93
111
  # 'name_de': examination.name_de,
94
112
  # 'name_en': examination.name_en,
95
113
  },
96
- 'findings': []
114
+ "findings": [],
97
115
  }
98
116
 
99
117
  for finding in findings:
100
118
  assert isinstance(finding, Finding), "Expected Finding instance"
101
119
  finding_data = {
102
- 'id': finding.id,
103
- 'name': finding.name,
120
+ "id": finding.id,
121
+ "name": finding.name,
104
122
  # 'name_de': finding.name_de,
105
123
  # 'name_en': finding.name_en,
106
124
  "classifications": [],
107
- 'location_classifications': [],
108
- 'morphology_classifications': []
125
+ "location_classifications": [],
126
+ "morphology_classifications": [],
109
127
  }
110
128
 
111
129
  for classification_obj in finding.get_classifications():
112
- assert isinstance(classification_obj, FindingClassification), "Expected FindingClassification instance"
130
+ assert isinstance(classification_obj, FindingClassification), (
131
+ "Expected FindingClassification instance"
132
+ )
113
133
  classification_data = {
114
- 'id': classification_obj.id,
115
- 'name': classification_obj.name,
134
+ "id": classification_obj.id,
135
+ "name": classification_obj.name,
116
136
  "choices": [
117
137
  {
118
- 'id': choice.id,
119
- 'name': choice.name,
138
+ "id": choice.id,
139
+ "name": choice.name,
120
140
  }
121
141
  for choice in classification_obj.choices.all()
122
- ]
142
+ ],
123
143
  }
124
144
 
125
- finding_data['classifications'].append(classification_data)
145
+ finding_data["classifications"].append(classification_data)
126
146
 
127
- @action(detail=False, methods=['post'])
147
+ @action(detail=False, methods=["post"])
128
148
  def bulk_create(self, request):
129
149
  """
130
150
  Bulk-Endpoint für gleichzeitige Erstellung mehrerer PatientFindings
131
151
  Optimiert für Mobile Apps mit schlechter Verbindung
132
152
  """
133
- findings_data = request.data.get('findings', [])
153
+ findings_data = request.data.get("findings", [])
134
154
  if not findings_data:
135
155
  return Response(
136
- {'error': 'findings array required'},
137
- status=status.HTTP_400_BAD_REQUEST
156
+ {"error": "findings array required"}, status=status.HTTP_400_BAD_REQUEST
138
157
  )
139
158
 
140
159
  created_findings = []
@@ -146,33 +165,34 @@ class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
146
165
  if serializer.is_valid():
147
166
  try:
148
167
  finding = serializer.save()
149
- created_findings.append({
150
- 'index': i,
151
- 'id': finding.id,
152
- 'status': 'created'
153
- })
168
+ created_findings.append(
169
+ {"index": i, "id": finding.id, "status": "created"}
170
+ )
154
171
  except Exception as e:
155
- errors.append({
156
- 'index': i,
157
- 'error': str(e),
158
- 'status': 'error'
159
- })
172
+ errors.append({"index": i, "error": str(e), "status": "error"})
160
173
  else:
161
- errors.append({
162
- 'index': i,
163
- 'errors': serializer.errors,
164
- 'status': 'validation_error'
165
- })
166
-
167
- return Response({
168
- 'created': created_findings,
169
- 'errors': errors,
170
- 'total_processed': len(findings_data),
171
- 'success_count': len(created_findings),
172
- 'error_count': len(errors)
173
- }, status=status.HTTP_201_CREATED if created_findings else status.HTTP_400_BAD_REQUEST)
174
-
175
- @action(detail=True, methods=['post'])
174
+ errors.append(
175
+ {
176
+ "index": i,
177
+ "errors": serializer.errors,
178
+ "status": "validation_error",
179
+ }
180
+ )
181
+
182
+ return Response(
183
+ {
184
+ "created": created_findings,
185
+ "errors": errors,
186
+ "total_processed": len(findings_data),
187
+ "success_count": len(created_findings),
188
+ "error_count": len(errors),
189
+ },
190
+ status=status.HTTP_201_CREATED
191
+ if created_findings
192
+ else status.HTTP_400_BAD_REQUEST,
193
+ )
194
+
195
+ @action(detail=True, methods=["post"])
176
196
  def add_classification(self, request, pk=None):
177
197
  """
178
198
  Create and link a PatientFindingClassification to the PatientFinding
@@ -185,32 +205,38 @@ class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
185
205
 
186
206
  """
187
207
  patient_finding = self.get_object()
188
- assert isinstance(patient_finding, PatientFinding), "Expected PatientFinding instance"
208
+ assert isinstance(patient_finding, PatientFinding), (
209
+ "Expected PatientFinding instance"
210
+ )
189
211
  classification_data = request.data
190
212
 
191
213
  # Validierung
192
- classification_id = classification_data.get('classification_id')
193
- choice_id = classification_data.get('choice_id')
214
+ classification_id = classification_data.get("classification_id")
215
+ choice_id = classification_data.get("choice_id")
194
216
 
195
217
  if not classification_id or not choice_id:
196
218
  return Response(
197
- {'error': 'classification und choice erforderlich'},
198
- status=status.HTTP_400_BAD_REQUEST
219
+ {"error": "classification und choice erforderlich"},
220
+ status=status.HTTP_400_BAD_REQUEST,
199
221
  )
200
222
 
201
223
  patient_finding.add_classification(classification_id, choice_id)
202
224
  try:
203
- patient_finding_classification = patient_finding.add_classification(classification_id, choice_id)
204
- serializer = PatientFindingClassificationSerializer(patient_finding_classification)
225
+ patient_finding_classification = patient_finding.add_classification(
226
+ classification_id, choice_id
227
+ )
228
+ serializer = PatientFindingClassificationSerializer(
229
+ patient_finding_classification
230
+ )
205
231
  return Response(serializer.data, status=status.HTTP_201_CREATED)
206
232
 
207
233
  except FindingClassification.DoesNotExist:
208
234
  return Response(
209
- {'error': 'location_classification nicht gefunden'},
210
- status=status.HTTP_404_NOT_FOUND
235
+ {"error": "location_classification nicht gefunden"},
236
+ status=status.HTTP_404_NOT_FOUND,
211
237
  )
212
238
 
213
- @action(detail=False, methods=['get'])
239
+ @action(detail=False, methods=["get"])
214
240
  def export_for_analysis(self, request):
215
241
  """
216
242
  Export-Endpoint für Datenanalyse mit flacher Struktur
@@ -219,41 +245,47 @@ class OptimizedPatientFindingViewSet(viewsets.ModelViewSet):
219
245
  queryset = self.filter_queryset(self.get_queryset())
220
246
 
221
247
  # Format-Parameter
222
- export_format = request.query_params.get('format', 'json')
248
+ export_format = request.query_params.get("format", "json")
223
249
 
224
250
  # Flache Datenstruktur für Analyse
225
251
  export_data = []
226
252
  for finding in queryset:
227
- assert isinstance(finding, PatientFinding), "Expected PatientFinding instance"
253
+ assert isinstance(finding, PatientFinding), (
254
+ "Expected PatientFinding instance"
255
+ )
228
256
  base_data = {
229
- 'finding_id': finding.id,
230
- 'patient_id': finding.patient_examination.patient.id,
231
- 'patient_name': finding.patient_examination.patient.get_full_name(),
232
- 'examination_type': finding.patient_examination.examination.name,
233
- 'examination_date': finding.patient_examination.date_start,
234
- 'finding_name': finding.finding.name,
257
+ "finding_id": finding.id,
258
+ "patient_id": finding.patient_examination.patient.id,
259
+ "patient_name": finding.patient_examination.patient.get_full_name(),
260
+ "examination_type": finding.patient_examination.examination.name,
261
+ "examination_date": finding.patient_examination.date_start,
262
+ "finding_name": finding.finding.name,
235
263
  }
236
264
 
237
265
  # Locations denormalisieren
238
266
  for classification in finding.classifications.all():
239
267
  classification_data = base_data.copy()
240
- classification_data.update({
241
- 'location_classification': classification.location_classification.name,
242
- 'location_choice': classification.location_choice.name,
243
- 'location_subcategories': classification.subcategories,
244
- })
268
+ classification_data.update(
269
+ {
270
+ "location_classification": classification.location_classification.name,
271
+ "location_choice": classification.location_choice.name,
272
+ "location_subcategories": classification.subcategories,
273
+ }
274
+ )
245
275
  export_data.append(classification_data)
246
276
 
247
277
  # Wenn keine Locations, trotzdem Base-Data hinzufügen
248
278
  if not finding.locations.exists():
249
279
  export_data.append(base_data)
250
280
 
251
- if export_format == 'csv':
281
+ if export_format == "csv":
252
282
  # CSV-Export implementierung würde hier hin
253
283
  pass
254
284
 
255
- return Response({
256
- 'data': export_data,
257
- 'count': len(export_data),
258
- 'exported_at': timezone.now()
259
- })
285
+ return Response(
286
+ {
287
+ "data": export_data,
288
+ "count": len(export_data),
289
+ "exported_at": timezone.now(),
290
+ }
291
+ )
@@ -2,4 +2,4 @@ from .pfc_create import create_patient_finding_classification
2
2
 
3
3
  __all__ = [
4
4
  "create_patient_finding_classification",
5
- ]
5
+ ]
@@ -4,10 +4,11 @@ from rest_framework import status
4
4
  from endoreg_db.models import (
5
5
  PatientFinding,
6
6
  FindingClassificationChoice,
7
- FindingClassification
7
+ FindingClassification,
8
8
  )
9
9
 
10
- @api_view(['POST'])
10
+
11
+ @api_view(["POST"])
11
12
  def create_patient_finding_classification(request):
12
13
  """
13
14
  Create a patient finding classification relationship.
@@ -18,50 +19,57 @@ def create_patient_finding_classification(request):
18
19
  }
19
20
  """
20
21
  try:
21
- patient_finding_id = request.data.get('patient_finding_id')
22
- choice_id = request.data.get('classification_choice_id')
23
- classification_id = request.data.get('classification_id')
24
-
22
+ patient_finding_id = request.data.get("patient_finding_id")
23
+ choice_id = request.data.get("classification_choice_id")
24
+ classification_id = request.data.get("classification_id")
25
+
25
26
  if not patient_finding_id or not choice_id:
26
27
  return Response(
27
- {'detail': 'patient_finding_id and classification_choice_id are required'},
28
- status=status.HTTP_400_BAD_REQUEST
28
+ {
29
+ "detail": "patient_finding_id and classification_choice_id are required"
30
+ },
31
+ status=status.HTTP_400_BAD_REQUEST,
29
32
  )
30
-
33
+
31
34
  # Get the objects
32
35
  try:
33
36
  patient_finding = PatientFinding.objects.get(id=patient_finding_id)
34
37
  except PatientFinding.DoesNotExist:
35
38
  return Response(
36
- {'detail': f'PatientFinding with id {patient_finding_id} not found'},
37
- status=status.HTTP_404_NOT_FOUND
39
+ {"detail": f"PatientFinding with id {patient_finding_id} not found"},
40
+ status=status.HTTP_404_NOT_FOUND,
38
41
  )
39
-
42
+
40
43
  try:
41
44
  choice = FindingClassificationChoice.objects.get(id=choice_id)
42
45
  except FindingClassificationChoice.DoesNotExist:
43
46
  return Response(
44
- {'detail': f'ClassificationChoice with id {choice_id} not found'},
45
- status=status.HTTP_404_NOT_FOUND
47
+ {"detail": f"ClassificationChoice with id {choice_id} not found"},
48
+ status=status.HTTP_404_NOT_FOUND,
46
49
  )
47
50
 
48
51
  try:
49
52
  FindingClassification.objects.get(id=classification_id)
50
53
  except FindingClassification.DoesNotExist:
51
54
  return Response(
52
- {'detail': f'Classification with id {classification_id} not found'},
53
- status=status.HTTP_404_NOT_FOUND
55
+ {"detail": f"Classification with id {classification_id} not found"},
56
+ status=status.HTTP_404_NOT_FOUND,
54
57
  )
55
- patient_finding_classification = patient_finding.add_classification(classification_id = classification_id, choice_id = choice_id)
56
-
57
- return Response({
58
- 'id': patient_finding_classification.id,
59
- 'patient_finding_id': patient_finding.id,
60
- 'classification_choice_id': choice.id
61
- }, status=status.HTTP_201_CREATED)
62
-
58
+ patient_finding_classification = patient_finding.add_classification(
59
+ classification_id=classification_id, choice_id=choice_id
60
+ )
61
+
62
+ return Response(
63
+ {
64
+ "id": patient_finding_classification.id,
65
+ "patient_finding_id": patient_finding.id,
66
+ "classification_choice_id": choice.id,
67
+ },
68
+ status=status.HTTP_201_CREATED,
69
+ )
70
+
63
71
  except Exception as e:
64
72
  return Response(
65
- {'detail': f'Error creating patient finding classification: {str(e)}'},
66
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
67
- )
73
+ {"detail": f"Error creating patient finding classification: {str(e)}"},
74
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR,
75
+ )
@@ -11,7 +11,7 @@ from endoreg_db.services.report_import import ReportImportService
11
11
  logger = logging.getLogger(__name__)
12
12
 
13
13
 
14
- class ReportReimportView(APIView):
14
+ class ReportReimportView(APIView):
15
15
  """
16
16
  API endpoint to re-import a pdf file and regenerate metadata.
17
17
  This is useful when OCR failed or metadata is incomplete.
@@ -5,7 +5,6 @@ import re
5
5
  from django.http import FileResponse, Http404, StreamingHttpResponse
6
6
  from django.views.decorators.clickjacking import (
7
7
  xframe_options_exempt,
8
- xframe_options_sameorigin,
9
8
  )
10
9
  from rest_framework.views import APIView
11
10
 
@@ -172,13 +171,11 @@ class ReportStreamView(APIView):
172
171
  logger.debug(f"Serving full {file_type} report {pk} ({file_size} bytes)")
173
172
 
174
173
  try:
175
- with open(file_path, "rb") as file_handle:
176
- response = FileResponse(file_handle, content_type="application/pdf")
177
- response["Content-Length"] = str(file_size)
178
- response["Accept-Ranges"] = "bytes"
179
- response["Content-Disposition"] = (
180
- f'inline; filename="{safe_filename}"'
181
- )
174
+ file_handle = open(file_path, "rb")
175
+ response = FileResponse(file_handle, content_type="application/pdf")
176
+ response["Content-Length"] = str(file_size)
177
+ response["Accept-Ranges"] = "bytes"
178
+ response["Content-Disposition"] = f'inline; filename="{safe_filename}"'
182
179
 
183
180
  # FileResponse will take ownership of file_handle and close it after response
184
181
  return response
@@ -4,7 +4,8 @@ from .evaluate import (
4
4
  from .lookup import (
5
5
  LookupViewSet,
6
6
  )
7
+
7
8
  __all__ = [
8
9
  "evaluate_requirements",
9
10
  "LookupViewSet",
10
- ]
11
+ ]
@@ -2,8 +2,7 @@ from endoreg_db.models.requirement.requirement import Requirement
2
2
  from endoreg_db.views.requirement.requirement_utils import safe_evaluate_requirement
3
3
  from endoreg_db.models.requirement.requirement_set import RequirementSet
4
4
  from endoreg_db.models.requirement.requirement_evaluation.evaluate_with_dependencies import (
5
- evaluate_requirement_sets_with_dependencies,
6
- RequirementStatus, # if you export it there, otherwise re-declare in view
5
+ evaluate_requirement_sets_with_dependencies, # if you export it there, otherwise re-declare in view
7
6
  )
8
7
  from endoreg_db.models.medical.patient.patient_examination import PatientExamination
9
8
  from rest_framework import status
@@ -51,10 +50,7 @@ def evaluate_requirements(request):
51
50
 
52
51
  # ---- fetch PatientExamination
53
52
  try:
54
- pe = (
55
- PatientExamination.objects.select_related("patient")
56
- .get(id=pe_id)
57
- )
53
+ pe = PatientExamination.objects.select_related("patient").get(id=pe_id)
58
54
  except PatientExamination.DoesNotExist:
59
55
  msg = f"PatientExamination with id {pe_id} does not exist"
60
56
  errors.append(msg)
@@ -153,9 +149,11 @@ def evaluate_requirements(request):
153
149
 
154
150
  for set_id, req_dict in set_results.items():
155
151
  req_set = sets_by_id.get(set_id)
156
- set_name = getattr(
157
- req_set, "name", str(set_id)
158
- ) if req_set is not None else str(set_id)
152
+ set_name = (
153
+ getattr(req_set, "name", str(set_id))
154
+ if req_set is not None
155
+ else str(set_id)
156
+ )
159
157
 
160
158
  for req_id, (status_value, details) in req_dict.items():
161
159
  try:
@@ -54,7 +54,7 @@ class LookupViewSet(viewsets.ViewSet):
54
54
  "selectedRequirementSetIds",
55
55
  "selectedChoices",
56
56
  }
57
-
57
+
58
58
  user_tags = Tag
59
59
 
60
60
  @action(detail=False, methods=["post"])
@@ -134,7 +134,7 @@ class LookupViewSet(viewsets.ViewSet):
134
134
 
135
135
  except Exception:
136
136
  pass
137
-
137
+
138
138
  user_tags = request.data.get("user_tags", None)
139
139
  if user_tags and not isinstance(user_tags, list):
140
140
  user_tags = [user_tags]
@@ -269,7 +269,6 @@ class LookupViewSet(viewsets.ViewSet):
269
269
  cache.set(f"{ORIGIN_MAP_PREFIX}{pk}", pe_id, DEFAULT_TTL_SECONDS)
270
270
  return Response(store.get_all(), status=status.HTTP_200_OK)
271
271
 
272
-
273
272
  except Exception:
274
273
  pass
275
274
 
@@ -8,7 +8,6 @@ from typing import Any, Dict, Iterable, Optional
8
8
  from django.conf import settings
9
9
  from django.core.cache import cache
10
10
 
11
- from endoreg_db.models.medical import PatientExamination
12
11
 
13
12
  # Align TTL with Django cache TIMEOUT for consistency in tests and runtime
14
13
 
@@ -31,7 +31,7 @@ def safe_evaluate_requirement(
31
31
  if hasattr(requirement, "evaluate_with_details"):
32
32
  met, details = requirement.evaluate_with_details(*args, mode=mode, **kwargs)
33
33
  else:
34
- met = requirement.evaluate(*args, mode=mode, **kwargs)
34
+ met = requirement.evaluate(*args, **kwargs)
35
35
  details = "Voraussetzung erfüllt" if met else "Voraussetzung nicht erfüllt"
36
36
  error = None
37
37
 
@@ -70,9 +70,7 @@ def safe_evaluate_requirement(
70
70
  display_name = getattr(requirement, "description", None) or getattr(
71
71
  requirement, "name", "unbekannte Voraussetzung"
72
72
  )
73
- details = (
74
- f"Bei der Auswertung der Voraussetzung „{display_name}“ ist ein interner Fehler aufgetreten."
75
- )
73
+ details = f"Bei der Auswertung der Voraussetzung „{display_name}“ ist ein interner Fehler aufgetreten."
76
74
  error = f"{e.__class__.__name__}: {e}"
77
75
  logger.exception(
78
76
  "Requirement '%s' unexpected error",
@@ -6,8 +6,8 @@ from .stats_views import (
6
6
  )
7
7
 
8
8
  __all__ = [
9
- 'ExaminationStatsView',
10
- 'VideoSegmentStatsView',
11
- 'SensitiveMetaStatsView',
12
- 'GeneralStatsView',
9
+ "ExaminationStatsView",
10
+ "VideoSegmentStatsView",
11
+ "SensitiveMetaStatsView",
12
+ "GeneralStatsView",
13
13
  ]