clinicedc 2.0.6__py3-none-any.whl → 2.0.8__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 (495) hide show
  1. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/METADATA +2 -2
  2. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/RECORD +489 -441
  3. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/WHEEL +1 -1
  4. edc_action_item/action.py +1 -1
  5. edc_action_item/action_item_notification.py +2 -2
  6. edc_action_item/auths.py +37 -32
  7. edc_action_item/create_action_item.py +1 -1
  8. edc_action_item/decorators.py +1 -1
  9. edc_action_item/migrations/0001_initial.py +21 -22
  10. edc_action_item/migrations/0006_auto_20180707_1659.py +4 -4
  11. edc_action_item/migrations/0008_auto_20180809_0303.py +4 -4
  12. edc_action_item/migrations/0015_auto_20190114_0250.py +4 -4
  13. edc_action_item/migrations/0017_auto_20190305_0123.py +11 -30
  14. edc_action_item/migrations/0030_edcpermissions.py +3 -2
  15. edc_action_item/migrations/0039_alter_actionitem_auto_created_comment_and_more.py +398 -0
  16. edc_action_item/migrations/0040_alter_actionitem_report_datetime_and_more.py +34 -0
  17. edc_action_item/models/action_item.py +9 -4
  18. edc_action_item/models/action_model_mixin.py +5 -6
  19. edc_action_item/models/reference.py +2 -2
  20. edc_action_item/models/signals.py +22 -23
  21. edc_action_item/post_migrate_signals.py +1 -1
  22. edc_action_item/send_email.py +0 -85
  23. edc_action_item/site_action_items.py +5 -9
  24. edc_action_item/utils.py +3 -3
  25. edc_adherence/migrations/0005_alter_nonadherencereasons_extra_value_and_more.py +36 -0
  26. edc_adherence/model_mixins.py +1 -1
  27. edc_adverse_event/auths.py +55 -51
  28. edc_adverse_event/migrations/0001_initial.py +5 -4
  29. edc_adverse_event/migrations/0002_auto_20190802_0059.py +3 -2
  30. edc_adverse_event/migrations/0008_auto_20220825_0451.py +3 -2
  31. edc_adverse_event/migrations/0009_auto_20220907_0157.py +3 -2
  32. edc_adverse_event/migrations/0016_alter_aeactionclassification_device_created_and_more.py +285 -0
  33. edc_adverse_event/model_mixins/ae_followup/ae_followup_fields_model_mixin.py +2 -2
  34. edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +6 -5
  35. edc_adverse_event/model_mixins/ae_special_interest/aesi_fields_model_mixin.py +2 -2
  36. edc_adverse_event/model_mixins/ae_susar/ae_susar_fields_model_mixin.py +2 -2
  37. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +15 -11
  38. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +2 -4
  39. edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +5 -4
  40. edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +6 -3
  41. edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +2 -2
  42. edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +4 -3
  43. edc_adverse_event/modeladmin_mixins/death_report_admin_mixin.py +3 -3
  44. edc_adverse_event/models/signals.py +7 -7
  45. edc_adverse_event/templatetags/edc_adverse_event_extras.py +5 -4
  46. edc_adverse_event/view_mixins/ae/ae_listboard_view_mixin.py +3 -5
  47. edc_adverse_event/view_mixins/ae/death_report_listboard_view_mixin.py +6 -8
  48. edc_adverse_event/view_mixins/tmg/tmg_ae_listboard_view_mixin.py +2 -2
  49. edc_adverse_event/views/tmg/summary_listboard_view.py +3 -2
  50. edc_appointment/admin/appointment_admin.py +2 -2
  51. edc_appointment/admin/list_filters.py +2 -2
  52. edc_appointment/auths.py +14 -10
  53. edc_appointment/creators/appointment_creator.py +1 -1
  54. edc_appointment/creators/appointments_creator.py +1 -1
  55. edc_appointment/form_validators/appointment_form_validator.py +108 -82
  56. edc_appointment/migrations/0003_auto_20161127_2226.py +5 -6
  57. edc_appointment/migrations/0006_auto_20170106_2118.py +5 -5
  58. edc_appointment/migrations/0018_auto_20190305_0123.py +5 -12
  59. edc_appointment/migrations/0050_alter_appointment_appt_type_and_more.py +220 -0
  60. edc_appointment/model_mixins/appointment_fields_model_mixin.py +1 -2
  61. edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -3
  62. edc_appointment/model_mixins/appointment_model_mixin.py +31 -28
  63. edc_appointment/model_mixins/window_period_model_mixin.py +6 -7
  64. edc_appointment/models/appointment.py +1 -1
  65. edc_appointment/models/signals.py +44 -35
  66. edc_appointment/utils.py +19 -24
  67. edc_appointment/view_utils/appointment_button.py +2 -2
  68. edc_auth/admin/user_admin.py +1 -1
  69. edc_auth/auth_objects/__init__.py +2 -20
  70. edc_auth/auth_objects/default_groups.py +13 -11
  71. edc_auth/auth_objects/default_roles.py +26 -24
  72. edc_auth/auth_updater/auth_updater.py +13 -2
  73. edc_auth/auth_updater/group_updater.py +12 -10
  74. edc_auth/auth_updater/role_updater.py +2 -2
  75. edc_auth/constants.py +10 -0
  76. edc_auth/import_users.py +3 -3
  77. edc_auth/migrations/0001_squashed_0033_alter_userprofile_is_multisite_viewer.py +5 -5
  78. edc_auth/migrations/0012_auto_20191026_0034.py +3 -2
  79. edc_auth/migrations/0013_auto_20191026_0055.py +3 -2
  80. edc_auth/migrations/0025_permissions.py +3 -2
  81. edc_auth/migrations/0035_alter_edcpermissions_device_created_and_more.py +85 -0
  82. edc_auth/models/user_profile.py +14 -11
  83. edc_auth/post_migrate_signals.py +1 -1
  84. edc_auth/site_auths.py +80 -67
  85. edc_consent/actions.py +4 -5
  86. edc_consent/auths.py +18 -12
  87. edc_consent/migrations/0001_initial.py +3 -2
  88. edc_consent/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  89. edc_consent/model_mixins/consent_extension_model_mixin.py +4 -5
  90. edc_consent/model_mixins/requires_consent_fields_model_mixin.py +2 -2
  91. edc_consent/utils.py +1 -1
  92. edc_constants/constants.py +1 -0
  93. edc_crf/auths.py +5 -0
  94. edc_crf/migrations/0001_initial.py +3 -2
  95. edc_crf/migrations/0009_alter_crfstatus_device_created_and_more.py +54 -0
  96. edc_dashboard/auths.py +10 -6
  97. edc_dashboard/migrations/0001_initial.py +3 -2
  98. edc_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  99. edc_dashboard/templatetags/edc_dashboard_extras.py +3 -2
  100. edc_dashboard/url_config.py +92 -83
  101. edc_dashboard/url_names.py +4 -4
  102. edc_dashboard/view_mixins/url_request_context_mixin.py +6 -5
  103. edc_data_manager/action_items.py +4 -6
  104. edc_data_manager/admin/actions.py +5 -5
  105. edc_data_manager/admin/data_query_admin.py +12 -11
  106. edc_data_manager/auths.py +37 -34
  107. edc_data_manager/handlers/handlers.py +6 -7
  108. edc_data_manager/migrations/0001_initial.py +19 -19
  109. edc_data_manager/migrations/0025_edcpermissions.py +3 -2
  110. edc_data_manager/migrations/0040_alter_datadictionary_device_created_and_more.py +327 -0
  111. edc_data_manager/migrations/0041_alter_dataquery_dm_user_and_more.py +164 -0
  112. edc_data_manager/models/data_query.py +5 -5
  113. edc_data_manager/models/model_mixins.py +8 -8
  114. edc_data_manager/rule/query_rule_wrapper.py +7 -7
  115. edc_data_manager/rule/rule_runner.py +4 -3
  116. edc_document_status/model_mixins.py +1 -1
  117. edc_egfr/egfr.py +11 -7
  118. edc_egfr/model_mixins/egfr_model_mixin.py +3 -7
  119. edc_export/admin/data_request_admin.py +2 -2
  120. edc_export/archive_exporter.py +7 -5
  121. edc_export/auths.py +32 -28
  122. edc_export/files_archiver.py +3 -2
  123. edc_export/migrations/0001_initial.py +26 -26
  124. edc_export/migrations/0004_auto_20190305_0123.py +25 -72
  125. edc_export/migrations/0013_edcpermissions.py +3 -2
  126. edc_export/migrations/0022_alter_datarequest_description_and_more.py +611 -0
  127. edc_export/migrations/0023_alter_datarequesthistory_archive_filename_and_more.py +29 -0
  128. edc_export/model_exporter/file_history_updater.py +10 -10
  129. edc_export/model_exporter/model_exporter.py +17 -15
  130. edc_export/model_exporter/object_history_helpers.py +2 -2
  131. edc_export/models/data_request_history.py +4 -4
  132. edc_export/utils.py +10 -15
  133. edc_facility/auths.py +8 -3
  134. edc_facility/facility.py +16 -22
  135. edc_facility/import_holidays.py +13 -13
  136. edc_facility/migrations/0005_healthfacility_healthfacilitytypes_and_more.py +8 -7
  137. edc_facility/migrations/0016_alter_healthfacility_device_created_and_more.py +139 -0
  138. edc_facility/migrations/0017_alter_healthfacility_gps_and_more.py +54 -0
  139. edc_facility/model_mixins.py +5 -5
  140. edc_form_label/custom_label_condition.py +11 -8
  141. edc_form_label/form_label.py +1 -1
  142. edc_form_runners/auths.py +11 -6
  143. edc_form_runners/form_runner.py +3 -5
  144. edc_form_runners/migrations/0001_initial.py +3 -2
  145. edc_form_runners/migrations/0005_alter_issue_device_created_and_more.py +49 -0
  146. edc_form_validators/applicable_field_validator.py +7 -6
  147. edc_form_validators/base_form_validator.py +8 -9
  148. edc_form_validators/other_specify_field_validator.py +2 -8
  149. edc_form_validators/required_field_validator.py +19 -16
  150. edc_identifier/migrations/0001_squashed_0018_auto_20180128_1054.py +3 -3
  151. edc_identifier/migrations/0002_auto_20190305_0123.py +3 -6
  152. edc_identifier/migrations/0006_auto_20161127_2226.py +15 -15
  153. edc_identifier/migrations/0007_auto_20161204_2227.py +3 -3
  154. edc_identifier/migrations/0009_auto_20161221_2323.py +3 -5
  155. edc_identifier/migrations/0010_auto_20170112_0602.py +17 -17
  156. edc_identifier/migrations/0011_alter_identifiermodel_device_created_and_more.py +79 -0
  157. edc_identifier/model_mixins.py +1 -1
  158. edc_identifier/models.py +9 -9
  159. edc_identifier/research_identifier.py +11 -10
  160. edc_identifier/simple_identifier.py +9 -5
  161. edc_identifier/subject_identifier.py +3 -2
  162. edc_lab/auths.py +26 -23
  163. edc_lab/lab/aliquot_creator.py +5 -8
  164. edc_lab/lab/primary_aliquot.py +14 -5
  165. edc_lab/migrations/0001_initial.py +29 -29
  166. edc_lab/migrations/0008_auto_20170921_0719.py +3 -3
  167. edc_lab/migrations/0010_auto_20171127_1541.py +15 -15
  168. edc_lab/migrations/0012_auto_20180114_1438.py +3 -3
  169. edc_lab/migrations/0019_auto_20190305_0123.py +43 -127
  170. edc_lab/migrations/0036_alter_aliquot_comment_alter_aliquot_device_created_and_more.py +1139 -0
  171. edc_lab/migrations/0037_alter_historicalorder_order_datetime_and_more.py +31 -0
  172. edc_lab/model_mixins/aliquot/aliquot_identifier_model_mixin.py +2 -2
  173. edc_lab/model_mixins/aliquot/aliquot_model_mixin.py +2 -2
  174. edc_lab/model_mixins/panel_model_mixin.py +18 -7
  175. edc_lab/model_mixins/requisition/crf_with_requisition_model_mixin.py +2 -4
  176. edc_lab/model_mixins/requisition/requisition_model_mixin.py +13 -16
  177. edc_lab/model_mixins/requisition/requisition_verify_model_mixin.py +1 -1
  178. edc_lab/model_mixins/result/result_item_model_mixin.py +4 -4
  179. edc_lab/model_mixins/shipping/manifest_model_mixin.py +4 -5
  180. edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -6
  181. edc_lab/models/aliquot.py +2 -2
  182. edc_lab/models/box.py +1 -1
  183. edc_lab/models/box_item.py +6 -7
  184. edc_lab/models/manifest/manifest.py +3 -3
  185. edc_lab/models/manifest/manifest_item.py +7 -7
  186. edc_lab/models/manifest/shipper.py +3 -4
  187. edc_lab/models/order.py +6 -4
  188. edc_lab/models/panel.py +4 -4
  189. edc_lab/models/result.py +2 -2
  190. edc_lab/models/result_item.py +2 -2
  191. edc_lab_dashboard/auths.py +16 -11
  192. edc_lab_dashboard/migrations/0001_initial.py +3 -2
  193. edc_lab_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  194. edc_lab_dashboard/views/action_views/receive_view.py +2 -2
  195. edc_lab_dashboard/views/action_views/verify_box_item_view.py +2 -2
  196. edc_lab_results/calculate_missing.py +8 -8
  197. edc_lab_results/form_validator_mixins/blood_results_form_validator_mixin.py +2 -2
  198. edc_lab_results/get_summary.py +26 -25
  199. edc_lab_results/model_mixins/blood_result_model_mixin.py +9 -7
  200. edc_lab_results/model_mixins/fbg_model_mixin.py +3 -3
  201. edc_lab_results/model_mixins/glucose_model_mixin.py +3 -3
  202. edc_lab_results/model_mixins/hba1c_model_mixin.py +3 -3
  203. edc_label/auths.py +6 -1
  204. edc_label/label_template.py +8 -8
  205. edc_label/migrations/0001_initial.py +3 -2
  206. edc_label/migrations/0007_alter_zpllabeltemplates_device_created_and_more.py +49 -0
  207. edc_list_data/list_model_maker.py +2 -2
  208. edc_list_data/load_list_data.py +11 -14
  209. edc_list_data/load_model_data.py +3 -3
  210. edc_list_data/model_mixins.py +12 -4
  211. edc_list_data/post_migrate_signals.py +1 -1
  212. edc_list_data/preload_data.py +4 -4
  213. edc_list_data/row.py +1 -1
  214. edc_list_data/site_list_data.py +6 -5
  215. edc_listboard/migrations/0001_initial.py +3 -2
  216. edc_listboard/migrations/0007_alter_listboard_device_created_and_more.py +49 -0
  217. edc_locator/auths.py +18 -13
  218. edc_locator/migrations/0001_initial.py +7 -7
  219. edc_locator/migrations/0018_auto_20190305_0123.py +5 -12
  220. edc_locator/migrations/0040_alter_historicalsubjectlocator_action_identifier_and_more.py +187 -0
  221. edc_locator/migrations/0041_alter_historicalsubjectlocator_report_datetime_and_more.py +27 -0
  222. edc_locator/model_mixins/locator_model_mixin.py +2 -2
  223. edc_locator/model_mixins/subject_contact_fields_mixin.py +1 -1
  224. edc_locator/modeladmin_mixins.py +5 -4
  225. edc_ltfu/model_mixins.py +7 -5
  226. edc_metadata/auths.py +11 -7
  227. edc_metadata/metadata/metadata.py +1 -1
  228. edc_metadata/metadata_rules/crf/crf_rule.py +1 -1
  229. edc_metadata/metadata_rules/decorators.py +1 -1
  230. edc_metadata/metadata_rules/metadata_rule_evaluator.py +5 -3
  231. edc_metadata/metadata_rules/rule.py +2 -3
  232. edc_metadata/metadata_rules/rule_evaluator.py +1 -1
  233. edc_metadata/migrations/0002_auto_20161127_2226.py +5 -5
  234. edc_metadata/migrations/0005_auto_20170112_0602.py +5 -5
  235. edc_metadata/migrations/0011_auto_20190305_0123.py +5 -12
  236. edc_metadata/migrations/0031_alter_crfmetadata_device_created_and_more.py +120 -0
  237. edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +7 -4
  238. edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +5 -2
  239. edc_metadata/models/crf_metadata.py +5 -5
  240. edc_metadata/models/crf_metadata_model_mixin.py +4 -5
  241. edc_metadata/models/requisition_metadata.py +6 -6
  242. edc_metadata/models/signals.py +10 -11
  243. edc_metadata/views/refresh_metadata_actions_view.py +3 -3
  244. edc_model/models/address_mixin.py +6 -6
  245. edc_model/models/fields/initials_field.py +2 -1
  246. edc_model/models/historical_records.py +2 -9
  247. edc_model/models/url_model_mixin.py +2 -2
  248. edc_model/validators/date.py +7 -8
  249. edc_model_admin/list_filters/future_date_list_filter.py +3 -3
  250. edc_model_admin/list_filters/past_date_list_filter.py +3 -3
  251. edc_model_admin/mixins/model_admin_protect_pii_mixin.py +4 -5
  252. edc_model_fields/fields/other_charfield.py +2 -2
  253. edc_navbar/auths.py +18 -13
  254. edc_navbar/migrations/0004_auto_20220825_0451.py +3 -2
  255. edc_navbar/migrations/0009_alter_edcpermissions_device_created_and_more.py +49 -0
  256. edc_notification/auths.py +9 -4
  257. edc_notification/migrations/0001_initial.py +3 -3
  258. edc_notification/migrations/0004_auto_20190305_0123.py +3 -6
  259. edc_notification/migrations/0011_alter_notification_device_created_and_more.py +59 -0
  260. edc_notification/models/notification.py +1 -1
  261. edc_notification/notification/graded_event_notification.py +2 -2
  262. edc_notification/notification/model_notification.py +3 -30
  263. edc_notification/notification/new_model_notification.py +1 -1
  264. edc_notification/notification/notification.py +12 -12
  265. edc_notification/notification/updated_model_notification.py +2 -2
  266. edc_offstudy/auths.py +12 -7
  267. edc_offstudy/migrations/0001_initial.py +4 -4
  268. edc_offstudy/migrations/0002_auto_20180921_0434.py +4 -4
  269. edc_offstudy/migrations/0005_auto_20190305_0123.py +5 -12
  270. edc_offstudy/migrations/0023_alter_historicalsubjectoffstudy_action_identifier_and_more.py +188 -0
  271. edc_offstudy/migrations/0024_alter_historicalsubjectoffstudy_offstudy_datetime_and_more.py +43 -0
  272. edc_offstudy/model_mixins/offstudy_model_mixin.py +3 -2
  273. edc_pdutils/df_exporters/csv_exporter.py +33 -37
  274. edc_pdutils/df_exporters/csv_model_exporter.py +7 -3
  275. edc_pdutils/migrations/0001_initial.py +8 -8
  276. edc_pharmacy/admin/prescription/rx_refill_admin.py +4 -3
  277. edc_pharmacy/admin/reports/stock_availability_admin.py +5 -6
  278. edc_pharmacy/auths.py +19 -15
  279. edc_pharmacy/migrations/0001_initial.py +64 -63
  280. edc_pharmacy/migrations/0015_auto_20220913_2139.py +26 -26
  281. edc_pharmacy/migrations/0024_allocation_assignment_containerunits_dispense_and_more.py +81 -86
  282. edc_pharmacy/migrations/0037_remove_historicalstock_confirmed_at_site_by_and_more.py +5 -5
  283. edc_pharmacy/migrations/0039_remove_dispense_registered_subject_and_more.py +7 -8
  284. edc_pharmacy/migrations/0049_remove_stocktransferconfirmation_stock_and_more.py +12 -12
  285. edc_pharmacy/migrations/0050_remove_stocktransferconfirmation2_location_and_more.py +5 -5
  286. edc_pharmacy/migrations/0051_alter_historicalstocktransferconfirmationitem_options_and_more.py +3 -4
  287. edc_pharmacy/migrations/0053_alter_location_managers_alter_historicalstock_lot_and_more.py +3 -3
  288. edc_pharmacy/migrations/0057_scanduplicates.py +3 -3
  289. edc_pharmacy/migrations/0060_alter_container_max_per_subject_and_more.py +13 -15
  290. edc_pharmacy/migrations/0068_stockout.py +2 -3
  291. edc_pharmacy/migrations/0076_historicalstockadjustment_stockadjustment.py +5 -5
  292. edc_pharmacy/migrations/0077_historicalstockadjustment_adjustment_datetime_and_more.py +3 -4
  293. edc_pharmacy/migrations/0081_historicalconfirmation_confirmation.py +8 -8
  294. edc_pharmacy/migrations/0084_confirmationatsiteitem_and_more.py +0 -2
  295. edc_pharmacy/migrations/0089_alter_allocation_allocated_by_and_more.py +3284 -0
  296. edc_pharmacy/migrations/0090_alter_allocation_allocation_datetime_and_more.py +227 -0
  297. edc_pharmacy/model_mixins/study_medication_refill_model_mixin.py +2 -2
  298. edc_pharmacy/models/medication/formulation.py +5 -7
  299. edc_pharmacy/models/medication/medication.py +3 -3
  300. edc_pharmacy/models/model_mixins.py +10 -11
  301. edc_pharmacy/models/prescription/rx.py +13 -12
  302. edc_pharmacy/models/prescription/rx_refill.py +0 -1
  303. edc_pharmacy/models/stock/allocation.py +3 -3
  304. edc_pharmacy/models/stock/confirmation.py +3 -3
  305. edc_pharmacy/models/stock/confirmation_at_site.py +3 -2
  306. edc_pharmacy/models/stock/confirmation_at_site_item.py +3 -4
  307. edc_pharmacy/models/stock/dispense.py +5 -6
  308. edc_pharmacy/models/stock/dispense_item.py +2 -2
  309. edc_pharmacy/models/stock/location.py +3 -4
  310. edc_pharmacy/models/stock/lot.py +6 -7
  311. edc_pharmacy/models/stock/order.py +1 -1
  312. edc_pharmacy/models/stock/receive.py +3 -3
  313. edc_pharmacy/models/stock/receive_item.py +4 -4
  314. edc_pharmacy/models/stock/repack_request.py +2 -2
  315. edc_pharmacy/models/stock/stock.py +12 -18
  316. edc_pharmacy/models/stock/stock_adjustment.py +4 -4
  317. edc_pharmacy/models/stock/stock_request.py +2 -2
  318. edc_pharmacy/models/stock/stock_request_item.py +2 -2
  319. edc_pharmacy/models/stock/stock_transfer.py +3 -3
  320. edc_pharmacy/models/stock/stock_transfer_item.py +2 -2
  321. edc_pharmacy/models/stock/storage_bin.py +3 -4
  322. edc_pharmacy/models/stock/storage_bin_item.py +2 -2
  323. edc_pharmacy/models/stock/supplier.py +3 -4
  324. edc_pharmacy/models/storage/box.py +2 -2
  325. edc_pharmacy/models/storage/items/container_model_mixin.py +3 -4
  326. edc_pharmacy/models/storage/items/pill_bottle_model_mixin.py +2 -2
  327. edc_pharmacy/models/storage/items/subject_pill_bottle.py +1 -1
  328. edc_pharmacy/models/storage/room.py +2 -2
  329. edc_pharmacy/models/storage/shelf.py +2 -2
  330. edc_pharmacy/models/storage/utils.py +1 -1
  331. edc_pharmacy/prescribe/create_prescription.py +3 -3
  332. edc_pharmacy/utils/allocate_stock.py +2 -3
  333. edc_pharmacy/utils/confirm_stock.py +3 -4
  334. edc_pharmacy/utils/confirm_stock_at_site.py +4 -5
  335. edc_pharmacy/utils/dispense.py +3 -4
  336. edc_pharmacy/utils/process_repack_request.py +4 -5
  337. edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
  338. edc_pharmacy/utils/transfer_stock.py +2 -3
  339. edc_pharmacy/views/add_to_storage_bin_view.py +2 -2
  340. edc_pharmacy/views/allocate_to_subject_view.py +2 -2
  341. edc_pharmacy/views/confirmation_at_site_view.py +6 -9
  342. edc_pharmacy/views/dispense_view.py +2 -2
  343. edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
  344. edc_pharmacy/views/print_labels_view.py +2 -2
  345. edc_prn/admin_site.py +5 -0
  346. edc_prn/prn.py +10 -11
  347. edc_prn/urls.py +11 -0
  348. edc_protocol/research_protocol_config.py +2 -3
  349. edc_protocol_incident/action_items.py +4 -4
  350. edc_protocol_incident/auths.py +27 -20
  351. edc_protocol_incident/migrations/0001_initial.py +7 -7
  352. edc_protocol_incident/migrations/0001_squashed_0015_auto_20220927_0401.py +13 -13
  353. edc_protocol_incident/migrations/0005_protocolincident_historicalprotocolincident_and_more.py +7 -7
  354. edc_protocol_incident/migrations/0024_alter_actionsrequired_extra_value_and_more.py +625 -0
  355. edc_protocol_incident/migrations/0025_alter_historicalprotocoldeviationviolation_report_datetime_and_more.py +42 -0
  356. edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +18 -11
  357. edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +26 -11
  358. edc_pylabels/actions.py +3 -5
  359. edc_pylabels/auths.py +6 -1
  360. edc_pylabels/migrations/0002_alter_label_options_label_created_and_more.py +3 -7
  361. edc_pylabels/migrations/0005_labelconfiguration_delete_label_and_more.py +3 -3
  362. edc_pylabels/migrations/0013_alter_labelconfiguration_device_created_and_more.py +49 -0
  363. edc_qareports/auths.py +11 -7
  364. edc_qareports/migrations/0001_initial.py +4 -5
  365. edc_qareports/migrations/0005_edcpermissions.py +3 -3
  366. edc_qareports/migrations/0006_qareportlog.py +2 -3
  367. edc_qareports/migrations/0019_alter_edcpermissions_device_created_and_more.py +102 -0
  368. edc_qareports/migrations/0020_alter_note_report_datetime_and_more.py +24 -0
  369. edc_qareports/model_mixins/note_model_mixin.py +7 -4
  370. edc_qareports/model_mixins/on_study_missing_values_model_mixin.py +4 -4
  371. edc_qareports/model_mixins/qa_report_model_mixin.py +2 -3
  372. edc_qareports/models/note.py +4 -4
  373. edc_qareports/models/qa_reports_log.py +2 -3
  374. edc_randomization/admin.py +30 -24
  375. edc_randomization/auths.py +12 -7
  376. edc_randomization/decorators.py +1 -1
  377. edc_randomization/migrations/0001_initial.py +3 -2
  378. edc_randomization/migrations/0002_historicalrandomizationlist.py +3 -2
  379. edc_randomization/migrations/0009_edcpermissions.py +3 -2
  380. edc_randomization/migrations/0014_alter_edcpermissions_device_created_and_more.py +141 -0
  381. edc_randomization/model_mixins.py +9 -9
  382. edc_randomization/randomizer.py +22 -20
  383. edc_randomization/utils.py +19 -18
  384. edc_refusal/auths.py +7 -2
  385. edc_refusal/migrations/0001_initial.py +4 -4
  386. edc_refusal/migrations/0002_historicalsubjectrefusal.py +4 -4
  387. edc_refusal/migrations/0012_alter_historicalsubjectrefusal_comment_and_more.py +122 -0
  388. edc_refusal/migrations/0013_alter_historicalsubjectrefusal_report_datetime_and_more.py +28 -0
  389. edc_refusal/model_mixins.py +4 -4
  390. edc_registration/auths.py +28 -23
  391. edc_registration/migrations/0002_auto_20161127_2226.py +3 -4
  392. edc_registration/migrations/0005_auto_20170111_1809.py +4 -2
  393. edc_registration/migrations/0016_historicalregisteredsubject.py +3 -2
  394. edc_registration/migrations/0017_auto_20190305_0123.py +5 -12
  395. edc_registration/migrations/0033_alter_historicalregisteredsubject_additional_key_and_more.py +302 -0
  396. edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +15 -7
  397. edc_registration/models/registered_subject.py +28 -27
  398. edc_reportable/age_evaluator.py +4 -2
  399. edc_reportable/formula.py +5 -5
  400. edc_reportable/migrations/0001_initial.py +7 -7
  401. edc_reportable/migrations/0003_referencerangecollection_grade1_and_more.py +3 -3
  402. edc_reportable/migrations/0004_alter_referencerangecollection_grade3_and_more.py +5 -5
  403. edc_reportable/migrations/0006_alter_gradingdata_revision_and_more.py +5 -6
  404. edc_reportable/migrations/0007_alter_gradingdata_age_phrase_and_more.py +509 -0
  405. edc_reportable/models/normal_data.py +4 -5
  406. edc_reportable/models/reference_model_mixins.py +10 -11
  407. edc_reportable/models/reference_range_collection.py +12 -13
  408. edc_reportable/post_migrate_signals.py +1 -1
  409. edc_reportable/utils/convert_units.py +11 -45
  410. edc_reportable/utils/get_normal_data_or_raise.py +2 -2
  411. edc_reportable/utils/get_reference_range_collection.py +2 -3
  412. edc_reportable/utils/load_data.py +4 -4
  413. edc_reportable/utils/update_grading_data.py +5 -5
  414. edc_review_dashboard/auths.py +23 -18
  415. edc_review_dashboard/migrations/0001_initial.py +3 -2
  416. edc_review_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  417. edc_screening/age_evaluator.py +6 -6
  418. edc_screening/auths.py +35 -30
  419. edc_screening/eligibility.py +1 -1
  420. edc_screening/gender_evaluator.py +1 -1
  421. edc_screening/migrations/0001_initial.py +3 -2
  422. edc_screening/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  423. edc_screening/model_mixins/eligibility_model_mixin.py +3 -6
  424. edc_screening/model_mixins/screening_fields_model_mixin.py +6 -8
  425. edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
  426. edc_screening/screening_eligibility.py +2 -4
  427. edc_screening/utils.py +9 -9
  428. edc_search/generate_slug.py +26 -0
  429. edc_search/model_mixins.py +10 -22
  430. edc_sites/auths.py +8 -3
  431. edc_sites/migrations/0007_edcpermissions.py +3 -2
  432. edc_sites/migrations/0010_alter_edcpermissions_device_created_and_more.py +69 -0
  433. edc_sites/model_mixins/site_model_mixin.py +2 -2
  434. edc_sites/site.py +5 -5
  435. edc_sites/system_checks.py +1 -1
  436. edc_subject_dashboard/auths.py +27 -22
  437. edc_subject_dashboard/migrations/0001_initial.py +3 -2
  438. edc_subject_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  439. edc_subject_dashboard/requisition_report.py +6 -4
  440. edc_subject_dashboard/requisition_verifier.py +6 -6
  441. edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +2 -2
  442. edc_subject_dashboard/view_mixins/subject_visit_view_mixin.py +7 -8
  443. edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +3 -2
  444. edc_subject_dashboard/view_utils/timepoint_status_button.py +2 -2
  445. edc_timepoint/apps.py +0 -21
  446. edc_timepoint/model_mixins.py +22 -20
  447. edc_transfer/model_mixins.py +4 -4
  448. edc_transfer/modeladmin_mixins.py +1 -1
  449. edc_unblinding/auths.py +9 -4
  450. edc_unblinding/migrations/0001_initial.py +13 -13
  451. edc_unblinding/migrations/0014_alter_historicalunblindingrequest_action_identifier_and_more.py +291 -0
  452. edc_unblinding/migrations/0015_alter_historicalunblindingrequest_report_datetime_and_more.py +45 -0
  453. edc_unblinding/models/unblinding_request.py +2 -2
  454. edc_unblinding/models/unblinding_review.py +3 -3
  455. edc_utils/__init__.py +3 -1
  456. edc_utils/age.py +10 -16
  457. edc_utils/show_urls.py +29 -2
  458. edc_visit_schedule/auths.py +6 -1
  459. edc_visit_schedule/migrations/0001_initial.py +3 -3
  460. edc_visit_schedule/migrations/0002_auto_20190305_0123.py +3 -6
  461. edc_visit_schedule/migrations/0003_historicalvisitschedule_visitschedule.py +5 -4
  462. edc_visit_schedule/migrations/0015_historicalonschedule_offschedule_onschedule.py +10 -10
  463. edc_visit_schedule/migrations/0019_alter_historicalonschedule_device_created_and_more.py +229 -0
  464. edc_visit_schedule/migrations/0020_alter_historicalonschedule_onschedule_datetime_and_more.py +65 -0
  465. edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +5 -4
  466. edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +5 -4
  467. edc_visit_schedule/model_mixins/visit_schedule/visit_code_fields_model_mixin.py +1 -1
  468. edc_visit_schedule/models/subject_schedule_history.py +6 -6
  469. edc_visit_schedule/schedule/visit_collection.py +1 -1
  470. edc_visit_schedule/site_visit_schedules.py +2 -2
  471. edc_visit_schedule/subject_schedule.py +5 -4
  472. edc_visit_schedule/view_mixins.py +2 -3
  473. edc_visit_schedule/visit/visit.py +3 -2
  474. edc_visit_tracking/migrations/0004_subjectvisit_subjectvisitmissedreasons_extra_value_and_more.py +13 -13
  475. edc_visit_tracking/migrations/0009_alter_historicalsubjectvisit_comments_and_more.py +450 -0
  476. edc_visit_tracking/migrations/0010_alter_historicalsubjectvisit_report_datetime_and_more.py +68 -0
  477. edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -3
  478. edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
  479. edc_visit_tracking/model_mixins/requisitions/visit_tracking_requisition_model_mixin.py +2 -2
  480. edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -2
  481. edc_visit_tracking/model_mixins/visit_model_mixin/caretaker_fields_mixin.py +2 -3
  482. edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +1 -1
  483. edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_fields_mixin.py +8 -11
  484. edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +1 -1
  485. edc_visit_tracking/models/signals.py +3 -3
  486. edc_visit_tracking/models/subject_visit.py +1 -1
  487. edc_vitals/calculators/bmi.py +7 -5
  488. edc_vitals/utils.py +1 -1
  489. edc_form_label/models.py +0 -0
  490. edc_search/constants.py +0 -1
  491. edc_search/models.py +0 -0
  492. edc_search/search_slug.py +0 -50
  493. edc_search/updater.py +0 -30
  494. edc_search/wsgi.py +0 -7
  495. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/licenses/LICENSE +0 -0
@@ -1,12 +1,12 @@
1
1
  from django.apps import apps as django_apps
2
2
  from django.contrib import messages
3
+ from django.utils import timezone
3
4
 
4
5
  from edc_constants.constants import YES
5
6
  from edc_dashboard.view_mixins import EdcViewMixin
6
7
  from edc_lab import Specimen
7
8
  from edc_lab.labels import AliquotLabel
8
9
  from edc_lab.site_labs import site_labs
9
- from edc_utils import get_utcnow
10
10
 
11
11
  from ...view_mixins import ProcessRequisitionViewMixin
12
12
  from .action_view import ActionView
@@ -38,7 +38,7 @@ class ReceiveView(EdcViewMixin, ProcessRequisitionViewMixin, ActionView):
38
38
  updated += (
39
39
  model_cls.objects.filter(pk__in=self.selected_items, is_drawn=YES)
40
40
  .exclude(received=True)
41
- .update(received=True, received_datetime=get_utcnow())
41
+ .update(received=True, received_datetime=timezone.now())
42
42
  )
43
43
  if updated:
44
44
  message = f"{updated} requisitions received."
@@ -1,8 +1,8 @@
1
1
  from django.contrib import messages
2
+ from django.utils import timezone
2
3
 
3
4
  from edc_dashboard.view_mixins import EdcViewMixin
4
5
  from edc_lab import SHIPPED
5
- from edc_utils import get_utcnow
6
6
 
7
7
  from ...view_mixins import BoxViewMixin
8
8
  from .action_view import ActionView
@@ -48,7 +48,7 @@ class VerifyBoxItemView(EdcViewMixin, BoxViewMixin, ActionView):
48
48
  if self.box_item:
49
49
  if self.box_item == box_item_in_position:
50
50
  box_item_in_position.verified = 1
51
- box_item_in_position.verified_datetime = get_utcnow()
51
+ box_item_in_position.verified_datetime = timezone.now()
52
52
  self.next_position()
53
53
  self.redirect_querystring.pop("alert")
54
54
  else:
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  from typing import Any
2
3
 
3
4
 
@@ -20,11 +21,10 @@ def calculate_missing(obj: Any, panel: Any) -> tuple[int, str | None]:
20
21
  missing = []
21
22
  for utest_id in panel.utest_ids:
22
23
  for field in fields:
23
- try:
24
- utest_id, _ = utest_id
25
- except ValueError:
26
- pass
27
- if field == utest_id or field == f"{utest_id}_value":
28
- if getattr(obj, field) is None:
29
- missing.append(field)
30
- return len(missing), ",".join(missing) if missing else None
24
+ with contextlib.suppress(ValueError):
25
+ utest_id, _ = utest_id # noqa: PLW2901
26
+ if field == utest_id or (
27
+ field == f"{utest_id}_value" and getattr(obj, field) is None
28
+ ):
29
+ missing.append(field)
30
+ return len(missing), ",".join(missing) if missing else ""
@@ -51,13 +51,13 @@ class BloodResultsFormValidatorMixin(
51
51
  self.required_if_not_none(
52
52
  field=f"{utest_id}{self.value_field_suffix or ''}",
53
53
  field_required=f"{utest_id}_abnormal",
54
- field_required_evaluate_as_int=True,
54
+ field_required_evaluate_as_int=False,
55
55
  )
56
56
  if f"{utest_id}_reportable" in self.cleaned_data:
57
57
  self.required_if_not_none(
58
58
  field=f"{utest_id}{self.value_field_suffix or ''}",
59
59
  field_required=f"{utest_id}_reportable",
60
- field_required_evaluate_as_int=True,
60
+ field_required_evaluate_as_int=False,
61
61
  )
62
62
  self.evaluate_value(prefix=utest_id)
63
63
  self.validate_reportable_fields(
@@ -18,36 +18,37 @@ def get_summary(obj) -> tuple[list[str], list[str], list[str]]:
18
18
  except ValueError:
19
19
  utest_id = field_name
20
20
  reference_range_collection = get_reference_range_collection(obj)
21
- if units := getattr(obj, f"{utest_id}_units", None):
22
- if value := getattr(obj, field_name):
23
- opts.update(units=units, label=utest_id)
21
+ if (units := getattr(obj, f"{utest_id}_units", None)) and (
22
+ value := getattr(obj, field_name)
23
+ ):
24
+ opts.update(units=units, label=utest_id)
25
+ try:
26
+ grading_data, grading_eval_phrase = reference_range_collection.get_grade(
27
+ value, **opts
28
+ )
29
+ except NotEvaluated as e:
30
+ errors.append(f"{e}.")
31
+ grading_data = None
32
+ grading_eval_phrase = None
33
+ if (
34
+ grading_data
35
+ and grading_data.grade
36
+ in reference_range_collection.reportable_grades(utest_id)
37
+ ):
38
+ setattr(obj, f"{utest_id}_grade", grading_data.grade)
39
+ setattr(obj, f"{utest_id}_grade_description", grading_data.description)
40
+ reportable.append(f"{grading_eval_phrase}")
41
+ else:
24
42
  try:
25
- grading_data, grading_eval_phrase = reference_range_collection.get_grade(
43
+ is_normal, normal_data = reference_range_collection.is_normal(
26
44
  value, **opts
27
45
  )
28
46
  except NotEvaluated as e:
29
47
  errors.append(f"{e}.")
30
- grading_data = None
31
- grading_eval_phrase = None
32
- if (
33
- grading_data
34
- and grading_data.grade
35
- in reference_range_collection.reportable_grades(utest_id)
36
- ):
37
- setattr(obj, f"{utest_id}_grade", grading_data.grade)
38
- setattr(obj, f"{utest_id}_grade_description", grading_data.description)
39
- reportable.append(f"{grading_eval_phrase}")
40
48
  else:
41
- try:
42
- is_normal, normal_data = reference_range_collection.is_normal(
43
- value, **opts
49
+ if is_normal is False:
50
+ abnormal.append(
51
+ f"{normal_data.label}: {value} {units} "
52
+ f"{normal_data.phrase} Abnormal"
44
53
  )
45
- except NotEvaluated as e:
46
- errors.append(f"{e}.")
47
- else:
48
- if is_normal is False:
49
- abnormal.append(
50
- f"{normal_data.label}: {value} {units} "
51
- f"{normal_data.phrase} Abnormal"
52
- )
53
54
  return reportable, abnormal, errors
@@ -16,12 +16,12 @@ class BloodResultsFieldsModelMixin(models.Model):
16
16
  choices=YES_NO,
17
17
  max_length=25,
18
18
  help_text=(
19
- "Abnormal results present at baseline or continuing from " "baseline not included."
19
+ "Abnormal results present at baseline or continuing from baseline not included."
20
20
  ),
21
21
  )
22
22
 
23
23
  results_reportable = models.CharField(
24
- verbose_name=("If any results are abnormal, are results within grade 3 or above?"),
24
+ verbose_name="If any results are abnormal, are results within grade 3 or above?",
25
25
  max_length=25,
26
26
  choices=YES_NO_NA,
27
27
  help_text=(
@@ -30,13 +30,13 @@ class BloodResultsFieldsModelMixin(models.Model):
30
30
  ),
31
31
  )
32
32
 
33
- summary = models.TextField(null=True, blank=True)
33
+ summary = models.TextField(default="", blank=True)
34
34
 
35
- reportable_summary = models.TextField(null=True, blank=True)
35
+ reportable_summary = models.TextField(default="", blank=True)
36
36
 
37
- abnormal_summary = models.TextField(null=True, blank=True)
37
+ abnormal_summary = models.TextField(default="", blank=True)
38
38
 
39
- errors = models.TextField(null=True, blank=True)
39
+ errors = models.TextField(default="", blank=True)
40
40
 
41
41
  missing_count = models.IntegerField(
42
42
  default=0,
@@ -45,7 +45,7 @@ class BloodResultsFieldsModelMixin(models.Model):
45
45
  )
46
46
 
47
47
  missing = models.TextField(
48
- null=True,
48
+ default="",
49
49
  editable=False,
50
50
  help_text="calculated string of field names that have been left blank",
51
51
  )
@@ -70,6 +70,8 @@ class BloodResultsMethodsModelMixin(models.Model):
70
70
  return get_summary(self)
71
71
 
72
72
  def get_summary_options(self: Any) -> dict:
73
+ # note: gender and dob are queried from RegisteredSubject
74
+ # in reportables
73
75
  return dict(
74
76
  subject_identifier=self.subject_visit.subject_identifier,
75
77
  report_datetime=self.report_datetime,
@@ -37,13 +37,13 @@ class FbgModelMixin(
37
37
  verbose_name="Was a point-of-care test used?",
38
38
  max_length=15,
39
39
  choices=YES_NO,
40
- null=True,
40
+ default="",
41
41
  )
42
42
  fasting = models.CharField(
43
43
  verbose_name="Was this fasting or non-fasting?",
44
44
  max_length=25,
45
45
  choices=FASTING_CHOICES,
46
- null=True,
46
+ default="",
47
47
  blank=False,
48
48
  )
49
49
 
@@ -55,7 +55,7 @@ class FbgModelMixin(
55
55
 
56
56
  def get_summary_options(self) -> dict:
57
57
  opts = super().get_summary_options()
58
- fasting = True if self.fasting == FASTING else False
58
+ fasting = self.fasting == FASTING
59
59
  opts.update(fasting=fasting)
60
60
  return opts
61
61
 
@@ -34,13 +34,13 @@ class GlucoseModelMixin(
34
34
  verbose_name="Was a point-of-care test used?",
35
35
  max_length=15,
36
36
  choices=YES_NO,
37
- null=True,
37
+ default="",
38
38
  )
39
39
  fasting = models.CharField(
40
40
  verbose_name="Was this fasting or non-fasting?",
41
41
  max_length=25,
42
42
  choices=FASTING_CHOICES,
43
- null=True,
43
+ default="",
44
44
  blank=False,
45
45
  )
46
46
 
@@ -52,7 +52,7 @@ class GlucoseModelMixin(
52
52
 
53
53
  def get_summary_options(self: Any) -> dict:
54
54
  opts = super().get_summary_options()
55
- fasting = True if self.fasting == FASTING else False
55
+ fasting = self.fasting == FASTING
56
56
  opts.update(fasting=fasting)
57
57
  return opts
58
58
 
@@ -10,18 +10,18 @@ class Hba1cModelMixin(BaseHba1cModelMixin, models.Model):
10
10
  verbose_name="Was a point-of-care test used?",
11
11
  max_length=15,
12
12
  choices=YES_NO,
13
- null=True,
13
+ default="",
14
14
  )
15
15
 
16
16
  hba1c_abnormal = models.CharField(
17
- verbose_name="abnormal", choices=YES_NO, max_length=25, null=True, blank=True
17
+ verbose_name="abnormal", choices=YES_NO, max_length=25, default="", blank=True
18
18
  )
19
19
 
20
20
  hba1c_reportable = models.CharField(
21
21
  verbose_name="reportable",
22
22
  choices=REPORTABLE,
23
23
  max_length=25,
24
- null=True,
24
+ default="",
25
25
  blank=True,
26
26
  )
27
27
 
edc_label/auths.py CHANGED
@@ -2,4 +2,9 @@ from edc_auth.site_auths import site_auths
2
2
 
3
3
  from .auth_objects import LABELING, codenames
4
4
 
5
- site_auths.add_group(*codenames, name=LABELING, no_delete=False)
5
+
6
+ def update_site_auths():
7
+ site_auths.add_group(*codenames, name=LABELING, no_delete=False)
8
+
9
+
10
+ update_site_auths()
@@ -1,4 +1,4 @@
1
- import os
1
+ from pathlib import Path
2
2
  from string import Template
3
3
 
4
4
  from django.apps import apps as django_apps
@@ -19,27 +19,27 @@ class LabelTemplate:
19
19
  zpl_label_template = django_apps.get_model(
20
20
  "edc_label.zpllabeltemplates"
21
21
  ).objects.get(name=self.template_name)
22
- except ObjectDoesNotExist:
22
+ except ObjectDoesNotExist as e:
23
23
  if static_files_path:
24
- path = finders.find(os.path.join(static_files_path, template_name))
24
+ path = finders.find(str(Path(static_files_path) / template_name))
25
25
  else:
26
26
  app_config = django_apps.get_app_config("edc_label")
27
27
  try:
28
28
  path = app_config.label_templates[template_name]
29
- except KeyError:
29
+ except KeyError as e:
30
30
  raise LabelTemplateError(
31
31
  f"Invalid label template name. "
32
32
  f"Expected one of {list(app_config.label_templates.keys())}. "
33
33
  f"Got '{template_name}'. "
34
34
  f"See edc_label.app_config."
35
- )
36
- if not os.path.exists(path or ""):
35
+ ) from e
36
+ if not path or not Path(path).exists():
37
37
  raise LabelTemplateError(
38
38
  f"Invalid label template path. "
39
39
  f"Looking for template '{template_name}'. "
40
40
  f"Got {path}. See edc_label.app_config."
41
- )
42
- with open(path) as f:
41
+ ) from e
42
+ with Path(path).open("r") as f:
43
43
  self.template = f.read()
44
44
  else:
45
45
  self.template = zpl_label_template.zpl_data.strip()
@@ -7,6 +7,7 @@ import django_audit_fields.fields.uuid_auto_field
7
7
  import django_audit_fields.models.audit_model_mixin
8
8
  import django_revision.revision_field
9
9
  from django.db import migrations, models
10
+ import django.utils.timezone
10
11
 
11
12
 
12
13
  class Migration(migrations.Migration):
@@ -33,14 +34,14 @@ class Migration(migrations.Migration):
33
34
  "created",
34
35
  models.DateTimeField(
35
36
  blank=True,
36
- default=django_audit_fields.models.audit_model_mixin.utcnow,
37
+ default=django.utils.timezone.now,
37
38
  ),
38
39
  ),
39
40
  (
40
41
  "modified",
41
42
  models.DateTimeField(
42
43
  blank=True,
43
- default=django_audit_fields.models.audit_model_mixin.utcnow,
44
+ default=django.utils.timezone.now,
44
45
  ),
45
46
  ),
46
47
  (
@@ -0,0 +1,49 @@
1
+ # Generated by Django 5.2.6 on 2025-09-17 16:53
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("edc_label", "0006_alter_zpllabeltemplates_revision"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name="zpllabeltemplates",
15
+ name="device_created",
16
+ field=models.CharField(
17
+ blank=True, default="", max_length=10, verbose_name="Device created"
18
+ ),
19
+ ),
20
+ migrations.AlterField(
21
+ model_name="zpllabeltemplates",
22
+ name="device_modified",
23
+ field=models.CharField(
24
+ blank=True, default="", max_length=10, verbose_name="Device modified"
25
+ ),
26
+ ),
27
+ migrations.AlterField(
28
+ model_name="zpllabeltemplates",
29
+ name="locale_created",
30
+ field=models.CharField(
31
+ blank=True,
32
+ default="",
33
+ help_text="Auto-updated by Modeladmin",
34
+ max_length=10,
35
+ verbose_name="Locale created",
36
+ ),
37
+ ),
38
+ migrations.AlterField(
39
+ model_name="zpllabeltemplates",
40
+ name="locale_modified",
41
+ field=models.CharField(
42
+ blank=True,
43
+ default="",
44
+ help_text="Auto-updated by Modeladmin",
45
+ max_length=10,
46
+ verbose_name="Locale modified",
47
+ ),
48
+ ),
49
+ ]
@@ -33,7 +33,7 @@ class ListModelMaker:
33
33
  try:
34
34
  self.name, self.display_name = row
35
35
  except ValueError as e:
36
- raise ListModelMakerError(e)
36
+ raise ListModelMakerError(e) from e
37
37
  except TypeError as e:
38
38
  if "Row" not in str(e):
39
39
  raise
@@ -46,7 +46,7 @@ class ListModelMaker:
46
46
  opts = dict(
47
47
  display_index=self.display_index,
48
48
  display_name=self.display_name,
49
- extra_value=self.extra_value,
49
+ extra_value=self.extra_value or "",
50
50
  )
51
51
  if "custom_name" in [f.name for f in self.model_cls._meta.get_fields()]:
52
52
  opts.update(custom_name=self.custom_name)
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import contextlib
4
+
3
5
  from django.apps import AppConfig
4
6
 
5
7
  from .list_model_maker import ListModelMaker, ListModelMakerError
@@ -10,7 +12,7 @@ class LoadListDataError(Exception):
10
12
 
11
13
 
12
14
  def load_list_data(
13
- list_data: dict = None, model_name: str | None = None, apps: AppConfig | None = None
15
+ list_data: dict | None = None, model_name: str | None = None, apps: AppConfig | None = None
14
16
  ) -> int:
15
17
  """Loads data into a list model.
16
18
 
@@ -24,25 +26,20 @@ def load_list_data(
24
26
  (name2, display_name),...],
25
27
  ...}
26
28
  """
27
- if model_name:
28
- model_names = [model_name]
29
- else:
30
- model_names = [k for k in list_data]
29
+ model_names = [model_name] if model_name else [k for k in list_data]
31
30
  n = 0
32
- for model_name in model_names:
31
+ for _model_name in model_names:
33
32
  try:
34
- data = list_data.get(model_name)()
33
+ data = list_data.get(_model_name)()
35
34
  except TypeError:
36
- data = list_data.get(model_name)
35
+ data = list_data.get(_model_name)
37
36
  try:
38
37
  for display_index, row in enumerate(data):
39
- try:
40
- row = row()
41
- except TypeError:
42
- pass
43
- maker = ListModelMaker(display_index, row, model_name, apps=apps)
38
+ with contextlib.suppress(TypeError):
39
+ row = row() # noqa: PLW2901
40
+ maker = ListModelMaker(display_index, row, _model_name, apps=apps)
44
41
  maker.create_or_update()
45
42
  except ListModelMakerError as e:
46
- raise LoadListDataError(f"{e} See {list_data.get(model_name)}.")
43
+ raise LoadListDataError(f"{e} See {list_data.get(_model_name)}.") from e
47
44
  n += 1
48
45
  return n
@@ -1,3 +1,5 @@
1
+ import contextlib
2
+
1
3
  from django.apps import AppConfig
2
4
  from django.apps import apps as django_apps
3
5
  from django.core.exceptions import ObjectDoesNotExist
@@ -34,10 +36,8 @@ def load_model_data(model_data: dict, apps: AppConfig | None = None) -> int:
34
36
  try:
35
37
  obj = model.objects.get(**{unique_field: opts.get(unique_field)})
36
38
  except ObjectDoesNotExist:
37
- try:
39
+ with contextlib.suppress(IntegrityError):
38
40
  model.objects.create(**opts)
39
- except IntegrityError:
40
- pass
41
41
  else:
42
42
  for key, value in opts.items():
43
43
  setattr(obj, key, value)
@@ -18,7 +18,11 @@ class BaseListModelMixin(models.Model):
18
18
  help_text="This is the stored value, required",
19
19
  )
20
20
 
21
- plural_name = models.CharField(verbose_name="Plural name", max_length=250, null=True)
21
+ plural_name = models.CharField(
22
+ verbose_name="Plural name",
23
+ max_length=250,
24
+ default="",
25
+ )
22
26
 
23
27
  display_name = models.CharField(
24
28
  verbose_name="Name",
@@ -34,10 +38,14 @@ class BaseListModelMixin(models.Model):
34
38
  )
35
39
 
36
40
  field_name = models.CharField(
37
- max_length=25, editable=False, null=True, blank=True, help_text="Not required"
41
+ max_length=25,
42
+ editable=False,
43
+ default="",
44
+ blank=True,
45
+ help_text="Not required",
38
46
  )
39
47
 
40
- extra_value = models.CharField(max_length=250, null=True)
48
+ extra_value = models.CharField(max_length=250, default="")
41
49
 
42
50
  version = models.CharField(max_length=35, editable=False, default="1.0")
43
51
 
@@ -85,7 +93,7 @@ class ListModelMixin2(BaseListModelMixin):
85
93
 
86
94
  custom_name = models.CharField(
87
95
  max_length=25,
88
- null=True,
96
+ default="",
89
97
  blank=True,
90
98
  help_text="A custom name/value to use on export instead of or in addition to `name`",
91
99
  )
@@ -6,7 +6,7 @@ style = color_style()
6
6
 
7
7
 
8
8
  def post_migrate_list_data(sender=None, **kwargs):
9
- from .site_list_data import get_autodiscover_enabled, site_list_data
9
+ from .site_list_data import get_autodiscover_enabled, site_list_data # noqa: PLC0415
10
10
 
11
11
  if get_autodiscover_enabled():
12
12
  sys.stdout.write(style.MIGRATE_HEADING("Updating list data:\n"))
@@ -11,9 +11,9 @@ style = color_style()
11
11
  class PreloadData:
12
12
  def __init__(
13
13
  self,
14
- list_data: dict[str, list[tuple[str | int, str]]] = None,
15
- model_data: dict = None,
16
- list_data_model_name: str = None,
14
+ list_data: dict[str, list[tuple[str | int, str]]],
15
+ model_data: dict | None = None,
16
+ list_data_model_name: str | None = None,
17
17
  apps: AppConfig = None,
18
18
  ) -> None:
19
19
  self.list_data = list_data
@@ -24,7 +24,7 @@ class PreloadData:
24
24
  if self.model_data:
25
25
  self.item_count += self.load_model_data()
26
26
 
27
- def load_list_data(self, model_name: str = None, apps: AppConfig | None = None) -> int:
27
+ def load_list_data(self, model_name: str, apps: AppConfig | None = None) -> int:
28
28
  return load_list_data(self.list_data, model_name=model_name, apps=apps)
29
29
 
30
30
  def load_model_data(self, apps: AppConfig | None = None) -> int:
edc_list_data/row.py CHANGED
@@ -24,7 +24,7 @@ class Row:
24
24
  @dataclass
25
25
  class AsListData:
26
26
  data: tuple[tuple[str, str, str], ...] | Choices
27
- rows: list[Row, ...] | None = field(default_factory=list, init=False)
27
+ rows: list[Row] | None = field(default_factory=list, init=False)
28
28
 
29
29
  def __post_init__(self):
30
30
  for tpl in self.data:
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  import copy
2
3
  import sys
3
4
  from importlib import import_module
@@ -51,7 +52,7 @@ class SiteListData:
51
52
  if app_name and app_name in self.app_names:
52
53
  raise AlreadyLoaded(f"App already loaded. Got {app_name}.")
53
54
  self.app_names.append(app_name)
54
- opts = copy.deepcopy(self._get_options(module))
55
+ opts = {k: v for k, v in self._get_options(module).items()}
55
56
  sys.stdout.write(f" - registered {self.module_name} from '{module.__name__}'\n")
56
57
  if opts.get(self.module_name):
57
58
  self._replace_list_data_or_raise_on_duplicate(module, opts)
@@ -60,6 +61,8 @@ class SiteListData:
60
61
  def load_data(self) -> None:
61
62
  """Calls `load` class with each list_data dictionary module to
62
63
  update database `list` tables.
64
+
65
+ See post_migrate_list_data.
63
66
  """
64
67
  style = color_style()
65
68
  for module_name, opts in self.registry.items():
@@ -142,10 +145,8 @@ class SiteListData:
142
145
  ):
143
146
  sys.stdout.write(f" * checking sites for `{self.module_name}` ...\n")
144
147
  for app_name in django_apps.app_configs:
145
- try:
148
+ with contextlib.suppress(ModuleNotFoundError):
146
149
  self._import_and_register(app_name)
147
- except ModuleNotFoundError:
148
- pass
149
150
 
150
151
  def _import_and_register(self, app_name: str) -> None:
151
152
  mod = import_module(app_name)
@@ -155,7 +156,7 @@ class SiteListData:
155
156
  except ImportError as e:
156
157
  site_list_data.registry = before_import_registry
157
158
  if module_has_submodule(mod, self.module_name):
158
- raise SiteListDataError(f"{e} See {app_name}.{self.module_name}")
159
+ raise SiteListDataError(f"{e} See {app_name}.{self.module_name}") from e
159
160
  else:
160
161
  self.register(module, app_name=app_name)
161
162
 
@@ -7,6 +7,7 @@ import django_audit_fields.fields.uuid_auto_field
7
7
  import django_audit_fields.models.audit_model_mixin
8
8
  import django_revision.revision_field
9
9
  from django.db import migrations, models
10
+ import django.utils.timezone
10
11
 
11
12
 
12
13
  class Migration(migrations.Migration):
@@ -33,14 +34,14 @@ class Migration(migrations.Migration):
33
34
  "created",
34
35
  models.DateTimeField(
35
36
  blank=True,
36
- default=django_audit_fields.models.audit_model_mixin.utcnow,
37
+ default=django.utils.timezone.now,
37
38
  ),
38
39
  ),
39
40
  (
40
41
  "modified",
41
42
  models.DateTimeField(
42
43
  blank=True,
43
- default=django_audit_fields.models.audit_model_mixin.utcnow,
44
+ default=django.utils.timezone.now,
44
45
  ),
45
46
  ),
46
47
  (