endoreg-db 0.8.6.1__py3-none-any.whl → 0.8.8.9__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 (503) 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 +2 -11
  10. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +3 -3
  11. endoreg_db/data/event_classification/data.yaml +4 -0
  12. endoreg_db/data/event_classification_choice/data.yaml +9 -0
  13. endoreg_db/data/examination/examinations/data.yaml +114 -14
  14. endoreg_db/data/examination/time-type/data.yaml +0 -3
  15. endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
  16. endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
  17. endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
  18. endoreg_db/data/finding/00_generic.yaml +35 -0
  19. endoreg_db/data/finding/00_generic_complication.yaml +9 -0
  20. endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
  21. endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
  22. endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
  23. endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
  24. endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
  25. endoreg_db/data/finding_classification/00_generic.yaml +44 -0
  26. endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
  27. endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
  28. endoreg_db/data/finding_classification/02_colonoscopy_baseline.yaml +83 -0
  29. endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
  30. endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
  31. endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
  32. endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
  33. endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
  34. endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
  35. endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
  36. endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
  37. endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
  38. endoreg_db/data/finding_classification_choice/{colonoscopy_not_complete_reason.yaml → 02_colonoscopy_generic.yaml} +1 -1
  39. endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
  40. endoreg_db/data/finding_classification_choice/{colonoscopy_location.yaml → 02_colonoscopy_location.yaml} +23 -4
  41. endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
  42. endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
  43. endoreg_db/data/finding_classification_choice/{colon_lesion_paris.yaml → 02_colonoscopy_polyp_morphology.yaml} +26 -8
  44. endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
  45. endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
  46. endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
  47. endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
  48. endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
  49. endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
  50. endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
  51. endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
  52. endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
  53. endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
  54. endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
  55. endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
  56. endoreg_db/data/finding_type/data.yaml +8 -12
  57. endoreg_db/data/requirement/01_patient_data.yaml +93 -0
  58. endoreg_db/data/requirement/old/colon_polyp_intervention.yaml +49 -0
  59. endoreg_db/data/requirement/old/coloreg_colon_polyp.yaml +49 -0
  60. endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
  61. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +29 -12
  62. endoreg_db/data/requirement_set/01_laboratory.yaml +13 -0
  63. endoreg_db/data/requirement_set/{endoscopy_bleeding_risk.yaml → 02_endoscopy_bleeding_risk.yaml} +0 -6
  64. endoreg_db/data/requirement_set/90_coloreg.yaml +190 -0
  65. endoreg_db/data/requirement_set/_old_ +109 -0
  66. endoreg_db/data/requirement_set_type/data.yaml +21 -0
  67. endoreg_db/data/setup_config.yaml +4 -4
  68. endoreg_db/data/tag/requirement_set_tags.yaml +21 -0
  69. endoreg_db/exceptions.py +4 -2
  70. endoreg_db/forms/examination_form.py +1 -1
  71. endoreg_db/helpers/data_loader.py +125 -53
  72. endoreg_db/helpers/default_objects.py +116 -81
  73. endoreg_db/import_files/__init__.py +27 -0
  74. endoreg_db/import_files/context/__init__.py +7 -0
  75. endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
  76. endoreg_db/import_files/context/ensure_center.py +17 -0
  77. endoreg_db/import_files/context/file_lock.py +66 -0
  78. endoreg_db/import_files/context/import_context.py +43 -0
  79. endoreg_db/import_files/context/validate_directories.py +56 -0
  80. endoreg_db/import_files/file_storage/__init__.py +15 -0
  81. endoreg_db/import_files/file_storage/create_report_file.py +76 -0
  82. endoreg_db/import_files/file_storage/create_video_file.py +75 -0
  83. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
  84. endoreg_db/import_files/file_storage/state_management.py +400 -0
  85. endoreg_db/import_files/file_storage/storage.py +36 -0
  86. endoreg_db/import_files/import_service.md +26 -0
  87. endoreg_db/import_files/processing/__init__.py +11 -0
  88. endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
  89. endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
  90. endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
  91. endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +119 -0
  92. endoreg_db/import_files/pseudonymization/fake.py +52 -0
  93. endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
  94. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
  95. endoreg_db/import_files/report_import_service.py +141 -0
  96. endoreg_db/import_files/video_import_service.py +150 -0
  97. endoreg_db/management/commands/create_model_meta_from_huggingface.py +21 -10
  98. endoreg_db/management/commands/create_multilabel_model_meta.py +299 -129
  99. endoreg_db/management/commands/import_report.py +130 -65
  100. endoreg_db/management/commands/import_video.py +9 -10
  101. endoreg_db/management/commands/import_video_with_classification.py +2 -2
  102. endoreg_db/management/commands/list_routes.py +18 -0
  103. endoreg_db/management/commands/load_ai_model_data.py +5 -5
  104. endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
  105. endoreg_db/management/commands/load_base_db_data.py +5 -134
  106. endoreg_db/management/commands/load_center_data.py +12 -12
  107. endoreg_db/management/commands/load_contraindication_data.py +14 -16
  108. endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
  109. endoreg_db/management/commands/load_disease_classification_data.py +15 -18
  110. endoreg_db/management/commands/load_disease_data.py +25 -28
  111. endoreg_db/management/commands/load_endoscope_data.py +20 -27
  112. endoreg_db/management/commands/load_event_data.py +14 -16
  113. endoreg_db/management/commands/load_examination_data.py +31 -44
  114. endoreg_db/management/commands/load_examination_indication_data.py +20 -21
  115. endoreg_db/management/commands/load_finding_data.py +52 -80
  116. endoreg_db/management/commands/load_information_source.py +21 -23
  117. endoreg_db/management/commands/load_lab_value_data.py +17 -26
  118. endoreg_db/management/commands/load_medication_data.py +13 -12
  119. endoreg_db/management/commands/load_organ_data.py +15 -19
  120. endoreg_db/management/commands/load_pdf_type_data.py +19 -18
  121. endoreg_db/management/commands/load_profession_data.py +14 -17
  122. endoreg_db/management/commands/load_qualification_data.py +20 -23
  123. endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
  124. endoreg_db/management/commands/load_requirement_data.py +62 -39
  125. endoreg_db/management/commands/load_requirement_set_tags.py +95 -0
  126. endoreg_db/management/commands/load_risk_data.py +7 -6
  127. endoreg_db/management/commands/load_shift_data.py +20 -23
  128. endoreg_db/management/commands/load_tag_data.py +8 -11
  129. endoreg_db/management/commands/load_unit_data.py +17 -19
  130. endoreg_db/management/commands/setup_endoreg_db.py +3 -3
  131. endoreg_db/management/commands/start_filewatcher.py +46 -37
  132. endoreg_db/management/commands/storage_management.py +271 -203
  133. endoreg_db/management/commands/validate_video_files.py +1 -5
  134. endoreg_db/migrations/0001_initial.py +297 -250
  135. endoreg_db/models/__init__.py +78 -123
  136. endoreg_db/models/administration/__init__.py +21 -42
  137. endoreg_db/models/administration/ai/active_model.py +2 -2
  138. endoreg_db/models/administration/ai/ai_model.py +7 -6
  139. endoreg_db/models/administration/case/__init__.py +1 -15
  140. endoreg_db/models/administration/case/case.py +3 -3
  141. endoreg_db/models/administration/case/case_template/__init__.py +2 -14
  142. endoreg_db/models/administration/case/case_template/case_template.py +2 -124
  143. endoreg_db/models/administration/case/case_template/case_template_rule.py +2 -268
  144. endoreg_db/models/administration/case/case_template/case_template_rule_value.py +2 -85
  145. endoreg_db/models/administration/case/case_template/case_template_type.py +2 -25
  146. endoreg_db/models/administration/center/center.py +33 -19
  147. endoreg_db/models/administration/center/center_product.py +12 -9
  148. endoreg_db/models/administration/center/center_resource.py +25 -19
  149. endoreg_db/models/administration/center/center_shift.py +21 -17
  150. endoreg_db/models/administration/center/center_waste.py +16 -8
  151. endoreg_db/models/administration/person/__init__.py +2 -0
  152. endoreg_db/models/administration/person/employee/employee.py +10 -5
  153. endoreg_db/models/administration/person/employee/employee_qualification.py +9 -4
  154. endoreg_db/models/administration/person/employee/employee_type.py +12 -6
  155. endoreg_db/models/administration/person/examiner/examiner.py +13 -11
  156. endoreg_db/models/administration/person/patient/__init__.py +2 -0
  157. endoreg_db/models/administration/person/patient/patient.py +129 -100
  158. endoreg_db/models/administration/person/patient/patient_external_id.py +37 -0
  159. endoreg_db/models/administration/person/person.py +4 -0
  160. endoreg_db/models/administration/person/profession/__init__.py +8 -4
  161. endoreg_db/models/administration/person/user/portal_user_information.py +11 -7
  162. endoreg_db/models/administration/product/product.py +20 -15
  163. endoreg_db/models/administration/product/product_material.py +17 -18
  164. endoreg_db/models/administration/product/product_weight.py +12 -8
  165. endoreg_db/models/administration/product/reference_product.py +23 -55
  166. endoreg_db/models/administration/qualification/qualification.py +7 -3
  167. endoreg_db/models/administration/qualification/qualification_type.py +7 -3
  168. endoreg_db/models/administration/shift/scheduled_days.py +8 -5
  169. endoreg_db/models/administration/shift/shift.py +16 -12
  170. endoreg_db/models/administration/shift/shift_type.py +23 -31
  171. endoreg_db/models/label/__init__.py +8 -9
  172. endoreg_db/models/label/annotation/image_classification.py +10 -9
  173. endoreg_db/models/label/annotation/video_segmentation_annotation.py +23 -28
  174. endoreg_db/models/label/label.py +15 -15
  175. endoreg_db/models/label/label_set.py +19 -6
  176. endoreg_db/models/label/label_type.py +1 -1
  177. endoreg_db/models/label/label_video_segment/_create_from_video.py +5 -8
  178. endoreg_db/models/label/label_video_segment/label_video_segment.py +98 -102
  179. endoreg_db/models/label/video_segmentation_label.py +4 -0
  180. endoreg_db/models/label/video_segmentation_labelset.py +4 -3
  181. endoreg_db/models/media/frame/frame.py +22 -22
  182. endoreg_db/models/media/pdf/raw_pdf.py +194 -194
  183. endoreg_db/models/media/pdf/report_file.py +25 -29
  184. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +55 -47
  185. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +23 -7
  186. endoreg_db/models/media/processing_history/__init__.py +5 -0
  187. endoreg_db/models/media/processing_history/processing_history.py +96 -0
  188. endoreg_db/models/media/video/__init__.py +1 -0
  189. endoreg_db/models/media/video/create_from_file.py +139 -77
  190. endoreg_db/models/media/video/pipe_2.py +8 -9
  191. endoreg_db/models/media/video/video_file.py +174 -112
  192. endoreg_db/models/media/video/video_file_ai.py +288 -74
  193. endoreg_db/models/media/video/video_file_anonymize.py +38 -38
  194. endoreg_db/models/media/video/video_file_frames/__init__.py +3 -1
  195. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -8
  196. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +7 -9
  197. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +9 -8
  198. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +38 -45
  199. endoreg_db/models/media/video/video_file_frames/_get_frame.py +6 -8
  200. endoreg_db/models/media/video/video_file_frames/_get_frame_number.py +4 -18
  201. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -3
  202. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +7 -6
  203. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +6 -8
  204. endoreg_db/models/media/video/video_file_frames/_get_frames.py +6 -8
  205. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +15 -25
  206. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +26 -23
  207. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +23 -14
  208. endoreg_db/models/media/video/video_file_io.py +113 -61
  209. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +3 -3
  210. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +5 -3
  211. endoreg_db/models/media/video/video_file_meta/get_fps.py +37 -34
  212. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +19 -25
  213. endoreg_db/models/media/video/video_file_meta/text_meta.py +41 -38
  214. endoreg_db/models/media/video/video_file_meta/video_meta.py +14 -7
  215. endoreg_db/models/media/video/video_file_segments.py +24 -17
  216. endoreg_db/models/media/video/video_metadata.py +19 -35
  217. endoreg_db/models/media/video/video_processing.py +96 -95
  218. endoreg_db/models/medical/contraindication/README.md +1 -0
  219. endoreg_db/models/medical/contraindication/__init__.py +13 -3
  220. endoreg_db/models/medical/disease.py +22 -16
  221. endoreg_db/models/medical/event.py +31 -18
  222. endoreg_db/models/medical/examination/__init__.py +13 -6
  223. endoreg_db/models/medical/examination/examination.py +39 -20
  224. endoreg_db/models/medical/examination/examination_indication.py +30 -95
  225. endoreg_db/models/medical/examination/examination_time.py +23 -8
  226. endoreg_db/models/medical/examination/examination_time_type.py +9 -6
  227. endoreg_db/models/medical/examination/examination_type.py +3 -4
  228. endoreg_db/models/medical/finding/finding.py +32 -40
  229. endoreg_db/models/medical/finding/finding_classification.py +42 -72
  230. endoreg_db/models/medical/finding/finding_intervention.py +25 -22
  231. endoreg_db/models/medical/finding/finding_type.py +13 -12
  232. endoreg_db/models/medical/hardware/endoscope.py +26 -26
  233. endoreg_db/models/medical/hardware/endoscopy_processor.py +2 -2
  234. endoreg_db/models/medical/laboratory/lab_value.py +62 -91
  235. endoreg_db/models/medical/medication/medication.py +22 -10
  236. endoreg_db/models/medical/medication/medication_indication.py +29 -3
  237. endoreg_db/models/medical/medication/medication_indication_type.py +25 -14
  238. endoreg_db/models/medical/medication/medication_intake_time.py +31 -19
  239. endoreg_db/models/medical/medication/medication_schedule.py +27 -16
  240. endoreg_db/models/medical/organ/__init__.py +15 -12
  241. endoreg_db/models/medical/patient/medication_examples.py +6 -6
  242. endoreg_db/models/medical/patient/patient_disease.py +20 -23
  243. endoreg_db/models/medical/patient/patient_event.py +19 -22
  244. endoreg_db/models/medical/patient/patient_examination.py +48 -54
  245. endoreg_db/models/medical/patient/patient_examination_indication.py +16 -14
  246. endoreg_db/models/medical/patient/patient_finding.py +122 -139
  247. endoreg_db/models/medical/patient/patient_finding_classification.py +44 -49
  248. endoreg_db/models/medical/patient/patient_finding_intervention.py +8 -19
  249. endoreg_db/models/medical/patient/patient_lab_sample.py +28 -23
  250. endoreg_db/models/medical/patient/patient_lab_value.py +82 -89
  251. endoreg_db/models/medical/patient/patient_medication.py +27 -38
  252. endoreg_db/models/medical/patient/patient_medication_schedule.py +28 -36
  253. endoreg_db/models/medical/risk/risk.py +7 -6
  254. endoreg_db/models/medical/risk/risk_type.py +8 -5
  255. endoreg_db/models/metadata/model_meta.py +60 -29
  256. endoreg_db/models/metadata/model_meta_logic.py +125 -18
  257. endoreg_db/models/metadata/pdf_meta.py +31 -24
  258. endoreg_db/models/metadata/sensitive_meta.py +105 -85
  259. endoreg_db/models/metadata/sensitive_meta_logic.py +198 -103
  260. endoreg_db/models/metadata/video_meta.py +51 -31
  261. endoreg_db/models/metadata/video_prediction_logic.py +16 -23
  262. endoreg_db/models/metadata/video_prediction_meta.py +29 -33
  263. endoreg_db/models/other/distribution/date_value_distribution.py +89 -29
  264. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +21 -5
  265. endoreg_db/models/other/distribution/numeric_value_distribution.py +114 -53
  266. endoreg_db/models/other/distribution/single_categorical_value_distribution.py +4 -3
  267. endoreg_db/models/other/emission/emission_factor.py +18 -8
  268. endoreg_db/models/other/gender.py +10 -5
  269. endoreg_db/models/other/information_source.py +50 -29
  270. endoreg_db/models/other/material.py +9 -5
  271. endoreg_db/models/other/resource.py +6 -4
  272. endoreg_db/models/other/tag.py +10 -5
  273. endoreg_db/models/other/transport_route.py +13 -8
  274. endoreg_db/models/other/unit.py +10 -6
  275. endoreg_db/models/other/waste.py +6 -5
  276. endoreg_db/models/report/report.py +6 -0
  277. endoreg_db/models/requirement/requirement.py +329 -361
  278. endoreg_db/models/requirement/requirement_error.py +85 -0
  279. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +268 -0
  280. endoreg_db/models/requirement/requirement_evaluation/operator_evaluation_models.py +3 -6
  281. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +90 -64
  282. endoreg_db/models/requirement/requirement_operator.py +103 -112
  283. endoreg_db/models/requirement/requirement_set.py +74 -57
  284. endoreg_db/models/state/__init__.py +4 -4
  285. endoreg_db/models/state/abstract.py +2 -2
  286. endoreg_db/models/state/anonymization.py +12 -0
  287. endoreg_db/models/state/audit_ledger.py +49 -51
  288. endoreg_db/models/state/label_video_segment.py +9 -0
  289. endoreg_db/models/state/raw_pdf.py +101 -68
  290. endoreg_db/models/state/sensitive_meta.py +6 -2
  291. endoreg_db/models/state/video.py +110 -90
  292. endoreg_db/models/upload_job.py +35 -34
  293. endoreg_db/models/utils.py +28 -25
  294. endoreg_db/queries/__init__.py +3 -1
  295. endoreg_db/root_urls.py +21 -2
  296. endoreg_db/schemas/examination_evaluation.py +1 -1
  297. endoreg_db/serializers/__init__.py +2 -10
  298. endoreg_db/serializers/anonymization.py +18 -10
  299. endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
  300. endoreg_db/serializers/meta/__init__.py +1 -6
  301. endoreg_db/serializers/meta/sensitive_meta_detail.py +63 -118
  302. endoreg_db/serializers/misc/file_overview.py +11 -99
  303. endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
  304. endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
  305. endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
  306. endoreg_db/serializers/requirements/requirement_sets.py +92 -22
  307. endoreg_db/serializers/video/segmentation.py +2 -1
  308. endoreg_db/serializers/video/video_file_list.py +65 -34
  309. endoreg_db/serializers/video/video_processing_history.py +20 -5
  310. endoreg_db/services/__old/pdf_import.py +1487 -0
  311. endoreg_db/services/__old/video_import.py +1306 -0
  312. endoreg_db/services/anonymization.py +128 -89
  313. endoreg_db/services/lookup_service.py +65 -52
  314. endoreg_db/services/lookup_store.py +2 -2
  315. endoreg_db/services/pdf_import.py +0 -1382
  316. endoreg_db/services/report_import.py +10 -0
  317. endoreg_db/services/video_import.py +6 -1255
  318. endoreg_db/tasks/upload_tasks.py +79 -70
  319. endoreg_db/tasks/video_ingest.py +8 -4
  320. endoreg_db/urls/__init__.py +5 -32
  321. endoreg_db/urls/ai.py +32 -0
  322. endoreg_db/urls/media.py +121 -83
  323. endoreg_db/urls/root_urls.py +29 -0
  324. endoreg_db/utils/__init__.py +15 -5
  325. endoreg_db/utils/ai/multilabel_classification_net.py +116 -20
  326. endoreg_db/utils/case_generator/__init__.py +3 -0
  327. endoreg_db/utils/dataloader.py +142 -40
  328. endoreg_db/utils/defaults/set_default_center.py +32 -0
  329. endoreg_db/utils/names.py +22 -16
  330. endoreg_db/utils/paths.py +110 -46
  331. endoreg_db/utils/permissions.py +2 -1
  332. endoreg_db/utils/pipelines/Readme.md +1 -1
  333. endoreg_db/utils/pipelines/process_video_dir.py +1 -1
  334. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +655 -0
  335. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
  336. endoreg_db/utils/setup_config.py +8 -5
  337. endoreg_db/utils/storage.py +115 -0
  338. endoreg_db/utils/validate_endo_roi.py +8 -2
  339. endoreg_db/utils/video/ffmpeg_wrapper.py +184 -188
  340. endoreg_db/views/__init__.py +85 -183
  341. endoreg_db/views/ai/__init__.py +8 -0
  342. endoreg_db/views/ai/label.py +155 -0
  343. endoreg_db/views/anonymization/media_management.py +202 -166
  344. endoreg_db/views/anonymization/overview.py +99 -67
  345. endoreg_db/views/anonymization/validate.py +182 -44
  346. endoreg_db/views/media/__init__.py +7 -20
  347. endoreg_db/views/media/pdf_media.py +197 -174
  348. endoreg_db/views/media/sensitive_metadata.py +193 -138
  349. endoreg_db/views/media/video_media.py +89 -82
  350. endoreg_db/views/meta/__init__.py +0 -8
  351. endoreg_db/views/misc/__init__.py +1 -7
  352. endoreg_db/views/misc/upload_views.py +94 -93
  353. endoreg_db/views/patient/patient.py +5 -4
  354. endoreg_db/views/report/__init__.py +5 -7
  355. endoreg_db/views/{pdf → report}/reimport.py +22 -22
  356. endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +46 -39
  357. endoreg_db/views/requirement/evaluate.py +188 -187
  358. endoreg_db/views/requirement/lookup.py +17 -3
  359. endoreg_db/views/requirement/lookup_store.py +22 -90
  360. endoreg_db/views/requirement/requirement_utils.py +89 -0
  361. endoreg_db/views/video/__init__.py +23 -24
  362. endoreg_db/views/video/correction.py +201 -172
  363. endoreg_db/views/video/reimport.py +1 -1
  364. endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +77 -40
  365. endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
  366. endoreg_db/views/video/video_stream.py +7 -8
  367. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/METADATA +7 -3
  368. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/RECORD +391 -413
  369. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/WHEEL +1 -1
  370. endoreg_db/data/finding/anatomy_colon.yaml +0 -128
  371. endoreg_db/data/finding/colonoscopy.yaml +0 -40
  372. endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
  373. endoreg_db/data/finding/complication.yaml +0 -16
  374. endoreg_db/data/finding/data.yaml +0 -105
  375. endoreg_db/data/finding/examination_setting.yaml +0 -16
  376. endoreg_db/data/finding/medication_related.yaml +0 -18
  377. endoreg_db/data/finding/outcome.yaml +0 -12
  378. endoreg_db/data/finding_classification/colonoscopy_bowel_preparation.yaml +0 -95
  379. endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
  380. endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
  381. endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  382. endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  383. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -68
  384. endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  385. endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -80
  386. endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
  387. endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
  388. endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
  389. endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
  390. endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
  391. endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
  392. endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
  393. endoreg_db/data/finding_classification/histology_colo.yaml +0 -51
  394. endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
  395. endoreg_db/data/finding_classification/medication_related.yaml +0 -23
  396. endoreg_db/data/finding_classification/visualized.yaml +0 -33
  397. endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  398. endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  399. endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  400. endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  401. endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  402. endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  403. endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  404. endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  405. endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
  406. endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  407. endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
  408. endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
  409. endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  410. endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
  411. endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
  412. endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  413. endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  414. endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
  415. endoreg_db/data/requirement/age.yaml +0 -26
  416. endoreg_db/data/requirement/gender.yaml +0 -25
  417. endoreg_db/management/commands/init_default_ai_model.py +0 -112
  418. endoreg_db/management/commands/reset_celery_schedule.py +0 -9
  419. endoreg_db/management/commands/validate_video.py +0 -204
  420. endoreg_db/migrations/0002_add_video_correction_models.py +0 -52
  421. endoreg_db/migrations/0003_add_center_display_name.py +0 -30
  422. endoreg_db/models/administration/permissions/__init__.py +0 -44
  423. endoreg_db/models/rule/__init__.py +0 -13
  424. endoreg_db/models/rule/rule.py +0 -27
  425. endoreg_db/models/rule/rule_applicator.py +0 -224
  426. endoreg_db/models/rule/rule_attribute_dtype.py +0 -17
  427. endoreg_db/models/rule/rule_type.py +0 -20
  428. endoreg_db/models/rule/ruleset.py +0 -17
  429. endoreg_db/renames.yml +0 -8
  430. endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
  431. endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
  432. endoreg_db/serializers/_old/video.py +0 -71
  433. endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
  434. endoreg_db/serializers/meta/report_meta.py +0 -53
  435. endoreg_db/serializers/report/__init__.py +0 -9
  436. endoreg_db/serializers/report/mixins.py +0 -45
  437. endoreg_db/serializers/report/report.py +0 -105
  438. endoreg_db/serializers/report/report_list.py +0 -22
  439. endoreg_db/serializers/report/secure_file_url.py +0 -26
  440. endoreg_db/serializers/video/video_metadata.py +0 -105
  441. endoreg_db/services/requirements_object.py +0 -147
  442. endoreg_db/services/storage_aware_video_processor.py +0 -344
  443. endoreg_db/urls/files.py +0 -6
  444. endoreg_db/urls/label_video_segment_validate.py +0 -33
  445. endoreg_db/urls/label_video_segments.py +0 -46
  446. endoreg_db/urls/report.py +0 -48
  447. endoreg_db/urls/video.py +0 -61
  448. endoreg_db/utils/case_generator/case_generator.py +0 -159
  449. endoreg_db/utils/case_generator/utils.py +0 -30
  450. endoreg_db/utils/requirement_operator_logic/model_evaluators.py +0 -368
  451. endoreg_db/views/label/__init__.py +0 -5
  452. endoreg_db/views/label/label.py +0 -15
  453. endoreg_db/views/label_video_segment/__init__.py +0 -16
  454. endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
  455. endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
  456. endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
  457. endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
  458. endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
  459. endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
  460. endoreg_db/views/label_video_segment/validate.py +0 -226
  461. endoreg_db/views/media/segments.py +0 -71
  462. endoreg_db/views/meta/available_files_list.py +0 -146
  463. endoreg_db/views/meta/report_meta.py +0 -53
  464. endoreg_db/views/meta/sensitive_meta_detail.py +0 -148
  465. endoreg_db/views/misc/secure_file_serving_view.py +0 -80
  466. endoreg_db/views/misc/secure_file_url_view.py +0 -84
  467. endoreg_db/views/misc/secure_url_validate.py +0 -79
  468. endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
  469. endoreg_db/views/patient_finding_location/__init__.py +0 -5
  470. endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
  471. endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
  472. endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
  473. endoreg_db/views/pdf/__init__.py +0 -8
  474. endoreg_db/views/report/report_list.py +0 -112
  475. endoreg_db/views/report/report_with_secure_url.py +0 -28
  476. endoreg_db/views/report/start_examination.py +0 -7
  477. endoreg_db/views/video/segmentation.py +0 -274
  478. endoreg_db/views/video/task_status.py +0 -49
  479. endoreg_db/views/video/timeline.py +0 -46
  480. endoreg_db/views/video/video_analyze.py +0 -52
  481. endoreg_db/views.py +0 -0
  482. /endoreg_db/data/requirement/{colonoscopy_baseline_austria.yaml → old/colonoscopy_baseline_austria.yaml} +0 -0
  483. /endoreg_db/data/requirement/{disease_cardiovascular.yaml → old/disease_cardiovascular.yaml} +0 -0
  484. /endoreg_db/data/requirement/{disease_classification_choice_cardiovascular.yaml → old/disease_classification_choice_cardiovascular.yaml} +0 -0
  485. /endoreg_db/data/requirement/{disease_hepatology.yaml → old/disease_hepatology.yaml} +0 -0
  486. /endoreg_db/data/requirement/{disease_misc.yaml → old/disease_misc.yaml} +0 -0
  487. /endoreg_db/data/requirement/{disease_renal.yaml → old/disease_renal.yaml} +0 -0
  488. /endoreg_db/data/requirement/{endoscopy_bleeding_risk.yaml → old/endoscopy_bleeding_risk.yaml} +0 -0
  489. /endoreg_db/data/requirement/{event_cardiology.yaml → old/event_cardiology.yaml} +0 -0
  490. /endoreg_db/data/requirement/{event_requirements.yaml → old/event_requirements.yaml} +0 -0
  491. /endoreg_db/data/requirement/{finding_colon_polyp.yaml → old/finding_colon_polyp.yaml} +0 -0
  492. /endoreg_db/{migrations/__init__.py → data/requirement/old/gender.yaml} +0 -0
  493. /endoreg_db/data/requirement/{lab_value.yaml → old/lab_value.yaml} +0 -0
  494. /endoreg_db/data/requirement/{medication.yaml → old/medication.yaml} +0 -0
  495. /endoreg_db/data/requirement_operator/{age.yaml → _old/age.yaml} +0 -0
  496. /endoreg_db/data/requirement_operator/{lab_operators.yaml → _old/lab_operators.yaml} +0 -0
  497. /endoreg_db/data/requirement_operator/{model_operators.yaml → _old/model_operators.yaml} +0 -0
  498. /endoreg_db/{models/media/video/refactor_plan.md → import_files/pseudonymization/__init__.py} +0 -0
  499. /endoreg_db/{models/media/video/video_file_frames.py → import_files/pseudonymization/pseudonymize.py} +0 -0
  500. /endoreg_db/models/{metadata/frame_ocr_result.py → report/__init__.py} +0 -0
  501. /endoreg_db/{urls/sensitive_meta.py → models/report/images.py} +0 -0
  502. /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
  503. {endoreg_db-0.8.6.1.dist-info → endoreg_db-0.8.8.9.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,13 @@
1
- from ..person import Person
2
- from django.db import models
3
- from faker import Faker
1
+ import logging
4
2
  import random
5
- from datetime import datetime
3
+ from datetime import date, datetime
6
4
  from typing import TYPE_CHECKING, List, Optional # Added List
7
- import logging
5
+
6
+ from django.db import models
8
7
  from django.utils import timezone # Add this import
8
+ from faker import Faker
9
+
10
+ from ..person import Person
9
11
 
10
12
  # Import RequirementLinks and Disease for the links property
11
13
 
@@ -13,23 +15,22 @@ logger = logging.getLogger("patient")
13
15
 
14
16
  if TYPE_CHECKING:
15
17
  from endoreg_db.models import (
18
+ AnonymExaminationReport,
19
+ AnonymHistologyReport,
20
+ Center,
16
21
  ExaminationIndication,
17
- PatientEvent, PatientDisease,
18
22
  Gender,
23
+ PatientDisease,
24
+ PatientEvent,
19
25
  PatientExamination,
20
- Center,
21
- AnonymExaminationReport,
22
- AnonymHistologyReport, RawPdfFile,
23
- # Added for links property
24
- Medication,
26
+ PatientExternalID,
27
+ PatientLabValue,
25
28
  PatientMedication,
26
- MedicationIndication,
27
- MedicationIntakeTime,
28
- PatientLabValue, # Assuming self.lab_values are PatientLabValue instances
29
- LabValue # If RequirementLinks expects actual LabValue instances
29
+ RawPdfFile,
30
30
  )
31
31
  from endoreg_db.utils.links.requirement_link import RequirementLinks
32
32
 
33
+
33
34
  class Patient(Person):
34
35
  """
35
36
  A class representing a patient.
@@ -44,31 +45,55 @@ class Patient(Person):
44
45
 
45
46
  """
46
47
 
47
- # -----gc-08-dev--changings---
48
- first_name = models.CharField(max_length=100) # type: ignore[assignment]
49
- last_name = models.CharField(max_length=100) # type: ignore[assignment]
50
- dob = models.DateField(null=True, blank=True) # type: ignore[assignment]
51
- gender = models.ForeignKey( # type: ignore[assignment]
48
+ first_name = models.CharField(max_length=100)
49
+ last_name = models.CharField(max_length=100)
50
+ dob = models.DateField(null=True, blank=True)
51
+ gender = models.ForeignKey(
52
52
  "Gender", on_delete=models.SET_NULL, null=True, blank=True
53
53
  )
54
- center = models.ForeignKey( # type: ignore[assignment]
54
+ center = models.ForeignKey(
55
55
  "Center", on_delete=models.SET_NULL, null=True, blank=True
56
56
  )
57
57
  patient_hash = models.CharField(max_length=255, blank=True, null=True)
58
-
58
+
59
59
  objects = models.Manager() # Default manager
60
60
 
61
61
  if TYPE_CHECKING:
62
- first_name: str
63
- last_name: str
64
- dob: datetime.date
65
- gender: "Gender"
66
- center: "Center"
67
- events: models.QuerySet["PatientEvent"]
68
- diseases: models.QuerySet["PatientDisease"]
69
- patient_examinations: models.QuerySet["PatientExamination"]
70
- anonymexaminationreport_set: models.QuerySet["AnonymExaminationReport"]
71
- anonymhistologyreport_set: models.QuerySet["AnonymHistologyReport"]
62
+ from django.db.models.manager import RelatedManager
63
+
64
+ first_name: models.CharField[str]
65
+ last_name: models.CharField[str]
66
+ dob: models.DateField[date | None]
67
+ gender: models.ForeignKey["Gender | None"]
68
+ center: models.ForeignKey["Center | None"]
69
+
70
+ @property
71
+ def events(self) -> RelatedManager[PatientEvent]: ...
72
+
73
+ @property
74
+ def diseases(self) -> RelatedManager[PatientDisease]: ...
75
+
76
+ @property
77
+ def patient_examinations(self) -> RelatedManager[PatientExamination]: ...
78
+
79
+ @property
80
+ def anonymexaminationreport_set(
81
+ self,
82
+ ) -> RelatedManager[AnonymExaminationReport]: ...
83
+
84
+ @property
85
+ def anonymhistologyreport_set(
86
+ self,
87
+ ) -> RelatedManager[AnonymHistologyReport]: ...
88
+
89
+ @property
90
+ def external_ids(self) -> RelatedManager[PatientExternalID]: ...
91
+
92
+ @property
93
+ def patientmedication_set(self) -> RelatedManager[PatientMedication]: ...
94
+
95
+ @property
96
+ def lab_values(self) -> RelatedManager[PatientLabValue]: ...
72
97
 
73
98
  def __str__(self):
74
99
  return f"{self.first_name} {self.last_name} ({self.dob})"
@@ -77,12 +102,13 @@ class Patient(Person):
77
102
  def get_or_create_pseudo_patient_by_hash(
78
103
  cls,
79
104
  patient_hash: str,
80
- center: "Center" = None,
81
- gender: "Gender | str" = None, # Allow string type hint
82
- birth_month: int = None,
83
- birth_year: int = None,
105
+ center: Optional["Center"] = None,
106
+ gender: Optional["Gender | str"] = None, # Allow string type hint
107
+ birth_month: Optional[int] = None,
108
+ birth_year: Optional[int] = None,
84
109
  ):
85
- from endoreg_db.utils import random_day_by_year, create_mock_patient_name
110
+ from endoreg_db.utils import create_mock_patient_name, random_day_by_year
111
+
86
112
  from ....other import Gender # Import Gender model
87
113
 
88
114
  created = False
@@ -130,9 +156,8 @@ class Patient(Person):
130
156
 
131
157
  return patient, created
132
158
 
133
- def get_dob(self) -> datetime.date:
134
- dob: datetime.date = self.dob
135
- return dob
159
+ def get_dob(self) -> date | None:
160
+ return self.dob
136
161
 
137
162
  def get_patient_examinations(self): # field: self.patient_examinations
138
163
  """Returns all patient examinations for this patient ordered by date (most recent is first)."""
@@ -146,10 +171,9 @@ class Patient(Person):
146
171
  save: bool = True,
147
172
  ) -> "PatientExamination":
148
173
  """Creates a patient examination for this patient."""
174
+ from ....medical import Examination, PatientExamination
149
175
 
150
176
  if examination_name_str:
151
- from ....medical import Examination, PatientExamination
152
-
153
177
  examination = Examination.objects.get(name=examination_name_str)
154
178
  patient_examination = PatientExamination(
155
179
  patient=self,
@@ -168,42 +192,16 @@ class Patient(Person):
168
192
 
169
193
  return patient_examination
170
194
 
171
- def create_examination_by_indication(
172
- self, indication: "ExaminationIndication", date_start: datetime = None, date_end: datetime = None
173
- ):
174
- from ....medical import (
175
- PatientExaminationIndication,
176
- PatientExamination,
177
- )
178
-
179
- examination = indication.get_examination()
180
-
181
- patient_examination = PatientExamination.objects.create(
182
- patient=self,
183
- examination=examination,
184
- date_start=date_start,
185
- date_end=date_end,
186
- )
187
-
188
- patient_examination.save()
189
-
190
- patient_examination_indication = PatientExaminationIndication.objects.create(
191
- patient_examination=patient_examination, examination_indication=indication
192
- )
193
- patient_examination_indication.save()
194
-
195
- return patient_examination, patient_examination_indication
196
-
197
195
  def create_event(
198
196
  self,
199
197
  event_name_str: str,
200
- date_start: datetime = None,
201
- date_end: datetime = None,
202
- description: str = None,
198
+ date_start: Optional[datetime] = None,
199
+ date_end: Optional[datetime] = None,
200
+ description: Optional[str] = None,
203
201
  ):
204
202
  """
205
203
  Creates a patient event with the specified event name and start date.
206
-
204
+
207
205
  If no start date is provided, the current datetime is used. Returns the created PatientEvent instance.
208
206
  """
209
207
  from ....medical import Event, PatientEvent
@@ -223,17 +221,18 @@ class Patient(Person):
223
221
 
224
222
  def create_examination_by_pdf(self, pdf: "RawPdfFile"):
225
223
  """
226
- Creates a patient examination and associates it with the provided PDF report file.
227
-
228
- The examination is created for this patient, saved, and linked to the given RawPdfFile instance. The PDF's examination field is updated and saved. Returns the created examination instance.
229
-
224
+ Creates a patient examination and associates it with the provided report report file.
225
+
226
+ The examination is created for this patient, saved, and linked to the given RawPdfFile instance. The report's examination field is updated and saved. Returns the created examination instance.
227
+
230
228
  Args:
231
229
  pdf: The RawPdfFile to associate with the new examination.
232
-
230
+
233
231
  Returns:
234
232
  The created PatientExamination instance.
235
233
  """
236
234
  from ....medical import PatientExamination
235
+
237
236
  patient_examination = PatientExamination(patient=self)
238
237
  patient_examination.save()
239
238
  pdf.examination = patient_examination
@@ -346,11 +345,17 @@ class Patient(Person):
346
345
  last_name=last_name,
347
346
  dob=dob,
348
347
  gender=gender,
349
- center=center_obj, # Assign the center object
348
+ center=center_obj, # Assign the center object
350
349
  )
351
350
  # No need to call save() again after create()
352
351
  return patient
353
352
 
353
+ @property
354
+ def age_safe(self) -> int:
355
+ age = self.age()
356
+ assert age is not None, "Patient age is not set."
357
+ return age
358
+
354
359
  def age(self) -> int | None:
355
360
  """
356
361
  Get the age of the patient.
@@ -358,7 +363,9 @@ class Patient(Person):
358
363
  :return: The age of the patient.
359
364
  """
360
365
  # calculate correct age based on current date including day and month
361
- current_date = timezone.now().date() # Use timezone.now() here too for consistency
366
+ current_date = (
367
+ timezone.now().date()
368
+ ) # Use timezone.now() here too for consistency
362
369
  dob = self.dob
363
370
  # Ensure dob is not None before calculation
364
371
  if dob:
@@ -385,7 +392,9 @@ class Patient(Person):
385
392
  date = timezone.now() # Use timezone.now() instead of datetime.now()
386
393
  # Ensure the provided date is timezone-aware if it's not None
387
394
  elif timezone.is_naive(date):
388
- logger.warning(f"Received naive datetime {date} for PatientLabSample. Making it timezone-aware using current timezone.")
395
+ logger.warning(
396
+ f"Received naive datetime {date} for PatientLabSample. Making it timezone-aware using current timezone."
397
+ )
389
398
  date = timezone.make_aware(date, timezone.get_current_timezone())
390
399
 
391
400
  if isinstance(sample_type, str):
@@ -411,50 +420,70 @@ class Patient(Person):
411
420
  as a RequirementLinks object. For a Patient, this includes their diseases, associated classification choices,
412
421
  all their lab values, and medication information.
413
422
  """
414
- from endoreg_db.utils.links.requirement_link import RequirementLinks
415
- from endoreg_db.models.medical.disease import Disease, DiseaseClassificationChoice
416
-
423
+ from endoreg_db.models.medical.disease import (
424
+ Disease,
425
+ DiseaseClassificationChoice,
426
+ )
427
+
417
428
  # Imports for medication related models
418
429
  from endoreg_db.models.medical.medication.medication import Medication
419
- from endoreg_db.models.medical.medication.medication_indication import MedicationIndication
420
- from endoreg_db.models.medical.medication.medication_intake_time import MedicationIntakeTime
430
+ from endoreg_db.models.medical.medication.medication_indication import (
431
+ MedicationIndication,
432
+ )
433
+ from endoreg_db.models.medical.medication.medication_intake_time import (
434
+ MedicationIntakeTime,
435
+ )
436
+ from endoreg_db.utils.links.requirement_link import RequirementLinks
437
+
421
438
  # PatientMedication objects are retrieved via self.patientmedication_set
422
439
  # PatientLabValue objects are retrieved via self.lab_values
423
440
 
424
- patient_disease_instances = list(self.diseases.all()) # These are PatientDisease model instances
441
+ patient_disease_instances = list(
442
+ self.diseases.all()
443
+ ) # These are PatientDisease model instances
425
444
  actual_diseases: List[Disease] = []
426
445
  all_classification_choices: List[DiseaseClassificationChoice] = []
427
446
 
428
447
  for pd_instance in patient_disease_instances:
429
- if pd_instance.disease: # pd_instance.disease is a Disease instance
448
+ if pd_instance.disease: # pd_instance.disease is a Disease instance
430
449
  actual_diseases.append(pd_instance.disease)
431
- all_classification_choices.extend(list(pd_instance.classification_choices.all()))
432
-
450
+ all_classification_choices.extend(
451
+ list(pd_instance.classification_choices.all())
452
+ )
453
+
433
454
  # Assuming self.lab_values is a related manager for PatientLabValue instances
434
- patient_lab_value_instances = list(self.lab_values.all()) # These are PatientLabValue model instances
455
+ patient_lab_value_instances = list(
456
+ self.lab_values.all()
457
+ ) # These are PatientLabValue model instances
435
458
 
436
459
  # Medication information
437
460
  # self.patientmedication_set gives a QuerySet of PatientMedication
438
- patient_medication_instances = list(self.patientmedication_set.all())
439
-
461
+ patient_medication_instances = list(self.patientmedication_set.all())
462
+
440
463
  actual_medications: List[Medication] = []
441
464
  med_indications: List[MedicationIndication] = []
442
465
  med_intake_times: List[MedicationIntakeTime] = []
443
466
 
444
467
  for pm_instance in patient_medication_instances:
445
- if pm_instance.medication: # pm_instance.medication is a Medication instance
468
+ if (
469
+ pm_instance.medication
470
+ ): # pm_instance.medication is a Medication instance
446
471
  actual_medications.append(pm_instance.medication)
447
- if pm_instance.medication_indication: # pm_instance.medication_indication is a MedicationIndication instance
472
+ if (
473
+ pm_instance.medication_indication
474
+ ): # pm_instance.medication_indication is a MedicationIndication instance
448
475
  med_indications.append(pm_instance.medication_indication)
449
- med_intake_times.extend(list(pm_instance.intake_times.all())) # pm_instance.intake_times is a ManyRelatedManager for MedicationIntakeTime
476
+ med_intake_times.extend(
477
+ list(pm_instance.intake_times.all())
478
+ ) # pm_instance.intake_times is a ManyRelatedManager for MedicationIntakeTime
450
479
 
451
480
  return RequirementLinks(
452
- diseases=list(set(actual_diseases)),
453
- patient_diseases=patient_disease_instances,
454
- disease_classification_choices=list(set(all_classification_choices)),
481
+ diseases=list(set(actual_diseases)),
482
+ patient_diseases=patient_disease_instances,
483
+ disease_classification_choices=list(set(all_classification_choices)),
455
484
  patient_lab_values=patient_lab_value_instances,
456
- medications=list(set(actual_medications)),
485
+ medications=list(set(actual_medications)),
457
486
  patient_medications=patient_medication_instances,
458
487
  medication_indications=list(set(med_indications)),
459
- medication_intake_times=list(set(med_intake_times))
488
+ medication_intake_times=list(set(med_intake_times)),
460
489
  )
@@ -0,0 +1,37 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from django.db import models # Add this import
4
+
5
+ if TYPE_CHECKING:
6
+ from endoreg_db.models import (
7
+ Patient,
8
+ )
9
+
10
+
11
+ class PatientExternalID(models.Model):
12
+ """
13
+ A class representing the identifier of external datasources.
14
+ Attributes:
15
+ external_id (str): The external ID value.
16
+ """
17
+
18
+ external_id: models.CharField = models.CharField(max_length=255)
19
+ patient = models.ForeignKey(
20
+ "Patient",
21
+ on_delete=models.CASCADE,
22
+ related_name="external_ids",
23
+ )
24
+ origin = models.CharField(max_length=255)
25
+
26
+ class Meta:
27
+ constraints = [
28
+ models.UniqueConstraint(
29
+ fields=("origin", "external_id"),
30
+ name="uniq_patient_external_id_per_origin",
31
+ )
32
+ ]
33
+
34
+ if TYPE_CHECKING:
35
+ patient: models.ForeignKey["Patient"]
36
+ origin: models.CharField[str]
37
+
@@ -22,6 +22,10 @@ class Person(models.Model):
22
22
  phone = models.CharField(max_length=255, blank=True, null=True)
23
23
  is_real_person = models.BooleanField(default=True)
24
24
 
25
+ post_code = models.CharField(max_length=20, blank=True, null=True)
26
+ city = models.CharField(max_length=255, blank=True, null=True)
27
+ street = models.CharField(max_length=255, blank=True, null=True)
28
+
25
29
  @abstractmethod
26
30
  def __str__(self):
27
31
  pass
@@ -1,24 +1,28 @@
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 endoreg_db.models import PortalUserInfo
6
7
 
8
+
7
9
  class ProfessionManager(models.Manager):
8
10
  def get_by_natural_key(self, name):
9
11
  return self.get(name=name)
10
12
 
13
+
11
14
  class Profession(models.Model):
12
15
  objects = ProfessionManager()
13
16
  name = models.CharField(max_length=100)
14
17
  description = models.TextField(blank=True, null=True)
15
18
 
16
-
17
19
  if TYPE_CHECKING:
18
- portal_user_infos: models.QuerySet["PortalUserInfo"]
20
+
21
+ @property
22
+ def portal_user_infos(self) -> models.QuerySet["PortalUserInfo"]: ...
19
23
 
20
24
  def __str__(self):
21
25
  """
22
26
  Return the profession's name as its string representation.
23
27
  """
24
- return str(self.name)
28
+ return str(self.name)
@@ -1,17 +1,21 @@
1
- from django.db import models
2
1
  from typing import TYPE_CHECKING
2
+
3
+ from django.db import models
4
+
3
5
  # models.py in your main app
4
6
 
5
7
  if TYPE_CHECKING:
6
- from ..profession import Profession
7
- from endoreg_db.models import Examiner
8
8
  from django.contrib.auth.models import User
9
9
 
10
+ from endoreg_db.models import Examiner
11
+
12
+ from ..profession import Profession
13
+
10
14
 
11
15
  class PortalUserInfo(models.Model):
12
16
  user = models.OneToOneField("auth.User", on_delete=models.CASCADE)
13
17
  profession = models.ForeignKey(
14
- 'endoreg_db.Profession',
18
+ "endoreg_db.Profession",
15
19
  on_delete=models.CASCADE,
16
20
  blank=True,
17
21
  null=True,
@@ -29,9 +33,9 @@ class PortalUserInfo(models.Model):
29
33
  )
30
34
 
31
35
  if TYPE_CHECKING:
32
- user: "User"
33
- profession: "Profession"
34
- examiner: "Examiner"
36
+ user: models.OneToOneField["User"]
37
+ profession: models.ForeignKey["Profession|None"]
38
+ examiner: models.OneToOneField["Examiner|None"]
35
39
 
36
40
  def __str__(self):
37
41
  return self.user.username
@@ -1,20 +1,23 @@
1
- from django.db import models
2
1
  from typing import TYPE_CHECKING
3
2
 
3
+ from django.db import models
4
+
4
5
  from endoreg_db.utils.product.sum_emissions import sum_emissions
5
6
  from endoreg_db.utils.product.sum_weights import sum_weights
6
7
 
7
8
  if TYPE_CHECKING:
8
9
  from ...other.transport_route import TransportRoute
9
10
  from .product_group import ProductGroup
10
- from .reference_product import ReferenceProduct
11
11
  from .product_material import ProductMaterial
12
+ from .reference_product import ReferenceProduct
12
13
  # from .product_weight import ProductWeight
13
14
 
15
+
14
16
  class ProductManager(models.Manager):
15
17
  def get_by_natural_key(self, name):
16
18
  return self.get(name=name)
17
-
19
+
20
+
18
21
  class Product(models.Model):
19
22
  objects = ProductManager()
20
23
 
@@ -29,15 +32,14 @@ class Product(models.Model):
29
32
  )
30
33
 
31
34
  if TYPE_CHECKING:
32
- transport_route: "TransportRoute"
33
- product_group: "ProductGroup"
35
+ transport_route: models.ForeignKey["TransportRoute|None"]
36
+ product_group: models.ForeignKey["ProductGroup|None"]
34
37
  reference_products: models.QuerySet["ReferenceProduct"]
35
38
  product_product_materials: models.QuerySet["ProductMaterial"]
36
39
 
37
-
38
40
  def natural_key(self):
39
41
  return (self.name,)
40
-
42
+
41
43
  def __str__(self):
42
44
  result = f"{self.name}"
43
45
  if self.product_group:
@@ -49,41 +51,44 @@ class Product(models.Model):
49
51
  result += f"{self.transport_route})"
50
52
  else:
51
53
  result += "no transport route)"
52
-
54
+
53
55
  return result
54
-
56
+
55
57
  def _calculate_material_metric(self, component: str, calculation_func):
56
58
  """Helper method to calculate weight or emission for materials of a specific component."""
57
- from .product_material import ProductMaterial # Import locally to avoid circular dependency issues at module level
59
+ from .product_material import ProductMaterial # Import locally to avoid circular dependency issues at module level
60
+
58
61
  materials = ProductMaterial.objects.filter(product=self, component=component)
59
62
  return calculation_func(materials)
60
63
 
61
64
  def get_product_weight(self):
62
65
  """Get the product weight, prioritizing material definitions."""
63
66
  from .product_material import ProductMaterial
67
+
64
68
  # Check if there are specific material definitions for the product component
65
69
  if ProductMaterial.objects.filter(product=self, component="product").exists():
66
70
  return self.get_product_material_weight()
67
-
71
+
68
72
  # Fallback: check if there is a direct product weight defined (Not implemented yet)
69
73
  # TODO: Implement logic for ProductWeight lookup
70
- return None # Or appropriate default/error
74
+ return None # Or appropriate default/error
71
75
 
72
76
  def get_package_weight(self):
73
77
  """Get the package weight, prioritizing material definitions."""
74
78
  from .product_material import ProductMaterial
79
+
75
80
  # Check if there are specific material definitions for the package component
76
81
  if ProductMaterial.objects.filter(product=self, component="package").exists():
77
82
  return self.get_package_material_weight()
78
-
83
+
79
84
  # Fallback: check if there is a direct package weight defined (Not implemented yet)
80
85
  # TODO: Implement logic for PackageWeight lookup (if different from ProductWeight)
81
- return None # Or appropriate default/error
86
+ return None # Or appropriate default/error
82
87
 
83
88
  def get_product_material_weight(self):
84
89
  """Calculate the total weight based on defined product materials."""
85
90
  return self._calculate_material_metric("product", sum_weights)
86
-
91
+
87
92
  def get_package_material_weight(self):
88
93
  """Calculate the total weight based on defined package materials."""
89
94
  return self._calculate_material_metric("package", sum_weights)
@@ -1,54 +1,53 @@
1
- from django.db import models
2
1
  from typing import TYPE_CHECKING
3
2
 
3
+ from django.db import models
4
+
4
5
  from endoreg_db.models.other.unit import Unit
5
6
 
6
7
  if TYPE_CHECKING:
7
- from ...other.emission import EmissionFactor
8
+ from ...other.material import Material
8
9
  from ...other.unit import Unit
9
10
  from .product import Product
10
- from ...other.material import Material
11
+
11
12
 
12
13
  class ProductMaterial(models.Model):
13
14
  component = models.CharField(max_length=255)
14
15
  material = models.ForeignKey(
15
16
  "Material",
16
17
  on_delete=models.CASCADE,
17
- related_name="material_product_materials", # Changed related_name
18
+ related_name="material_product_materials", # Changed related_name
18
19
  )
19
20
  product = models.ForeignKey(
20
21
  "Product",
21
22
  on_delete=models.CASCADE,
22
- related_name="product_product_materials" # Changed related_name
23
+ related_name="product_product_materials", # Changed related_name
23
24
  )
24
25
  unit = models.ForeignKey(
25
26
  "Unit",
26
27
  on_delete=models.CASCADE,
27
- related_name="unit_product_materials", # Changed related_name
28
+ related_name="unit_product_materials", # Changed related_name
28
29
  )
29
30
  quantity = models.FloatField()
30
31
 
31
32
  if TYPE_CHECKING:
32
- product: "Product"
33
- material: "Material"
34
- unit: "Unit"
35
- emission_factor: "EmissionFactor"
33
+ product: models.ForeignKey["Product"]
34
+ material: models.ForeignKey["Material"]
35
+ unit: models.ForeignKey["Unit"]
36
36
 
37
37
  def get_emission(self) -> tuple[float, Unit]:
38
38
  emission_factor = self.material.emission_factor
39
39
  if emission_factor is None:
40
40
  raise Exception("No emission factor for material " + self.material.name + " found.")
41
-
41
+
42
42
  # make sure product_material.unit is the same as emission_factor.unit
43
- if self.unit != emission_factor.unit:
44
- raise Exception("Unit mismatch: " + self.unit.name + " != " + emission_factor.unit.name)
45
-
43
+ if self.unit is not None and emission_factor.unit is not None:
44
+ if self.unit != emission_factor.unit:
45
+ raise Exception("Unit mismatch: " + self.unit.name + " != " + emission_factor.unit.name)
46
+
46
47
  emmision_value = emission_factor.value * self.quantity
48
+ assert isinstance(emission_factor.unit, Unit)
47
49
  emission_unit = emission_factor.unit
48
50
  return emmision_value, emission_unit
49
-
51
+
50
52
  def __str__(self) -> str:
51
53
  return f"{self.product.name} - {self.material.name} - {self.quantity} {self.unit.name}"
52
-
53
-
54
-