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,3 @@
1
- from typing import Optional, Union
2
-
3
1
  from django.forms import ValidationError
4
2
 
5
3
  from edc_constants.constants import NOT_APPLICABLE, OTHER
@@ -28,7 +26,7 @@ class ManyToManyFieldValidator(BaseFormValidator):
28
26
  }
29
27
 
30
28
  def m2m_applicable_if_true(self, cond: bool, m2m_field: str = None) -> bool:
31
- code: Optional[str] = None
29
+ code: str | None = None
32
30
  message: dict = {}
33
31
  qs = self.cleaned_data.get(m2m_field)
34
32
  if cond:
@@ -37,12 +35,11 @@ class ManyToManyFieldValidator(BaseFormValidator):
37
35
  if NOT_APPLICABLE in selected:
38
36
  message = {m2m_field: "This field is applicable"}
39
37
  code = APPLICABLE_ERROR
40
- else:
41
- if qs and qs.count() > 0:
42
- selected = self.get_m2m_selected(m2m_field)
43
- if NOT_APPLICABLE not in selected:
44
- message = {m2m_field: "This field is not applicable"}
45
- code = NOT_APPLICABLE_ERROR
38
+ elif qs and qs.count() > 0:
39
+ selected = self.get_m2m_selected(m2m_field)
40
+ if NOT_APPLICABLE not in selected:
41
+ message = {m2m_field: "This field is not applicable"}
42
+ code = NOT_APPLICABLE_ERROR
46
43
  if message:
47
44
  self._errors.update(message)
48
45
  self._error_codes.append(code)
@@ -51,7 +48,7 @@ class ManyToManyFieldValidator(BaseFormValidator):
51
48
 
52
49
  def m2m_applicable_if(
53
50
  self,
54
- *responses: Union[str, int, bool],
51
+ *responses: str | int | bool,
55
52
  field: str = None,
56
53
  m2m_field: str = None,
57
54
  ) -> bool:
@@ -59,7 +56,7 @@ class ManyToManyFieldValidator(BaseFormValidator):
59
56
 
60
57
  m2m_field is applicable if field is in responses.
61
58
  """
62
- code: Optional[str] = None
59
+ code: str | None = None
63
60
  message: dict = {}
64
61
  if self.cleaned_data.get(field):
65
62
  qs = self.cleaned_data.get(m2m_field)
@@ -70,13 +67,12 @@ class ManyToManyFieldValidator(BaseFormValidator):
70
67
  if NOT_APPLICABLE not in selected:
71
68
  message = {m2m_field: "This field is not applicable"}
72
69
  code = NOT_APPLICABLE_ERROR
73
- else:
74
- # m2m should != NOT_APPLICABLE
75
- if qs and qs.count() > 0:
76
- selected = self.get_m2m_selected(m2m_field)
77
- if NOT_APPLICABLE in selected:
78
- message = {m2m_field: "This field is applicable"}
79
- code = APPLICABLE_ERROR
70
+ # m2m should != NOT_APPLICABLE
71
+ elif qs and qs.count() > 0:
72
+ selected = self.get_m2m_selected(m2m_field)
73
+ if NOT_APPLICABLE in selected:
74
+ message = {m2m_field: "This field is applicable"}
75
+ code = APPLICABLE_ERROR
80
76
  if message:
81
77
  self._errors.update(message)
82
78
  self._error_codes.append(code)
@@ -88,7 +84,7 @@ class ManyToManyFieldValidator(BaseFormValidator):
88
84
 
89
85
  m2m_field is required.
90
86
  """
91
- code: Optional[str] = None
87
+ code: str | None = None
92
88
  message: dict = {}
93
89
  if not self.cleaned_data.get(m2m_field):
94
90
  message = {m2m_field: "This field is required"}
@@ -104,7 +100,7 @@ class ManyToManyFieldValidator(BaseFormValidator):
104
100
 
105
101
  m2m_field is not required.
106
102
  """
107
- code: Optional[str] = None
103
+ code: str | None = None
108
104
  message: dict = {}
109
105
  if self.cleaned_data.get(m2m_field):
110
106
  message = {m2m_field: "This field is not required"}
@@ -116,18 +112,17 @@ class ManyToManyFieldValidator(BaseFormValidator):
116
112
  return False
117
113
 
118
114
  def m2m_required_if(
119
- self, response: Union[str, int, bool], field: str = None, m2m_field: str = None
115
+ self, response: str | int | bool, field: str = None, m2m_field: str = None
120
116
  ) -> bool:
121
117
  """Raises an exception or returns False.
122
118
 
123
119
  m2m_field is required if field == response
124
120
  """
125
- code: Optional[str] = None
121
+ code: str | None = None
126
122
  message: dict = {}
127
- if self.cleaned_data.get(field) == response and not self.cleaned_data.get(m2m_field):
128
- message = {m2m_field: "This field is required"}
129
- code = REQUIRED_ERROR
130
- elif (
123
+ if (
124
+ self.cleaned_data.get(field) == response and not self.cleaned_data.get(m2m_field)
125
+ ) or (
131
126
  self.cleaned_data.get(field) == response
132
127
  and self.cleaned_data.get(m2m_field).count() == 0
133
128
  ):
@@ -169,10 +164,10 @@ class ManyToManyFieldValidator(BaseFormValidator):
169
164
 
170
165
  def required_if_m2m(
171
166
  self,
172
- *responses: Union[str, int, bool],
167
+ *responses: str | int | bool,
173
168
  field: str = None,
174
- field_required: Optional[str] = None,
175
- field_other_evaluate_as_int: Optional[bool] = None,
169
+ field_required: str | None = None,
170
+ field_other_evaluate_as_int: bool | None = None,
176
171
  ) -> bool:
177
172
  """Same as required_if() but where field is an m2m field."""
178
173
  return self.m2m_other_specify(
@@ -184,10 +179,10 @@ class ManyToManyFieldValidator(BaseFormValidator):
184
179
 
185
180
  def m2m_other_specify(
186
181
  self,
187
- *responses: Union[str, int, bool],
182
+ *responses: str | int | bool,
188
183
  m2m_field: str = None,
189
- field_other: Optional[str] = None,
190
- field_other_evaluate_as_int: Optional[bool] = None,
184
+ field_other: str | None = None,
185
+ field_other_evaluate_as_int: bool | None = None,
191
186
  ) -> bool:
192
187
  """Raises an exception or returns False.
193
188
 
@@ -213,7 +208,7 @@ class ManyToManyFieldValidator(BaseFormValidator):
213
208
  self._errors.update(message)
214
209
  self._error_codes.append(REQUIRED_ERROR)
215
210
  raise ValidationError(message, code=REQUIRED_ERROR)
216
- elif not found and field_other_has_value:
211
+ if not found and field_other_has_value:
217
212
  message = {field_other: "This field is not required."}
218
213
  self._errors.update(message)
219
214
  self._error_codes.append(NOT_REQUIRED_ERROR)
@@ -227,9 +222,9 @@ class ManyToManyFieldValidator(BaseFormValidator):
227
222
 
228
223
  def m2m_other_not_specify(
229
224
  self,
230
- *responses: Union[str, int, bool],
225
+ *responses: str | int | bool,
231
226
  m2m_field: str = None,
232
- field_other: Optional[str] = None,
227
+ field_other: str | None = None,
233
228
  ) -> bool:
234
229
  """Raises an exception or returns False.
235
230
 
@@ -249,7 +244,7 @@ class ManyToManyFieldValidator(BaseFormValidator):
249
244
  self._errors.update(message)
250
245
  self._error_codes.append(NOT_REQUIRED_ERROR)
251
246
  raise ValidationError(message, code=NOT_REQUIRED_ERROR)
252
- elif not found and not self.cleaned_data.get(field_other):
247
+ if not found and not self.cleaned_data.get(field_other):
253
248
  message = {field_other: "This field is required."}
254
249
  self._errors.update(message)
255
250
  self._error_codes.append(REQUIRED_ERROR)
@@ -263,9 +258,9 @@ class ManyToManyFieldValidator(BaseFormValidator):
263
258
 
264
259
  def m2m_other_specify_applicable(
265
260
  self,
266
- *responses: Union[str, int, bool],
261
+ *responses: str | int | bool,
267
262
  m2m_field: str = None,
268
- field_other: Optional[str] = None,
263
+ field_other: str | None = None,
269
264
  ) -> bool:
270
265
  """Raises an exception or returns False.
271
266
 
@@ -285,7 +280,7 @@ class ManyToManyFieldValidator(BaseFormValidator):
285
280
  self._errors.update(message)
286
281
  self._error_codes.append(APPLICABLE_ERROR)
287
282
  raise ValidationError(message, code=APPLICABLE_ERROR)
288
- elif not found and self.cleaned_data.get(field_other) != NOT_APPLICABLE:
283
+ if not found and self.cleaned_data.get(field_other) != NOT_APPLICABLE:
289
284
  message = {field_other: "This field is not applicable."}
290
285
  self._errors.update(message)
291
286
  self._error_codes.append(NOT_APPLICABLE_ERROR)
@@ -299,7 +294,7 @@ class ManyToManyFieldValidator(BaseFormValidator):
299
294
 
300
295
  def m2m_selection_expected(
301
296
  self,
302
- response: Union[str, int, bool],
297
+ response: str | int | bool,
303
298
  m2m_field: str = None,
304
299
  error_msg: str = None,
305
300
  ) -> bool:
@@ -329,9 +324,9 @@ class ManyToManyFieldValidator(BaseFormValidator):
329
324
 
330
325
  def m2m_selections_not_expected(
331
326
  self,
332
- *responses: Union[str, int, bool],
327
+ *responses: str | int | bool,
333
328
  m2m_field: str = None,
334
- error_msg: Optional[str] = None,
329
+ error_msg: str | None = None,
335
330
  ) -> bool:
336
331
  """Raises an exception or returns False.
337
332
 
@@ -354,7 +349,7 @@ class ManyToManyFieldValidator(BaseFormValidator):
354
349
  )
355
350
  message = {
356
351
  m2m_field: error_msg
357
- or f"Invalid selection. " f"Cannot be any of: {display_names}."
352
+ or f"Invalid selection. Cannot be any of: {display_names}."
358
353
  }
359
354
  self._errors.update(message)
360
355
  self._error_codes.append(M2M_INVALID_SELECTION)
@@ -1,4 +1,4 @@
1
- from typing import Any, Optional
1
+ from typing import Any
2
2
 
3
3
  from django.forms import ValidationError
4
4
 
@@ -15,12 +15,12 @@ class OtherSpecifyFieldValidator(BaseFormValidator):
15
15
  def validate_other_specify(
16
16
  self,
17
17
  field: str,
18
- other_specify_field: Optional[str] = None,
19
- required_msg: Optional[str] = None,
20
- not_required_msg: Optional[str] = None,
21
- other_stored_value: Optional[Any] = None,
22
- ref: Optional[str] = None,
23
- fk_stored_field_name: Optional[str] = None,
18
+ other_specify_field: str | None = None,
19
+ required_msg: str | None = None,
20
+ not_required_msg: str | None = None,
21
+ other_stored_value: Any | None = None,
22
+ ref: str | None = None,
23
+ fk_stored_field_name: str | None = None,
24
24
  ) -> bool:
25
25
  """Returns False or raises a ValidationError.
26
26
 
@@ -51,19 +51,11 @@ class OtherSpecifyFieldValidator(BaseFormValidator):
51
51
  self._errors.update(message)
52
52
  self._error_codes.append(REQUIRED_ERROR)
53
53
  raise ValidationError(message, code=REQUIRED_ERROR)
54
- elif (
54
+ if (
55
55
  field_value is not None
56
56
  and field_value != other
57
57
  and cleaned_data.get(other_specify_field)
58
- ):
59
- ref = "" if not ref else f" ref: {ref}"
60
- message = {
61
- other_specify_field: not_required_msg or f"This field is not required.{ref}"
62
- }
63
- self._errors.update(message)
64
- self._error_codes.append(NOT_REQUIRED_ERROR)
65
- raise ValidationError(message, code=NOT_REQUIRED_ERROR)
66
- elif field_value is None and cleaned_data.get(other_specify_field):
58
+ ) or (field_value is None and cleaned_data.get(other_specify_field)):
67
59
  ref = "" if not ref else f" ref: {ref}"
68
60
  message = {
69
61
  other_specify_field: not_required_msg or f"This field is not required.{ref}"
@@ -1,5 +1,4 @@
1
1
  from copy import copy
2
- from typing import Optional, Union
3
2
 
4
3
  from django.db.models import QuerySet
5
4
  from django.utils.translation import gettext_lazy as _
@@ -20,7 +19,7 @@ class RequiredFieldValidatorError(Exception):
20
19
 
21
20
  class RequiredFieldValidator(BaseFormValidator):
22
21
  def raise_required(
23
- self, field: str, msg: Optional[str] = None, inline_set: Optional[str] = None
22
+ self, field: str, msg: str | None = None, inline_set: str | None = None
24
23
  ) -> None:
25
24
  if inline_set:
26
25
  default_errmsg = _("Based on your responses, inline information is required.")
@@ -29,10 +28,9 @@ class RequiredFieldValidator(BaseFormValidator):
29
28
  errmsg = _("This field is required")
30
29
  message = {field: f"{errmsg}. {msg or ''}".strip()}
31
30
  self.raise_validation_error(message, REQUIRED_ERROR)
32
- return None
33
31
 
34
32
  def raise_not_required(
35
- self, field: str, msg: Optional[str] = None, inline_set: Optional[str] = None
33
+ self, field: str, msg: str | None = None, inline_set: str | None = None
36
34
  ) -> None:
37
35
  if inline_set:
38
36
  default_errmsg = _("Based on your responses, inline information is not required.")
@@ -41,20 +39,19 @@ class RequiredFieldValidator(BaseFormValidator):
41
39
  errmsg = _("This field is not required")
42
40
  message = {field: f"{errmsg}. {msg or ''}".strip()}
43
41
  self.raise_validation_error(message, NOT_REQUIRED_ERROR)
44
- return None
45
42
 
46
43
  def required_if(
47
44
  self,
48
- *responses: Union[str, int, bool],
45
+ *responses: str | int | bool,
49
46
  field: str = None,
50
47
  field_required: str = None,
51
- required_msg: Optional[str] = None,
52
- not_required_msg: Optional[str] = None,
53
- optional_if_dwta: Optional[bool] = None,
54
- optional_if_na: Optional[bool] = None,
55
- inverse: Optional[bool] = None,
56
- is_instance_field: Optional[bool] = None,
57
- field_required_evaluate_as_int: Optional[bool] = None,
48
+ required_msg: str | None = None,
49
+ not_required_msg: str | None = None,
50
+ optional_if_dwta: bool | None = None,
51
+ optional_if_na: bool | None = None,
52
+ inverse: bool | None = None,
53
+ is_instance_field: bool | None = None,
54
+ field_required_evaluate_as_int: bool | None = None,
58
55
  fk_stored_field_name=None,
59
56
  field_required_inline_set=None,
60
57
  ) -> bool:
@@ -88,9 +85,7 @@ class RequiredFieldValidator(BaseFormValidator):
88
85
  field_required_has_value = self.get(field_required, inline_set=inline_set)
89
86
 
90
87
  if field in self.cleaned_data:
91
- if DWTA in responses and optional_if_dwta and field_value == DWTA:
92
- pass
93
- elif (
88
+ if (DWTA in responses and optional_if_dwta and field_value == DWTA) or (
94
89
  NOT_APPLICABLE in responses
95
90
  and optional_if_na
96
91
  and field_value == NOT_APPLICABLE
@@ -123,9 +118,9 @@ class RequiredFieldValidator(BaseFormValidator):
123
118
  self,
124
119
  condition: bool,
125
120
  field_required: str = None,
126
- required_msg: Optional[str] = None,
127
- not_required_msg: Optional[str] = None,
128
- inverse: Optional[bool] = None,
121
+ required_msg: str | None = None,
122
+ not_required_msg: str | None = None,
123
+ inverse: bool | None = None,
129
124
  ) -> bool:
130
125
  inverse = True if inverse is None else inverse
131
126
  if not field_required:
@@ -151,8 +146,8 @@ class RequiredFieldValidator(BaseFormValidator):
151
146
  self,
152
147
  condition: bool,
153
148
  field: str = None,
154
- msg: Optional[str] = None,
155
- is_instance_field: Optional[bool] = None,
149
+ msg: str | None = None,
150
+ is_instance_field: bool | None = None,
156
151
  ) -> bool:
157
152
  """Raises a ValidationError if condition is True stating the
158
153
  field is NOT required.
@@ -177,12 +172,12 @@ class RequiredFieldValidator(BaseFormValidator):
177
172
  self,
178
173
  field: str = None,
179
174
  field_required: str = None,
180
- required_msg: Optional[str] = None,
181
- not_required_msg: Optional[str] = None,
182
- optional_if_dwta: Optional[bool] = None,
183
- inverse: Optional[bool] = None,
184
- field_required_evaluate_as_int: Optional[bool] = None,
185
- is_instance_field: Optional[bool] = None,
175
+ required_msg: str | None = None,
176
+ not_required_msg: str | None = None,
177
+ optional_if_dwta: bool | None = None,
178
+ inverse: bool | None = None,
179
+ field_required_evaluate_as_int: bool | None = None,
180
+ is_instance_field: bool | None = None,
186
181
  ) -> bool:
187
182
  """Raises an exception or returns False.
188
183
 
@@ -225,15 +220,15 @@ class RequiredFieldValidator(BaseFormValidator):
225
220
 
226
221
  def not_required_if(
227
222
  self,
228
- *responses: Union[str, int, bool],
223
+ *responses: str | int | bool,
229
224
  field: str = None,
230
225
  field_required: str = None,
231
- field_not_required: Optional[str] = None,
232
- required_msg: Optional[str] = None,
233
- not_required_msg: Optional[str] = None,
234
- optional_if_dwta: Optional[bool] = None,
235
- inverse: Optional[bool] = None,
236
- is_instance_field: Optional[bool] = None,
226
+ field_not_required: str | None = None,
227
+ required_msg: str | None = None,
228
+ not_required_msg: str | None = None,
229
+ optional_if_dwta: bool | None = None,
230
+ inverse: bool | None = None,
231
+ is_instance_field: bool | None = None,
237
232
  ) -> bool:
238
233
  """Raises an exception or returns False.
239
234
 
@@ -266,8 +261,8 @@ class RequiredFieldValidator(BaseFormValidator):
266
261
  self,
267
262
  field: str = None,
268
263
  field_required: str = None,
269
- required_msg: Optional[str] = None,
270
- is_instance_field: Optional[bool] = None,
264
+ required_msg: str | None = None,
265
+ is_instance_field: bool | None = None,
271
266
  ) -> bool:
272
267
  """Required `b` if `a`; do not require `b` if not `a`"""
273
268
  if is_instance_field:
@@ -286,16 +281,16 @@ class RequiredFieldValidator(BaseFormValidator):
286
281
 
287
282
  @staticmethod
288
283
  def _inspect_params(
289
- *responses: Union[str, int, bool], field: str = None, field_required: str = None
284
+ *responses: str | int | bool, field: str = None, field_required: str = None
290
285
  ) -> bool:
291
286
  """Inspects params and raises if any are None"""
292
287
  if not field:
293
288
  errmsg = _("`field` cannot be `None`")
294
289
  raise InvalidModelFormFieldValidator(f"{errmsg}.")
295
- elif not responses:
290
+ if not responses:
296
291
  errmsg = _(f"At least one valid response for field '{field}' must be provided.")
297
292
  raise InvalidModelFormFieldValidator(errmsg)
298
- elif not field_required:
293
+ if not field_required:
299
294
  raise InvalidModelFormFieldValidator('"field_required" cannot be None.')
300
295
  return False
301
296
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Type
3
+ from typing import TYPE_CHECKING
4
4
 
5
5
  from django.forms import ValidationError
6
6
  from django.test import TestCase
@@ -11,16 +11,16 @@ if TYPE_CHECKING:
11
11
 
12
12
 
13
13
  class FormValidatorTestCaseMixin:
14
- form_validator_cls: Type[FormValidator] = None
15
- form_validator_model_cls: Type[BaseUuidModel] = None
14
+ form_validator_cls: type[FormValidator] = None
15
+ form_validator_model_cls: type[BaseUuidModel] = None
16
16
 
17
17
  def validate_form_validator(
18
18
  self: FormValidatorTestCaseMixin,
19
19
  cleaned_data: dict,
20
20
  *,
21
21
  instance: BaseUuidModel | None = None,
22
- model_cls: Type[BaseUuidModel] | None = None,
23
- form_validator_cls: Type[FormValidator] | None = None,
22
+ model_cls: type[BaseUuidModel] | None = None,
23
+ form_validator_cls: type[FormValidator] | None = None,
24
24
  ) -> FormValidator:
25
25
  form_validator = (form_validator_cls or self.form_validator_cls)(
26
26
  cleaned_data=cleaned_data,
edc_identifier/admin.py CHANGED
@@ -1,5 +1,3 @@
1
- from typing import Tuple
2
-
3
1
  from django.contrib import admin
4
2
  from django_audit_fields import audit_fieldset_tuple
5
3
 
@@ -53,7 +51,7 @@ class IdentifierModelAdmin(admin.ModelAdmin):
53
51
  )
54
52
  search_fields = ("identifier", "subject_identifier", "linked_identifier")
55
53
 
56
- def get_readonly_fields(self, request, obj=None) -> Tuple[str, ...]:
54
+ def get_readonly_fields(self, request, obj=None) -> tuple[str, ...]:
57
55
  return (
58
56
  "identifier",
59
57
  "protocol_number",
@@ -114,9 +114,8 @@ class Identifier:
114
114
  """
115
115
  if not identifier:
116
116
  return identifier
117
- else:
118
- self.identifier_as_list = identifier.split(self.separator)
119
- return "".join(self.identifier_as_list)
117
+ self.identifier_as_list = identifier.split(self.separator)
118
+ return "".join(self.identifier_as_list)
120
119
 
121
120
  def insert_separator(self, identifier):
122
121
  """Returns the identifier by reinserting the separator."""
@@ -1,5 +1,4 @@
1
1
  import re
2
- from typing import Union
3
2
  from uuid import uuid4
4
3
 
5
4
  from django.apps import apps as django_apps
@@ -21,7 +20,7 @@ class NonUniqueSubjectIdentifierFieldMixin(models.Model):
21
20
 
22
21
  class Meta:
23
22
  abstract = True
24
- indexes = [models.Index(fields=["subject_identifier"])]
23
+ indexes = (models.Index(fields=["subject_identifier"]),)
25
24
 
26
25
 
27
26
  class UniqueSubjectIdentifierFieldMixin(models.Model):
@@ -66,11 +65,9 @@ class SubjectIdentifierMethodsModelMixin(models.Model):
66
65
  self.subject_identifier = self.update_subject_identifier_on_save()
67
66
  super().save(*args, **kwargs)
68
67
 
69
- def update_subject_identifier_on_save(self) -> Union[str, models.CharField]:
68
+ def update_subject_identifier_on_save(self) -> str | models.CharField:
70
69
  """Returns a subject_identifier if not already set."""
71
- if not self.subject_identifier:
72
- self.subject_identifier = self.get_or_create_identifier()
73
- elif re.match(UUID_PATTERN, self.subject_identifier):
70
+ if not self.subject_identifier or re.match(UUID_PATTERN, self.subject_identifier):
74
71
  self.subject_identifier = self.get_or_create_identifier()
75
72
  return self.subject_identifier
76
73
 
@@ -115,7 +112,7 @@ class SubjectIdentifierMethodsModelMixin(models.Model):
115
112
  except MultipleObjectsReturned as e:
116
113
  raise IdentifierError(
117
114
  "Cannot lookup a unique RegisteredSubject instance. "
118
- "Identity {} is not unique. Got {}".format(self.identity, e)
115
+ f"Identity {self.identity} is not unique. Got {e}"
119
116
  )
120
117
  return obj
121
118
 
@@ -139,7 +136,7 @@ class UniqueSubjectIdentifierModelMixin(
139
136
 
140
137
  def get_subject_identifier_as_pk(self):
141
138
  """Returns the subject_identifier_as_pk"""
142
- return self.subject_identifier_as_pk # noqa
139
+ return self.subject_identifier_as_pk
143
140
 
144
141
  class Meta:
145
142
  abstract = True
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from string import Formatter
4
- from typing import TYPE_CHECKING, Optional
4
+ from typing import TYPE_CHECKING
5
5
 
6
6
  from django.apps import apps as django_apps
7
7
 
@@ -22,22 +22,20 @@ class IdentifierMissingTemplateValue(Exception):
22
22
 
23
23
  class ResearchIdentifier:
24
24
  label: str = None # e.g. subject_identifier, plot_identifier, etc
25
- identifier_type: Optional[str] = (
26
- None # e.g. 'subject', 'infant', 'plot', a.k.a subject_type
27
- )
28
- template: Optional[str] = None
25
+ identifier_type: str | None = None # e.g. 'subject', 'infant', 'plot', a.k.a subject_type
26
+ template: str | None = None
29
27
  padding: int = 5
30
28
  checkdigit = LuhnMixin()
31
29
 
32
30
  def __init__(
33
31
  self,
34
- identifier_type: Optional[str] = None,
35
- template: Optional[str] = None,
36
- device_id: Optional[str] = None,
37
- protocol_number: Optional[str] = None,
38
- site: Optional[Site] = None,
39
- requesting_model: Optional[str] = None,
40
- identifier: Optional[str] = None,
32
+ identifier_type: str | None = None,
33
+ template: str | None = None,
34
+ device_id: str | None = None,
35
+ protocol_number: str | None = None,
36
+ site: Site | None = None,
37
+ requesting_model: str | None = None,
38
+ identifier: str | None = None,
41
39
  ) -> None:
42
40
  self._identifier = None
43
41
  self.requesting_model = requesting_model
@@ -75,7 +75,7 @@ class ShortIdentifier:
75
75
  raise ShortIdentifierPrefixError(
76
76
  "Prefix does not match prefix pattern. Got prefix=None."
77
77
  )
78
- elif self.prefix and not self.prefix_pattern.match(self.prefix):
78
+ if self.prefix and not self.prefix_pattern.match(self.prefix):
79
79
  raise ShortIdentifierPrefixError(
80
80
  "Prefix does not match prefix pattern. "
81
81
  f"Got '{self.prefix}' does not match "