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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
from django.apps import apps as django_apps
|
|
6
6
|
from django.core.exceptions import ObjectDoesNotExist
|
|
@@ -32,7 +32,7 @@ class SourceModelMetadataMixin:
|
|
|
32
32
|
return self._source_model
|
|
33
33
|
|
|
34
34
|
@property
|
|
35
|
-
def source_model_cls(self) ->
|
|
35
|
+
def source_model_cls(self) -> type[CrfModelMixin]:
|
|
36
36
|
return django_apps.get_model(self.source_model)
|
|
37
37
|
|
|
38
38
|
@property
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Self
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Self
|
|
4
4
|
|
|
5
5
|
from edc_visit_schedule.visit import CrfCollection
|
|
6
6
|
|
|
@@ -52,7 +52,7 @@ class CrfRuleGroup(RuleGroup, metaclass=RuleGroupMetaclass):
|
|
|
52
52
|
cls: Any,
|
|
53
53
|
related_visit: RelatedVisitModel = None,
|
|
54
54
|
allow_create: bool | None = None,
|
|
55
|
-
) ->
|
|
55
|
+
) -> tuple[dict[str, dict[str, dict]], dict[str, CrfMetadata]]:
|
|
56
56
|
rule_results = {}
|
|
57
57
|
metadata_objects = {}
|
|
58
58
|
for rule in cls._meta.options.get("rules"):
|
|
@@ -70,9 +70,7 @@ class CrfRuleGroup(RuleGroup, metaclass=RuleGroupMetaclass):
|
|
|
70
70
|
f"Target model and visit model are the same! "
|
|
71
71
|
f"Got {target_model}=={related_visit._meta.label_lower}"
|
|
72
72
|
)
|
|
73
|
-
|
|
74
|
-
target_model.split(".")[1] == related_visit._meta.label_lower.split(".")[1]
|
|
75
|
-
):
|
|
73
|
+
if target_model.split(".")[1] == related_visit._meta.label_lower.split(".")[1]:
|
|
76
74
|
raise TargetModelConflict(
|
|
77
75
|
f"Target model and visit model might be the same. "
|
|
78
76
|
f"Got {target_model}~={related_visit._meta.label_lower}"
|
|
@@ -33,7 +33,7 @@ class Logic:
|
|
|
33
33
|
alternative: str = None,
|
|
34
34
|
comment: str | None = None,
|
|
35
35
|
) -> None:
|
|
36
|
-
if not
|
|
36
|
+
if not callable(predicate):
|
|
37
37
|
raise RuleLogicError(
|
|
38
38
|
"Predicate must be a callable. For example a "
|
|
39
39
|
'predicate class such as "P" or "PF"'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any
|
|
1
|
+
from typing import Any
|
|
2
2
|
|
|
3
3
|
from ...constants import REQUISITION
|
|
4
4
|
from ..rule import Rule
|
|
@@ -10,7 +10,7 @@ class RequisitionRuleEvaluatorError(Exception):
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class RequisitionRuleEvaluator(RuleEvaluator):
|
|
13
|
-
def __init__(self, source_panel:
|
|
13
|
+
def __init__(self, source_panel: Any | None = None, **kwargs) -> None:
|
|
14
14
|
self.source_panel = source_panel
|
|
15
15
|
super().__init__(**kwargs)
|
|
16
16
|
|
|
@@ -20,8 +20,8 @@ class RequisitionRule(Rule):
|
|
|
20
20
|
|
|
21
21
|
def __init__(
|
|
22
22
|
self,
|
|
23
|
-
source_panel:
|
|
24
|
-
target_panels:
|
|
23
|
+
source_panel: Any | None = None,
|
|
24
|
+
target_panels: list | None = None,
|
|
25
25
|
**kwargs,
|
|
26
26
|
) -> None:
|
|
27
27
|
self.metadata_category = REQUISITION
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections import namedtuple
|
|
4
|
-
from typing import TYPE_CHECKING, Any
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
5
|
|
|
6
6
|
from django.core.exceptions import ValidationError
|
|
7
7
|
|
|
@@ -97,7 +97,7 @@ class RequisitionRuleGroup(RuleGroup, metaclass=RequisitionMetaclass):
|
|
|
97
97
|
cls: Any,
|
|
98
98
|
related_visit: RelatedVisitModel = None,
|
|
99
99
|
allow_create: bool | None = None,
|
|
100
|
-
) ->
|
|
100
|
+
) -> tuple[dict[str, dict[str, list[RuleResult]]], dict[str, RequisitionMetadata]]:
|
|
101
101
|
"""Returns a tuple of (rule_results, metadata_objects) where
|
|
102
102
|
rule_results ...
|
|
103
103
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
from django.conf import settings
|
|
6
6
|
from django.core.exceptions import ObjectDoesNotExist
|
|
@@ -57,12 +57,11 @@ class RuleEvaluator:
|
|
|
57
57
|
if predicate:
|
|
58
58
|
if self.logic.consequence != DO_NOTHING:
|
|
59
59
|
self.result = self.logic.consequence
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
self.result = self.logic.alternative
|
|
60
|
+
elif self.logic.alternative != DO_NOTHING:
|
|
61
|
+
self.result = self.logic.alternative
|
|
63
62
|
|
|
64
63
|
@property
|
|
65
|
-
def registered_subject_model(self) ->
|
|
64
|
+
def registered_subject_model(self) -> type[RegisteredSubject]:
|
|
66
65
|
return get_registered_subject_model_cls()
|
|
67
66
|
|
|
68
67
|
@property
|
|
@@ -75,7 +74,7 @@ class RuleEvaluator:
|
|
|
75
74
|
)
|
|
76
75
|
except ObjectDoesNotExist as e:
|
|
77
76
|
raise RuleEvaluatorRegisterSubjectError(
|
|
78
|
-
f"Registered subject required for rule {
|
|
77
|
+
f"Registered subject required for rule {self!r}. "
|
|
79
78
|
f"subject_identifier='{self.related_visit.subject_identifier}'. "
|
|
80
79
|
f"Got {e}."
|
|
81
80
|
)
|
|
@@ -70,10 +70,9 @@ class RuleGroupMetaclass(type):
|
|
|
70
70
|
raise RuleGroupError(
|
|
71
71
|
"RuleGroup Meta attr `predicates` may not be `None` if a "
|
|
72
72
|
"rule.predicate in the RuleGroup is a string. "
|
|
73
|
-
f
|
|
73
|
+
f"See {attrs.get('__qualname__')}."
|
|
74
74
|
)
|
|
75
|
-
|
|
76
|
-
rule.predicate = getattr(meta.predicates, rule.predicate)
|
|
75
|
+
rule.predicate = getattr(meta.predicates, rule.predicate)
|
|
77
76
|
for k, v in meta.options.items():
|
|
78
77
|
setattr(rule, k, v)
|
|
79
78
|
rule.target_models = mcs.__get_target_models(rule, meta)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import sys
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
from django.apps import apps as django_apps
|
|
6
6
|
from django.core.management.color import color_style
|
|
@@ -23,14 +23,14 @@ class SiteMetadataRules:
|
|
|
23
23
|
def __init__(self) -> None:
|
|
24
24
|
self.registry = {}
|
|
25
25
|
|
|
26
|
-
def register(self, rule_group_cls:
|
|
26
|
+
def register(self, rule_group_cls: Any | None = None) -> None:
|
|
27
27
|
"""Register MetadataRules to a list per app_label
|
|
28
28
|
for the module the rule groups were declared in.
|
|
29
29
|
"""
|
|
30
30
|
if rule_group_cls:
|
|
31
31
|
if not rule_group_cls._meta.options.get("rules"):
|
|
32
32
|
raise SiteMetadataNoRulesError(
|
|
33
|
-
f"The metadata rule group {rule_group_cls.name}
|
|
33
|
+
f"The metadata rule group {rule_group_cls.name} has no rule!"
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
if rule_group_cls._meta.app_label not in self.registry:
|
|
@@ -39,8 +39,7 @@ class SiteMetadataRules:
|
|
|
39
39
|
for rgroup in self.registry.get(rule_group_cls._meta.app_label):
|
|
40
40
|
if rgroup.name == rule_group_cls.name:
|
|
41
41
|
raise SiteMetadataRulesAlreadyRegistered(
|
|
42
|
-
f"The metadata rule group {rule_group_cls.name} "
|
|
43
|
-
f"is already registered"
|
|
42
|
+
f"The metadata rule group {rule_group_cls.name} is already registered"
|
|
44
43
|
)
|
|
45
44
|
self.registry.get(rule_group_cls._meta.app_label).append(rule_group_cls)
|
|
46
45
|
|
|
@@ -51,11 +50,11 @@ class SiteMetadataRules:
|
|
|
51
50
|
def validate(self) -> None:
|
|
52
51
|
for rule_groups in self.registry.values():
|
|
53
52
|
for rule_group in rule_groups:
|
|
54
|
-
sys.stdout.write(f"{
|
|
53
|
+
sys.stdout.write(f"{rule_group!r}\n")
|
|
55
54
|
rule_group.validate()
|
|
56
55
|
|
|
57
56
|
@staticmethod
|
|
58
|
-
def autodiscover(module_name:
|
|
57
|
+
def autodiscover(module_name: str | None = None) -> None:
|
|
59
58
|
"""Autodiscovers rules in the metadata_rules.py file
|
|
60
59
|
of any INSTALLED_APP.
|
|
61
60
|
"""
|
edc_metadata/metadata_updater.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 .constants import CRF, KEYED
|
|
6
6
|
from .metadata_handler import MetadataHandler
|
|
@@ -25,7 +25,7 @@ class MetadataUpdater(SourceModelMetadataMixin):
|
|
|
25
25
|
the related_visit, source model name and desired entry status.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
metadata_handler_cls:
|
|
28
|
+
metadata_handler_cls: type[MetadataHandler] = MetadataHandler
|
|
29
29
|
metadata_category: str = CRF
|
|
30
30
|
metadata_model: str = "edc_metadata.crfmetadata"
|
|
31
31
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
from django.apps import apps as django_apps
|
|
6
6
|
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
|
@@ -41,7 +41,7 @@ class MetadataWrapper:
|
|
|
41
41
|
f"Visit code mismatch. Visit is {self.visit.visit_code}."
|
|
42
42
|
f"{self.visit.visit_code_sequence} but metadata object has "
|
|
43
43
|
f"{self.metadata_obj.visit_code}."
|
|
44
|
-
f"{self.metadata_obj.visit_code_sequence}. Got {
|
|
44
|
+
f"{self.metadata_obj.visit_code_sequence}. Got {metadata_obj!r}."
|
|
45
45
|
)
|
|
46
46
|
|
|
47
47
|
def __repr__(self) -> str:
|
|
@@ -59,7 +59,7 @@ class MetadataWrapper:
|
|
|
59
59
|
self._source_model_obj = self.source_model_cls.objects.get(**self.options)
|
|
60
60
|
except AttributeError as e:
|
|
61
61
|
if "related_visit_model_attr" not in str(e):
|
|
62
|
-
raise ImproperlyConfigured(f"{e} See {
|
|
62
|
+
raise ImproperlyConfigured(f"{e} See {self.source_model_cls!r}")
|
|
63
63
|
except ObjectDoesNotExist:
|
|
64
64
|
self._source_model_obj = None
|
|
65
65
|
return self._source_model_obj
|
|
@@ -69,6 +69,6 @@ class MetadataWrapper:
|
|
|
69
69
|
self._source_model_obj = value
|
|
70
70
|
|
|
71
71
|
@property
|
|
72
|
-
def source_model_cls(self) ->
|
|
72
|
+
def source_model_cls(self) -> type[CrfModelMixin]:
|
|
73
73
|
"""Returns a CRF model class"""
|
|
74
74
|
return django_apps.get_model(self.metadata_obj.model)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
from django.db import models, transaction
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@ if TYPE_CHECKING:
|
|
|
19
19
|
from edc_visit_tracking.typing_stubs import RelatedVisitProtocol
|
|
20
20
|
else:
|
|
21
21
|
|
|
22
|
-
class RelatedVisitProtocol: ...
|
|
22
|
+
class RelatedVisitProtocol: ...
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class CreatesMetadataModelMixin(RelatedVisitProtocol, models.Model):
|
|
@@ -27,9 +27,9 @@ class CreatesMetadataModelMixin(RelatedVisitProtocol, models.Model):
|
|
|
27
27
|
create metadata on save.
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
|
-
metadata_cls:
|
|
31
|
-
metadata_destroyer_cls:
|
|
32
|
-
metadata_rule_evaluator_cls:
|
|
30
|
+
metadata_cls: type[Metadata] = Metadata
|
|
31
|
+
metadata_destroyer_cls: type[Destroyer] = Destroyer
|
|
32
|
+
metadata_rule_evaluator_cls: type[MetadataRuleEvaluator] = MetadataRuleEvaluator
|
|
33
33
|
|
|
34
34
|
def metadata_create(self) -> None:
|
|
35
35
|
"""Creates metadata, called by post_save signal."""
|
|
@@ -96,8 +96,7 @@ class CreatesMetadataModelMixin(RelatedVisitProtocol, models.Model):
|
|
|
96
96
|
for key in [CRF, REQUISITION]:
|
|
97
97
|
if [obj for obj in self.metadata[key] if obj.get_entry_status() == KEYED]:
|
|
98
98
|
raise DeleteMetadataError(
|
|
99
|
-
f"Metadata cannot be deleted. {key}s have been "
|
|
100
|
-
f"keyed. Got {repr(self)}."
|
|
99
|
+
f"Metadata cannot be deleted. {key}s have been keyed. Got {self!r}."
|
|
101
100
|
)
|
|
102
101
|
destroyer = self.metadata_destroyer_cls(related_visit=self)
|
|
103
102
|
destroyer.delete(entry_status_not_in=[KEYED])
|
|
@@ -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.db import models
|
|
@@ -44,7 +44,7 @@ class UpdatesCrfMetadataModelMixin(UpdatesMetadataModelMixin):
|
|
|
44
44
|
return super().metadata_query_options
|
|
45
45
|
|
|
46
46
|
@property
|
|
47
|
-
def metadata_model(self: CrfModel) ->
|
|
47
|
+
def metadata_model(self: CrfModel) -> type[CrfMetadata]:
|
|
48
48
|
"""Returns the metadata model associated with self."""
|
|
49
49
|
metadata_model = "edc_metadata.crfmetadata"
|
|
50
50
|
return django_apps.get_model(metadata_model)
|
|
@@ -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.db import models
|
|
6
6
|
|
|
@@ -74,7 +74,7 @@ class UpdatesMetadataModelMixin(models.Model):
|
|
|
74
74
|
@property
|
|
75
75
|
def metadata_model(
|
|
76
76
|
self: CrfModel | RequisitionModel,
|
|
77
|
-
) ->
|
|
77
|
+
) -> type[CrfMetadata] | type[RequisitionMetadata]:
|
|
78
78
|
"""Returns the metadata model associated with self.
|
|
79
79
|
|
|
80
80
|
Override
|
|
@@ -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.db import models
|
|
@@ -68,7 +68,7 @@ class UpdatesRequisitionMetadataModelMixin(UpdatesMetadataModelMixin):
|
|
|
68
68
|
return REQUIRED if requisition.required else NOT_REQUIRED
|
|
69
69
|
|
|
70
70
|
@property
|
|
71
|
-
def metadata_model(self: RequisitionModel) ->
|
|
71
|
+
def metadata_model(self: RequisitionModel) -> type[RequisitionMetadata]:
|
|
72
72
|
"""Returns the metadata model associated with self."""
|
|
73
73
|
metadata_model = "edc_metadata.requisitionmetadata"
|
|
74
74
|
return django_apps.get_model(metadata_model)
|
|
@@ -57,33 +57,31 @@ class CrfMetadata(CrfMetadataModelMixin, BaseUuidModel):
|
|
|
57
57
|
)
|
|
58
58
|
]
|
|
59
59
|
indexes = (
|
|
60
|
-
CrfMetadataModelMixin.Meta.indexes
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
),
|
|
88
|
-
]
|
|
60
|
+
*CrfMetadataModelMixin.Meta.indexes,
|
|
61
|
+
*BaseUuidModel.Meta.indexes,
|
|
62
|
+
models.Index(
|
|
63
|
+
fields=[
|
|
64
|
+
"site",
|
|
65
|
+
"entry_status",
|
|
66
|
+
"visit_code",
|
|
67
|
+
"visit_code_sequence",
|
|
68
|
+
"model",
|
|
69
|
+
"subject_identifier",
|
|
70
|
+
"schedule_name",
|
|
71
|
+
"visit_schedule_name",
|
|
72
|
+
],
|
|
73
|
+
),
|
|
74
|
+
models.Index(
|
|
75
|
+
fields=[
|
|
76
|
+
"subject_identifier",
|
|
77
|
+
"visit_schedule_name",
|
|
78
|
+
"schedule_name",
|
|
79
|
+
"visit_code",
|
|
80
|
+
"visit_code_sequence",
|
|
81
|
+
"model",
|
|
82
|
+
"entry_status",
|
|
83
|
+
"timepoint",
|
|
84
|
+
"show_order",
|
|
85
|
+
],
|
|
86
|
+
),
|
|
89
87
|
)
|
|
@@ -48,7 +48,7 @@ class CrfMetadataModelMixin(
|
|
|
48
48
|
|
|
49
49
|
report_datetime = models.DateTimeField(null=True, blank=True)
|
|
50
50
|
|
|
51
|
-
entry_comment = models.TextField(max_length=250,
|
|
51
|
+
entry_comment = models.TextField(max_length=250, default="", blank=True)
|
|
52
52
|
|
|
53
53
|
close_datetime = models.DateTimeField(null=True, blank=True)
|
|
54
54
|
|
|
@@ -86,35 +86,33 @@ class RequisitionMetadata(CrfMetadataModelMixin, BaseUuidModel):
|
|
|
86
86
|
)
|
|
87
87
|
]
|
|
88
88
|
indexes = (
|
|
89
|
-
CrfMetadataModelMixin.Meta.indexes
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
),
|
|
119
|
-
]
|
|
89
|
+
*CrfMetadataModelMixin.Meta.indexes,
|
|
90
|
+
*BaseUuidModel.Meta.indexes,
|
|
91
|
+
models.Index(
|
|
92
|
+
fields=[
|
|
93
|
+
"site",
|
|
94
|
+
"entry_status",
|
|
95
|
+
"visit_code",
|
|
96
|
+
"visit_code_sequence",
|
|
97
|
+
"model",
|
|
98
|
+
"panel_name",
|
|
99
|
+
"subject_identifier",
|
|
100
|
+
"schedule_name",
|
|
101
|
+
"visit_schedule_name",
|
|
102
|
+
],
|
|
103
|
+
),
|
|
104
|
+
models.Index(
|
|
105
|
+
fields=[
|
|
106
|
+
"subject_identifier",
|
|
107
|
+
"visit_schedule_name",
|
|
108
|
+
"schedule_name",
|
|
109
|
+
"visit_code",
|
|
110
|
+
"visit_code_sequence",
|
|
111
|
+
"model",
|
|
112
|
+
"panel_name",
|
|
113
|
+
"entry_status",
|
|
114
|
+
"timepoint",
|
|
115
|
+
"show_order",
|
|
116
|
+
],
|
|
117
|
+
),
|
|
120
118
|
)
|
edc_metadata/stubs.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any, Protocol
|
|
1
|
+
from typing import Any, Protocol
|
|
2
2
|
|
|
3
3
|
from django.db.models import Manager, Model, QuerySet
|
|
4
4
|
|
|
@@ -28,11 +28,11 @@ class VisitModel(Protocol):
|
|
|
28
28
|
visit_schedule_name: str
|
|
29
29
|
_meta: ModelMetaStub
|
|
30
30
|
|
|
31
|
-
def visit_schedule(self) -> VisitSchedule: ...
|
|
31
|
+
def visit_schedule(self) -> VisitSchedule: ...
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
class CrfMetadataModelStub(Protocol):
|
|
35
|
-
updater_cls =
|
|
35
|
+
updater_cls = type["CrfMetadataUpdaterStub"]
|
|
36
36
|
entry_status: str
|
|
37
37
|
metadata_query_options: dict
|
|
38
38
|
model: str
|
|
@@ -45,13 +45,13 @@ class CrfMetadataModelStub(Protocol):
|
|
|
45
45
|
visit: VisitModel
|
|
46
46
|
_meta: ModelMetaStub
|
|
47
47
|
|
|
48
|
-
def save(self, *args, **kwargs) -> None: ...
|
|
48
|
+
def save(self, *args, **kwargs) -> None: ...
|
|
49
49
|
|
|
50
|
-
def delete(self) -> int: ...
|
|
50
|
+
def delete(self) -> int: ...
|
|
51
51
|
|
|
52
|
-
def metadata_visit_object(self) -> Visit: ...
|
|
52
|
+
def metadata_visit_object(self) -> Visit: ...
|
|
53
53
|
|
|
54
|
-
def refresh_from_db(self) -> None: ...
|
|
54
|
+
def refresh_from_db(self) -> None: ...
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
class PanelStub(Protocol):
|
|
@@ -59,7 +59,7 @@ class PanelStub(Protocol):
|
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
class RequisitionMetadataModelStub(Protocol):
|
|
62
|
-
updater_cls =
|
|
62
|
+
updater_cls = type["RequisitionMetadataUpdaterStub"]
|
|
63
63
|
entry_status: str
|
|
64
64
|
metadata_query_options: dict
|
|
65
65
|
model: str
|
|
@@ -73,13 +73,13 @@ class RequisitionMetadataModelStub(Protocol):
|
|
|
73
73
|
visit: VisitModel
|
|
74
74
|
_meta: ModelMetaStub
|
|
75
75
|
|
|
76
|
-
def save(self, *args, **kwargs) -> None: ...
|
|
76
|
+
def save(self, *args, **kwargs) -> None: ...
|
|
77
77
|
|
|
78
78
|
def delete(self) -> int: ...
|
|
79
79
|
|
|
80
|
-
def metadata_visit_object(self) -> Visit: ...
|
|
80
|
+
def metadata_visit_object(self) -> Visit: ...
|
|
81
81
|
|
|
82
|
-
def metadata_updater_cls(self, **opts: dict): ...
|
|
82
|
+
def metadata_updater_cls(self, **opts: dict): ...
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
class MetadataGetterStub(Protocol):
|
|
@@ -87,23 +87,23 @@ class MetadataGetterStub(Protocol):
|
|
|
87
87
|
visit: RelatedVisitModelStub | None
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
class CrfMetadataUpdaterStub(Protocol): ...
|
|
90
|
+
class CrfMetadataUpdaterStub(Protocol): ...
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
class RequisitionMetadataUpdaterStub(Protocol): ...
|
|
93
|
+
class RequisitionMetadataUpdaterStub(Protocol): ...
|
|
94
94
|
|
|
95
95
|
|
|
96
|
-
class RequisitionMetadataGetterStub(MetadataGetterStub, Protocol): ...
|
|
96
|
+
class RequisitionMetadataGetterStub(MetadataGetterStub, Protocol): ...
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
class MetadataWrapperStub(Protocol):
|
|
100
100
|
options: dict
|
|
101
101
|
model_obj: CrfMetadataModelStub
|
|
102
|
-
model_cls:
|
|
103
|
-
...
|
|
102
|
+
model_cls: type[CrfMetadataModelStub]
|
|
103
|
+
...
|
|
104
104
|
|
|
105
105
|
|
|
106
|
-
class RequisitionMetadataWrapperStub(MetadataWrapperStub, Protocol): ...
|
|
106
|
+
class RequisitionMetadataWrapperStub(MetadataWrapperStub, Protocol): ...
|
|
107
107
|
|
|
108
108
|
|
|
109
109
|
class Predicate(Protocol):
|
edc_metadata/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.apps import apps as django_apps
|
|
6
6
|
from django.conf import settings
|
|
@@ -43,17 +43,17 @@ class HasKeyedMetadata(Exception):
|
|
|
43
43
|
pass
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def get_crf_metadata_model_cls() ->
|
|
46
|
+
def get_crf_metadata_model_cls() -> type[CrfMetadata]:
|
|
47
47
|
return django_apps.get_model("edc_metadata.crfmetadata")
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
def get_requisition_metadata_model_cls() ->
|
|
50
|
+
def get_requisition_metadata_model_cls() -> type[RequisitionMetadata]:
|
|
51
51
|
return django_apps.get_model("edc_metadata.requisitionmetadata")
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
def get_metadata_model_cls(
|
|
55
55
|
metadata_category: str,
|
|
56
|
-
) ->
|
|
56
|
+
) -> type[CrfMetadata] | type[RequisitionMetadata]:
|
|
57
57
|
if metadata_category == CRF:
|
|
58
58
|
model_cls = get_crf_metadata_model_cls()
|
|
59
59
|
elif metadata_category == REQUISITION:
|
edc_model/__init__.py
CHANGED
|
@@ -13,7 +13,7 @@ class SerializableModel(models.Model):
|
|
|
13
13
|
objects = SerializableModelManager()
|
|
14
14
|
|
|
15
15
|
def natural_key(self) -> tuple:
|
|
16
|
-
return (self.history_id,)
|
|
16
|
+
return (self.history_id,)
|
|
17
17
|
|
|
18
18
|
def related_visit_model_attr(self):
|
|
19
19
|
try:
|
|
@@ -37,7 +37,7 @@ class SerializableCrfModel(models.Model):
|
|
|
37
37
|
return NotImplemented(self)
|
|
38
38
|
|
|
39
39
|
def natural_key(self) -> tuple:
|
|
40
|
-
return (self.history_id,)
|
|
40
|
+
return (self.history_id,)
|
|
41
41
|
|
|
42
42
|
class Meta:
|
|
43
43
|
abstract = True
|
edc_model/models/signals.py
CHANGED
|
@@ -16,7 +16,7 @@ def remove_f_expressions(sender, instance, history_instance, **kwargs) -> None:
|
|
|
16
16
|
django-simple-history-by-overriding-save/62369328#62369328
|
|
17
17
|
"""
|
|
18
18
|
f_expression_fields = []
|
|
19
|
-
for field in history_instance._meta.fields:
|
|
19
|
+
for field in history_instance._meta.fields:
|
|
20
20
|
field_value = getattr(history_instance, field.name)
|
|
21
21
|
if isinstance(field_value, expressions.BaseExpression):
|
|
22
22
|
f_expression_fields.append(field.name)
|