endoreg-db 0.8.9.2__py3-none-any.whl → 0.8.9.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of endoreg-db might be problematic. Click here for more details.

Files changed (450) hide show
  1. endoreg_db/admin.py +10 -5
  2. endoreg_db/apps.py +4 -7
  3. endoreg_db/authz/auth.py +1 -0
  4. endoreg_db/authz/backends.py +1 -1
  5. endoreg_db/authz/management/commands/list_routes.py +2 -0
  6. endoreg_db/authz/middleware.py +8 -7
  7. endoreg_db/authz/permissions.py +21 -10
  8. endoreg_db/authz/policy.py +14 -19
  9. endoreg_db/authz/views_auth.py +14 -10
  10. endoreg_db/codemods/rename_datetime_fields.py +8 -1
  11. endoreg_db/exceptions.py +5 -2
  12. endoreg_db/forms/__init__.py +0 -1
  13. endoreg_db/forms/examination_form.py +4 -3
  14. endoreg_db/forms/patient_finding_intervention_form.py +30 -8
  15. endoreg_db/forms/patient_form.py +9 -13
  16. endoreg_db/forms/questionnaires/__init__.py +1 -1
  17. endoreg_db/forms/settings/__init__.py +4 -1
  18. endoreg_db/forms/unit.py +2 -1
  19. endoreg_db/helpers/count_db.py +17 -14
  20. endoreg_db/helpers/default_objects.py +2 -1
  21. endoreg_db/helpers/download_segmentation_model.py +4 -3
  22. endoreg_db/helpers/interact.py +0 -5
  23. endoreg_db/helpers/test_video_helper.py +33 -25
  24. endoreg_db/import_files/__init__.py +1 -1
  25. endoreg_db/import_files/context/__init__.py +1 -1
  26. endoreg_db/import_files/context/default_sensitive_meta.py +11 -9
  27. endoreg_db/import_files/context/ensure_center.py +4 -4
  28. endoreg_db/import_files/context/file_lock.py +3 -3
  29. endoreg_db/import_files/context/import_context.py +11 -12
  30. endoreg_db/import_files/context/validate_directories.py +1 -0
  31. endoreg_db/import_files/file_storage/create_report_file.py +57 -34
  32. endoreg_db/import_files/file_storage/create_video_file.py +64 -35
  33. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +5 -2
  34. endoreg_db/import_files/file_storage/state_management.py +89 -122
  35. endoreg_db/import_files/file_storage/storage.py +5 -1
  36. endoreg_db/import_files/processing/report_processing/report_anonymization.py +24 -19
  37. endoreg_db/import_files/processing/sensitive_meta_adapter.py +3 -3
  38. endoreg_db/import_files/processing/video_processing/video_anonymization.py +18 -18
  39. endoreg_db/import_files/pseudonymization/k_anonymity.py +8 -9
  40. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +16 -5
  41. endoreg_db/import_files/report_import_service.py +36 -30
  42. endoreg_db/import_files/video_import_service.py +27 -23
  43. endoreg_db/logger_conf.py +56 -40
  44. endoreg_db/management/__init__.py +1 -1
  45. endoreg_db/management/commands/__init__.py +1 -1
  46. endoreg_db/management/commands/check_auth.py +45 -38
  47. endoreg_db/management/commands/create_model_meta_from_huggingface.py +53 -2
  48. endoreg_db/management/commands/create_multilabel_model_meta.py +54 -19
  49. endoreg_db/management/commands/fix_missing_patient_data.py +105 -71
  50. endoreg_db/management/commands/fix_video_paths.py +75 -54
  51. endoreg_db/management/commands/import_report.py +1 -3
  52. endoreg_db/management/commands/list_routes.py +2 -0
  53. endoreg_db/management/commands/load_ai_model_data.py +8 -2
  54. endoreg_db/management/commands/load_ai_model_label_data.py +0 -1
  55. endoreg_db/management/commands/load_center_data.py +3 -3
  56. endoreg_db/management/commands/load_distribution_data.py +35 -38
  57. endoreg_db/management/commands/load_endoscope_data.py +0 -3
  58. endoreg_db/management/commands/load_examination_data.py +20 -4
  59. endoreg_db/management/commands/load_finding_data.py +18 -3
  60. endoreg_db/management/commands/load_gender_data.py +17 -24
  61. endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +95 -85
  62. endoreg_db/management/commands/load_information_source.py +0 -3
  63. endoreg_db/management/commands/load_lab_value_data.py +14 -3
  64. endoreg_db/management/commands/load_legacy_data.py +303 -0
  65. endoreg_db/management/commands/load_name_data.py +1 -2
  66. endoreg_db/management/commands/load_pdf_type_data.py +4 -8
  67. endoreg_db/management/commands/load_profession_data.py +0 -1
  68. endoreg_db/management/commands/load_report_reader_flag_data.py +0 -4
  69. endoreg_db/management/commands/load_requirement_data.py +6 -2
  70. endoreg_db/management/commands/load_unit_data.py +0 -4
  71. endoreg_db/management/commands/load_user_groups.py +5 -7
  72. endoreg_db/management/commands/model_input.py +169 -0
  73. endoreg_db/management/commands/register_ai_model.py +22 -16
  74. endoreg_db/management/commands/setup_endoreg_db.py +110 -32
  75. endoreg_db/management/commands/storage_management.py +14 -8
  76. endoreg_db/management/commands/summarize_db_content.py +154 -63
  77. endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
  78. endoreg_db/management/commands/validate_video_files.py +82 -50
  79. endoreg_db/management/commands/video_validation.py +4 -6
  80. endoreg_db/migrations/0001_initial.py +112 -63
  81. endoreg_db/models/__init__.py +8 -0
  82. endoreg_db/models/administration/ai/active_model.py +5 -5
  83. endoreg_db/models/administration/ai/ai_model.py +41 -18
  84. endoreg_db/models/administration/ai/model_type.py +1 -0
  85. endoreg_db/models/administration/case/case.py +22 -22
  86. endoreg_db/models/administration/center/__init__.py +5 -5
  87. endoreg_db/models/administration/center/center.py +6 -2
  88. endoreg_db/models/administration/center/center_resource.py +18 -4
  89. endoreg_db/models/administration/center/center_shift.py +3 -1
  90. endoreg_db/models/administration/center/center_waste.py +6 -2
  91. endoreg_db/models/administration/person/__init__.py +1 -1
  92. endoreg_db/models/administration/person/employee/__init__.py +1 -1
  93. endoreg_db/models/administration/person/employee/employee_type.py +3 -1
  94. endoreg_db/models/administration/person/examiner/__init__.py +1 -1
  95. endoreg_db/models/administration/person/examiner/examiner.py +10 -2
  96. endoreg_db/models/administration/person/names/first_name.py +6 -4
  97. endoreg_db/models/administration/person/names/last_name.py +4 -3
  98. endoreg_db/models/administration/person/patient/__init__.py +1 -1
  99. endoreg_db/models/administration/person/patient/patient.py +0 -1
  100. endoreg_db/models/administration/person/patient/patient_external_id.py +0 -1
  101. endoreg_db/models/administration/person/person.py +1 -1
  102. endoreg_db/models/administration/product/__init__.py +7 -6
  103. endoreg_db/models/administration/product/product.py +6 -2
  104. endoreg_db/models/administration/product/product_group.py +9 -7
  105. endoreg_db/models/administration/product/product_material.py +9 -2
  106. endoreg_db/models/administration/product/reference_product.py +64 -15
  107. endoreg_db/models/administration/qualification/qualification.py +3 -1
  108. endoreg_db/models/administration/shift/shift.py +3 -1
  109. endoreg_db/models/administration/shift/shift_type.py +12 -4
  110. endoreg_db/models/aidataset/__init__.py +5 -0
  111. endoreg_db/models/aidataset/aidataset.py +193 -0
  112. endoreg_db/models/label/__init__.py +1 -1
  113. endoreg_db/models/label/label.py +10 -2
  114. endoreg_db/models/label/label_set.py +3 -1
  115. endoreg_db/models/label/label_video_segment/_create_from_video.py +6 -2
  116. endoreg_db/models/label/label_video_segment/label_video_segment.py +148 -44
  117. endoreg_db/models/media/__init__.py +12 -5
  118. endoreg_db/models/media/frame/__init__.py +1 -1
  119. endoreg_db/models/media/frame/frame.py +34 -8
  120. endoreg_db/models/media/pdf/__init__.py +2 -1
  121. endoreg_db/models/media/pdf/raw_pdf.py +11 -4
  122. endoreg_db/models/media/pdf/report_file.py +6 -2
  123. endoreg_db/models/media/pdf/report_reader/__init__.py +3 -3
  124. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +15 -5
  125. endoreg_db/models/media/video/create_from_file.py +20 -41
  126. endoreg_db/models/media/video/pipe_1.py +75 -30
  127. endoreg_db/models/media/video/pipe_2.py +37 -12
  128. endoreg_db/models/media/video/video_file.py +36 -24
  129. endoreg_db/models/media/video/video_file_ai.py +235 -70
  130. endoreg_db/models/media/video/video_file_anonymize.py +240 -65
  131. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -1
  132. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +3 -1
  133. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +30 -9
  134. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +95 -29
  135. endoreg_db/models/media/video/video_file_frames/_get_frame.py +13 -3
  136. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -1
  137. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +15 -3
  138. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +15 -3
  139. endoreg_db/models/media/video/video_file_frames/_get_frames.py +7 -2
  140. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +109 -23
  141. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +111 -27
  142. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +46 -13
  143. endoreg_db/models/media/video/video_file_io.py +85 -33
  144. endoreg_db/models/media/video/video_file_meta/__init__.py +6 -6
  145. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +17 -4
  146. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +28 -7
  147. endoreg_db/models/media/video/video_file_meta/get_fps.py +46 -13
  148. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +81 -20
  149. endoreg_db/models/media/video/video_file_meta/text_meta.py +61 -20
  150. endoreg_db/models/media/video/video_file_meta/video_meta.py +40 -12
  151. endoreg_db/models/media/video/video_file_segments.py +118 -27
  152. endoreg_db/models/media/video/video_metadata.py +25 -6
  153. endoreg_db/models/media/video/video_processing.py +54 -15
  154. endoreg_db/models/medical/__init__.py +3 -13
  155. endoreg_db/models/medical/contraindication/__init__.py +3 -1
  156. endoreg_db/models/medical/disease.py +18 -6
  157. endoreg_db/models/medical/event.py +6 -2
  158. endoreg_db/models/medical/examination/__init__.py +5 -1
  159. endoreg_db/models/medical/examination/examination.py +22 -6
  160. endoreg_db/models/medical/examination/examination_indication.py +23 -7
  161. endoreg_db/models/medical/examination/examination_time.py +6 -2
  162. endoreg_db/models/medical/finding/__init__.py +3 -1
  163. endoreg_db/models/medical/finding/finding.py +37 -12
  164. endoreg_db/models/medical/finding/finding_classification.py +27 -8
  165. endoreg_db/models/medical/finding/finding_intervention.py +19 -6
  166. endoreg_db/models/medical/finding/finding_type.py +3 -1
  167. endoreg_db/models/medical/hardware/__init__.py +1 -1
  168. endoreg_db/models/medical/hardware/endoscope.py +14 -2
  169. endoreg_db/models/medical/laboratory/__init__.py +1 -1
  170. endoreg_db/models/medical/laboratory/lab_value.py +139 -39
  171. endoreg_db/models/medical/medication/__init__.py +7 -3
  172. endoreg_db/models/medical/medication/medication.py +3 -1
  173. endoreg_db/models/medical/medication/medication_indication.py +3 -1
  174. endoreg_db/models/medical/medication/medication_indication_type.py +11 -3
  175. endoreg_db/models/medical/medication/medication_intake_time.py +3 -1
  176. endoreg_db/models/medical/medication/medication_schedule.py +3 -1
  177. endoreg_db/models/medical/patient/__init__.py +2 -10
  178. endoreg_db/models/medical/patient/medication_examples.py +3 -14
  179. endoreg_db/models/medical/patient/patient_disease.py +17 -5
  180. endoreg_db/models/medical/patient/patient_event.py +12 -4
  181. endoreg_db/models/medical/patient/patient_examination.py +52 -15
  182. endoreg_db/models/medical/patient/patient_examination_indication.py +15 -4
  183. endoreg_db/models/medical/patient/patient_finding.py +105 -29
  184. endoreg_db/models/medical/patient/patient_finding_classification.py +41 -12
  185. endoreg_db/models/medical/patient/patient_finding_intervention.py +11 -3
  186. endoreg_db/models/medical/patient/patient_lab_sample.py +6 -2
  187. endoreg_db/models/medical/patient/patient_lab_value.py +42 -10
  188. endoreg_db/models/medical/patient/patient_medication.py +25 -7
  189. endoreg_db/models/medical/patient/patient_medication_schedule.py +34 -10
  190. endoreg_db/models/metadata/model_meta.py +40 -12
  191. endoreg_db/models/metadata/model_meta_logic.py +51 -16
  192. endoreg_db/models/metadata/sensitive_meta.py +65 -28
  193. endoreg_db/models/metadata/sensitive_meta_logic.py +28 -26
  194. endoreg_db/models/metadata/video_meta.py +146 -39
  195. endoreg_db/models/metadata/video_prediction_logic.py +70 -21
  196. endoreg_db/models/metadata/video_prediction_meta.py +80 -27
  197. endoreg_db/models/operation_log.py +63 -0
  198. endoreg_db/models/other/__init__.py +10 -10
  199. endoreg_db/models/other/distribution/__init__.py +9 -7
  200. endoreg_db/models/other/distribution/base_value_distribution.py +3 -1
  201. endoreg_db/models/other/distribution/date_value_distribution.py +19 -5
  202. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +3 -1
  203. endoreg_db/models/other/distribution/numeric_value_distribution.py +34 -9
  204. endoreg_db/models/other/emission/__init__.py +1 -1
  205. endoreg_db/models/other/emission/emission_factor.py +9 -3
  206. endoreg_db/models/other/information_source.py +15 -5
  207. endoreg_db/models/other/material.py +3 -1
  208. endoreg_db/models/other/transport_route.py +3 -1
  209. endoreg_db/models/other/unit.py +6 -2
  210. endoreg_db/models/report/report.py +0 -1
  211. endoreg_db/models/requirement/requirement.py +84 -27
  212. endoreg_db/models/requirement/requirement_error.py +5 -6
  213. endoreg_db/models/requirement/requirement_evaluation/__init__.py +1 -1
  214. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +8 -8
  215. endoreg_db/models/requirement/requirement_evaluation/get_values.py +3 -3
  216. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +24 -8
  217. endoreg_db/models/requirement/requirement_operator.py +28 -8
  218. endoreg_db/models/requirement/requirement_set.py +34 -11
  219. endoreg_db/models/state/__init__.py +1 -0
  220. endoreg_db/models/state/audit_ledger.py +9 -2
  221. endoreg_db/models/{media → state}/processing_history/__init__.py +1 -3
  222. endoreg_db/models/state/processing_history/processing_history.py +136 -0
  223. endoreg_db/models/state/raw_pdf.py +0 -1
  224. endoreg_db/models/state/video.py +2 -4
  225. endoreg_db/models/utils.py +4 -2
  226. endoreg_db/queries/__init__.py +2 -6
  227. endoreg_db/queries/annotations/__init__.py +1 -3
  228. endoreg_db/queries/annotations/legacy.py +37 -26
  229. endoreg_db/root_urls.py +3 -4
  230. endoreg_db/schemas/examination_evaluation.py +3 -0
  231. endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +249 -163
  232. endoreg_db/serializers/__init__.py +2 -8
  233. endoreg_db/serializers/administration/__init__.py +1 -2
  234. endoreg_db/serializers/administration/ai/__init__.py +0 -1
  235. endoreg_db/serializers/administration/ai/active_model.py +3 -1
  236. endoreg_db/serializers/administration/ai/ai_model.py +5 -3
  237. endoreg_db/serializers/administration/ai/model_type.py +3 -1
  238. endoreg_db/serializers/administration/center.py +7 -2
  239. endoreg_db/serializers/administration/gender.py +4 -2
  240. endoreg_db/serializers/anonymization.py +13 -13
  241. endoreg_db/serializers/evaluation/examination_evaluation.py +0 -1
  242. endoreg_db/serializers/examination/__init__.py +1 -1
  243. endoreg_db/serializers/examination/base.py +12 -13
  244. endoreg_db/serializers/examination/dropdown.py +6 -7
  245. endoreg_db/serializers/examination_serializer.py +3 -6
  246. endoreg_db/serializers/finding/__init__.py +1 -1
  247. endoreg_db/serializers/finding/finding.py +14 -7
  248. endoreg_db/serializers/finding_classification/__init__.py +3 -3
  249. endoreg_db/serializers/finding_classification/choice.py +3 -3
  250. endoreg_db/serializers/finding_classification/classification.py +2 -4
  251. endoreg_db/serializers/label_video_segment/__init__.py +5 -3
  252. endoreg_db/serializers/{label → label_video_segment}/image_classification_annotation.py +5 -5
  253. endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
  254. endoreg_db/serializers/{label → label_video_segment/label}/label.py +1 -1
  255. endoreg_db/serializers/label_video_segment/label_video_segment.py +338 -228
  256. endoreg_db/serializers/meta/__init__.py +1 -2
  257. endoreg_db/serializers/meta/sensitive_meta_detail.py +28 -13
  258. endoreg_db/serializers/meta/sensitive_meta_update.py +51 -46
  259. endoreg_db/serializers/meta/sensitive_meta_verification.py +19 -16
  260. endoreg_db/serializers/misc/__init__.py +2 -2
  261. endoreg_db/serializers/misc/file_overview.py +11 -7
  262. endoreg_db/serializers/misc/stats.py +10 -8
  263. endoreg_db/serializers/misc/translatable_field_mix_in.py +6 -6
  264. endoreg_db/serializers/misc/upload_job.py +32 -29
  265. endoreg_db/serializers/patient/__init__.py +2 -1
  266. endoreg_db/serializers/patient/patient.py +32 -15
  267. endoreg_db/serializers/patient/patient_dropdown.py +11 -3
  268. endoreg_db/serializers/patient_examination/__init__.py +1 -1
  269. endoreg_db/serializers/patient_examination/patient_examination.py +67 -40
  270. endoreg_db/serializers/patient_finding/__init__.py +1 -1
  271. endoreg_db/serializers/patient_finding/patient_finding.py +2 -1
  272. endoreg_db/serializers/patient_finding/patient_finding_classification.py +17 -9
  273. endoreg_db/serializers/patient_finding/patient_finding_detail.py +26 -17
  274. endoreg_db/serializers/patient_finding/patient_finding_intervention.py +7 -5
  275. endoreg_db/serializers/patient_finding/patient_finding_list.py +10 -11
  276. endoreg_db/serializers/patient_finding/patient_finding_write.py +36 -27
  277. endoreg_db/serializers/pdf/__init__.py +1 -3
  278. endoreg_db/serializers/requirements/requirement_schema.py +1 -6
  279. endoreg_db/serializers/sensitive_meta_serializer.py +100 -81
  280. endoreg_db/serializers/video/__init__.py +2 -2
  281. endoreg_db/serializers/video/{segmentation.py → video_file.py} +66 -47
  282. endoreg_db/serializers/video/video_file_brief.py +6 -2
  283. endoreg_db/serializers/video/video_file_detail.py +36 -23
  284. endoreg_db/serializers/video/video_file_list.py +4 -2
  285. endoreg_db/serializers/video/video_processing_history.py +54 -50
  286. endoreg_db/services/__init__.py +1 -1
  287. endoreg_db/services/anonymization.py +2 -2
  288. endoreg_db/services/examination_evaluation.py +40 -17
  289. endoreg_db/services/model_meta_from_hf.py +76 -0
  290. endoreg_db/services/polling_coordinator.py +101 -70
  291. endoreg_db/services/pseudonym_service.py +27 -22
  292. endoreg_db/services/report_import.py +6 -3
  293. endoreg_db/services/segment_sync.py +75 -59
  294. endoreg_db/services/video_import.py +6 -7
  295. endoreg_db/urls/__init__.py +2 -2
  296. endoreg_db/urls/ai.py +7 -25
  297. endoreg_db/urls/anonymization.py +61 -15
  298. endoreg_db/urls/auth.py +4 -4
  299. endoreg_db/urls/classification.py +4 -9
  300. endoreg_db/urls/examination.py +27 -18
  301. endoreg_db/urls/media.py +27 -34
  302. endoreg_db/urls/patient.py +11 -7
  303. endoreg_db/urls/requirements.py +3 -1
  304. endoreg_db/urls/root_urls.py +2 -3
  305. endoreg_db/urls/stats.py +24 -16
  306. endoreg_db/urls/upload.py +3 -11
  307. endoreg_db/utils/__init__.py +14 -15
  308. endoreg_db/utils/ai/__init__.py +1 -1
  309. endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
  310. endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
  311. endoreg_db/utils/ai/get.py +2 -1
  312. endoreg_db/utils/ai/inference_dataset.py +14 -15
  313. endoreg_db/utils/ai/model_training/config.py +117 -0
  314. endoreg_db/utils/ai/model_training/dataset.py +74 -0
  315. endoreg_db/utils/ai/model_training/losses.py +68 -0
  316. endoreg_db/utils/ai/model_training/metrics.py +78 -0
  317. endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
  318. endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
  319. endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
  320. endoreg_db/utils/ai/multilabel_classification_net.py +21 -6
  321. endoreg_db/utils/ai/predict.py +4 -4
  322. endoreg_db/utils/ai/preprocess.py +19 -11
  323. endoreg_db/utils/calc_duration_seconds.py +4 -4
  324. endoreg_db/utils/case_generator/lab_sample_factory.py +3 -4
  325. endoreg_db/utils/check_video_files.py +74 -47
  326. endoreg_db/utils/cropping.py +10 -9
  327. endoreg_db/utils/dataloader.py +11 -3
  328. endoreg_db/utils/dates.py +3 -4
  329. endoreg_db/utils/defaults/set_default_center.py +7 -6
  330. endoreg_db/utils/env.py +6 -2
  331. endoreg_db/utils/extract_specific_frames.py +24 -9
  332. endoreg_db/utils/file_operations.py +30 -18
  333. endoreg_db/utils/fix_video_path_direct.py +57 -41
  334. endoreg_db/utils/frame_anonymization_utils.py +157 -157
  335. endoreg_db/utils/hashs.py +3 -18
  336. endoreg_db/utils/links/requirement_link.py +96 -52
  337. endoreg_db/utils/ocr.py +30 -25
  338. endoreg_db/utils/operation_log.py +61 -0
  339. endoreg_db/utils/parse_and_generate_yaml.py +12 -13
  340. endoreg_db/utils/paths.py +6 -6
  341. endoreg_db/utils/permissions.py +40 -24
  342. endoreg_db/utils/pipelines/process_video_dir.py +50 -26
  343. endoreg_db/utils/product/sum_emissions.py +5 -3
  344. endoreg_db/utils/product/sum_weights.py +4 -2
  345. endoreg_db/utils/pydantic_models/__init__.py +3 -4
  346. endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +207 -107
  347. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +252 -65
  348. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +27 -10
  349. endoreg_db/utils/setup_config.py +21 -5
  350. endoreg_db/utils/storage.py +3 -1
  351. endoreg_db/utils/translation.py +19 -15
  352. endoreg_db/utils/uuid.py +1 -0
  353. endoreg_db/utils/validate_endo_roi.py +12 -4
  354. endoreg_db/utils/validate_subcategory_dict.py +26 -24
  355. endoreg_db/utils/validate_video_detailed.py +207 -149
  356. endoreg_db/utils/video/__init__.py +7 -3
  357. endoreg_db/utils/video/extract_frames.py +30 -18
  358. endoreg_db/utils/video/names.py +11 -6
  359. endoreg_db/utils/video/streaming_processor.py +175 -101
  360. endoreg_db/utils/video/video_splitter.py +30 -19
  361. endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +59 -50
  362. endoreg_db/views/__init__.py +0 -20
  363. endoreg_db/views/anonymization/__init__.py +6 -2
  364. endoreg_db/views/anonymization/media_management.py +2 -6
  365. endoreg_db/views/anonymization/overview.py +34 -1
  366. endoreg_db/views/anonymization/validate.py +79 -18
  367. endoreg_db/views/auth/__init__.py +1 -1
  368. endoreg_db/views/auth/keycloak.py +16 -14
  369. endoreg_db/views/examination/__init__.py +12 -15
  370. endoreg_db/views/examination/examination.py +5 -5
  371. endoreg_db/views/examination/examination_manifest_cache.py +5 -5
  372. endoreg_db/views/examination/get_finding_classification_choices.py +8 -5
  373. endoreg_db/views/examination/get_finding_classifications.py +9 -7
  374. endoreg_db/views/examination/get_findings.py +8 -10
  375. endoreg_db/views/examination/get_instruments.py +3 -2
  376. endoreg_db/views/examination/get_interventions.py +1 -1
  377. endoreg_db/views/finding/__init__.py +2 -2
  378. endoreg_db/views/finding/finding.py +58 -54
  379. endoreg_db/views/finding/get_classifications.py +1 -1
  380. endoreg_db/views/finding/get_interventions.py +1 -1
  381. endoreg_db/views/finding_classification/__init__.py +5 -5
  382. endoreg_db/views/finding_classification/finding_classification.py +5 -6
  383. endoreg_db/views/finding_classification/get_classification_choices.py +3 -4
  384. endoreg_db/views/media/__init__.py +13 -13
  385. endoreg_db/views/media/pdf_media.py +9 -9
  386. endoreg_db/views/media/sensitive_metadata.py +10 -7
  387. endoreg_db/views/media/video_media.py +4 -4
  388. endoreg_db/views/meta/__init__.py +1 -1
  389. endoreg_db/views/meta/sensitive_meta_list.py +20 -22
  390. endoreg_db/views/meta/sensitive_meta_verification.py +14 -11
  391. endoreg_db/views/misc/__init__.py +6 -34
  392. endoreg_db/views/misc/center.py +2 -1
  393. endoreg_db/views/misc/csrf.py +2 -1
  394. endoreg_db/views/misc/gender.py +2 -1
  395. endoreg_db/views/misc/stats.py +141 -106
  396. endoreg_db/views/patient/__init__.py +1 -3
  397. endoreg_db/views/patient/patient.py +141 -99
  398. endoreg_db/views/patient_examination/__init__.py +5 -5
  399. endoreg_db/views/patient_examination/patient_examination.py +43 -42
  400. endoreg_db/views/patient_examination/patient_examination_create.py +10 -15
  401. endoreg_db/views/patient_examination/patient_examination_detail.py +12 -15
  402. endoreg_db/views/patient_examination/patient_examination_list.py +21 -17
  403. endoreg_db/views/patient_examination/video.py +114 -80
  404. endoreg_db/views/patient_finding/__init__.py +1 -1
  405. endoreg_db/views/patient_finding/patient_finding.py +17 -10
  406. endoreg_db/views/patient_finding/patient_finding_optimized.py +127 -95
  407. endoreg_db/views/patient_finding_classification/__init__.py +1 -1
  408. endoreg_db/views/patient_finding_classification/pfc_create.py +35 -27
  409. endoreg_db/views/report/reimport.py +1 -1
  410. endoreg_db/views/report/report_stream.py +5 -8
  411. endoreg_db/views/requirement/__init__.py +2 -1
  412. endoreg_db/views/requirement/evaluate.py +7 -9
  413. endoreg_db/views/requirement/lookup.py +2 -3
  414. endoreg_db/views/requirement/lookup_store.py +0 -1
  415. endoreg_db/views/requirement/requirement_utils.py +2 -4
  416. endoreg_db/views/stats/__init__.py +4 -4
  417. endoreg_db/views/stats/stats_views.py +152 -115
  418. endoreg_db/views/video/__init__.py +18 -27
  419. endoreg_db/views/{ai → video/ai}/__init__.py +2 -2
  420. endoreg_db/views/{ai → video/ai}/label.py +20 -16
  421. endoreg_db/views/video/correction.py +5 -6
  422. endoreg_db/views/video/reimport.py +134 -99
  423. endoreg_db/views/video/segments_crud.py +134 -44
  424. endoreg_db/views/video/video_apply_mask.py +13 -12
  425. endoreg_db/views/video/video_correction.py +2 -1
  426. endoreg_db/views/video/video_download_processed.py +15 -15
  427. endoreg_db/views/video/video_meta_stats.py +7 -6
  428. endoreg_db/views/video/video_processing_history.py +3 -2
  429. endoreg_db/views/video/video_remove_frames.py +13 -12
  430. endoreg_db/views/video/video_stream.py +110 -82
  431. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
  432. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +434 -431
  433. endoreg_db/management/commands/import_fallback_video.py +0 -203
  434. endoreg_db/management/commands/import_video.py +0 -422
  435. endoreg_db/management/commands/import_video_with_classification.py +0 -367
  436. endoreg_db/models/media/processing_history/processing_history.py +0 -96
  437. endoreg_db/serializers/label/__init__.py +0 -7
  438. endoreg_db/serializers/label_video_segment/_lvs_create.py +0 -149
  439. endoreg_db/serializers/label_video_segment/_lvs_update.py +0 -138
  440. endoreg_db/serializers/label_video_segment/_lvs_validate.py +0 -149
  441. endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +0 -99
  442. endoreg_db/serializers/label_video_segment/label_video_segment_update.py +0 -163
  443. endoreg_db/services/__old/pdf_import.py +0 -1487
  444. endoreg_db/services/__old/video_import.py +0 -1306
  445. endoreg_db/tasks/upload_tasks.py +0 -216
  446. endoreg_db/tasks/video_ingest.py +0 -161
  447. endoreg_db/tasks/video_processing_tasks.py +0 -327
  448. endoreg_db/views/misc/translation.py +0 -182
  449. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
  450. {endoreg_db-0.8.9.2.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
@@ -18,8 +18,12 @@ from django.http import HttpResponse
18
18
  Middleware now sees token, verifies it, injects user
19
19
  DRF view (KeycloakVideoView) is allowed to execute and returns data
20
20
  """
21
+
22
+
21
23
  class KeycloakVideoView(APIView):
22
- permission_classes = [IsAuthenticated] #This uses DRF permissions to ensure request.user.is_authenticated == True.
24
+ permission_classes = [
25
+ IsAuthenticated
26
+ ] # This uses DRF permissions to ensure request.user.is_authenticated == True.
23
27
  print("1")
24
28
 
25
29
  def get(self, request):
@@ -27,8 +31,10 @@ class KeycloakVideoView(APIView):
27
31
  We already inject a mock user in the middleware, so this will pass if the middleware succeeded.
28
32
  Returns a message including the Keycloak username.
29
33
  """
30
- username = getattr(request.user, 'preferred_username', 'Unknown')
31
- return Response({"message": f"🎥 Hello, {username}. You are viewing protected videos!"})
34
+ username = getattr(request.user, "preferred_username", "Unknown")
35
+ return Response(
36
+ {"message": f"🎥 Hello, {username}. You are viewing protected videos!"}
37
+ )
32
38
 
33
39
 
34
40
  def keycloak_login(request):
@@ -37,11 +43,11 @@ def keycloak_login(request):
37
43
  """
38
44
  - This gets triggered when middleware redirects to /login/.
39
45
  """
40
- redirect_uri = request.build_absolute_uri('/login/callback/')
46
+ redirect_uri = request.build_absolute_uri("/login/callback/")
41
47
  print("Redirect URI:", redirect_uri)
42
48
  auth_url = f"{settings.KEYCLOAK_SERVER_URL}/realms/{settings.KEYCLOAK_REALM}/protocol/openid-connect/auth"
43
49
 
44
- #OAuth2 Authorization Code Flow
50
+ # OAuth2 Authorization Code Flow
45
51
  params = {
46
52
  "client_id": settings.KEYCLOAK_CLIENT_ID,
47
53
  "response_type": "code",
@@ -54,13 +60,11 @@ def keycloak_login(request):
54
60
  return redirect(f"{auth_url}?{urlencode(params)}")
55
61
 
56
62
 
57
-
58
63
  def keycloak_callback(request):
59
-
60
- #User lands here after login (Keycloak redirects here with code).
64
+ # User lands here after login (Keycloak redirects here with code).
61
65
  """
62
66
  Handles the OAuth2 callback from Keycloak, exchanging the authorization code for tokens.
63
-
67
+
64
68
  Receives the authorization code from Keycloak, exchanges it for access and refresh tokens, stores them in the user's session, and redirects to the protected videos page. Returns an error response if the code is missing, the token exchange fails, or an exception occurs.
65
69
  """
66
70
  code = request.GET.get("code")
@@ -69,7 +73,7 @@ def keycloak_callback(request):
69
73
 
70
74
  # Exchanges the code for an access_token.
71
75
  token_url = f"{settings.KEYCLOAK_SERVER_URL}/realms/{settings.KEYCLOAK_REALM}/protocol/openid-connect/token"
72
- redirect_uri = request.build_absolute_uri('/login/callback/')
76
+ redirect_uri = request.build_absolute_uri("/login/callback/")
73
77
 
74
78
  data = {
75
79
  "grant_type": "authorization_code",
@@ -87,8 +91,7 @@ def keycloak_callback(request):
87
91
 
88
92
  if response.status_code != 200:
89
93
  return HttpResponse(
90
- f"<h2> Token exchange failed</h2><pre>{response.text}</pre>",
91
- status=500
94
+ f"<h2> Token exchange failed</h2><pre>{response.text}</pre>", status=500
92
95
  )
93
96
 
94
97
  token_data = response.json()
@@ -108,6 +111,5 @@ def keycloak_callback(request):
108
111
 
109
112
 
110
113
  def public_home(request):
111
- print("Reached the public home page!")
114
+ print("Reached the public home page!")
112
115
  return HttpResponse("This is a public home page — no login required.")
113
-
@@ -3,7 +3,7 @@ from .examination import ExaminationViewSet
3
3
  from .get_finding_classification_choices import (
4
4
  get_classification_choices_for_examination,
5
5
  get_morphology_classification_choices_for_examination,
6
- get_location_classification_choices_for_examination,
6
+ get_location_classification_choices_for_examination,
7
7
  )
8
8
  from .get_finding_classifications import (
9
9
  get_classifications_for_examination,
@@ -17,17 +17,14 @@ from .get_interventions import get_interventions_for_examination
17
17
 
18
18
  __all__ = [
19
19
  "ExaminationManifestCache",
20
- 'ExaminationViewSet',
21
-
22
- 'get_classification_choices_for_examination',
23
- 'get_morphology_classification_choices_for_examination',
24
- 'get_location_classification_choices_for_examination',
25
-
26
- 'get_classifications_for_examination',
27
- 'get_location_classifications_for_examination',
28
- 'get_morphology_classifications_for_examination',
29
-
30
- 'get_findings_for_examination',
31
- 'get_instruments_for_examination',
32
- 'get_interventions_for_examination',
33
- ]
20
+ "ExaminationViewSet",
21
+ "get_classification_choices_for_examination",
22
+ "get_morphology_classification_choices_for_examination",
23
+ "get_location_classification_choices_for_examination",
24
+ "get_classifications_for_examination",
25
+ "get_location_classifications_for_examination",
26
+ "get_morphology_classifications_for_examination",
27
+ "get_findings_for_examination",
28
+ "get_instruments_for_examination",
29
+ "get_interventions_for_examination",
30
+ ]
@@ -3,15 +3,15 @@ from rest_framework.response import Response
3
3
  from rest_framework.decorators import action
4
4
  from rest_framework.permissions import IsAuthenticatedOrReadOnly
5
5
 
6
- from endoreg_db.models import (
7
- Examination
8
- )
6
+ from endoreg_db.models import Examination
9
7
  from endoreg_db.serializers import ExaminationSerializer, FindingSerializer
10
8
 
9
+
11
10
  class ExaminationViewSet(ReadOnlyModelViewSet):
12
11
  """
13
12
  ViewSet for handling Examination related operations.
14
13
  """
14
+
15
15
  queryset = Examination.objects.all()
16
16
  serializer_class = ExaminationSerializer
17
17
  permission_classes = [IsAuthenticatedOrReadOnly]
@@ -25,7 +25,7 @@ class ExaminationViewSet(ReadOnlyModelViewSet):
25
25
  # return OptimizedExaminationSerializer
26
26
  # return ExaminationSerializer
27
27
 
28
- @action(detail=True, methods=['get'])
28
+ @action(detail=True, methods=["get"])
29
29
  def findings(self, request, pk=None):
30
30
  """
31
31
  Get findings associated with a specific examination.
@@ -34,4 +34,4 @@ class ExaminationViewSet(ReadOnlyModelViewSet):
34
34
  examination = self.get_object()
35
35
  findings = examination.get_available_findings()
36
36
  serializer = FindingSerializer(findings, many=True)
37
- return Response(serializer.data)
37
+ return Response(serializer.data)
@@ -5,22 +5,22 @@ class ExaminationManifestCache:
5
5
  """Cache-Manager für Examination Manifests"""
6
6
 
7
7
  @staticmethod
8
- def get_cache_key(examination_id, language='en'):
8
+ def get_cache_key(examination_id, language="en"):
9
9
  return f"examination_manifest:{examination_id}:{language}"
10
10
 
11
11
  @staticmethod
12
- def get_manifest(examination_id, language='en'):
12
+ def get_manifest(examination_id, language="en"):
13
13
  cache_key = ExaminationManifestCache.get_cache_key(examination_id, language)
14
14
  return cache.get(cache_key)
15
15
 
16
16
  @staticmethod
17
- def set_manifest(examination_id, data, language='en', timeout=60*60): # 1 Stunde
17
+ def set_manifest(examination_id, data, language="en", timeout=60 * 60): # 1 Stunde
18
18
  cache_key = ExaminationManifestCache.get_cache_key(examination_id, language)
19
19
  cache.set(cache_key, data, timeout)
20
20
 
21
21
  @staticmethod
22
22
  def invalidate_manifest(examination_id):
23
23
  """Invalidiere Cache für alle Sprachen"""
24
- for lang in ['en', 'de']:
24
+ for lang in ["en", "de"]:
25
25
  cache_key = ExaminationManifestCache.get_cache_key(examination_id, lang)
26
- cache.delete(cache_key)
26
+ cache.delete(cache_key)
@@ -6,11 +6,12 @@ from rest_framework.response import Response
6
6
  from django.shortcuts import get_object_or_404
7
7
  from rest_framework.decorators import api_view
8
8
 
9
+
9
10
  @api_view(["GET"])
10
11
  def get_classification_choices_for_examination(request, exam_id):
11
12
  """
12
13
  Retrieves distinct morphology classification choices for a specific examination.
13
-
14
+
14
15
  Returns a list of unique morphology classification choices associated with the required and optional morphology classification types of findings linked to the given examination.
15
16
  """
16
17
  exam = get_object_or_404(Examination, id=exam_id)
@@ -23,11 +24,12 @@ def get_classification_choices_for_examination(request, exam_id):
23
24
  ).distinct()
24
25
  return Response([{"id": c.id, "name": c.name} for c in choices])
25
26
 
27
+
26
28
  @api_view(["GET"])
27
29
  def get_morphology_classification_choices_for_examination(request, exam_id):
28
30
  """
29
31
  Retrieves distinct morphology classification choices for a specific examination.
30
-
32
+
31
33
  Returns a list of unique morphology classification choices associated with the required and optional morphology classification types of findings linked to the given examination.
32
34
  """
33
35
  exam = get_object_or_404(Examination, id=exam_id)
@@ -40,14 +42,15 @@ def get_morphology_classification_choices_for_examination(request, exam_id):
40
42
  ).distinct()
41
43
  return Response([{"id": c.id, "name": c.name} for c in choices])
42
44
 
45
+
43
46
  @api_view(["GET"])
44
47
  def get_location_classification_choices_for_examination(request, exam_id):
45
48
  """
46
49
  Retrieves distinct location classification choices for a specific examination.
47
-
50
+
48
51
  Returns a list of unique location classification choices associated with the required and optional location classification types of findings linked to the given examination.
49
52
  """
50
-
53
+
51
54
  exam = get_object_or_404(Examination, id=exam_id)
52
55
  findings = exam.get_available_findings()
53
56
  all_classifications = set()
@@ -56,4 +59,4 @@ def get_location_classification_choices_for_examination(request, exam_id):
56
59
  choices = FindingClassificationChoice.objects.filter(
57
60
  classification__in=all_classifications
58
61
  ).distinct()
59
- return Response([{"id": c.id, "name": c.name} for c in choices])
62
+ return Response([{"id": c.id, "name": c.name} for c in choices])
@@ -1,15 +1,15 @@
1
-
2
1
  from rest_framework.decorators import api_view
3
2
  from rest_framework.response import Response
4
3
  from django.shortcuts import get_object_or_404
5
4
  from endoreg_db.models import Examination, FindingClassification
6
5
  from endoreg_db.utils.translation import build_multilingual_response
7
6
 
7
+
8
8
  @api_view(["GET"])
9
9
  def get_classifications_for_examination(request, exam_id):
10
10
  """
11
11
  Retrieves all classifications for a specific examination.
12
-
12
+
13
13
  Returns a list of all FindingClassification objects linked to the given examination.
14
14
  """
15
15
  exam = get_object_or_404(Examination, id=exam_id)
@@ -17,20 +17,22 @@ def get_classifications_for_examination(request, exam_id):
17
17
  result = [build_multilingual_response(c) for c in classifications]
18
18
  return Response(result)
19
19
 
20
+
20
21
  @api_view(["GET"])
21
22
  def get_location_classifications_for_examination(request, exam_id):
22
23
  exam = get_object_or_404(Examination, id=exam_id)
23
24
  location_classifications = FindingClassification.objects.filter(
24
- classification_types__name__iexact="location",
25
- examinations=exam
25
+ classification_types__name__iexact="location", examinations=exam
26
26
  )
27
27
  return Response([{"id": lc.id, "name": lc.name} for lc in location_classifications])
28
28
 
29
+
29
30
  @api_view(["GET"])
30
31
  def get_morphology_classifications_for_examination(request, exam_id):
31
32
  exam = get_object_or_404(Examination, id=exam_id)
32
33
  morphology_classifications = FindingClassification.objects.filter(
33
- classification_types__name__iexact="morphology",
34
- examinations=exam
34
+ classification_types__name__iexact="morphology", examinations=exam
35
+ )
36
+ return Response(
37
+ [{"id": mc.id, "name": mc.name} for mc in morphology_classifications]
35
38
  )
36
- return Response([{"id": mc.id, "name": mc.name} for mc in morphology_classifications])
@@ -1,4 +1,3 @@
1
-
2
1
  from rest_framework.decorators import api_view
3
2
  from rest_framework.response import Response
4
3
  from django.shortcuts import get_object_or_404
@@ -7,6 +6,7 @@ from ...serializers.finding import FindingSerializer
7
6
  from endoreg_db.utils.translation import build_multilingual_response
8
7
  from endoreg_db.models import PatientExamination
9
8
 
9
+
10
10
  @api_view(["GET"])
11
11
  def get_findings_for_examination(request, examination_id):
12
12
  """
@@ -18,24 +18,22 @@ def get_findings_for_examination(request, examination_id):
18
18
  exam = get_object_or_404(Examination, id=examination_id)
19
19
  findings = exam.get_available_findings()
20
20
 
21
- response_format = request.query_params.get('format', 'optimized')
22
- if response_format == 'multilingual':
23
- return Response([
24
- build_multilingual_response(f)
25
- for f in findings
26
- ])
21
+ response_format = request.query_params.get("format", "optimized")
22
+ if response_format == "multilingual":
23
+ return Response([build_multilingual_response(f) for f in findings])
27
24
  else:
28
25
  serializer = FindingSerializer(findings, many=True)
29
26
  return Response(serializer.data)
30
-
27
+
31
28
 
32
29
  def get_findings_for_patient_examination(request, patient_examination_id):
33
30
  """
34
31
  Retrieve findings for a specific PatientExamination.
35
32
  """
36
33
  # Assuming PatientExamination model has a related_name 'patient_findings' for its findings
37
- patient_examination = get_object_or_404(PatientExamination, id=patient_examination_id)
34
+ patient_examination = get_object_or_404(
35
+ PatientExamination, id=patient_examination_id
36
+ )
38
37
  findings = patient_examination.patient_findings.all()
39
38
  serializer = FindingSerializer(findings, many=True)
40
39
  return Response(serializer.data)
41
-
@@ -3,6 +3,7 @@
3
3
  # FindingClassificationChoice,
4
4
  # )
5
5
  from rest_framework.response import Response
6
+
6
7
  # from django.shortcuts import get_object_or_404
7
8
  from rest_framework.decorators import api_view
8
9
 
@@ -12,7 +13,7 @@ def get_instruments_for_examination(request, exam_id):
12
13
  # Placeholder if you plan to link instruments to exams
13
14
  """
14
15
  Returns an empty list of instruments for the specified examination.
15
-
16
+
16
17
  This placeholder endpoint is intended for future implementation of instrument retrieval linked to an examination.
17
18
  """
18
- return Response([])
19
+ return Response([])
@@ -11,4 +11,4 @@ def get_interventions_for_examination(request, exam_id):
11
11
  exam = get_object_or_404(Examination, id=exam_id)
12
12
  findings = exam.get_available_findings()
13
13
  interventions = FindingIntervention.objects.filter(findings__in=findings).distinct()
14
- return Response([{"id": i.id, "name": i.name} for i in interventions])
14
+ return Response([{"id": i.id, "name": i.name} for i in interventions])
@@ -5,5 +5,5 @@ from .get_classifications import get_classifications_for_finding
5
5
  __all__ = [
6
6
  "FindingViewSet",
7
7
  "get_interventions_for_finding",
8
- "get_classifications_for_finding"
9
- ]
8
+ "get_classifications_for_finding",
9
+ ]
@@ -6,12 +6,13 @@ from rest_framework.response import Response
6
6
  from endoreg_db.models import Finding
7
7
  from ...serializers.finding import FindingSerializer
8
8
 
9
+
9
10
  class FindingViewSet(ReadOnlyModelViewSet):
10
11
  queryset = Finding.objects.all()
11
12
  serializer_class = FindingSerializer
12
13
  permission_classes = [IsAuthenticatedOrReadOnly]
13
14
 
14
- @action(detail=True, methods=['get'])
15
+ @action(detail=True, methods=["get"])
15
16
  def location_classifications(self, request, pk=None):
16
17
  """
17
18
  Get location classifications for a specific finding.
@@ -19,46 +20,48 @@ class FindingViewSet(ReadOnlyModelViewSet):
19
20
  """
20
21
  try:
21
22
  finding = self.get_object()
22
-
23
+
23
24
  assert isinstance(finding, Finding), "Finding object is not valid"
24
25
  location_classifications = finding.get_location_classifications()
25
-
26
+
26
27
  # Return with choices included
27
28
  result = []
28
29
  for lc in location_classifications:
29
30
  lc_data = {
30
- 'id': lc.id,
31
- 'name': lc.name,
32
- 'name_de': getattr(lc, 'name_de', ''),
33
- 'name_en': getattr(lc, 'name_en', ''),
34
- 'description': getattr(lc, 'description', ''),
35
- 'description_de': getattr(lc, 'description_de', ''),
36
- 'description_en': getattr(lc, 'description_en', ''),
37
- 'required': True, # TODO: Determine if required or optional
38
- 'choices': []
31
+ "id": lc.id,
32
+ "name": lc.name,
33
+ "name_de": getattr(lc, "name_de", ""),
34
+ "name_en": getattr(lc, "name_en", ""),
35
+ "description": getattr(lc, "description", ""),
36
+ "description_de": getattr(lc, "description_de", ""),
37
+ "description_en": getattr(lc, "description_en", ""),
38
+ "required": True, # TODO: Determine if required or optional
39
+ "choices": [],
39
40
  }
40
-
41
+
41
42
  # Get choices for this classification
42
43
  choices = lc.get_choices()
43
44
  for choice in choices:
44
- lc_data['choices'].append({
45
- 'id': choice.id,
46
- 'name': choice.name,
47
- 'name_de': getattr(choice, 'name_de', ''),
48
- 'name_en': getattr(choice, 'name_en', ''),
49
- 'description': getattr(choice, 'description', ''),
50
- 'description_de': getattr(choice, 'description_de', ''),
51
- 'description_en': getattr(choice, 'description_en', ''),
52
- 'classificationId': lc.id
53
- })
54
-
45
+ lc_data["choices"].append(
46
+ {
47
+ "id": choice.id,
48
+ "name": choice.name,
49
+ "name_de": getattr(choice, "name_de", ""),
50
+ "name_en": getattr(choice, "name_en", ""),
51
+ "description": getattr(choice, "description", ""),
52
+ "description_de": getattr(choice, "description_de", ""),
53
+ "description_en": getattr(choice, "description_en", ""),
54
+ "classificationId": lc.id,
55
+ }
56
+ )
57
+
55
58
  result.append(lc_data)
56
-
59
+
57
60
  return Response(result)
58
61
  except Exception as e:
59
- return Response({'error': str(e)}, status=500)
62
+ return Response({"error": str(e)}, status=500)
60
63
 
61
- @action(detail=True, methods=['get'])
64
+ @action(detail=True, methods=["get"])
62
65
  def morphology_classifications(self, request, pk=None):
63
66
  """
64
67
  Get morphology classifications for a specific finding.
@@ -68,45 +71,46 @@ class FindingViewSet(ReadOnlyModelViewSet):
68
71
  finding = self.get_object()
69
72
  assert isinstance(finding, Finding), "Finding object is not valid"
70
73
  morphology_classifications = finding.get_morphology_classifications()
71
-
74
+
72
75
  # Return with choices included
73
76
  result = []
74
77
  for mc in morphology_classifications:
75
78
  mc_data = {
76
- 'id': mc.id,
77
- 'name': mc.name,
78
- 'name_de': getattr(mc, 'name_de', ''),
79
- 'name_en': getattr(mc, 'name_en', ''),
80
- 'description': getattr(mc, 'description', ''),
81
- 'description_de': getattr(mc, 'description_de', ''),
82
- 'description_en': getattr(mc, 'description_en', ''),
83
- 'required': True, # TODO: Determine if required or optional
84
- 'choices': []
79
+ "id": mc.id,
80
+ "name": mc.name,
81
+ "name_de": getattr(mc, "name_de", ""),
82
+ "name_en": getattr(mc, "name_en", ""),
83
+ "description": getattr(mc, "description", ""),
84
+ "description_de": getattr(mc, "description_de", ""),
85
+ "description_en": getattr(mc, "description_en", ""),
86
+ "required": True, # TODO: Determine if required or optional
87
+ "choices": [],
85
88
  }
86
-
89
+
87
90
  # Get choices for this classification
88
91
  choices = mc.get_choices()
89
92
  for choice in choices:
90
- mc_data['choices'].append({
91
- 'id': choice.id,
92
- 'name': choice.name,
93
- 'name_de': getattr(choice, 'name_de', ''),
94
- 'name_en': getattr(choice, 'name_en', ''),
95
- 'description': getattr(choice, 'description', ''),
96
- 'description_de': getattr(choice, 'description_de', ''),
97
- 'description_en': getattr(choice, 'description_en', ''),
98
- 'classificationId': mc.id
99
- })
100
-
93
+ mc_data["choices"].append(
94
+ {
95
+ "id": choice.id,
96
+ "name": choice.name,
97
+ "name_de": getattr(choice, "name_de", ""),
98
+ "name_en": getattr(choice, "name_en", ""),
99
+ "description": getattr(choice, "description", ""),
100
+ "description_de": getattr(choice, "description_de", ""),
101
+ "description_en": getattr(choice, "description_en", ""),
102
+ "classificationId": mc.id,
103
+ }
104
+ )
105
+
101
106
  result.append(mc_data)
102
-
107
+
103
108
  return Response(result)
104
109
  except Exception as e:
105
- return Response({'error': str(e)}, status=500)
106
-
107
- @action(detail=False, methods=['get'], url_path='by-id/(?P<finding_id>[^/.]+)')
110
+ return Response({"error": str(e)}, status=500)
111
+
112
+ @action(detail=False, methods=["get"], url_path="by-id/(?P<finding_id>[^/.]+)")
108
113
  def get_finding_by_id(self, request, finding_id=None):
109
114
  findings_obj = Finding.objects.filter(id=finding_id)
110
115
  serializer = FindingSerializer(findings_obj, many=False)
111
116
  return Response(serializer.data)
112
-
@@ -11,4 +11,4 @@ def get_classifications_for_finding(request, finding_id):
11
11
  finding = get_object_or_404(Finding, id=finding_id)
12
12
  classifications = finding.get_classifications()
13
13
 
14
- return Response([{"id": i.id, "name": i.name} for i in classifications])
14
+ return Response([{"id": i.id, "name": i.name} for i in classifications])
@@ -14,4 +14,4 @@ def get_interventions_for_finding(request, exam_id, finding_id):
14
14
  if finding not in exam_findings:
15
15
  return Response({"error": "Finding not found for this examination"}, status=404)
16
16
  interventions = finding.finding_interventions.all()
17
- return Response([{"id": i.id, "name": i.name} for i in interventions])
17
+ return Response([{"id": i.id, "name": i.name} for i in interventions])
@@ -1,13 +1,13 @@
1
1
  from .finding_classification import FindingClassificationViewSet
2
2
  from .get_classification_choices import (
3
3
  get_classification_choices,
4
- get_morphology_choices, # DEPRECATED
5
- get_location_choices, # DEPRECATED
4
+ get_morphology_choices, # DEPRECATED
5
+ get_location_choices, # DEPRECATED
6
6
  )
7
7
 
8
8
  __all__ = [
9
9
  "FindingClassificationViewSet",
10
10
  "get_classification_choices",
11
- "get_morphology_choices", # DEPRECATED
12
- "get_location_choices", # DEPRECATED
13
- ]
11
+ "get_morphology_choices", # DEPRECATED
12
+ "get_location_choices", # DEPRECATED
13
+ ]
@@ -12,12 +12,13 @@ from ...serializers.finding_classification import (
12
12
  FindingClassificationChoiceSerializer,
13
13
  )
14
14
 
15
+
15
16
  class FindingClassificationViewSet(ReadOnlyModelViewSet):
16
17
  queryset = FindingClassification.objects.all()
17
18
  serializer_class = FindingClassificationSerializer
18
19
  permission_classes = [IsAuthenticatedOrReadOnly]
19
20
 
20
- @action(detail=True, methods=['get'])
21
+ @action(detail=True, methods=["get"])
21
22
  def choices(self, request, pk=None):
22
23
  """
23
24
  Get choices for a specific location classification.
@@ -26,17 +27,15 @@ class FindingClassificationViewSet(ReadOnlyModelViewSet):
26
27
  try:
27
28
  classification = self.get_object()
28
29
  choices = classification.get_choices()
29
-
30
+
30
31
  serializer = FindingClassificationChoiceSerializer(choices, many=True)
31
32
  return Response(serializer.data)
32
33
  except FindingClassification.DoesNotExist:
33
34
  return Response(
34
35
  {"error": "FindingClassification not found"},
35
- status=status.HTTP_404_NOT_FOUND
36
+ status=status.HTTP_404_NOT_FOUND,
36
37
  )
37
38
  except Exception as e:
38
39
  return Response(
39
- {"error": str(e)},
40
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
40
+ {"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR
41
41
  )
42
-
@@ -5,6 +5,7 @@ from django.http import JsonResponse
5
5
  from django.views.decorators.http import require_GET
6
6
  import warnings
7
7
 
8
+
8
9
  @require_GET
9
10
  def get_classification_choices(request, classification_id):
10
11
  """
@@ -30,7 +31,7 @@ def get_location_choices(request, location_id):
30
31
  "The get_location_choices function is deprecated and will be removed in future versions. "
31
32
  "Use the 'get_classification_choices' function instead.",
32
33
  DeprecationWarning,
33
- stacklevel=2
34
+ stacklevel=2,
34
35
  )
35
36
 
36
37
  # Fetch location choices using the new method
@@ -46,10 +47,8 @@ def get_morphology_choices(request, morphology_id):
46
47
  "The get_morphology_choices function is deprecated and will be removed in future versions. "
47
48
  "Use the 'get_classification_choices' function instead.",
48
49
  DeprecationWarning,
49
- stacklevel=2
50
+ stacklevel=2,
50
51
  )
51
52
 
52
53
  # Fetch morphology choices using the new method
53
54
  return get_classification_choices(request, morphology_id)
54
-
55
-