clinicedc 2.0.3__py3-none-any.whl → 2.0.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of clinicedc might be problematic. Click here for more details.

Files changed (478) hide show
  1. {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/METADATA +41 -45
  2. {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/RECORD +478 -478
  3. edc_action_item/action.py +76 -54
  4. edc_action_item/action_item_notification.py +1 -3
  5. edc_action_item/action_with_notification.py +4 -4
  6. edc_action_item/create_action_item.py +2 -2
  7. edc_action_item/create_or_update_action_type.py +1 -1
  8. edc_action_item/data_fixers.py +4 -5
  9. edc_action_item/delete_action_item.py +0 -1
  10. edc_action_item/modeladmin_mixins.py +2 -4
  11. edc_action_item/modelform_mixins/modelform_mixins.py +1 -1
  12. edc_action_item/models/action_item.py +53 -38
  13. edc_action_item/models/action_model_mixin.py +17 -17
  14. edc_action_item/models/action_type.py +33 -13
  15. edc_action_item/models/reference.py +3 -2
  16. edc_action_item/site_action_items.py +13 -14
  17. edc_action_item/stubs.py +9 -9
  18. edc_action_item/templatetags/action_item_extras.py +2 -2
  19. edc_action_item/view_utils/action_item_button.py +3 -3
  20. edc_action_item/view_utils/action_item_popover_list_item.py +4 -4
  21. edc_adherence/form_validator_mixin.py +1 -1
  22. edc_adverse_event/action_items/ae_followup_action.py +1 -1
  23. edc_adverse_event/action_items/ae_initial_action.py +1 -1
  24. edc_adverse_event/action_items/ae_susar_action.py +1 -1
  25. edc_adverse_event/action_items/ae_tmg_action.py +1 -1
  26. edc_adverse_event/action_items/death_report_action.py +1 -2
  27. edc_adverse_event/action_items/death_report_tmg_action.py +1 -1
  28. edc_adverse_event/action_items/death_report_tmg_second_action.py +1 -1
  29. edc_adverse_event/action_items/hospitalization_action.py +1 -1
  30. edc_adverse_event/form_validator_mixins/death_report_form_validator.py +3 -3
  31. edc_adverse_event/form_validator_mixins/requires_death_report_form_validator_mixin.py +3 -4
  32. edc_adverse_event/form_validators/death_report_tmg.py +1 -1
  33. edc_adverse_event/model_mixins/ae_followup/ae_followup_methods_model_mixin.py +3 -3
  34. edc_adverse_event/model_mixins/ae_followup/ae_followup_model_mixin.py +3 -3
  35. edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +0 -1
  36. edc_adverse_event/model_mixins/ae_initial/ae_initial_methods_model_mixin.py +3 -3
  37. edc_adverse_event/model_mixins/ae_initial/ae_initial_model_mixin.py +3 -3
  38. edc_adverse_event/model_mixins/ae_special_interest/aesi_methods_model_mixin.py +4 -4
  39. edc_adverse_event/model_mixins/ae_special_interest/aesi_model_mixin.py +3 -3
  40. edc_adverse_event/model_mixins/ae_susar/ae_susar_methods_model_mixin.py +4 -4
  41. edc_adverse_event/model_mixins/ae_susar/ae_susar_model_mixin.py +3 -3
  42. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +4 -5
  43. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +4 -4
  44. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_model_mixin.py +3 -3
  45. edc_adverse_event/model_mixins/death_report/death_report_extra_fields_model_mixin.py +2 -3
  46. edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +11 -11
  47. edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +9 -11
  48. edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +7 -6
  49. edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +0 -1
  50. edc_adverse_event/modeladmin_mixins/ae_followup_admin_mixin.py +9 -11
  51. edc_adverse_event/modeladmin_mixins/ae_initial_admin_mixin.py +4 -6
  52. edc_adverse_event/modeladmin_mixins/modeladmin_mixins.py +1 -1
  53. edc_adverse_event/modeladmin_mixins/utils.py +4 -4
  54. edc_adverse_event/models/signals.py +7 -19
  55. edc_adverse_event/pdf_reports/death_pdf_report.py +8 -9
  56. edc_adverse_event/templatetags/edc_adverse_event_extras.py +10 -20
  57. edc_adverse_event/urls.py +7 -3
  58. edc_adverse_event/utils.py +2 -2
  59. edc_adverse_event/view_utils/tmg_button.py +4 -4
  60. edc_appconfig/system_checks.py +1 -1
  61. edc_appointment/appointment_status_updater.py +14 -15
  62. edc_appointment/creators/appointment_creator.py +7 -11
  63. edc_appointment/creators/appointments_creator.py +1 -1
  64. edc_appointment/creators/unscheduled_appointment_creator.py +12 -13
  65. edc_appointment/form_validator_mixins/next_appointment_crf_form_validator_mixin.py +1 -3
  66. edc_appointment/form_validator_mixins/window_period_form_validator_mixin.py +7 -6
  67. edc_appointment/form_validators/appointment_form_validator.py +2 -4
  68. edc_appointment/form_validators/utils.py +4 -4
  69. edc_appointment/managers.py +4 -4
  70. edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -2
  71. edc_appointment/model_mixins/appointment_model_mixin.py +5 -5
  72. edc_appointment/model_mixins/window_period_model_mixin.py +1 -1
  73. edc_appointment/models/appointment.py +1 -1
  74. edc_appointment/skip_appointments.py +5 -6
  75. edc_appointment/stubs.py +12 -12
  76. edc_appointment/utils.py +41 -47
  77. edc_appointment/view_utils/appointment_button.py +3 -5
  78. edc_auth/admin/role_admin.py +5 -7
  79. edc_auth/auth_objects/default_roles.py +1 -3
  80. edc_auth/auth_updater/auth_updater.py +5 -7
  81. edc_auth/auth_updater/group_updater.py +8 -8
  82. edc_auth/auth_updater/role_updater.py +1 -2
  83. edc_auth/get_app_codenames.py +1 -3
  84. edc_auth/import_users.py +19 -19
  85. edc_auth/models/role.py +4 -3
  86. edc_auth/password_setter.py +6 -7
  87. edc_auth/send_new_credentials_to_user.py +2 -3
  88. edc_auth/site_auths.py +3 -3
  89. edc_consent/actions.py +4 -5
  90. edc_consent/consent_definition.py +8 -11
  91. edc_consent/consent_definition_extension.py +3 -3
  92. edc_consent/form_validators/__init__.py +1 -1
  93. edc_consent/model_mixins/__init__.py +2 -2
  94. edc_consent/model_mixins/consent_version_model_mixin.py +1 -1
  95. edc_consent/modeladmin_mixins/consent_model_admin_mixin.py +1 -2
  96. edc_consent/modelform_mixins/consent_modelform_mixin/consent_modelform_validation_mixin.py +3 -5
  97. edc_consent/site_consents.py +10 -15
  98. edc_consent/stubs.py +2 -2
  99. edc_consent/utils.py +1 -1
  100. edc_constants/utils.py +2 -4
  101. edc_crf/crf_form_validator_mixins.py +2 -2
  102. edc_crf/model_mixins/crf_no_manager_model_mixin.py +2 -2
  103. edc_crf/model_mixins/crf_status_model_mixin.py +1 -1
  104. edc_crf/models/crf_status.py +10 -12
  105. edc_crf/update_crf_status_command.py +1 -3
  106. edc_dashboard/management/commands/update_search_slugs.py +8 -11
  107. edc_dashboard/templatetags/edc_dashboard_extras.py +1 -1
  108. edc_dashboard/url_config.py +3 -3
  109. edc_dashboard/utils.py +3 -4
  110. edc_dashboard/views/dashboard_view.py +1 -1
  111. edc_data_manager/models/data_dictionary.py +1 -2
  112. edc_data_manager/models/data_query.py +3 -3
  113. edc_data_manager/models/query_rule.py +2 -2
  114. edc_data_manager/tasks.py +0 -2
  115. edc_device/device.py +1 -1
  116. edc_device/view_mixins.py +1 -1
  117. edc_document_status/fieldsets.py +1 -3
  118. edc_document_status/model_mixins.py +2 -2
  119. edc_document_status/modeladmin_mixins.py +1 -4
  120. edc_egfr/admin/egfr_drop_notification_admin_mixin.py +5 -7
  121. edc_egfr/egfr.py +6 -7
  122. edc_egfr/get_drop_notification_model.py +1 -1
  123. edc_egfr/model_mixins/egfr_drop_notification_model_mixin.py +1 -1
  124. edc_export/archive_exporter.py +26 -27
  125. edc_export/exportables.py +2 -3
  126. edc_export/management/commands/import_receipts.py +6 -6
  127. edc_export/model_exporter/file_history_updater.py +1 -1
  128. edc_export/model_exporter/model_exporter.py +1 -1
  129. edc_export/model_exporter/value_getter.py +6 -6
  130. edc_export/model_mixins/notification_model_mixin.py +4 -4
  131. edc_export/models/data_request.py +3 -3
  132. edc_export/models/data_request_history.py +2 -2
  133. edc_export/models/export_receipt.py +1 -1
  134. edc_export/models/file_history.py +5 -5
  135. edc_export/models/plan.py +4 -4
  136. edc_export/models/upload_export_receipt_file.py +2 -2
  137. edc_export/utils.py +1 -1
  138. edc_facility/facility.py +6 -6
  139. edc_facility/holidays.py +2 -5
  140. edc_facility/import_holidays.py +6 -6
  141. edc_facility/model_mixins.py +1 -1
  142. edc_facility/models/holiday.py +1 -1
  143. edc_facility/utils.py +3 -3
  144. edc_fieldsets/fieldsets.py +1 -1
  145. edc_form_describer/forms_reference.py +5 -8
  146. edc_form_describer/make_forms_reference.py +1 -1
  147. edc_form_describer/management/commands/make_forms_reference.py +1 -1
  148. edc_form_label/custom_label_condition.py +1 -1
  149. edc_form_label/form_label.py +2 -2
  150. edc_form_runners/exceptions.py +1 -1
  151. edc_form_runners/models/issue.py +3 -2
  152. edc_form_runners/site.py +2 -2
  153. edc_form_runners/templatetags/form_runners_extras.py +1 -1
  154. edc_form_runners/utils.py +5 -5
  155. edc_form_validators/applicable_field_validator.py +32 -32
  156. edc_form_validators/base_form_validator.py +1 -1
  157. edc_form_validators/extra_mixins/study_day_form_validator.py +1 -1
  158. edc_form_validators/many_to_many_field_validator.py +38 -43
  159. edc_form_validators/other_specify_field_validator.py +9 -17
  160. edc_form_validators/required_field_validator.py +34 -39
  161. edc_form_validators/test_case_mixin.py +5 -5
  162. edc_identifier/admin.py +1 -3
  163. edc_identifier/identifier.py +2 -3
  164. edc_identifier/model_mixins.py +5 -8
  165. edc_identifier/research_identifier.py +10 -12
  166. edc_identifier/short_identifier.py +1 -1
  167. edc_identifier/simple_identifier.py +22 -22
  168. edc_identifier/utils.py +1 -1
  169. edc_lab/admin/fieldsets.py +7 -9
  170. edc_lab/admin/modeladmin_mixins.py +5 -6
  171. edc_lab/form_validators/requisition_form_validator_mixin.py +2 -3
  172. edc_lab/forms/box_form.py +5 -11
  173. edc_lab/identifiers/aliquot_identifier.py +5 -8
  174. edc_lab/identifiers/prefix.py +2 -5
  175. edc_lab/lab/aliquot_creator.py +1 -2
  176. edc_lab/lab/aliquot_type.py +2 -4
  177. edc_lab/lab/manifest.py +5 -7
  178. edc_lab/lab/requisition_panel.py +2 -4
  179. edc_lab/lab/requisition_panel_group.py +5 -7
  180. edc_lab/model_mixins/requisition/requisition_model_mixin.py +5 -4
  181. edc_lab/model_mixins/shipping/manifest_model_mixin.py +6 -6
  182. edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -3
  183. edc_lab/models/aliquot.py +1 -1
  184. edc_lab/models/box.py +2 -2
  185. edc_lab/models/box_item.py +1 -1
  186. edc_lab/models/box_type.py +1 -1
  187. edc_lab/models/manifest/manifest_item.py +1 -1
  188. edc_lab/pdf_reports/manifest_pdf_report.py +3 -7
  189. edc_lab/site_labs.py +3 -3
  190. edc_lab_dashboard/dashboard_templates.py +1 -1
  191. edc_lab_dashboard/view_mixins/box_view_mixin.py +4 -9
  192. edc_lab_dashboard/views/action_views/action_view.py +1 -2
  193. edc_lab_dashboard/views/action_views/manage_manifest_view.py +1 -1
  194. edc_lab_dashboard/views/action_views/manifest_view.py +9 -11
  195. edc_lab_dashboard/views/action_views/pack_view.py +11 -14
  196. edc_lab_results/calculate_missing.py +2 -2
  197. edc_lab_results/fieldsets.py +6 -6
  198. edc_lab_results/model_mixin_factories/__init__.py +2 -2
  199. edc_lab_results/model_mixin_factories/reportable_result_model_mixin_factory.py +7 -9
  200. edc_lab_results/model_mixin_factories/result_model_mixin_factory.py +7 -9
  201. edc_lab_results/model_mixins/fbg_model_mixin.py +1 -1
  202. edc_lab_results/model_mixins/glucose_model_mixin.py +1 -1
  203. edc_label/admin.py +1 -3
  204. edc_label/label.py +2 -4
  205. edc_label/label_template.py +1 -1
  206. edc_label/subject_label.py +1 -3
  207. edc_list_data/admin.py +3 -5
  208. edc_list_data/load_list_data.py +1 -1
  209. edc_list_data/load_model_data.py +1 -3
  210. edc_list_data/model_mixins.py +3 -5
  211. edc_list_data/preload_data.py +2 -4
  212. edc_list_data/site_list_data.py +6 -7
  213. edc_listboard/filters/listboard_filter.py +2 -2
  214. edc_listboard/views/listboard_view.py +1 -3
  215. edc_locator/models.py +2 -2
  216. edc_locator/view_mixins/subject_locator_view_mixins.py +2 -2
  217. edc_ltfu/action_items.py +1 -1
  218. edc_ltfu/model_mixins.py +0 -2
  219. edc_ltfu/models.py +4 -4
  220. edc_metadata/admin/modeladmin_mixins.py +1 -1
  221. edc_metadata/admin/requisition_metadata.py +2 -4
  222. edc_metadata/metadata/crf_metadata_getter.py +1 -3
  223. edc_metadata/metadata/requisition_metadata_getter.py +1 -3
  224. edc_metadata/metadata_handler.py +2 -2
  225. edc_metadata/metadata_helper/metadata_helper_mixin.py +2 -3
  226. edc_metadata/metadata_mixins/source_model_metadata_mixin.py +2 -2
  227. edc_metadata/metadata_refresher.py +1 -1
  228. edc_metadata/metadata_rules/crf/crf_rule_group.py +3 -5
  229. edc_metadata/metadata_rules/logic.py +1 -1
  230. edc_metadata/metadata_rules/requisition/requisition_rule.py +4 -4
  231. edc_metadata/metadata_rules/requisition/requisition_rule_group.py +2 -2
  232. edc_metadata/metadata_rules/rule_evaluator.py +5 -6
  233. edc_metadata/metadata_rules/rule_group_metaclass.py +2 -3
  234. edc_metadata/metadata_rules/site.py +6 -7
  235. edc_metadata/metadata_updater.py +2 -2
  236. edc_metadata/metadata_wrappers/metadata_wrapper.py +4 -4
  237. edc_metadata/model_mixins/creates/creates_metadata_model_mixin.py +6 -7
  238. edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +2 -2
  239. edc_metadata/model_mixins/updates/updates_metadata_model_mixin.py +2 -2
  240. edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +2 -2
  241. edc_metadata/models/crf_metadata.py +27 -29
  242. edc_metadata/models/crf_metadata_model_mixin.py +1 -1
  243. edc_metadata/models/requisition_metadata.py +29 -31
  244. edc_metadata/stubs.py +17 -17
  245. edc_metadata/utils.py +4 -4
  246. edc_model/__init__.py +2 -2
  247. edc_model/models/historical_records.py +2 -2
  248. edc_model/models/signals.py +1 -1
  249. edc_model/models/url_model_mixin.py +1 -1
  250. edc_model/utils.py +0 -2
  251. edc_model_admin/dashboard/model_admin_dashboard_mixin.py +1 -3
  252. edc_model_admin/history/model_admin_simple_history.py +7 -9
  253. edc_model_admin/mixins/base_model_admin_redirect_mixin.py +4 -6
  254. edc_model_admin/mixins/model_admin_limit_to_selected_foreignkey.py +2 -2
  255. edc_model_admin/mixins/model_admin_model_redirect_mixin.py +2 -10
  256. edc_model_admin/mixins/model_admin_next_url_redirect_mixin.py +8 -9
  257. edc_model_admin/utils.py +6 -9
  258. edc_model_form/mixins/__init__.py +1 -1
  259. edc_model_form/mixins/base_model_form_mixin.py +1 -1
  260. edc_model_to_dataframe/model_to_dataframe.py +2 -4
  261. edc_navbar/site_navbars.py +2 -2
  262. edc_navbar/system_checks.py +1 -1
  263. edc_notification/mailing_list_manager.py +5 -8
  264. edc_notification/management/commands/list_recipients_by_notification.py +1 -1
  265. edc_notification/models/__init__.py +4 -2
  266. edc_notification/notification/graded_event_notification.py +2 -4
  267. edc_notification/notification/model_notification.py +1 -3
  268. edc_notification/notification/notification.py +14 -17
  269. edc_notification/site_notifications.py +7 -7
  270. edc_notification/stubs.py +6 -6
  271. edc_notification/update_mailing_lists_in_m2m.py +2 -2
  272. edc_offstudy/action_items.py +2 -2
  273. edc_offstudy/model_mixins/offstudy_model_mixin.py +1 -1
  274. edc_offstudy/models.py +1 -1
  275. edc_pdf_reports/crf_pdf_report.py +2 -2
  276. edc_pdf_reports/model_mixins.py +2 -2
  277. edc_pdf_reports/report.py +4 -5
  278. edc_pdf_reports/utils.py +1 -1
  279. edc_pdutils/dataframes/get_subject_consent.py +1 -3
  280. edc_pdutils/df_exporters/csv_exporter.py +5 -7
  281. edc_pdutils/df_exporters/tables_exporter.py +2 -2
  282. edc_pdutils/df_handlers/crf_df_handler.py +1 -2
  283. edc_pdutils/dialects/crf_dialect.py +3 -3
  284. edc_pdutils/management/commands/export_models.py +6 -7
  285. edc_pdutils/site_values_mappings.py +2 -2
  286. edc_pdutils/utils/datetime_to_date.py +1 -2
  287. edc_pdutils/utils/refresh_model_from_dataframe.py +1 -3
  288. edc_pdutils/utils/table_names.py +2 -4
  289. edc_pdutils/utils/undash.py +1 -1
  290. edc_pharmacy/admin/medication/assignment_admin.py +2 -4
  291. edc_pharmacy/admin/medication/dosage_guideline_admin.py +2 -4
  292. edc_pharmacy/admin/medication/formulation_admin.py +3 -5
  293. edc_pharmacy/admin/medication/medication_admin.py +3 -5
  294. edc_pharmacy/admin/prescription/rx_refill_admin.py +7 -9
  295. edc_pharmacy/admin/stock/lot_admin.py +5 -7
  296. edc_pharmacy/admin/stock/order_admin.py +2 -2
  297. edc_pharmacy/admin/stock/order_item_admin.py +6 -6
  298. edc_pharmacy/admin/stock/receive_admin.py +1 -1
  299. edc_pharmacy/admin/stock/receive_item_admin.py +2 -2
  300. edc_pharmacy/admin/stock/stock_request_admin.py +4 -6
  301. edc_pharmacy/dosage_calculator.py +4 -4
  302. edc_pharmacy/form_validators/crf/study_medication_form_validator.py +8 -8
  303. edc_pharmacy/forms/stock/stock_request_form.py +2 -4
  304. edc_pharmacy/model_mixins/study_medication_crf_model_mixin.py +2 -2
  305. edc_pharmacy/models/medication/formulation.py +3 -4
  306. edc_pharmacy/models/medication/medication.py +1 -2
  307. edc_pharmacy/models/prescription/rx.py +2 -2
  308. edc_pharmacy/models/prescription/rx_refill.py +7 -9
  309. edc_pharmacy/models/reports/stock_availability.py +3 -4
  310. edc_pharmacy/models/stock/confirmation_at_site.py +1 -3
  311. edc_pharmacy/models/stock/order.py +1 -2
  312. edc_pharmacy/models/stock/receive.py +3 -4
  313. edc_pharmacy/models/stock/receive_item.py +2 -3
  314. edc_pharmacy/models/stock/stock.py +1 -2
  315. edc_pharmacy/models/stock/stock_adjustment.py +1 -2
  316. edc_pharmacy/models/stock/stock_request.py +4 -5
  317. edc_pharmacy/models/storage/box.py +1 -1
  318. edc_pharmacy/models/storage/items/container_model_mixin.py +1 -1
  319. edc_pharmacy/models/storage/room.py +1 -1
  320. edc_pharmacy/models/storage/shelf.py +1 -1
  321. edc_pharmacy/models/storage/utils.py +15 -16
  322. edc_pharmacy/prescribe/create_prescription.py +5 -5
  323. edc_pharmacy/refill/refill_creator.py +1 -1
  324. edc_pharmacy/sample_usb_printing/usb_printing.py +1 -1
  325. edc_pharmacy/utils/__init__.py +1 -1
  326. edc_pharmacy/utils/confirm_stock.py +3 -3
  327. edc_pharmacy/utils/confirm_stock_at_site.py +9 -8
  328. edc_pharmacy/utils/dispense.py +5 -8
  329. edc_pharmacy/utils/format_qty.py +3 -3
  330. edc_pharmacy/utils/get_codenames.py +1 -1
  331. edc_pharmacy/utils/miscellaneous.py +1 -1
  332. edc_pharmacy/utils/process_repack_request.py +18 -19
  333. edc_pharmacy/utils/process_repack_request_queryset.py +0 -2
  334. edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
  335. edc_pharmacy/views/add_to_storage_bin_view.py +1 -1
  336. edc_pharmacy/views/allocate_to_subject_view.py +2 -6
  337. edc_pharmacy/views/confirm_stock_from_instance_view.py +4 -4
  338. edc_pharmacy/views/confirm_stock_from_queryset_view.py +1 -5
  339. edc_pharmacy/views/confirmation_at_site_view.py +2 -3
  340. edc_pharmacy/views/dispense_view.py +1 -1
  341. edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
  342. edc_pharmacy/views/print_labels_view.py +30 -31
  343. edc_pharmacy/views/transfer_stock_view.py +1 -1
  344. edc_prn/prn.py +1 -1
  345. edc_prn/site_prn_forms.py +1 -2
  346. edc_protocol_incident/action_items.py +2 -2
  347. edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +3 -3
  348. edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +3 -5
  349. edc_protocol_incident/modeladmin_mixins.py +3 -5
  350. edc_protocol_incident/models/protocol_deviation_violation.py +5 -5
  351. edc_protocol_incident/models/protocol_incident.py +5 -5
  352. edc_pylabels/site_label_configs.py +5 -5
  353. edc_qareports/model_mixins/qa_report_model_mixin.py +4 -2
  354. edc_qareports/models/qa_reports_log.py +1 -2
  355. edc_qareports/utils.py +1 -2
  356. edc_randomization/admin.py +3 -5
  357. edc_randomization/auth_objects.py +2 -3
  358. edc_randomization/blinding.py +1 -1
  359. edc_randomization/constants.py +2 -4
  360. edc_randomization/model_mixins.py +3 -3
  361. edc_randomization/randomization_list_importer.py +13 -14
  362. edc_randomization/randomization_list_verifier.py +11 -13
  363. edc_randomization/randomizer.py +2 -2
  364. edc_randomization/system_checks.py +1 -2
  365. edc_randomization/utils.py +5 -5
  366. edc_refusal/admin.py +1 -1
  367. edc_refusal/model_mixins.py +1 -1
  368. edc_refusal/utils.py +1 -1
  369. edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +2 -2
  370. edc_registration/modeladmin_mixins.py +4 -7
  371. edc_registration/models/registered_subject.py +7 -9
  372. edc_registration/utils.py +3 -4
  373. edc_reportable/data/grading_data/daids_july_2017.py +3 -3
  374. edc_reportable/evaluator.py +5 -5
  375. edc_reportable/formula.py +1 -1
  376. edc_reportable/reference_range_evaluator.py +3 -3
  377. edc_reportable/utils/convert_units.py +10 -12
  378. edc_reportable/utils/grading_data_model_cls.py +2 -2
  379. edc_reportable/utils/grading_exception_model_cls.py +2 -2
  380. edc_reportable/utils/molecular_weight_model_cls.py +2 -2
  381. edc_reportable/utils/normal_data_model_cls.py +2 -2
  382. edc_reportable/utils/reference_range_colllection_model_cls.py +2 -2
  383. edc_screening/age_evaluator.py +2 -4
  384. edc_screening/eligibility.py +1 -1
  385. edc_screening/form_validator_mixins.py +2 -2
  386. edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
  387. edc_screening/screening_eligibility.py +1 -1
  388. edc_screening/utils.py +4 -6
  389. edc_search/model_mixins.py +1 -1
  390. edc_search/search_slug.py +1 -3
  391. edc_search/updater.py +1 -1
  392. edc_sites/admin/site_model_admin_mixin.py +2 -2
  393. edc_sites/model_mixins/site_model_mixin.py +1 -2
  394. edc_sites/modelform_mixins.py +2 -2
  395. edc_sites/models/__init__.py +1 -1
  396. edc_sites/models/site_profile.py +4 -4
  397. edc_sites/site.py +24 -32
  398. edc_sites/system_checks.py +1 -1
  399. edc_sites/utils/get_message_text.py +1 -1
  400. edc_sites/utils/valid_site_for_subject_or_raise.py +5 -6
  401. edc_subject_dashboard/requisition_report.py +4 -5
  402. edc_subject_dashboard/requisition_verifier.py +4 -2
  403. edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +16 -17
  404. edc_subject_dashboard/view_utils/__init__.py +1 -1
  405. edc_subject_dashboard/view_utils/crf_button.py +1 -3
  406. edc_subject_dashboard/view_utils/subject_consent_dashboard_button.py +2 -2
  407. edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +2 -2
  408. edc_subject_dashboard/view_utils/timepoint_status_button.py +1 -4
  409. edc_subject_dashboard/views/requisition_print_actions_view.py +2 -2
  410. edc_subject_dashboard/views/subject_dashboard_view.py +1 -1
  411. edc_timepoint/model_mixins.py +2 -2
  412. edc_transfer/action_items.py +1 -1
  413. edc_transfer/model_mixins.py +4 -3
  414. edc_transfer/modeladmin_mixins.py +3 -6
  415. edc_unblinding/action_items.py +2 -2
  416. edc_unblinding/models/unblinding_request.py +3 -3
  417. edc_unblinding/models/unblinding_review.py +3 -3
  418. edc_utils/__init__.py +6 -5
  419. edc_utils/age.py +1 -1
  420. edc_utils/celery.py +3 -8
  421. edc_utils/get_static_file.py +1 -1
  422. edc_utils/text.py +5 -6
  423. edc_view_utils/__init__.py +3 -3
  424. edc_view_utils/dashboard_model_button.py +4 -4
  425. edc_view_utils/model_button.py +7 -8
  426. edc_view_utils/perms.py +3 -3
  427. edc_visit_schedule/action_items.py +2 -2
  428. edc_visit_schedule/admin/list_filters.py +11 -9
  429. edc_visit_schedule/admin/subject_schedule_history_admin.py +13 -15
  430. edc_visit_schedule/admin/visit_schedule_admin.py +7 -7
  431. edc_visit_schedule/fieldsets.py +4 -6
  432. edc_visit_schedule/management/commands/find_invalid_onschedules.py +1 -1
  433. edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +3 -1
  434. edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +1 -1
  435. edc_visit_schedule/modelform_mixins/__init__.py +1 -1
  436. edc_visit_schedule/modelform_mixins/off_schedule_modelform_mixin.py +1 -2
  437. edc_visit_schedule/models/subject_schedule_history.py +2 -1
  438. edc_visit_schedule/models/visit_schedule.py +2 -2
  439. edc_visit_schedule/schedule/schedule.py +11 -12
  440. edc_visit_schedule/schedule/visit_collection.py +4 -3
  441. edc_visit_schedule/schedule/window.py +19 -12
  442. edc_visit_schedule/site_visit_schedules.py +9 -9
  443. edc_visit_schedule/subject_schedule.py +6 -7
  444. edc_visit_schedule/system_checks.py +8 -4
  445. edc_visit_schedule/view_mixins.py +1 -1
  446. edc_visit_schedule/visit/crf.py +3 -7
  447. edc_visit_schedule/visit/requisition.py +2 -2
  448. edc_visit_schedule/visit/visit.py +6 -7
  449. edc_visit_schedule/visit/window_period.py +8 -8
  450. edc_visit_schedule/visit_schedule/schedules_collection.py +2 -5
  451. edc_visit_tracking/action_items.py +11 -13
  452. edc_visit_tracking/form_validators/visit_form_validator.py +5 -5
  453. edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -4
  454. edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
  455. edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -3
  456. edc_visit_tracking/model_mixins/utils.py +1 -1
  457. edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +2 -2
  458. edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +3 -3
  459. edc_visit_tracking/modeladmin_mixins/crf_model_admin_mixin.py +6 -4
  460. edc_visit_tracking/modeladmin_mixins/visit_model_admin_mixin.py +6 -7
  461. edc_visit_tracking/modelform_mixins/crf/visit_tracking_crf_modelform_mixin.py +4 -5
  462. edc_visit_tracking/modelform_mixins/visit_tracking_modelform_mixin.py +3 -4
  463. edc_visit_tracking/models/subject_visit.py +1 -1
  464. edc_visit_tracking/models/subject_visit_missed.py +1 -1
  465. edc_visit_tracking/stubs.py +7 -7
  466. edc_visit_tracking/typing_stubs.py +11 -11
  467. edc_visit_tracking/utils.py +5 -5
  468. edc_visit_tracking/view_utils/related_visit_button.py +5 -5
  469. edc_vitals/calculators/bmi.py +1 -1
  470. edc_vitals/form_validators/blood_pressure_form_validator_mixin.py +8 -12
  471. edc_vitals/form_validators/bmi_form_validator_mixin.py +1 -1
  472. edc_vitals/form_validators/weight_height_with_bmi_form_validator_mixin.py +5 -2
  473. edc_vitals/model_mixins/blood_pressure_model_mixin.py +3 -4
  474. edc_vitals/model_mixins/weight_height_bmi_model_mixin.py +4 -4
  475. edc_vitals/utils.py +1 -1
  476. edc_vitals/validators.py +1 -1
  477. {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/WHEEL +0 -0
  478. {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,5 @@
1
1
  import sys
2
- from typing import Any, List, Optional
2
+ from typing import Any
3
3
  from warnings import warn
4
4
 
5
5
  from django.apps import apps as django_apps
@@ -36,13 +36,13 @@ class GroupUpdater:
36
36
 
37
37
  def __init__(
38
38
  self,
39
- groups: Optional[dict] = None,
39
+ groups: dict | None = None,
40
40
  apps=None,
41
41
  verbose=None,
42
- pii_models: Optional[list] = None,
43
- custom_permissions_tuples: Optional[dict] = None,
42
+ pii_models: list | None = None,
43
+ custom_permissions_tuples: dict | None = None,
44
44
  warn_only=None,
45
- codename_prefixes: Optional[list] = None,
45
+ codename_prefixes: list | None = None,
46
46
  ):
47
47
  self.apps = apps or django_apps
48
48
  self.content_type_model_cls = self.apps.get_model("contenttypes.contenttype")
@@ -102,7 +102,7 @@ class GroupUpdater:
102
102
  group.permissions.add(permission)
103
103
 
104
104
  def get_permissions_qs_from_codenames(
105
- self, codenames: List[Any], allow_multiple_objects: Optional[bool] = None
105
+ self, codenames: list[Any], allow_multiple_objects: bool | None = None
106
106
  ):
107
107
  """Returns a list of permission model instances for the given
108
108
  codenames.
@@ -281,8 +281,8 @@ class GroupUpdater:
281
281
  def remove_permissions_by_codenames(
282
282
  self,
283
283
  group: Any = None,
284
- codenames: List[str] = None,
285
- allow_multiple_objects: Optional[bool] = None,
284
+ codenames: list[str] = None,
285
+ allow_multiple_objects: bool | None = None,
286
286
  ):
287
287
  """Remove the given codenames from the given group."""
288
288
  permissions = self.get_permissions_qs_from_codenames(
@@ -1,5 +1,4 @@
1
1
  import sys
2
- from typing import Optional
3
2
 
4
3
  from django.apps import apps as django_apps
5
4
  from django.core.exceptions import ObjectDoesNotExist
@@ -15,7 +14,7 @@ class RoleUpdaterError(Exception):
15
14
  class RoleUpdater:
16
15
  def __init__(
17
16
  self,
18
- roles: Optional[dict] = None,
17
+ roles: dict | None = None,
19
18
  verbose=None,
20
19
  ):
21
20
  self.roles = roles
@@ -70,9 +70,7 @@ def get_codename(
70
70
  autocomplete_models = autocomplete_models or []
71
71
  label_lower: str = model_cls._meta.label_lower
72
72
  model_name: str = model_cls._meta.model_name
73
- if "historical" in label_lower:
74
- codenames.append(f"{app_name}.view_{model_name}")
75
- elif label_lower in autocomplete_models:
73
+ if "historical" in label_lower or label_lower in autocomplete_models:
76
74
  codenames.append(f"{app_name}.view_{model_name}")
77
75
  else:
78
76
  permissions = override_permissions or model_cls._meta.default_permissions
edc_auth/import_users.py CHANGED
@@ -3,7 +3,7 @@ import os
3
3
  import re
4
4
  from datetime import datetime
5
5
  from string import Template
6
- from typing import Any, List, Optional
6
+ from typing import Any
7
7
 
8
8
  from django.contrib.auth.models import User
9
9
  from django.contrib.sites.models import Site
@@ -67,12 +67,12 @@ fieldnames = [
67
67
 
68
68
  def import_users(
69
69
  path: str,
70
- resource_name: Optional[str] = None,
71
- send_email_to_user: Optional[Any] = None,
72
- resend_as_newly_created: Optional[Any] = None,
73
- verbose: Optional[Any] = None,
74
- export_to_file: Optional[Any] = None,
75
- limit_to_username: Optional[str] = None,
70
+ resource_name: str | None = None,
71
+ send_email_to_user: Any | None = None,
72
+ resend_as_newly_created: Any | None = None,
73
+ verbose: Any | None = None,
74
+ export_to_file: Any | None = None,
75
+ limit_to_username: str | None = None,
76
76
  **kwargs,
77
77
  ):
78
78
  """Import users from a CSV file with columns:
@@ -140,20 +140,20 @@ class UserImporter:
140
140
  email: str = None,
141
141
  alternate_email: str = None,
142
142
  mobile: str = None,
143
- site_names: List[str] = None,
144
- role_names: List[str] = None,
143
+ site_names: list[str] = None,
144
+ role_names: list[str] = None,
145
145
  is_active: bool = None,
146
146
  is_staff: bool = None,
147
147
  resource_name: str = None,
148
- created_email_template: Optional[Template] = None,
149
- updated_email_template: Optional[Template] = None,
150
- send_email_to_user: Optional[Any] = None,
151
- test_email_address: Optional[Any] = None,
152
- resend_as_new: Optional[Any] = None,
153
- nwords: Optional[int] = None,
148
+ created_email_template: Template | None = None,
149
+ updated_email_template: Template | None = None,
150
+ send_email_to_user: Any | None = None,
151
+ test_email_address: Any | None = None,
152
+ resend_as_new: Any | None = None,
153
+ nwords: int | None = None,
154
154
  **kwargs,
155
155
  ):
156
- self._messages: List[str] = []
156
+ self._messages: list[str] = []
157
157
  self._user = None
158
158
  self.created = False
159
159
  self.password = None
@@ -236,7 +236,7 @@ class UserImporter:
236
236
  self._user.save()
237
237
  return self._user
238
238
 
239
- def update_user_sites(self, site_names: List[str]) -> None:
239
+ def update_user_sites(self, site_names: list[str]) -> None:
240
240
  self.user.userprofile.sites.clear()
241
241
  for site_name in site_names:
242
242
  try:
@@ -250,7 +250,7 @@ class UserImporter:
250
250
  else:
251
251
  self.user.userprofile.sites.add(site)
252
252
 
253
- def update_user_roles(self, role_names: List[str]) -> None:
253
+ def update_user_roles(self, role_names: list[str]) -> None:
254
254
  self.user.userprofile.roles.clear()
255
255
  role_names.extend(required_role_names)
256
256
  for role_name in role_names:
@@ -277,7 +277,7 @@ class UserImporter:
277
277
  to=(self.test_email_address or self.user.email,),
278
278
  )
279
279
 
280
- def get_username(self) -> Optional[str]:
280
+ def get_username(self) -> str | None:
281
281
  if self.first_name and self.last_name:
282
282
  last_name = "".join(self.last_name.split(" ")).lower()
283
283
  return f"{self.first_name.lower()[0]}{last_name}"
edc_auth/models/role.py CHANGED
@@ -50,6 +50,7 @@ class Role(BaseUuidModel):
50
50
  return (self.name,)
51
51
 
52
52
  class Meta(BaseUuidModel.Meta):
53
- indexes = BaseUuidModel.Meta.indexes + [
54
- models.Index(fields=["display_name", "display_index"])
55
- ]
53
+ indexes = (
54
+ *BaseUuidModel.Meta.indexes,
55
+ models.Index(fields=["display_name", "display_index"]),
56
+ )
@@ -1,5 +1,4 @@
1
1
  from string import Template
2
- from typing import List, Optional
3
2
 
4
3
  from django.contrib.auth.models import User
5
4
  from django.core.exceptions import ObjectDoesNotExist
@@ -26,8 +25,8 @@ class PasswordSetter:
26
25
  def __init__(
27
26
  self,
28
27
  super_username: str,
29
- alternate_email: Optional[str] = None,
30
- nwords: Optional[int] = None,
28
+ alternate_email: str | None = None,
29
+ nwords: int | None = None,
31
30
  **kwargs,
32
31
  ) -> None:
33
32
  self.administrator_fullname = self.get_administrator_fullname(super_username)
@@ -48,7 +47,7 @@ class PasswordSetter:
48
47
  users = User.objects.filter(is_active=True, is_staff=True, is_superuser=False)
49
48
  self._reset(users)
50
49
 
51
- def reset_by_groups(self, group_names: List[str] = None) -> None:
50
+ def reset_by_groups(self, group_names: list[str] = None) -> None:
52
51
  users = User.objects.filter(
53
52
  groups__name__in=group_names,
54
53
  is_active=True,
@@ -57,7 +56,7 @@ class PasswordSetter:
57
56
  )
58
57
  self._reset(users)
59
58
 
60
- def reset_users(self, usernames: List[str]) -> None:
59
+ def reset_users(self, usernames: list[str]) -> None:
61
60
  users = User.objects.filter(username__in=usernames, is_active=True, is_staff=True)
62
61
  self._reset(users)
63
62
 
@@ -65,7 +64,7 @@ class PasswordSetter:
65
64
  usernames = [username]
66
65
  self.reset_users(usernames)
67
66
 
68
- def reset_by_sites(self, site_names: List[str] = None) -> None:
67
+ def reset_by_sites(self, site_names: list[str] = None) -> None:
69
68
  users = User.objects.filter(
70
69
  userprofile__sites__name__in=site_names,
71
70
  is_active=True,
@@ -74,7 +73,7 @@ class PasswordSetter:
74
73
  )
75
74
  self._reset(users)
76
75
 
77
- def _reset(self, users: List[User]) -> None:
76
+ def _reset(self, users: list[User]) -> None:
78
77
  for user in users:
79
78
  password = self.password_generator.get_password()
80
79
  user.set_password(password)
@@ -1,4 +1,3 @@
1
- from typing import Optional
2
1
  from urllib.parse import urlparse
3
2
 
4
3
  from django.core.mail.message import EmailMessage
@@ -10,7 +9,7 @@ from edc_protocol.research_protocol_config import ResearchProtocolConfig
10
9
  from .import_users import change_user_template
11
10
 
12
11
 
13
- def change_password(user, nwords: Optional[int] = None) -> str:
12
+ def change_password(user, nwords: int | None = None) -> str:
14
13
  nwords = nwords or 4
15
14
  pwdgen = PasswordGenerator(nwords=nwords)
16
15
  password = pwdgen.get_password()
@@ -19,7 +18,7 @@ def change_password(user, nwords: Optional[int] = None) -> str:
19
18
  return password
20
19
 
21
20
 
22
- def send_new_credentials_to_user(user, nwords: Optional[int] = None) -> EmailMessage:
21
+ def send_new_credentials_to_user(user, nwords: int | None = None) -> EmailMessage:
23
22
  body = change_user_template
24
23
  site_names = "\n - ".join([s.name for s in user.userprofile.sites.all()])
25
24
  role_names = "\n - ".join([r.display_name for r in user.userprofile.roles.all()])
edc_auth/site_auths.py CHANGED
@@ -1,8 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import sys
4
+ from collections.abc import Callable
4
5
  from copy import deepcopy
5
- from typing import Callable, Tuple
6
6
  from warnings import warn
7
7
 
8
8
  from django.apps import apps as django_apps
@@ -206,7 +206,7 @@ class SiteAuths:
206
206
  self.registry[key].update({name: existing_group_names})
207
207
 
208
208
  def add_custom_permissions_tuples(
209
- self, model: str, codename_tuples: Tuple[Tuple[str, str], ...]
209
+ self, model: str, codename_tuples: tuple[tuple[str, str], ...]
210
210
  ):
211
211
  try:
212
212
  self.registry["custom_permissions_tuples"][model]
@@ -278,7 +278,7 @@ class SiteAuths:
278
278
  return self.registry["pre_update_funcs"]
279
279
 
280
280
  @property
281
- def post_update_funcs(self) -> Tuple[str, Callable]:
281
+ def post_update_funcs(self) -> tuple[str, Callable]:
282
282
  return self.registry["post_update_funcs"]
283
283
 
284
284
  @property
edc_consent/actions.py CHANGED
@@ -6,11 +6,10 @@ from edc_utils import get_utcnow
6
6
  def verify_consent(request=None, consent_obj=None):
7
7
  if consent_obj.is_verified:
8
8
  return None
9
- else:
10
- consent_obj.is_verified = True
11
- consent_obj.is_verified_datetime = get_utcnow()
12
- consent_obj.verified_by = request.user.username
13
- consent_obj.save(update_fields=["is_verified", "is_verified_datetime", "verified_by"])
9
+ consent_obj.is_verified = True
10
+ consent_obj.is_verified_datetime = get_utcnow()
11
+ consent_obj.verified_by = request.user.username
12
+ consent_obj.save(update_fields=["is_verified", "is_verified_datetime", "verified_by"])
14
13
  return consent_obj
15
14
 
16
15
 
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from dataclasses import KW_ONLY, dataclass, field
4
4
  from datetime import datetime
5
- from typing import TYPE_CHECKING, Type
5
+ from typing import TYPE_CHECKING
6
6
 
7
7
  from django.apps import apps as django_apps
8
8
  from django.core.exceptions import ObjectDoesNotExist
@@ -27,9 +27,7 @@ if TYPE_CHECKING:
27
27
  from .consent_definition_extension import ConsentDefinitionExtension
28
28
  from .stubs import ConsentLikeModel
29
29
 
30
- class SubjectScreening(
31
- ScreeningModelMixin, EligibilityModelMixin, BaseUuidModel
32
- ): ... # noqa
30
+ class SubjectScreening(ScreeningModelMixin, EligibilityModelMixin, BaseUuidModel): ...
33
31
 
34
32
 
35
33
  @dataclass(order=True)
@@ -84,13 +82,13 @@ class ConsentDefinition:
84
82
  raise ConsentDefinitionError(f"Invalid gender. Got {self.gender}.")
85
83
  if not self.start.tzinfo:
86
84
  raise ConsentDefinitionError(f"Naive datetime not allowed. Got {self.start}.")
87
- elif str(self.start.tzinfo).upper() != "UTC":
85
+ if str(self.start.tzinfo).upper() != "UTC":
88
86
  raise ConsentDefinitionError(
89
87
  f"Start date must be UTC. Got {self.start} / {self.start.tzinfo}."
90
88
  )
91
89
  if not self.end.tzinfo:
92
90
  raise ConsentDefinitionError(f"Naive datetime not allowed Got {self.end}.")
93
- elif str(self.end.tzinfo).upper() != "UTC":
91
+ if str(self.end.tzinfo).upper() != "UTC":
94
92
  raise ConsentDefinitionError(
95
93
  f"End date must be UTC. Got {self.end} / {self.start.tzinfo}."
96
94
  )
@@ -110,13 +108,13 @@ class ConsentDefinition:
110
108
  raise ConsentDefinitionError(
111
109
  f"Model class must be a proxy. See {self.name}. Got {model_cls}"
112
110
  )
113
- elif not isinstance(model_cls.objects, (ConsentObjectsByCdefManager,)):
111
+ if not isinstance(model_cls.objects, (ConsentObjectsByCdefManager,)):
114
112
  raise ConsentDefinitionError(
115
113
  "Incorrect 'objects' model manager for consent model. "
116
114
  f"Expected {ConsentObjectsByCdefManager}. See {self.name}. "
117
115
  f"Got {model_cls.objects.__class__}"
118
116
  )
119
- elif not isinstance(model_cls.on_site, (CurrentSiteByCdefManager,)):
117
+ if not isinstance(model_cls.on_site, (CurrentSiteByCdefManager,)):
120
118
  raise ConsentDefinitionError(
121
119
  "Incorrect 'on_site' model manager for consent model. "
122
120
  f"Expected {CurrentSiteByCdefManager}. See {self.name}. "
@@ -170,7 +168,7 @@ class ConsentDefinition:
170
168
  return consent_obj
171
169
 
172
170
  @property
173
- def model_cls(self) -> Type[ConsentLikeModel]:
171
+ def model_cls(self) -> type[ConsentLikeModel]:
174
172
  return django_apps.get_model(self.model)
175
173
 
176
174
  @property
@@ -229,5 +227,4 @@ class ConsentDefinition:
229
227
  )
230
228
  if previous_consent.count() > 0:
231
229
  return previous_consent.last()
232
- else:
233
- raise ObjectDoesNotExist("Previous consent does not exist")
230
+ raise ObjectDoesNotExist("Previous consent does not exist")
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from dataclasses import KW_ONLY, dataclass, field
4
4
  from datetime import datetime
5
- from typing import TYPE_CHECKING, Type
5
+ from typing import TYPE_CHECKING
6
6
 
7
7
  from django.apps import apps as django_apps
8
8
  from django.core.exceptions import ObjectDoesNotExist
@@ -72,7 +72,7 @@ class ConsentDefinitionExtension:
72
72
  self.sort_index = self.name
73
73
  if not self.start.tzinfo:
74
74
  raise ConsentDefinitionError(f"Naive datetime not allowed. Got {self.start}.")
75
- elif str(self.start.tzinfo) != "UTC":
75
+ if str(self.start.tzinfo) != "UTC":
76
76
  raise ConsentDefinitionError(f"Start date must be UTC. Got {self.start}.")
77
77
  self.extends.check_date_within_study_period()
78
78
 
@@ -98,7 +98,7 @@ class ConsentDefinitionExtension:
98
98
  return visits
99
99
 
100
100
  @property
101
- def model_cls(self) -> Type[ConsentExtensionLikeModel]:
101
+ def model_cls(self) -> type[ConsentExtensionLikeModel]:
102
102
  return django_apps.get_model(self.model)
103
103
 
104
104
  @property
@@ -1,4 +1,4 @@
1
1
  from .consent_definition_form_validator_mixin import ConsentDefinitionFormValidatorMixin
2
2
  from .subject_consent_form_validator import SubjectConsentFormValidatorMixin
3
3
 
4
- __all__ = ["SubjectConsentFormValidatorMixin", "ConsentDefinitionFormValidatorMixin"]
4
+ __all__ = ["ConsentDefinitionFormValidatorMixin", "SubjectConsentFormValidatorMixin"]
@@ -4,8 +4,8 @@ from .consent_version_model_mixin import ConsentVersionModelMixin
4
4
  from .requires_consent_fields_model_mixin import RequiresConsentFieldsModelMixin
5
5
 
6
6
  __all__ = [
7
+ "ConsentExtensionModelMixin",
7
8
  "ConsentModelMixin",
8
- "RequiresConsentFieldsModelMixin",
9
9
  "ConsentVersionModelMixin",
10
- "ConsentExtensionModelMixin",
10
+ "RequiresConsentFieldsModelMixin",
11
11
  ]
@@ -69,7 +69,7 @@ class ConsentVersionModelMixin(models.Model):
69
69
  f"to 'create' consent version '{cdef.version}'. Expected "
70
70
  f"'{cdef.model}'. Got '{self._meta.label_lower}'."
71
71
  )
72
- elif cdef.updates and self._meta.label_lower != cdef.updates.updated_by.model:
72
+ if cdef.updates and self._meta.label_lower != cdef.updates.updated_by.model:
73
73
  raise ConsentDefinitionModelError(
74
74
  f"Incorrect model to update a consent. This model cannot be used "
75
75
  f"to 'update' consent version '{cdef.version}'. Expected "
@@ -72,8 +72,7 @@ class ConsentModelAdminMixin:
72
72
  return (
73
73
  fields + ("consent_datetime", "identity", "confirm_identity") + readonly_fields
74
74
  )
75
- else:
76
- return fields + readonly_fields
75
+ return fields + readonly_fields
77
76
 
78
77
  def get_search_fields(self, request) -> tuple[str, ...]:
79
78
  search_fields: tuple[str] = super().get_search_fields(request)
@@ -121,8 +121,7 @@ class ConsentModelFormValidationMixin:
121
121
  )
122
122
  if "identity" in self.cleaned_data:
123
123
  raise forms.ValidationError({"identity": msg})
124
- else:
125
- raise forms.ValidationError({"__all__": msg})
124
+ raise forms.ValidationError({"__all__": msg})
126
125
 
127
126
  def validate_identity_plus_version_is_unique(self) -> None:
128
127
  """Enforce a unique constraint on personal identity number
@@ -146,8 +145,7 @@ class ConsentModelFormValidationMixin:
146
145
  )
147
146
  if "identity" in self.cleaned_data:
148
147
  raise forms.ValidationError({"identity": msg})
149
- else:
150
- raise forms.ValidationError({"__all__": msg})
148
+ raise forms.ValidationError({"__all__": msg})
151
149
 
152
150
  def validate_identity_with_unique_fields(self) -> None:
153
151
  cleaned_data = self.cleaned_data
@@ -189,7 +187,7 @@ class ConsentModelFormValidationMixin:
189
187
  gender = self.cleaned_data.get("gender")
190
188
  if gender not in self.consent_definition.gender:
191
189
  raise forms.ValidationError(
192
- "Gender of consent can only be " "'%(gender_of_consent)s'. Got '%(gender)s'.",
190
+ "Gender of consent can only be '%(gender_of_consent)s'. Got '%(gender)s'.",
193
191
  params={
194
192
  "gender_of_consent": "' or '".join(self.consent_definition.gender),
195
193
  "gender": gender,
@@ -71,14 +71,14 @@ class SiteConsents:
71
71
  f"Updates unregistered consent definition. See {cdef.name}. "
72
72
  f"Got {cdef.updates.name}"
73
73
  )
74
- elif cdef.updates and cdef.updates.updated_by is None:
74
+ if cdef.updates and cdef.updates.updated_by is None:
75
75
  raise ConsentDefinitionError(
76
76
  f"Cdef mismatch with consent definition configured to update another. "
77
77
  f"'{cdef.name}' is configured to update "
78
78
  f"'{cdef.updates.name}' but '{cdef.updates.name}' "
79
79
  f"updated_by is None. "
80
80
  )
81
- elif cdef.updates and cdef.updates.updated_by != cdef:
81
+ if cdef.updates and cdef.updates.updated_by != cdef:
82
82
  raise ConsentDefinitionError(
83
83
  f"Cdef mismatch with consent definition configured to update another. "
84
84
  f"'{cdef.name}' is configured to update "
@@ -164,7 +164,7 @@ class SiteConsents:
164
164
  f"'{consent_definition.version}' "
165
165
  f"of consent on or after report_datetime='{dte}'?"
166
166
  )
167
- elif consent_definition.start <= to_utc(report_datetime) <= consent_definition.end:
167
+ if consent_definition.start <= to_utc(report_datetime) <= consent_definition.end:
168
168
  # ensures the higher version is returned if there is overlap
169
169
  pass
170
170
  elif (
@@ -284,8 +284,7 @@ class SiteConsents:
284
284
  raise ConsentDefinitionDoesNotExist(
285
285
  f"There are no consent definitions using this model. Got {model}."
286
286
  )
287
- else:
288
- errror_messages.append(f"model={model}")
287
+ errror_messages.append(f"model={model}")
289
288
  return cdefs, errror_messages
290
289
 
291
290
  @staticmethod
@@ -303,16 +302,13 @@ class SiteConsents:
303
302
  if model == screening_model:
304
303
  if cdef not in cdefs:
305
304
  cdefs.append(cdef)
306
- else:
307
- if model == cdef.screening_model:
308
- cdefs.append(cdef)
305
+ elif model == cdef.screening_model:
306
+ cdefs.append(cdef)
309
307
  if not cdefs:
310
308
  raise ConsentDefinitionDoesNotExist(
311
- "There are no consent definitions using this screening model."
312
- f"Got {model}."
309
+ f"There are no consent definitions using this screening model.Got {model}."
313
310
  )
314
- else:
315
- errror_messages.append(f"model={model}")
311
+ errror_messages.append(f"model={model}")
316
312
  return cdefs, errror_messages
317
313
 
318
314
  def _filter_cdefs_by_report_datetime_or_raise(
@@ -336,9 +332,8 @@ class SiteConsents:
336
332
  f"consent definition. Got {date_string}. {using_msg}. "
337
333
  f"Possible consent definitions are: {consent_definitions}. "
338
334
  )
339
- else:
340
- date_string = formatted_date(report_datetime)
341
- errror_messages.append(f"report_datetime={date_string}")
335
+ date_string = formatted_date(report_datetime)
336
+ errror_messages.append(f"report_datetime={date_string}")
342
337
  return cdefs, errror_messages
343
338
 
344
339
  def _filter_cdefs_by_version_or_raise(
edc_consent/stubs.py CHANGED
@@ -11,7 +11,7 @@ from .model_mixins import ConsentModelMixin
11
11
  class ConsentModelStub(Protocol):
12
12
  subject_identifier: str
13
13
  report_datetime: datetime
14
- ... # noqa
14
+ ...
15
15
 
16
16
 
17
17
  class ConsentLikeModel(
@@ -19,4 +19,4 @@ class ConsentLikeModel(
19
19
  ConsentModelMixin,
20
20
  NonUniqueSubjectIdentifierModelMixin,
21
21
  BaseUuidModel,
22
- ): ... # noqa
22
+ ): ...
edc_consent/utils.py CHANGED
@@ -19,7 +19,7 @@ if TYPE_CHECKING:
19
19
 
20
20
  from .model_mixins import ConsentModelMixin
21
21
 
22
- class ConsentModel(ConsentModelMixin, BaseUuidModel): ... # noqa
22
+ class ConsentModel(ConsentModelMixin, BaseUuidModel): ...
23
23
 
24
24
 
25
25
  class InvalidInitials(Exception):
edc_constants/utils.py CHANGED
@@ -1,9 +1,7 @@
1
- from typing import Optional, Tuple
2
-
3
1
  from .constants import QUESTION_RETIRED
4
2
 
5
3
 
6
- def get_display(choices, label) -> Optional[str]:
4
+ def get_display(choices, label) -> str | None:
7
5
  """Returns the display value of a choices tuple for label."""
8
6
  for choice in choices:
9
7
  store_value, display_value = choice
@@ -12,7 +10,7 @@ def get_display(choices, label) -> Optional[str]:
12
10
  return None
13
11
 
14
12
 
15
- def append_question_retired_choice(choices) -> Tuple[Tuple[str, str], ...]:
13
+ def append_question_retired_choice(choices) -> tuple[tuple[str, str], ...]:
16
14
  choices = list(choices)
17
15
  choices.append((QUESTION_RETIRED, QUESTION_RETIRED))
18
16
  choices = tuple(choices)
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from datetime import datetime
4
- from typing import TYPE_CHECKING, Type
4
+ from typing import TYPE_CHECKING
5
5
 
6
6
  from django.core.exceptions import ObjectDoesNotExist
7
7
 
@@ -83,7 +83,7 @@ class CrfFormValidatorMixin(BaseFormValidatorMixin):
83
83
  return get_related_visit(self, related_visit_model_attr=self.related_visit_model_attr)
84
84
 
85
85
  @property
86
- def related_visit_model_cls(self) -> Type[RelatedVisitModel]:
86
+ def related_visit_model_cls(self) -> type[RelatedVisitModel]:
87
87
  """Returns a subject visit model instance or None"""
88
88
  return get_related_visit(
89
89
  self, related_visit_model_attr=self.related_visit_model_attr
@@ -31,8 +31,8 @@ class CrfNoManagerModelMixin(
31
31
 
32
32
  class Meta:
33
33
  abstract = True
34
- indexes = [
34
+ indexes = (
35
35
  models.Index(fields=["subject_visit", "site"]),
36
36
  models.Index(fields=["subject_visit", "report_datetime"]),
37
- ]
37
+ )
38
38
  default_permissions = ("add", "change", "delete", "view", "export", "import")
@@ -29,8 +29,8 @@ class CrfStatusModelMixin(models.Model):
29
29
 
30
30
  crf_status_comments = models.TextField(
31
31
  verbose_name=_("Any comments related to status of this CRF"),
32
- null=True,
33
32
  blank=True,
33
+ default="",
34
34
  help_text=_("for example, why some data is still pending"),
35
35
  )
36
36
 
@@ -21,16 +21,14 @@ class CrfStatus(
21
21
  verbose_name = "CRF Status"
22
22
  verbose_name_plural = "CRF Status"
23
23
  indexes = (
24
- BaseUuidModel.Meta.indexes
25
- + NonUniqueSubjectIdentifierFieldMixin.Meta.indexes
26
- + [
27
- Index(
28
- fields=[
29
- "schedule_name",
30
- "visit_schedule_name",
31
- "visit_code",
32
- "visit_code_sequence",
33
- ]
34
- )
35
- ]
24
+ *BaseUuidModel.Meta.indexes,
25
+ *NonUniqueSubjectIdentifierFieldMixin.Meta.indexes,
26
+ Index(
27
+ fields=[
28
+ "schedule_name",
29
+ "visit_schedule_name",
30
+ "visit_code",
31
+ "visit_code_sequence",
32
+ ]
33
+ ),
36
34
  )
@@ -1,5 +1,3 @@
1
- from typing import Optional
2
-
3
1
  from django.apps import apps as django_apps
4
2
 
5
3
  from edc_constants.constants import INCOMPLETE
@@ -8,7 +6,7 @@ from .model_mixins import CrfStatusModelMixin
8
6
  from .update_crf_status_for_instance import update_crf_status_for_instance
9
7
 
10
8
 
11
- def update_crf_status_command(app_label: Optional[str] = None) -> None:
9
+ def update_crf_status_command(app_label: str | None = None) -> None:
12
10
  if app_label:
13
11
  app_configs = [django_apps.get_app_config(app_label)]
14
12
  else: