endoreg-db 0.8.6.1__py3-none-any.whl → 0.8.8.0__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 (360) hide show
  1. endoreg_db/authz/auth.py +74 -0
  2. endoreg_db/authz/backends.py +168 -0
  3. endoreg_db/authz/management/commands/list_routes.py +18 -0
  4. endoreg_db/authz/middleware.py +83 -0
  5. endoreg_db/authz/permissions.py +127 -0
  6. endoreg_db/authz/policy.py +218 -0
  7. endoreg_db/authz/views_auth.py +66 -0
  8. endoreg_db/config/env.py +13 -8
  9. endoreg_db/data/__init__.py +8 -31
  10. endoreg_db/data/_examples/disease.yaml +55 -0
  11. endoreg_db/data/_examples/disease_classification.yaml +13 -0
  12. endoreg_db/data/_examples/disease_classification_choice.yaml +62 -0
  13. endoreg_db/data/_examples/event.yaml +64 -0
  14. endoreg_db/data/_examples/examination.yaml +72 -0
  15. endoreg_db/data/_examples/finding/anatomy_colon.yaml +128 -0
  16. endoreg_db/data/_examples/finding/colonoscopy.yaml +40 -0
  17. endoreg_db/data/_examples/finding/colonoscopy_bowel_prep.yaml +56 -0
  18. endoreg_db/data/_examples/finding/complication.yaml +16 -0
  19. endoreg_db/data/_examples/finding/data.yaml +105 -0
  20. endoreg_db/data/_examples/finding/examination_setting.yaml +16 -0
  21. endoreg_db/data/_examples/finding/medication_related.yaml +18 -0
  22. endoreg_db/data/_examples/finding/outcome.yaml +12 -0
  23. endoreg_db/data/_examples/finding_classification/colonoscopy_bowel_preparation.yaml +68 -0
  24. endoreg_db/data/_examples/finding_classification/colonoscopy_jnet.yaml +22 -0
  25. endoreg_db/data/_examples/finding_classification/colonoscopy_kudo.yaml +25 -0
  26. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_circularity.yaml +20 -0
  27. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_planarity.yaml +24 -0
  28. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_size.yaml +68 -0
  29. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_surface.yaml +20 -0
  30. endoreg_db/data/_examples/finding_classification/colonoscopy_location.yaml +80 -0
  31. endoreg_db/data/_examples/finding_classification/colonoscopy_lst.yaml +21 -0
  32. endoreg_db/data/_examples/finding_classification/colonoscopy_nice.yaml +20 -0
  33. endoreg_db/data/_examples/finding_classification/colonoscopy_paris.yaml +26 -0
  34. endoreg_db/data/_examples/finding_classification/colonoscopy_sano.yaml +22 -0
  35. endoreg_db/data/_examples/finding_classification/colonoscopy_summary.yaml +53 -0
  36. endoreg_db/data/_examples/finding_classification/complication_generic.yaml +25 -0
  37. endoreg_db/data/_examples/finding_classification/examination_setting_generic.yaml +40 -0
  38. endoreg_db/data/_examples/finding_classification/histology_colo.yaml +51 -0
  39. endoreg_db/data/_examples/finding_classification/intervention_required.yaml +26 -0
  40. endoreg_db/data/_examples/finding_classification/medication_related.yaml +23 -0
  41. endoreg_db/data/_examples/finding_classification/visualized.yaml +33 -0
  42. endoreg_db/data/_examples/finding_classification_choice/bowel_preparation.yaml +78 -0
  43. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_circularity_default.yaml +32 -0
  44. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_jnet.yaml +15 -0
  45. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_kudo.yaml +23 -0
  46. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_lst.yaml +15 -0
  47. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_nice.yaml +17 -0
  48. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_paris.yaml +57 -0
  49. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_planarity_default.yaml +49 -0
  50. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_sano.yaml +14 -0
  51. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_surface_intact_default.yaml +36 -0
  52. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_location.yaml +229 -0
  53. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_not_complete_reason.yaml +19 -0
  54. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_size.yaml +82 -0
  55. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +15 -0
  56. endoreg_db/data/_examples/finding_classification_choice/complication_generic_types.yaml +15 -0
  57. endoreg_db/data/_examples/finding_classification_choice/examination_setting_generic_types.yaml +15 -0
  58. endoreg_db/data/_examples/finding_classification_choice/histology.yaml +24 -0
  59. endoreg_db/data/_examples/finding_classification_choice/histology_polyp.yaml +20 -0
  60. endoreg_db/data/_examples/finding_classification_choice/outcome.yaml +19 -0
  61. endoreg_db/data/_examples/finding_classification_choice/yes_no_na.yaml +11 -0
  62. endoreg_db/data/_examples/finding_classification_type/colonoscopy_basic.yaml +48 -0
  63. endoreg_db/data/_examples/finding_intervention/endoscopy.yaml +43 -0
  64. endoreg_db/data/_examples/finding_intervention/endoscopy_colonoscopy.yaml +168 -0
  65. endoreg_db/data/_examples/finding_intervention/endoscopy_egd.yaml +128 -0
  66. endoreg_db/data/_examples/finding_intervention/endoscopy_ercp.yaml +32 -0
  67. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_lower.yaml +9 -0
  68. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_upper.yaml +36 -0
  69. endoreg_db/data/_examples/finding_intervention_type/endoscopy.yaml +15 -0
  70. endoreg_db/data/_examples/finding_type/data.yaml +43 -0
  71. endoreg_db/data/_examples/requirement/age.yaml +26 -0
  72. endoreg_db/data/_examples/requirement/colonoscopy_baseline_austria.yaml +45 -0
  73. endoreg_db/data/_examples/requirement/disease_cardiovascular.yaml +79 -0
  74. endoreg_db/data/_examples/requirement/disease_classification_choice_cardiovascular.yaml +41 -0
  75. endoreg_db/data/_examples/requirement/disease_hepatology.yaml +12 -0
  76. endoreg_db/data/_examples/requirement/disease_misc.yaml +12 -0
  77. endoreg_db/data/_examples/requirement/disease_renal.yaml +96 -0
  78. endoreg_db/data/_examples/requirement/endoscopy_bleeding_risk.yaml +59 -0
  79. endoreg_db/data/_examples/requirement/event_cardiology.yaml +251 -0
  80. endoreg_db/data/_examples/requirement/event_requirements.yaml +145 -0
  81. endoreg_db/data/_examples/requirement/finding_colon_polyp.yaml +50 -0
  82. endoreg_db/data/_examples/requirement/gender.yaml +25 -0
  83. endoreg_db/data/_examples/requirement/lab_value.yaml +441 -0
  84. endoreg_db/data/_examples/requirement/medication.yaml +93 -0
  85. endoreg_db/data/_examples/requirement_operator/age.yaml +13 -0
  86. endoreg_db/data/_examples/requirement_operator/lab_operators.yaml +129 -0
  87. endoreg_db/data/_examples/requirement_operator/model_operators.yaml +96 -0
  88. endoreg_db/data/_examples/requirement_set/01_endoscopy_generic.yaml +48 -0
  89. endoreg_db/data/_examples/requirement_set/colonoscopy_austria_screening.yaml +57 -0
  90. endoreg_db/data/_examples/yaml_examples.xlsx +0 -0
  91. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +4 -3
  92. endoreg_db/data/event_classification/data.yaml +4 -0
  93. endoreg_db/data/event_classification_choice/data.yaml +9 -0
  94. endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +43 -70
  95. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +22 -52
  96. endoreg_db/data/finding_classification/colonoscopy_location.yaml +31 -62
  97. endoreg_db/data/finding_classification/histology_colo.yaml +28 -36
  98. endoreg_db/data/requirement/colon_polyp_intervention.yaml +49 -0
  99. endoreg_db/data/requirement/coloreg_colon_polyp.yaml +49 -0
  100. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +31 -12
  101. endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
  102. endoreg_db/data/requirement_set/02_endoscopy_bleeding_risk.yaml +46 -0
  103. endoreg_db/data/requirement_set/90_coloreg.yaml +178 -0
  104. endoreg_db/data/requirement_set/_old_ +109 -0
  105. endoreg_db/data/requirement_set_type/data.yaml +21 -0
  106. endoreg_db/data/setup_config.yaml +4 -4
  107. endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
  108. endoreg_db/exceptions.py +5 -2
  109. endoreg_db/helpers/data_loader.py +1 -1
  110. endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
  111. endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
  112. endoreg_db/management/commands/import_video.py +9 -10
  113. endoreg_db/management/commands/import_video_with_classification.py +1 -1
  114. endoreg_db/management/commands/init_default_ai_model.py +1 -1
  115. endoreg_db/management/commands/list_routes.py +18 -0
  116. endoreg_db/management/commands/load_center_data.py +12 -12
  117. endoreg_db/management/commands/load_requirement_data.py +60 -31
  118. endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
  119. endoreg_db/management/commands/setup_endoreg_db.py +3 -3
  120. endoreg_db/management/commands/storage_management.py +271 -203
  121. endoreg_db/migrations/0001_initial.py +1799 -1300
  122. endoreg_db/migrations/0002_requirementset_depends_on.py +18 -0
  123. endoreg_db/migrations/_old/0001_initial.py +1857 -0
  124. endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +68 -0
  125. endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +77 -0
  126. endoreg_db/migrations/_old/0005_merge_20251111_1003.py +14 -0
  127. endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +68 -0
  128. endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +89 -0
  129. endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +27 -0
  130. endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +21 -0
  131. endoreg_db/models/__init__.py +78 -123
  132. endoreg_db/models/administration/__init__.py +21 -42
  133. endoreg_db/models/administration/ai/active_model.py +2 -2
  134. endoreg_db/models/administration/ai/ai_model.py +7 -6
  135. endoreg_db/models/administration/case/__init__.py +1 -15
  136. endoreg_db/models/administration/case/case.py +3 -3
  137. endoreg_db/models/administration/case/case_template/__init__.py +2 -14
  138. endoreg_db/models/administration/case/case_template/case_template.py +2 -124
  139. endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
  140. endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
  141. endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
  142. endoreg_db/models/administration/center/center.py +33 -19
  143. endoreg_db/models/administration/center/center_product.py +12 -9
  144. endoreg_db/models/administration/center/center_resource.py +25 -19
  145. endoreg_db/models/administration/center/center_shift.py +21 -17
  146. endoreg_db/models/administration/center/center_waste.py +16 -8
  147. endoreg_db/models/administration/person/__init__.py +2 -0
  148. endoreg_db/models/administration/person/employee/employee.py +10 -5
  149. endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
  150. endoreg_db/models/administration/person/employee/employee_type.py +12 -6
  151. endoreg_db/models/administration/person/examiner/examiner.py +13 -11
  152. endoreg_db/models/administration/person/patient/__init__.py +2 -0
  153. endoreg_db/models/administration/person/patient/patient.py +103 -100
  154. endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
  155. endoreg_db/models/administration/person/person.py +4 -0
  156. endoreg_db/models/administration/person/profession/__init__.py +8 -4
  157. endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
  158. endoreg_db/models/administration/product/product.py +20 -15
  159. endoreg_db/models/administration/product/product_material.py +17 -18
  160. endoreg_db/models/administration/product/product_weight.py +12 -8
  161. endoreg_db/models/administration/product/reference_product.py +23 -55
  162. endoreg_db/models/administration/qualification/qualification.py +7 -3
  163. endoreg_db/models/administration/qualification/qualification_type.py +7 -3
  164. endoreg_db/models/administration/shift/scheduled_days.py +8 -5
  165. endoreg_db/models/administration/shift/shift.py +16 -12
  166. endoreg_db/models/administration/shift/shift_type.py +23 -31
  167. endoreg_db/models/label/__init__.py +7 -8
  168. endoreg_db/models/label/annotation/image_classification.py +10 -9
  169. endoreg_db/models/label/annotation/video_segmentation_annotation.py +8 -5
  170. endoreg_db/models/label/label.py +15 -15
  171. endoreg_db/models/label/label_set.py +19 -6
  172. endoreg_db/models/label/label_type.py +1 -1
  173. endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
  174. endoreg_db/models/label/label_video_segment/label_video_segment.py +76 -102
  175. endoreg_db/models/label/video_segmentation_label.py +4 -0
  176. endoreg_db/models/label/video_segmentation_labelset.py +4 -3
  177. endoreg_db/models/media/frame/frame.py +22 -22
  178. endoreg_db/models/media/pdf/raw_pdf.py +110 -182
  179. endoreg_db/models/media/pdf/report_file.py +25 -29
  180. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +30 -46
  181. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
  182. endoreg_db/models/media/video/__init__.py +1 -0
  183. endoreg_db/models/media/video/create_from_file.py +48 -56
  184. endoreg_db/models/media/video/pipe_2.py +8 -9
  185. endoreg_db/models/media/video/video_file.py +150 -108
  186. endoreg_db/models/media/video/video_file_ai.py +288 -74
  187. endoreg_db/models/media/video/video_file_anonymize.py +38 -38
  188. endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
  189. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
  190. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
  191. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
  192. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
  193. endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
  194. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
  195. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
  196. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
  197. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
  198. endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
  199. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
  200. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
  201. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
  202. endoreg_db/models/media/video/video_file_io.py +109 -62
  203. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
  204. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
  205. endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
  206. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
  207. endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
  208. endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
  209. endoreg_db/models/media/video/video_file_segments.py +24 -17
  210. endoreg_db/models/media/video/video_metadata.py +19 -35
  211. endoreg_db/models/media/video/video_processing.py +96 -95
  212. endoreg_db/models/medical/contraindication/__init__.py +13 -3
  213. endoreg_db/models/medical/disease.py +22 -16
  214. endoreg_db/models/medical/event.py +31 -18
  215. endoreg_db/models/medical/examination/__init__.py +13 -6
  216. endoreg_db/models/medical/examination/examination.py +17 -18
  217. endoreg_db/models/medical/examination/examination_indication.py +26 -25
  218. endoreg_db/models/medical/examination/examination_time.py +16 -6
  219. endoreg_db/models/medical/examination/examination_time_type.py +9 -6
  220. endoreg_db/models/medical/examination/examination_type.py +3 -4
  221. endoreg_db/models/medical/finding/finding.py +38 -39
  222. endoreg_db/models/medical/finding/finding_classification.py +37 -48
  223. endoreg_db/models/medical/finding/finding_intervention.py +27 -22
  224. endoreg_db/models/medical/finding/finding_type.py +13 -12
  225. endoreg_db/models/medical/hardware/endoscope.py +20 -26
  226. endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
  227. endoreg_db/models/medical/laboratory/lab_value.py +62 -91
  228. endoreg_db/models/medical/medication/medication.py +22 -10
  229. endoreg_db/models/medical/medication/medication_indication.py +29 -3
  230. endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
  231. endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
  232. endoreg_db/models/medical/medication/medication_schedule.py +27 -16
  233. endoreg_db/models/medical/organ/__init__.py +15 -12
  234. endoreg_db/models/medical/patient/medication_examples.py +1 -5
  235. endoreg_db/models/medical/patient/patient_disease.py +20 -23
  236. endoreg_db/models/medical/patient/patient_event.py +19 -22
  237. endoreg_db/models/medical/patient/patient_examination.py +48 -54
  238. endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
  239. endoreg_db/models/medical/patient/patient_finding.py +122 -139
  240. endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
  241. endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
  242. endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
  243. endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
  244. endoreg_db/models/medical/patient/patient_medication.py +27 -38
  245. endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
  246. endoreg_db/models/medical/risk/risk.py +7 -6
  247. endoreg_db/models/medical/risk/risk_type.py +8 -5
  248. endoreg_db/models/metadata/model_meta.py +60 -29
  249. endoreg_db/models/metadata/model_meta_logic.py +125 -18
  250. endoreg_db/models/metadata/pdf_meta.py +19 -24
  251. endoreg_db/models/metadata/sensitive_meta.py +102 -85
  252. endoreg_db/models/metadata/sensitive_meta_logic.py +192 -173
  253. endoreg_db/models/metadata/video_meta.py +51 -31
  254. endoreg_db/models/metadata/video_prediction_logic.py +16 -23
  255. endoreg_db/models/metadata/video_prediction_meta.py +29 -33
  256. endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
  257. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
  258. endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
  259. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
  260. endoreg_db/models/other/emission/emission_factor.py +18 -8
  261. endoreg_db/models/other/gender.py +10 -5
  262. endoreg_db/models/other/information_source.py +25 -25
  263. endoreg_db/models/other/material.py +9 -5
  264. endoreg_db/models/other/resource.py +6 -4
  265. endoreg_db/models/other/tag.py +10 -5
  266. endoreg_db/models/other/transport_route.py +13 -8
  267. endoreg_db/models/other/unit.py +10 -6
  268. endoreg_db/models/other/waste.py +6 -5
  269. endoreg_db/models/requirement/requirement.py +580 -272
  270. endoreg_db/models/requirement/requirement_error.py +85 -0
  271. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
  272. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
  273. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
  274. endoreg_db/models/requirement/requirement_operator.py +36 -33
  275. endoreg_db/models/requirement/requirement_set.py +74 -57
  276. endoreg_db/models/state/__init__.py +4 -4
  277. endoreg_db/models/state/abstract.py +2 -2
  278. endoreg_db/models/state/anonymization.py +12 -0
  279. endoreg_db/models/state/audit_ledger.py +46 -47
  280. endoreg_db/models/state/label_video_segment.py +9 -0
  281. endoreg_db/models/state/raw_pdf.py +40 -46
  282. endoreg_db/models/state/sensitive_meta.py +6 -2
  283. endoreg_db/models/state/video.py +58 -53
  284. endoreg_db/models/upload_job.py +32 -55
  285. endoreg_db/models/utils.py +1 -2
  286. endoreg_db/root_urls.py +21 -2
  287. endoreg_db/serializers/__init__.py +0 -2
  288. endoreg_db/serializers/anonymization.py +18 -10
  289. endoreg_db/serializers/meta/report_meta.py +1 -1
  290. endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
  291. endoreg_db/serializers/misc/file_overview.py +11 -99
  292. endoreg_db/serializers/requirements/requirement_sets.py +92 -22
  293. endoreg_db/serializers/video/segmentation.py +2 -1
  294. endoreg_db/serializers/video/video_processing_history.py +20 -5
  295. endoreg_db/services/anonymization.py +75 -73
  296. endoreg_db/services/lookup_service.py +37 -24
  297. endoreg_db/services/pdf_import.py +166 -68
  298. endoreg_db/services/storage_aware_video_processor.py +140 -114
  299. endoreg_db/services/video_import.py +193 -283
  300. endoreg_db/urls/__init__.py +7 -20
  301. endoreg_db/urls/media.py +108 -67
  302. endoreg_db/urls/root_urls.py +29 -0
  303. endoreg_db/utils/__init__.py +15 -5
  304. endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
  305. endoreg_db/utils/case_generator/__init__.py +3 -0
  306. endoreg_db/utils/dataloader.py +88 -16
  307. endoreg_db/utils/defaults/set_default_center.py +32 -0
  308. endoreg_db/utils/names.py +22 -16
  309. endoreg_db/utils/permissions.py +2 -1
  310. endoreg_db/utils/pipelines/process_video_dir.py +1 -1
  311. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +414 -127
  312. endoreg_db/utils/setup_config.py +8 -5
  313. endoreg_db/utils/storage.py +115 -0
  314. endoreg_db/utils/validate_endo_roi.py +8 -2
  315. endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
  316. endoreg_db/views/__init__.py +0 -10
  317. endoreg_db/views/anonymization/media_management.py +198 -163
  318. endoreg_db/views/anonymization/overview.py +4 -1
  319. endoreg_db/views/anonymization/validate.py +174 -40
  320. endoreg_db/views/media/__init__.py +2 -0
  321. endoreg_db/views/media/pdf_media.py +131 -152
  322. endoreg_db/views/media/sensitive_metadata.py +46 -6
  323. endoreg_db/views/media/video_media.py +89 -82
  324. endoreg_db/views/media/video_segments.py +2 -3
  325. endoreg_db/views/meta/sensitive_meta_detail.py +0 -63
  326. endoreg_db/views/patient/patient.py +5 -4
  327. endoreg_db/views/pdf/pdf_stream.py +20 -21
  328. endoreg_db/views/pdf/reimport.py +11 -32
  329. endoreg_db/views/requirement/evaluate.py +188 -187
  330. endoreg_db/views/requirement/lookup.py +17 -3
  331. endoreg_db/views/requirement/requirement_utils.py +89 -0
  332. endoreg_db/views/video/__init__.py +0 -2
  333. endoreg_db/views/video/correction.py +2 -2
  334. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/METADATA +7 -3
  335. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/RECORD +341 -245
  336. endoreg_db/models/administration/permissions/__init__.py +0 -44
  337. endoreg_db/models/media/video/video_file_frames.py +0 -0
  338. endoreg_db/models/metadata/frame_ocr_result.py +0 -0
  339. endoreg_db/models/rule/__init__.py +0 -13
  340. endoreg_db/models/rule/rule.py +0 -27
  341. endoreg_db/models/rule/rule_applicator.py +0 -224
  342. endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
  343. endoreg_db/models/rule/rule_type.py +0 -20
  344. endoreg_db/models/rule/ruleset.py +0 -17
  345. endoreg_db/serializers/video/video_metadata.py +0 -105
  346. endoreg_db/urls/report.py +0 -48
  347. endoreg_db/urls/video.py +0 -61
  348. endoreg_db/utils/case_generator/case_generator.py +0 -159
  349. endoreg_db/utils/case_generator/utils.py +0 -30
  350. endoreg_db/views/report/__init__.py +0 -9
  351. endoreg_db/views/report/report_list.py +0 -112
  352. endoreg_db/views/report/report_with_secure_url.py +0 -28
  353. endoreg_db/views/report/start_examination.py +0 -7
  354. endoreg_db/views.py +0 -0
  355. /endoreg_db/data/{requirement_set → _examples/requirement_set}/endoscopy_bleeding_risk.yaml +0 -0
  356. /endoreg_db/migrations/{0002_add_video_correction_models.py → _old/0002_add_video_correction_models.py} +0 -0
  357. /endoreg_db/migrations/{0003_add_center_display_name.py → _old/0003_add_center_display_name.py} +0 -0
  358. /endoreg_db/{models/media/video/refactor_plan.md → views/pdf/pdf_stream_views.py} +0 -0
  359. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/WHEEL +0 -0
  360. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,44 +1,56 @@
1
- '''Model for medication intake time'''
1
+ """Model for medication intake time"""
2
+
3
+ from typing import TYPE_CHECKING
4
+
2
5
  from django.db import models
3
6
 
4
7
 
5
8
  class MedicationIntakeTimeManager(models.Manager):
6
- '''Manager for the medication intake time model.'''
9
+ """Manager for the medication intake time model."""
10
+
7
11
  def get_by_natural_key(self, name):
8
- '''Retrieve a medication intake time by its natural key.'''
12
+ """Retrieve a medication intake time by its natural key."""
9
13
  return self.get(name=name)
10
-
14
+
15
+
11
16
  class MedicationIntakeTime(models.Model):
12
- '''Model representing a medication intake time.'''
13
- name = models.CharField(max_length=255, unique=True) # Made unique=True
14
- repeats = models.CharField(max_length=20, default = "daily")
17
+ """Model representing a medication intake time."""
18
+
19
+ name = models.CharField(max_length=255, unique=True) # Made unique=True
20
+ repeats = models.CharField(max_length=20, default="daily")
15
21
  time = models.TimeField()
16
22
 
17
23
  objects = MedicationIntakeTimeManager()
18
24
 
25
+ if TYPE_CHECKING:
26
+ from endoreg_db.models import MedicationSchedule
27
+
28
+ @property
29
+ def medication_schedules(self) -> "models.manager.RelatedManager[MedicationSchedule]": ...
30
+
19
31
  @classmethod
20
32
  def dm(cls):
21
- '''Return the daily morning intake time object.'''
22
- return cls.objects.get(name='daily-morning')
23
-
33
+ """Return the daily morning intake time object."""
34
+ return cls.objects.get(name="daily-morning")
35
+
24
36
  @classmethod
25
37
  def dno(cls):
26
- '''Return the daily noon intake time object.'''
27
- return cls.objects.get(name='daily-noon')
38
+ """Return the daily noon intake time object."""
39
+ return cls.objects.get(name="daily-noon")
28
40
 
29
41
  @classmethod
30
42
  def de(cls):
31
- '''Return the daily evening intake time object.'''
32
- return cls.objects.get(name='daily-evening')
33
-
43
+ """Return the daily evening intake time object."""
44
+ return cls.objects.get(name="daily-evening")
45
+
34
46
  @classmethod
35
47
  def dn(cls):
36
- '''Return the daily night intake time object.'''
37
- return cls.objects.get(name='daily-night')
48
+ """Return the daily night intake time object."""
49
+ return cls.objects.get(name="daily-night")
38
50
 
39
51
  def natural_key(self):
40
- '''Return the natural key for the medication intake time.'''
52
+ """Return the natural key for the medication intake time."""
41
53
  return (self.name,)
42
-
54
+
43
55
  def __str__(self):
44
56
  return self.name + " at " + str(self.time) + " (" + self.repeats + ")"
@@ -1,45 +1,56 @@
1
- '''Model for the medication schedule.'''
2
- from typing import List, TYPE_CHECKING
1
+ """Model for the medication schedule."""
2
+
3
+ from typing import TYPE_CHECKING, List, cast
4
+
3
5
  from django.db import models
4
6
 
5
7
  if TYPE_CHECKING:
6
- from endoreg_db.models import MedicationIntakeTime
8
+ from endoreg_db.models import Medication, MedicationIntakeTime, Unit
9
+
10
+
7
11
  class MedicationScheduleManager(models.Manager):
8
- '''Manager for the medication schedule model.'''
12
+ """Manager for the medication schedule model."""
13
+
9
14
  def get_by_natural_key(self, name):
10
15
  """
11
16
  Retrieve a MedicationSchedule instance by its name.
12
-
17
+
13
18
  Parameters:
14
19
  name (str): The name of the medication schedule to retrieve.
15
-
20
+
16
21
  Returns:
17
22
  MedicationSchedule: The matching medication schedule instance.
18
23
  """
19
24
  return self.get(name=name)
20
-
25
+
26
+
21
27
  class MedicationSchedule(models.Model):
22
- '''Model representing a medication schedule.'''
23
- name = models.CharField(max_length=255, unique=True)
28
+ """Model representing a medication schedule."""
29
+
30
+ name = models.CharField(max_length=255, unique=True)
24
31
  description = models.TextField(blank=True, null=True)
25
32
  medication = models.ForeignKey("Medication", on_delete=models.CASCADE)
26
33
  unit = models.ForeignKey("Unit", on_delete=models.CASCADE)
27
34
  therapy_duration_d = models.FloatField(blank=True, null=True)
28
35
  dose = models.FloatField()
29
36
  intake_times = models.ManyToManyField(
30
- "MedicationIntakeTime",
37
+ "MedicationIntakeTime",
31
38
  )
32
39
 
33
40
  objects = MedicationScheduleManager()
34
41
 
42
+ if TYPE_CHECKING:
43
+ unit: models.ForeignKey["Unit"]
44
+ medication: models.ForeignKey["Medication"]
45
+ intake_times = cast("models.manager.RelatedManager[MedicationIntakeTime]", intake_times)
46
+
35
47
  def natural_key(self):
36
- '''Return the natural key for the medication schedule.'''
48
+ """Return the natural key for the medication schedule."""
37
49
  return (self.name,)
38
-
50
+
39
51
  def __str__(self):
40
52
  return str(self.name)
41
-
53
+
42
54
  def get_intake_times(self) -> List["MedicationIntakeTime"]:
43
- '''Return a list of all intake times for this medication schedule.'''
44
- return [_ for _ in self.intake_times.all()] # type: ignore # pylint: disable=E1101
45
-
55
+ """Return a list of all intake times for this medication schedule."""
56
+ return [_ for _ in self.intake_times.all()]
@@ -1,35 +1,38 @@
1
1
  """Module for Organ models."""
2
+
2
3
  from django.db import models
3
4
 
5
+
4
6
  class OrganManager(models.Manager):
5
7
  """Manager for Organ model."""
6
8
 
7
9
  def get_by_natural_key(self, name):
8
10
  """Retrieve an Organ by its natural key."""
9
11
  return self.get(name=name)
10
-
12
+
11
13
  def all_names(self):
12
14
  """Return a list of all organ names."""
13
- return list(self.all().values_list('name', flat=True))
14
-
15
+ return list(self.all().values_list("name", flat=True))
16
+
17
+
15
18
  class Organ(models.Model):
16
19
  """Model representing an organ."""
17
-
18
- name = models.CharField(max_length=100, unique=True)
20
+
21
+ name = models.CharField(max_length=100, unique=True)
19
22
  description = models.TextField(blank=True, null=True)
20
23
 
21
24
  # Deprecated
22
- location_choices = models.ManyToManyField(
23
- 'FindingClassificationChoice',
24
- blank=True, related_name='organs'
25
- )
25
+ # location_choices = models.ManyToManyField(
26
+ # 'FindingClassificationChoice',
27
+ # blank=True, related_name='organs'
28
+ # )
26
29
 
27
30
  objects = OrganManager()
28
-
31
+
29
32
  def natural_key(self):
30
33
  """Return the natural key for the organ."""
31
34
  return (self.name,)
32
-
35
+
33
36
  def __str__(self):
34
37
  """Return string representation of the organ."""
35
- return str(self.name)
38
+ return str(self.name)
@@ -1,12 +1,8 @@
1
1
  from endoreg_db.models import (
2
- Patient,
3
- PatientMedication,
4
- PatientMedicationSchedule,
5
2
  Medication,
6
3
  MedicationIndication,
7
4
  MedicationIndicationType,
8
- MedicationIntakeTime,
9
- MedicationSchedule
5
+ MedicationIntakeTime
10
6
  )
11
7
  from endoreg_db.helpers.default_objects import generate_patient
12
8
 
@@ -1,10 +1,12 @@
1
+ from typing import TYPE_CHECKING, cast # Added List
2
+
1
3
  from django.db import models
2
- from typing import TYPE_CHECKING # Added List
3
4
 
4
5
  if TYPE_CHECKING:
6
+ from endoreg_db.utils.links.requirement_link import RequirementLinks # Added RequirementLinks
7
+
5
8
  from ...administration.person.patient.patient import Patient
6
9
  from ..disease import Disease, DiseaseClassificationChoice
7
- from endoreg_db.utils.links.requirement_link import RequirementLinks # Added RequirementLinks
8
10
 
9
11
 
10
12
  class PatientDisease(models.Model):
@@ -14,14 +16,9 @@ class PatientDisease(models.Model):
14
16
  Links a patient to a disease type, optional classification choices, start/end dates,
15
17
  and stores associated subcategory values and numerical descriptors.
16
18
  """
17
- patient = models.ForeignKey(
18
- "Patient", on_delete=models.CASCADE,
19
- related_name="diseases"
20
- )
21
- disease = models.ForeignKey(
22
- "Disease", on_delete=models.CASCADE,
23
- related_name="patient_diseases"
24
- )
19
+
20
+ patient = models.ForeignKey("Patient", on_delete=models.CASCADE, related_name="diseases")
21
+ disease = models.ForeignKey("Disease", on_delete=models.CASCADE, related_name="patient_diseases")
25
22
  classification_choices = models.ManyToManyField("DiseaseClassificationChoice")
26
23
  start_date = models.DateField(blank=True, null=True)
27
24
  end_date = models.DateField(blank=True, null=True)
@@ -31,33 +28,33 @@ class PatientDisease(models.Model):
31
28
  last_update = models.DateTimeField(auto_now=True)
32
29
 
33
30
  if TYPE_CHECKING:
34
- patient: "Patient"
35
- disease: "Disease"
36
- classification_choices: models.QuerySet["DiseaseClassificationChoice"]
31
+ patient: models.ForeignKey["Patient"]
32
+ disease: models.ForeignKey["Disease"]
33
+
34
+ classification_choices = cast(
35
+ "models.manager.RelatedManager[DiseaseClassificationChoice]",
36
+ classification_choices,
37
+ )
37
38
 
38
39
  def __str__(self):
39
40
  """Returns a string representation including the patient and disease name."""
40
41
  return f"{self.patient} - {self.disease}"
41
-
42
+
42
43
  @property
43
44
  def links(self) -> "RequirementLinks":
44
- from endoreg_db.utils.links.requirement_link import RequirementLinks # Added RequirementLinks
45
+ from endoreg_db.utils.links.requirement_link import RequirementLinks # Added RequirementLinks
45
46
 
46
47
  """
47
48
  Aggregates and returns related model instances relevant for requirement evaluation
48
49
  as a RequirementLinks object.
49
50
  """
50
- links_data = {
51
- "patient_diseases": [self],
52
- "diseases": [],
53
- "disease_classification_choices": list(self.classification_choices.all())
54
- }
51
+ links_data = {"patient_diseases": [self], "diseases": [], "disease_classification_choices": list(self.classification_choices.all())}
55
52
  if self.disease:
56
53
  links_data["diseases"].append(self.disease)
57
-
54
+
58
55
  return RequirementLinks(**links_data)
59
56
 
60
57
  class Meta:
61
58
  # unique_together = ('patient', 'disease', 'start_date')
62
- verbose_name = 'Patient Disease'
63
- verbose_name_plural = 'Patient Diseases'
59
+ verbose_name = "Patient Disease"
60
+ verbose_name_plural = "Patient Diseases"
@@ -1,10 +1,12 @@
1
- from django.db import models
2
1
  from typing import TYPE_CHECKING
3
2
 
3
+ from django.db import models
4
+
4
5
  if TYPE_CHECKING:
5
6
  from ...administration.person.patient.patient import Patient
6
7
  from ..event import Event, EventClassificationChoice
7
8
 
9
+
8
10
  class PatientEvent(models.Model):
9
11
  """
10
12
  Represents a specific event occurrence for a patient, potentially with classification details.
@@ -12,26 +14,24 @@ class PatientEvent(models.Model):
12
14
  Links a patient to an event type, dates, description, and optional classification choices,
13
15
  subcategories, and numerical descriptors.
14
16
  """
15
- patient:models.ForeignKey["Patient"] = models.ForeignKey(
16
- "Patient", on_delete=models.CASCADE,
17
- related_name="events"
18
- )
19
- event:models.ForeignKey["Event"] = models.ForeignKey(
20
- "Event", on_delete=models.CASCADE,
21
- related_name="patient_events"
22
- )
17
+
18
+ patient: models.ForeignKey["Patient"] = models.ForeignKey("Patient", on_delete=models.CASCADE, related_name="events")
19
+ event: models.ForeignKey["Event"] = models.ForeignKey("Event", on_delete=models.CASCADE, related_name="patient_events")
23
20
  date_start = models.DateField()
24
21
  date_end = models.DateField(blank=True, null=True)
25
22
  description = models.TextField(blank=True, null=True)
26
- classification_choice:models.ForeignKey["EventClassificationChoice"] = models.ForeignKey(
27
- "EventClassificationChoice", on_delete=models.CASCADE, blank=True, null=True
28
- )
23
+ classification_choice = models.ForeignKey("EventClassificationChoice", on_delete=models.CASCADE, blank=True, null=True)
29
24
 
30
25
  subcategories = models.JSONField(default=dict)
31
26
  numerical_descriptors = models.JSONField(default=dict)
32
27
 
33
28
  last_update = models.DateTimeField(auto_now=True)
34
29
 
30
+ if TYPE_CHECKING:
31
+ patient: models.ForeignKey["Patient"]
32
+ event: models.ForeignKey["Event"]
33
+ classification_choice: models.ForeignKey["EventClassificationChoice|None"]
34
+
35
35
  @property
36
36
  def links(self):
37
37
  """
@@ -39,12 +39,9 @@ class PatientEvent(models.Model):
39
39
  Currently, it only includes the patient and event.
40
40
  """
41
41
  from endoreg_db.utils.links.requirement_link import RequirementLinks
42
- return RequirementLinks(
43
- patient_events=[self],
44
- patients=[self.patient],
45
- events=[self.event]
46
- )
47
-
42
+
43
+ return RequirementLinks(patient_events=[self], events=[self.event])
44
+
48
45
  @property
49
46
  def date(self):
50
47
  """
@@ -57,19 +54,19 @@ class PatientEvent(models.Model):
57
54
  Returns a string representation of the event's start date and name.
58
55
  """
59
56
  return str(self.date_start) + ": " + self.event.name
60
-
57
+
61
58
  def set_subcategories_from_classification_choice(self):
62
59
  """Copies subcategory definitions from the linked classification choice."""
63
60
  if self.classification_choice:
64
61
  self.subcategories = self.classification_choice.subcategories
65
62
  self.save()
66
-
63
+
67
64
  return self.subcategories
68
-
65
+
69
66
  def set_numerical_descriptors_from_classification_choice(self):
70
67
  """Copies numerical descriptor definitions from the linked classification choice."""
71
68
  if self.classification_choice:
72
69
  self.numerical_descriptors = self.classification_choice.numerical_descriptors
73
70
  self.save()
74
-
71
+
75
72
  return self.numerical_descriptors
@@ -1,48 +1,51 @@
1
- from django.db import models
2
1
  from typing import TYPE_CHECKING, List, Optional
3
2
 
4
- if TYPE_CHECKING:
3
+ from django.db import models
4
+
5
+ if TYPE_CHECKING:
6
+ from endoreg_db.utils.links.requirement_link import RequirementLinks
7
+
5
8
  from ...administration.person.patient import Patient
9
+ from ...media import AnonymExaminationReport, AnonymHistologyReport, RawPdfFile, VideoFile
10
+ from ..examination import Examination, ExaminationIndication, ExaminationIndicationClassificationChoice
6
11
  from ..finding import Finding
7
- from .patient_finding import PatientFinding
8
- from ..examination import Examination
9
- from ...media import VideoFile, RawPdfFile, AnonymExaminationReport, AnonymHistologyReport
10
12
  from .patient_examination_indication import PatientExaminationIndication
11
- from ..examination import ExaminationIndicationClassificationChoice, ExaminationIndication
12
- from endoreg_db.utils.links.requirement_link import RequirementLinks
13
+ from .patient_finding import PatientFinding
14
+
13
15
 
14
16
  class PatientExamination(models.Model):
15
- patient = models.ForeignKey(
16
- "Patient", on_delete=models.CASCADE, related_name="patient_examinations"
17
- )
18
- examination = models.ForeignKey( # type: ignore[assignment]
19
- "Examination", on_delete=models.CASCADE, null=True, blank=True
20
- )
21
- video = models.OneToOneField( # type: ignore[assignment]
17
+ patient = models.ForeignKey("Patient", on_delete=models.CASCADE, related_name="patient_examinations")
18
+ examination = models.ForeignKey("Examination", on_delete=models.CASCADE, null=True, blank=True)
19
+ video = models.OneToOneField(
22
20
  "VideoFile",
23
21
  on_delete=models.CASCADE,
24
22
  null=True,
25
23
  blank=True,
26
24
  related_name="patient_examination",
27
25
  )
28
-
26
+
29
27
  objects = models.Manager()
30
-
28
+
31
29
  date_start = models.DateField(null=True, blank=True)
32
30
  date_end = models.DateField(null=True, blank=True)
33
31
  hash = models.CharField(max_length=255, unique=True)
34
-
35
32
 
36
33
  if TYPE_CHECKING:
37
34
  patient: "models.ForeignKey[Patient]"
38
- examination: "models.ForeignKey[Examination]"
39
- video: "models.OneToOneField[VideoFile]"
35
+ examination: "models.ForeignKey[Examination|None]"
36
+ video: "models.OneToOneField[VideoFile|None]"
40
37
  patient_findings: models.QuerySet["PatientFinding"]
41
38
  indications: models.QuerySet["PatientExaminationIndication"]
42
39
  raw_pdf_files: models.QuerySet["RawPdfFile"]
43
40
  anonymexaminationreport_set: models.QuerySet["AnonymExaminationReport"]
44
41
  anonymhistologyreport_set: models.QuerySet["AnonymHistologyReport"]
45
42
 
43
+ @property
44
+ def examination_safe(self):
45
+ if self.examination is None:
46
+ raise ValueError("Examination is not set for this PatientExamination.")
47
+ return self.examination
48
+
46
49
  # report_files
47
50
  class Meta:
48
51
  verbose_name = "Patient Examination"
@@ -61,12 +64,8 @@ class PatientExamination(models.Model):
61
64
 
62
65
  created = False
63
66
 
64
- if PatientExamination.objects.filter(
65
- patient__patient_hash=patient_hash, hash=examination_hash
66
- ).exists():
67
- return PatientExamination.objects.get(
68
- patient__patient_hash=patient_hash, hash=examination_hash
69
- ), created
67
+ if PatientExamination.objects.filter(patient__patient_hash=patient_hash, hash=examination_hash).exists():
68
+ return PatientExamination.objects.get(patient__patient_hash=patient_hash, hash=examination_hash), created
70
69
 
71
70
  patient, created = Patient.get_or_create_pseudo_patient_by_hash(patient_hash)
72
71
  if examination_name is not None:
@@ -74,9 +73,7 @@ class PatientExamination(models.Model):
74
73
  else:
75
74
  examination = None
76
75
 
77
- patient_examination = cls.objects.create(
78
- patient=patient, examination=examination, hash=examination_hash
79
- )
76
+ patient_examination = cls.objects.create(patient=patient, examination=examination, hash=examination_hash)
80
77
 
81
78
  patient_examination.save()
82
79
 
@@ -94,9 +91,7 @@ class PatientExamination(models.Model):
94
91
  import random
95
92
  import string
96
93
 
97
- _hash = "DEFAULT_HASH_" + "".join(
98
- random.choices(string.ascii_uppercase + string.digits, k=10)
99
- )
94
+ _hash = "DEFAULT_HASH_" + "".join(random.choices(string.ascii_uppercase + string.digits, k=10))
100
95
 
101
96
  return _hash
102
97
 
@@ -114,6 +109,8 @@ class PatientExamination(models.Model):
114
109
  patient: Patient = self.patient
115
110
  dob = patient.get_dob()
116
111
  date_start = self.date_start
112
+ assert dob is not None
113
+ assert date_start is not None
117
114
  return (date_start - dob).days // 365
118
115
 
119
116
  def get_available_findings(self):
@@ -121,6 +118,7 @@ class PatientExamination(models.Model):
121
118
  Returns all findings that are associated with the examination of this patient examination.
122
119
  """
123
120
 
121
+ assert self.examination is not None
124
122
  return self.examination.get_available_findings()
125
123
 
126
124
  def get_findings(self) -> models.QuerySet["PatientFinding"]:
@@ -139,13 +137,11 @@ class PatientExamination(models.Model):
139
137
  def get_indication_choices(self) -> List["ExaminationIndicationClassificationChoice"]:
140
138
  """
141
139
  Returns a list of indication choices associated with this patient examination.
142
-
140
+
143
141
  Only includes indication choices that are not None.
144
142
  """
145
143
 
146
- choices = [
147
- _.indication_choice for _ in self.get_indications() if _.indication_choice is not None
148
- ]
144
+ choices = [_.indication_choice for _ in self.get_indications() if _.indication_choice is not None]
149
145
  return choices
150
146
 
151
147
  def get_or_create_patient_examination_by_id(self, pk: int) -> Optional["PatientExamination"]:
@@ -153,14 +149,14 @@ class PatientExamination(models.Model):
153
149
  if not self.objects.filter(pk=pk).exists():
154
150
  return None
155
151
  else:
156
- return self.objects.filter(pk=pk)
152
+ return self.objects.filter(pk=pk).first()
157
153
 
158
154
  @property
159
155
  def links(self) -> "RequirementLinks":
160
156
  """
161
157
  Aggregates and returns all related model instances relevant for requirement evaluation
162
158
  as a RequirementLinks object.
163
-
159
+
164
160
  This includes:
165
161
  - All findings associated with this examination
166
162
  - All classifications and choices from those findings
@@ -168,12 +164,12 @@ class PatientExamination(models.Model):
168
164
  - Examination indications and their choices
169
165
  - Patient lab values
170
166
  """
171
- from endoreg_db.utils.links.requirement_link import RequirementLinks
172
167
  from endoreg_db.models.medical.patient.patient_lab_value import PatientLabValue
173
-
168
+ from endoreg_db.utils.links.requirement_link import RequirementLinks
169
+
174
170
  # Get all PatientExaminationIndication instances linked to this PatientExamination
175
- patient_exam_indications = self.indications.all()
176
-
171
+ patient_exam_indications = self.indications.all()
172
+
177
173
  examination_indications_list: List["ExaminationIndication"] = []
178
174
  indication_choices_list: List["ExaminationIndicationClassificationChoice"] = []
179
175
 
@@ -189,37 +185,37 @@ class PatientExamination(models.Model):
189
185
  patient_lab_values = list(PatientLabValue.objects.filter(patient=self.patient))
190
186
 
191
187
  current_examination = [self.examination] if self.examination else []
192
-
188
+
193
189
  # Now aggregate findings data from all PatientFinding instances
194
190
  findings_list = []
195
191
  finding_classifications_list = []
196
192
  finding_classification_choices_list = []
197
193
  finding_interventions_list = []
198
194
  patient_findings_list = []
199
-
195
+
200
196
  for patient_finding in self.patient_findings.all():
201
197
  # Add the PatientFinding itself
202
198
  patient_findings_list.append(patient_finding)
203
-
199
+
204
200
  # Add the base Finding
205
201
  if patient_finding.finding:
206
202
  findings_list.append(patient_finding.finding)
207
-
203
+
208
204
  # Add all active classifications and their choices from this PatientFinding
209
205
  for pf_classification in patient_finding.active_classifications:
210
206
  if pf_classification.classification:
211
207
  finding_classifications_list.append(pf_classification.classification)
212
208
  if pf_classification.classification_choice:
213
209
  finding_classification_choices_list.append(pf_classification.classification_choice)
214
-
215
- # Add all active interventions from this PatientFinding
210
+
211
+ # Add all active interventions from this PatientFinding
216
212
  for pf_intervention in patient_finding.active_interventions:
217
213
  if pf_intervention.intervention:
218
214
  finding_interventions_list.append(pf_intervention.intervention)
219
215
 
220
216
  return RequirementLinks(
221
217
  patient_examinations=[self], # Add the instance itself
222
- examinations=current_examination, # Add the related Examination model
218
+ examinations=current_examination, # Add the related Examination model
223
219
  examination_indications=examination_indications_list,
224
220
  examination_indication_classification_choices=indication_choices_list,
225
221
  patient_lab_values=patient_lab_values,
@@ -231,18 +227,16 @@ class PatientExamination(models.Model):
231
227
  finding_interventions=finding_interventions_list,
232
228
  )
233
229
 
234
- def create_finding(self, finding:"Finding") -> "PatientFinding":
230
+ def create_finding(self, finding: "Finding") -> "PatientFinding":
235
231
  """
236
232
  Adds a finding to this patient examination.
237
233
  """
238
234
  from .patient_finding import PatientFinding
239
235
 
240
- examination: Examination = self.examination
241
- assert examination
236
+ examination = self.examination
237
+ assert examination is not None
242
238
 
243
- patient_finding = PatientFinding.objects.create(
244
- patient_examination=self, finding=finding
245
- )
239
+ patient_finding = PatientFinding.objects.create(patient_examination=self, finding=finding)
246
240
 
247
241
  patient_finding.save()
248
242