canvas 0.8.0__tar.gz → 0.8.1__tar.gz
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 canvas might be problematic. Click here for more details.
- {canvas-0.8.0 → canvas-0.8.1}/PKG-INFO +2 -2
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/auth/tests.py +10 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/emit.py +0 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/logs/logs.py +4 -4
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/plugin/plugin.py +55 -43
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/plugin/tests.py +4 -2
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/conftest.py +1 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/main.py +1 -2
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/protocols/my_protocol.py +1 -2
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/tests.py +36 -26
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/context/context.py +4 -2
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/context/tests.py +1 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/print/tests.py +2 -2
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/validators/tests.py +2 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/base.py +1 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/base.py +4 -6
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/prescribe.py +3 -3
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/reason_for_visit.py +1 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/task.py +3 -2
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/vitals.py +0 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/constants.py +3 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/tests/protocol/tests.py +6 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/tests/schema/tests.py +5 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/tests/test_utils.py +27 -12
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/tests/unit/tests.py +3 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/__init__.py +2 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/banner_alert/__init__.py +2 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/banner_alert/tests.py +22 -14
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/protocol_card/__init__.py +2 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/protocol_card/tests.py +10 -6
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/events/__init__.py +2 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/handlers/__init__.py +2 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/protocols/__init__.py +2 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/protocols/base.py +0 -2
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/protocols/clinical_quality_measure.py +2 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/utils/http.py +2 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/utils/tests.py +4 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/__init__.py +13 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/allergy_intolerance.py +0 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/base.py +5 -5
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/billing.py +2 -2
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/common.py +0 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/patient.py +1 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/questionnaire.py +2 -1
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/custom.py +0 -10
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/tests/test_value_sets.py +4 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/individual_characteristic.py +12 -6
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/procedure.py +4 -2
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/value_set.py +1 -1
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/plugin_runner.py +4 -3
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/sandbox.py +6 -8
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/test_plugin_runner.py +1 -2
- {canvas-0.8.0 → canvas-0.8.1}/pyproject.toml +30 -13
- {canvas-0.8.0 → canvas-0.8.1}/settings.py +3 -1
- {canvas-0.8.0 → canvas-0.8.1}/README.md +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/auth/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/auth/utils.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ALLERGY_INTOLERANCE_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ALLERGY_INTOLERANCE_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/APPOINTMENT_CANCELED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/APPOINTMENT_CHECKED_IN.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/APPOINTMENT_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/APPOINTMENT_NO_SHOWED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/APPOINTMENT_RESCHEDULED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/APPOINTMENT_RESTORED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/APPOINTMENT_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__CONDITION_SELECTED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__POST_COMMIT.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__POST_ORIGINATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__POST_UPDATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__PRE_COMMIT.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__PRE_ORIGINATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__PRE_UPDATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/BILLING_LINE_ITEM_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/BILLING_LINE_ITEM_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/CONDITION_ASSESSED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/CONDITION_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/CONDITION_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/CRON.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ENCOUNTER_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/ENCOUNTER_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/IMMUNIZATION_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/IMMUNIZATION_STATEMENT_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/IMMUNIZATION_STATEMENT_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/IMMUNIZATION_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/INTERVIEW_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/INTERVIEW_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/LAB_ORDER_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/LAB_ORDER_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/MEDICATION_LIST_ITEM_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/MEDICATION_LIST_ITEM_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__POST_COMMIT.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__POST_ORIGINATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__POST_UPDATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__PRE_COMMIT.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__PRE_ORIGINATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__PRE_UPDATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT__MEDICATION__POST_SEARCH.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/PATIENT_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/PATIENT_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/PLAN_COMMAND__POST_ORIGINATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/PLAN_COMMAND__PRE_ORIGINATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__POST_COMMIT.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__POST_ORIGINATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__POST_UPDATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__PRE_COMMIT.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__PRE_ORIGINATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__PRE_UPDATE.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE__QUESTIONNAIRE__POST_SEARCH.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/TASK_COMMENT_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/TASK_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/TASK_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/VITAL_SIGN_CREATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/emit/event_fixtures/VITAL_SIGN_UPDATED.ndjson +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/logs/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/plugin/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/run_plugins/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/apps/run_plugins/run_plugins.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/templates/plugins/default/cookiecutter.json +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/CANVAS_MANIFEST.json +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/README.md +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/protocols/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/context/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/print/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/print/print.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/urls/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/urls/tests.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/urls/urls.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/validators/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/validators/manifest_schema.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_cli/utils/validators/validators.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/messages/effects_pb2.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/messages/effects_pb2.pyi +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/messages/effects_pb2_grpc.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/messages/events_pb2.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/messages/events_pb2.pyi +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/messages/events_pb2_grpc.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/messages/plugins_pb2.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/messages/plugins_pb2.pyi +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/messages/plugins_pb2_grpc.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/services/plugin_runner_pb2.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/services/plugin_runner_pb2.pyi +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_generated/services/plugin_runner_pb2_grpc.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/allergy.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/assess.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/close_goal.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/diagnose.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/family_history.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/goal.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/history_present_illness.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/instruct.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/lab_order.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/medical_history.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/medication_statement.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/past_surgical_history.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/perform.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/plan.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/questionnaire.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/refill.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/remove_allergy.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/stop_medication.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/update_diagnosis.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/commands/update_goal.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/tests/protocol/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/tests/schema/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/commands/tests/unit/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/banner_alert/add_banner_alert.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/banner_alert/remove_banner_alert.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/base.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/patient_chart_summary_configuration.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/protocol_card/protocol_card.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/effects/task/task.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/handlers/base.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/handlers/cron_task.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/protocols/timeframe.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/tests/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/utils/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/utils/db.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/utils/stats.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/command.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/condition.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/detected_issue.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/device.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/imaging.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/lab.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/medication.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/note.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/observation.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/protocol_override.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/staff.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/task.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/v1/data/user.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/adverse_event.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/allergy.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/assessment.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/communication.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/condition.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/device.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/diagnostic_study.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/encounter.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/immunization.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/intervention.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/laboratory_test.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/medication.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/physical_exam.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/value_set/v2022/symptom.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/canvas_sdk/views/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/logger/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/logger/logger.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/authentication.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/plugin_synchronizer.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/data/plugins/.gitkeep +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/example_plugin/CANVAS_MANIFEST.json +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/example_plugin/README.md +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/example_plugin/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/example_plugin/protocols/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/example_plugin/protocols/my_protocol.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/CANVAS_MANIFEST.json +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/README.md +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/other_module/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/other_module/base.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/protocols/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/protocols/my_protocol.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/CANVAS_MANIFEST.json +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/README.md +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/other_module/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/other_module/base.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/protocols/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/protocols/my_protocol.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/CANVAS_MANIFEST.json +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/README.md +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/other_module/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/other_module/base.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/protocols/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/protocols/my_protocol.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/CANVAS_MANIFEST.json +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/README.md +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/other_module/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/other_module/base.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/protocols/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/protocols/my_protocol.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/plugin_runner/tests/test_sandbox.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/pubsub/__init__.py +0 -0
- {canvas-0.8.0 → canvas-0.8.1}/pubsub/pubsub.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: canvas
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.1
|
|
4
4
|
Summary: SDK to customize event-driven actions in your Canvas instance
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Canvas Team
|
|
@@ -15,7 +15,7 @@ Requires-Dist: cron-converter (>=1.2.1,<2.0.0)
|
|
|
15
15
|
Requires-Dist: django (>=5.1.1,<6.0.0)
|
|
16
16
|
Requires-Dist: django-stubs[compatible-mypy] (>=5.1.1,<6.0.0)
|
|
17
17
|
Requires-Dist: django-timezone-utils (>=0.15.0,<0.16.0)
|
|
18
|
-
Requires-Dist: env-tools (>=2.
|
|
18
|
+
Requires-Dist: env-tools (>=2.4.0,<3.0.0)
|
|
19
19
|
Requires-Dist: grpcio (>=1.60.1,<2.0.0)
|
|
20
20
|
Requires-Dist: ipython (>=8.21.0,<9.0.0)
|
|
21
21
|
Requires-Dist: jsonschema (>=4.21.1,<5.0.0)
|
|
@@ -8,6 +8,8 @@ from canvas_cli.apps.auth import get_or_request_api_token
|
|
|
8
8
|
|
|
9
9
|
@pytest.fixture
|
|
10
10
|
def valid_token_response() -> Any:
|
|
11
|
+
"""Returns a valid token response."""
|
|
12
|
+
|
|
11
13
|
class TokenResponse:
|
|
12
14
|
status_code = 200
|
|
13
15
|
|
|
@@ -19,6 +21,8 @@ def valid_token_response() -> Any:
|
|
|
19
21
|
|
|
20
22
|
@pytest.fixture
|
|
21
23
|
def error_token_response() -> Any:
|
|
24
|
+
"""Returns an error token response."""
|
|
25
|
+
|
|
22
26
|
class TokenResponse:
|
|
23
27
|
status_code = 500
|
|
24
28
|
|
|
@@ -27,6 +31,8 @@ def error_token_response() -> Any:
|
|
|
27
31
|
|
|
28
32
|
@pytest.fixture
|
|
29
33
|
def expired_token_response() -> Any:
|
|
34
|
+
"""Returns an expired token response."""
|
|
35
|
+
|
|
30
36
|
class TokenResponse:
|
|
31
37
|
status_code = 200
|
|
32
38
|
|
|
@@ -45,6 +51,7 @@ def test_get_or_request_api_token_uses_stored_token(
|
|
|
45
51
|
mock_get_password: MagicMock,
|
|
46
52
|
valid_token_response: Any,
|
|
47
53
|
) -> None:
|
|
54
|
+
"""Test that get_or_request_api_token uses a stored token if it is valid."""
|
|
48
55
|
mock_is_token_valid.return_value = True
|
|
49
56
|
mock_get_password.return_value = "a-stored-valid-token"
|
|
50
57
|
mock_post.return_value = valid_token_response
|
|
@@ -66,6 +73,7 @@ def test_get_or_request_api_token_requests_token_if_none_stored(
|
|
|
66
73
|
mock_set_password: MagicMock,
|
|
67
74
|
valid_token_response: Any,
|
|
68
75
|
) -> None:
|
|
76
|
+
"""Test that get_or_request_api_token requests a new token if none is stored."""
|
|
69
77
|
mock_client_credentials.return_value = "client_id=id&client_secret=secret"
|
|
70
78
|
mock_get_password.return_value = None
|
|
71
79
|
mock_post.return_value = valid_token_response
|
|
@@ -95,6 +103,7 @@ def test_get_or_request_api_token_raises_exception_if_error_token_response(
|
|
|
95
103
|
mock_get_password: MagicMock,
|
|
96
104
|
error_token_response: Any,
|
|
97
105
|
) -> None:
|
|
106
|
+
"""Test that get_or_request_api_token raises an exception if an error token response is received."""
|
|
98
107
|
mock_client_credentials.return_value = "client_id=id&client_secret=secret"
|
|
99
108
|
mock_get_password.return_value = None
|
|
100
109
|
mock_post.return_value = error_token_response
|
|
@@ -123,6 +132,7 @@ def test_get_or_request_api_token_raises_exception_if_expired_token(
|
|
|
123
132
|
mock_get_password: MagicMock,
|
|
124
133
|
expired_token_response: Any,
|
|
125
134
|
) -> None:
|
|
135
|
+
"""Test that get_or_request_api_token raises an exception if an expired token is received."""
|
|
126
136
|
mock_client_credentials.return_value = "client_id=id&client_secret=secret"
|
|
127
137
|
mock_get_password.return_value = None
|
|
128
138
|
mock_post.return_value = expired_token_response
|
|
@@ -7,7 +7,6 @@ import grpc
|
|
|
7
7
|
import typer
|
|
8
8
|
|
|
9
9
|
from canvas_generated.messages.events_pb2 import Event as PluginRunnerEvent
|
|
10
|
-
from canvas_generated.messages.events_pb2 import EventType as PluginRunnerEventType
|
|
11
10
|
from canvas_generated.services.plugin_runner_pb2_grpc import PluginRunnerStub
|
|
12
11
|
|
|
13
12
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import cast
|
|
3
3
|
from urllib.parse import urlparse
|
|
4
4
|
|
|
5
5
|
import typer
|
|
@@ -31,9 +31,9 @@ def _on_open(ws: websocket.WebSocket) -> None:
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def logs(
|
|
34
|
-
host:
|
|
34
|
+
host: str | None = typer.Option(
|
|
35
35
|
callback=get_default_host, help="Canvas instance to connect to", default=None
|
|
36
|
-
)
|
|
36
|
+
),
|
|
37
37
|
) -> None:
|
|
38
38
|
"""Listens and prints log streams from the instance."""
|
|
39
39
|
if not host:
|
|
@@ -62,4 +62,4 @@ def logs(
|
|
|
62
62
|
ws.run_forever()
|
|
63
63
|
|
|
64
64
|
except KeyboardInterrupt:
|
|
65
|
-
raise typer.Exit(0)
|
|
65
|
+
raise typer.Exit(0) from None
|
|
@@ -2,8 +2,9 @@ import ast
|
|
|
2
2
|
import json
|
|
3
3
|
import tarfile
|
|
4
4
|
import tempfile
|
|
5
|
+
from collections.abc import Iterable
|
|
5
6
|
from pathlib import Path
|
|
6
|
-
from typing import Any,
|
|
7
|
+
from typing import Any, cast
|
|
7
8
|
from urllib.parse import urljoin
|
|
8
9
|
|
|
9
10
|
import requests
|
|
@@ -53,14 +54,15 @@ def _build_package(package: Path) -> Path:
|
|
|
53
54
|
def _get_name_from_metadata(host: str, token: str, package: Path) -> str | None:
|
|
54
55
|
"""Extract metadata from a provided package and return the package name if it exists in the metadata."""
|
|
55
56
|
try:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
with open(package) as package_file:
|
|
58
|
+
metadata_response = requests.post(
|
|
59
|
+
plugin_url(host, "extract-metadata"),
|
|
60
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
61
|
+
files={"package": package_file},
|
|
62
|
+
)
|
|
61
63
|
except requests.exceptions.RequestException:
|
|
62
64
|
print(f"Failed to connect to {host}")
|
|
63
|
-
raise typer.Exit(1)
|
|
65
|
+
raise typer.Exit(1) from None
|
|
64
66
|
|
|
65
67
|
if metadata_response.status_code != requests.codes.ok:
|
|
66
68
|
print(f"Status code {metadata_response.status_code}: {metadata_response.text}")
|
|
@@ -116,8 +118,8 @@ def _get_meta_properties(protocol_path: Path, classname: str) -> dict[str, str]:
|
|
|
116
118
|
|
|
117
119
|
|
|
118
120
|
def _get_protocols_with_new_cqm_properties(
|
|
119
|
-
protocol_classes:
|
|
120
|
-
) ->
|
|
121
|
+
protocol_classes: Iterable[dict[str, Any]], plugin: Path
|
|
122
|
+
) -> Iterable[dict[str, Any]] | None:
|
|
121
123
|
"""Extract the meta properties of any ClinicalQualityMeasure Protocols included in the plugin if they have changed."""
|
|
122
124
|
has_updates = False
|
|
123
125
|
protocol_props = []
|
|
@@ -146,14 +148,14 @@ def init() -> None:
|
|
|
146
148
|
try:
|
|
147
149
|
project_dir = cookiecutter(str(template))
|
|
148
150
|
except OutputDirExistsException:
|
|
149
|
-
raise typer.BadParameter(
|
|
151
|
+
raise typer.BadParameter("The supplied directory already exists") from None
|
|
150
152
|
|
|
151
153
|
print(f"Project created in {project_dir}")
|
|
152
154
|
|
|
153
155
|
|
|
154
156
|
def install(
|
|
155
157
|
plugin_name: Path = typer.Argument(..., help="Path to plugin to install"),
|
|
156
|
-
host:
|
|
158
|
+
host: str | None = typer.Option(
|
|
157
159
|
callback=get_default_host,
|
|
158
160
|
help="Canvas instance to connect to",
|
|
159
161
|
default=None,
|
|
@@ -181,15 +183,16 @@ def install(
|
|
|
181
183
|
print(f"Posting {built_package_path.absolute()} to {url}")
|
|
182
184
|
|
|
183
185
|
try:
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
with open(built_package_path, "rb") as package:
|
|
187
|
+
r = requests.post(
|
|
188
|
+
url,
|
|
189
|
+
data={"is_enabled": True},
|
|
190
|
+
files={"package": package},
|
|
191
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
192
|
+
)
|
|
190
193
|
except requests.exceptions.RequestException:
|
|
191
194
|
print(f"Failed to connect to {host}")
|
|
192
|
-
raise typer.Exit(1)
|
|
195
|
+
raise typer.Exit(1) from None
|
|
193
196
|
|
|
194
197
|
if r.status_code == requests.codes.created:
|
|
195
198
|
print(f"Plugin {plugin_name} successfully installed!")
|
|
@@ -207,7 +210,7 @@ def install(
|
|
|
207
210
|
|
|
208
211
|
def uninstall(
|
|
209
212
|
name: str = typer.Argument(..., help="Plugin name to uninstall"),
|
|
210
|
-
host:
|
|
213
|
+
host: str | None = typer.Option(
|
|
211
214
|
callback=get_default_host,
|
|
212
215
|
help="Canvas instance to connect to",
|
|
213
216
|
default=None,
|
|
@@ -232,7 +235,7 @@ def uninstall(
|
|
|
232
235
|
)
|
|
233
236
|
except requests.exceptions.RequestException:
|
|
234
237
|
print(f"Failed to connect to {host}")
|
|
235
|
-
raise typer.Exit(1)
|
|
238
|
+
raise typer.Exit(1) from None
|
|
236
239
|
|
|
237
240
|
if r.status_code == requests.codes.no_content:
|
|
238
241
|
print(f"Plugin {name} successfully uninstalled!")
|
|
@@ -243,7 +246,7 @@ def uninstall(
|
|
|
243
246
|
|
|
244
247
|
def enable(
|
|
245
248
|
name: str = typer.Argument(..., help="Plugin name to enable"),
|
|
246
|
-
host:
|
|
249
|
+
host: str | None = typer.Option(
|
|
247
250
|
callback=get_default_host,
|
|
248
251
|
help="Canvas instance to connect to",
|
|
249
252
|
default=None,
|
|
@@ -269,7 +272,7 @@ def enable(
|
|
|
269
272
|
)
|
|
270
273
|
except requests.exceptions.RequestException:
|
|
271
274
|
print(f"Failed to connect to {host}")
|
|
272
|
-
raise typer.Exit(1)
|
|
275
|
+
raise typer.Exit(1) from None
|
|
273
276
|
|
|
274
277
|
if r.ok:
|
|
275
278
|
print(f"Plugin {name} successfully enabled!")
|
|
@@ -280,7 +283,7 @@ def enable(
|
|
|
280
283
|
|
|
281
284
|
def disable(
|
|
282
285
|
name: str = typer.Argument(..., help="Plugin name to disable"),
|
|
283
|
-
host:
|
|
286
|
+
host: str | None = typer.Option(
|
|
284
287
|
callback=get_default_host,
|
|
285
288
|
help="Canvas instance to connect to",
|
|
286
289
|
default=None,
|
|
@@ -306,7 +309,7 @@ def disable(
|
|
|
306
309
|
)
|
|
307
310
|
except requests.exceptions.RequestException:
|
|
308
311
|
print(f"Failed to connect to {host}")
|
|
309
|
-
raise typer.Exit(1)
|
|
312
|
+
raise typer.Exit(1) from None
|
|
310
313
|
|
|
311
314
|
if r.ok:
|
|
312
315
|
print(f"Plugin {name} successfully disabled!")
|
|
@@ -316,11 +319,11 @@ def disable(
|
|
|
316
319
|
|
|
317
320
|
|
|
318
321
|
def list(
|
|
319
|
-
host:
|
|
322
|
+
host: str | None = typer.Option(
|
|
320
323
|
callback=get_default_host,
|
|
321
324
|
help="Canvas instance to connect to",
|
|
322
325
|
default=None,
|
|
323
|
-
)
|
|
326
|
+
),
|
|
324
327
|
) -> None:
|
|
325
328
|
"""List all plugins from a Canvas instance."""
|
|
326
329
|
if not host:
|
|
@@ -337,7 +340,7 @@ def list(
|
|
|
337
340
|
)
|
|
338
341
|
except requests.exceptions.RequestException:
|
|
339
342
|
print(f"Failed to connect to {host}")
|
|
340
|
-
raise typer.Exit(1)
|
|
343
|
+
raise typer.Exit(1) from None
|
|
341
344
|
|
|
342
345
|
if r.status_code == requests.codes.ok:
|
|
343
346
|
plugins = r.json().get("results", [])
|
|
@@ -382,7 +385,7 @@ def validate_manifest(
|
|
|
382
385
|
|
|
383
386
|
except json.JSONDecodeError:
|
|
384
387
|
print("There was a problem loading the manifest file, please ensure it's valid JSON")
|
|
385
|
-
raise typer.Abort()
|
|
388
|
+
raise typer.Abort() from None
|
|
386
389
|
|
|
387
390
|
validate_manifest_file(manifest_json)
|
|
388
391
|
|
|
@@ -391,14 +394,14 @@ def validate_manifest(
|
|
|
391
394
|
|
|
392
395
|
def update(
|
|
393
396
|
name: str = typer.Argument(..., help="Plugin name to update"),
|
|
394
|
-
|
|
397
|
+
package_path: Path | None = typer.Option(
|
|
395
398
|
help="Path to a wheel or sdist file containing the python package to install",
|
|
396
399
|
default=None,
|
|
397
400
|
),
|
|
398
|
-
is_enabled:
|
|
401
|
+
is_enabled: bool | None = typer.Option(
|
|
399
402
|
None, "--enable/--disable", show_default=False, help="Enable/disable the plugin"
|
|
400
403
|
),
|
|
401
|
-
host:
|
|
404
|
+
host: str | None = typer.Option(
|
|
402
405
|
callback=get_default_host,
|
|
403
406
|
help="Canvas instance to connect to",
|
|
404
407
|
default=None,
|
|
@@ -408,27 +411,36 @@ def update(
|
|
|
408
411
|
if not host:
|
|
409
412
|
raise typer.BadParameter("Please specify a host or set a default via the `auth` command")
|
|
410
413
|
|
|
411
|
-
if
|
|
412
|
-
validate_package(
|
|
414
|
+
if package_path:
|
|
415
|
+
validate_package(package_path)
|
|
413
416
|
|
|
414
417
|
token = get_or_request_api_token(host)
|
|
415
418
|
|
|
416
|
-
print(f"Updating plugin {name} from {host} with {is_enabled=}, {
|
|
417
|
-
|
|
418
|
-
binary_package = {"package": open(package, "rb")} if package else None
|
|
419
|
+
print(f"Updating plugin {name} from {host} with {is_enabled=}, {package_path=}")
|
|
419
420
|
|
|
420
421
|
url = plugin_url(host, name)
|
|
421
422
|
|
|
422
423
|
try:
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
424
|
+
data = {"is_enabled": is_enabled} if is_enabled is not None else {}
|
|
425
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
426
|
+
|
|
427
|
+
if package_path:
|
|
428
|
+
with open(package_path, "rb") as package:
|
|
429
|
+
r = requests.patch(
|
|
430
|
+
url,
|
|
431
|
+
data=data,
|
|
432
|
+
headers=headers,
|
|
433
|
+
files={"package": package},
|
|
434
|
+
)
|
|
435
|
+
else:
|
|
436
|
+
r = requests.patch(
|
|
437
|
+
url,
|
|
438
|
+
data=data,
|
|
439
|
+
headers=headers,
|
|
440
|
+
)
|
|
429
441
|
except requests.exceptions.RequestException:
|
|
430
442
|
print(f"Failed to connect to {host}")
|
|
431
|
-
raise typer.Exit(1)
|
|
443
|
+
raise typer.Exit(1) from None
|
|
432
444
|
|
|
433
445
|
if r.status_code == requests.codes.ok:
|
|
434
446
|
print("Plugin successfully updated!")
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import shutil
|
|
2
|
+
from collections.abc import Generator
|
|
2
3
|
from datetime import datetime
|
|
3
4
|
from pathlib import Path
|
|
4
|
-
from typing import Any
|
|
5
|
+
from typing import Any
|
|
5
6
|
|
|
6
7
|
import pytest
|
|
7
8
|
import typer
|
|
@@ -39,12 +40,13 @@ def test_validate_package_valid_file(tmp_path: Path) -> None:
|
|
|
39
40
|
|
|
40
41
|
@pytest.fixture(scope="session")
|
|
41
42
|
def init_plugin_name() -> str:
|
|
42
|
-
"""The plugin name to be used for the canvas cli init test"""
|
|
43
|
+
"""The plugin name to be used for the canvas cli init test."""
|
|
43
44
|
return f"testing_init-{datetime.now().timestamp()}".replace(".", "")
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
@pytest.fixture(autouse=True, scope="session")
|
|
47
48
|
def clean_up_plugin(init_plugin_name: str) -> Generator[Any, Any, Any]:
|
|
49
|
+
"""Cleans up the plugin directory after the test."""
|
|
48
50
|
yield
|
|
49
51
|
if Path(f"./{init_plugin_name}").exists():
|
|
50
52
|
shutil.rmtree(Path(f"./{init_plugin_name}"))
|
|
@@ -19,6 +19,7 @@ def monkeypatch_app_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None
|
|
|
19
19
|
@pytest.fixture(autouse=True)
|
|
20
20
|
def reset_context_variables() -> None:
|
|
21
21
|
"""Reset the context properties to their default value.
|
|
22
|
+
|
|
22
23
|
This is needed because we cannot build a `reset` method in the CLIContext class,
|
|
23
24
|
because `load_from_file` loads properties dynamically.
|
|
24
25
|
Also since this is a CLI, it's not expected to keep the global context in memory for more than a run,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import importlib.metadata
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import Optional
|
|
4
3
|
|
|
5
4
|
import typer
|
|
6
5
|
|
|
@@ -62,7 +61,7 @@ def get_or_create_config_file() -> Path:
|
|
|
62
61
|
|
|
63
62
|
@app.callback()
|
|
64
63
|
def main(
|
|
65
|
-
version:
|
|
64
|
+
version: bool | None = typer.Option(
|
|
66
65
|
None, "--version", callback=version_callback, is_eager=True
|
|
67
66
|
),
|
|
68
67
|
) -> None:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import shutil
|
|
3
|
+
from collections.abc import Callable, Generator
|
|
3
4
|
from datetime import datetime
|
|
4
5
|
from pathlib import Path
|
|
5
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, cast
|
|
6
7
|
from unittest.mock import MagicMock, patch
|
|
7
8
|
from urllib.parse import urlparse
|
|
8
9
|
|
|
@@ -20,14 +21,13 @@ runner = CliRunner()
|
|
|
20
21
|
|
|
21
22
|
@pytest.fixture(scope="session")
|
|
22
23
|
def plugin_name() -> str:
|
|
23
|
-
"""The plugin name to be used for the canvas cli test"""
|
|
24
|
+
"""The plugin name to be used for the canvas cli test."""
|
|
24
25
|
return f"cli-{datetime.now().timestamp()}".replace(".", "")
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
@pytest.fixture(scope="session")
|
|
28
29
|
def create_or_update_config_auth_file_for_testing(plugin_name: str) -> Generator[None, None, None]:
|
|
29
30
|
"""Creates the necessary config file for auth before performing cli tests."""
|
|
30
|
-
|
|
31
31
|
if not settings.INTEGRATION_TEST_URL:
|
|
32
32
|
raise ImproperlyConfigured("INTEGRATION_TEST_URL is not set")
|
|
33
33
|
|
|
@@ -45,19 +45,27 @@ def create_or_update_config_auth_file_for_testing(plugin_name: str) -> Generator
|
|
|
45
45
|
|
|
46
46
|
temp_path = path.parent / "temp_credentials.ini"
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
open(path
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
# Read the original content
|
|
49
|
+
with open(path) as original_file:
|
|
50
|
+
original_content = original_file.read()
|
|
51
|
+
|
|
52
|
+
# Write new content to the original file
|
|
53
|
+
with open(path, "w") as original_file:
|
|
54
|
+
original_file.writelines(
|
|
55
|
+
[
|
|
56
|
+
f"[{host}]\n",
|
|
57
|
+
f"client_id={client_id}\n",
|
|
58
|
+
f"client_secret={client_secret}\n",
|
|
59
|
+
]
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Append original content to the temp file
|
|
63
|
+
with open(temp_path, "a") as temp_file:
|
|
64
|
+
temp_file.write(original_content)
|
|
57
65
|
|
|
58
66
|
yield
|
|
59
67
|
|
|
60
|
-
with open(temp_path
|
|
68
|
+
with open(temp_path) as temp:
|
|
61
69
|
original_content = temp.read()
|
|
62
70
|
with open(path, "w") as f:
|
|
63
71
|
f.write(original_content)
|
|
@@ -66,9 +74,10 @@ def create_or_update_config_auth_file_for_testing(plugin_name: str) -> Generator
|
|
|
66
74
|
|
|
67
75
|
@pytest.fixture(autouse=True, scope="session")
|
|
68
76
|
def write_plugin(plugin_name: str) -> Generator[Any, Any, Any]:
|
|
77
|
+
"""Writes a plugin to the file system."""
|
|
69
78
|
runner.invoke(app, "init", input=plugin_name)
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
|
|
80
|
+
protocol_code = """
|
|
72
81
|
from canvas_sdk.events import EventType
|
|
73
82
|
from canvas_sdk.protocols import BaseProtocol
|
|
74
83
|
from logger import log
|
|
@@ -81,8 +90,9 @@ class Protocol(BaseProtocol):
|
|
|
81
90
|
log.info(self.NARRATIVE_STRING)
|
|
82
91
|
return []
|
|
83
92
|
"""
|
|
84
|
-
|
|
85
|
-
|
|
93
|
+
|
|
94
|
+
with open(f"./{plugin_name}/protocols/my_protocol.py", "w") as protocol:
|
|
95
|
+
protocol.write(protocol_code)
|
|
86
96
|
|
|
87
97
|
yield
|
|
88
98
|
|
|
@@ -91,12 +101,12 @@ class Protocol(BaseProtocol):
|
|
|
91
101
|
|
|
92
102
|
|
|
93
103
|
def list_empty_plugins(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
94
|
-
"""Step 1 - list all plugins"""
|
|
104
|
+
"""Step 1 - list all plugins."""
|
|
95
105
|
return ("list", 0, [], [f"{plugin_name}"])
|
|
96
106
|
|
|
97
107
|
|
|
98
108
|
def install_new_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
99
|
-
"""Step 2 - install a new plugin"""
|
|
109
|
+
"""Step 2 - install a new plugin."""
|
|
100
110
|
return (
|
|
101
111
|
f"install {plugin_name}",
|
|
102
112
|
0,
|
|
@@ -111,12 +121,12 @@ def install_new_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]
|
|
|
111
121
|
|
|
112
122
|
|
|
113
123
|
def list_newly_installed_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
114
|
-
"""Step 3 - list all plugins, including newly installed one"""
|
|
124
|
+
"""Step 3 - list all plugins, including newly installed one."""
|
|
115
125
|
return ("list", 0, [f"{plugin_name}@0.0.1 enabled"], [])
|
|
116
126
|
|
|
117
127
|
|
|
118
128
|
def disable_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
119
|
-
"""Step 4 - disable plugin"""
|
|
129
|
+
"""Step 4 - disable plugin."""
|
|
120
130
|
return (
|
|
121
131
|
f"disable {plugin_name}",
|
|
122
132
|
0,
|
|
@@ -126,12 +136,12 @@ def disable_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
|
126
136
|
|
|
127
137
|
|
|
128
138
|
def list_disabled_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
129
|
-
"""Step 5 - list disabled plugin"""
|
|
139
|
+
"""Step 5 - list disabled plugin."""
|
|
130
140
|
return ("list", 0, [f"{plugin_name}@0.0.1 disabled"], [])
|
|
131
141
|
|
|
132
142
|
|
|
133
143
|
def enable_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
134
|
-
"""Step 6 - enable the disabled plugin"""
|
|
144
|
+
"""Step 6 - enable the disabled plugin."""
|
|
135
145
|
return (
|
|
136
146
|
f"enable {plugin_name}",
|
|
137
147
|
0,
|
|
@@ -141,7 +151,7 @@ def enable_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
|
141
151
|
|
|
142
152
|
|
|
143
153
|
def uninstall_enabled_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
144
|
-
"""Step 7 - try to uninstall the enabled plugin"""
|
|
154
|
+
"""Step 7 - try to uninstall the enabled plugin."""
|
|
145
155
|
return (
|
|
146
156
|
f"uninstall {plugin_name}",
|
|
147
157
|
1,
|
|
@@ -154,7 +164,7 @@ def uninstall_enabled_plugin(plugin_name: str) -> tuple[str, int, list[str], lis
|
|
|
154
164
|
|
|
155
165
|
|
|
156
166
|
def uninstall_disabled_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
157
|
-
"""Step 8 - disable and then uninstall the plugin"""
|
|
167
|
+
"""Step 8 - disable and then uninstall the plugin."""
|
|
158
168
|
runner.invoke(app, f"disable {plugin_name}")
|
|
159
169
|
|
|
160
170
|
return (
|
|
@@ -192,7 +202,7 @@ def test_canvas_list_install_disable_enable_uninstall(
|
|
|
192
202
|
create_or_update_config_auth_file_for_testing: None,
|
|
193
203
|
step: Callable,
|
|
194
204
|
) -> None:
|
|
195
|
-
"""Tests that the Canvas CLI can list, install, disable, enable, and uninstall a plugin"""
|
|
205
|
+
"""Tests that the Canvas CLI can list, install, disable, enable, and uninstall a plugin."""
|
|
196
206
|
mock_get_password.return_value = None
|
|
197
207
|
mock_set_password.return_value = None
|
|
198
208
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import json
|
|
3
|
+
from collections.abc import Callable
|
|
3
4
|
from pathlib import Path
|
|
4
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, TypeVar, cast
|
|
5
6
|
|
|
6
7
|
import typer
|
|
7
8
|
|
|
@@ -12,6 +13,7 @@ F = TypeVar("F", bound=Callable)
|
|
|
12
13
|
|
|
13
14
|
class CLIContext:
|
|
14
15
|
"""Class that handles configuration across the CLI.
|
|
16
|
+
|
|
15
17
|
Includes methods for:
|
|
16
18
|
* Loading a JSON file with configuration keys into memory.
|
|
17
19
|
* Making a property transient (default, value is not persisted) or persistent (via decorators)
|
|
@@ -118,7 +120,7 @@ class CLIContext:
|
|
|
118
120
|
success=False,
|
|
119
121
|
path=str(file),
|
|
120
122
|
)
|
|
121
|
-
raise typer.Abort()
|
|
123
|
+
raise typer.Abort() from None
|
|
122
124
|
|
|
123
125
|
self._config_file_path = file
|
|
124
126
|
|
|
@@ -18,7 +18,7 @@ def test_print_json_outputs_valid_json(message: Any, capfd: pytest.CaptureFixtur
|
|
|
18
18
|
try:
|
|
19
19
|
json.loads(output)
|
|
20
20
|
except ValueError as exc:
|
|
21
|
-
assert
|
|
21
|
+
assert AssertionError(f"{output} is not valid json: {exc}")
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def test_print_json_outputs_kwargs(capfd: pytest.CaptureFixture[str]) -> None:
|
|
@@ -33,7 +33,7 @@ def test_print_json_outputs_kwargs(capfd: pytest.CaptureFixture[str]) -> None:
|
|
|
33
33
|
assert json_dict.get("a_dict") == {"one": 2}
|
|
34
34
|
|
|
35
35
|
except ValueError as exc:
|
|
36
|
-
assert
|
|
36
|
+
assert AssertionError(f"{output} is not valid json: {exc}")
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
def test_print_overrides_default(capfd: pytest.CaptureFixture[str]) -> None:
|
|
@@ -5,6 +5,7 @@ from canvas_cli.utils.validators import validate_manifest_file
|
|
|
5
5
|
|
|
6
6
|
@pytest.fixture
|
|
7
7
|
def protocol_manifest_example() -> dict:
|
|
8
|
+
"""Return a valid protocol manifest example."""
|
|
8
9
|
return {
|
|
9
10
|
"sdk_version": "0.3.1",
|
|
10
11
|
"plugin_version": "1.0.1",
|
|
@@ -32,5 +33,5 @@ def protocol_manifest_example() -> dict:
|
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
def test_manifest_file_schema(protocol_manifest_example: dict) -> None:
|
|
35
|
-
"""Test that no exception raised when a valid manifest file is validated"""
|
|
36
|
+
"""Test that no exception raised when a valid manifest file is validated."""
|
|
36
37
|
validate_manifest_file(protocol_manifest_example)
|
|
@@ -24,7 +24,7 @@ class Model(BaseModel):
|
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
def _get_effect_method_required_fields(self, method: Any) -> tuple:
|
|
27
|
-
return getattr(self.Meta, f"{method}_required_fields",
|
|
27
|
+
return getattr(self.Meta, f"{method}_required_fields", ())
|
|
28
28
|
|
|
29
29
|
def _create_error_detail(self, type: str, message: str, value: Any) -> InitErrorDetails:
|
|
30
30
|
return InitErrorDetails({"type": PydanticCustomError(type, message), "input": value})
|