clinicedc 2.0.3__py3-none-any.whl → 2.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of clinicedc might be problematic. Click here for more details.
- {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/METADATA +41 -45
- {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/RECORD +478 -478
- edc_action_item/action.py +76 -54
- edc_action_item/action_item_notification.py +1 -3
- edc_action_item/action_with_notification.py +4 -4
- edc_action_item/create_action_item.py +2 -2
- edc_action_item/create_or_update_action_type.py +1 -1
- edc_action_item/data_fixers.py +4 -5
- edc_action_item/delete_action_item.py +0 -1
- edc_action_item/modeladmin_mixins.py +2 -4
- edc_action_item/modelform_mixins/modelform_mixins.py +1 -1
- edc_action_item/models/action_item.py +53 -38
- edc_action_item/models/action_model_mixin.py +17 -17
- edc_action_item/models/action_type.py +33 -13
- edc_action_item/models/reference.py +3 -2
- edc_action_item/site_action_items.py +13 -14
- edc_action_item/stubs.py +9 -9
- edc_action_item/templatetags/action_item_extras.py +2 -2
- edc_action_item/view_utils/action_item_button.py +3 -3
- edc_action_item/view_utils/action_item_popover_list_item.py +4 -4
- edc_adherence/form_validator_mixin.py +1 -1
- edc_adverse_event/action_items/ae_followup_action.py +1 -1
- edc_adverse_event/action_items/ae_initial_action.py +1 -1
- edc_adverse_event/action_items/ae_susar_action.py +1 -1
- edc_adverse_event/action_items/ae_tmg_action.py +1 -1
- edc_adverse_event/action_items/death_report_action.py +1 -2
- edc_adverse_event/action_items/death_report_tmg_action.py +1 -1
- edc_adverse_event/action_items/death_report_tmg_second_action.py +1 -1
- edc_adverse_event/action_items/hospitalization_action.py +1 -1
- edc_adverse_event/form_validator_mixins/death_report_form_validator.py +3 -3
- edc_adverse_event/form_validator_mixins/requires_death_report_form_validator_mixin.py +3 -4
- edc_adverse_event/form_validators/death_report_tmg.py +1 -1
- edc_adverse_event/model_mixins/ae_followup/ae_followup_methods_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_followup/ae_followup_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +0 -1
- edc_adverse_event/model_mixins/ae_initial/ae_initial_methods_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_initial/ae_initial_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_special_interest/aesi_methods_model_mixin.py +4 -4
- edc_adverse_event/model_mixins/ae_special_interest/aesi_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_susar/ae_susar_methods_model_mixin.py +4 -4
- edc_adverse_event/model_mixins/ae_susar/ae_susar_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +4 -5
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +4 -4
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/death_report/death_report_extra_fields_model_mixin.py +2 -3
- edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +11 -11
- edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +9 -11
- edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +7 -6
- edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +0 -1
- edc_adverse_event/modeladmin_mixins/ae_followup_admin_mixin.py +9 -11
- edc_adverse_event/modeladmin_mixins/ae_initial_admin_mixin.py +4 -6
- edc_adverse_event/modeladmin_mixins/modeladmin_mixins.py +1 -1
- edc_adverse_event/modeladmin_mixins/utils.py +4 -4
- edc_adverse_event/models/signals.py +7 -19
- edc_adverse_event/pdf_reports/death_pdf_report.py +8 -9
- edc_adverse_event/templatetags/edc_adverse_event_extras.py +10 -20
- edc_adverse_event/urls.py +7 -3
- edc_adverse_event/utils.py +2 -2
- edc_adverse_event/view_utils/tmg_button.py +4 -4
- edc_appconfig/system_checks.py +1 -1
- edc_appointment/appointment_status_updater.py +14 -15
- edc_appointment/creators/appointment_creator.py +7 -11
- edc_appointment/creators/appointments_creator.py +1 -1
- edc_appointment/creators/unscheduled_appointment_creator.py +12 -13
- edc_appointment/form_validator_mixins/next_appointment_crf_form_validator_mixin.py +1 -3
- edc_appointment/form_validator_mixins/window_period_form_validator_mixin.py +7 -6
- edc_appointment/form_validators/appointment_form_validator.py +2 -4
- edc_appointment/form_validators/utils.py +4 -4
- edc_appointment/managers.py +4 -4
- edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -2
- edc_appointment/model_mixins/appointment_model_mixin.py +5 -5
- edc_appointment/model_mixins/window_period_model_mixin.py +1 -1
- edc_appointment/models/appointment.py +1 -1
- edc_appointment/skip_appointments.py +5 -6
- edc_appointment/stubs.py +12 -12
- edc_appointment/utils.py +41 -47
- edc_appointment/view_utils/appointment_button.py +3 -5
- edc_auth/admin/role_admin.py +5 -7
- edc_auth/auth_objects/default_roles.py +1 -3
- edc_auth/auth_updater/auth_updater.py +5 -7
- edc_auth/auth_updater/group_updater.py +8 -8
- edc_auth/auth_updater/role_updater.py +1 -2
- edc_auth/get_app_codenames.py +1 -3
- edc_auth/import_users.py +19 -19
- edc_auth/models/role.py +4 -3
- edc_auth/password_setter.py +6 -7
- edc_auth/send_new_credentials_to_user.py +2 -3
- edc_auth/site_auths.py +3 -3
- edc_consent/actions.py +4 -5
- edc_consent/consent_definition.py +8 -11
- edc_consent/consent_definition_extension.py +3 -3
- edc_consent/form_validators/__init__.py +1 -1
- edc_consent/model_mixins/__init__.py +2 -2
- edc_consent/model_mixins/consent_version_model_mixin.py +1 -1
- edc_consent/modeladmin_mixins/consent_model_admin_mixin.py +1 -2
- edc_consent/modelform_mixins/consent_modelform_mixin/consent_modelform_validation_mixin.py +3 -5
- edc_consent/site_consents.py +10 -15
- edc_consent/stubs.py +2 -2
- edc_consent/utils.py +1 -1
- edc_constants/utils.py +2 -4
- edc_crf/crf_form_validator_mixins.py +2 -2
- edc_crf/model_mixins/crf_no_manager_model_mixin.py +2 -2
- edc_crf/model_mixins/crf_status_model_mixin.py +1 -1
- edc_crf/models/crf_status.py +10 -12
- edc_crf/update_crf_status_command.py +1 -3
- edc_dashboard/management/commands/update_search_slugs.py +8 -11
- edc_dashboard/templatetags/edc_dashboard_extras.py +1 -1
- edc_dashboard/url_config.py +3 -3
- edc_dashboard/utils.py +3 -4
- edc_dashboard/views/dashboard_view.py +1 -1
- edc_data_manager/models/data_dictionary.py +1 -2
- edc_data_manager/models/data_query.py +3 -3
- edc_data_manager/models/query_rule.py +2 -2
- edc_data_manager/tasks.py +0 -2
- edc_device/device.py +1 -1
- edc_device/view_mixins.py +1 -1
- edc_document_status/fieldsets.py +1 -3
- edc_document_status/model_mixins.py +2 -2
- edc_document_status/modeladmin_mixins.py +1 -4
- edc_egfr/admin/egfr_drop_notification_admin_mixin.py +5 -7
- edc_egfr/egfr.py +6 -7
- edc_egfr/get_drop_notification_model.py +1 -1
- edc_egfr/model_mixins/egfr_drop_notification_model_mixin.py +1 -1
- edc_export/archive_exporter.py +26 -27
- edc_export/exportables.py +2 -3
- edc_export/management/commands/import_receipts.py +6 -6
- edc_export/model_exporter/file_history_updater.py +1 -1
- edc_export/model_exporter/model_exporter.py +1 -1
- edc_export/model_exporter/value_getter.py +6 -6
- edc_export/model_mixins/notification_model_mixin.py +4 -4
- edc_export/models/data_request.py +3 -3
- edc_export/models/data_request_history.py +2 -2
- edc_export/models/export_receipt.py +1 -1
- edc_export/models/file_history.py +5 -5
- edc_export/models/plan.py +4 -4
- edc_export/models/upload_export_receipt_file.py +2 -2
- edc_export/utils.py +1 -1
- edc_facility/facility.py +6 -6
- edc_facility/holidays.py +2 -5
- edc_facility/import_holidays.py +6 -6
- edc_facility/model_mixins.py +1 -1
- edc_facility/models/holiday.py +1 -1
- edc_facility/utils.py +3 -3
- edc_fieldsets/fieldsets.py +1 -1
- edc_form_describer/forms_reference.py +5 -8
- edc_form_describer/make_forms_reference.py +1 -1
- edc_form_describer/management/commands/make_forms_reference.py +1 -1
- edc_form_label/custom_label_condition.py +1 -1
- edc_form_label/form_label.py +2 -2
- edc_form_runners/exceptions.py +1 -1
- edc_form_runners/models/issue.py +3 -2
- edc_form_runners/site.py +2 -2
- edc_form_runners/templatetags/form_runners_extras.py +1 -1
- edc_form_runners/utils.py +5 -5
- edc_form_validators/applicable_field_validator.py +32 -32
- edc_form_validators/base_form_validator.py +1 -1
- edc_form_validators/extra_mixins/study_day_form_validator.py +1 -1
- edc_form_validators/many_to_many_field_validator.py +38 -43
- edc_form_validators/other_specify_field_validator.py +9 -17
- edc_form_validators/required_field_validator.py +34 -39
- edc_form_validators/test_case_mixin.py +5 -5
- edc_identifier/admin.py +1 -3
- edc_identifier/identifier.py +2 -3
- edc_identifier/model_mixins.py +5 -8
- edc_identifier/research_identifier.py +10 -12
- edc_identifier/short_identifier.py +1 -1
- edc_identifier/simple_identifier.py +22 -22
- edc_identifier/utils.py +1 -1
- edc_lab/admin/fieldsets.py +7 -9
- edc_lab/admin/modeladmin_mixins.py +5 -6
- edc_lab/form_validators/requisition_form_validator_mixin.py +2 -3
- edc_lab/forms/box_form.py +5 -11
- edc_lab/identifiers/aliquot_identifier.py +5 -8
- edc_lab/identifiers/prefix.py +2 -5
- edc_lab/lab/aliquot_creator.py +1 -2
- edc_lab/lab/aliquot_type.py +2 -4
- edc_lab/lab/manifest.py +5 -7
- edc_lab/lab/requisition_panel.py +2 -4
- edc_lab/lab/requisition_panel_group.py +5 -7
- edc_lab/model_mixins/requisition/requisition_model_mixin.py +5 -4
- edc_lab/model_mixins/shipping/manifest_model_mixin.py +6 -6
- edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -3
- edc_lab/models/aliquot.py +1 -1
- edc_lab/models/box.py +2 -2
- edc_lab/models/box_item.py +1 -1
- edc_lab/models/box_type.py +1 -1
- edc_lab/models/manifest/manifest_item.py +1 -1
- edc_lab/pdf_reports/manifest_pdf_report.py +3 -7
- edc_lab/site_labs.py +3 -3
- edc_lab_dashboard/dashboard_templates.py +1 -1
- edc_lab_dashboard/view_mixins/box_view_mixin.py +4 -9
- edc_lab_dashboard/views/action_views/action_view.py +1 -2
- edc_lab_dashboard/views/action_views/manage_manifest_view.py +1 -1
- edc_lab_dashboard/views/action_views/manifest_view.py +9 -11
- edc_lab_dashboard/views/action_views/pack_view.py +11 -14
- edc_lab_results/calculate_missing.py +2 -2
- edc_lab_results/fieldsets.py +6 -6
- edc_lab_results/model_mixin_factories/__init__.py +2 -2
- edc_lab_results/model_mixin_factories/reportable_result_model_mixin_factory.py +7 -9
- edc_lab_results/model_mixin_factories/result_model_mixin_factory.py +7 -9
- edc_lab_results/model_mixins/fbg_model_mixin.py +1 -1
- edc_lab_results/model_mixins/glucose_model_mixin.py +1 -1
- edc_label/admin.py +1 -3
- edc_label/label.py +2 -4
- edc_label/label_template.py +1 -1
- edc_label/subject_label.py +1 -3
- edc_list_data/admin.py +3 -5
- edc_list_data/load_list_data.py +1 -1
- edc_list_data/load_model_data.py +1 -3
- edc_list_data/model_mixins.py +3 -5
- edc_list_data/preload_data.py +2 -4
- edc_list_data/site_list_data.py +6 -7
- edc_listboard/filters/listboard_filter.py +2 -2
- edc_listboard/views/listboard_view.py +1 -3
- edc_locator/models.py +2 -2
- edc_locator/view_mixins/subject_locator_view_mixins.py +2 -2
- edc_ltfu/action_items.py +1 -1
- edc_ltfu/model_mixins.py +0 -2
- edc_ltfu/models.py +4 -4
- edc_metadata/admin/modeladmin_mixins.py +1 -1
- edc_metadata/admin/requisition_metadata.py +2 -4
- edc_metadata/metadata/crf_metadata_getter.py +1 -3
- edc_metadata/metadata/requisition_metadata_getter.py +1 -3
- edc_metadata/metadata_handler.py +2 -2
- edc_metadata/metadata_helper/metadata_helper_mixin.py +2 -3
- edc_metadata/metadata_mixins/source_model_metadata_mixin.py +2 -2
- edc_metadata/metadata_refresher.py +1 -1
- edc_metadata/metadata_rules/crf/crf_rule_group.py +3 -5
- edc_metadata/metadata_rules/logic.py +1 -1
- edc_metadata/metadata_rules/requisition/requisition_rule.py +4 -4
- edc_metadata/metadata_rules/requisition/requisition_rule_group.py +2 -2
- edc_metadata/metadata_rules/rule_evaluator.py +5 -6
- edc_metadata/metadata_rules/rule_group_metaclass.py +2 -3
- edc_metadata/metadata_rules/site.py +6 -7
- edc_metadata/metadata_updater.py +2 -2
- edc_metadata/metadata_wrappers/metadata_wrapper.py +4 -4
- edc_metadata/model_mixins/creates/creates_metadata_model_mixin.py +6 -7
- edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +2 -2
- edc_metadata/model_mixins/updates/updates_metadata_model_mixin.py +2 -2
- edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +2 -2
- edc_metadata/models/crf_metadata.py +27 -29
- edc_metadata/models/crf_metadata_model_mixin.py +1 -1
- edc_metadata/models/requisition_metadata.py +29 -31
- edc_metadata/stubs.py +17 -17
- edc_metadata/utils.py +4 -4
- edc_model/__init__.py +2 -2
- edc_model/models/historical_records.py +2 -2
- edc_model/models/signals.py +1 -1
- edc_model/models/url_model_mixin.py +1 -1
- edc_model/utils.py +0 -2
- edc_model_admin/dashboard/model_admin_dashboard_mixin.py +1 -3
- edc_model_admin/history/model_admin_simple_history.py +7 -9
- edc_model_admin/mixins/base_model_admin_redirect_mixin.py +4 -6
- edc_model_admin/mixins/model_admin_limit_to_selected_foreignkey.py +2 -2
- edc_model_admin/mixins/model_admin_model_redirect_mixin.py +2 -10
- edc_model_admin/mixins/model_admin_next_url_redirect_mixin.py +8 -9
- edc_model_admin/utils.py +6 -9
- edc_model_form/mixins/__init__.py +1 -1
- edc_model_form/mixins/base_model_form_mixin.py +1 -1
- edc_model_to_dataframe/model_to_dataframe.py +2 -4
- edc_navbar/site_navbars.py +2 -2
- edc_navbar/system_checks.py +1 -1
- edc_notification/mailing_list_manager.py +5 -8
- edc_notification/management/commands/list_recipients_by_notification.py +1 -1
- edc_notification/models/__init__.py +4 -2
- edc_notification/notification/graded_event_notification.py +2 -4
- edc_notification/notification/model_notification.py +1 -3
- edc_notification/notification/notification.py +14 -17
- edc_notification/site_notifications.py +7 -7
- edc_notification/stubs.py +6 -6
- edc_notification/update_mailing_lists_in_m2m.py +2 -2
- edc_offstudy/action_items.py +2 -2
- edc_offstudy/model_mixins/offstudy_model_mixin.py +1 -1
- edc_offstudy/models.py +1 -1
- edc_pdf_reports/crf_pdf_report.py +2 -2
- edc_pdf_reports/model_mixins.py +2 -2
- edc_pdf_reports/report.py +4 -5
- edc_pdf_reports/utils.py +1 -1
- edc_pdutils/dataframes/get_subject_consent.py +1 -3
- edc_pdutils/df_exporters/csv_exporter.py +5 -7
- edc_pdutils/df_exporters/tables_exporter.py +2 -2
- edc_pdutils/df_handlers/crf_df_handler.py +1 -2
- edc_pdutils/dialects/crf_dialect.py +3 -3
- edc_pdutils/management/commands/export_models.py +6 -7
- edc_pdutils/site_values_mappings.py +2 -2
- edc_pdutils/utils/datetime_to_date.py +1 -2
- edc_pdutils/utils/refresh_model_from_dataframe.py +1 -3
- edc_pdutils/utils/table_names.py +2 -4
- edc_pdutils/utils/undash.py +1 -1
- edc_pharmacy/admin/medication/assignment_admin.py +2 -4
- edc_pharmacy/admin/medication/dosage_guideline_admin.py +2 -4
- edc_pharmacy/admin/medication/formulation_admin.py +3 -5
- edc_pharmacy/admin/medication/medication_admin.py +3 -5
- edc_pharmacy/admin/prescription/rx_refill_admin.py +7 -9
- edc_pharmacy/admin/stock/lot_admin.py +5 -7
- edc_pharmacy/admin/stock/order_admin.py +2 -2
- edc_pharmacy/admin/stock/order_item_admin.py +6 -6
- edc_pharmacy/admin/stock/receive_admin.py +1 -1
- edc_pharmacy/admin/stock/receive_item_admin.py +2 -2
- edc_pharmacy/admin/stock/stock_request_admin.py +4 -6
- edc_pharmacy/dosage_calculator.py +4 -4
- edc_pharmacy/form_validators/crf/study_medication_form_validator.py +8 -8
- edc_pharmacy/forms/stock/stock_request_form.py +2 -4
- edc_pharmacy/model_mixins/study_medication_crf_model_mixin.py +2 -2
- edc_pharmacy/models/medication/formulation.py +3 -4
- edc_pharmacy/models/medication/medication.py +1 -2
- edc_pharmacy/models/prescription/rx.py +2 -2
- edc_pharmacy/models/prescription/rx_refill.py +7 -9
- edc_pharmacy/models/reports/stock_availability.py +3 -4
- edc_pharmacy/models/stock/confirmation_at_site.py +1 -3
- edc_pharmacy/models/stock/order.py +1 -2
- edc_pharmacy/models/stock/receive.py +3 -4
- edc_pharmacy/models/stock/receive_item.py +2 -3
- edc_pharmacy/models/stock/stock.py +1 -2
- edc_pharmacy/models/stock/stock_adjustment.py +1 -2
- edc_pharmacy/models/stock/stock_request.py +4 -5
- edc_pharmacy/models/storage/box.py +1 -1
- edc_pharmacy/models/storage/items/container_model_mixin.py +1 -1
- edc_pharmacy/models/storage/room.py +1 -1
- edc_pharmacy/models/storage/shelf.py +1 -1
- edc_pharmacy/models/storage/utils.py +15 -16
- edc_pharmacy/prescribe/create_prescription.py +5 -5
- edc_pharmacy/refill/refill_creator.py +1 -1
- edc_pharmacy/sample_usb_printing/usb_printing.py +1 -1
- edc_pharmacy/utils/__init__.py +1 -1
- edc_pharmacy/utils/confirm_stock.py +3 -3
- edc_pharmacy/utils/confirm_stock_at_site.py +9 -8
- edc_pharmacy/utils/dispense.py +5 -8
- edc_pharmacy/utils/format_qty.py +3 -3
- edc_pharmacy/utils/get_codenames.py +1 -1
- edc_pharmacy/utils/miscellaneous.py +1 -1
- edc_pharmacy/utils/process_repack_request.py +18 -19
- edc_pharmacy/utils/process_repack_request_queryset.py +0 -2
- edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
- edc_pharmacy/views/add_to_storage_bin_view.py +1 -1
- edc_pharmacy/views/allocate_to_subject_view.py +2 -6
- edc_pharmacy/views/confirm_stock_from_instance_view.py +4 -4
- edc_pharmacy/views/confirm_stock_from_queryset_view.py +1 -5
- edc_pharmacy/views/confirmation_at_site_view.py +2 -3
- edc_pharmacy/views/dispense_view.py +1 -1
- edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
- edc_pharmacy/views/print_labels_view.py +30 -31
- edc_pharmacy/views/transfer_stock_view.py +1 -1
- edc_prn/prn.py +1 -1
- edc_prn/site_prn_forms.py +1 -2
- edc_protocol_incident/action_items.py +2 -2
- edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +3 -3
- edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +3 -5
- edc_protocol_incident/modeladmin_mixins.py +3 -5
- edc_protocol_incident/models/protocol_deviation_violation.py +5 -5
- edc_protocol_incident/models/protocol_incident.py +5 -5
- edc_pylabels/site_label_configs.py +5 -5
- edc_qareports/model_mixins/qa_report_model_mixin.py +4 -2
- edc_qareports/models/qa_reports_log.py +1 -2
- edc_qareports/utils.py +1 -2
- edc_randomization/admin.py +3 -5
- edc_randomization/auth_objects.py +2 -3
- edc_randomization/blinding.py +1 -1
- edc_randomization/constants.py +2 -4
- edc_randomization/model_mixins.py +3 -3
- edc_randomization/randomization_list_importer.py +13 -14
- edc_randomization/randomization_list_verifier.py +11 -13
- edc_randomization/randomizer.py +2 -2
- edc_randomization/system_checks.py +1 -2
- edc_randomization/utils.py +5 -5
- edc_refusal/admin.py +1 -1
- edc_refusal/model_mixins.py +1 -1
- edc_refusal/utils.py +1 -1
- edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +2 -2
- edc_registration/modeladmin_mixins.py +4 -7
- edc_registration/models/registered_subject.py +7 -9
- edc_registration/utils.py +3 -4
- edc_reportable/data/grading_data/daids_july_2017.py +3 -3
- edc_reportable/evaluator.py +5 -5
- edc_reportable/formula.py +1 -1
- edc_reportable/reference_range_evaluator.py +3 -3
- edc_reportable/utils/convert_units.py +10 -12
- edc_reportable/utils/grading_data_model_cls.py +2 -2
- edc_reportable/utils/grading_exception_model_cls.py +2 -2
- edc_reportable/utils/molecular_weight_model_cls.py +2 -2
- edc_reportable/utils/normal_data_model_cls.py +2 -2
- edc_reportable/utils/reference_range_colllection_model_cls.py +2 -2
- edc_screening/age_evaluator.py +2 -4
- edc_screening/eligibility.py +1 -1
- edc_screening/form_validator_mixins.py +2 -2
- edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
- edc_screening/screening_eligibility.py +1 -1
- edc_screening/utils.py +4 -6
- edc_search/model_mixins.py +1 -1
- edc_search/search_slug.py +1 -3
- edc_search/updater.py +1 -1
- edc_sites/admin/site_model_admin_mixin.py +2 -2
- edc_sites/model_mixins/site_model_mixin.py +1 -2
- edc_sites/modelform_mixins.py +2 -2
- edc_sites/models/__init__.py +1 -1
- edc_sites/models/site_profile.py +4 -4
- edc_sites/site.py +24 -32
- edc_sites/system_checks.py +1 -1
- edc_sites/utils/get_message_text.py +1 -1
- edc_sites/utils/valid_site_for_subject_or_raise.py +5 -6
- edc_subject_dashboard/requisition_report.py +4 -5
- edc_subject_dashboard/requisition_verifier.py +4 -2
- edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +16 -17
- edc_subject_dashboard/view_utils/__init__.py +1 -1
- edc_subject_dashboard/view_utils/crf_button.py +1 -3
- edc_subject_dashboard/view_utils/subject_consent_dashboard_button.py +2 -2
- edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +2 -2
- edc_subject_dashboard/view_utils/timepoint_status_button.py +1 -4
- edc_subject_dashboard/views/requisition_print_actions_view.py +2 -2
- edc_subject_dashboard/views/subject_dashboard_view.py +1 -1
- edc_timepoint/model_mixins.py +2 -2
- edc_transfer/action_items.py +1 -1
- edc_transfer/model_mixins.py +4 -3
- edc_transfer/modeladmin_mixins.py +3 -6
- edc_unblinding/action_items.py +2 -2
- edc_unblinding/models/unblinding_request.py +3 -3
- edc_unblinding/models/unblinding_review.py +3 -3
- edc_utils/__init__.py +6 -5
- edc_utils/age.py +1 -1
- edc_utils/celery.py +3 -8
- edc_utils/get_static_file.py +1 -1
- edc_utils/text.py +5 -6
- edc_view_utils/__init__.py +3 -3
- edc_view_utils/dashboard_model_button.py +4 -4
- edc_view_utils/model_button.py +7 -8
- edc_view_utils/perms.py +3 -3
- edc_visit_schedule/action_items.py +2 -2
- edc_visit_schedule/admin/list_filters.py +11 -9
- edc_visit_schedule/admin/subject_schedule_history_admin.py +13 -15
- edc_visit_schedule/admin/visit_schedule_admin.py +7 -7
- edc_visit_schedule/fieldsets.py +4 -6
- edc_visit_schedule/management/commands/find_invalid_onschedules.py +1 -1
- edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +3 -1
- edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +1 -1
- edc_visit_schedule/modelform_mixins/__init__.py +1 -1
- edc_visit_schedule/modelform_mixins/off_schedule_modelform_mixin.py +1 -2
- edc_visit_schedule/models/subject_schedule_history.py +2 -1
- edc_visit_schedule/models/visit_schedule.py +2 -2
- edc_visit_schedule/schedule/schedule.py +11 -12
- edc_visit_schedule/schedule/visit_collection.py +4 -3
- edc_visit_schedule/schedule/window.py +19 -12
- edc_visit_schedule/site_visit_schedules.py +9 -9
- edc_visit_schedule/subject_schedule.py +6 -7
- edc_visit_schedule/system_checks.py +8 -4
- edc_visit_schedule/view_mixins.py +1 -1
- edc_visit_schedule/visit/crf.py +3 -7
- edc_visit_schedule/visit/requisition.py +2 -2
- edc_visit_schedule/visit/visit.py +6 -7
- edc_visit_schedule/visit/window_period.py +8 -8
- edc_visit_schedule/visit_schedule/schedules_collection.py +2 -5
- edc_visit_tracking/action_items.py +11 -13
- edc_visit_tracking/form_validators/visit_form_validator.py +5 -5
- edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -4
- edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -3
- edc_visit_tracking/model_mixins/utils.py +1 -1
- edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +3 -3
- edc_visit_tracking/modeladmin_mixins/crf_model_admin_mixin.py +6 -4
- edc_visit_tracking/modeladmin_mixins/visit_model_admin_mixin.py +6 -7
- edc_visit_tracking/modelform_mixins/crf/visit_tracking_crf_modelform_mixin.py +4 -5
- edc_visit_tracking/modelform_mixins/visit_tracking_modelform_mixin.py +3 -4
- edc_visit_tracking/models/subject_visit.py +1 -1
- edc_visit_tracking/models/subject_visit_missed.py +1 -1
- edc_visit_tracking/stubs.py +7 -7
- edc_visit_tracking/typing_stubs.py +11 -11
- edc_visit_tracking/utils.py +5 -5
- edc_visit_tracking/view_utils/related_visit_button.py +5 -5
- edc_vitals/calculators/bmi.py +1 -1
- edc_vitals/form_validators/blood_pressure_form_validator_mixin.py +8 -12
- edc_vitals/form_validators/bmi_form_validator_mixin.py +1 -1
- edc_vitals/form_validators/weight_height_with_bmi_form_validator_mixin.py +5 -2
- edc_vitals/model_mixins/blood_pressure_model_mixin.py +3 -4
- edc_vitals/model_mixins/weight_height_bmi_model_mixin.py +4 -4
- edc_vitals/utils.py +1 -1
- edc_vitals/validators.py +1 -1
- {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/WHEEL +0 -0
- {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -59,17 +59,15 @@ class RandomizationListVerifier:
|
|
|
59
59
|
"Resolve this issue before using the system."
|
|
60
60
|
)
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if message := self.verify():
|
|
72
|
-
self.messages.append(message)
|
|
62
|
+
elif not self.randomizationlist_path or not self.randomizationlist_path.exists():
|
|
63
|
+
self.messages.append(
|
|
64
|
+
f"Randomization list file does not exist but SIDs "
|
|
65
|
+
f"have been loaded. Expected file "
|
|
66
|
+
f"{self.randomizationlist_path}. "
|
|
67
|
+
f"Resolve this issue before using the system."
|
|
68
|
+
)
|
|
69
|
+
elif message := self.verify():
|
|
70
|
+
self.messages.append(message)
|
|
73
71
|
if self.messages:
|
|
74
72
|
if (
|
|
75
73
|
"migrate" not in sys.argv
|
|
@@ -118,7 +116,7 @@ class RandomizationListVerifier:
|
|
|
118
116
|
f"{self.randomizationlist_path}. "
|
|
119
117
|
f"Resolve this issue before using the system. "
|
|
120
118
|
f"Problem started on line {index + 1}. "
|
|
121
|
-
f
|
|
119
|
+
f"Got '{row['sid']}' != '{obj1.sid}'."
|
|
122
120
|
)
|
|
123
121
|
if not message:
|
|
124
122
|
assignment = self.get_assignment(row)
|
|
@@ -136,7 +134,7 @@ class RandomizationListVerifier:
|
|
|
136
134
|
f"does not match model data. See file "
|
|
137
135
|
f"{self.randomizationlist_path}. "
|
|
138
136
|
f"Resolve this issue before using the system. "
|
|
139
|
-
f
|
|
137
|
+
f"Got '{obj2.site_name}' != '{row['site_name']}' "
|
|
140
138
|
f"for sid={obj2.sid}."
|
|
141
139
|
)
|
|
142
140
|
return message
|
edc_randomization/randomizer.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import warnings
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import TYPE_CHECKING, Any
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
7
|
|
|
8
8
|
from django.apps import apps as django_apps
|
|
9
9
|
from django.conf import settings
|
|
@@ -195,7 +195,7 @@ class Randomizer:
|
|
|
195
195
|
return {self.identifier_attr: getattr(self, self.identifier_attr)}
|
|
196
196
|
|
|
197
197
|
@classmethod
|
|
198
|
-
def get_registration_model_cls(cls) ->
|
|
198
|
+
def get_registration_model_cls(cls) -> type[RegisteredSubject]:
|
|
199
199
|
return get_registered_subject_model_cls()
|
|
200
200
|
|
|
201
201
|
@property
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Type
|
|
5
4
|
|
|
6
5
|
from django.conf import settings
|
|
7
6
|
from django.core.checks import Error, Warning
|
|
@@ -15,7 +14,7 @@ from .site_randomizers import site_randomizers
|
|
|
15
14
|
@dataclass(frozen=True)
|
|
16
15
|
class Err:
|
|
17
16
|
id: str
|
|
18
|
-
cls:
|
|
17
|
+
cls: type[Warning | Error]
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
error_configs = dict(
|
edc_randomization/utils.py
CHANGED
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import csv
|
|
4
4
|
import os
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any
|
|
6
6
|
|
|
7
7
|
from django.conf import settings
|
|
8
8
|
from django.contrib.auth import get_user_model
|
|
@@ -93,9 +93,9 @@ def generate_fake_randomization_list(
|
|
|
93
93
|
all_sites=None,
|
|
94
94
|
country=None,
|
|
95
95
|
site_name=None,
|
|
96
|
-
assignment:
|
|
97
|
-
slots:
|
|
98
|
-
write_header:
|
|
96
|
+
assignment: list | None = None,
|
|
97
|
+
slots: int | None = None,
|
|
98
|
+
write_header: bool | None = None,
|
|
99
99
|
filename=None,
|
|
100
100
|
assignment_map=None,
|
|
101
101
|
):
|
|
@@ -137,7 +137,7 @@ def generate_fake_randomization_list(
|
|
|
137
137
|
|
|
138
138
|
|
|
139
139
|
def export_randomization_list(
|
|
140
|
-
randomizer_name: str, path:
|
|
140
|
+
randomizer_name: str, path: str | None = None, username: str | None = None
|
|
141
141
|
):
|
|
142
142
|
randomizer_cls = site_randomizers.get(randomizer_name)
|
|
143
143
|
|
edc_refusal/admin.py
CHANGED
|
@@ -70,5 +70,5 @@ class SubjectRefusalAdmin(
|
|
|
70
70
|
if callable(super().view_on_site):
|
|
71
71
|
url = super().view_on_site(obj)
|
|
72
72
|
else:
|
|
73
|
-
raise NoReverseMatch(f"{e}. See subject_dashboard_url_name for {
|
|
73
|
+
raise NoReverseMatch(f"{e}. See subject_dashboard_url_name for {self!r}.")
|
|
74
74
|
return url
|
edc_refusal/model_mixins.py
CHANGED
edc_refusal/utils.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from django.core.exceptions import ObjectDoesNotExist
|
|
6
6
|
from django.db import models
|
|
@@ -23,7 +23,7 @@ class UpdatesOrCreatesRegistrationModelMixin(models.Model):
|
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
@property
|
|
26
|
-
def registration_model(self) ->
|
|
26
|
+
def registration_model(self) -> type[RegisteredSubject]:
|
|
27
27
|
"""Returns the Registration model"""
|
|
28
28
|
return get_registered_subject_model_cls()
|
|
29
29
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Tuple
|
|
2
|
-
|
|
3
1
|
from django.contrib import admin
|
|
4
2
|
from django_audit_fields.admin import audit_fields
|
|
5
3
|
|
|
@@ -25,11 +23,10 @@ class RegisteredSubjectModelAdminMixin(ModelAdminSubjectDashboardMixin, admin.Mo
|
|
|
25
23
|
if self.fieldsets:
|
|
26
24
|
if self.show_pii(request):
|
|
27
25
|
return self.fieldsets
|
|
28
|
-
|
|
29
|
-
return self.fieldsets_no_pii
|
|
26
|
+
return self.fieldsets_no_pii
|
|
30
27
|
return [(None, {"fields": self.get_fields(request, obj)})]
|
|
31
28
|
|
|
32
|
-
def get_readonly_fields(self, request, obj=None) ->
|
|
29
|
+
def get_readonly_fields(self, request, obj=None) -> tuple[str, ...]:
|
|
33
30
|
readonly_fields = super().get_readonly_fields(request, obj=obj)
|
|
34
31
|
return (
|
|
35
32
|
readonly_fields
|
|
@@ -85,7 +82,7 @@ class RegisteredSubjectModelAdminMixin(ModelAdminSubjectDashboardMixin, admin.Mo
|
|
|
85
82
|
)
|
|
86
83
|
return custom_fields + tuple(f for f in list_display if f not in custom_fields)
|
|
87
84
|
|
|
88
|
-
def get_list_filter(self, request) ->
|
|
85
|
+
def get_list_filter(self, request) -> tuple[str, ...]:
|
|
89
86
|
list_filter = super().get_list_filter(request)
|
|
90
87
|
custom_fields = (
|
|
91
88
|
"subject_type",
|
|
@@ -98,7 +95,7 @@ class RegisteredSubjectModelAdminMixin(ModelAdminSubjectDashboardMixin, admin.Mo
|
|
|
98
95
|
)
|
|
99
96
|
return custom_fields + tuple(f for f in list_filter if f not in custom_fields)
|
|
100
97
|
|
|
101
|
-
def get_search_fields(self, request) ->
|
|
98
|
+
def get_search_fields(self, request) -> tuple[str, ...]:
|
|
102
99
|
search_fields = super().get_search_fields(request)
|
|
103
100
|
pii_fields = (
|
|
104
101
|
"first_name",
|
|
@@ -44,9 +44,7 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
|
|
|
44
44
|
validators=[
|
|
45
45
|
RegexValidator(
|
|
46
46
|
regex=r"^[A-Z]{2,3}$",
|
|
47
|
-
message=(
|
|
48
|
-
"Ensure initials consist of letters " "only in upper case, no spaces."
|
|
49
|
-
),
|
|
47
|
+
message=("Ensure initials consist of letters only in upper case, no spaces."),
|
|
50
48
|
)
|
|
51
49
|
],
|
|
52
50
|
null=True,
|
|
@@ -154,7 +152,7 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
|
|
|
154
152
|
super().save(*args, **kwargs)
|
|
155
153
|
|
|
156
154
|
def natural_key(self):
|
|
157
|
-
return (self.subject_identifier_as_pk,)
|
|
155
|
+
return (self.subject_identifier_as_pk,)
|
|
158
156
|
|
|
159
157
|
def __str__(self):
|
|
160
158
|
return self.masked_subject_identifier
|
|
@@ -228,10 +226,9 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
|
|
|
228
226
|
).get(**{attrname: getattr(self, attrname)})
|
|
229
227
|
if not self.id:
|
|
230
228
|
raise RegisteredSubjectError(error_msg.format(action="insert"))
|
|
231
|
-
|
|
232
|
-
raise RegisteredSubjectError(error_msg.format(action="update"))
|
|
233
|
-
else:
|
|
229
|
+
if self.subject_identifier_is_set and obj.id != self.id:
|
|
234
230
|
raise RegisteredSubjectError(error_msg.format(action="update"))
|
|
231
|
+
raise RegisteredSubjectError(error_msg.format(action="update"))
|
|
235
232
|
except ObjectDoesNotExist:
|
|
236
233
|
pass
|
|
237
234
|
|
|
@@ -255,10 +252,11 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
|
|
|
255
252
|
name="%(app_label)s_%(class)s_first_name_uniq",
|
|
256
253
|
)
|
|
257
254
|
]
|
|
258
|
-
indexes =
|
|
255
|
+
indexes = (
|
|
256
|
+
*BaseUuidModel.Meta.indexes,
|
|
259
257
|
models.Index(fields=["first_name", "dob", "initials", "additional_key"]),
|
|
260
258
|
models.Index(fields=["subject_identifier", "identity", "screening_identifier"]),
|
|
261
|
-
|
|
259
|
+
)
|
|
262
260
|
permissions = (
|
|
263
261
|
("display_firstname", "Can display first name"),
|
|
264
262
|
("display_lastname", "Can display last name"),
|
edc_registration/utils.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
from django.apps import apps as django_apps
|
|
7
7
|
from django.conf import settings
|
|
@@ -27,7 +27,7 @@ def get_registered_subject_model_name() -> str:
|
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def get_registered_subject_model_cls() ->
|
|
30
|
+
def get_registered_subject_model_cls() -> type[RegisteredSubject]:
|
|
31
31
|
return django_apps.get_model(get_registered_subject_model_name())
|
|
32
32
|
|
|
33
33
|
|
|
@@ -62,6 +62,5 @@ def valid_subject_identifier_or_raise(
|
|
|
62
62
|
f"See `edc_protocol.ResearchProtocolConfig().subject_identifier_pattern`. "
|
|
63
63
|
f"Got `{subject_identifier}`."
|
|
64
64
|
)
|
|
65
|
-
|
|
66
|
-
return False
|
|
65
|
+
return False
|
|
67
66
|
return True
|
edc_reportable/evaluator.py
CHANGED
|
@@ -94,8 +94,8 @@ class Evaluator:
|
|
|
94
94
|
if upper and upper >= float(HIGH_VALUE):
|
|
95
95
|
upper = ""
|
|
96
96
|
return (
|
|
97
|
-
f
|
|
98
|
-
f
|
|
97
|
+
f"{lower}{self.lower_operator or ''}{value}"
|
|
98
|
+
f"{self.upper_operator or ''}{upper} {self.units}"
|
|
99
99
|
)
|
|
100
100
|
|
|
101
101
|
def in_bounds_or_raise(self, value: int | float, units: str = None) -> bool:
|
|
@@ -111,10 +111,10 @@ class Evaluator:
|
|
|
111
111
|
"""
|
|
112
112
|
value = float(value)
|
|
113
113
|
if units != self.units:
|
|
114
|
-
raise InvalidUnits(f"Expected {self.units}. See {
|
|
114
|
+
raise InvalidUnits(f"Expected {self.units}. See {self!r}")
|
|
115
115
|
condition_str = (
|
|
116
|
-
f'
|
|
117
|
-
f
|
|
116
|
+
f"{'' if self.lower is None else self.lower}{self.lower_operator or ''}{value}"
|
|
117
|
+
f"{self.upper_operator or ''}{'' if self.upper is None else self.upper}"
|
|
118
118
|
)
|
|
119
119
|
if not eval(condition_str): # nosec B307
|
|
120
120
|
raise ValueBoundryError(condition_str)
|
edc_reportable/formula.py
CHANGED
|
@@ -7,7 +7,7 @@ from edc_constants.constants import FEMALE, MALE
|
|
|
7
7
|
|
|
8
8
|
from .adult_age_options import adult_age_options
|
|
9
9
|
|
|
10
|
-
__all__ = ["Formula", "
|
|
10
|
+
__all__ = ["Formula", "FormulaError", "dummy_formula", "formula"]
|
|
11
11
|
|
|
12
12
|
from .exceptions import FormulaError
|
|
13
13
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from datetime import date, datetime
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
from django import forms
|
|
7
7
|
from django.apps import apps as django_apps
|
|
@@ -77,11 +77,11 @@ class ReferenceRangeEvaluator:
|
|
|
77
77
|
return self.reference_range_collection.grades(utest_id)
|
|
78
78
|
|
|
79
79
|
@property
|
|
80
|
-
def reference_range_collection_model_cls(self) ->
|
|
80
|
+
def reference_range_collection_model_cls(self) -> type[ReferenceRangeCollection]:
|
|
81
81
|
return django_apps.get_model("edc_reportable.referencerangecollection")
|
|
82
82
|
|
|
83
83
|
@property
|
|
84
|
-
def normal_data_model_cls(self) ->
|
|
84
|
+
def normal_data_model_cls(self) -> type[NormalData]:
|
|
85
85
|
return django_apps.get_model("edc_reportable.normaldata")
|
|
86
86
|
|
|
87
87
|
def validate_reportable_fields(self):
|
|
@@ -34,14 +34,13 @@ def micromoles_per_liter_to(
|
|
|
34
34
|
) -> dict:
|
|
35
35
|
if units_to == MICROMOLES_PER_LITER:
|
|
36
36
|
return {MICROMOLES_PER_LITER: float(value)}
|
|
37
|
-
|
|
37
|
+
if units_to == MILLIMOLES_PER_LITER:
|
|
38
38
|
return {MILLIMOLES_PER_LITER: float(value) / 1000.00}
|
|
39
|
-
|
|
39
|
+
if units_to == GRAMS_PER_LITER:
|
|
40
40
|
return {GRAMS_PER_LITER: (float(value) * get_mw(label)) / 100.00}
|
|
41
|
-
|
|
41
|
+
if units_to == MILLIGRAMS_PER_DECILITER:
|
|
42
42
|
return {MILLIGRAMS_PER_DECILITER: (float(value) * get_mw(label)) / 10000.00}
|
|
43
|
-
|
|
44
|
-
raise ConversionNotHandled(f"Conversion not found. Tried umol/L to {units_to}. ")
|
|
43
|
+
raise ConversionNotHandled(f"Conversion not found. Tried umol/L to {units_to}. ")
|
|
45
44
|
|
|
46
45
|
|
|
47
46
|
def milligrams_per_deciliter_to(
|
|
@@ -49,16 +48,15 @@ def milligrams_per_deciliter_to(
|
|
|
49
48
|
) -> dict[str:float]:
|
|
50
49
|
if units_to == MILLIGRAMS_PER_DECILITER:
|
|
51
50
|
return {MILLIGRAMS_PER_DECILITER: float(value)}
|
|
52
|
-
|
|
51
|
+
if units_to == MILLIMOLES_PER_LITER:
|
|
53
52
|
return {MILLIMOLES_PER_LITER: (float(value) * 10.00) / get_mw(label)}
|
|
54
|
-
|
|
53
|
+
if units_to == MICROMOLES_PER_LITER:
|
|
55
54
|
return {MICROMOLES_PER_LITER: (float(value) * 10000.00) / get_mw(label)}
|
|
56
|
-
|
|
55
|
+
if units_to == MILLIGRAMS_PER_LITER:
|
|
57
56
|
return {MILLIGRAMS_PER_LITER: float(value) * 10.00}
|
|
58
|
-
|
|
57
|
+
if units_to == GRAMS_PER_LITER:
|
|
59
58
|
return {GRAMS_PER_LITER: float(value) / 100.00}
|
|
60
|
-
|
|
61
|
-
raise ConversionNotHandled(f"Conversion not found. Tried mg/dL to {units_to}. ")
|
|
59
|
+
raise ConversionNotHandled(f"Conversion not found. Tried mg/dL to {units_to}. ")
|
|
62
60
|
|
|
63
61
|
|
|
64
62
|
class UnitsConverter:
|
|
@@ -79,7 +77,7 @@ class UnitsConverter:
|
|
|
79
77
|
|
|
80
78
|
if label is None:
|
|
81
79
|
raise ValueError("label is required. See convert_units.")
|
|
82
|
-
|
|
80
|
+
if value is not None and units_from and units_to and units_from != units_to:
|
|
83
81
|
self.converted_value = self.get_converted_value()
|
|
84
82
|
elif units_from == units_to:
|
|
85
83
|
self.converted_value = value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from django.apps import apps as django_apps
|
|
6
6
|
|
|
@@ -10,5 +10,5 @@ if TYPE_CHECKING:
|
|
|
10
10
|
__all__ = ["grading_data_model_cls"]
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def grading_data_model_cls() ->
|
|
13
|
+
def grading_data_model_cls() -> type[GradingData]:
|
|
14
14
|
return django_apps.get_model("edc_reportable.gradingdata")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from django.apps import apps as django_apps
|
|
6
6
|
|
|
@@ -10,5 +10,5 @@ if TYPE_CHECKING:
|
|
|
10
10
|
__all__ = ["grading_exception_model_cls"]
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def grading_exception_model_cls() ->
|
|
13
|
+
def grading_exception_model_cls() -> type[GradingException]:
|
|
14
14
|
return django_apps.get_model("edc_reportable.gradingexception")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from django.apps import apps as django_apps
|
|
6
6
|
|
|
@@ -8,5 +8,5 @@ if TYPE_CHECKING:
|
|
|
8
8
|
from edc_reportable.models import MolecularWeight
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def molecular_weight_model_cls() ->
|
|
11
|
+
def molecular_weight_model_cls() -> type[MolecularWeight]:
|
|
12
12
|
return django_apps.get_model("edc_reportable", "MolecularWeight")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from django.apps import apps as django_apps
|
|
6
6
|
|
|
@@ -11,5 +11,5 @@ if TYPE_CHECKING:
|
|
|
11
11
|
__all__ = ["normal_data_model_cls"]
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def normal_data_model_cls() ->
|
|
14
|
+
def normal_data_model_cls() -> type[NormalData]:
|
|
15
15
|
return django_apps.get_model("edc_reportable.normaldata")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from django.apps import apps as django_apps
|
|
6
6
|
|
|
@@ -11,5 +11,5 @@ if TYPE_CHECKING:
|
|
|
11
11
|
__all__ = ["reference_range_colllection_model_cls"]
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def reference_range_colllection_model_cls() ->
|
|
14
|
+
def reference_range_colllection_model_cls() -> type[ReferenceRangeCollection]:
|
|
15
15
|
return django_apps.get_model("edc_reportable.referencerangecollection")
|
edc_screening/age_evaluator.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
from dateutil.relativedelta import relativedelta
|
|
4
2
|
from django.utils.timezone import localtime
|
|
5
3
|
|
|
@@ -10,10 +8,10 @@ from edc_utils.date import get_utcnow
|
|
|
10
8
|
|
|
11
9
|
class AgeEvaluator(ReportableAgeEvaluator):
|
|
12
10
|
def __init__(self, **kwargs) -> None:
|
|
13
|
-
self.reasons_ineligible:
|
|
11
|
+
self.reasons_ineligible: str | None = None
|
|
14
12
|
super().__init__(**kwargs)
|
|
15
13
|
|
|
16
|
-
def eligible(self, age:
|
|
14
|
+
def eligible(self, age: int | None = None) -> bool:
|
|
17
15
|
self.reasons_ineligible = None
|
|
18
16
|
eligible = False
|
|
19
17
|
if age:
|
edc_screening/eligibility.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from django.apps import apps as django_apps
|
|
6
6
|
from django.core.exceptions import ObjectDoesNotExist
|
|
@@ -33,7 +33,7 @@ class SubjectScreeningFormValidatorMixin:
|
|
|
33
33
|
return get_subject_screening_model()
|
|
34
34
|
|
|
35
35
|
@property
|
|
36
|
-
def subject_screening_model_cls(self) ->
|
|
36
|
+
def subject_screening_model_cls(self) -> type[ScreeningModelMixin]:
|
|
37
37
|
return django_apps.get_model(self.subject_screening_model)
|
|
38
38
|
|
|
39
39
|
@property
|
|
@@ -12,7 +12,7 @@ class ScreeningMethodsModeMixin(models.Model):
|
|
|
12
12
|
return f"{self.screening_identifier} {self.gender} {self.age_in_years}"
|
|
13
13
|
|
|
14
14
|
def natural_key(self: SubjectScreeningModelStub):
|
|
15
|
-
return (self.screening_identifier,)
|
|
15
|
+
return (self.screening_identifier,)
|
|
16
16
|
|
|
17
17
|
@staticmethod
|
|
18
18
|
def get_search_slug_fields():
|
|
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
|
|
|
20
20
|
|
|
21
21
|
from .model_mixins import EligibilityModelMixin, ScreeningModelMixin
|
|
22
22
|
|
|
23
|
-
class SubjectScreeningModel(ScreeningModelMixin, BaseUuidModel): ...
|
|
23
|
+
class SubjectScreeningModel(ScreeningModelMixin, BaseUuidModel): ...
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
__all__ = ["ScreeningEligibility"]
|
edc_screening/utils.py
CHANGED
|
@@ -26,7 +26,7 @@ def get_subject_screening_app_label() -> str:
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def get_subject_screening_model() -> str:
|
|
29
|
-
return
|
|
29
|
+
return settings.SUBJECT_SCREENING_MODEL
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def get_subject_screening_model_cls() -> Any:
|
|
@@ -74,11 +74,9 @@ def get_subject_screening_or_raise(
|
|
|
74
74
|
except ObjectDoesNotExist as e:
|
|
75
75
|
if is_modelform:
|
|
76
76
|
raise forms.ValidationError("Not allowed. Screening form not found.")
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
"Perhaps catch this in the form."
|
|
81
|
-
)
|
|
77
|
+
raise ObjectDoesNotExist(
|
|
78
|
+
f"{e} screening_identifier={screening_identifier}. Perhaps catch this in the form."
|
|
79
|
+
)
|
|
82
80
|
return subject_screening
|
|
83
81
|
|
|
84
82
|
|
edc_search/model_mixins.py
CHANGED
edc_search/search_slug.py
CHANGED
|
@@ -37,9 +37,7 @@ class SearchSlug:
|
|
|
37
37
|
slugs = [slugify(item or "") for item in values]
|
|
38
38
|
slug = SEARCH_SLUG_SEP.join(slugs)
|
|
39
39
|
if len(slug) > 250:
|
|
40
|
-
self.warning =
|
|
41
|
-
f"Warning! Search slug string exceeds 250 chars. See {repr(obj)}\n"
|
|
42
|
-
)
|
|
40
|
+
self.warning = f"Warning! Search slug string exceeds 250 chars. See {obj!r}\n"
|
|
43
41
|
sys.stdout.write(style.WARNING(self.warning))
|
|
44
42
|
self.slug = slug[:250]
|
|
45
43
|
|
edc_search/updater.py
CHANGED
|
@@ -23,7 +23,7 @@ class SearchSlugUpdater:
|
|
|
23
23
|
def __init__(self, fields: list[str], model_obj: Model | SearchSlugModelMixin = None):
|
|
24
24
|
if len(fields) > len(list(set(fields))):
|
|
25
25
|
raise SearchSlugDuplicateFields(
|
|
26
|
-
f"Duplicate search slug fields detected. Got {fields}.
|
|
26
|
+
f"Duplicate search slug fields detected. Got {fields}. See {self!r}"
|
|
27
27
|
)
|
|
28
28
|
search_slug = self.search_slug_cls(obj=model_obj, fields=fields)
|
|
29
29
|
self.warning = search_slug.warning
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import collections
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
from django.contrib import admin
|
|
7
7
|
from django.contrib.auth import get_permission_codename
|
|
@@ -68,7 +68,7 @@ class SiteModelAdminMixin:
|
|
|
68
68
|
return obj.site.name
|
|
69
69
|
return f"{site_profile.site.id} {site_profile.description}"
|
|
70
70
|
|
|
71
|
-
def get_list_filter(self, request) -> tuple[str |
|
|
71
|
+
def get_list_filter(self, request) -> tuple[str | type[SimpleListFilter], ...]:
|
|
72
72
|
"""Insert `SiteListFilter` before field name `created`.
|
|
73
73
|
|
|
74
74
|
Remove site from the list if user does not have access
|
|
@@ -36,7 +36,6 @@ class SiteModelMixin(models.Model):
|
|
|
36
36
|
pass
|
|
37
37
|
else:
|
|
38
38
|
self.validate_site_against_current()
|
|
39
|
-
return None
|
|
40
39
|
|
|
41
40
|
def get_site_on_create(self) -> Site:
|
|
42
41
|
"""Returns a site model instance.
|
|
@@ -65,7 +64,7 @@ class SiteModelMixin(models.Model):
|
|
|
65
64
|
|
|
66
65
|
def validate_site_against_current(self) -> None:
|
|
67
66
|
"""Validate existing site instance matches current_site."""
|
|
68
|
-
return
|
|
67
|
+
return
|
|
69
68
|
|
|
70
69
|
class Meta:
|
|
71
70
|
abstract = True
|
edc_sites/modelform_mixins.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from django import forms
|
|
6
6
|
from django.apps import apps as django_apps
|
|
@@ -32,7 +32,7 @@ class SiteModelFormMixin:
|
|
|
32
32
|
return cleaned_data
|
|
33
33
|
|
|
34
34
|
@property
|
|
35
|
-
def site_model_cls(self) ->
|
|
35
|
+
def site_model_cls(self) -> type[Site]:
|
|
36
36
|
return django_apps.get_model("sites.site")
|
|
37
37
|
|
|
38
38
|
@property
|