meta-edc 0.3.39__py3-none-any.whl → 1.4.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.
Files changed (637) hide show
  1. meta_ae/action_items.py +38 -27
  2. meta_ae/admin/__init__.py +11 -0
  3. meta_ae/admin/ae_initial_admin.py +5 -2
  4. meta_ae/admin/ae_susar_admin.py +1 -1
  5. meta_ae/admin/death_report_admin.py +1 -1
  6. meta_ae/admin/modeladmin_mixins.py +14 -15
  7. meta_ae/baker_recipes.py +4 -6
  8. meta_ae/choices.py +1 -1
  9. meta_ae/forms/__init__.py +13 -0
  10. meta_ae/forms/death_report_form.py +1 -1
  11. meta_ae/forms/modelform_mixins.py +2 -2
  12. meta_ae/list_data.py +1 -1
  13. meta_ae/migrations/0001_initial.py +27 -27
  14. meta_ae/migrations/0006_aelocalreview_aesponsorreview.py +5 -5
  15. meta_ae/migrations/0017_auto_20221130_2257.py +1 -1
  16. meta_ae/migrations/0022_historicalhospitalization_hospitalization.py +5 -13
  17. meta_ae/migrations/0023_alter_aefollowup_action_identifier_and_more.py +2017 -0
  18. meta_ae/model_mixins/__init__.py +2 -0
  19. meta_ae/model_mixins/ae_review_model_mixin.py +6 -6
  20. meta_ae/model_mixins/death_report_model_mixin.py +3 -3
  21. meta_ae/models/__init__.py +13 -0
  22. meta_ae/models/hospitalization.py +3 -3
  23. meta_ae/pdf_reports/__init__.py +2 -0
  24. meta_ae/templatetags/meta_ae_extras.py +4 -6
  25. meta_analytics/.DS_Store +0 -0
  26. meta_analytics/README.rst +1 -2
  27. meta_analytics/dataframes/__init__.py +27 -0
  28. meta_analytics/dataframes/constants.py +5 -2
  29. meta_analytics/dataframes/get_eos_df.py +16 -4
  30. meta_analytics/dataframes/get_glucose_df.py +166 -0
  31. meta_analytics/dataframes/get_glucose_fbg_df.py +26 -0
  32. meta_analytics/dataframes/get_glucose_fbg_ogtt_df.py +21 -0
  33. meta_analytics/dataframes/get_last_imp_visits_df.py +12 -10
  34. meta_analytics/dataframes/glucose_endpoints/__init__.py +2 -0
  35. meta_analytics/dataframes/glucose_endpoints/endpoint_by_date.py +125 -124
  36. meta_analytics/dataframes/glucose_endpoints/glucose_endpoints_by_date.py +111 -235
  37. meta_analytics/dataframes/screening/__init__.py +2 -0
  38. meta_analytics/dataframes/screening/get_glucose_tested_only_df.py +1 -2
  39. meta_analytics/dataframes/screening/get_screening_df.py +9 -15
  40. meta_analytics/dataframes/utils.py +21 -12
  41. meta_analytics/get_tables.py +1 -2
  42. meta_analytics/tables/__init__.py +2 -0
  43. meta_analytics/tables/enrolled/glucose.py +2 -1
  44. meta_analytics/utils.py +81 -0
  45. meta_auth/auths.py +1 -1
  46. meta_consent/action_items.py +22 -3
  47. meta_consent/admin/__init__.py +7 -0
  48. meta_consent/admin/actions/__init__.py +2 -0
  49. meta_consent/admin/actions/create_missing_prescriptions.py +2 -2
  50. meta_consent/admin/list_filters.py +22 -0
  51. meta_consent/admin/modeladmin_mixins.py +4 -5
  52. meta_consent/admin/subject_consent_v1_ext_admin.py +93 -0
  53. meta_consent/baker_recipes.py +7 -7
  54. meta_consent/consents.py +15 -2
  55. meta_consent/constants.py +1 -0
  56. meta_consent/form_validators/__init__.py +2 -0
  57. meta_consent/forms/__init__.py +8 -0
  58. meta_consent/forms/subject_consent_v1_ext_form.py +47 -0
  59. meta_consent/forms/subject_reconsent_form.py +4 -4
  60. meta_consent/management/commands/create_missing_prescriptions.py +5 -3
  61. meta_consent/migrations/0001_initial.py +9 -9
  62. meta_consent/migrations/0024_historicalsubjectconsentv1.py +3 -8
  63. meta_consent/migrations/0026_historicalsubjectconsentv1ext_subjectconsentv1ext.py +535 -0
  64. meta_consent/migrations/0027_auto_20250111_0344.py +30 -0
  65. meta_consent/migrations/0028_historicalsubjectconsentv1ext_assessment_score_and_more.py +162 -0
  66. meta_consent/migrations/0029_alter_historicalsubjectconsentv1ext_agrees_to_extension_and_more.py +33 -0
  67. meta_consent/migrations/0030_auto_20250120_2114.py +40 -0
  68. meta_consent/migrations/0031_alter_historicalsubjectconsent_guardian_name_and_more.py +124 -0
  69. meta_consent/migrations/0032_alter_historicalsubjectconsent_device_created_and_more.py +678 -0
  70. meta_consent/migrations/0033_historicalsubjectconsentspfq_subjectconsentspfq.py +615 -0
  71. meta_consent/migrations/0034_remove_subjectconsentspfq_site_and_more.py +23 -0
  72. meta_consent/migrations/0035_alter_historicalsubjectconsent_consent_definition_name_and_more.py +43 -0
  73. meta_consent/models/__init__.py +10 -0
  74. meta_consent/models/model_mixins.py +1 -2
  75. meta_consent/models/signals.py +25 -11
  76. meta_consent/models/subject_consent.py +2 -2
  77. meta_consent/models/subject_consent_v1.py +0 -1
  78. meta_consent/models/subject_consent_v1_ext.py +34 -0
  79. meta_consent/models/subject_reconsent.py +4 -4
  80. meta_dashboard/navbars.py +2 -6
  81. meta_dashboard/patterns.py +1 -1
  82. meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/eligibility_button.html +1 -1
  83. meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/screening_button.html +1 -1
  84. meta_dashboard/templates/meta_dashboard/subject/dashboard/sidebar.html +24 -0
  85. meta_dashboard/templates/meta_dashboard/{bootstrap3/subject → subject}/dashboard/top_bar.html +1 -1
  86. meta_dashboard/templates/meta_dashboard/subject/dashboard.html +14 -0
  87. meta_dashboard/templatetags/meta_dashboard_extras.py +9 -14
  88. meta_dashboard/urls.py +5 -5
  89. meta_dashboard/view_utils/__init__.py +13 -0
  90. meta_dashboard/view_utils/subject_screening_button.py +13 -20
  91. meta_dashboard/views/__init__.py +8 -0
  92. meta_dashboard/views/ae/__init__.py +2 -0
  93. meta_dashboard/views/ae/ae_listboard_view.py +1 -1
  94. meta_dashboard/views/ae/death_report_listboard_view.py +1 -1
  95. meta_dashboard/views/screening/__init__.py +2 -0
  96. meta_dashboard/views/screening/listboard_view.py +2 -3
  97. meta_dashboard/views/subject/__init__.py +2 -0
  98. meta_dashboard/views/subject/dashboard/__init__.py +2 -0
  99. meta_dashboard/views/subject/dashboard/dashboard_view.py +19 -8
  100. meta_dashboard/views/subject/listboard/__init__.py +2 -0
  101. meta_dashboard/views/subject/listboard/listboard_view.py +2 -3
  102. meta_edc/__init__.py +5 -9
  103. meta_edc/admin.py +3 -4
  104. meta_edc/celery.py +2 -2
  105. meta_edc/celery_live.py +19 -0
  106. meta_edc/celery_uat.py +25 -0
  107. meta_edc/management/commands/update_forms_reference.py +16 -14
  108. meta_edc/meta_version.py +2 -2
  109. meta_edc/navbars.py +7 -5
  110. meta_edc/settings/debug.py +13 -4
  111. meta_edc/settings/defaults.py +55 -18
  112. meta_edc/settings/live.py +4 -1
  113. meta_edc/settings/logging.py +9 -4
  114. meta_edc/settings/minimal.py +4 -5
  115. meta_edc/settings/uat.py +3 -1
  116. meta_edc/templates/meta_edc/{bootstrap3/base.html → base.html} +1 -1
  117. meta_edc/templates/meta_edc/{bootstrap3/home.html → home.html} +2 -2
  118. meta_edc/urls.py +3 -1
  119. meta_edc/utils.py +3 -1
  120. meta_edc/views/__init__.py +2 -0
  121. meta_edc/views/home_view.py +1 -2
  122. meta_edc-1.4.0.dist-info/METADATA +174 -0
  123. {meta_edc-0.3.39.dist-info → meta_edc-1.4.0.dist-info}/RECORD +578 -586
  124. meta_edc-1.4.0.dist-info/WHEEL +4 -0
  125. meta_labs/list_data.py +2 -2
  126. meta_labs/reportables.py +80 -11
  127. meta_lists/list_data.py +13 -4
  128. meta_lists/migrations/0008_auto_20200528_1517.py +2 -2
  129. meta_lists/migrations/0019_auto_20250128_0143.py +48 -0
  130. meta_lists/migrations/0020_alter_abnormalfootappearanceobservations_extra_value_and_more.py +404 -0
  131. meta_pharmacy/admin/__init__.py +5 -0
  132. meta_pharmacy/admin/rx_admin.py +1 -0
  133. meta_pharmacy/admin/substitutions_admin.py +3 -3
  134. meta_pharmacy/constants.py +1 -1
  135. meta_pharmacy/forms/__init__.py +2 -0
  136. meta_pharmacy/forms/rx_form.py +0 -1
  137. meta_pharmacy/forms/substitutions_form.py +6 -4
  138. meta_pharmacy/labels/__init__.py +5 -2
  139. meta_pharmacy/labels/draw_label_for_subject_with_barcode.py +4 -1
  140. meta_pharmacy/labels/draw_label_with_test_data.py +2 -2
  141. meta_pharmacy/labels/label_data.py +1 -2
  142. meta_pharmacy/labels/print_sheets.py +4 -6
  143. meta_pharmacy/management/commands/update_initial_pharmacy_data.py +4 -3
  144. meta_pharmacy/migrations/0002_initial.py +7 -20
  145. meta_pharmacy/migrations/0003_auto_20240909_2335.py +3 -2
  146. meta_pharmacy/migrations/0006_lotnumber_label.py +5 -14
  147. meta_pharmacy/migrations/0008_remove_lotnumber_medication_and_more.py +5 -6
  148. meta_pharmacy/migrations/0010_alter_historicallabeldata_device_created_and_more.py +382 -0
  149. meta_pharmacy/models/__init__.py +7 -0
  150. meta_pharmacy/models/label_data.py +4 -5
  151. meta_pharmacy/models/rx_label.py +0 -1
  152. meta_pharmacy/models/substitutions.py +4 -4
  153. meta_pharmacy/prepare_meta_pharmacy.py +1 -1
  154. meta_pharmacy/utils/__init__.py +2 -0
  155. meta_pharmacy/utils/update_initial_pharmacy_data.py +1 -1
  156. meta_prn/action_items.py +44 -45
  157. meta_prn/admin/__init__.py +16 -0
  158. meta_prn/admin/dm_referral_admin.py +2 -1
  159. meta_prn/admin/end_of_study_admin.py +26 -15
  160. meta_prn/admin/loss_to_followup_admin.py +3 -2
  161. meta_prn/admin/off_study_medication_admin.py +5 -6
  162. meta_prn/admin/offschedule_admin.py +12 -11
  163. meta_prn/admin/offschedule_dm_referral_admin.py +11 -10
  164. meta_prn/admin/offschedule_postnatal_admin.py +15 -7
  165. meta_prn/admin/offschedule_pregnancy_admin.py +18 -9
  166. meta_prn/admin/onschedule_admin.py +7 -8
  167. meta_prn/admin/onschedule_dm_referral_admin.py +11 -12
  168. meta_prn/admin/pregnancy_notification_admin.py +5 -6
  169. meta_prn/admin/protocol_incident_admin.py +1 -1
  170. meta_prn/admin/subject_transfer_admin.py +1 -1
  171. meta_prn/baker_recipes.py +10 -10
  172. meta_prn/choices.py +11 -7
  173. meta_prn/constants.py +1 -0
  174. meta_prn/form_validators/__init__.py +5 -0
  175. meta_prn/form_validators/end_of_study.py +65 -20
  176. meta_prn/form_validators/protocol_incident.py +1 -1
  177. meta_prn/forms/__init__.py +13 -0
  178. meta_prn/forms/dm_referral_form.py +2 -8
  179. meta_prn/forms/end_of_study_form.py +1 -1
  180. meta_prn/forms/loss_to_followup_form.py +1 -1
  181. meta_prn/forms/off_study_medication_form.py +2 -2
  182. meta_prn/forms/offschedule_form.py +25 -0
  183. meta_prn/forms/pregnancy_notification_form.py +15 -17
  184. meta_prn/list_data.py +3 -3
  185. meta_prn/migrations/0001_initial.py +25 -25
  186. meta_prn/migrations/0017_auto_20220307_1929.py +5 -5
  187. meta_prn/migrations/0018_auto_20220309_2106.py +9 -9
  188. meta_prn/migrations/0021_auto_20220316_2147.py +13 -13
  189. meta_prn/migrations/0022_auto_20220318_0133.py +9 -9
  190. meta_prn/migrations/0032_historicalegfrnotification_egfrnotification.py +5 -13
  191. meta_prn/migrations/0034_auto_20220630_1110.py +1 -1
  192. meta_prn/migrations/0035_auto_20220630_1140.py +1 -1
  193. meta_prn/migrations/0038_alter_endofstudy_delivery_date_and_more.py +5 -13
  194. meta_prn/migrations/0041_endofstudy_transfer_date_and_more.py +5 -13
  195. meta_prn/migrations/0057_historicalonscheduledmreferral_and_more.py +13 -38
  196. meta_prn/migrations/0060_alter_onschedule_managers_and_more.py +55 -0
  197. meta_prn/migrations/0061_auto_20250115_2025.py +56 -0
  198. meta_prn/migrations/0062_alter_endofstudy_offstudy_reason_and_more.py +72 -0
  199. meta_prn/migrations/0063_historicaloffstudymedication_singleton_field_and_more.py +37 -0
  200. meta_prn/migrations/0064_auto_20250602_2143.py +18 -0
  201. meta_prn/migrations/0065_alter_historicaloffstudymedication_subject_identifier_and_more.py +23 -0
  202. meta_prn/migrations/0066_alter_historicallosstofollowup_subject_identifier_and_more.py +23 -0
  203. meta_prn/migrations/0067_alter_offschedule_managers_and_more.py +2557 -0
  204. meta_prn/migrations/0068_alter_dmreferral_referral_note_and_more.py +235 -0
  205. meta_prn/migrations/0069_alter_historicaloffstudymedication_singleton_field_and_more.py +37 -0
  206. meta_prn/models/__init__.py +20 -0
  207. meta_prn/models/dm_referral.py +2 -2
  208. meta_prn/models/end_of_study.py +28 -23
  209. meta_prn/models/loss_to_followup.py +8 -10
  210. meta_prn/models/off_study_medication.py +7 -4
  211. meta_prn/models/offschedule.py +4 -4
  212. meta_prn/models/pregnancy_notification.py +3 -5
  213. meta_prn/models/protocol_incident.py +5 -2
  214. meta_prn/models/signals.py +16 -14
  215. meta_prn/models/subject_transfer.py +7 -0
  216. meta_prn/templates/meta_prn/eos/additional_instructions.html +3 -0
  217. meta_prn/templates/meta_prn/offschedule/additional_instructions.html +2 -0
  218. meta_rando/migrations/0001_initial.py +5 -5
  219. meta_rando/migrations/0006_alter_historicalrandomizationlist_allocated_user_and_more.py +130 -0
  220. meta_rando/migrations/0007_spfqlist.py +197 -0
  221. meta_rando/migrations/0008_delete_spfqlist.py +16 -0
  222. meta_rando/models/__init__.py +1 -0
  223. meta_rando/{models.py → models/randomization_list.py} +3 -3
  224. meta_rando/randomizers.py +2 -2
  225. meta_reports/__init__.py +2 -0
  226. meta_reports/admin/__init__.py +16 -0
  227. meta_reports/admin/dbviews/__init__.py +13 -0
  228. meta_reports/admin/dbviews/glucose_summary_admin.py +7 -7
  229. meta_reports/admin/dbviews/imp_substitutions_admin.py +14 -13
  230. meta_reports/admin/dbviews/missing_screening_ogtt_admin/__init__.py +5 -0
  231. meta_reports/admin/dbviews/missing_screening_ogtt_admin/note_model_admin.py +27 -3
  232. meta_reports/admin/dbviews/missing_screening_ogtt_admin/unmanaged_model_admin.py +7 -7
  233. meta_reports/admin/dbviews/on_study_missing_lab_values_admin/__init__.py +2 -0
  234. meta_reports/admin/dbviews/on_study_missing_lab_values_admin/unmanaged_model_admin.py +0 -3
  235. meta_reports/admin/dbviews/on_study_missing_values_admin/__init__.py +2 -0
  236. meta_reports/admin/dbviews/on_study_missing_values_admin/unmanaged_model_admin.py +0 -1
  237. meta_reports/admin/dbviews/patient_history_missing_baseline_cd4_admin.py +9 -9
  238. meta_reports/admin/dbviews/unattended_three_in_row2_admin.py +6 -6
  239. meta_reports/admin/dbviews/unattended_three_in_row_admin.py +5 -5
  240. meta_reports/admin/dbviews/unattended_two_in_row_admin.py +5 -5
  241. meta_reports/admin/endpoints_admin.py +1 -1
  242. meta_reports/admin/endpoints_all_admin.py +0 -1
  243. meta_reports/admin/last_imp_refill_admin.py +33 -36
  244. meta_reports/admin/list_filters.py +3 -3
  245. meta_reports/admin/modeladmin_mixins.py +10 -17
  246. meta_reports/death_report.py +2 -2
  247. meta_reports/forms/__init__.py +2 -0
  248. meta_reports/forms/missing_ogtt_note_form.py +3 -4
  249. meta_reports/management/commands/generate_endpoints.py +5 -4
  250. meta_reports/migrations/0035_historicalmissingogttnote_missingogttnote.py +5 -14
  251. meta_reports/migrations/0054_auto_20250422_2003.py +81 -0
  252. meta_reports/migrations/0055_alter_glucosesummary_table.py +17 -0
  253. meta_reports/migrations/0056_auto_20250422_2214.py +54 -0
  254. meta_reports/migrations/0057_auto_20250422_2224.py +54 -0
  255. meta_reports/migrations/0058_auto_20250422_2232.py +54 -0
  256. meta_reports/migrations/0059_alter_endpoints_created_and_more.py +161 -0
  257. meta_reports/migrations/0060_auto_20250926_0242.py +366 -0
  258. meta_reports/migrations/0061_auto_20251004_0043.py +21 -0
  259. meta_reports/migrations/0062_auto_20251004_0106.py +21 -0
  260. meta_reports/models/__init__.py +17 -0
  261. meta_reports/models/dbviews/__init__.py +14 -0
  262. meta_reports/models/dbviews/glucose_summary/__init__.py +2 -0
  263. meta_reports/models/dbviews/glucose_summary/unmanaged_model.py +15 -3
  264. meta_reports/models/dbviews/glucose_summary/view_definition.py +8 -5
  265. meta_reports/models/dbviews/imp_substitutions/__init__.py +2 -0
  266. meta_reports/models/dbviews/imp_substitutions/unmanaged_model.py +1 -2
  267. meta_reports/models/dbviews/imp_substitutions/view_definition.py +1 -1
  268. meta_reports/models/dbviews/missing_screening_ogtt/__init__.py +2 -0
  269. meta_reports/models/dbviews/missing_screening_ogtt/note_model.py +2 -2
  270. meta_reports/models/dbviews/missing_screening_ogtt/unmanaged_model.py +4 -3
  271. meta_reports/models/dbviews/on_study_missing_lab_values/__init__.py +2 -0
  272. meta_reports/models/dbviews/on_study_missing_lab_values/qa_cases.py +13 -11
  273. meta_reports/models/dbviews/on_study_missing_lab_values/unmanged_model.py +0 -1
  274. meta_reports/models/dbviews/on_study_missing_values/__init__.py +2 -0
  275. meta_reports/models/dbviews/on_study_missing_values/qa_cases.py +19 -1
  276. meta_reports/models/dbviews/on_study_missing_values/unmanged_model.py +0 -1
  277. meta_reports/models/dbviews/patient_history_missing_baseline_cd4/__init__.py +2 -0
  278. meta_reports/models/dbviews/patient_history_missing_baseline_cd4/unmanaged_model.py +0 -1
  279. meta_reports/models/dbviews/unattended_three_in_row/__init__.py +2 -0
  280. meta_reports/models/dbviews/unattended_three_in_row/unmanaged_model.py +0 -1
  281. meta_reports/models/dbviews/unattended_three_in_row2/__init__.py +2 -0
  282. meta_reports/models/dbviews/unattended_three_in_row2/unmanaged_model.py +0 -1
  283. meta_reports/models/dbviews/unattended_two_in_row/__init__.py +2 -0
  284. meta_reports/models/dbviews/unattended_two_in_row/unmanaged_model.py +0 -1
  285. meta_reports/models/endpoints.py +8 -4
  286. meta_reports/models/last_imp_refill.py +2 -3
  287. meta_reports/pdf_report.py +2 -2
  288. meta_reports/tasks.py +4 -3
  289. meta_reports/templates/meta_reports/columns/subject_identifier_column.html +1 -1
  290. meta_reports/templates/meta_reports/endpoints_all_change_list_note.html +1 -1
  291. meta_reports/templates/meta_reports/endpoints_change_list_note.html +1 -1
  292. meta_reports/templates/meta_reports/last_imp_refill/changelist_note.html +13 -0
  293. meta_screening/admin/__init__.py +8 -0
  294. meta_screening/admin/fieldsets.py +13 -15
  295. meta_screening/admin/list_filters.py +7 -5
  296. meta_screening/admin/screening_part_one_admin.py +1 -3
  297. meta_screening/admin/screening_part_three_admin.py +2 -3
  298. meta_screening/admin/screening_part_two_admin.py +7 -10
  299. meta_screening/admin/subject_refusal_admin.py +5 -3
  300. meta_screening/admin/subject_screening_admin.py +21 -10
  301. meta_screening/baker_recipes.py +18 -10
  302. meta_screening/calculators.py +1 -1
  303. meta_screening/choices.py +1 -1
  304. meta_screening/constants.py +1 -1
  305. meta_screening/eligibility/__init__.py +9 -0
  306. meta_screening/eligibility/eligibility.py +21 -14
  307. meta_screening/eligibility/eligibility_part_one.py +1 -1
  308. meta_screening/eligibility/eligibility_part_three/__init__.py +2 -0
  309. meta_screening/eligibility/eligibility_part_three/base_eligibility_part_three.py +68 -49
  310. meta_screening/eligibility/eligibility_part_three/eligibility_part_three_phase_three.py +14 -15
  311. meta_screening/eligibility/eligibility_part_two.py +1 -1
  312. meta_screening/form_validators/__init__.py +8 -0
  313. meta_screening/form_validators/screening_part_one.py +1 -1
  314. meta_screening/form_validators/screening_part_three.py +6 -2
  315. meta_screening/form_validators/screening_part_two.py +1 -1
  316. meta_screening/form_validators/subject_refusal.py +1 -1
  317. meta_screening/forms/__init__.py +20 -0
  318. meta_screening/forms/field_lists.py +16 -18
  319. meta_screening/forms/screening_part_one_form.py +2 -2
  320. meta_screening/forms/screening_part_three_form.py +5 -3
  321. meta_screening/forms/screening_part_two_form.py +1 -5
  322. meta_screening/forms/subject_refusal_form.py +0 -4
  323. meta_screening/forms/subject_screening_form.py +0 -4
  324. meta_screening/migrations/0001_initial.py +15 -15
  325. meta_screening/migrations/0010_auto_20191106_0828.py +5 -5
  326. meta_screening/migrations/0012_auto_20191107_0427.py +1 -1
  327. meta_screening/migrations/0068_alter_historicalscreeningpartone_acute_condition_and_more.py +1579 -0
  328. meta_screening/model_mixins/__init__.py +8 -0
  329. meta_screening/model_mixins/calculated_model_mixin.py +2 -2
  330. meta_screening/model_mixins/creatinine_fields_model_mixin.py +1 -1
  331. meta_screening/model_mixins/eligibility_model_mixin.py +6 -4
  332. meta_screening/model_mixins/part_one_fields_model_mixin.py +16 -19
  333. meta_screening/model_mixins/part_three_fields_model_mixin.py +6 -7
  334. meta_screening/model_mixins/part_two_fields_model_mixin.py +19 -17
  335. meta_screening/models/__init__.py +9 -0
  336. meta_screening/models/icp_referral.py +5 -5
  337. meta_screening/models/proxy_models.py +1 -1
  338. meta_screening/models/signals.py +10 -11
  339. meta_screening/models/subject_refusal.py +1 -1
  340. meta_screening/models/subject_screening.py +2 -4
  341. meta_subject/action_items.py +18 -14
  342. meta_subject/admin/__init__.py +42 -0
  343. meta_subject/admin/birth_outcome_admin.py +7 -9
  344. meta_subject/admin/blood_results/__init__.py +9 -0
  345. meta_subject/admin/blood_results/blood_results_fbc_admin.py +1 -1
  346. meta_subject/admin/blood_results/blood_results_hba1c_admin.py +1 -1
  347. meta_subject/admin/blood_results/blood_results_ins_admin.py +1 -1
  348. meta_subject/admin/blood_results/blood_results_lft_admin.py +1 -1
  349. meta_subject/admin/blood_results/blood_results_lipids_admin.py +1 -1
  350. meta_subject/admin/blood_results/blood_results_rft_admin.py +3 -5
  351. meta_subject/admin/complications_glycemia_admin.py +1 -1
  352. meta_subject/admin/delivery_admin.py +8 -11
  353. meta_subject/admin/diabetes/__init__.py +2 -0
  354. meta_subject/admin/diabetes/dm_endpoint_admin.py +2 -2
  355. meta_subject/admin/diabetes/dm_followup_admin.py +3 -2
  356. meta_subject/admin/egfr_drop_notification_admin.py +1 -1
  357. meta_subject/admin/fields.py +5 -5
  358. meta_subject/admin/fieldsets.py +5 -5
  359. meta_subject/admin/followup_examination_admin.py +11 -9
  360. meta_subject/admin/followup_vitals_admin.py +31 -6
  361. meta_subject/admin/glucose_admin.py +4 -8
  362. meta_subject/admin/glucose_fbg_admin.py +18 -11
  363. meta_subject/admin/health_economics/__init__.py +2 -0
  364. meta_subject/admin/health_economics/health_economics_simple_admin.py +1 -1
  365. meta_subject/admin/health_economics/health_economics_update_admin.py +1 -1
  366. meta_subject/admin/hepatitis_test_admin.py +1 -1
  367. meta_subject/admin/hiv_exit_review_admin.py +55 -0
  368. meta_subject/admin/list_filters.py +5 -5
  369. meta_subject/admin/mnsi_admin.py +7 -5
  370. meta_subject/admin/next_appointment_admin.py +19 -0
  371. meta_subject/admin/other_arv_regimens_admin.py +3 -3
  372. meta_subject/admin/patient_history_admin.py +4 -4
  373. meta_subject/admin/physical_exam_admin.py +1 -1
  374. meta_subject/admin/pregnancy_update_admin.py +1 -1
  375. meta_subject/admin/study_medication_admin.py +8 -15
  376. meta_subject/admin/subject_requisition_admin.py +2 -2
  377. meta_subject/admin/subject_visit_admin.py +1 -1
  378. meta_subject/admin/subject_visit_missed_admin.py +1 -1
  379. meta_subject/admin/urine_dipstick_test_admin.py +1 -1
  380. meta_subject/admin/urine_pregnancy_admin.py +1 -1
  381. meta_subject/baker_recipes.py +15 -15
  382. meta_subject/choices.py +4 -3
  383. meta_subject/form_validators/__init__.py +15 -0
  384. meta_subject/form_validators/delivery_form_validator.py +3 -3
  385. meta_subject/form_validators/dm_endpoint_form_validator.py +3 -1
  386. meta_subject/form_validators/dm_followup_form_validator.py +8 -7
  387. meta_subject/form_validators/egfr_drop_notification_form_validator.py +1 -1
  388. meta_subject/form_validators/followup_examination_form_validator.py +1 -1
  389. meta_subject/form_validators/glucose_fbg_form_validator.py +76 -0
  390. meta_subject/form_validators/glucose_form_validator.py +10 -67
  391. meta_subject/form_validators/hiv_exit_review_form_validator.py +18 -0
  392. meta_subject/form_validators/mixins.py +95 -0
  393. meta_subject/forms/__init__.py +44 -0
  394. meta_subject/forms/blood_results/__init__.py +9 -0
  395. meta_subject/forms/blood_results/blood_results_hba1c_form.py +1 -1
  396. meta_subject/forms/blood_results/blood_results_rft_form.py +60 -4
  397. meta_subject/forms/delivery_form.py +2 -0
  398. meta_subject/forms/diabetes/__init__.py +2 -0
  399. meta_subject/forms/diabetes/dm_followup_form.py +2 -2
  400. meta_subject/forms/followup_vitals_form.py +27 -1
  401. meta_subject/forms/glucose_fbg_form.py +1 -46
  402. meta_subject/forms/health_economics/__init__.py +2 -0
  403. meta_subject/forms/hepatitis_test_form.py +1 -1
  404. meta_subject/forms/hiv_exit_review_form.py +13 -0
  405. meta_subject/forms/mixins.py +1 -1
  406. meta_subject/forms/next_appointment_form.py +36 -0
  407. meta_subject/forms/other_arv_regimens_form.py +1 -1
  408. meta_subject/forms/patient_history_form.py +1 -1
  409. meta_subject/forms/physical_exam_form.py +1 -1
  410. meta_subject/forms/pregnancy_update_form.py +1 -1
  411. meta_subject/forms/slider_widget.py +1 -1
  412. meta_subject/forms/study_medication_form.py +18 -12
  413. meta_subject/forms/subject_requisition_form.py +1 -1
  414. meta_subject/forms/subject_visit_missed_form.py +1 -1
  415. meta_subject/forms/urine_dipstick_test_form.py +1 -1
  416. meta_subject/forms/urine_pregnancy_form.py +1 -1
  417. meta_subject/management/commands/create_missing_refills.py +3 -3
  418. meta_subject/management/commands/create_missing_rx.py +2 -2
  419. meta_subject/management/commands/missed.py +20 -23
  420. meta_subject/metadata_rules/__init__.py +2 -0
  421. meta_subject/metadata_rules/metadata_rules.py +14 -0
  422. meta_subject/metadata_rules/predicates.py +44 -25
  423. meta_subject/migrations/0001_initial.py +61 -61
  424. meta_subject/migrations/0002_auto_20191021_0353.py +5 -5
  425. meta_subject/migrations/0012_auto_20200118_2334.py +5 -5
  426. meta_subject/migrations/0014_auto_20200120_1622.py +5 -5
  427. meta_subject/migrations/0018_coronakap_historicalcoronakap.py +5 -5
  428. meta_subject/migrations/0033_auto_20200516_2356.py +5 -5
  429. meta_subject/migrations/0038_auto_20200520_0020.py +5 -5
  430. meta_subject/migrations/0040_auto_20200527_2155.py +1 -1
  431. meta_subject/migrations/0045_auto_20200530_1801.py +1 -1
  432. meta_subject/migrations/0051_auto_20200617_2117.py +5 -5
  433. meta_subject/migrations/0063_auto_20210715_0337.py +5 -5
  434. meta_subject/migrations/0066_auto_20210721_0335.py +9 -9
  435. meta_subject/migrations/0067_auto_20210726_0340.py +5 -5
  436. meta_subject/migrations/0068_auto_20210728_1809.py +5 -5
  437. meta_subject/migrations/0072_auto_20210805_1545.py +7 -7
  438. meta_subject/migrations/0073_auto_20210809_0055.py +5 -5
  439. meta_subject/migrations/0077_auto_20210809_2323.py +3 -3
  440. meta_subject/migrations/0082_auto_20210823_1612.py +3 -3
  441. meta_subject/migrations/0083_auto_20210823_1620.py +3 -3
  442. meta_subject/migrations/0088_auto_20210924_0027.py +5 -5
  443. meta_subject/migrations/0090_auto_20210924_0424.py +5 -5
  444. meta_subject/migrations/0093_auto_20211117_0352.py +5 -5
  445. meta_subject/migrations/0095_auto_20220128_1719.py +5 -5
  446. meta_subject/migrations/0098_auto_20220309_2106.py +5 -5
  447. meta_subject/migrations/0101_auto_20220316_2147.py +13 -13
  448. meta_subject/migrations/0107_auto_20220415_0043.py +1 -1
  449. meta_subject/migrations/0115_historicalegfrnotification_egfrnotification.py +5 -13
  450. meta_subject/migrations/0128_auto_20220720_0055.py +1 -1
  451. meta_subject/migrations/0131_auto_20220722_0411.py +1 -1
  452. meta_subject/migrations/0135_auto_20220722_2212.py +2 -1
  453. meta_subject/migrations/0164_dmreferralfollowup_historicaldmreferralfollowup.py +5 -5
  454. meta_subject/migrations/0172_remove_historicalbloodresultsglu_action_item_and_more.py +1 -2
  455. meta_subject/migrations/0177_alter_bloodresultslft_alp_value_and_more.py +1 -2
  456. meta_subject/migrations/0178_historicalhealtheconomicsupdate_and_more.py +5 -14
  457. meta_subject/migrations/0186_healtheconomicsupdate_singleton_field_and_more.py +1 -2
  458. meta_subject/migrations/0187_dmdiagnosis_historicaldmdiagnosis_dmdxresult_and_more.py +5 -14
  459. meta_subject/migrations/0188_historicaldmdxresult_dmdxresult.py +5 -14
  460. meta_subject/migrations/0199_auto_20240516_0247.py +1 -1
  461. meta_subject/migrations/0209_remove_historicaldmdxresult_dm_diagnosis_and_more.py +1 -2
  462. meta_subject/migrations/0212_auto_20240827_2222.py +1 -1
  463. meta_subject/migrations/0216_historicalnextappointment_nextappointment.py +553 -0
  464. meta_subject/migrations/0217_alter_historicalnextappointment_appt_datetime_and_more.py +42 -0
  465. meta_subject/migrations/0218_alter_historicalnextappointment_appt_date_and_more.py +53 -0
  466. meta_subject/migrations/0219_remove_historicalnextappointment_allow_create_interim_and_more.py +92 -0
  467. meta_subject/migrations/0220_historicalbloodresultsgludummy_bloodresultsgludummy.py +825 -0
  468. meta_subject/migrations/0221_auto_20250402_1913.py +42 -0
  469. meta_subject/migrations/0222_alter_historicalstudymedication_stock_codes_and_more.py +46 -0
  470. meta_subject/migrations/0223_bloodresultsfbc_errors_bloodresultsgludummy_errors_and_more.py +83 -0
  471. meta_subject/migrations/0224_bloodresultsfbc_abnormal_summary_and_more.py +153 -0
  472. meta_subject/migrations/0225_followupvitals_waist_circumference_and_more.py +46 -0
  473. meta_subject/migrations/0226_followupvitals_waist_circumference_comment_and_more.py +97 -0
  474. meta_subject/migrations/0227_alter_followupvitals_waist_circumference_comment_and_more.py +97 -0
  475. meta_subject/migrations/0228_bloodresultshba1c_hba1c_datetime_and_more.py +2518 -0
  476. meta_subject/migrations/0229_alter_glucosefbg_consent_model_and_more.py +1918 -0
  477. meta_subject/migrations/0230_alter_historicaldelivery_action_identifier_and_more.py +1733 -0
  478. meta_subject/migrations/0231_alter_historicalmedicationadherence_consent_model_and_more.py +2054 -0
  479. meta_subject/migrations/0232_alter_patienthistory_concomitant_conditions_and_more.py +1170 -0
  480. meta_subject/migrations/0233_historicalspfq_spfq.py +1066 -0
  481. meta_subject/migrations/0234_remove_spfq_site_remove_spfq_subject_visit_and_more.py +27 -0
  482. meta_subject/migrations/0235_glucosefbg_endpoint_today_and_more.py +606 -0
  483. meta_subject/migrations/0236_alter_historicalhivexitreview_other_current_arv_regimen_and_more.py +58 -0
  484. meta_subject/migrations/0237_historicalhivexitreview_singleton_field_and_more.py +68 -0
  485. meta_subject/migrations/0238_historicalhivexitreview_available_and_more.py +88 -0
  486. meta_subject/model_mixins/__init__.py +10 -0
  487. meta_subject/model_mixins/arv_history_model_mixin.py +3 -44
  488. meta_subject/model_mixins/arv_review_model_mixin.py +53 -0
  489. meta_subject/model_mixins/search_slug_model_mixin.py +1 -2
  490. meta_subject/model_mixins/vitals_fields_model_mixin.py +33 -0
  491. meta_subject/models/__init__.py +52 -0
  492. meta_subject/models/birth_outcomes.py +3 -3
  493. meta_subject/models/blood_results/__init__.py +11 -0
  494. meta_subject/models/blood_results/blood_results_glu.py +29 -0
  495. meta_subject/models/blood_results/blood_results_hba1c.py +0 -1
  496. meta_subject/models/blood_results/blood_results_ins.py +0 -1
  497. meta_subject/models/blood_results/blood_results_lft.py +0 -1
  498. meta_subject/models/delivery.py +4 -6
  499. meta_subject/models/diabetes/__init__.py +2 -0
  500. meta_subject/models/diabetes/dm_endpoint.py +5 -5
  501. meta_subject/models/diabetes/dm_followup.py +7 -8
  502. meta_subject/models/diet_and_lifestyle.py +2 -2
  503. meta_subject/models/followup_examination.py +12 -14
  504. meta_subject/models/glucose.py +5 -5
  505. meta_subject/models/glucose_fbg.py +17 -4
  506. meta_subject/models/health_economics/__init__.py +2 -0
  507. meta_subject/models/health_economics/health_economics.py +8 -8
  508. meta_subject/models/health_economics/health_economics_simple.py +2 -2
  509. meta_subject/models/health_economics/health_economics_update.py +3 -2
  510. meta_subject/models/hepatitis_test.py +2 -2
  511. meta_subject/models/hiv_exit_review.py +44 -0
  512. meta_subject/models/next_appointment.py +15 -0
  513. meta_subject/models/other_arv_regimens_detail.py +1 -1
  514. meta_subject/models/patient_history.py +6 -7
  515. meta_subject/models/physical_exam.py +2 -2
  516. meta_subject/models/pregnancy_update.py +1 -1
  517. meta_subject/models/signals.py +15 -13
  518. meta_subject/models/subject_visit.py +2 -2
  519. meta_subject/models/todo.txt +1 -1
  520. meta_subject/models/urine_dipstick_test.py +2 -2
  521. meta_subject/models/urine_pregnancy.py +1 -1
  522. meta_subject/static/meta_subject/slider.css +1 -1
  523. meta_subject/templates/meta_subject/endpoint_review_instructions.html +1 -1
  524. meta_subject/templates/meta_subject/widgets/slider.html +0 -1
  525. meta_visit_schedule/visit_schedules/__init__.py +2 -0
  526. meta_visit_schedule/visit_schedules/phase_three/__init__.py +2 -0
  527. meta_visit_schedule/visit_schedules/phase_three/crfs.py +34 -1
  528. meta_visit_schedule/visit_schedules/phase_three/schedule.py +4 -4
  529. meta_visit_schedule/visit_schedules/phase_three/schedule_dm_referral.py +1 -2
  530. meta_visit_schedule/visit_schedules/phase_three/schedule_pregnancy.py +2 -3
  531. meta_ae/tests/holidays.csv +0 -15
  532. meta_ae/tests/tests/test_actions.py +0 -127
  533. meta_ae/tests/urls.py +0 -10
  534. meta_analytics/dataframes/enrolled/__init__.py +0 -1
  535. meta_analytics/dataframes/enrolled/get_glucose_df.py +0 -122
  536. meta_analytics/tests/__init__.py +0 -0
  537. meta_analytics/tests/test_endpoints_by_date.py +0 -94
  538. meta_consent/tests/__init__.py +0 -0
  539. meta_consent/tests/holidays.csv +0 -15
  540. meta_consent/tests/tests/__init__.py +0 -0
  541. meta_consent/tests/tests/test_form_validators.py +0 -110
  542. meta_consent/tests/tests/test_subject_consent.py +0 -10
  543. meta_consent/tests/urls.py +0 -17
  544. meta_dashboard/templates/meta_dashboard/bootstrap3/subject/dashboard.html +0 -11
  545. meta_dashboard/tests/__init__.py +0 -0
  546. meta_dashboard/tests/admin.py +0 -22
  547. meta_dashboard/tests/holidays.csv +0 -15
  548. meta_dashboard/tests/tests/__init__.py +0 -0
  549. meta_dashboard/tests/urls.py +0 -55
  550. meta_edc/tests/__init__.py +0 -0
  551. meta_edc/tests/tests/__init__.py +0 -0
  552. meta_edc/tests/tests/test_endpoints.py +0 -554
  553. meta_edc-0.3.39.dist-info/AUTHORS +0 -0
  554. meta_edc-0.3.39.dist-info/METADATA +0 -766
  555. meta_edc-0.3.39.dist-info/WHEEL +0 -5
  556. meta_edc-0.3.39.dist-info/top_level.txt +0 -20
  557. meta_labs/tests/__init__.py +0 -0
  558. meta_labs/tests/test_labs.py +0 -27
  559. meta_labs/tests/test_reportables.py +0 -16
  560. meta_labs/tests/urls.py +0 -4
  561. meta_lists/tests/__init__.py +0 -0
  562. meta_lists/tests/test_lists.py +0 -8
  563. meta_pharmacy/admin/actions.py +0 -38
  564. meta_prn/tests/__init__.py +0 -0
  565. meta_prn/tests/tests/__init__.py +0 -0
  566. meta_prn/tests/tests/test_actions.py +0 -97
  567. meta_prn/tests/tests/test_dm_referral.py +0 -206
  568. meta_prn/tests/tests/test_manager_order.py +0 -14
  569. meta_prn/tests/tests/test_pregnancy_notification.py +0 -93
  570. meta_prn/tests/urls.py +0 -10
  571. meta_rando/tests/__init__.py +0 -0
  572. meta_rando/tests/tests/__init__.py +0 -0
  573. meta_rando/tests/tests/test_randomizers.py +0 -57
  574. meta_reports/tests/__init__.py +0 -0
  575. meta_reports/tests/test_reports.py +0 -35
  576. meta_reports/tests/test_sql_gen.py +0 -5
  577. meta_reports/tests/urls.py +0 -4
  578. meta_screening/offline_models.py +0 -3
  579. meta_screening/tests/__init__.py +0 -0
  580. meta_screening/tests/holidays.csv +0 -15
  581. meta_screening/tests/meta_test_case_mixin.py +0 -216
  582. meta_screening/tests/options.py +0 -127
  583. meta_screening/tests/tests/__init__.py +0 -0
  584. meta_screening/tests/tests/test_forms.py +0 -397
  585. meta_screening/tests/tests/test_screening_part_one.py +0 -108
  586. meta_screening/tests/tests/test_screening_part_three.py +0 -436
  587. meta_screening/tests/tests/test_screening_part_two.py +0 -84
  588. meta_sites/tests/__init__.py +0 -0
  589. meta_sites/tests/test_sites.py +0 -12
  590. meta_sites/tests/urls.py +0 -4
  591. meta_stats/__init__.py +0 -0
  592. meta_stats/incidence.py +0 -16
  593. meta_stats/models.py +0 -0
  594. meta_stats/tests/__init__.py +0 -0
  595. meta_stats/tests/tests/__init__.py +0 -0
  596. meta_stats/tests/tests/test_incidence.py +0 -10
  597. meta_subject/tests/__init__.py +0 -0
  598. meta_subject/tests/holidays.csv +0 -15
  599. meta_subject/tests/tests/__init__.py +0 -0
  600. meta_subject/tests/tests/test_egfr.py +0 -234
  601. meta_subject/tests/tests/test_fixes.py +0 -64
  602. meta_subject/tests/tests/test_followup.py +0 -52
  603. meta_subject/tests/tests/test_manager_order.py +0 -11
  604. meta_subject/tests/tests/test_medication_adherence.py +0 -75
  605. meta_subject/tests/tests/test_metadata_rules.py +0 -135
  606. meta_subject/tests/tests/test_mnsi.py +0 -317
  607. meta_subject/tests/tests/test_patient_history_form.py +0 -74
  608. meta_subject/tests/tests/test_physical_exam.py +0 -84
  609. meta_subject/tests/tests/test_sf12.py +0 -173
  610. meta_subject/tests/tests/test_study_medication.py +0 -230
  611. meta_subject/tests/urls.py +0 -24
  612. meta_visit_schedule/tests/__init__.py +0 -0
  613. meta_visit_schedule/tests/tests/__init__.py +0 -0
  614. meta_visit_schedule/tests/tests/test_schedule.py +0 -181
  615. meta_visit_schedule/tests/urls.py +0 -4
  616. tests/__init__.py +0 -0
  617. tests/etc/randomization_list.csv +0 -241
  618. tests/etc/randomization_list_phase_three.csv +0 -241
  619. tests/etc/user-aes-local.key +0 -0
  620. tests/etc/user-aes-restricted.key +0 -1
  621. tests/etc/user-rsa-local-private.pem +0 -27
  622. tests/etc/user-rsa-local-public.pem +0 -9
  623. tests/etc/user-rsa-restricted-private.pem +0 -27
  624. tests/etc/user-rsa-restricted-public.pem +0 -9
  625. tests/etc/user-salt-local.key +0 -0
  626. tests/etc/user-salt-restricted.key +0 -0
  627. tests/holidays.csv +0 -15
  628. tests/test_settings.py +0 -186
  629. /meta_ae/templates/meta_ae/{bootstrap3/ae_initial_description.html → aeinitial_description.html} +0 -0
  630. /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/add_consent_button.html +0 -0
  631. /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/dashboard_button.html +0 -0
  632. /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/refusal_button.html +0 -0
  633. /meta_dashboard/templates/meta_dashboard/{bootstrap3/screening → screening}/listboard.html +0 -0
  634. /meta_dashboard/templates/meta_dashboard/{bootstrap3/subject → subject}/listboard.html +0 -0
  635. {meta_edc-0.3.39.dist-info → meta_edc-1.4.0.dist-info/licenses}/LICENSE +0 -0
  636. /meta_ae/tests/__init__.py → /meta_subject/management/__init__py.py +0 -0
  637. /meta_ae/tests/tests/__init__.py → /meta_subject/management/commands/__init__py.py +0 -0
@@ -1,44 +1,28 @@
1
1
  import numpy as np
2
2
  import pandas as pd
3
+ from clinicedc_constants import NULL_STRING, YES
3
4
  from django.apps import apps as django_apps
4
- from edc_constants.constants import NO, YES
5
- from edc_pdutils.dataframes import (
6
- get_crf,
7
- get_eos,
8
- get_subject_consent,
9
- get_subject_visit,
10
- )
11
- from edc_utils import get_utcnow
5
+ from django.utils import timezone
12
6
 
13
7
  from ..constants import (
14
8
  CASE_EOS,
15
- CASE_FBG_ONLY,
9
+ CASE_FBG_VERY_HIGH,
16
10
  CASE_FBGS_WITH_FIRST_OGTT,
17
11
  CASE_FBGS_WITH_SECOND_OGTT,
18
12
  CASE_OGTT,
13
+ FBG_BEYOND_THRESHOLD,
19
14
  endpoint_cases,
20
15
  endpoint_columns,
21
16
  )
17
+ from ..get_glucose_df import get_glucose_df
22
18
  from ..utils import (
23
19
  get_empty_endpoint_df,
24
20
  get_test_string,
25
21
  get_unique_subject_identifiers,
26
- get_unique_visit_codes,
27
22
  )
28
23
  from .endpoint_by_date import EndpointByDate
29
24
 
30
25
 
31
- def calculate_fasting_hrs(df: pd.DataFrame):
32
- df.loc[(df["fasting"] == NO), "fasting_duration_delta"] = pd.NaT
33
- if df.empty:
34
- df["fasting_hrs"] = np.nan
35
- else:
36
- df["fasting_hrs"] = df["fasting_duration_delta"].apply(
37
- lambda s: np.nan if pd.isna(s) else s.total_seconds() / 3600
38
- )
39
- return df
40
-
41
-
42
26
  class GlucoseEndpointsByDate:
43
27
  """
44
28
  Usage:
@@ -58,10 +42,11 @@ class GlucoseEndpointsByDate:
58
42
  """
59
43
 
60
44
  fbg_threshhold = 7.0
45
+ fbg_beyond_threshold = FBG_BEYOND_THRESHOLD
61
46
  ogtt_threshhold = 11.1
62
47
  endpoint_cls = EndpointByDate
63
- keep_cols = [
64
- "fasting",
48
+ keep_cols = [ # noqa: RUF012
49
+ "fasted",
65
50
  "fasting_hrs",
66
51
  "fbg_value",
67
52
  "fbg_units",
@@ -91,217 +76,86 @@ class GlucoseEndpointsByDate:
91
76
  CASE_OGTT,
92
77
  CASE_FBGS_WITH_FIRST_OGTT,
93
78
  CASE_FBGS_WITH_SECOND_OGTT,
79
+ CASE_FBG_VERY_HIGH,
94
80
  CASE_EOS,
95
81
  ]
96
82
  self.endpoint_cases = {k: v for k, v in endpoint_cases.items() if k in self.case_list}
97
83
 
98
- # merge two model DFs
99
- if self.glucose_fbg_ogtt_df.empty:
100
- self.df = self.glucose_fbg_df.copy()
101
- self.df[["ogtt_value", "ogtt_units"]] = np.nan
102
- self.df[["ogtt_datetime"]] = pd.NaT
103
- elif self.glucose_fbg_df.empty:
104
- self.df = self.glucose_fbg_ogtt_df.copy()
105
- else:
106
- self.df = self.glucose_fbg_ogtt_df.merge(
107
- self.glucose_fbg_df,
108
- on=["subject_visit_id"],
109
- how="outer",
110
- indicator=True,
111
- suffixes=("", "_y"),
112
- )
113
- # cast as ...
114
- for col in ["fasting_hrs", "fbg_value"]:
115
- self.df[col] = self.df[col].astype("float64")
116
- if f"{col}_y" in self.df.columns:
117
- self.df[f"{col}_y"] = self.df[f"{col}_y"].astype("float64")
118
- for col in ["fasting", "fbg_units", "source"]:
119
- self.df[col] = self.df[col].astype("object")
120
- if f"{col}_y" in self.df.columns:
121
- self.df[f"{col}_y"] = self.df[f"{col}_y"].astype("object")
122
- self.df = self.df.drop(
123
- columns=[col for col in self.df.columns if col.endswith("_y") or col == "_merge"]
124
- )
125
- self.df = self.df.reset_index(drop=True)
126
-
127
- # merge w/ subject_visit
128
- subject_visit_df = get_subject_visit(
129
- "meta_subject.subjectvisit", subject_identifiers=self.subject_identifiers
130
- )
131
- self.df = subject_visit_df.merge(
132
- self.df, on=["subject_visit_id"], how="left", suffixes=("", "_y")
133
- )
134
- self.df = self.df[[col for col in self.keep_cols]]
135
- self.df = self.df.reset_index(drop=True)
136
-
137
- # pivot right_only cols
138
- cols = [
139
- "fasting",
140
- "fasting_hrs",
141
- "fbg_value",
142
- "fbg_units",
143
- "fbg_datetime",
144
- "source",
145
- "report_datetime",
146
- ]
147
- for col in cols:
148
- if f"{col}_y" in self.df.columns and not self.df[f"{col}_y"].isnull().all():
149
- self.df.loc[
150
- (self.df["_merge"].isin(["both", "right_only"])) & (self.df[col].isna()),
151
- col,
152
- ] = self.df[f"{col}_y"]
153
- # if fbg_datetime still null, use visit datetime
154
- if self.df["fbg_datetime"].isnull().all():
155
- self["fbg_datetime"] = self.df["visit_datetime"]
156
- else:
157
- self.df.loc[(self.df["fbg_datetime"].isna()), "fbg_datetime"] = self.df[
158
- "visit_datetime"
159
- ]
160
- self.df = self.df.drop(
161
- columns=[col for col in self.df.columns if col.endswith("_y") or col == "_merge"]
162
- )
163
- self.df = self.df.reset_index(drop=True)
164
-
165
- self.merge_with_consent()
166
- self.merge_with_eos()
167
-
168
- self.add_calculated_days_from_baseline_to_event_columns()
84
+ self.df = get_glucose_df(subject_identifiers=self.subject_identifiers).copy()
169
85
 
170
86
  # label rows by type of glu tests (ones with value)
171
87
  self.df["test"] = self.df.apply(get_test_string, axis=1)
172
- self.df = self.df.reset_index(drop=True)
173
-
174
- self.visit_codes_df = get_unique_visit_codes(self.df)
175
- self.subject_identifiers_df = get_unique_subject_identifiers(self.df)
176
-
177
- self.df = self.df.sort_values(by=["subject_identifier", "fbg_datetime"])
178
- self.df = self.df.reset_index(drop=True)
179
88
 
89
+ self.df = (
90
+ self.df.query("not (fbg_value.isna() and ogtt_value.isna())")
91
+ .sort_values(by=["subject_identifier", "fbg_datetime"])
92
+ .reset_index(drop=True)
93
+ )
180
94
  self.working_df = self.df.copy()
181
95
  self.working_df["endpoint"] = 0
182
96
  self.endpoint_df = get_empty_endpoint_df()
183
97
 
184
98
  def run(self):
185
- self.pre_check_endpoint()
186
- for index, row in self.subject_identifiers_df.iterrows():
187
- subject_df = self.get_subject_df(row["subject_identifier"])
188
- subject_df = self.check_endpoint_by_fbg_for_subject(
189
- subject_df, case_list=[CASE_FBGS_WITH_FIRST_OGTT, CASE_FBGS_WITH_SECOND_OGTT]
190
- )
99
+ self.process_by_ogtt_only()
100
+ self.process_by_fbg_only()
101
+ subject_identifiers_df = get_unique_subject_identifiers(self.df)
102
+ for _, row in subject_identifiers_df.iterrows():
103
+ subject_df = self.endpoint_cls(
104
+ subject_df=self.get_subject_df(row["subject_identifier"]),
105
+ fbg_threshhold=self.fbg_threshhold,
106
+ ogtt_threshhold=self.ogtt_threshhold,
107
+ ).subject_df
191
108
  if len(subject_df.loc[subject_df["endpoint"] == 1]) == 1:
192
109
  self.append_subject_to_endpoint_df(subject_df)
193
110
  self.remove_subject_from_working_df(row)
194
-
195
- if CASE_FBG_ONLY in self.endpoint_cases:
196
- for index, row in self.subject_identifiers_df.iterrows():
197
- subject_df = self.get_subject_df(row["subject_identifier"])
198
- subject_df = self.check_endpoint_by_fbg_for_subject(
199
- subject_df, case_list=[CASE_FBG_ONLY]
200
- )
201
- if len(subject_df.loc[subject_df["endpoint"] == 1]) == 1:
202
- self.append_subject_to_endpoint_df(subject_df)
203
- self.remove_subject_from_working_df(row)
204
-
205
111
  self.post_check_endpoint()
206
112
  self.merge_with_final_endpoints()
207
113
 
208
- @property
209
- def glucose_fbg_df(self) -> pd.DataFrame:
210
- """Returns a prepared Dataframe of CRF
211
- meta_subject.glucosefbg.
114
+ def process_by_fbg_only(self):
115
+ """Flag subjects that meta endpoint by hitting the absurd FBG"""
116
+ subject_endpoint_df = self.working_df.loc[
117
+ (self.working_df["fbg_value"] >= self.fbg_beyond_threshold)
118
+ # & (self.working_df["fasted"] == YES)
119
+ ].copy()
212
120
 
213
- Note: meta_subject.glucosefbg has only FBG measures.
214
- """
215
- if self._glucose_fbg_df.empty:
216
- df = get_crf(
217
- model="meta_subject.glucosefbg",
218
- subject_identifiers=self.subject_identifiers,
219
- # subject_visit_model="meta_subject.subjectvisit",
220
- )
221
- df["source"] = "meta_subject.glucosefbg"
222
- df.rename(columns={"fbg_fasting": "fasting"}, inplace=True)
223
- df.loc[(df["fasting"] == "fasting"), "fasting"] = YES
224
- df.loc[(df["fasting"] == "non_fasting"), "fasting"] = NO
225
- df = calculate_fasting_hrs(df)
226
- # df = df[[col for col in self.keep_cols if not col.startswith("ogtt")]]
227
- df = df.reset_index(drop=True)
228
- self._glucose_fbg_df = df
229
- return self._glucose_fbg_df
230
-
231
- @property
232
- def glucose_fbg_ogtt_df(self):
233
- """Returns a prepared Dataframe of CRF meta_subject.glucose.
234
-
235
- Note: meta_subject.glucose has FBG and OGTT measures.
236
- """
237
- if self._glucose_fbg_ogtt_df.empty:
238
- df = get_crf(
239
- model="meta_subject.glucose",
240
- subject_identifiers=self.subject_identifiers,
241
- # subject_visit_model="meta_subject.subjectvisit",
242
- )
243
- df["source"] = "meta_subject.glucose"
244
- df = calculate_fasting_hrs(df)
245
- # df = df[self.keep_cols]
246
- df = df.reset_index(drop=True)
247
- self._glucose_fbg_ogtt_df = df
248
- return self._glucose_fbg_ogtt_df
249
-
250
- def merge_with_consent(self):
251
- """Merge in consent DF."""
252
- df_consent = get_subject_consent(
253
- "meta_consent.subjectconsent", subject_identifiers=self.subject_identifiers
254
- )
255
- self.df = pd.merge(
256
- self.df, df_consent, on="subject_identifier", how="left", suffixes=("", "_y")
121
+ subject_endpoint_df = (
122
+ subject_endpoint_df.sort_values(by=["subject_identifier", "fbg_datetime"])
123
+ .reset_index(drop=True)
124
+ .drop_duplicates(subset=["subject_identifier"], keep="first")
125
+ .reset_index(drop=True)
257
126
  )
258
- self.df = self.df.sort_values(by=["subject_identifier", "fbg_datetime"])
259
- self.df = self.df.reset_index(drop=True)
260
-
261
- def merge_with_eos(self):
262
- """Merge in EoS DF.
127
+ if not subject_endpoint_df.empty:
128
+ # flag the selected endpoint rows as endpoints
129
+ subject_endpoint_df["endpoint"] = 1
130
+ subject_endpoint_df["endpoint_label"] = self.endpoint_cases[CASE_FBG_VERY_HIGH]
131
+ subject_endpoint_df["endpoint_type"] = CASE_FBG_VERY_HIGH
132
+ subject_endpoint_df["interval_in_days"] = np.nan
263
133
 
264
- Drops patients who were taken off study by late exclusion.
265
- """
266
- df_eos = get_eos("meta_prn.endofstudy", subject_identifiers=self.subject_identifiers)
267
- df_eos = df_eos[
268
- df_eos["offstudy_reason"]
269
- != (
270
- "Patient fulfilled late exclusion criteria (due to abnormal blood "
271
- "values or raised blood pressure at enrolment"
272
- )
273
- ]
274
- self.df = pd.merge(
275
- self.df, df_eos, on="subject_identifier", how="left", suffixes=("", "_y")
276
- )
277
- self.df = self.df.sort_values(by=["subject_identifier", "fbg_datetime"])
278
- self.df = self.df.reset_index(drop=True)
134
+ # add back the others rows for these subjects
135
+ subjects_df = self.working_df.loc[
136
+ (
137
+ self.working_df["subject_identifier"].isin(
138
+ subject_endpoint_df["subject_identifier"]
139
+ )
140
+ & ~(
141
+ self.working_df["fbg_datetime"].isin(
142
+ subject_endpoint_df["fbg_datetime"]
143
+ )
144
+ )
145
+ )
146
+ ].copy()
147
+ subjects_df = subjects_df.reset_index(drop=True)
148
+ subjects_df["endpoint"] = np.nan
149
+ subjects_df["endpoint_label"] = None
150
+ subjects_df["endpoint_type"] = None
151
+ subjects_df["interval_in_days"] = np.nan
152
+ subjects_df = pd.concat([subjects_df, subject_endpoint_df])
153
+ subjects_df = subjects_df.reset_index(drop=True)
279
154
 
280
- def add_calculated_days_from_baseline_to_event_columns(self):
281
- """Add columns that calculate number of days from
282
- baseline to visit, fbg, and ogtt.
283
- """
284
- self.df["visit_days"] = np.nan
285
- self.df["fbg_days"] = np.nan
286
- self.df["ogtt_days"] = np.nan
287
- self.df["test"] = np.nan
288
- self.df["visit_days"] = (
289
- self.df["visit_datetime"] - self.df["baseline_datetime"]
290
- ).dt.days
291
- if not self.df["fbg_datetime"].isnull().all():
292
- self.df["fbg_days"] = (
293
- self.df["fbg_datetime"] - self.df["baseline_datetime"]
294
- ).dt.days
295
- if not self.df["ogtt_datetime"].isnull().all():
296
- self.df["ogtt_days"] = (
297
- self.df["ogtt_datetime"] - self.df["baseline_datetime"]
298
- ).dt.days
299
- self.df["visit_days"] = pd.to_numeric(self.df["visit_days"], downcast="integer")
300
- self.df["fbg_days"] = pd.to_numeric(self.df["fbg_days"], downcast="integer")
301
- self.df["ogtt_days"] = pd.to_numeric(self.df["ogtt_days"], downcast="integer")
302
- self.df = self.df.reset_index(drop=True)
155
+ self.append_subject_to_endpoint_df(subjects_df[endpoint_columns])
156
+ self.remove_subjects_from_working_df(subjects_df)
303
157
 
304
- def pre_check_endpoint(self):
158
+ def process_by_ogtt_only(self):
305
159
  """Flag subjects that met endpoint by hitting the OGTT
306
160
  threshold.
307
161
 
@@ -322,15 +176,17 @@ class GlucoseEndpointsByDate:
322
176
  """
323
177
  subject_endpoint_df = self.working_df.loc[
324
178
  (self.working_df["ogtt_value"] >= self.ogtt_threshhold)
325
- & (self.working_df["fasting"] == YES)
179
+ & (self.working_df["ogtt_value"] <= 9999.99)
180
+ & (self.working_df["fasted"] == YES)
326
181
  & (self.working_df["fbg_value"].notna())
327
182
  ].copy()
328
- subject_endpoint_df.sort_values(by=["subject_identifier", "fbg_datetime"])
329
- subject_endpoint_df = subject_endpoint_df.reset_index(drop=True)
330
- subject_endpoint_df = subject_endpoint_df.drop_duplicates(
331
- subset=["subject_identifier"], keep="first"
183
+
184
+ subject_endpoint_df = (
185
+ subject_endpoint_df.sort_values(by=["subject_identifier", "fbg_datetime"])
186
+ .reset_index(drop=True)
187
+ .drop_duplicates(subset=["subject_identifier"], keep="first")
188
+ .reset_index(drop=True)
332
189
  )
333
- subject_endpoint_df = subject_endpoint_df.reset_index(drop=True)
334
190
  if not subject_endpoint_df.empty:
335
191
  # flag the selected endpoint rows as endpoints
336
192
  subject_endpoint_df["endpoint"] = 1
@@ -372,8 +228,7 @@ class GlucoseEndpointsByDate:
372
228
  self.endpoint_df = pd.concat([self.endpoint_df, subject_df])
373
229
  self.endpoint_df = self.endpoint_df.sort_values(
374
230
  by=["subject_identifier", "visit_code"]
375
- )
376
- self.endpoint_df = self.endpoint_df.reset_index(drop=True)
231
+ ).reset_index(drop=True)
377
232
 
378
233
  def remove_subject_from_working_df(self, row: pd.Series) -> None:
379
234
  """Removes one subject from the working DF given a Series with
@@ -383,8 +238,7 @@ class GlucoseEndpointsByDate:
383
238
  index=self.working_df[
384
239
  self.working_df["subject_identifier"] == row["subject_identifier"]
385
240
  ].index
386
- )
387
- self.working_df = self.working_df.reset_index(drop=True)
241
+ ).reset_index(drop=True)
388
242
 
389
243
  def remove_subjects_from_working_df(self, rows: pd.DataFrame) -> None:
390
244
  """Removes subjects from the working DF given a DF with
@@ -394,8 +248,7 @@ class GlucoseEndpointsByDate:
394
248
  index=self.working_df.loc[
395
249
  self.working_df["subject_identifier"].isin(rows["subject_identifier"])
396
250
  ].index
397
- )
398
- self.working_df = self.working_df.reset_index(drop=True)
251
+ ).reset_index(drop=True)
399
252
 
400
253
  def get_subject_df(self, subject_identifier: str) -> pd.DataFrame:
401
254
  subject_df = self.working_df.loc[
@@ -407,22 +260,28 @@ class GlucoseEndpointsByDate:
407
260
  subject_df["endpoint"] = 0
408
261
  subject_df = subject_df[endpoint_columns]
409
262
  subject_df = subject_df.sort_values(["subject_identifier", "fbg_datetime"])
410
- subject_df = subject_df.reset_index(drop=True)
411
- return subject_df
263
+ subject_df[[col for col in subject_df if "value" in col]] = subject_df[
264
+ [col for col in subject_df if "value" in col]
265
+ ].fillna(0.0)
266
+
267
+ return subject_df.reset_index(drop=True)
412
268
 
413
269
  def check_endpoint_by_fbg_for_subject(
414
- self, subject_df: pd.DataFrame, case_list: list[int] | None = None
270
+ self,
271
+ subject_df: pd.DataFrame,
272
+ case_list: list[int] | None = None, # noqa: ARG002
415
273
  ) -> pd.DataFrame:
416
- case_list = case_list or [2, 3]
417
274
  endpoint = self.endpoint_cls(
418
275
  subject_df=subject_df,
419
276
  fbg_threshhold=self.fbg_threshhold,
420
277
  ogtt_threshhold=self.ogtt_threshhold,
421
- case_list=case_list,
422
278
  )
423
279
  return endpoint.subject_df
424
280
 
425
281
  def post_check_endpoint(self):
282
+ """Add any who were taken off study before endpoint guidelines
283
+ were clearly defined.
284
+ """
426
285
  df_eos = self.working_df.loc[
427
286
  self.working_df["offstudy_reason"] == "Patient developed diabetes"
428
287
  ].copy()
@@ -477,24 +336,37 @@ class GlucoseEndpointsByDate:
477
336
  self.endpoint_only_df = pd.concat([df1, df2])
478
337
  self.endpoint_only_df = self.endpoint_only_df.reset_index(drop=True)
479
338
 
480
- self.df = pd.merge(
481
- self.df,
339
+ self.df = self.df.merge(
482
340
  self.endpoint_only_df[["subject_identifier", "visit_code", "endpoint"]],
483
341
  on=["subject_identifier", "visit_code"],
484
342
  how="left",
485
343
  suffixes=("", "_y"),
486
344
  )
487
- self.df = self.df.sort_values(by=["subject_identifier", "fbg_datetime"])
488
- self.df = self.df.reset_index(drop=True)
345
+ self.df = self.df.sort_values(by=["subject_identifier", "fbg_datetime"]).reset_index(
346
+ drop=True
347
+ )
489
348
 
490
349
  def to_model(self):
491
350
  """Write endpoint_only_df to the Endpoints model"""
492
351
  df = self.endpoint_only_df
493
352
  model = "meta_reports.endpoints"
494
- now = get_utcnow()
353
+ now = timezone.now()
495
354
  model_cls = django_apps.get_model(model)
496
355
  if self.subject_identifiers:
497
356
  model_cls.objects.filter(subject_identifier__in=self.subject_identifiers).delete()
357
+ if self.endpoint_only_df.empty:
358
+ df = pd.DataFrame()
359
+ else:
360
+ df = (
361
+ self.endpoint_only_df[
362
+ self.endpoint_only_df["subject_identifier"].isin(
363
+ self.subject_identifiers
364
+ )
365
+ ]
366
+ .copy()
367
+ .sort_values(by=["subject_identifier"])
368
+ .reset_index(drop=True)
369
+ )
498
370
  else:
499
371
  model_cls.objects.all().delete()
500
372
  created = 0
@@ -512,15 +384,19 @@ class GlucoseEndpointsByDate:
512
384
  fbg_value=(None if pd.isna(row["fbg_value"]) else row["fbg_value"]),
513
385
  ogtt_value=None if pd.isna(row["ogtt_value"]) else row["ogtt_value"],
514
386
  fbg_date=(None if pd.isna(row["fbg_datetime"]) else row["fbg_datetime"]),
515
- fasting=(None if pd.isna(row["fasting"]) else row["fasting"]),
387
+ fasting=(NULL_STRING if pd.isna(row["fasted"]) else row["fasted"]),
516
388
  endpoint_label=(
517
- None if pd.isna(row["endpoint_label"]) else row["endpoint_label"]
389
+ NULL_STRING
390
+ if pd.isna(row["endpoint_label"])
391
+ else row["endpoint_label"]
518
392
  ),
519
393
  offstudy_date=(
520
394
  None if pd.isna(row["offstudy_datetime"]) else row["offstudy_datetime"]
521
395
  ),
522
396
  offstudy_reason=(
523
- None if pd.isna(row["offstudy_reason"]) else row["offstudy_reason"]
397
+ NULL_STRING
398
+ if pd.isna(row["offstudy_reason"])
399
+ else row["offstudy_reason"]
524
400
  ),
525
401
  report_model=model,
526
402
  created=now,
@@ -1,2 +1,4 @@
1
1
  from .get_glucose_tested_only_df import get_glucose_tested_only_df
2
2
  from .get_screening_df import get_screening_df
3
+
4
+ __all__ = ["get_glucose_tested_only_df", "get_screening_df"]
@@ -16,5 +16,4 @@ def get_glucose_tested_only_df(df: pd.DataFrame | None = None):
16
16
  | (df["ogtt2_value"].notna())
17
17
  )
18
18
  cond = (df["eligible_part_one"] == "Yes") & (df["eligible_part_two"] == "Yes") & cond_glu
19
- df = df[cond]
20
- return df
19
+ return df[cond]
@@ -72,7 +72,7 @@ def get_screening_df(df: pd.DataFrame | None = None) -> pd.DataFrame:
72
72
  # condition to include any glucose test
73
73
 
74
74
  # has_dm fillna with unk
75
- df["has_dm"] = df["has_dm"].apply(lambda x: "unk" if not x else x)
75
+ df["has_dm"] = df["has_dm"].apply(lambda x: x if x else "unk")
76
76
 
77
77
  na = "Not applicable, subject is not eligible based on the criteria above"
78
78
  df["already_fasted"] = df["already_fasted"].apply(lambda x: "N/A" if x == na else x)
@@ -110,29 +110,26 @@ def get_screening_df(df: pd.DataFrame | None = None) -> pd.DataFrame:
110
110
 
111
111
  # bmi
112
112
  # subject SR9E8B4D has eligible part two == No but subject has a glucose value
113
- df.loc[(df["screening_identifier"] == "SR9E8B4D"), "eligible_part_two"] = "Yes"
113
+ # NOTE: update 10-02-2025: subject is not eligible by congestive_heart_failure
114
+ # df.loc[(df["screening_identifier"] == "SR9E8B4D"), "eligible_part_two"] = "Yes"
114
115
 
115
116
  # merge with physical exam to get waist circumference if taken at baseline
116
117
  subject_identifiers = list(df["subject_identifier"])
117
118
  qs_subject_visit = SubjectVisit.objects.filter(subject_identifier__in=subject_identifiers)
118
119
  df_subject_visit = read_frame(qs_subject_visit)
119
- df_subject_visit.rename(columns={"id": "subject_visit"}, inplace=True)
120
+ df_subject_visit = df_subject_visit.rename(columns={"id": "subject_visit"})
120
121
  qs_physical_exam = PhysicalExam.objects.filter(
121
122
  subject_visit__subject_identifier__in=subject_identifiers
122
123
  )
123
124
  df_physical_exam = read_frame(qs_physical_exam)
124
125
  # merge w/ subject visit to get subject_identifier
125
- df_physical_exam = pd.merge(
126
- df_physical_exam,
126
+ df_physical_exam = df_physical_exam.merge(
127
127
  df_subject_visit[
128
128
  ["subject_visit", "subject_identifier", "visit_code", "visit_code_sequence"]
129
129
  ],
130
130
  on="subject_visit",
131
131
  how="left",
132
- )
133
- df_physical_exam = df_physical_exam[
134
- ["subject_identifier", "visit_code", "visit_code_sequence", "waist_circumference"]
135
- ]
132
+ )[["subject_identifier", "visit_code", "visit_code_sequence", "waist_circumference"]]
136
133
  df_physical_exam[["waist_circumference"]] = df_physical_exam[
137
134
  ["waist_circumference"]
138
135
  ].apply(pd.to_numeric)
@@ -143,12 +140,11 @@ def get_screening_df(df: pd.DataFrame | None = None) -> pd.DataFrame:
143
140
  ["waist_circumference_baseline"]
144
141
  ].apply(pd.to_numeric)
145
142
  # merge on subject_identifier with main DF
146
- df = pd.merge(
147
- df,
143
+ df = df.merge(
148
144
  df_physical_exam[["subject_identifier", "waist_circumference_baseline"]],
149
145
  on="subject_identifier",
150
146
  how="left",
151
- )
147
+ ).reset_index(drop=True)
152
148
  # set waist_circumference=waist_circumference_baseline
153
149
  # if `waist_circumference` is none and `waist_circumference_baseline` is not
154
150
  df.loc[
@@ -157,6 +153,4 @@ def get_screening_df(df: pd.DataFrame | None = None) -> pd.DataFrame:
157
153
  ] = df["waist_circumference_baseline"]
158
154
 
159
155
  # drop waist_circumference_baseline
160
- df.drop(columns=["waist_circumference_baseline"], inplace=True)
161
-
162
- return df
156
+ return df.drop(columns=["waist_circumference_baseline"])
@@ -1,4 +1,6 @@
1
+ import numpy as np
1
2
  import pandas as pd
3
+ from clinicedc_constants import NO
2
4
 
3
5
  from .constants import endpoint_columns
4
6
 
@@ -35,16 +37,12 @@ def get_empty_endpoint_df() -> pd.DataFrame:
35
37
  "endpoint",
36
38
  "endpoint_type",
37
39
  ]
38
- ].apply(
39
- pd.to_numeric
40
- )
40
+ ].apply(pd.to_numeric)
41
41
  endpoint_df[
42
42
  ["baseline_datetime", "visit_datetime", "fbg_datetime", "offstudy_datetime"]
43
43
  ] = endpoint_df[
44
44
  ["baseline_datetime", "visit_datetime", "fbg_datetime", "offstudy_datetime"]
45
- ].apply(
46
- pd.to_datetime
47
- )
45
+ ].apply(pd.to_datetime)
48
46
  endpoint_df["visit_code"] = endpoint_df["visit_code"].astype(float)
49
47
  return endpoint_df
50
48
 
@@ -54,12 +52,23 @@ def get_unique_visit_codes(df: pd.DataFrame) -> pd.DataFrame:
54
52
  stats_df = stats_df.reset_index()
55
53
  stats_df["visit_code"] = stats_df["visit_code"].astype(float)
56
54
  stats_df = stats_df.sort_values(["visit_code"])
57
- stats_df = stats_df.reset_index(drop=True)
58
- return stats_df
55
+ return stats_df.reset_index(drop=True)
59
56
 
60
57
 
61
58
  def get_unique_subject_identifiers(df: pd.DataFrame) -> pd.DataFrame:
62
- values_df = pd.DataFrame(df["subject_identifier"].unique(), columns=["subject_identifier"])
63
- values_df = values_df.sort_values(["subject_identifier"])
64
- values_df = values_df.reset_index()
65
- return values_df
59
+ return (
60
+ pd.DataFrame(df["subject_identifier"].unique(), columns=["subject_identifier"])
61
+ .sort_values(["subject_identifier"])
62
+ .reset_index()
63
+ )
64
+
65
+
66
+ def calculate_fasting_hrs(df: pd.DataFrame) -> pd.DataFrame:
67
+ df.loc[(df["fasting"] == NO), "fasting_duration_delta"] = pd.NaT
68
+ if df.empty:
69
+ df["fasting_hrs"] = np.nan
70
+ else:
71
+ df["fasting_hrs"] = df["fasting_duration_delta"].apply(
72
+ lambda s: np.nan if pd.isna(s) else s.total_seconds() / 3600
73
+ )
74
+ return df
@@ -35,8 +35,7 @@ def get_tables() -> dict[str, Data]:
35
35
  & (df_not_tested["eligible_part_two"] == "Yes")
36
36
  )
37
37
  ]
38
- df_not_tested.drop(df_not_eligible_p1p2.index, inplace=True)
39
- df_not_tested.drop(df_fbg.index, inplace=True)
38
+ df_not_tested = df_not_tested.drop(df_not_eligible_p1p2.index).drop(df_fbg.index)
40
39
 
41
40
  df_stats = pd.DataFrame(
42
41
  {
@@ -1,2 +1,4 @@
1
1
  from .eligible import EligibleP12Table
2
2
  from .has_dm import HasDmTable
3
+
4
+ __all__ = ["EligibleP12Table", "HasDmTable"]
@@ -17,10 +17,11 @@ class GlucoseTable(Table):
17
17
  super().__init__(colname="", main_df=main_df, title="Glucose (enrolled)")
18
18
 
19
19
  def build_table_df(self) -> None:
20
+ super().build_table_df()
20
21
  df = self.main_df
21
22
  s = df.groupby("subject_identifier")[["age_in_years", "gender"]].value_counts()
22
23
  df_tmp = s.to_frame()
23
24
  df_tmp = df_tmp.reset_index()
24
25
  gender_tbl = GenderTable(main_df=df_tmp).table_df
25
26
  age_tbl = AgeTable(main_df=df_tmp).table_df
26
- return pd.concat([gender_tbl, age_tbl])
27
+ self.table_df = pd.concat([self.table_df, gender_tbl, age_tbl]).reset_index(drop=True)