meta-edc 0.3.15__py3-none-any.whl → 0.3.50__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (333) hide show
  1. meta_ae/action_items.py +2 -2
  2. meta_ae/migrations/0017_auto_20221130_2257.py +12 -7
  3. meta_ae/tests/holidays.csv +1 -1
  4. meta_analytics/README.rst +17 -0
  5. meta_analytics/dataframes/__init__.py +19 -0
  6. meta_analytics/dataframes/constants.py +33 -0
  7. meta_analytics/dataframes/enrolled/__init__.py +1 -0
  8. meta_analytics/dataframes/enrolled/get_glucose_df.py +122 -0
  9. meta_analytics/dataframes/get_eos_df.py +26 -0
  10. meta_analytics/dataframes/get_last_imp_visits_df.py +101 -0
  11. meta_analytics/dataframes/glucose_endpoints/__init__.py +2 -0
  12. meta_analytics/dataframes/glucose_endpoints/endpoint_by_date.py +183 -0
  13. meta_analytics/dataframes/glucose_endpoints/glucose_endpoints_by_date.py +531 -0
  14. meta_analytics/dataframes/screening/__init__.py +2 -0
  15. meta_analytics/dataframes/screening/get_glucose_tested_only_df.py +20 -0
  16. meta_analytics/dataframes/screening/get_screening_df.py +163 -0
  17. meta_analytics/dataframes/utils.py +65 -0
  18. meta_analytics/get_tables.py +81 -0
  19. meta_analytics/tables/__init__.py +2 -0
  20. meta_analytics/tables/eligible.py +106 -0
  21. meta_analytics/tables/enrolled/__init__.py +0 -0
  22. meta_analytics/tables/enrolled/glucose.py +28 -0
  23. meta_analytics/tables/has_dm.py +61 -0
  24. meta_analytics/tests/__init__.py +0 -0
  25. meta_analytics/tests/test_endpoints_by_date.py +94 -0
  26. meta_auth/auth_objects.py +22 -0
  27. meta_auth/auths.py +18 -3
  28. meta_consent/action_items.py +18 -1
  29. meta_consent/admin/__init__.py +1 -0
  30. meta_consent/admin/subject_consent_v1_ext_admin.py +45 -0
  31. meta_consent/baker_recipes.py +1 -0
  32. meta_consent/consents.py +20 -1
  33. meta_consent/constants.py +1 -0
  34. meta_consent/forms/__init__.py +1 -0
  35. meta_consent/forms/subject_consent_v1_ext_form.py +16 -0
  36. meta_consent/locale/lg/LC_MESSAGES/django.po +69 -0
  37. meta_consent/locale/sw/LC_MESSAGES/django.po +12 -12
  38. meta_consent/migrations/0026_historicalsubjectconsentv1ext_subjectconsentv1ext.py +544 -0
  39. meta_consent/migrations/0027_auto_20250111_0344.py +30 -0
  40. meta_consent/models/__init__.py +1 -0
  41. meta_consent/models/signals.py +18 -0
  42. meta_consent/models/subject_consent_v1_ext.py +29 -0
  43. meta_consent/tests/holidays.csv +1 -1
  44. meta_dashboard/locale/lg/LC_MESSAGES/django.po +30 -0
  45. meta_dashboard/locale/sw/LC_MESSAGES/django.po +11 -2
  46. meta_dashboard/navbars.py +3 -1
  47. meta_dashboard/templates/meta_dashboard/bootstrap3/buttons/eligibility_button.html +1 -1
  48. meta_dashboard/templates/meta_dashboard/bootstrap3/buttons/screening_button.html +1 -1
  49. meta_dashboard/templates/meta_dashboard/bootstrap3/subject/dashboard/sidebar.html +24 -0
  50. meta_dashboard/templates/meta_dashboard/bootstrap3/subject/dashboard.html +3 -0
  51. meta_dashboard/templatetags/meta_dashboard_extras.py +1 -1
  52. meta_dashboard/tests/holidays.csv +1 -1
  53. meta_dashboard/tests/urls.py +0 -1
  54. meta_dashboard/view_utils/__init__.py +6 -0
  55. meta_dashboard/view_utils/subject_screening_button.py +2 -2
  56. meta_dashboard/views/subject/dashboard/dashboard_view.py +38 -0
  57. meta_edc/__init__.py +7 -0
  58. meta_edc/celery.py +4 -13
  59. meta_edc/celery_live.py +18 -0
  60. meta_edc/celery_uat.py +24 -0
  61. meta_edc/management/commands/update_forms_reference.py +6 -2
  62. meta_edc/migrations/__init__.py +0 -0
  63. meta_edc/navbars.py +2 -1
  64. meta_edc/settings/debug.py +10 -2
  65. meta_edc/settings/defaults.py +58 -43
  66. meta_edc/templates/meta_edc/bootstrap3/home.html +5 -2
  67. meta_edc/tests/tests/test_endpoints.py +2 -0
  68. meta_edc/urls.py +4 -1
  69. meta_edc/wsgi.py +1 -1
  70. meta_edc/wsgi_live.py +1 -1
  71. meta_edc/wsgi_uat.py +1 -1
  72. meta_edc-0.3.50.dist-info/AUTHORS +0 -0
  73. meta_edc-0.3.50.dist-info/METADATA +766 -0
  74. {meta_edc-0.3.15.dist-info → meta_edc-0.3.50.dist-info}/RECORD +316 -127
  75. {meta_edc-0.3.15.dist-info → meta_edc-0.3.50.dist-info}/WHEEL +1 -1
  76. {meta_edc-0.3.15.dist-info → meta_edc-0.3.50.dist-info}/top_level.txt +1 -0
  77. meta_pharmacy/admin/__init__.py +2 -0
  78. meta_pharmacy/admin/rx_admin.py +75 -0
  79. meta_pharmacy/admin/substitutions_admin.py +67 -0
  80. meta_pharmacy/admin_site.py +9 -0
  81. meta_pharmacy/apps.py +5 -0
  82. meta_pharmacy/constants.py +10 -0
  83. meta_pharmacy/forms/__init__.py +2 -0
  84. meta_pharmacy/forms/rx_form.py +16 -0
  85. meta_pharmacy/forms/substitutions_form.py +54 -0
  86. meta_pharmacy/label_configs.py +30 -0
  87. meta_pharmacy/labels/__init__.py +5 -0
  88. meta_pharmacy/labels/draw_label_for_subject_with_barcode.py +62 -0
  89. meta_pharmacy/labels/draw_label_for_subject_with_code128.py +14 -0
  90. meta_pharmacy/labels/draw_label_with_test_data.py +26 -0
  91. meta_pharmacy/labels/label_data.py +14 -0
  92. meta_pharmacy/labels/print_sheets.py +97 -0
  93. meta_pharmacy/list_data.py +8 -0
  94. meta_pharmacy/management/__init__.py +0 -0
  95. meta_pharmacy/management/commands/__init__.py +0 -0
  96. meta_pharmacy/management/commands/update_initial_pharmacy_data.py +10 -0
  97. meta_pharmacy/migrations/0002_initial.py +695 -0
  98. meta_pharmacy/migrations/0003_auto_20240909_2335.py +64 -0
  99. meta_pharmacy/migrations/0004_alter_historicalsubstitutions_report_datetime_and_more.py +23 -0
  100. meta_pharmacy/migrations/0005_auto_20240911_0352.py +17 -0
  101. meta_pharmacy/migrations/0006_lotnumber_label.py +289 -0
  102. meta_pharmacy/migrations/0007_lotnumber_medication.py +24 -0
  103. meta_pharmacy/migrations/0008_remove_lotnumber_medication_and_more.py +390 -0
  104. meta_pharmacy/migrations/0009_remove_historicalrx_slug.py +17 -0
  105. meta_pharmacy/models/__init__.py +3 -0
  106. meta_pharmacy/models/label_data.py +38 -0
  107. meta_pharmacy/models/rx.py +18 -0
  108. meta_pharmacy/models/rx_label.py +39 -0
  109. meta_pharmacy/models/substitutions.py +88 -0
  110. meta_pharmacy/urls.py +8 -0
  111. meta_pharmacy/utils/__init__.py +1 -0
  112. meta_pharmacy/utils/update_initial_pharmacy_data.py +146 -0
  113. meta_prn/action_items.py +9 -1
  114. meta_prn/admin/pregnancy_notification_admin.py +6 -2
  115. meta_prn/migrations/0034_auto_20220630_1110.py +3 -3
  116. meta_prn/migrations/0035_auto_20220630_1140.py +59 -56
  117. meta_prn/tests/tests/test_dm_referral.py +3 -6
  118. meta_reports/__init__.py +1 -0
  119. meta_reports/admin/__init__.py +15 -0
  120. meta_reports/admin/dbviews/__init__.py +14 -0
  121. meta_reports/admin/dbviews/glucose_summary_admin.py +116 -0
  122. meta_reports/admin/dbviews/imp_substitutions_admin.py +101 -0
  123. meta_reports/admin/dbviews/missing_screening_ogtt_admin/__init__.py +2 -0
  124. meta_reports/admin/dbviews/missing_screening_ogtt_admin/note_model_admin.py +53 -0
  125. meta_reports/admin/dbviews/missing_screening_ogtt_admin/unmanaged_model_admin.py +84 -0
  126. meta_reports/admin/dbviews/on_study_missing_lab_values_admin/__init__.py +1 -0
  127. meta_reports/admin/dbviews/on_study_missing_lab_values_admin/unmanaged_model_admin.py +13 -0
  128. meta_reports/admin/dbviews/on_study_missing_values_admin/__init__.py +1 -0
  129. meta_reports/admin/dbviews/on_study_missing_values_admin/unmanaged_model_admin.py +13 -0
  130. meta_reports/admin/dbviews/patient_history_missing_baseline_cd4_admin.py +58 -0
  131. meta_reports/admin/dbviews/unattended_three_in_row2_admin.py +47 -0
  132. meta_reports/admin/dbviews/unattended_three_in_row_admin.py +35 -0
  133. meta_reports/admin/dbviews/unattended_two_in_row_admin.py +34 -0
  134. meta_reports/admin/endpoints_admin.py +14 -0
  135. meta_reports/admin/endpoints_all_admin.py +13 -0
  136. meta_reports/admin/last_imp_refill_admin.py +181 -0
  137. meta_reports/admin/list_filters.py +30 -0
  138. meta_reports/admin/modeladmin_mixins.py +112 -0
  139. meta_reports/admin_site.py +5 -0
  140. meta_reports/apps.py +1 -16
  141. meta_reports/forms/__init__.py +1 -0
  142. meta_reports/forms/missing_ogtt_note_form.py +33 -0
  143. meta_reports/management/__init__.py +0 -0
  144. meta_reports/management/commands/__init__.py +0 -0
  145. meta_reports/management/commands/generate_endpoints.py +13 -0
  146. meta_reports/migrations/0001_initial.py +87 -0
  147. meta_reports/migrations/0002_patienthistorymissingbaselinecd4_and_more.py +64 -0
  148. meta_reports/migrations/0003_auto_20240618_0505.py +12 -0
  149. meta_reports/migrations/0004_alter_patienthistorymissingbaselinecd4_table.py +17 -0
  150. meta_reports/migrations/0005_endpoints.py +47 -0
  151. meta_reports/migrations/0006_endpoints_baseline_datetime.py +18 -0
  152. meta_reports/migrations/0007_alter_endpoints_endpoint_label_and_more.py +43 -0
  153. meta_reports/migrations/0008_alter_endpoints_endpoint_label.py +18 -0
  154. meta_reports/migrations/0009_alter_endpoints_options.py +21 -0
  155. meta_reports/migrations/0010_alter_patienthistorymissingbaselinecd4_options_and_more.py +49 -0
  156. meta_reports/migrations/0011_auto_20240813_0156.py +54 -0
  157. meta_reports/migrations/0012_auto_20240813_1516.py +48 -0
  158. meta_reports/migrations/0013_auto_20240813_1516.py +48 -0
  159. meta_reports/migrations/0014_auto_20240813_1517.py +48 -0
  160. meta_reports/migrations/0015_alter_endpoints_site.py +22 -0
  161. meta_reports/migrations/0016_missingscreeningogtt.py +47 -0
  162. meta_reports/migrations/0017_auto_20240819_1711.py +166 -0
  163. meta_reports/migrations/0018_auto_20240819_1713.py +54 -0
  164. meta_reports/migrations/0019_auto_20240819_1721.py +54 -0
  165. meta_reports/migrations/0020_auto_20240819_1811.py +54 -0
  166. meta_reports/migrations/0021_auto_20240819_1817.py +54 -0
  167. meta_reports/migrations/0022_auto_20240819_1832.py +54 -0
  168. meta_reports/migrations/0023_endpoints_meta_report_subject_a56b22_idx.py +20 -0
  169. meta_reports/migrations/0024_glucosesummary.py +38 -0
  170. meta_reports/migrations/0025_auto_20240822_0115.py +87 -0
  171. meta_reports/migrations/0026_auto_20240822_0120.py +54 -0
  172. meta_reports/migrations/0027_auto_20240822_0140.py +54 -0
  173. meta_reports/migrations/0028_alter_glucosesummary_options.py +22 -0
  174. meta_reports/migrations/0029_auto_20240822_0149.py +54 -0
  175. meta_reports/migrations/0030_auto_20240822_1637.py +54 -0
  176. meta_reports/migrations/0031_endpointsproxy.py +25 -0
  177. meta_reports/migrations/0032_alter_endpointsproxy_options.py +21 -0
  178. meta_reports/migrations/0033_auto_20240823_0012.py +54 -0
  179. meta_reports/migrations/0034_auto_20240823_1642.py +54 -0
  180. meta_reports/migrations/0035_historicalmissingogttnote_missingogttnote.py +457 -0
  181. meta_reports/migrations/0036_historicalmissingogttnote_fasting_and_more.py +86 -0
  182. meta_reports/migrations/0037_historicalmissingogttnote_result_status_and_more.py +51 -0
  183. meta_reports/migrations/0038_alter_historicalmissingogttnote_fasting_and_more.py +33 -0
  184. meta_reports/migrations/0039_onstudymissingvalues.py +44 -0
  185. meta_reports/migrations/0040_auto_20240824_0412.py +282 -0
  186. meta_reports/migrations/0041_auto_20240828_2229.py +14 -0
  187. meta_reports/migrations/0042_onstudymissinglabvalues.py +43 -0
  188. meta_reports/migrations/0043_auto_20240828_2309.py +88 -0
  189. meta_reports/migrations/0044_auto_20240828_2323.py +93 -0
  190. meta_reports/migrations/0045_auto_20240829_0248.py +54 -0
  191. meta_reports/migrations/0046_auto_20240829_0250.py +54 -0
  192. meta_reports/migrations/0047_impsubstitutions.py +56 -0
  193. meta_reports/migrations/0048_auto_20240909_2338.py +48 -0
  194. meta_reports/migrations/0049_auto_20240911_0327.py +54 -0
  195. meta_reports/migrations/0050_alter_endpoints_created.py +19 -0
  196. meta_reports/migrations/0051_remove_endpoints_baseline_datetime_and_more.py +40 -0
  197. meta_reports/migrations/0052_lastimpvisit.py +57 -0
  198. meta_reports/migrations/0053_rename_lastimpvisit_lastimprefill_and_more.py +31 -0
  199. meta_reports/models/__init__.py +16 -0
  200. meta_reports/models/dbviews/README +14 -0
  201. meta_reports/models/dbviews/__init__.py +9 -0
  202. meta_reports/models/dbviews/glucose_summary/__init__.py +2 -0
  203. meta_reports/models/dbviews/glucose_summary/unmanaged_model.py +35 -0
  204. meta_reports/models/dbviews/glucose_summary/view_definition.py +28 -0
  205. meta_reports/models/dbviews/imp_substitutions/__init__.py +1 -0
  206. meta_reports/models/dbviews/imp_substitutions/unmanaged_model.py +41 -0
  207. meta_reports/models/dbviews/imp_substitutions/view_definition.py +21 -0
  208. meta_reports/models/dbviews/missing_screening_ogtt/__init__.py +2 -0
  209. meta_reports/models/dbviews/missing_screening_ogtt/note_model.py +57 -0
  210. meta_reports/models/dbviews/missing_screening_ogtt/unmanaged_model.py +41 -0
  211. meta_reports/models/dbviews/missing_screening_ogtt/view_definition.py +20 -0
  212. meta_reports/models/dbviews/on_study_missing_lab_values/__init__.py +1 -0
  213. meta_reports/models/dbviews/on_study_missing_lab_values/qa_cases.py +53 -0
  214. meta_reports/models/dbviews/on_study_missing_lab_values/unmanged_model.py +20 -0
  215. meta_reports/models/dbviews/on_study_missing_lab_values/view_definition.py +17 -0
  216. meta_reports/models/dbviews/on_study_missing_values/__init__.py +1 -0
  217. meta_reports/models/dbviews/on_study_missing_values/qa_cases.py +54 -0
  218. meta_reports/models/dbviews/on_study_missing_values/unmanged_model.py +20 -0
  219. meta_reports/models/dbviews/on_study_missing_values/view_definition.py +17 -0
  220. meta_reports/models/dbviews/patient_history_missing_baseline_cd4/__init__.py +1 -0
  221. meta_reports/models/dbviews/patient_history_missing_baseline_cd4/unmanaged_model.py +31 -0
  222. meta_reports/models/dbviews/patient_history_missing_baseline_cd4/view_definition.py +21 -0
  223. meta_reports/models/dbviews/unattended_three_in_row/__init__.py +1 -0
  224. meta_reports/models/dbviews/unattended_three_in_row/unmanaged_model.py +29 -0
  225. meta_reports/models/dbviews/unattended_three_in_row/view_definition.py +31 -0
  226. meta_reports/models/dbviews/unattended_three_in_row2/__init__.py +1 -0
  227. meta_reports/models/dbviews/unattended_three_in_row2/unmanaged_model.py +29 -0
  228. meta_reports/models/dbviews/unattended_three_in_row2/view_definition.py +50 -0
  229. meta_reports/models/dbviews/unattended_two_in_row/__init__.py +1 -0
  230. meta_reports/models/dbviews/unattended_two_in_row/unmanaged_model.py +27 -0
  231. meta_reports/models/dbviews/unattended_two_in_row/view_definition.py +30 -0
  232. meta_reports/models/endpoints.py +31 -0
  233. meta_reports/models/endpoints_proxy.py +11 -0
  234. meta_reports/models/last_imp_refill.py +34 -0
  235. meta_reports/tasks.py +12 -0
  236. meta_reports/templates/meta_reports/columns/subject_identifier_column.html +1 -0
  237. meta_reports/templates/meta_reports/endpoints_all_change_list_note.html +12 -0
  238. meta_reports/templates/meta_reports/endpoints_change_list_note.html +12 -0
  239. meta_reports/tests/test_sql_gen.py +5 -0
  240. meta_reports/urls.py +8 -0
  241. meta_reports/utils.py +0 -0
  242. meta_screening/admin/subject_screening_admin.py +1 -0
  243. meta_screening/migrations/0067_alter_historicalscreeningpartone_report_datetime_and_more.py +84 -0
  244. meta_screening/tests/holidays.csv +1 -1
  245. meta_screening/tests/meta_test_case_mixin.py +15 -0
  246. meta_sites/tests/test_sites.py +1 -1
  247. meta_subject/action_items.py +2 -2
  248. meta_subject/admin/__init__.py +2 -1
  249. meta_subject/admin/birth_outcome_admin.py +2 -0
  250. meta_subject/admin/blood_results/__init__.py +1 -1
  251. meta_subject/admin/blood_results/{blood_results_lipid_admin.py → blood_results_lipids_admin.py} +7 -7
  252. meta_subject/admin/diabetes/__init__.py +1 -1
  253. meta_subject/admin/diabetes/dm_endpoint_admin.py +35 -0
  254. meta_subject/admin/glucose_fbg_admin.py +4 -0
  255. meta_subject/admin/other_arv_regimens_admin.py +2 -0
  256. meta_subject/admin/study_medication_admin.py +10 -0
  257. meta_subject/form_validators/__init__.py +1 -1
  258. meta_subject/form_validators/dm_endpoint_form_validator.py +35 -0
  259. meta_subject/forms/__init__.py +2 -2
  260. meta_subject/forms/blood_results/__init__.py +1 -1
  261. meta_subject/forms/blood_results/{blood_results_lipid_form.py → blood_results_lipids_form.py} +5 -5
  262. meta_subject/forms/diabetes/__init__.py +1 -2
  263. meta_subject/forms/diabetes/dm_endpoint_form.py +13 -0
  264. meta_subject/forms/study_medication_form.py +35 -0
  265. meta_subject/locale/lg/LC_MESSAGES/django.po +470 -0
  266. meta_subject/locale/sw/LC_MESSAGES/django.po +191 -89
  267. meta_subject/metadata_rules/metadata_rules.py +7 -0
  268. meta_subject/metadata_rules/predicates.py +45 -8
  269. meta_subject/migrations/0107_auto_20220415_0043.py +28 -22
  270. meta_subject/migrations/0126_auto_20220719_2142.py +4 -4
  271. meta_subject/migrations/0131_auto_20220722_0411.py +28 -23
  272. meta_subject/migrations/0132_auto_20220722_1825.py +10 -6
  273. meta_subject/migrations/0135_auto_20220722_2212.py +39 -35
  274. meta_subject/migrations/0150_auto_20220914_0039.py +15 -11
  275. meta_subject/migrations/0207_alter_historicalphysicalexam_waist_circumference_and_more.py +46 -0
  276. meta_subject/migrations/0208_birthoutcomes_crf_status_and_more.py +62 -0
  277. meta_subject/migrations/0209_remove_historicaldmdxresult_dm_diagnosis_and_more.py +37 -0
  278. meta_subject/migrations/0210_remove_dmdxresult_dm_diagnosis_and_more.py +123 -0
  279. meta_subject/migrations/0211_dmendpoint_endpoint_reached_and_more.py +45 -0
  280. meta_subject/migrations/0212_auto_20240827_2222.py +23 -0
  281. meta_subject/migrations/0213_rename_bloodresultslipid_bloodresultslipids_and_more.py +35 -0
  282. meta_subject/migrations/0214_historicalstudymedication_stock_codes_and_more.py +44 -0
  283. meta_subject/migrations/0215_alter_historicalstudymedication_stock_codes_and_more.py +46 -0
  284. meta_subject/model_mixins/arv_history_model_mixin.py +3 -3
  285. meta_subject/models/__init__.py +3 -2
  286. meta_subject/models/birth_outcomes.py +6 -1
  287. meta_subject/models/blood_results/__init__.py +1 -1
  288. meta_subject/models/blood_results/{blood_results_lipid.py → blood_results_lipids.py} +3 -3
  289. meta_subject/models/diabetes/__init__.py +1 -2
  290. meta_subject/models/diabetes/dm_endpoint.py +61 -0
  291. meta_subject/models/glucose.py +4 -1
  292. meta_subject/models/physical_exam.py +1 -0
  293. meta_subject/models/signals.py +19 -0
  294. meta_subject/models/todo.txt +1 -1
  295. meta_subject/static/meta_subject/slider.css +1 -1
  296. meta_subject/templates/meta_subject/endpoint_review_instructions.html +1 -1
  297. meta_subject/templates/meta_subject/widgets/slider.html +0 -1
  298. meta_subject/tests/holidays.csv +1 -1
  299. meta_subject/tests/tests/test_medication_adherence.py +5 -1
  300. meta_subject/tests/tests/test_metadata_rules.py +2 -2
  301. meta_subject/tests/tests/test_mnsi.py +212 -121
  302. meta_subject/tests/tests/test_sf12.py +0 -12
  303. meta_visit_schedule/constants.py +4 -0
  304. meta_visit_schedule/tests/tests/test_schedule.py +4 -0
  305. meta_visit_schedule/visit_schedules/phase_three/crfs.py +75 -13
  306. meta_visit_schedule/visit_schedules/phase_three/requisitions.py +12 -0
  307. meta_visit_schedule/visit_schedules/phase_three/schedule.py +65 -2
  308. meta_visit_schedule/visit_schedules/phase_three/schedule_dm_referral.py +1 -1
  309. tests/etc/randomization_list.csv +1 -1
  310. {meta_edc/tests → tests}/etc/randomization_list_phase_three.csv +4 -4
  311. tests/holidays.csv +1 -1
  312. {meta_edc/tests → tests}/test_settings.py +16 -6
  313. meta_edc/tests/etc/user-aes-local.key +0 -1
  314. meta_edc/tests/etc/user-aes-restricted.key +0 -0
  315. meta_edc/tests/etc/user-rsa-local-private.pem +0 -27
  316. meta_edc/tests/etc/user-rsa-local-public.pem +0 -9
  317. meta_edc/tests/etc/user-rsa-restricted-private.pem +0 -27
  318. meta_edc/tests/etc/user-rsa-restricted-public.pem +0 -9
  319. meta_edc/tests/etc/user-salt-local.key +0 -0
  320. meta_edc/tests/etc/user-salt-restricted.key +0 -0
  321. meta_edc-0.3.15.dist-info/METADATA +0 -88
  322. meta_reports/tests/holidays.csv +0 -15
  323. meta_subject/admin/diabetes/dm_diagnosis_admin.py +0 -89
  324. meta_subject/form_validators/dm_diagnosis_form_validator.py +0 -38
  325. meta_subject/form_validators/dm_dx_result_form_validator.py +0 -7
  326. meta_subject/forms/diabetes/dm_diagnosis_form.py +0 -13
  327. meta_subject/forms/diabetes/dm_dx_result_form.py +0 -11
  328. meta_subject/models/diabetes/dm_diagnosis.py +0 -50
  329. meta_subject/models/diabetes/dm_dx_result.py +0 -70
  330. /meta_edc-0.3.15.dist-info/AUTHORS → /meta_analytics/__init__.py +0 -0
  331. /meta_pharmacy/models.py → /meta_analytics/constants.py +0 -0
  332. /meta_reports/models.py → /meta_analytics/notebooks/cleaning/__init__.py +0 -0
  333. {meta_edc-0.3.15.dist-info → meta_edc-0.3.50.dist-info}/LICENSE +0 -0
@@ -0,0 +1,531 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ 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
12
+
13
+ from ..constants import (
14
+ CASE_EOS,
15
+ CASE_FBG_ONLY,
16
+ CASE_FBGS_WITH_FIRST_OGTT,
17
+ CASE_FBGS_WITH_SECOND_OGTT,
18
+ CASE_OGTT,
19
+ endpoint_cases,
20
+ endpoint_columns,
21
+ )
22
+ from ..utils import (
23
+ get_empty_endpoint_df,
24
+ get_test_string,
25
+ get_unique_subject_identifiers,
26
+ get_unique_visit_codes,
27
+ )
28
+ from .endpoint_by_date import EndpointByDate
29
+
30
+
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
+ class GlucoseEndpointsByDate:
43
+ """
44
+ Usage:
45
+ cls = GlucoseEndpointsByDate()
46
+ cls.run()
47
+
48
+ # subjects who reached endpoint
49
+ cls.endpoint_only_df.endpoint_type.value_counts()
50
+ cls.endpoint_only_df.endpoint_label.value_counts()
51
+
52
+ # subjects who reached endpoint with total
53
+ result_df = cls.endpoint_only_df.endpoint_label.value_counts().to_frame().reset_index()
54
+ result_df.columns = ["endpoint_label", "total"]
55
+ result_df.loc[-1] = ["total", result_df.total.sum()]
56
+ result_df = result_df.reset_index(drop=True)
57
+ result_df
58
+ """
59
+
60
+ fbg_threshhold = 7.0
61
+ ogtt_threshhold = 11.1
62
+ endpoint_cls = EndpointByDate
63
+ keep_cols = [
64
+ "fasting",
65
+ "fasting_hrs",
66
+ "fbg_value",
67
+ "fbg_units",
68
+ "fbg_datetime",
69
+ "ogtt_value",
70
+ "ogtt_units",
71
+ "ogtt_datetime",
72
+ "source",
73
+ "report_datetime",
74
+ "subject_visit_id",
75
+ "subject_identifier",
76
+ "visit_code",
77
+ "visit_datetime",
78
+ "site_id",
79
+ "baseline_datetime",
80
+ ]
81
+
82
+ def __init__(
83
+ self, subject_identifiers: list[str] | None = None, case_list: list[int] | None = None
84
+ ):
85
+ self._glucose_fbg_df = pd.DataFrame()
86
+ self._glucose_fbg_ogtt_df = pd.DataFrame()
87
+ self.endpoint_only_df = pd.DataFrame()
88
+
89
+ self.subject_identifiers = subject_identifiers or []
90
+ self.case_list = case_list or [
91
+ CASE_OGTT,
92
+ CASE_FBGS_WITH_FIRST_OGTT,
93
+ CASE_FBGS_WITH_SECOND_OGTT,
94
+ CASE_EOS,
95
+ ]
96
+ self.endpoint_cases = {k: v for k, v in endpoint_cases.items() if k in self.case_list}
97
+
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()
169
+
170
+ # label rows by type of glu tests (ones with value)
171
+ 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
+
180
+ self.working_df = self.df.copy()
181
+ self.working_df["endpoint"] = 0
182
+ self.endpoint_df = get_empty_endpoint_df()
183
+
184
+ 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
+ )
191
+ if len(subject_df.loc[subject_df["endpoint"] == 1]) == 1:
192
+ self.append_subject_to_endpoint_df(subject_df)
193
+ 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
+ self.post_check_endpoint()
206
+ self.merge_with_final_endpoints()
207
+
208
+ @property
209
+ def glucose_fbg_df(self) -> pd.DataFrame:
210
+ """Returns a prepared Dataframe of CRF
211
+ meta_subject.glucosefbg.
212
+
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")
257
+ )
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.
263
+
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)
279
+
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)
303
+
304
+ def pre_check_endpoint(self):
305
+ """Flag subjects that met endpoint by hitting the OGTT
306
+ threshold.
307
+
308
+ Add them to the endpoint_df and remove them from the
309
+ working_df.
310
+
311
+ Subject must have fasted at the timepoint.
312
+
313
+ The OGTT must have an FBG measure at the same timepoint.
314
+ The value of the FBG is not considered.
315
+
316
+ Most of these where taken off study for the OGTT. We are
317
+ using the OGTT as the reason/date instead of the offstudy
318
+ reason/date.
319
+
320
+ See `merge_with_final_endpoints` where we pick the date of
321
+ the first OGTT.
322
+ """
323
+ subject_endpoint_df = self.working_df.loc[
324
+ (self.working_df["ogtt_value"] >= self.ogtt_threshhold)
325
+ & (self.working_df["fasting"] == YES)
326
+ & (self.working_df["fbg_value"].notna())
327
+ ].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"
332
+ )
333
+ subject_endpoint_df = subject_endpoint_df.reset_index(drop=True)
334
+ if not subject_endpoint_df.empty:
335
+ # flag the selected endpoint rows as endpoints
336
+ subject_endpoint_df["endpoint"] = 1
337
+ subject_endpoint_df["endpoint_label"] = self.endpoint_cases[CASE_OGTT]
338
+ subject_endpoint_df["endpoint_type"] = CASE_OGTT
339
+ subject_endpoint_df["interval_in_days"] = np.nan
340
+
341
+ # add back the others rows for these subjects
342
+ subjects_df = self.working_df.loc[
343
+ (
344
+ self.working_df["subject_identifier"].isin(
345
+ subject_endpoint_df["subject_identifier"]
346
+ )
347
+ & ~(
348
+ self.working_df["fbg_datetime"].isin(
349
+ subject_endpoint_df["fbg_datetime"]
350
+ )
351
+ )
352
+ )
353
+ ].copy()
354
+ subjects_df = subjects_df.reset_index(drop=True)
355
+ subjects_df["endpoint"] = np.nan
356
+ subjects_df["endpoint_label"] = None
357
+ subjects_df["endpoint_type"] = None
358
+ subjects_df["interval_in_days"] = np.nan
359
+ subjects_df = pd.concat([subjects_df, subject_endpoint_df])
360
+ subjects_df = subjects_df.reset_index(drop=True)
361
+
362
+ self.append_subject_to_endpoint_df(subjects_df[endpoint_columns])
363
+ self.remove_subjects_from_working_df(subjects_df)
364
+
365
+ def append_subject_to_endpoint_df(self, subject_df: pd.DataFrame) -> None:
366
+ """Appends all rows of a subject, or subjects, to the
367
+ Endpoints DF.
368
+ """
369
+ if self.endpoint_df.empty:
370
+ self.endpoint_df = subject_df.copy()
371
+ else:
372
+ self.endpoint_df = pd.concat([self.endpoint_df, subject_df])
373
+ self.endpoint_df = self.endpoint_df.sort_values(
374
+ by=["subject_identifier", "visit_code"]
375
+ )
376
+ self.endpoint_df = self.endpoint_df.reset_index(drop=True)
377
+
378
+ def remove_subject_from_working_df(self, row: pd.Series) -> None:
379
+ """Removes one subject from the working DF given a Series with
380
+ value `subject_identifier`.
381
+ """
382
+ self.working_df = self.working_df.drop(
383
+ index=self.working_df[
384
+ self.working_df["subject_identifier"] == row["subject_identifier"]
385
+ ].index
386
+ )
387
+ self.working_df = self.working_df.reset_index(drop=True)
388
+
389
+ def remove_subjects_from_working_df(self, rows: pd.DataFrame) -> None:
390
+ """Removes subjects from the working DF given a DF with
391
+ column `subject_identifier`.
392
+ """
393
+ self.working_df = self.working_df.drop(
394
+ index=self.working_df.loc[
395
+ self.working_df["subject_identifier"].isin(rows["subject_identifier"])
396
+ ].index
397
+ )
398
+ self.working_df = self.working_df.reset_index(drop=True)
399
+
400
+ def get_subject_df(self, subject_identifier: str) -> pd.DataFrame:
401
+ subject_df = self.working_df.loc[
402
+ self.working_df["subject_identifier"] == subject_identifier
403
+ ].copy()
404
+ subject_df["interval_in_days"] = np.nan
405
+ subject_df["endpoint_type"] = None
406
+ subject_df["endpoint_label"] = None
407
+ subject_df["endpoint"] = 0
408
+ subject_df = subject_df[endpoint_columns]
409
+ subject_df = subject_df.sort_values(["subject_identifier", "fbg_datetime"])
410
+ subject_df = subject_df.reset_index(drop=True)
411
+ return subject_df
412
+
413
+ def check_endpoint_by_fbg_for_subject(
414
+ self, subject_df: pd.DataFrame, case_list: list[int] | None = None
415
+ ) -> pd.DataFrame:
416
+ case_list = case_list or [2, 3]
417
+ endpoint = self.endpoint_cls(
418
+ subject_df=subject_df,
419
+ fbg_threshhold=self.fbg_threshhold,
420
+ ogtt_threshhold=self.ogtt_threshhold,
421
+ case_list=case_list,
422
+ )
423
+ return endpoint.subject_df
424
+
425
+ def post_check_endpoint(self):
426
+ df_eos = self.working_df.loc[
427
+ self.working_df["offstudy_reason"] == "Patient developed diabetes"
428
+ ].copy()
429
+ df_eos["endpoint"] = 1
430
+ df_eos["endpoint_label"] = self.endpoint_cases[CASE_EOS]
431
+ df_eos["endpoint_type"] = CASE_EOS
432
+ df_eos["interval_in_days"] = np.nan
433
+ df_eos = df_eos.reset_index(drop=True)
434
+ self.append_subject_to_endpoint_df(df_eos[endpoint_columns])
435
+ self.working_df = self.working_df.drop(
436
+ index=self.working_df.loc[
437
+ self.working_df["subject_identifier"].isin(df_eos["subject_identifier"])
438
+ ].index
439
+ )
440
+
441
+ def merge_with_final_endpoints(self):
442
+ """Merge endpoint_df with original df"""
443
+ if self.endpoint_df.empty:
444
+ self.df = self.df[~(self.df["subject_identifier"].isin(self.subject_identifiers))]
445
+ else:
446
+ self.endpoint_df["test"] = self.endpoint_df.apply(get_test_string, axis=1)
447
+ self.endpoint_df.loc[self.endpoint_df["endpoint"] == 1, "days_to_endpoint"] = (
448
+ self.endpoint_df["fbg_datetime"] - self.endpoint_df["baseline_datetime"]
449
+ ).dt.days
450
+
451
+ # Create DF of subjects taken offstudy (EOS) where endpoint==1.
452
+ # Keep the last record for the subject by fbg_datetime.
453
+ df1 = self.endpoint_df.copy()
454
+ df1 = df1[
455
+ (df1["endpoint_type"].isin([CASE_EOS, CASE_OGTT])) & (df1["endpoint"] == 1)
456
+ ]
457
+ df1 = df1.sort_values(["subject_identifier", "fbg_datetime"])
458
+ df1 = df1.reset_index(drop=True)
459
+ df1 = df1.set_index(["subject_identifier"])
460
+ df1 = df1[~df1.index.duplicated(keep="last")]
461
+ df1 = df1.reset_index(drop=False)
462
+
463
+ # Create DF of subjects still on-study where endpoint==1.
464
+ # Keep the first record for the subject by fbg_datetime.
465
+ df2 = self.endpoint_df.copy()
466
+ df2 = df2[
467
+ ~(df2["endpoint_type"].isin([CASE_EOS, CASE_OGTT])) & (df2["endpoint"] == 1)
468
+ ]
469
+ df2 = df2.sort_values(["subject_identifier", "fbg_datetime"])
470
+ df2 = df2.reset_index(drop=True)
471
+ df2 = df2.set_index(["subject_identifier"])
472
+ df2 = df2[~df2.index.duplicated(keep="first")]
473
+ df2 = df2.reset_index(drop=False)
474
+
475
+ # create new DF with ONE row per subject for those that reached
476
+ # the endpoint (endpoint=1) by merging two DFs above.
477
+ self.endpoint_only_df = pd.concat([df1, df2])
478
+ self.endpoint_only_df = self.endpoint_only_df.reset_index(drop=True)
479
+
480
+ self.df = pd.merge(
481
+ self.df,
482
+ self.endpoint_only_df[["subject_identifier", "visit_code", "endpoint"]],
483
+ on=["subject_identifier", "visit_code"],
484
+ how="left",
485
+ suffixes=("", "_y"),
486
+ )
487
+ self.df = self.df.sort_values(by=["subject_identifier", "fbg_datetime"])
488
+ self.df = self.df.reset_index(drop=True)
489
+
490
+ def to_model(self):
491
+ """Write endpoint_only_df to the Endpoints model"""
492
+ df = self.endpoint_only_df
493
+ model = "meta_reports.endpoints"
494
+ now = get_utcnow()
495
+ model_cls = django_apps.get_model(model)
496
+ if self.subject_identifiers:
497
+ model_cls.objects.filter(subject_identifier__in=self.subject_identifiers).delete()
498
+ else:
499
+ model_cls.objects.all().delete()
500
+ created = 0
501
+ if not df.empty:
502
+ df["fbg_datetime"] = df["fbg_datetime"].dt.tz_localize("UTC")
503
+ df["baseline_datetime"] = df["baseline_datetime"].dt.tz_localize("UTC")
504
+ data = [
505
+ model_cls(
506
+ subject_identifier=row["subject_identifier"],
507
+ site_id=row["site_id"],
508
+ baseline_date=(
509
+ None if pd.isna(row["baseline_datetime"]) else row["baseline_datetime"]
510
+ ),
511
+ visit_code=None if pd.isna(row["visit_code"]) else row["visit_code"],
512
+ fbg_value=(None if pd.isna(row["fbg_value"]) else row["fbg_value"]),
513
+ ogtt_value=None if pd.isna(row["ogtt_value"]) else row["ogtt_value"],
514
+ fbg_date=(None if pd.isna(row["fbg_datetime"]) else row["fbg_datetime"]),
515
+ fasting=(None if pd.isna(row["fasting"]) else row["fasting"]),
516
+ endpoint_label=(
517
+ None if pd.isna(row["endpoint_label"]) else row["endpoint_label"]
518
+ ),
519
+ offstudy_date=(
520
+ None if pd.isna(row["offstudy_datetime"]) else row["offstudy_datetime"]
521
+ ),
522
+ offstudy_reason=(
523
+ None if pd.isna(row["offstudy_reason"]) else row["offstudy_reason"]
524
+ ),
525
+ report_model=model,
526
+ created=now,
527
+ )
528
+ for _, row in df.iterrows()
529
+ ]
530
+ created = len(model_cls.objects.bulk_create(data))
531
+ return created
@@ -0,0 +1,2 @@
1
+ from .get_glucose_tested_only_df import get_glucose_tested_only_df
2
+ from .get_screening_df import get_screening_df
@@ -0,0 +1,20 @@
1
+ import pandas as pd
2
+
3
+ from .get_screening_df import get_screening_df
4
+
5
+
6
+ def get_glucose_tested_only_df(df: pd.DataFrame | None = None):
7
+ """ "Returns a DF of 5618 records"""
8
+ df = pd.DataFrame() if not hasattr(df, "empty") else df
9
+ if df.empty:
10
+ df = get_screening_df()
11
+ # condition where subject is eligible P1/P2 and has any type of glucose test
12
+ cond_glu = (
13
+ (df["fbg_value"].notna())
14
+ | (df["ogtt_value"].notna())
15
+ | (df["fbg2_value"].notna())
16
+ | (df["ogtt2_value"].notna())
17
+ )
18
+ cond = (df["eligible_part_one"] == "Yes") & (df["eligible_part_two"] == "Yes") & cond_glu
19
+ df = df[cond]
20
+ return df