clinicedc 2.0.4__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.4.dist-info → clinicedc-2.0.5.dist-info}/METADATA +41 -45
  2. {clinicedc-2.0.4.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 +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 -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.4.dist-info → clinicedc-2.0.5.dist-info}/WHEEL +0 -0
  478. {clinicedc-2.0.4.dist-info → clinicedc-2.0.5.dist-info}/licenses/LICENSE +0 -0
@@ -186,7 +186,7 @@ class AddToStorageBinView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin, T
186
186
  },
187
187
  )
188
188
  return HttpResponseRedirect(url)
189
- elif items_to_scan and stock_codes:
189
+ if items_to_scan and stock_codes:
190
190
  try:
191
191
  codes_created, codes_not_created = update_bin(
192
192
  storage_bin,
@@ -33,9 +33,7 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
33
33
 
34
34
  def get_context_data(self, **kwargs):
35
35
  remaining_count, total_count = self.get_counts(self.stock_request)
36
- show_count = (
37
- self.items_per_page if remaining_count >= self.items_per_page else remaining_count
38
- )
36
+ show_count = min(self.items_per_page, remaining_count)
39
37
  kwargs.update(
40
38
  stock_request=self.stock_request,
41
39
  assignment=self.selected_assignment,
@@ -255,7 +253,6 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
255
253
  def redirect_on_all_allocated_for_assignment(
256
254
  self, stock_request: StockRequest, assignment: Assignment
257
255
  ) -> str | None:
258
-
259
256
  if not stock_request.stockrequestitem_set.filter(
260
257
  allocation__isnull=True, assignment=assignment
261
258
  ).exists():
@@ -284,7 +281,6 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
284
281
  stock_request: StockRequest,
285
282
  assignment: Assignment,
286
283
  ) -> str | None:
287
-
288
284
  if stock_codes and Stock.objects.filter(
289
285
  code__in=stock_codes, lot__assignment=assignment
290
286
  ).count() != len(stock_codes):
@@ -347,7 +343,7 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
347
343
  return HttpResponseRedirect(url)
348
344
 
349
345
  if stock_codes and subject_identifiers and assignment:
350
- allocation_data = dict(zip(stock_codes, subject_identifiers))
346
+ allocation_data = dict(zip(stock_codes, subject_identifiers, strict=False))
351
347
  try:
352
348
  allocated, not_allocated = allocate_stock(
353
349
  stock_request,
@@ -47,7 +47,7 @@ class ConfirmStockFromInstanceView(
47
47
  )
48
48
  .count()
49
49
  )
50
- unconfirmed_count = 12 if unconfirmed_count > 12 else unconfirmed_count
50
+ unconfirmed_count = min(unconfirmed_count, 12)
51
51
 
52
52
  kwargs.update(
53
53
  source_identifier=dct.get("source_identifier"),
@@ -83,12 +83,12 @@ class ConfirmStockFromInstanceView(
83
83
  @property
84
84
  def source_changelist_url(self):
85
85
  return reverse(
86
- f"edc_pharmacy_admin:edc_pharmacy_{self.kwargs.get("model")}_changelist"
86
+ f"edc_pharmacy_admin:edc_pharmacy_{self.kwargs.get('model')}_changelist"
87
87
  )
88
88
 
89
89
  @property
90
90
  def model_cls(self):
91
- return django_apps.get_model(f"edc_pharmacy.{self.kwargs.get("model")}")
91
+ return django_apps.get_model(f"edc_pharmacy.{self.kwargs.get('model')}")
92
92
 
93
93
  def post(self, request, *args, **kwargs):
94
94
  dct = self.get_values_dict(**kwargs)
@@ -114,5 +114,5 @@ class ConfirmStockFromInstanceView(
114
114
  ):
115
115
  url = reverse("edc_pharmacy:confirm_stock_from_instance_url", kwargs=kwargs)
116
116
  else:
117
- url = f"{self.source_changelist_url}?q={dct.get("obj").pk}"
117
+ url = f"{self.source_changelist_url}?q={dct.get('obj').pk}"
118
118
  return HttpResponseRedirect(url)
@@ -105,11 +105,7 @@ class ConfirmStockFromQuerySetView(
105
105
 
106
106
  @property
107
107
  def adjusted_unconfirmed_count(self) -> int:
108
- return (
109
- self.codes_per_page
110
- if self.unconfirmed_count > self.codes_per_page
111
- else self.unconfirmed_count
112
- )
108
+ return min(self.unconfirmed_count, self.codes_per_page)
113
109
 
114
110
  @property
115
111
  def source_changelist_url(self):
@@ -94,7 +94,7 @@ class ConfirmationAtSiteView(
94
94
 
95
95
  def get_adjusted_unconfirmed_count(self, stock_transfer):
96
96
  unconfirmed_count = self.get_unconfirmed_count(stock_transfer)
97
- return 12 if unconfirmed_count > 12 else unconfirmed_count
97
+ return min(unconfirmed_count, 12)
98
98
 
99
99
  def get_stock_codes(self, stock_transfer):
100
100
  stock_codes = [
@@ -199,7 +199,6 @@ class ConfirmationAtSiteView(
199
199
  return stock_transfer
200
200
 
201
201
  def post(self, request, *args, **kwargs) -> HttpResponseRedirect:
202
-
203
202
  # cancel
204
203
  if request.POST.get("cancel") and request.POST.get("cancel") == "cancel":
205
204
  url = reverse("edc_pharmacy:home_url")
@@ -230,7 +229,7 @@ class ConfirmationAtSiteView(
230
229
  )
231
230
  return HttpResponseRedirect(url)
232
231
 
233
- elif stock_codes:
232
+ if stock_codes:
234
233
  # you have scanned codes, process them
235
234
  confirmed, already_confirmed, invalid = confirm_stock_at_site(
236
235
  stock_transfer, stock_codes, location_id, request=request
@@ -106,7 +106,7 @@ class DispenseView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin, Template
106
106
  )
107
107
  return HttpResponseRedirect(url)
108
108
 
109
- elif stock_codes and location and formulation and rx and container_count:
109
+ if stock_codes and location and formulation and rx and container_count:
110
110
  dispense_qs = dispense(
111
111
  stock_codes,
112
112
  location,
@@ -28,7 +28,7 @@ def move_to_bin(
28
28
  )
29
29
  if new_capacity > 50:
30
30
  raise StorageBinError(f"Storage bin {storage_bin.name} capacity may not exceeded 50")
31
- elif new_capacity > storage_bin.capacity:
31
+ if new_capacity > storage_bin.capacity:
32
32
  storage_bin.capacity = new_capacity
33
33
  storage_bin.save()
34
34
  messages.add_message(
@@ -66,7 +66,6 @@ def move_to_bin(
66
66
 
67
67
  @method_decorator(login_required, name="dispatch")
68
68
  class MoveToStorageBinView(AddToStorageBinView):
69
-
70
69
  action_word = "Move"
71
70
 
72
71
  def redirect_on_stock_not_already_in_a_bin(
@@ -109,7 +108,7 @@ class MoveToStorageBinView(AddToStorageBinView):
109
108
  },
110
109
  )
111
110
  return HttpResponseRedirect(url)
112
- elif items_to_scan and stock_codes:
111
+ if items_to_scan and stock_codes:
113
112
  try:
114
113
  codes_moved, codes_not_moved = move_to_bin(
115
114
  storage_bin, stock_codes, request.user.username, request
@@ -94,37 +94,36 @@ class PrintLabelsView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin, Templ
94
94
  ),
95
95
  )
96
96
  return HttpResponseRedirect(request.META.get("HTTP_REFERER", ""))
97
+ label_data = [obj for obj in queryset]
98
+ drawing_callable = site_label_configs.get(
99
+ label_configuration.name
100
+ ).drawing_callable
101
+ specs = Specification(**label_configuration.label_specification.as_dict)
102
+ sheet = Sheet(
103
+ specs,
104
+ drawing_callable,
105
+ border=label_configuration.label_specification.border,
106
+ )
107
+ try:
108
+ sheet.add_labels(label_data)
109
+ except AttributeError:
110
+ messages.add_message(
111
+ request,
112
+ messages.ERROR,
113
+ (
114
+ "Unable to print these items using the "
115
+ f"label format '{label_configuration.name}'. Perhaps try another."
116
+ ),
117
+ )
118
+ return HttpResponseRedirect(request.META.get("HTTP_REFERER", ""))
97
119
  else:
98
- label_data = [obj for obj in queryset]
99
- drawing_callable = site_label_configs.get(
100
- label_configuration.name
101
- ).drawing_callable
102
- specs = Specification(**label_configuration.label_specification.as_dict)
103
- sheet = Sheet(
104
- specs,
105
- drawing_callable,
106
- border=label_configuration.label_specification.border,
120
+ buffer = sheet.save_to_buffer()
121
+ now = get_utcnow()
122
+ return FileResponse(
123
+ buffer,
124
+ as_attachment=True,
125
+ filename=(
126
+ f"{label_configuration.name}_{now.strftime('%Y-%m-%d %H:%M')}.pdf"
127
+ ),
107
128
  )
108
- try:
109
- sheet.add_labels(label_data)
110
- except AttributeError:
111
- messages.add_message(
112
- request,
113
- messages.ERROR,
114
- (
115
- "Unable to print these items using the "
116
- f"label format '{label_configuration.name}'. Perhaps try another."
117
- ),
118
- )
119
- return HttpResponseRedirect(request.META.get("HTTP_REFERER", ""))
120
- else:
121
- buffer = sheet.save_to_buffer()
122
- now = get_utcnow()
123
- return FileResponse(
124
- buffer,
125
- as_attachment=True,
126
- filename=(
127
- f"{label_configuration.name}_{now.strftime('%Y-%m-%d %H:%M')}.pdf"
128
- ),
129
- )
130
129
  return HttpResponseRedirect(url)
@@ -35,7 +35,7 @@ class TransferStockView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin, Tem
35
35
  stock_transfer=stock_transfer
36
36
  ).count()
37
37
  item_count = stock_transfer.item_count - transferred_count
38
- item_count = 12 if item_count > 12 else item_count
38
+ item_count = min(item_count, 12)
39
39
  kwargs.update(
40
40
  stock_transfer=stock_transfer,
41
41
  source_model_name=self.model_cls._meta.verbose_name_plural,
edc_prn/prn.py CHANGED
@@ -58,7 +58,7 @@ class Prn:
58
58
  try:
59
59
  return django_apps.get_model(self.model)
60
60
  except LookupError as e:
61
- raise PrnError(f"{e}. See {repr(self)}")
61
+ raise PrnError(f"{e}. See {self!r}")
62
62
 
63
63
  def get_show_on_dashboard(self, subject_identifier=None, **kwargs):
64
64
  count = 0
edc_prn/site_prn_forms.py CHANGED
@@ -38,8 +38,7 @@ class PrnFormsCollection:
38
38
  def register(self, prn: Prn = None) -> None:
39
39
  if prn.model in self.registry:
40
40
  raise AlreadyRegistered(f"PRN form {prn.model} is already registered.")
41
- else:
42
- self.registry.update({prn.model: prn})
41
+ self.registry.update({prn.model: prn})
43
42
  self.reorder_registry()
44
43
 
45
44
  def unregister(self, prn: Prn = None) -> None:
@@ -15,7 +15,7 @@ class ProtocolDeviationViolationAction(ActionWithNotification):
15
15
  name = PROTOCOL_DEVIATION_VIOLATION_ACTION
16
16
  display_name = "Submit Protocol Deviation / Violation Report"
17
17
  notification_display_name = "Protocol Deviation / Violation Report"
18
- parent_action_names = []
18
+ parent_action_names = ()
19
19
  show_link_to_changelist = True
20
20
  show_link_to_add = True
21
21
  priority = HIGH_PRIORITY
@@ -31,7 +31,7 @@ class ProtocolIncidentAction(ActionWithNotification):
31
31
  name = PROTOCOL_INCIDENT_ACTION
32
32
  display_name = "Submit Protocol Incident Report"
33
33
  notification_display_name = "Protocol Incident Report"
34
- parent_action_names = []
34
+ parent_action_names = ()
35
35
  show_link_to_changelist = True
36
36
  show_link_to_add = True
37
37
  priority = HIGH_PRIORITY
@@ -32,7 +32,7 @@ class ProtocolDeviationViolationModelMixin(models.Model):
32
32
  )
33
33
 
34
34
  safety_impact = models.CharField(
35
- verbose_name="Could this occurrence have an impact on safety of the " "participant?",
35
+ verbose_name="Could this occurrence have an impact on safety of the participant?",
36
36
  max_length=25,
37
37
  choices=YES_NO_NA,
38
38
  default=NOT_APPLICABLE,
@@ -78,7 +78,7 @@ class ProtocolDeviationViolationModelMixin(models.Model):
78
78
  null=True,
79
79
  blank=True,
80
80
  help_text=(
81
- "Describe in full. Explain how the violation " "happened, what occurred, etc."
81
+ "Describe in full. Explain how the violation happened, what occurred, etc."
82
82
  ),
83
83
  )
84
84
 
@@ -135,4 +135,4 @@ class ProtocolDeviationViolationModelMixin(models.Model):
135
135
  abstract = True
136
136
  verbose_name = "Protocol Deviation/Violation"
137
137
  verbose_name_plural = "Protocol Deviations/Violations"
138
- indexes = [models.Index(fields=["subject_identifier", "action_identifier", "site"])]
138
+ indexes = (models.Index(fields=["subject_identifier", "action_identifier", "site"]),)
@@ -19,10 +19,8 @@ class ProtocolIncidentModelMixin(models.Model):
19
19
  null=True,
20
20
  blank=False,
21
21
  help_text=(
22
- (
23
- "Max 35 characters. Note: there is additional space below for "
24
- "a more detailed description"
25
- )
22
+ "Max 35 characters. Note: there is additional space below for "
23
+ "a more detailed description"
26
24
  ),
27
25
  )
28
26
 
@@ -132,4 +130,4 @@ class ProtocolIncidentModelMixin(models.Model):
132
130
  abstract = True
133
131
  verbose_name = "Protocol Incident"
134
132
  verbose_name_plural = "Protocol Incident"
135
- indexes = [models.Index(fields=["subject_identifier", "action_identifier", "site"])]
133
+ indexes = (models.Index(fields=["subject_identifier", "action_identifier", "site"]),)
@@ -1,5 +1,3 @@
1
- from typing import Tuple
2
-
3
1
  from django.contrib import admin
4
2
  from django.utils.html import format_html
5
3
  from django_audit_fields.admin import audit_fieldset_tuple
@@ -88,7 +86,7 @@ class ProtocolIncidentModelAdminMixin:
88
86
 
89
87
  search_fields = ("subject_identifier",)
90
88
 
91
- def get_list_display(self, request) -> Tuple[str, ...]:
89
+ def get_list_display(self, request) -> tuple[str, ...]:
92
90
  list_display = super().get_list_display(request)
93
91
  custom_fields = (
94
92
  "subject_identifier",
@@ -103,12 +101,12 @@ class ProtocolIncidentModelAdminMixin:
103
101
  )
104
102
  return custom_fields + tuple(f for f in list_display if f not in custom_fields)
105
103
 
106
- def get_list_filter(self, request) -> Tuple[str, ...]:
104
+ def get_list_filter(self, request) -> tuple[str, ...]:
107
105
  list_filter = super().get_list_filter(request)
108
106
  custom_fields = ("action_required", "report_status", "report_type")
109
107
  return custom_fields + tuple(f for f in list_filter if f not in custom_fields)
110
108
 
111
- def get_search_fields(self, request) -> Tuple[str, ...]:
109
+ def get_search_fields(self, request) -> tuple[str, ...]:
112
110
  search_fields = super().get_search_fields(request)
113
111
  custom_fields = ("short_description",)
114
112
  return tuple(set(custom_fields + search_fields))
@@ -23,12 +23,12 @@ class ProtocolDeviationViolation(
23
23
  objects = ActionIdentifierModelManager()
24
24
 
25
25
  def natural_key(self):
26
- return (self.action_identifier,) # noqa
26
+ return (self.action_identifier,)
27
27
 
28
28
  class Meta(ProtocolDeviationViolationModelMixin.Meta, BaseUuidModel.Meta):
29
29
  indexes = (
30
- ProtocolDeviationViolationModelMixin.Meta.indexes
31
- + NonUniqueSubjectIdentifierFieldMixin.Meta.indexes
32
- + ActionModelMixin.Meta.indexes
33
- + BaseUuidModel.Meta.indexes
30
+ *ProtocolDeviationViolationModelMixin.Meta.indexes,
31
+ *NonUniqueSubjectIdentifierFieldMixin.Meta.indexes,
32
+ *ActionModelMixin.Meta.indexes,
33
+ *BaseUuidModel.Meta.indexes,
34
34
  )
@@ -23,12 +23,12 @@ class ProtocolIncident(
23
23
  objects = ActionIdentifierModelManager()
24
24
 
25
25
  def natural_key(self):
26
- return (self.action_identifier,) # noqa
26
+ return (self.action_identifier,)
27
27
 
28
28
  class Meta(ProtocolIncidentModelMixin.Meta, BaseUuidModel.Meta):
29
29
  indexes = (
30
- ProtocolIncidentModelMixin.Meta.indexes
31
- + NonUniqueSubjectIdentifierFieldMixin.Meta.indexes
32
- + ActionModelMixin.Meta.indexes
33
- + BaseUuidModel.Meta.indexes
30
+ *ProtocolIncidentModelMixin.Meta.indexes,
31
+ *NonUniqueSubjectIdentifierFieldMixin.Meta.indexes,
32
+ *ActionModelMixin.Meta.indexes,
33
+ *BaseUuidModel.Meta.indexes,
34
34
  )
@@ -2,8 +2,9 @@ from __future__ import annotations
2
2
 
3
3
  import copy
4
4
  import sys
5
+ from collections.abc import Callable
5
6
  from importlib import import_module
6
- from typing import Any, Callable
7
+ from typing import Any
7
8
 
8
9
  from django.apps import apps as django_apps
9
10
  from django.core.management.color import color_style
@@ -67,10 +68,9 @@ class SiteLabelConfigs:
67
68
  ) -> None:
68
69
  if name in self.registry:
69
70
  raise AlreadyRegistered(f"Already registered. Got name='{name}' ")
70
- else:
71
- self.registry.update(
72
- {name: LabelConfig(name, drawing_callable, label_cls, test_data_func)}
73
- )
71
+ self.registry.update(
72
+ {name: LabelConfig(name, drawing_callable, label_cls, test_data_func)}
73
+ )
74
74
 
75
75
  def all(self) -> dict[str, LabelConfig]:
76
76
  return self.registry
@@ -9,7 +9,6 @@ from .qa_reports_permissions import qa_reports_permissions
9
9
 
10
10
 
11
11
  class QaReportModelMixin(models.Model):
12
-
13
12
  report_model = models.CharField(max_length=50)
14
13
 
15
14
  subject_identifier = models.CharField(max_length=25)
@@ -18,6 +17,9 @@ class QaReportModelMixin(models.Model):
18
17
 
19
18
  created = models.DateTimeField(default=get_utcnow)
20
19
 
20
+ def __str__(self):
21
+ return f"{self.subject_identifier}: {self.report_model}"
22
+
21
23
  @classmethod
22
24
  def recreate_db_view(cls, drop: bool | None = None, verbose: bool | None = None):
23
25
  recreate_db_view(cls, drop=drop, verbose=verbose)
@@ -25,4 +27,4 @@ class QaReportModelMixin(models.Model):
25
27
  class Meta:
26
28
  abstract = True
27
29
  default_permissions = qa_reports_permissions
28
- indexes = [Index(fields=["subject_identifier", "site"])]
30
+ indexes = (Index(fields=["subject_identifier", "site"]),)
@@ -7,7 +7,6 @@ from ..model_mixins import qa_reports_permissions
7
7
 
8
8
 
9
9
  class QaReportLog(models.Model):
10
-
11
10
  username = models.CharField(max_length=100)
12
11
  site = models.ForeignKey(Site, on_delete=models.CASCADE)
13
12
  report_model = models.CharField(max_length=100)
@@ -16,5 +15,5 @@ class QaReportLog(models.Model):
16
15
  class Meta:
17
16
  verbose_name = "QA Report Log"
18
17
  verbose_name_plural = "QA Report Logs"
19
- indexes = [models.Index(fields=["accessed"])]
18
+ indexes = (models.Index(fields=["accessed"]),)
20
19
  default_permissions = qa_reports_permissions
edc_qareports/utils.py CHANGED
@@ -84,7 +84,7 @@ def recreate_db_view(model_cls, drop: bool | None = None, verbose: bool | None =
84
84
  """
85
85
  drop = True if drop is None else drop
86
86
  try:
87
- sql = model_cls.view_definition.get(settings.DATABASES["default"]["ENGINE"]) # noqa
87
+ sql = model_cls.view_definition.get(settings.DATABASES["default"]["ENGINE"])
88
88
  except AttributeError as e:
89
89
  raise AttributeError(
90
90
  f"Is this model linked to a view? Declare model with `DBView`. Got {e}"
@@ -107,7 +107,6 @@ def recreate_db_view(model_cls, drop: bool | None = None, verbose: bool | None =
107
107
 
108
108
 
109
109
  def recreate_dbview_for_all():
110
-
111
110
  from .model_mixins import QaReportModelMixin
112
111
 
113
112
  for model_cls in django_apps.get_models():
@@ -1,5 +1,3 @@
1
- from typing import Tuple
2
-
3
1
  from django.conf import settings
4
2
  from django.contrib import admin
5
3
  from django.contrib.admin.sites import AlreadyRegistered
@@ -91,7 +89,7 @@ class RandomizationListModelAdmin(TemplatesModelAdminMixin, admin.ModelAdmin):
91
89
  qs = qs.order_by(*ordering)
92
90
  return qs
93
91
 
94
- def get_list_display(self, request) -> Tuple[str, ...]:
92
+ def get_list_display(self, request) -> tuple[str, ...]:
95
93
  list_display = [
96
94
  "sid",
97
95
  "assignment",
@@ -114,7 +112,7 @@ class RandomizationListModelAdmin(TemplatesModelAdminMixin, admin.ModelAdmin):
114
112
  return tuple(list_display)
115
113
 
116
114
  @staticmethod
117
- def get_fieldnames(request) -> Tuple[str, ...]:
115
+ def get_fieldnames(request) -> tuple[str, ...]:
118
116
  fields = [
119
117
  "subject_identifier",
120
118
  "sid",
@@ -132,7 +130,7 @@ class RandomizationListModelAdmin(TemplatesModelAdminMixin, admin.ModelAdmin):
132
130
  fields.remove("assignment")
133
131
  return tuple(fields)
134
132
 
135
- def get_list_filter(self, request) -> Tuple[str, ...]:
133
+ def get_list_filter(self, request) -> tuple[str, ...]:
136
134
  list_filter = [
137
135
  "assignment",
138
136
  "allocated_datetime",
@@ -1,5 +1,4 @@
1
1
  import sys
2
- from typing import Optional
3
2
 
4
3
  from .site_randomizers import site_randomizers
5
4
 
@@ -36,7 +35,7 @@ export_rando = [
36
35
 
37
36
 
38
37
  # post_update_func
39
- def update_rando_group_permissions(auth_updater, app_label: Optional[str]):
38
+ def update_rando_group_permissions(auth_updater, app_label: str | None):
40
39
  """Update group permissions for each registered randomizer class."""
41
40
  for randomizer_cls in site_randomizers._registry.values():
42
41
  if auth_updater.verbose:
@@ -56,7 +55,7 @@ def update_rando_group_permissions(auth_updater, app_label: Optional[str]):
56
55
  )
57
56
 
58
57
 
59
- def make_randomizationlist_view_only(auth_updater, app_label: Optional[str]):
58
+ def make_randomizationlist_view_only(auth_updater, app_label: str | None):
60
59
  for randomizer_cls in site_randomizers._registry.values():
61
60
  randomizer_cls.apps = auth_updater.apps
62
61
  app_label, model = randomizer_cls.model_cls()._meta.label_lower.split(".")
@@ -1,4 +1,4 @@
1
- from typing import Iterable
1
+ from collections.abc import Iterable
2
2
 
3
3
  from django import forms
4
4
  from django.conf import settings
@@ -1,5 +1,3 @@
1
- from typing import Dict
2
-
3
1
  RANDOMIZED = "RANDOMIZED"
4
2
 
5
3
  ACTIVE = "active"
@@ -7,8 +5,8 @@ ACTIVE_NAME = "Active: "
7
5
  PLACEBO = "placebo"
8
6
  PLACEBO_NAME = "Placebo: "
9
7
  DEFAULT = "default"
10
- DEFAULT_ASSIGNMENT_MAP: Dict[str, int] = {ACTIVE: 1, PLACEBO: 2}
11
- DEFAULT_ASSIGNMENT_DESCRIPTION_MAP: Dict[str, str] = {
8
+ DEFAULT_ASSIGNMENT_MAP: dict[str, int] = {ACTIVE: 1, PLACEBO: 2}
9
+ DEFAULT_ASSIGNMENT_DESCRIPTION_MAP: dict[str, str] = {
12
10
  ACTIVE: "Active",
13
11
  PLACEBO: "Placebo",
14
12
  }
@@ -72,7 +72,7 @@ class RandomizationListModelMixin(models.Model):
72
72
  def save(self, *args, **kwargs):
73
73
  self.randomizer_name = self.randomizer_cls.name
74
74
  try:
75
- getattr(self, "assignment_description")
75
+ self.assignment_description
76
76
  except RandomizationError as e:
77
77
  raise RandomizationListModelError(e)
78
78
  try:
@@ -80,7 +80,7 @@ class RandomizationListModelMixin(models.Model):
80
80
  except ObjectDoesNotExist:
81
81
  site_names = [obj.name for obj in Site.objects.all()]
82
82
  raise RandomizationListModelError(
83
- f"Invalid site name. Got {self.site_name}. " f"Expected one of {site_names}."
83
+ f"Invalid site name. Got {self.site_name}. Expected one of {site_names}."
84
84
  )
85
85
  super().save(*args, **kwargs)
86
86
 
@@ -105,7 +105,7 @@ class RandomizationListModelMixin(models.Model):
105
105
  return self.assignment
106
106
 
107
107
  def natural_key(self):
108
- return (self.sid,) # noqa
108
+ return (self.sid,)
109
109
 
110
110
  class Meta:
111
111
  abstract = True
@@ -153,18 +153,17 @@ class RandomizationListImporter:
153
153
  f"File is empty. See {self.randomizer_name}. "
154
154
  f"Got {self.randomizationlist_path} (1)."
155
155
  )
156
- else:
157
- index = 0
158
- with self.randomizationlist_path.open(mode="r") as csvfile:
159
- reader = csv.DictReader(csvfile)
160
- for index, row in enumerate(reader):
161
- if index == 0:
162
- continue
163
- if index == 0:
164
- raise RandomizationListImportError(
165
- f"File is empty. See {self.randomizer_name}. "
166
- f"Got {self.randomizationlist_path} (2)."
167
- )
156
+ index = 0
157
+ with self.randomizationlist_path.open(mode="r") as csvfile:
158
+ reader = csv.DictReader(csvfile)
159
+ for index, row in enumerate(reader):
160
+ if index == 0:
161
+ continue
162
+ if index == 0:
163
+ raise RandomizationListImportError(
164
+ f"File is empty. See {self.randomizer_name}. "
165
+ f"Got {self.randomizationlist_path} (2)."
166
+ )
168
167
 
169
168
  def _raise_on_invalid_header(self):
170
169
  with self.randomizationlist_path.open(mode="r") as csvfile:
@@ -174,7 +173,7 @@ class RandomizationListImporter:
174
173
  for fieldname in self.required_csv_fieldnames:
175
174
  if fieldname not in row:
176
175
  raise RandomizationListImportError(
177
- "Invalid header. Missing column " f"`{fieldname}`. Got {row}"
176
+ f"Invalid header. Missing column `{fieldname}`. Got {row}"
178
177
  )
179
178
  elif index == 1:
180
179
  if self.dryrun:
@@ -286,7 +285,7 @@ class RandomizationListImporter:
286
285
  raise InvalidAssignment(
287
286
  f"Invalid assignment. Expected one of {list(assignment_map.keys())}. "
288
287
  f"Got `{assignment}`. "
289
- f"See randomizer `{self.randomizer_name}` {repr(self)}. "
288
+ f"See randomizer `{self.randomizer_name}` {self!r}. "
290
289
  )
291
290
  return assignment
292
291