clinicedc 2.0.4__py3-none-any.whl → 2.0.6__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.4.dist-info → clinicedc-2.0.6.dist-info}/METADATA +41 -45
  2. {clinicedc-2.0.4.dist-info → clinicedc-2.0.6.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 +1 -1
  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 -10
  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.4.dist-info → clinicedc-2.0.6.dist-info}/WHEEL +0 -0
  478. {clinicedc-2.0.4.dist-info → clinicedc-2.0.6.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,5 @@
1
1
  from secrets import choice
2
- from typing import Any, Optional, Type
2
+ from typing import Any
3
3
 
4
4
  from django.apps import apps as django_apps
5
5
  from django.core.exceptions import ObjectDoesNotExist
@@ -26,12 +26,12 @@ class SimpleIdentifier:
26
26
 
27
27
  def __init__(
28
28
  self,
29
- template: Optional[str] = None,
30
- random_string_length: Optional[int] = None,
31
- identifier_prefix: Optional[str] = None,
32
- device_id: Optional[str] = None,
29
+ template: str | None = None,
30
+ random_string_length: int | None = None,
31
+ identifier_prefix: str | None = None,
32
+ device_id: str | None = None,
33
33
  ) -> None:
34
- self._identifier: Optional[str] = None
34
+ self._identifier: str | None = None
35
35
  self.template = template or self.template
36
36
  self.random_string_length = random_string_length or self.random_string_length
37
37
  self.device_id = device_id or django_apps.get_app_config("edc_device").device_id
@@ -80,14 +80,14 @@ class SimpleTimestampIdentifier(SimpleIdentifier):
80
80
 
81
81
 
82
82
  class SimpleSequentialIdentifier:
83
- prefix: Optional[str] = None
83
+ prefix: str | None = None
84
84
 
85
85
  def __init__(self):
86
86
  sequence: int = int(get_utcnow().timestamp())
87
87
  random_number: int = choice(range(1000, 9999)) # nosec B311
88
88
  sequence: str = f"{sequence}{random_number}"
89
89
  chk: int = int(sequence) % 11
90
- self.identifier: str = f'{self.prefix or ""}{sequence}{chk}'
90
+ self.identifier: str = f"{self.prefix or ''}{sequence}{chk}"
91
91
 
92
92
  def __str__(self) -> str:
93
93
  return self.identifier
@@ -107,26 +107,26 @@ class SimpleUniqueIdentifier:
107
107
  identifier_attr: str = "identifier"
108
108
  model: str = "edc_identifier.identifiermodel"
109
109
  template: str = "{device_id}{random_string}"
110
- identifier_prefix: Optional[str] = None
110
+ identifier_prefix: str | None = None
111
111
  identifier_cls = SimpleIdentifier
112
- make_human_readable: Optional[bool] = None
112
+ make_human_readable: bool | None = None
113
113
 
114
114
  def __init__(
115
115
  self,
116
116
  model: str = None,
117
- identifier_attr: Optional[str] = None,
118
- identifier_type: Optional[str] = None,
119
- identifier_prefix: Optional[str] = None,
120
- make_human_readable: Optional[bool] = None,
121
- linked_identifier: Optional[str] = None,
122
- protocol_number: Optional[str] = None,
123
- source_model: Optional[str] = None,
124
- subject_identifier: Optional[str] = None,
117
+ identifier_attr: str | None = None,
118
+ identifier_type: str | None = None,
119
+ identifier_prefix: str | None = None,
120
+ make_human_readable: bool | None = None,
121
+ linked_identifier: str | None = None,
122
+ protocol_number: str | None = None,
123
+ source_model: str | None = None,
124
+ subject_identifier: str | None = None,
125
125
  name: str | None = None,
126
- site: Optional[Any] = None,
127
- site_id: Optional[str] = None,
126
+ site: Any | None = None,
127
+ site_id: str | None = None,
128
128
  ):
129
- self._identifier: Optional[str] = None
129
+ self._identifier: str | None = None
130
130
  self.site_id = site_id
131
131
  self.name = name or ""
132
132
  self.model = model or self.model
@@ -194,7 +194,7 @@ class SimpleUniqueIdentifier:
194
194
  return identifier.identifier
195
195
 
196
196
  @property
197
- def model_cls(self) -> Type[models.Model]:
197
+ def model_cls(self) -> type[models.Model]:
198
198
  return django_apps.get_model(self.model)
199
199
 
200
200
  def update_identifier_model(self, **kwargs) -> bool:
edc_identifier/utils.py CHANGED
@@ -21,7 +21,7 @@ def is_subject_identifier_or_raise(subject_identifier, reference_obj=None, raise
21
21
  ):
22
22
  reference_msg = ""
23
23
  if reference_obj:
24
- reference_msg = f"See {repr(reference_obj)}. "
24
+ reference_msg = f"See {reference_obj!r}. "
25
25
  raise SubjectIdentifierError(
26
26
  f"Invalid format for subject identifier. {reference_msg}"
27
27
  f"Got `{subject_identifier or ''}`. "
@@ -1,6 +1,4 @@
1
- from typing import Dict, Tuple
2
-
3
- requisition_fieldset: Tuple[str, Dict[str, Tuple[str, ...]]] = (
1
+ requisition_fieldset: tuple[str, dict[str, tuple[str, ...]]] = (
4
2
  "Requisition",
5
3
  {
6
4
  "fields": (
@@ -17,7 +15,7 @@ requisition_fieldset: Tuple[str, Dict[str, Tuple[str, ...]]] = (
17
15
  )
18
16
 
19
17
 
20
- requisition_status_fields: Tuple[str, ...] = (
18
+ requisition_status_fields: tuple[str, ...] = (
21
19
  "received",
22
20
  "received_datetime",
23
21
  "processed",
@@ -28,29 +26,29 @@ requisition_status_fields: Tuple[str, ...] = (
28
26
  "shipped_datetime",
29
27
  )
30
28
 
31
- requisition_verify_fields: Tuple[str, ...] = (
29
+ requisition_verify_fields: tuple[str, ...] = (
32
30
  "clinic_verified",
33
31
  "clinic_verified_datetime",
34
32
  )
35
33
 
36
- requisition_status_fieldset: Tuple[str, Dict[str, Tuple[str, ...]]] = (
34
+ requisition_status_fieldset: tuple[str, dict[str, tuple[str, ...]]] = (
37
35
  "Status (For laboratory use only)",
38
36
  {"classes": ("collapse",), "fields": requisition_status_fields},
39
37
  )
40
38
 
41
39
 
42
- requisition_identifier_fields: Tuple[str, ...] = (
40
+ requisition_identifier_fields: tuple[str, ...] = (
43
41
  "requisition_identifier",
44
42
  "identifier_prefix",
45
43
  "primary_aliquot_identifier",
46
44
  )
47
45
 
48
- requisition_identifier_fieldset: Tuple[str, Dict[str, Tuple[str, ...]]] = (
46
+ requisition_identifier_fieldset: tuple[str, dict[str, tuple[str, ...]]] = (
49
47
  "Identifiers",
50
48
  {"classes": ("collapse",), "fields": requisition_identifier_fields},
51
49
  )
52
50
 
53
- requisition_verify_fieldset: Tuple[str, Dict[str, Tuple[str, ...]]] = (
51
+ requisition_verify_fieldset: tuple[str, dict[str, tuple[str, ...]]] = (
54
52
  "Verification",
55
53
  {"classes": ("collapse",), "fields": requisition_verify_fields},
56
54
  )
@@ -1,4 +1,3 @@
1
- from typing import Tuple
2
1
  from uuid import UUID
3
2
 
4
3
  from django.contrib import admin
@@ -29,7 +28,7 @@ class RequisitionAdminMixin:
29
28
  "item_type": admin.VERTICAL,
30
29
  }
31
30
 
32
- search_fields: Tuple[str, ...] = (
31
+ search_fields: tuple[str, ...] = (
33
32
  "requisition_identifier",
34
33
  "subject_identifier",
35
34
  "panel__display_name",
@@ -43,7 +42,7 @@ class RequisitionAdminMixin:
43
42
  def requisition(obj=None):
44
43
  if obj.is_drawn == YES:
45
44
  return obj.requisition_identifier
46
- elif not obj.is_drawn:
45
+ if not obj.is_drawn:
47
46
  return format_html(
48
47
  '<span style="color:red;">{}</span>', obj.requisition_identifier
49
48
  )
@@ -61,13 +60,13 @@ class RequisitionAdminMixin:
61
60
  )
62
61
  return super().formfield_for_foreignkey(db_field, request, **kwargs)
63
62
 
64
- def get_list_filter(self, request) -> Tuple[str, ...]:
63
+ def get_list_filter(self, request) -> tuple[str, ...]:
65
64
  list_filter = super().get_list_filter(request)
66
65
  custom_fields = ("requisition_datetime", "site", "is_drawn", "panel")
67
66
  list_filter = tuple(f for f in list_filter if f not in custom_fields)
68
67
  return custom_fields + list_filter
69
68
 
70
- def get_list_display(self, request) -> Tuple[str, ...]:
69
+ def get_list_display(self, request) -> tuple[str, ...]:
71
70
  list_display = super().get_list_display(request)
72
71
  custom_fields = (
73
72
  "requisition",
@@ -80,7 +79,7 @@ class RequisitionAdminMixin:
80
79
  list_display = tuple(f for f in list_display if f not in custom_fields)
81
80
  return custom_fields + list_display
82
81
 
83
- def get_readonly_fields(self, request, obj=None) -> Tuple[str, ...]:
82
+ def get_readonly_fields(self, request, obj=None) -> tuple[str, ...]:
84
83
  readonly_fields = super().get_readonly_fields(request, obj=obj)
85
84
  return tuple(
86
85
  set(readonly_fields + requisition_identifier_fields + requisition_verify_fields)
@@ -24,7 +24,7 @@ class RequisitionFormValidatorMixin:
24
24
  if self.instance:
25
25
  if self.cleaned_data.get("packed") != self.instance.packed:
26
26
  raise forms.ValidationError({"packed": "Value may not be changed here."})
27
- elif self.cleaned_data.get("processed") != self.instance.processed:
27
+ if self.cleaned_data.get("processed") != self.instance.processed:
28
28
  if self.aliqout_model_cls.objects.filter(
29
29
  requisition_identifier=self.instance.requisition_identifier
30
30
  ).exists():
@@ -42,8 +42,7 @@ class RequisitionFormValidatorMixin:
42
42
  )
43
43
  elif self.instance.received:
44
44
  raise forms.ValidationError(
45
- "Requisition may not be changed. The specimen has "
46
- "already been received."
45
+ "Requisition may not be changed. The specimen has already been received."
47
46
  )
48
47
 
49
48
  self.applicable_if(NO, field="is_drawn", field_applicable="reason_not_drawn")
edc_lab/forms/box_form.py CHANGED
@@ -14,23 +14,17 @@ class BoxForm(forms.ModelForm):
14
14
  if cleaned_data.get("specimen_types"):
15
15
  pattern = "([0-9][0-9]*[ ]*,[ ]*)*[0-9][0-9]*"
16
16
  match = re.match(pattern, cleaned_data.get("specimen_types"))
17
- if not match:
17
+ if not match or match.group() != cleaned_data.get("specimen_types"):
18
18
  raise forms.ValidationError(
19
19
  {"specimen_types": "Invalid list of specimen types."},
20
20
  code="invalid format",
21
21
  )
22
- elif match.group() != cleaned_data.get("specimen_types"):
22
+ specimen_types = [code.strip() for code in match.group().split(",")]
23
+ if len(specimen_types) != len(list(set(specimen_types))):
23
24
  raise forms.ValidationError(
24
- {"specimen_types": "Invalid list of specimen types."},
25
- code="invalid format",
25
+ {"specimen_types": "List must be unique."},
26
+ code="list not unique",
26
27
  )
27
- else:
28
- specimen_types = [code.strip() for code in match.group().split(",")]
29
- if len(specimen_types) != len(list(set(specimen_types))):
30
- raise forms.ValidationError(
31
- {"specimen_types": "List must be unique."},
32
- code="list not unique",
33
- )
34
28
  cleaned_data["specimen_types"] = ",".join(specimen_types)
35
29
  form_validator.validate_other_specify("category")
36
30
  return cleaned_data
@@ -1,6 +1,3 @@
1
- from typing import Optional
2
-
3
-
4
1
  class AliquotIdentifierLengthError(Exception):
5
2
  pass
6
3
 
@@ -17,10 +14,10 @@ class AliquotIdentifier:
17
14
 
18
15
  def __init__(
19
16
  self,
20
- identifier_prefix: Optional[str] = None,
21
- parent_segment: Optional[str] = None,
22
- numeric_code: Optional[str] = None,
23
- count: Optional[int] = None,
17
+ identifier_prefix: str | None = None,
18
+ parent_segment: str | None = None,
19
+ numeric_code: str | None = None,
20
+ count: int | None = None,
24
21
  ):
25
22
  """
26
23
  A class to generate aliquot identifiers:
@@ -30,7 +27,7 @@ class AliquotIdentifier:
30
27
  * numeric_code: aliquot type numeric code (2 digits segment)
31
28
  * count: sequence in aliquoting history relative to primary. (01 for primary)
32
29
  """
33
- self.count: Optional[int] = count
30
+ self.count: int | None = count
34
31
  self.identifier_prefix: str = identifier_prefix or ""
35
32
  self.is_primary: bool = True
36
33
  self.numeric_code: str = numeric_code or ""
@@ -1,6 +1,3 @@
1
- from typing import Optional
2
-
3
-
4
1
  class PrefixLengthError(Exception):
5
2
  pass
6
3
 
@@ -17,8 +14,8 @@ class Prefix:
17
14
 
18
15
  def __init__(
19
16
  self,
20
- template: Optional[str] = None,
21
- length: Optional[int] = None,
17
+ template: str | None = None,
18
+ length: int | None = None,
22
19
  **template_opts,
23
20
  ):
24
21
  self.template: str = template or self.template
@@ -37,8 +37,7 @@ class AliquotCreator:
37
37
  "Cannot create child aliquot without parent aliquot identifier. "
38
38
  f"Got is_primary={is_primary}."
39
39
  )
40
- else:
41
- self.parent_identifier = parent_identifier
40
+ self.parent_identifier = parent_identifier
42
41
  self.identifier_prefix = (
43
42
  identifier_prefix
44
43
  or f"{ResearchProtocolConfig().protocol_number}{self.requisition_identifier}"
@@ -22,12 +22,10 @@ class AliquotType:
22
22
  self.name = name
23
23
  if not alpha_code or not re.match(r"^[A-Z]+$", alpha_code, re.ASCII):
24
24
  raise AliquotTypeAlphaCodeError(f"Invalid alpha code. Got {alpha_code}.")
25
- else:
26
- self.alpha_code = alpha_code
25
+ self.alpha_code = alpha_code
27
26
  if not numeric_code or not re.match(r"^\d+$", numeric_code, re.ASCII):
28
27
  raise AliquotTypeNumericCodeError(f"Invalid numeric code. Got {numeric_code}.")
29
- else:
30
- self.numeric_code = numeric_code
28
+ self.numeric_code = numeric_code
31
29
 
32
30
  def __repr__(self):
33
31
  return "{self.__class__.__name__}({self.name}, {self.alpha_code}, {self.numeric_code})"
edc_lab/lab/manifest.py CHANGED
@@ -41,7 +41,7 @@ class Manifest:
41
41
  """
42
42
  added = 0
43
43
  if not box:
44
- message = "Box does not exist. Got {}.".format(manifest_item_identifier)
44
+ message = f"Box does not exist. Got {manifest_item_identifier}."
45
45
  messages.error(self.request, message)
46
46
  elif self.validate_box_category(box) and self.validate_box_verified(box):
47
47
  try:
@@ -77,8 +77,8 @@ class Manifest:
77
77
  )
78
78
  messages.error(self.request, message)
79
79
  else:
80
- message = "Duplicate item. Got {}.".format(
81
- manifest_item.manifest.human_readable_identifier
80
+ message = (
81
+ f"Duplicate item. Got {manifest_item.manifest.human_readable_identifier}."
82
82
  )
83
83
  messages.error(self.request, message)
84
84
  return added
@@ -86,9 +86,7 @@ class Manifest:
86
86
  def validate_box_category(self, box=None):
87
87
  """Returns True if box category matches manifest category."""
88
88
  if box.category != self.manifest.category:
89
- message = "Invalid category. Manifest accepts {}. Got {}.".format(
90
- self.manifest.get_category_display(), box.get_category_display()
91
- )
89
+ message = f"Invalid category. Manifest accepts {self.manifest.get_category_display()}. Got {box.get_category_display()}."
92
90
  messages.error(self.request, message)
93
91
  return False
94
92
  return True
@@ -96,7 +94,7 @@ class Manifest:
96
94
  def validate_box_verified(self, box=None):
97
95
  """Returns True if box status is verified."""
98
96
  if box.status != VERIFIED:
99
- message = "Box is not verified. Got {}.".format(box.human_readable_identifier)
97
+ message = f"Box is not verified. Got {box.human_readable_identifier}."
100
98
  messages.error(self.request, message)
101
99
  return False
102
100
  return True
@@ -1,7 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Type
4
-
5
3
  from django.apps import apps as django_apps
6
4
  from django.db import models
7
5
 
@@ -85,7 +83,7 @@ class RequisitionPanel:
85
83
  return self._panel_model_obj
86
84
 
87
85
  @property
88
- def requisition_model_cls(self) -> Type[models.Model]:
86
+ def requisition_model_cls(self) -> type[models.Model]:
89
87
  """Returns the requisition model class associated with this
90
88
  panel (set by it's lab profile).
91
89
  """
@@ -95,7 +93,7 @@ class RequisitionPanel:
95
93
  raise RequisitionPanelLookupError(
96
94
  f"Invalid requisition model. requisition model="
97
95
  f"'{self.requisition_model}'. "
98
- f"See {repr(self)} or the lab profile {self.lab_profile_name}."
96
+ f"See {self!r} or the lab profile {self.lab_profile_name}."
99
97
  f"Got {e}"
100
98
  )
101
99
  return requisition_model_cls
@@ -1,5 +1,3 @@
1
- from typing import Optional
2
-
3
1
  from .processing_profile import ProcessingProfile
4
2
  from .requisition_panel import RequisitionPanel
5
3
 
@@ -12,11 +10,11 @@ class RequisitionPanelGroup(RequisitionPanel):
12
10
  def __init__(
13
11
  self,
14
12
  *panels,
15
- name: Optional[str] = None,
16
- verbose_name: Optional[str] = None,
17
- abbreviation: Optional[str] = None,
18
- is_poc: Optional[bool] = None,
19
- reference_range_collection_name: Optional[str] = None,
13
+ name: str | None = None,
14
+ verbose_name: str | None = None,
15
+ abbreviation: str | None = None,
16
+ is_poc: bool | None = None,
17
+ reference_range_collection_name: str | None = None,
20
18
  ):
21
19
  processing_profile = ProcessingProfile(
22
20
  name=f"{name} group", aliquot_type=panels[0].aliquot_type
@@ -110,7 +110,7 @@ class RequisitionModelMixin(
110
110
  ),
111
111
  )
112
112
 
113
- comments = models.TextField(max_length=25, null=True, blank=True)
113
+ comments = models.TextField(max_length=25, blank=True, default="")
114
114
 
115
115
  objects = RequisitionManager()
116
116
 
@@ -130,7 +130,7 @@ class RequisitionModelMixin(
130
130
  super().save(*args, **kwargs)
131
131
 
132
132
  def natural_key(self):
133
- return (self.requisition_identifier,) # noqa
133
+ return (self.requisition_identifier,)
134
134
 
135
135
  natural_key.dependencies = [settings.SUBJECT_VISIT_MODEL, "sites.Site"]
136
136
 
@@ -155,8 +155,9 @@ class RequisitionModelMixin(
155
155
  )
156
156
  ]
157
157
 
158
- indexes = NonUniqueSubjectIdentifierFieldMixin.Meta.indexes + [
158
+ indexes = (
159
+ *NonUniqueSubjectIdentifierFieldMixin.Meta.indexes,
159
160
  models.Index(fields=["subject_visit", "site", "panel"]),
160
161
  models.Index(fields=["subject_visit", "panel"]),
161
162
  models.Index(fields=["subject_visit", "report_datetime"]),
162
- ]
163
+ )
@@ -20,13 +20,13 @@ class ManifestModelMixin(SiteModelMixin, models.Model):
20
20
 
21
21
  manifest_datetime = models.DateTimeField(default=timezone.now)
22
22
 
23
- export_datetime = models.DateTimeField(null=True, blank=True)
23
+ export_datetime = models.DateTimeField(blank=True)
24
24
 
25
- export_references = models.TextField(null=True, blank=True)
25
+ export_references = models.TextField(blank=True, default="")
26
26
 
27
27
  description = models.TextField(
28
28
  verbose_name="Description of contents",
29
- null=True,
29
+ default="",
30
30
  help_text="If blank will be automatically generated",
31
31
  )
32
32
 
@@ -36,7 +36,7 @@ class ManifestModelMixin(SiteModelMixin, models.Model):
36
36
 
37
37
  category_other = models.CharField(max_length=25, null=True, blank=True)
38
38
 
39
- comment = models.TextField(verbose_name="Comment", null=True)
39
+ comment = models.TextField(verbose_name="Comment", blank=True, default="")
40
40
 
41
41
  shipped = models.BooleanField(default=False)
42
42
 
@@ -56,14 +56,14 @@ class ManifestModelMixin(SiteModelMixin, models.Model):
56
56
  super().save(*args, **kwargs)
57
57
 
58
58
  def natural_key(self):
59
- return (self.manifest_identifier,) # noqa
59
+ return (self.manifest_identifier,)
60
60
 
61
61
  natural_key.dependencies = ["sites.Site"]
62
62
 
63
63
  @property
64
64
  def human_readable_identifier(self):
65
65
  x = self.manifest_identifier
66
- return "{}-{}-{}".format(x[0:4], x[4:8], x[8:12])
66
+ return f"{x[0:4]}-{x[4:8]}-{x[8:12]}"
67
67
 
68
68
  class Meta:
69
69
  abstract = True
@@ -41,9 +41,10 @@ class VerifyBoxModelMixin(VerifyModelMixin, models.Model):
41
41
 
42
42
  @property
43
43
  def is_verified(self):
44
- if self.boxitem_set.all().count() == 0:
45
- return False
46
- elif self.boxitem_set.filter(verified=False).exists():
44
+ if (
45
+ self.boxitem_set.all().count() == 0
46
+ or self.boxitem_set.filter(verified=False).exists()
47
+ ):
47
48
  return False
48
49
  return True
49
50
 
edc_lab/models/aliquot.py CHANGED
@@ -42,7 +42,7 @@ class Aliquot(
42
42
  def human_readable_identifier(self):
43
43
  """Returns a human readable aliquot identifier."""
44
44
  x = self.aliquot_identifier
45
- return "{}-{}-{}-{}-{}".format(x[0:3], x[3:6], x[6:10], x[10:14], x[14:18])
45
+ return f"{x[0:3]}-{x[3:6]}-{x[6:10]}-{x[10:14]}-{x[14:18]}"
46
46
 
47
47
  class Meta(BaseUuidModel.Meta):
48
48
  verbose_name = "Aliquot"
edc_lab/models/box.py CHANGED
@@ -68,7 +68,7 @@ class Box(SearchSlugModelMixin, VerifyBoxModelMixin, SiteModelMixin, BaseUuidMod
68
68
  help_text="Tick to allow 'primary' specimens to be added to this box",
69
69
  )
70
70
 
71
- comment = models.TextField(null=True, blank=True)
71
+ comment = models.TextField(blank=True, default="")
72
72
 
73
73
  objects = BoxManager()
74
74
 
@@ -104,7 +104,7 @@ class Box(SearchSlugModelMixin, VerifyBoxModelMixin, SiteModelMixin, BaseUuidMod
104
104
  @property
105
105
  def human_readable_identifier(self):
106
106
  x = self.box_identifier
107
- return "{}-{}-{}".format(x[0:4], x[4:8], x[8:12])
107
+ return f"{x[0:4]}-{x[4:8]}-{x[8:12]}"
108
108
 
109
109
  @property
110
110
  def next_position(self):
@@ -45,7 +45,7 @@ class BoxItem(SearchSlugModelMixin, VerifyModelMixin, BaseUuidModel):
45
45
  if self.identifier:
46
46
  x = self.identifier
47
47
  if re.match(aliquot_pattern, self.identifier):
48
- return "{}-{}-{}-{}-{}".format(x[0:3], x[3:6], x[6:10], x[10:14], x[14:18])
48
+ return f"{x[0:3]}-{x[3:6]}-{x[6:10]}-{x[10:14]}-{x[14:18]}"
49
49
  return self.identifier
50
50
 
51
51
  def get_slugs(self):
@@ -36,7 +36,7 @@ class BoxType(BaseUuidModel):
36
36
  return f"{self.name} max={self.total}"
37
37
 
38
38
  def natural_key(self):
39
- return (self.name,) # noqa
39
+ return (self.name,)
40
40
 
41
41
  class Meta(BaseUuidModel.Meta):
42
42
  verbose_name = "Box Type"
@@ -35,7 +35,7 @@ class ManifestItem(SiteModelMixin, SearchSlugModelMixin, VerifyModelMixin, BaseU
35
35
  @property
36
36
  def human_readable_identifier(self):
37
37
  x = self.identifier
38
- return "{}-{}-{}".format(x[0:4], x[4:8], x[8:12])
38
+ return f"{x[0:4]}-{x[4:8]}-{x[8:12]}"
39
39
 
40
40
  class Meta(BaseUuidModel.Meta):
41
41
  verbose_name = "Manifest Item"
@@ -23,7 +23,7 @@ if TYPE_CHECKING:
23
23
 
24
24
  from ..model_mixins import ManifestModelMixin
25
25
 
26
- class Model(PdfReportModelMixin, ManifestModelMixin, BaseUuidModel): ... # noqa
26
+ class Model(PdfReportModelMixin, ManifestModelMixin, BaseUuidModel): ...
27
27
 
28
28
 
29
29
  class ManifestPdfReportError(Exception):
@@ -403,7 +403,7 @@ class ManifestPdfReport(Report):
403
403
  ),
404
404
  Paragraph(box.specimen_types, self.styles["line_data_large"]),
405
405
  Paragraph(
406
- f"{str(box.count)}/{str(box.box_type.total)}",
406
+ f"{box.count!s}/{box.box_type.total!s}",
407
407
  self.styles["line_data_large"],
408
408
  ),
409
409
  Paragraph(
@@ -450,11 +450,7 @@ class ManifestPdfReport(Report):
450
450
  Paragraph(aliquot.human_readable_identifier, self.styles["row_data"]),
451
451
  Paragraph(aliquot.subject_identifier, self.styles["row_data"]),
452
452
  Paragraph(
453
- "{} ({}) {}".format(
454
- aliquot.aliquot_type,
455
- aliquot.numeric_code,
456
- panel_object.abbreviation,
457
- ),
453
+ f"{aliquot.aliquot_type} ({aliquot.numeric_code}) {panel_object.abbreviation}",
458
454
  self.styles["row_data"],
459
455
  ),
460
456
  Paragraph(
edc_lab/site_labs.py CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import copy
4
4
  import sys
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
@@ -53,7 +53,7 @@ class SiteLabs:
53
53
  def registry(self):
54
54
  if not self.loaded:
55
55
  raise RegistryNotLoaded(
56
- "Registry not loaded. Is AppConfig for 'edc_lab' " "declared in settings?."
56
+ "Registry not loaded. Is AppConfig for 'edc_lab' declared in settings?."
57
57
  )
58
58
  return self._registry
59
59
 
@@ -112,7 +112,7 @@ class SiteLabs:
112
112
  f"before attempting to creating new Panel model instances."
113
113
  )
114
114
 
115
- def update_panel_model(self, panel_model_cls: Type[Panel] = None) -> None:
115
+ def update_panel_model(self, panel_model_cls: type[Panel] = None) -> None:
116
116
  """Updates or creates panel mode instances.
117
117
 
118
118
  Initially called in the post_migrate signal.
@@ -12,7 +12,7 @@ dashboard_templates = dict(
12
12
  edc_lab_base_listboard_template="edc_lab_dashboard/base_listboard.html",
13
13
  edc_lab_listboard_template="edc_lab_dashboard/listboard.html",
14
14
  manage_box_listboard_template="edc_lab_dashboard/manage_box_listboard.html",
15
- manage_manifest_listboard_template="edc_lab_dashboard/manage_manifest_listboard.html", # noqa
15
+ manage_manifest_listboard_template="edc_lab_dashboard/manage_manifest_listboard.html",
16
16
  manifest_listboard_template="edc_lab_dashboard/manifest_listboard.html",
17
17
  pack_listboard_template="edc_lab_dashboard/pack_listboard.html",
18
18
  process_listboard_template="edc_lab_dashboard/process_listboard.html",