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
@@ -6,7 +6,7 @@ style = color_style()
6
6
 
7
7
 
8
8
  class Command(BaseCommand):
9
- help = "Update search slugs if 'get_slugs' " "method definitions have changed."
9
+ help = "Update search slugs if 'get_slugs' method definitions have changed."
10
10
 
11
11
  def add_arguments(self, parser):
12
12
  parser.add_argument(
@@ -31,9 +31,7 @@ class Command(BaseCommand):
31
31
  if "historical" not in model._meta.label_lower:
32
32
  if hasattr(model, "update_search_slugs"):
33
33
  self.stdout.write(
34
- self.style.WARNING(
35
- "Updating '{}' ...".format(model._meta.label_lower)
36
- ),
34
+ self.style.WARNING(f"Updating '{model._meta.label_lower}' ..."),
37
35
  ending="\r",
38
36
  )
39
37
  try:
@@ -42,20 +40,19 @@ class Command(BaseCommand):
42
40
  if "update_search_slugs" in str(e):
43
41
  raise CommandError(
44
42
  "Missing manager method 'update_search_slugs'. "
45
- "See model {}. Got {}".format(model._meta.label_lower, str(e))
43
+ f"See model {model._meta.label_lower}. Got {e!s}"
46
44
  )
47
- else:
48
- raise CommandError(e)
45
+ raise CommandError(e)
49
46
  except Exception as e:
50
47
  raise CommandError(
51
- "An exception occurred when updating model {}. "
52
- "Got {}".format(model._meta.label_lower, e)
48
+ f"An exception occurred when updating model {model._meta.label_lower}. "
49
+ f"Got {e}"
53
50
  )
54
51
  else:
55
52
  self.stdout.write(
56
53
  self.style.SUCCESS(
57
- "Updating '{}' ... Done".format(model._meta.label_lower)
54
+ f"Updating '{model._meta.label_lower}' ... Done"
58
55
  )
59
56
  )
60
57
  else:
61
- self.stdout.write("------- {}".format(model._meta.label_lower))
58
+ self.stdout.write(f"------- {model._meta.label_lower}")
@@ -58,7 +58,7 @@ def page_numbers(page, numpages):
58
58
  min_n = page - 5
59
59
  min_n = 1 if min_n <= 0 else min_n
60
60
  max_n = min_n + 9
61
- max_n = numpages if max_n >= numpages else max_n
61
+ max_n = min(numpages, max_n)
62
62
  page_numbers_ = [x for x in range(min_n, max_n + 1)]
63
63
  return page_numbers_ or []
64
64
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Type
3
+ from typing import TYPE_CHECKING
4
4
 
5
5
  from django.urls.conf import re_path
6
6
 
@@ -14,7 +14,7 @@ if TYPE_CHECKING:
14
14
 
15
15
  from .view_mixins import UrlRequestContextMixin
16
16
 
17
- class View(UrlRequestContextMixin, BaseView): ... # noqa
17
+ class View(UrlRequestContextMixin, BaseView): ...
18
18
 
19
19
 
20
20
  class UrlConfig:
@@ -22,7 +22,7 @@ class UrlConfig:
22
22
  self,
23
23
  url_name: str = None,
24
24
  namespace: str = None,
25
- view_class: Type[View | UrlRequestContextMixin] = None,
25
+ view_class: type[View | UrlRequestContextMixin] = None,
26
26
  label: str = None,
27
27
  identifier_label: str = None,
28
28
  identifier_pattern: str = None,
edc_dashboard/utils.py CHANGED
@@ -30,12 +30,11 @@ def splitall(path):
30
30
  if parts[0] == path: # sentinel for absolute paths
31
31
  allparts.insert(0, parts[0])
32
32
  break
33
- elif parts[1] == path: # sentinel for relative paths
33
+ if parts[1] == path: # sentinel for relative paths
34
34
  allparts.insert(0, parts[1])
35
35
  break
36
- else:
37
- path = parts[0]
38
- allparts.insert(0, parts[1])
36
+ path = parts[0]
37
+ allparts.insert(0, parts[1])
39
38
  return allparts
40
39
 
41
40
 
@@ -18,7 +18,7 @@ class DashboardView(UrlRequestContextMixin, TemplateRequestContextMixin, Templat
18
18
  if not self.dashboard_template and not self.dashboard_template_name:
19
19
  raise ImproperlyConfigured(
20
20
  f"Both 'dashboard_template' and 'dashboard_template_name' "
21
- f"cannot be None. See {repr(self)}."
21
+ f"cannot be None. See {self!r}."
22
22
  )
23
23
  super().__init__(**kwargs)
24
24
 
@@ -11,7 +11,6 @@ class DataDictionaryManager(models.Manager):
11
11
 
12
12
 
13
13
  class DataDictionary(BaseUuidModel):
14
-
15
14
  # see edc_model_to_dataframe
16
15
  m2m_related_field = "model"
17
16
 
@@ -74,4 +73,4 @@ class DataDictionary(BaseUuidModel):
74
73
  verbose_name_plural = "Data Dictionary Items"
75
74
  default_permissions = ("view", "export")
76
75
  unique_together = (("model", "field_name"),)
77
- indexes = [Index(fields=["model", "number", "prompt"])]
76
+ indexes = (Index(fields=["model", "number", "prompt"]),)
@@ -193,7 +193,7 @@ class DataQuery(DataQueryModelMixin, ActionModelMixin, SiteModelMixin, BaseUuidM
193
193
  verbose_name = "Data Query"
194
194
  verbose_name_plural = "Data Queries"
195
195
  unique_together = ["registered_subject", "rule_reference", "visit_schedule"]
196
- indexes = [
196
+ indexes = (
197
197
  models.Index(
198
198
  fields=[
199
199
  "subject_identifier",
@@ -203,5 +203,5 @@ class DataQuery(DataQueryModelMixin, ActionModelMixin, SiteModelMixin, BaseUuidM
203
203
  "registered_subject",
204
204
  "visit_schedule",
205
205
  ]
206
- )
207
- ]
206
+ ),
207
+ )
@@ -207,7 +207,7 @@ class QueryRule(BaseUuidModel):
207
207
  super().save(*args, **kwargs)
208
208
 
209
209
  def natural_key(self):
210
- return (self.title,) # noqa
210
+ return (self.title,)
211
211
 
212
212
  natural_key.dependencies = [
213
213
  "edc_data_manager.CrfDataDictionary",
@@ -238,4 +238,4 @@ class QueryRule(BaseUuidModel):
238
238
  class Meta(BaseUuidModel.Meta):
239
239
  verbose_name = "Query Rule"
240
240
  verbose_name_plural = "Query Rules"
241
- indexes = [models.Index(fields=["title", "active"])]
241
+ indexes = (models.Index(fields=["title", "active"]),)
edc_data_manager/tasks.py CHANGED
@@ -1,5 +1,3 @@
1
- from __future__ import absolute_import, unicode_literals
2
-
3
1
  from celery import shared_task
4
2
  from django.conf import settings
5
3
 
edc_device/device.py CHANGED
@@ -36,7 +36,7 @@ class Device:
36
36
  f"Central server ID may not be included with node IDs. "
37
37
  f"Got {self.central_server_id}, nodes={self.nodes}."
38
38
  )
39
- elif central_server_id in self.middlemen:
39
+ if central_server_id in self.middlemen:
40
40
  raise DeviceIdError(
41
41
  f"Central server ID may not be included with middleman IDs. "
42
42
  f"Got {self.central_server_id}, middlemen={self.middlemen}."
edc_device/view_mixins.py CHANGED
@@ -12,7 +12,7 @@ def get_client_ip(request):
12
12
  ip = request.META.get("REMOTE_ADDR")
13
13
  try:
14
14
  socket.inet_aton(ip)
15
- except socket.error:
15
+ except OSError:
16
16
  return None
17
17
  else:
18
18
  return ip
@@ -1,6 +1,4 @@
1
- from typing import Dict, Tuple
2
-
3
- document_status_fieldset_tuple: Tuple[str, Dict[str, Tuple[str, ...]]] = (
1
+ document_status_fieldset_tuple: tuple[str, dict[str, tuple[str, ...]]] = (
4
2
  "Document status",
5
3
  {"classes": ("collapse",), "fields": ("document_status",)},
6
4
  )
@@ -1,4 +1,4 @@
1
- from typing import Any, Optional
1
+ from typing import Any
2
2
 
3
3
  from django.db import models
4
4
 
@@ -26,7 +26,7 @@ class DocumentStatusModelMixin(models.Model):
26
26
  self.update_document_status_on_save(kwargs.get("update_fields"))
27
27
  super().save(*args, **kwargs)
28
28
 
29
- def update_document_status_on_save(self, update_fields: Optional[list] = None) -> None:
29
+ def update_document_status_on_save(self, update_fields: list | None = None) -> None:
30
30
  """Updates `document_status` as complete unless field is listed
31
31
  in update_fields.
32
32
 
@@ -1,7 +1,4 @@
1
- from typing import Tuple
2
-
3
-
4
1
  class DocumentStatusModelAdminMixin:
5
- def get_readonly_fields(self, request, obj=None) -> Tuple[str, ...]:
2
+ def get_readonly_fields(self, request, obj=None) -> tuple[str, ...]:
6
3
  readonly_fields = super().get_readonly_fields(request, obj=obj)
7
4
  return tuple(set(readonly_fields + ("document_status",)))
@@ -1,5 +1,3 @@
1
- from typing import Dict, Optional, Tuple
2
-
3
1
  from django.contrib import admin
4
2
  from django_audit_fields.admin import audit_fieldset_tuple
5
3
 
@@ -15,7 +13,7 @@ class EgfrDropNotificationAdminMixin:
15
13
 
16
14
  def get_fieldsets(
17
15
  self, request, obj=None
18
- ) -> Tuple[Tuple[Optional[str], Dict[str, Tuple[str, ...]]], ...]:
16
+ ) -> tuple[tuple[str | None, dict[str, tuple[str, ...]]], ...]:
19
17
  fieldsets = [
20
18
  (None, {"fields": ("subject_visit", "report_datetime")}),
21
19
  (
@@ -40,7 +38,7 @@ class EgfrDropNotificationAdminMixin:
40
38
  fieldsets.append(audit_fieldset_tuple)
41
39
  return tuple(fieldsets)
42
40
 
43
- def get_search_fields(self, request) -> Tuple[str, ...]:
41
+ def get_search_fields(self, request) -> tuple[str, ...]:
44
42
  fields = super().get_search_fields(request)
45
43
  custom_fields = (
46
44
  "subject_visit__subject_identifier",
@@ -48,7 +46,7 @@ class EgfrDropNotificationAdminMixin:
48
46
  )
49
47
  return tuple(f for f in fields if f not in custom_fields) + custom_fields
50
48
 
51
- def get_readonly_fields(self, request, obj=None) -> Tuple[str, ...]:
49
+ def get_readonly_fields(self, request, obj=None) -> tuple[str, ...]:
52
50
  fields = super().get_readonly_fields(request, obj)
53
51
  return (
54
52
  "creatinine_date",
@@ -57,11 +55,11 @@ class EgfrDropNotificationAdminMixin:
57
55
  "egfr_percent_change",
58
56
  ) + fields
59
57
 
60
- def get_list_filter(self, request) -> Tuple[str, ...]:
58
+ def get_list_filter(self, request) -> tuple[str, ...]:
61
59
  list_filter = super().get_list_filter(request)
62
60
  return ("report_status", "creatinine_date") + list_filter
63
61
 
64
- def get_list_display(self, request) -> Tuple[str, ...]:
62
+ def get_list_display(self, request) -> tuple[str, ...]:
65
63
  list_display = super().get_list_display(request)
66
64
  custom_fields = (
67
65
  "report_status",
edc_egfr/egfr.py CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from datetime import date, datetime
4
4
  from decimal import Decimal
5
- from typing import TYPE_CHECKING, Any, Optional
5
+ from typing import TYPE_CHECKING, Any
6
6
  from zoneinfo import ZoneInfo
7
7
 
8
8
  from dateutil.relativedelta import relativedelta
@@ -63,8 +63,7 @@ class Egfr:
63
63
  f"Invalid formula_name. Expected one of {list(self.calculators.keys())}. "
64
64
  f"Got {formula_name}."
65
65
  )
66
- else:
67
- self.calculator_cls = self.calculators.get(formula_name)
66
+ self.calculator_cls = self.calculators.get(formula_name)
68
67
  self.age_in_years = age_in_years
69
68
  self.dob = dob
70
69
  self.weight_in_kgs = weight_in_kgs
@@ -153,7 +152,7 @@ class Egfr:
153
152
  return self._egfr_value
154
153
 
155
154
  @property
156
- def egfr_grade(self) -> Optional[int]:
155
+ def egfr_grade(self) -> int | None:
157
156
  if self._egfr_grade is None:
158
157
  grading_data, _ = get_grade_for_value(
159
158
  self.reference_range_collection,
@@ -178,11 +177,11 @@ class Egfr:
178
177
  )
179
178
  else:
180
179
  egfr_drop_value = 0.0000
181
- self._egfr_drop_value = 0.0000 if egfr_drop_value < 0.0000 else egfr_drop_value
180
+ self._egfr_drop_value = max(egfr_drop_value, 0.0)
182
181
  return self._egfr_drop_value
183
182
 
184
183
  @property
185
- def egfr_drop_grade(self) -> Optional[int]:
184
+ def egfr_drop_grade(self) -> int | None:
186
185
  if self._egfr_drop_grade is None:
187
186
  grading_data, _ = get_grade_for_value(
188
187
  self.reference_range_collection,
@@ -198,7 +197,7 @@ class Egfr:
198
197
  self._egfr_drop_grade = grading_data.grade
199
198
  return self._egfr_drop_grade
200
199
 
201
- def get_weight_in_kgs(self) -> Optional[float]:
200
+ def get_weight_in_kgs(self) -> float | None:
202
201
  return self.weight_in_kgs
203
202
 
204
203
  def create_or_update_egfr_drop_notification(self):
@@ -3,7 +3,7 @@ from django.conf import settings
3
3
 
4
4
 
5
5
  def get_egfr_drop_notification_model():
6
- return getattr(settings, "EDC_EGFR_DROP_NOTIFICATION_MODEL")
6
+ return settings.EDC_EGFR_DROP_NOTIFICATION_MODEL
7
7
 
8
8
 
9
9
  def get_egfr_drop_notification_model_cls():
@@ -44,8 +44,8 @@ class EgfrDropNotificationModelMixin(
44
44
 
45
45
  narrative = models.TextField(
46
46
  verbose_name="Narrative",
47
- null=True,
48
47
  blank=True,
48
+ default="",
49
49
  )
50
50
 
51
51
  report_status = models.CharField(max_length=15, choices=REPORT_STATUS, default=NEW)
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from tempfile import mkdtemp
4
- from typing import TYPE_CHECKING, Type
4
+ from typing import TYPE_CHECKING
5
5
 
6
6
  from edc_pdutils.df_exporters import CsvModelExporter
7
7
  from edc_sites.site import sites
@@ -32,9 +32,9 @@ class ArchiveExporter:
32
32
  """
33
33
 
34
34
  date_format: str = "%Y%m%d%H%M%S"
35
- csv_exporter_cls: Type[CsvModelExporter] = CsvModelExporter
36
- files_emailer_cls: Type[FilesEmailer] = FilesEmailer
37
- files_archiver_cls: Type[FilesArchiver] = FilesArchiver
35
+ csv_exporter_cls: type[CsvModelExporter] = CsvModelExporter
36
+ files_emailer_cls: type[FilesEmailer] = FilesEmailer
37
+ files_archiver_cls: type[FilesArchiver] = FilesArchiver
38
38
 
39
39
  def __init__(
40
40
  self,
@@ -65,29 +65,28 @@ class ArchiveExporter:
65
65
  self.exported.append(csv_exporter.to_csv())
66
66
  if not self.exported:
67
67
  raise ArchiveExporterNothingExported(f"Nothing exported. Got models={models}.")
68
- else:
69
- if archive:
70
- archiver = self.files_archiver_cls(
68
+ if archive:
69
+ archiver = self.files_archiver_cls(
70
+ path=tmp_folder,
71
+ user=user,
72
+ exported_datetime=self.exported_datetime,
73
+ date_format=self.date_format,
74
+ )
75
+ self.archive_filename = archiver.archive_filename
76
+ self.exported_datetime = archiver.exported_datetime
77
+ if email_to_user:
78
+ summary = [str(x) for x in self.exported]
79
+ summary.sort()
80
+ try:
81
+ self.files_emailer_cls(
71
82
  path=tmp_folder,
72
83
  user=user,
73
- exported_datetime=self.exported_datetime,
74
- date_format=self.date_format,
84
+ file_ext=".zip" if archive else ".csv",
85
+ summary="\n".join(summary),
75
86
  )
76
- self.archive_filename = archiver.archive_filename
77
- self.exported_datetime = archiver.exported_datetime
78
- if email_to_user:
79
- summary = [str(x) for x in self.exported]
80
- summary.sort()
81
- try:
82
- self.files_emailer_cls(
83
- path=tmp_folder,
84
- user=user,
85
- file_ext=".zip" if archive else ".csv",
86
- summary="\n".join(summary),
87
- )
88
- except FilesEmailerError as e:
89
- raise ArchiveExporterEmailError(e)
90
- else:
91
- self.emailed_to = user.email
92
- self.emailed_datetime = get_utcnow()
93
- self.exported_datetime = self.exported_datetime or self.emailed_datetime
87
+ except FilesEmailerError as e:
88
+ raise ArchiveExporterEmailError(e)
89
+ else:
90
+ self.emailed_to = user.email
91
+ self.emailed_datetime = get_utcnow()
92
+ self.exported_datetime = self.exported_datetime or self.emailed_datetime
edc_export/exportables.py CHANGED
@@ -42,9 +42,8 @@ class Exportable(OrderedDict):
42
42
  self.historical_models.append(model_opts)
43
43
  elif model_opts.is_list_model:
44
44
  self.list_models.append(model_opts)
45
- else:
46
- if not model._meta.proxy:
47
- self.models.append(model_opts)
45
+ elif not model._meta.proxy:
46
+ self.models.append(model_opts)
48
47
  self.models.sort(key=lambda x: x.verbose_name.title())
49
48
  self.historical_models.sort(key=lambda x: x.verbose_name.title())
50
49
  self.list_models.sort(key=lambda x: x.verbose_name.title())
@@ -31,7 +31,7 @@ class Command(BaseCommand):
31
31
  error_filepath = os.path.join(
32
32
  os.path.expanduser(self.export_plan.target_path) or "", self.error_filename
33
33
  )
34
- with open(self.ack_filename, "r") as f, open(error_filepath, "w") as error_file:
34
+ with open(self.ack_filename) as f, open(error_filepath, "w") as error_file:
35
35
  rows = csv.reader(f, delimiter="|")
36
36
  writer = csv.writer(error_file, delimiter="|")
37
37
  for row in rows:
@@ -42,8 +42,8 @@ class Command(BaseCommand):
42
42
  try:
43
43
  export_uuid = row[header.index("export_UUID")]
44
44
  except ValueError as e:
45
- writer.writerow("error reading file. Got {0}".format(e))
46
- print("Failed to process file {0}".format(self.ack_filename))
45
+ writer.writerow(f"error reading file. Got {e}")
46
+ print(f"Failed to process file {self.ack_filename}")
47
47
  raise ValueError(e)
48
48
  if ExportTransaction.objects.filter(export_uuid=export_uuid):
49
49
  for export_transaction in ExportTransaction.objects.filter(
@@ -79,7 +79,7 @@ class Command(BaseCommand):
79
79
  except ValueError:
80
80
  CommandError(
81
81
  "Invalid file name. Expected format xxx_app_label_objectname_timestamp.xxx. "
82
- "Got {0}".format(self.ack_filename)
82
+ f"Got {self.ack_filename}"
83
83
  )
84
84
  return error_filename
85
85
 
@@ -91,9 +91,9 @@ class Command(BaseCommand):
91
91
  )
92
92
  except ExportPlan.DoesNotExist as e:
93
93
  CommandError(
94
- "ExportPlan not found for {0}, {1}. "
94
+ f"ExportPlan not found for {self.app_label}, {self.object_name}. "
95
95
  "Check filename format or create an ExportPlan. "
96
- "Got {2}".format(self.app_label, self.object_name, e)
96
+ f"Got {e}"
97
97
  )
98
98
  return export_plan
99
99
 
@@ -29,7 +29,7 @@ class FileHistoryUpdater:
29
29
  def update(self):
30
30
  exported_pks = []
31
31
  export_uuids = []
32
- with open(self.path, "r") as f:
32
+ with open(self.path) as f:
33
33
  csv_reader = csv.DictReader(f, delimiter=self.delimiter)
34
34
  for row in csv_reader:
35
35
  exported_pks.append(row["id"])
@@ -33,7 +33,7 @@ class AdditionalValues:
33
33
  self.export_change_type = None
34
34
 
35
35
 
36
- class ModelExporter(object):
36
+ class ModelExporter:
37
37
  delimiter = "|"
38
38
  file_history_updater_cls = FileHistoryUpdater
39
39
  object_history_helper_cls = ObjectHistoryHelper
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import string
4
- from typing import TYPE_CHECKING, Any, Type
4
+ from typing import TYPE_CHECKING, Any
5
5
 
6
6
  from django.core.exceptions import ValidationError
7
7
  from django.db.models import Manager
@@ -16,7 +16,7 @@ if TYPE_CHECKING:
16
16
  pass
17
17
 
18
18
 
19
- __all__ = ["ValueGetter", "ValueGetterUnknownField", "ValueGetterInvalidLookup"]
19
+ __all__ = ["ValueGetter", "ValueGetterInvalidLookup", "ValueGetterUnknownField"]
20
20
 
21
21
 
22
22
  class ValueGetterUnknownField(ValidationError):
@@ -82,7 +82,7 @@ class ValueGetter:
82
82
  self._value = self.strip_value(self._value)
83
83
  return self._value
84
84
 
85
- def _get_field_value(self, model_obj: Type[MyModel] = None, field_name: str = None) -> Any:
85
+ def _get_field_value(self, model_obj: type[MyModel] = None, field_name: str = None) -> Any:
86
86
  """Returns a field value.
87
87
 
88
88
  1. Tries to access a field as a model instance attribute;
@@ -105,7 +105,7 @@ class ValueGetter:
105
105
  value = self.get_lookup_value(model_obj=model_obj, field_name=field_name)
106
106
  else:
107
107
  raise ValueGetterUnknownField(
108
- f"Unknown field name. Perhaps add a lookup. " f"Got {field_name}.",
108
+ f"Unknown field name. Perhaps add a lookup. Got {field_name}.",
109
109
  code=field_name,
110
110
  )
111
111
  if isinstance(value, Manager):
@@ -117,7 +117,7 @@ class ValueGetter:
117
117
  )
118
118
  return value
119
119
 
120
- def get_lookup_value(self, model_obj: Type[MyModel] = None, field_name: str = None) -> Any:
120
+ def get_lookup_value(self, model_obj: type[MyModel] = None, field_name: str = None) -> Any:
121
121
  """Returns the field value by following the lookup string
122
122
  to a related instance.
123
123
  """
@@ -137,7 +137,7 @@ class ValueGetter:
137
137
  """Returns the list of m2m field names for this model."""
138
138
  return [m2m.name for m2m in self.model_cls._meta.many_to_many]
139
139
 
140
- def get_m2m_value(self, model_obj: Type[MyModel] = None, field_name: str = None) -> str:
140
+ def get_m2m_value(self, model_obj: type[MyModel] = None, field_name: str = None) -> str:
141
141
  """Returns an m2m field value as a delimited string."""
142
142
  return self.m2m_delimiter.join(
143
143
  [value.name for value in getattr(model_obj, field_name).all()]
@@ -9,11 +9,11 @@ class NotificationMixin(models.Model):
9
9
 
10
10
  subject = models.CharField(max_length=200)
11
11
 
12
- recipient_list = models.TextField(null=True)
12
+ recipient_list = models.TextField(null=True, default="")
13
13
 
14
- cc_list = models.TextField(null=True)
14
+ cc_list = models.TextField(null=True, default="")
15
15
 
16
- body = models.TextField(null=True)
16
+ body = models.TextField(null=True, default="")
17
17
 
18
18
  status = models.CharField(
19
19
  max_length=15,
@@ -27,4 +27,4 @@ class NotificationMixin(models.Model):
27
27
 
28
28
  class Meta:
29
29
  abstract = True
30
- indexes = [Index(fields=["notification_datetime"])]
30
+ indexes = (Index(fields=["notification_datetime"]),)
@@ -13,14 +13,14 @@ from ..model_options import ModelOptions
13
13
  class DataRequest(SiteModelMixin, BaseUuidModel):
14
14
  name = models.CharField(max_length=25)
15
15
 
16
- description = models.TextField(null=True)
16
+ description = models.TextField(default="")
17
17
 
18
18
  decrypt = models.BooleanField(default=False)
19
19
 
20
20
  export_format = models.CharField(max_length=25, choices=EXPORT_FORMATS, default=CSV)
21
21
 
22
22
  models = models.TextField(
23
- help_text='List one table per line, no commas. Use "label lower" format.'
23
+ default="", help_text='List one table per line, no commas. Use "label lower" format.'
24
24
  )
25
25
 
26
26
  history = HistoricalRecords()
@@ -41,4 +41,4 @@ class DataRequest(SiteModelMixin, BaseUuidModel):
41
41
  return [ModelOptions(x) for x in models_as_list]
42
42
 
43
43
  class Meta:
44
- indexes = [Index(fields=["name"])]
44
+ indexes = (Index(fields=["name"]),)
@@ -18,11 +18,11 @@ class DataRequestHistory(SiteModelMixin, BaseUuidModel):
18
18
 
19
19
  emailed_datetime = models.DateTimeField(null=True)
20
20
 
21
- summary = models.TextField(null=True)
21
+ summary = models.TextField(default="")
22
22
 
23
23
  exported_datetime = models.DateTimeField(default=get_utcnow)
24
24
 
25
25
  class Meta:
26
26
  verbose_name = "Data Request History"
27
27
  verbose_name_plural = "Data Request History"
28
- indexes = [Index(fields=["exported_datetime"])]
28
+ indexes = (Index(fields=["exported_datetime"]),)
@@ -33,4 +33,4 @@ class ExportReceipt(BaseUuidModel):
33
33
  return (self.export_uuid,)
34
34
 
35
35
  class Meta(BaseUuidModel.Meta):
36
- indexes = [Index(fields=["timestamp"])]
36
+ indexes = (Index(fields=["timestamp"]),)
@@ -23,11 +23,11 @@ class FileHistory(BaseUuidModel):
23
23
  model = models.CharField(max_length=50)
24
24
 
25
25
  export_uuid_list = models.TextField(
26
- null=True, help_text="list of export_uuid's of model app_label.model_name"
26
+ default="", help_text="list of export_uuid's of model app_label.model_name"
27
27
  )
28
28
 
29
29
  pk_list = models.TextField(
30
- null=True, help_text="list of pk's of model app_label.model_name"
30
+ default="", help_text="list of pk's of model app_label.model_name"
31
31
  )
32
32
 
33
33
  exit_message = models.CharField(
@@ -41,14 +41,14 @@ class FileHistory(BaseUuidModel):
41
41
  filename = models.CharField(max_length=250, help_text="original filename on export")
42
42
 
43
43
  file_contents = models.TextField(
44
- null=True, help_text="save contents of file as a list of rows"
44
+ default="", help_text="save contents of file as a list of rows"
45
45
  )
46
46
 
47
47
  exported = models.BooleanField(default=False, help_text="exported to a file")
48
48
 
49
49
  exported_datetime = models.DateTimeField(null=True)
50
50
 
51
- notification_plan_name = models.CharField(max_length=50, null=True)
51
+ notification_plan_name = models.CharField(max_length=50, default="")
52
52
 
53
53
  sent = models.BooleanField(default=False, help_text="export file sent to recipient")
54
54
 
@@ -78,4 +78,4 @@ class FileHistory(BaseUuidModel):
78
78
  return (self.history_uuid,)
79
79
 
80
80
  class Meta(BaseUuidModel.Meta):
81
- indexes = [Index(fields=["sent_datetime"])]
81
+ indexes = (Index(fields=["sent_datetime"]),)