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,52 +1,87 @@
1
- '''Model for numeric value distribution'''
1
+ """Model for numeric value distribution"""
2
2
 
3
- from django.db import models
4
3
  import numpy as np
5
- from .base_value_distribution import BaseValueDistribution
4
+ from django.db import models
6
5
  from scipy.stats import skewnorm
6
+ from typing import TYPE_CHECKING
7
+
8
+ from .base_value_distribution import BaseValueDistribution
9
+
10
+ if TYPE_CHECKING:
11
+ from endoreg_db.models import LabValue, Patient
7
12
 
8
13
 
9
14
  class NumericValueDistributionManager(models.Manager):
10
- '''Object manager for NumericValueDistribution'''
15
+ """Object manager for NumericValueDistribution"""
16
+
11
17
  def get_by_natural_key(self, name):
12
- '''Retrieve a NumericValueDistribution by its natural key.'''
18
+ """Retrieve a NumericValueDistribution by its natural key."""
13
19
  return self.get(name=name)
14
20
 
21
+
15
22
  class NumericValueDistribution(BaseValueDistribution):
16
23
  """
17
24
  Numeric value distribution model.
18
25
  Supports uniform, normal, and skewed normal distributions with hard limits.
19
26
  """
27
+
20
28
  objects = NumericValueDistributionManager()
21
29
  DISTRIBUTION_CHOICES = [
22
- ('uniform', 'Uniform'),
23
- ('normal', 'Normal'),
24
- ('skewed_normal', 'Skewed Normal'),
30
+ ("uniform", "Uniform"),
31
+ ("normal", "Normal"),
32
+ ("skewed_normal", "Skewed Normal"),
25
33
  ]
26
34
 
27
35
  distribution_type = models.CharField(max_length=20, choices=DISTRIBUTION_CHOICES)
28
- min_descriptor = models.CharField(
29
- max_length=20
30
- )
31
-
32
- max_descriptor = models.CharField(
33
- max_length=20
34
- )
35
-
36
- def generate_value(self, lab_value, patient):
37
- '''Generate a value based on the distribution rules.'''
38
- #FIXME
39
- from endoreg_db.models import LabValue, Patient
40
- assert isinstance(patient, Patient)
41
- assert isinstance(lab_value, LabValue)
42
- default_normal_range_dict = lab_value.get_normal_range(patient.age(), patient.gender)
36
+ min_descriptor = models.CharField(max_length=20)
37
+ max_descriptor = models.CharField(max_length=20)
38
+ min_value = models.FloatField(blank=True, null=True, help_text="Lower hard limit for generated values")
39
+ max_value = models.FloatField(blank=True, null=True, help_text="Upper hard limit for generated values")
40
+ mean = models.FloatField(blank=True, null=True, help_text="Mean used for normal or skewed normal distributions")
41
+ std_dev = models.FloatField(blank=True, null=True, help_text="Standard deviation for bell-shaped distributions")
42
+ skewness = models.FloatField(blank=True, null=True, help_text="Shape parameter for skewed normal distributions")
43
+
44
+ @property
45
+ def min_value_safe(self):
46
+ if self.min_value is None:
47
+ raise ValueError("min_value is not set")
48
+ return self.min_value
49
+
50
+ @property
51
+ def max_value_safe(self):
52
+ if self.max_value is None:
53
+ raise ValueError("max_value is not set")
54
+ return self.max_value
55
+
56
+ @property
57
+ def mean_safe(self):
58
+ if self.mean is None:
59
+ raise ValueError("mean is not set")
60
+ return self.mean
61
+
62
+ @property
63
+ def std_dev_safe(self):
64
+ if self.std_dev is None:
65
+ raise ValueError("std_dev is not set")
66
+ return self.std_dev
67
+
68
+ @property
69
+ def skewness_safe(self):
70
+ if self.skewness is None:
71
+ raise ValueError("skewness is not set")
72
+ return self.skewness
73
+
74
+ def generate_value(self, lab_value: "LabValue", patient: "Patient"):
75
+ """Generate a value based on the distribution rules."""
76
+
77
+ default_normal_range_dict = lab_value.get_normal_range(patient.age_safe, patient.gender)
43
78
  assert isinstance(default_normal_range_dict, dict)
44
79
 
45
- if self.distribution_type == 'uniform':
80
+ if self.distribution_type == "uniform":
46
81
  assert self.min_descriptor and self.max_descriptor
47
-
48
- min_key_needed = self.min_descriptor.split('_')[0]
49
- max_key_needed = self.max_descriptor.split('_')[0]
82
+
83
+ min_key_needed = self.min_descriptor.split("_")[0]
84
+ max_key_needed = self.max_descriptor.split("_")[0]
50
85
 
51
86
  min_val_from_range = default_normal_range_dict.get(min_key_needed)
52
87
  max_val_from_range = default_normal_range_dict.get(max_key_needed)
@@ -61,7 +96,7 @@ class NumericValueDistribution(BaseValueDistribution):
61
96
  f"LabValue '{lab_value.name}' is gender-dependent: {lab_value.normal_range_gender_dependent}. "
62
97
  f"Check LabValue's default_normal_range definition for this patient context."
63
98
  )
64
-
99
+
65
100
  if max_val_from_range is None:
66
101
  raise ValueError(
67
102
  f"Cannot generate value for LabValue '{lab_value.name}' using distribution "
@@ -72,22 +107,29 @@ class NumericValueDistribution(BaseValueDistribution):
72
107
  f"LabValue '{lab_value.name}' is gender-dependent: {lab_value.normal_range_gender_dependent}. "
73
108
  f"Check LabValue's default_normal_range definition for this patient context."
74
109
  )
75
-
110
+
76
111
  value = self._generate_value_uniform(default_normal_range_dict)
77
-
112
+
78
113
  return value
79
-
80
- elif self.distribution_type == 'normal':
114
+
115
+ elif self.distribution_type == "normal":
116
+ self._validate_normal_parameters()
117
+ assert self.mean is not None
118
+ assert self.std_dev is not None
81
119
  value = np.random.normal(self.mean, self.std_dev)
82
- return np.clip(value, self.min_value, self.max_value)
83
- elif self.distribution_type == 'skewed_normal':
120
+ return self._clip_to_bounds(value)
121
+ elif self.distribution_type == "skewed_normal":
122
+ self._validate_skewed_normal_parameters()
123
+ assert self.mean is not None
124
+ assert self.std_dev is not None
125
+ assert self.skewness is not None
84
126
  value = skewnorm.rvs(a=self.skewness, loc=self.mean, scale=self.std_dev)
85
- return np.clip(value, self.min_value, self.max_value)
127
+ return self._clip_to_bounds(value)
86
128
  else:
87
129
  raise ValueError("Unsupported distribution type")
88
130
 
89
- def parse_value_descriptor(self, value_descriptor:str):
90
- '''Parse the value descriptor string into a dict with a lambda function.'''
131
+ def parse_value_descriptor(self, value_descriptor: str):
132
+ """Parse the value descriptor string into a dict with a lambda function."""
91
133
  # strings of shape f"{value_key}_{operator}_{value}"
92
134
  # extract value_key, operator, value
93
135
  value_key, operator, value = value_descriptor.split("_")
@@ -104,22 +146,41 @@ class NumericValueDistribution(BaseValueDistribution):
104
146
 
105
147
  # create dict with {value_key: lambda x: x operator value}
106
148
 
107
- def _generate_value_uniform(self, default_normal_range_dict:dict):
108
- value_function_dict = self.parse_value_descriptor(
109
- self.min_descriptor
110
- )
149
+ def _generate_value_uniform(self, default_normal_range_dict: dict):
150
+ value_function_dict = self.parse_value_descriptor(self.min_descriptor)
151
+ value_function_dict.update(self.parse_value_descriptor(self.max_descriptor))
111
152
 
112
- _ = self.parse_value_descriptor(
113
- self.max_descriptor
114
- )
115
-
116
- value_function_dict.update(_)
117
-
118
- result_dict = {
119
- key: value_function(default_normal_range_dict[key])
120
- for key, value_function in value_function_dict.items()
121
- }
153
+ result_dict = {key: value_function(default_normal_range_dict[key]) for key, value_function in value_function_dict.items()}
122
154
 
123
155
  # generate value
124
- return np.random.uniform(result_dict["min"], result_dict["max"])
125
-
156
+ return float(np.random.uniform(result_dict["min"], result_dict["max"]))
157
+
158
+ @property
159
+ def stddev(self):
160
+ """Alias to std_dev for backwards compatibility."""
161
+ return self.std_dev
162
+
163
+ @stddev.setter
164
+ def stddev(self, value):
165
+ self.std_dev = value
166
+
167
+ def _clip_to_bounds(self, value: float) -> float:
168
+ """Clip the provided value to the configured hard bounds if available."""
169
+ lower = self.min_value
170
+ upper = self.max_value
171
+
172
+ if lower is not None and upper is not None:
173
+ return float(np.clip(value, lower, upper))
174
+ if lower is not None:
175
+ return float(max(value, lower))
176
+ if upper is not None:
177
+ return float(min(value, upper))
178
+ return float(value)
179
+
180
+ def _validate_normal_parameters(self) -> None:
181
+ if self.mean is None or self.std_dev is None:
182
+ raise ValueError(f"Normal distribution '{getattr(self, 'name', self.pk)}' requires both mean and std_dev.")
183
+
184
+ def _validate_skewed_normal_parameters(self) -> None:
185
+ if self.mean is None or self.std_dev is None or self.skewness is None:
186
+ raise ValueError(f"Skewed normal distribution '{getattr(self, 'name', self.pk)}' requires mean, std_dev, and skewness.")
@@ -1,5 +1,6 @@
1
- from django.db import models
2
1
  import numpy as np
2
+ from django.db import models
3
+
3
4
  from .base_value_distribution import BaseValueDistribution
4
5
 
5
6
 
@@ -7,16 +8,16 @@ class SingleCategoricalValueDistributionManager(models.Manager):
7
8
  def get_by_natural_key(self, name):
8
9
  return self.get(name=name)
9
10
 
11
+
10
12
  class SingleCategoricalValueDistribution(BaseValueDistribution):
11
13
  """
12
14
  Single categorical value distribution model.
13
15
  Assigns a single value based on specified probabilities.
14
16
  """
17
+
15
18
  objects = SingleCategoricalValueDistributionManager()
16
19
  categories = models.JSONField() # { "category": "probability", ... }
17
20
 
18
21
  def generate_value(self):
19
22
  categories, probabilities = zip(*self.categories.items())
20
23
  return np.random.choice(categories, p=probabilities)
21
-
22
-
@@ -1,21 +1,26 @@
1
- from django.db import models
2
1
  from typing import TYPE_CHECKING, List
3
2
 
3
+ from django.db import models
4
+
4
5
  if TYPE_CHECKING:
5
6
  from ...administration import ReferenceProduct
6
7
  from ..unit import Unit
7
8
 
9
+
8
10
  class EmissionFactorManager(models.Manager):
9
11
  """
10
12
  Manager for EmissionFactor with custom query methods.
11
13
  """
14
+
12
15
  def get_by_natural_key(self, name: str) -> "EmissionFactor":
13
16
  return self.get(name=name)
14
17
 
18
+
15
19
  # get debug from settings
16
20
  # from django.conf import settings
17
21
  # DEBUG = settings.DEBUG
18
22
 
23
+
19
24
  class EmissionFactor(models.Model):
20
25
  """
21
26
  Represents an emission factor with associated unit and value.
@@ -25,6 +30,7 @@ class EmissionFactor(models.Model):
25
30
  unit (ForeignKey): The unit associated with the emission factor.
26
31
  value (float): The value of the emission factor.
27
32
  """
33
+
28
34
  objects = EmissionFactorManager()
29
35
 
30
36
  name = models.CharField(max_length=255)
@@ -32,13 +38,17 @@ class EmissionFactor(models.Model):
32
38
  value = models.FloatField()
33
39
 
34
40
  if TYPE_CHECKING:
35
- unit: "Unit"
36
- reference_products: models.QuerySet["ReferenceProduct"]
37
- reference_product_package: models.QuerySet["ReferenceProduct"]
38
- reference_product_product: models.QuerySet["ReferenceProduct"]
41
+ unit: models.ForeignKey["Unit|None"]
42
+
43
+ @property
44
+ def reference_products(self) -> models.QuerySet["ReferenceProduct"]: ...
45
+
46
+ @property
47
+ def reference_product_package(self) -> models.QuerySet["ReferenceProduct"]: ...
48
+
49
+ @property
50
+ def reference_product_product(self) -> models.QuerySet["ReferenceProduct"]: ...
39
51
 
40
-
41
-
42
52
  def natural_key(self) -> tuple:
43
53
  """
44
54
  Returns the natural key for the emission factor.
@@ -65,7 +75,7 @@ class EmissionFactor(models.Model):
65
75
  result += f"\n\t\t{source}"
66
76
 
67
77
  return result
68
-
78
+
69
79
  def get_reference_products(self) -> List["ReferenceProduct"]:
70
80
  """
71
81
  Retrieves all reference products associated with the emission factor.
@@ -1,15 +1,19 @@
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 import Patient
6
7
 
8
+
7
9
  class GenderManager(models.Manager):
8
10
  def get_by_natural_key(self, name):
9
11
  return self.get(name=name)
10
-
12
+
13
+
11
14
  class Gender(models.Model):
12
15
  """A class representing gender."""
16
+
13
17
  objects = GenderManager()
14
18
 
15
19
  name = models.CharField(max_length=255)
@@ -17,11 +21,12 @@ class Gender(models.Model):
17
21
  description = models.TextField(blank=True, null=True)
18
22
 
19
23
  if TYPE_CHECKING:
20
- patients: models.QuerySet["Patient"]
24
+
25
+ @property
26
+ def patients(self) -> models.QuerySet["Patient"]: ...
21
27
 
22
28
  def natural_key(self):
23
29
  return (self.name,)
24
-
30
+
25
31
  def __str__(self):
26
32
  return str(self.name)
27
-
@@ -1,12 +1,15 @@
1
- from django.db import models
2
1
  from typing import TYPE_CHECKING
2
+
3
+ from django.db import models
4
+
3
5
  if TYPE_CHECKING:
4
6
  from endoreg_db.models import InformationSourceType
5
7
 
8
+
6
9
  def get_prediction_information_source():
7
10
  """
8
11
  Returns the InformationSource instance with the name "prediction".
9
-
12
+
10
13
  Raises:
11
14
  AssertionError: If no InformationSource with the name "prediction" exists.
12
15
  """
@@ -21,10 +24,10 @@ class InformationSourceManager(models.Manager):
21
24
  def get_by_natural_key(self, name):
22
25
  """
23
26
  Retrieves a model instance using its natural key.
24
-
27
+
25
28
  Args:
26
29
  name: The natural key value corresponding to the model's 'name' field.
27
-
30
+
28
31
  Returns:
29
32
  The model instance that matches the provided natural key.
30
33
  """
@@ -42,11 +45,12 @@ class InformationSource(models.Model):
42
45
  date_created = models.DateField(auto_now_add=True)
43
46
  date_modified = models.DateField(auto_now=True)
44
47
  abbreviation = models.CharField(max_length=100, blank=True, null=True, unique=True)
45
-
48
+
46
49
  if TYPE_CHECKING:
47
- #information_source_types: models.QuerySet["InformationSourceType"]
50
+ # information_source_types: models.QuerySet["InformationSourceType"]
48
51
  # Avoid self-referential import; use forward references instead
49
52
  pass
53
+
50
54
  class Meta:
51
55
  verbose_name = "Information Source"
52
56
  verbose_name_plural = "Information Sources"
@@ -55,14 +59,13 @@ class InformationSource(models.Model):
55
59
  indexes = [
56
60
  models.Index(fields=["name"]),
57
61
  models.Index(fields=["abbreviation"]),
58
- ]
59
-
62
+ ]
60
63
 
61
64
  def natural_key(self):
62
65
  """
63
66
  Returns the natural key tuple for the information source.
64
-
65
- The tuple contains the object's name, which uniquely identifies it for
67
+
68
+ The tuple contains the object's name, which uniquely identifies it for
66
69
  serialization and natural key lookup.
67
70
  """
68
71
  return (self.name,)
@@ -73,19 +76,21 @@ class InformationSource(models.Model):
73
76
  """
74
77
  return str(self.name)
75
78
 
79
+
76
80
  class InformationSourceTypeManager(models.Manager):
77
81
  def get_by_natural_key(self, name):
78
82
  """
79
83
  Retrieve an instance of the model by its natural key, which is the 'name' field.
80
-
84
+
81
85
  Parameters:
82
86
  name (str): The value of the 'name' field to look up.
83
-
87
+
84
88
  Returns:
85
89
  The model instance with the specified name.
86
90
  """
87
91
  return self.get(name=name)
88
-
92
+
93
+
89
94
  class InformationSourceType(models.Model):
90
95
  objects = InformationSourceTypeManager()
91
96
 
@@ -108,10 +113,10 @@ class InformationSourceType(models.Model):
108
113
  def get_prediction_type(cls) -> "InformationSourceType":
109
114
  """
110
115
  Return the InformationSourceType instance with the name "prediction".
111
-
116
+
112
117
  Returns:
113
118
  InformationSourceType: The instance representing the "prediction" information source type.
114
-
119
+
115
120
  Raises:
116
121
  InformationSourceType.DoesNotExist: If no such instance exists.
117
122
 
@@ -119,20 +124,17 @@ class InformationSourceType(models.Model):
119
124
  try:
120
125
  return cls.objects.get(name="prediction")
121
126
  except cls.DoesNotExist as e:
122
- raise cls.DoesNotExist(
123
- "The 'prediction' InformationSourceType was not found. "
124
- "Please check your data fixtures or initial data migrations."
125
- ) from e
127
+ raise cls.DoesNotExist("The 'prediction' InformationSourceType was not found. Please check your data fixtures or initial data migrations.") from e
126
128
 
127
129
  @classmethod
128
130
  def get_manual_annotation_type(cls) -> "InformationSourceType":
129
131
  """
130
132
 
131
133
  Return the InformationSourceType instance representing manual annotation.
132
-
134
+
133
135
  Returns:
134
136
  InformationSourceType: The instance with name "annotation".
135
-
137
+
136
138
  Raises:
137
139
  AssertionError: If no InformationSourceType with name "annotation" exists.
138
140
 
@@ -141,11 +143,9 @@ class InformationSourceType(models.Model):
141
143
  return cls.objects.get(name="manual_annotation")
142
144
  except cls.DoesNotExist as e:
143
145
  raise cls.DoesNotExist(
144
- "The 'manual_annotation' InformationSourceType was not found. "
145
- "Please check your data fixtures or initial data migrations."
146
+ "The 'manual_annotation' InformationSourceType was not found. Please check your data fixtures or initial data migrations."
146
147
  ) from e
147
148
 
148
-
149
149
  def natural_key(self):
150
150
  """
151
151
  Return a tuple containing the name of the information source type for natural key serialization.
@@ -156,4 +156,4 @@ class InformationSourceType(models.Model):
156
156
  """
157
157
  Return the name of the InformationSourceType as its string representation.
158
158
  """
159
- return str(self.name)
159
+ return str(self.name)
@@ -1,15 +1,17 @@
1
- from django.db import models
2
1
  from typing import TYPE_CHECKING
3
2
 
3
+ from django.db import models
4
4
 
5
5
  if TYPE_CHECKING:
6
- from .emission import EmissionFactor
7
6
  from ..administration.product.product_material import ProductMaterial
7
+ from .emission import EmissionFactor
8
+
8
9
 
9
10
  class MaterialManager(models.Manager):
10
11
  def get_by_natural_key(self, name):
11
12
  return self.get(name=name)
12
13
 
14
+
13
15
  class Material(models.Model):
14
16
  objects = MaterialManager()
15
17
 
@@ -17,12 +19,14 @@ class Material(models.Model):
17
19
  emission_factor = models.ForeignKey("EmissionFactor", on_delete=models.SET_NULL, null=True)
18
20
 
19
21
  if TYPE_CHECKING:
20
- emission_factor: "EmissionFactor"
21
- material_product_materials: models.QuerySet["ProductMaterial"]
22
+ emission_factor: models.ForeignKey["EmissionFactor|None"]
23
+
24
+ @property
25
+ def material_product_materials(self) -> models.QuerySet["ProductMaterial"]: ...
22
26
 
23
27
  def natural_key(self):
24
28
  return (self.name,)
25
-
29
+
26
30
  def __str__(self):
27
31
  result = f"{self.name} - EmissionFactor: {self.emission_factor}"
28
32
  return result
@@ -1,9 +1,11 @@
1
1
  from django.db import models
2
2
 
3
+
3
4
  class ResourceManager(models.Manager):
4
5
  def get_by_natural_key(self, name):
5
6
  return self.get(name=name)
6
-
7
+
8
+
7
9
  class Resource(models.Model):
8
10
  objects = ResourceManager()
9
11
 
@@ -12,11 +14,11 @@ class Resource(models.Model):
12
14
  def natural_key(self):
13
15
  """
14
16
  Return a tuple representing the natural key for this resource instance.
15
-
17
+
16
18
  Returns:
17
19
  tuple: A one-element tuple containing the resource's name.
18
20
  """
19
21
  return (self.name,)
20
-
22
+
21
23
  def __str__(self):
22
- return self.name
24
+ return self.name
@@ -1,20 +1,25 @@
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 RequirementSet
6
7
 
8
+
7
9
  class TagManager(models.Manager):
8
10
  def get_by_natural_key(self, name):
9
11
  return self.get(name=name)
10
-
12
+
13
+
11
14
  class Tag(models.Model):
12
15
  name = models.CharField(max_length=100, unique=True)
13
16
 
14
17
  objects = TagManager()
15
-
18
+
16
19
  if TYPE_CHECKING:
17
- requirement_sets: "models.ManyToManyField[RequirementSet]"
20
+
21
+ @property
22
+ def requirement_sets(self) -> "models.QuerySet[RequirementSet]": ...
18
23
 
19
24
  class Meta:
20
25
  verbose_name = "Tag"
@@ -24,4 +29,4 @@ class Tag(models.Model):
24
29
  return self.name
25
30
 
26
31
  def natural_key(self):
27
- return (self.name,)
32
+ return (self.name,)
@@ -1,17 +1,20 @@
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 (
6
- Product,
7
7
  EmissionFactor,
8
+ Product,
8
9
  Unit,
9
10
  )
10
11
 
12
+
11
13
  class TransportRouteManager(models.Manager):
12
14
  def get_by_natural_key(self, name):
13
15
  return self.get(name=name)
14
-
16
+
17
+
15
18
  class TransportRoute(models.Model):
16
19
  objects = TransportRouteManager()
17
20
 
@@ -21,13 +24,15 @@ class TransportRoute(models.Model):
21
24
  unit = models.ForeignKey("Unit", on_delete=models.SET_NULL, null=True)
22
25
 
23
26
  if TYPE_CHECKING:
24
- emission_factor: "EmissionFactor"
25
- unit: "Unit"
26
- products: models.QuerySet["Product"]
27
+ emission_factor: models.ForeignKey["EmissionFactor|None"]
28
+ unit: models.ForeignKey["Unit|None"]
29
+
30
+ @property
31
+ def products(self) -> models.QuerySet["Product"]: ...
27
32
 
28
33
  def natural_key(self):
29
34
  return (self.name,)
30
-
35
+
31
36
  def __str__(self):
32
37
  result = f"{self.name} ({self.distance} {self.unit}) - {self.emission_factor}"
33
- return result
38
+ return result