canvas 0.33.0__py3-none-any.whl → 0.33.1__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 canvas might be problematic. Click here for more details.
- {canvas-0.33.0.dist-info → canvas-0.33.1.dist-info}/METADATA +2 -1
- canvas-0.33.1.dist-info/RECORD +272 -0
- canvas_sdk/__init__.py +3 -0
- canvas_sdk/commands/__init__.py +1 -1
- canvas_sdk/commands/base.py +3 -0
- canvas_sdk/commands/commands/__init__.py +1 -0
- canvas_sdk/commands/commands/adjust_prescription.py +3 -0
- canvas_sdk/commands/commands/allergy.py +7 -0
- canvas_sdk/commands/commands/assess.py +2 -0
- canvas_sdk/commands/commands/close_goal.py +3 -0
- canvas_sdk/commands/commands/diagnose.py +3 -0
- canvas_sdk/commands/commands/exam.py +3 -0
- canvas_sdk/commands/commands/family_history.py +3 -0
- canvas_sdk/commands/commands/follow_up.py +3 -0
- canvas_sdk/commands/commands/goal.py +3 -0
- canvas_sdk/commands/commands/history_present_illness.py +3 -0
- canvas_sdk/commands/commands/imaging_order.py +3 -0
- canvas_sdk/commands/commands/instruct.py +3 -0
- canvas_sdk/commands/commands/lab_order.py +3 -0
- canvas_sdk/commands/commands/medical_history.py +3 -0
- canvas_sdk/commands/commands/medication_statement.py +2 -0
- canvas_sdk/commands/commands/past_surgical_history.py +3 -0
- canvas_sdk/commands/commands/perform.py +3 -0
- canvas_sdk/commands/commands/plan.py +3 -0
- canvas_sdk/commands/commands/prescribe.py +8 -0
- canvas_sdk/commands/commands/questionnaire/__init__.py +3 -13
- canvas_sdk/commands/commands/questionnaire/question.py +10 -0
- canvas_sdk/commands/commands/reason_for_visit.py +3 -0
- canvas_sdk/commands/commands/refer.py +3 -0
- canvas_sdk/commands/commands/refill.py +3 -0
- canvas_sdk/commands/commands/remove_allergy.py +3 -0
- canvas_sdk/commands/commands/resolve_condition.py +3 -0
- canvas_sdk/commands/commands/review_of_systems.py +3 -0
- canvas_sdk/commands/commands/stop_medication.py +3 -0
- canvas_sdk/commands/commands/structured_assessment.py +3 -0
- canvas_sdk/commands/commands/task.py +7 -0
- canvas_sdk/commands/commands/update_diagnosis.py +3 -0
- canvas_sdk/commands/commands/update_goal.py +3 -0
- canvas_sdk/commands/commands/vitals.py +3 -0
- canvas_sdk/commands/constants.py +8 -0
- canvas_sdk/effects/__init__.py +1 -1
- canvas_sdk/effects/banner_alert/__init__.py +1 -1
- canvas_sdk/effects/banner_alert/add_banner_alert.py +3 -0
- canvas_sdk/effects/banner_alert/remove_banner_alert.py +3 -0
- canvas_sdk/effects/base.py +7 -0
- canvas_sdk/effects/billing_line_item/__init__.py +5 -1
- canvas_sdk/effects/billing_line_item/add_billing_line_item.py +3 -0
- canvas_sdk/effects/billing_line_item/remove_billing_line_item.py +3 -0
- canvas_sdk/effects/billing_line_item/update_billing_line_item.py +3 -0
- canvas_sdk/effects/launch_modal.py +3 -0
- canvas_sdk/effects/patient_chart_summary_configuration.py +3 -0
- canvas_sdk/effects/patient_portal/__init__.py +1 -0
- canvas_sdk/effects/patient_portal/application_configuration.py +3 -0
- canvas_sdk/effects/patient_portal/form_result.py +3 -0
- canvas_sdk/effects/patient_portal_menu_configuration.py +3 -0
- canvas_sdk/effects/patient_profile_configuration.py +5 -1
- canvas_sdk/effects/protocol_card/__init__.py +1 -1
- canvas_sdk/effects/protocol_card/protocol_card.py +6 -0
- canvas_sdk/effects/questionnaire_result.py +3 -0
- canvas_sdk/effects/send_invite.py +3 -0
- canvas_sdk/effects/show_button.py +3 -0
- canvas_sdk/effects/simple_api.py +9 -0
- canvas_sdk/effects/surescripts/__init__.py +2 -2
- canvas_sdk/effects/surescripts/surescripts_messages.py +7 -0
- canvas_sdk/effects/task/__init__.py +6 -1
- canvas_sdk/effects/task/task.py +8 -0
- canvas_sdk/effects/update_user.py +3 -0
- canvas_sdk/effects/widgets/__init__.py +1 -1
- canvas_sdk/effects/widgets/portal_widget.py +3 -0
- canvas_sdk/events/__init__.py +6 -1
- canvas_sdk/events/base.py +3 -0
- canvas_sdk/handlers/__init__.py +1 -1
- canvas_sdk/handlers/action_button.py +6 -0
- canvas_sdk/handlers/application.py +3 -0
- canvas_sdk/handlers/base.py +3 -0
- canvas_sdk/handlers/cron_task.py +3 -0
- canvas_sdk/handlers/simple_api/__init__.py +3 -2
- canvas_sdk/handlers/simple_api/api.py +26 -1
- canvas_sdk/handlers/simple_api/exceptions.py +10 -0
- canvas_sdk/handlers/simple_api/security.py +21 -5
- canvas_sdk/handlers/simple_api/tools.py +9 -0
- canvas_sdk/protocols/__init__.py +1 -1
- canvas_sdk/protocols/base.py +3 -0
- canvas_sdk/protocols/clinical_quality_measure.py +6 -1
- canvas_sdk/protocols/timeframe.py +3 -0
- canvas_sdk/questionnaires/__init__.py +1 -1
- canvas_sdk/questionnaires/utils.py +7 -0
- canvas_sdk/templates/__init__.py +1 -1
- canvas_sdk/templates/utils.py +3 -0
- canvas_sdk/utils/__init__.py +1 -1
- canvas_sdk/utils/http.py +69 -35
- canvas_sdk/utils/plugins.py +4 -0
- canvas_sdk/utils/stats.py +11 -0
- canvas_sdk/v1/__init__.py +1 -0
- canvas_sdk/v1/apps.py +3 -0
- canvas_sdk/v1/data/__init__.py +2 -2
- canvas_sdk/v1/data/allergy_intolerance.py +3 -0
- canvas_sdk/v1/data/appointment.py +7 -0
- canvas_sdk/v1/data/assessment.py +3 -0
- canvas_sdk/v1/data/banner_alert.py +3 -0
- canvas_sdk/v1/data/base.py +3 -0
- canvas_sdk/v1/data/billing.py +7 -0
- canvas_sdk/v1/data/care_team.py +7 -0
- canvas_sdk/v1/data/command.py +3 -0
- canvas_sdk/v1/data/common.py +18 -0
- canvas_sdk/v1/data/condition.py +7 -0
- canvas_sdk/v1/data/coverage.py +14 -0
- canvas_sdk/v1/data/detected_issue.py +3 -0
- canvas_sdk/v1/data/device.py +3 -0
- canvas_sdk/v1/data/imaging.py +7 -0
- canvas_sdk/v1/data/lab.py +16 -0
- canvas_sdk/v1/data/medication.py +3 -0
- canvas_sdk/v1/data/note.py +9 -0
- canvas_sdk/v1/data/observation.py +9 -0
- canvas_sdk/v1/data/organization.py +3 -0
- canvas_sdk/v1/data/patient.py +18 -2
- canvas_sdk/v1/data/practicelocation.py +7 -0
- canvas_sdk/v1/data/protocol_override.py +7 -0
- canvas_sdk/v1/data/questionnaire.py +16 -3
- canvas_sdk/v1/data/reason_for_visit.py +3 -0
- canvas_sdk/v1/data/staff.py +3 -0
- canvas_sdk/v1/data/task.py +12 -0
- canvas_sdk/v1/data/team.py +8 -1
- canvas_sdk/v1/data/user.py +3 -0
- canvas_sdk/v1/models.py +2 -0
- canvas_sdk/value_set/__init__.py +1 -0
- canvas_sdk/value_set/_utilities.py +16 -0
- canvas_sdk/value_set/custom.py +4 -0
- canvas_sdk/value_set/hcc2018.py +3 -0
- canvas_sdk/value_set/v2022/__init__.py +1 -0
- canvas_sdk/value_set/v2022/adverse_event.py +3 -0
- canvas_sdk/value_set/v2022/allergy.py +5 -0
- canvas_sdk/value_set/v2022/assessment.py +5 -0
- canvas_sdk/value_set/v2022/communication.py +5 -0
- canvas_sdk/value_set/v2022/condition.py +5 -0
- canvas_sdk/value_set/v2022/device.py +5 -0
- canvas_sdk/value_set/v2022/diagnostic_study.py +5 -0
- canvas_sdk/value_set/v2022/encounter.py +5 -0
- canvas_sdk/value_set/v2022/immunization.py +5 -0
- canvas_sdk/value_set/v2022/individual_characteristic.py +5 -0
- canvas_sdk/value_set/v2022/intervention.py +5 -0
- canvas_sdk/value_set/v2022/laboratory_test.py +5 -0
- canvas_sdk/value_set/v2022/medication.py +5 -0
- canvas_sdk/value_set/v2022/physical_exam.py +5 -0
- canvas_sdk/value_set/v2022/procedure.py +5 -0
- canvas_sdk/value_set/v2022/symptom.py +3 -0
- canvas_sdk/value_set/value_set.py +9 -0
- canvas_sdk/views/__init__.py +1 -0
- logger/__init__.py +2 -0
- logger/logger.py +3 -0
- plugin_runner/aws_headers.py +1 -1
- plugin_runner/load_all_plugins.py +202 -0
- plugin_runner/plugin_runner.py +21 -24
- plugin_runner/sandbox.py +497 -115
- settings.py +5 -2
- canvas-0.33.0.dist-info/RECORD +0 -366
- canvas_cli/apps/auth/tests.py +0 -155
- canvas_cli/apps/plugin/tests.py +0 -85
- canvas_cli/conftest.py +0 -28
- canvas_cli/tests.py +0 -217
- canvas_cli/utils/context/tests.py +0 -131
- canvas_cli/utils/print/tests.py +0 -69
- canvas_cli/utils/urls/tests.py +0 -12
- canvas_cli/utils/validators/tests.py +0 -37
- canvas_sdk/commands/tests/protocol/__init__.py +0 -0
- canvas_sdk/commands/tests/protocol/tests.py +0 -83
- canvas_sdk/commands/tests/schema/__init__.py +0 -0
- canvas_sdk/commands/tests/schema/tests.py +0 -108
- canvas_sdk/commands/tests/test_base_command.py +0 -81
- canvas_sdk/commands/tests/test_utils.py +0 -375
- canvas_sdk/commands/tests/unit/__init__.py +0 -0
- canvas_sdk/commands/tests/unit/tests.py +0 -278
- canvas_sdk/effects/banner_alert/tests.py +0 -288
- canvas_sdk/effects/protocol_card/tests.py +0 -191
- canvas_sdk/questionnaires/tests/__init__.py +0 -0
- canvas_sdk/questionnaires/tests/test_utils.py +0 -74
- canvas_sdk/templates/tests/__init__.py +0 -0
- canvas_sdk/templates/tests/test_utils.py +0 -43
- canvas_sdk/tests/__init__.py +0 -0
- canvas_sdk/tests/handlers/__init__.py +0 -0
- canvas_sdk/tests/handlers/test_simple_api.py +0 -1167
- canvas_sdk/utils/tests.py +0 -72
- canvas_sdk/value_set/tests/test_value_sets.py +0 -72
- plugin_runner/tests/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/example_plugin/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/example_plugin/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/example_plugin/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/example_plugin/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/example_plugin/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/CANVAS_MANIFEST.json +0 -38
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/README.md +0 -11
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/protocols/my_protocol.py +0 -33
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/templates/__init__.py +0 -3
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/templates/base.py +0 -6
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/utils/__init__.py +0 -5
- plugin_runner/tests/fixtures/plugins/test_implicit_imports_plugin/utils/base.py +0 -4
- plugin_runner/tests/fixtures/plugins/test_load_questionnaire/CANVAS_MANIFEST.json +0 -52
- plugin_runner/tests/fixtures/plugins/test_load_questionnaire/README.md +0 -11
- plugin_runner/tests/fixtures/plugins/test_load_questionnaire/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_load_questionnaire/protocols/my_protocol.py +0 -39
- plugin_runner/tests/fixtures/plugins/test_load_questionnaire/questionnaires/example_questionnaire.yml +0 -61
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/other_module/base.py +0 -10
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_plugin/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/other_module/base.py +0 -10
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_forbidden_imports_runtime_plugin/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/other_module/base.py +0 -3
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v1/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/other_module/base.py +0 -6
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v2/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/other_module/base.py +0 -8
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_outside_plugin_v3/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/CANVAS_MANIFEST.json +0 -29
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/README.md +0 -12
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/other_module/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/other_module/base.py +0 -3
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_module_imports_plugin/protocols/my_protocol.py +0 -18
- plugin_runner/tests/fixtures/plugins/test_render_template/CANVAS_MANIFEST.json +0 -47
- plugin_runner/tests/fixtures/plugins/test_render_template/README.md +0 -11
- plugin_runner/tests/fixtures/plugins/test_render_template/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_render_template/protocols/my_protocol.py +0 -43
- plugin_runner/tests/fixtures/plugins/test_render_template/templates/template.html +0 -10
- plugin_runner/tests/fixtures/plugins/test_simple_api/CANVAS_MANIFEST.json +0 -47
- plugin_runner/tests/fixtures/plugins/test_simple_api/README.md +0 -11
- plugin_runner/tests/fixtures/plugins/test_simple_api/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_simple_api/protocols/__init__.py +0 -0
- plugin_runner/tests/fixtures/plugins/test_simple_api/protocols/my_protocol.py +0 -43
- plugin_runner/tests/test_application.py +0 -65
- plugin_runner/tests/test_plugin_installer.py +0 -127
- plugin_runner/tests/test_plugin_runner.py +0 -388
- plugin_runner/tests/test_sandbox.py +0 -137
- {canvas-0.33.0.dist-info → canvas-0.33.1.dist-info}/WHEEL +0 -0
- {canvas-0.33.0.dist-info → canvas-0.33.1.dist-info}/entry_points.txt +0 -0
canvas_cli/apps/plugin/tests.py
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import shutil
|
|
2
|
-
from collections.abc import Generator
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from typing import Any
|
|
6
|
-
|
|
7
|
-
import pytest
|
|
8
|
-
import typer
|
|
9
|
-
from typer.testing import CliRunner
|
|
10
|
-
|
|
11
|
-
from canvas_cli.main import app
|
|
12
|
-
|
|
13
|
-
from .plugin import validate_package
|
|
14
|
-
|
|
15
|
-
runner = CliRunner()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def test_validate_package_unexistant_path() -> None:
|
|
19
|
-
"""Tests the validate_package callback with an invalid folder."""
|
|
20
|
-
with pytest.raises(typer.BadParameter):
|
|
21
|
-
validate_package(Path("/a_random_url_that_will_not_exist_or_so_I_hope"))
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def test_validate_package_wrong_file_type(tmp_path: Path) -> None:
|
|
25
|
-
"""Tests the validate_package callback with an invalid file type."""
|
|
26
|
-
invalid_file = tmp_path / "tmp_file.zip"
|
|
27
|
-
invalid_file.write_text("definitely not a python package")
|
|
28
|
-
|
|
29
|
-
with pytest.raises(typer.BadParameter):
|
|
30
|
-
validate_package(invalid_file)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def test_validate_package_valid_file(tmp_path: Path) -> None:
|
|
34
|
-
"""Tests the validate_package callback with a valid file type."""
|
|
35
|
-
package_path = tmp_path / "test-package.whl"
|
|
36
|
-
package_path.write_text("something")
|
|
37
|
-
result = validate_package(package_path)
|
|
38
|
-
assert result == package_path
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
@pytest.fixture(scope="session")
|
|
42
|
-
def init_plugin_name() -> str:
|
|
43
|
-
"""The plugin name to be used for the canvas cli init test."""
|
|
44
|
-
return f"testing_init-{datetime.now().timestamp()}".replace(".", "")
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@pytest.fixture(autouse=True, scope="session")
|
|
48
|
-
def clean_up_plugin(init_plugin_name: str) -> Generator[Any, Any, Any]:
|
|
49
|
-
"""Cleans up the plugin directory after the test."""
|
|
50
|
-
yield
|
|
51
|
-
if Path(f"./{init_plugin_name}").exists():
|
|
52
|
-
shutil.rmtree(Path(f"./{init_plugin_name}"))
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def test_canvas_init(init_plugin_name: str) -> None:
|
|
56
|
-
"""Tests that the CLI successfully creates a plugin with init."""
|
|
57
|
-
result = runner.invoke(app, "init", input=init_plugin_name)
|
|
58
|
-
assert result.exit_code == 0
|
|
59
|
-
|
|
60
|
-
# plugin directory exists
|
|
61
|
-
plugin = Path(f"./{init_plugin_name}")
|
|
62
|
-
assert plugin.exists()
|
|
63
|
-
assert plugin.is_dir()
|
|
64
|
-
|
|
65
|
-
# manifest file exists
|
|
66
|
-
manifest = Path(f"./{init_plugin_name}/CANVAS_MANIFEST.json")
|
|
67
|
-
assert manifest.exists()
|
|
68
|
-
assert manifest.is_file()
|
|
69
|
-
manifest_result = runner.invoke(app, f"validate-manifest {init_plugin_name}")
|
|
70
|
-
assert manifest_result.exit_code == 0
|
|
71
|
-
|
|
72
|
-
# readme file exists
|
|
73
|
-
readme = Path(f"./{init_plugin_name}/README.md")
|
|
74
|
-
assert readme.exists()
|
|
75
|
-
assert readme.is_file()
|
|
76
|
-
|
|
77
|
-
# protocols dir exists
|
|
78
|
-
protocols = Path(f"./{init_plugin_name}/protocols")
|
|
79
|
-
assert protocols.exists()
|
|
80
|
-
assert protocols.is_dir()
|
|
81
|
-
|
|
82
|
-
# protocol file exists in protocols dir
|
|
83
|
-
protocol = Path(f"./{init_plugin_name}/protocols/my_protocol.py")
|
|
84
|
-
assert protocol.exists()
|
|
85
|
-
assert protocol.is_file()
|
canvas_cli/conftest.py
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
|
|
3
|
-
import pytest
|
|
4
|
-
|
|
5
|
-
import canvas_cli.main
|
|
6
|
-
from canvas_cli.utils.context import context
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@pytest.fixture(autouse=True)
|
|
10
|
-
def monkeypatch_app_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
11
|
-
"""Monkeypatch `get_app_dir` in order to return a temp dir when testing, so we don't overwrite our config file."""
|
|
12
|
-
|
|
13
|
-
def app_dir() -> str:
|
|
14
|
-
return str(tmp_path)
|
|
15
|
-
|
|
16
|
-
monkeypatch.setattr(canvas_cli.main, "get_app_dir", app_dir)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@pytest.fixture(autouse=True)
|
|
20
|
-
def reset_context_variables() -> None:
|
|
21
|
-
"""Reset the context properties to their default value.
|
|
22
|
-
|
|
23
|
-
This is needed because we cannot build a `reset` method in the CLIContext class,
|
|
24
|
-
because `load_from_file` loads properties dynamically.
|
|
25
|
-
Also since this is a CLI, it's not expected to keep the global context in memory for more than a run,
|
|
26
|
-
which definitely happens with tests run
|
|
27
|
-
"""
|
|
28
|
-
context._default_host = None
|
canvas_cli/tests.py
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import shutil
|
|
3
|
-
from collections.abc import Callable, Generator
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Any, cast
|
|
7
|
-
from unittest.mock import MagicMock, patch
|
|
8
|
-
from urllib.parse import urlparse
|
|
9
|
-
|
|
10
|
-
import pytest
|
|
11
|
-
from django.core.exceptions import ImproperlyConfigured
|
|
12
|
-
from typer.testing import CliRunner
|
|
13
|
-
|
|
14
|
-
import settings
|
|
15
|
-
from canvas_cli.apps.auth.utils import CONFIG_PATH
|
|
16
|
-
|
|
17
|
-
from .main import app
|
|
18
|
-
|
|
19
|
-
runner = CliRunner()
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
@pytest.fixture(scope="session")
|
|
23
|
-
def plugin_name() -> str:
|
|
24
|
-
"""The plugin name to be used for the canvas cli test."""
|
|
25
|
-
return f"cli-{datetime.now().timestamp()}".replace(".", "")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@pytest.fixture(scope="session")
|
|
29
|
-
def create_or_update_config_auth_file_for_testing(plugin_name: str) -> Generator[None, None, None]:
|
|
30
|
-
"""Creates the necessary config file for auth before performing cli tests."""
|
|
31
|
-
if not settings.INTEGRATION_TEST_URL:
|
|
32
|
-
raise ImproperlyConfigured("INTEGRATION_TEST_URL is not set")
|
|
33
|
-
|
|
34
|
-
host = cast(str, urlparse(settings.INTEGRATION_TEST_URL).hostname).replace(
|
|
35
|
-
".canvasmedical.com", ""
|
|
36
|
-
)
|
|
37
|
-
client_id = settings.INTEGRATION_TEST_CLIENT_ID
|
|
38
|
-
client_secret = settings.INTEGRATION_TEST_CLIENT_SECRET
|
|
39
|
-
|
|
40
|
-
path = CONFIG_PATH
|
|
41
|
-
if not path.exists():
|
|
42
|
-
if not path.parent.exists():
|
|
43
|
-
path.parent.mkdir()
|
|
44
|
-
path.touch()
|
|
45
|
-
|
|
46
|
-
temp_path = path.parent / "temp_credentials.ini"
|
|
47
|
-
|
|
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)
|
|
65
|
-
|
|
66
|
-
yield
|
|
67
|
-
|
|
68
|
-
with open(temp_path) as temp:
|
|
69
|
-
original_content = temp.read()
|
|
70
|
-
with open(path, "w") as f:
|
|
71
|
-
f.write(original_content)
|
|
72
|
-
os.remove(temp_path)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
@pytest.fixture(autouse=True, scope="session")
|
|
76
|
-
def write_plugin(plugin_name: str) -> Generator[Any, Any, Any]:
|
|
77
|
-
"""Writes a plugin to the file system."""
|
|
78
|
-
runner.invoke(app, "init", input=plugin_name)
|
|
79
|
-
|
|
80
|
-
protocol_code = """
|
|
81
|
-
from canvas_sdk.events import EventType
|
|
82
|
-
from canvas_sdk.protocols import BaseProtocol
|
|
83
|
-
from logger import log
|
|
84
|
-
|
|
85
|
-
class Protocol(BaseProtocol):
|
|
86
|
-
RESPONDS_TO = EventType.Name(EventType.ASSESS_COMMAND__CONDITION_SELECTED)
|
|
87
|
-
NARRATIVE_STRING = "I was inserted from my plugin's protocol."
|
|
88
|
-
|
|
89
|
-
def compute(self):
|
|
90
|
-
log.info(self.NARRATIVE_STRING)
|
|
91
|
-
return []
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
with open(f"./{plugin_name}/protocols/my_protocol.py", "w") as protocol:
|
|
95
|
-
protocol.write(protocol_code)
|
|
96
|
-
|
|
97
|
-
yield
|
|
98
|
-
|
|
99
|
-
if Path(f"./{plugin_name}").exists():
|
|
100
|
-
shutil.rmtree(Path(f"./{plugin_name}"))
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def list_empty_plugins(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
104
|
-
"""Step 1 - list all plugins."""
|
|
105
|
-
return ("list", 0, [], [f"{plugin_name}"])
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def install_new_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
109
|
-
"""Step 2 - install a new plugin."""
|
|
110
|
-
return (
|
|
111
|
-
f"install {plugin_name}",
|
|
112
|
-
0,
|
|
113
|
-
[
|
|
114
|
-
f"Plugin {plugin_name} has a valid CANVAS_MANIFEST.json file",
|
|
115
|
-
"Installing plugin:",
|
|
116
|
-
"Posting",
|
|
117
|
-
f"Plugin {plugin_name} successfully installed!",
|
|
118
|
-
],
|
|
119
|
-
[],
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def list_newly_installed_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
124
|
-
"""Step 3 - list all plugins, including newly installed one."""
|
|
125
|
-
return ("list", 0, [f"{plugin_name}@0.0.1 enabled"], [])
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def disable_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
129
|
-
"""Step 4 - disable plugin."""
|
|
130
|
-
return (
|
|
131
|
-
f"disable {plugin_name}",
|
|
132
|
-
0,
|
|
133
|
-
[f"Disabling {plugin_name} using ", f"Plugin {plugin_name} successfully disabled!"],
|
|
134
|
-
[],
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
def list_disabled_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
139
|
-
"""Step 5 - list disabled plugin."""
|
|
140
|
-
return ("list", 0, [f"{plugin_name}@0.0.1 disabled"], [])
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def enable_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
144
|
-
"""Step 6 - enable the disabled plugin."""
|
|
145
|
-
return (
|
|
146
|
-
f"enable {plugin_name}",
|
|
147
|
-
0,
|
|
148
|
-
[f"Enabling {plugin_name} using ", f"Plugin {plugin_name} successfully enabled!"],
|
|
149
|
-
[],
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def uninstall_enabled_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
154
|
-
"""Step 7 - try to uninstall the enabled plugin."""
|
|
155
|
-
return (
|
|
156
|
-
f"uninstall {plugin_name}",
|
|
157
|
-
1,
|
|
158
|
-
[
|
|
159
|
-
f"Uninstalling {plugin_name} using",
|
|
160
|
-
'Status code 403: {"detail":"Cannot delete an enabled plugin."}',
|
|
161
|
-
],
|
|
162
|
-
[],
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def uninstall_disabled_plugin(plugin_name: str) -> tuple[str, int, list[str], list[str]]:
|
|
167
|
-
"""Step 8 - disable and then uninstall the plugin."""
|
|
168
|
-
runner.invoke(app, f"disable {plugin_name}")
|
|
169
|
-
|
|
170
|
-
return (
|
|
171
|
-
f"uninstall {plugin_name}",
|
|
172
|
-
0,
|
|
173
|
-
[
|
|
174
|
-
f"Uninstalling {plugin_name} using",
|
|
175
|
-
f"Plugin {plugin_name} successfully uninstalled!",
|
|
176
|
-
],
|
|
177
|
-
[],
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
@pytest.mark.integtest
|
|
182
|
-
@patch("keyring.get_password")
|
|
183
|
-
@patch("keyring.set_password")
|
|
184
|
-
@pytest.mark.parametrize(
|
|
185
|
-
"step",
|
|
186
|
-
[
|
|
187
|
-
(list_empty_plugins),
|
|
188
|
-
(install_new_plugin),
|
|
189
|
-
(list_newly_installed_plugin),
|
|
190
|
-
(disable_plugin),
|
|
191
|
-
(list_disabled_plugin),
|
|
192
|
-
(enable_plugin),
|
|
193
|
-
(uninstall_enabled_plugin),
|
|
194
|
-
(uninstall_disabled_plugin),
|
|
195
|
-
(list_empty_plugins),
|
|
196
|
-
],
|
|
197
|
-
)
|
|
198
|
-
def test_canvas_list_install_disable_enable_uninstall(
|
|
199
|
-
mock_get_password: MagicMock,
|
|
200
|
-
mock_set_password: MagicMock,
|
|
201
|
-
plugin_name: str,
|
|
202
|
-
create_or_update_config_auth_file_for_testing: None,
|
|
203
|
-
step: Callable,
|
|
204
|
-
) -> None:
|
|
205
|
-
"""Tests that the Canvas CLI can list, install, disable, enable, and uninstall a plugin."""
|
|
206
|
-
mock_get_password.return_value = None
|
|
207
|
-
mock_set_password.return_value = None
|
|
208
|
-
|
|
209
|
-
(command, expected_exit_code, expected_outputs, expected_no_outputs) = step(plugin_name)
|
|
210
|
-
|
|
211
|
-
result = runner.invoke(app, command)
|
|
212
|
-
|
|
213
|
-
assert result.exit_code == expected_exit_code
|
|
214
|
-
for expected_output in expected_outputs:
|
|
215
|
-
assert expected_output in result.stdout
|
|
216
|
-
for expected_no_output in expected_no_outputs:
|
|
217
|
-
assert expected_no_output not in result.stdout
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
from collections.abc import Generator
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
import pytest
|
|
7
|
-
import typer
|
|
8
|
-
|
|
9
|
-
from canvas_cli.utils.context import CLIContext
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class CLIContextTestHelper(CLIContext):
|
|
13
|
-
"""CLIContext subclass that defines some properties we can test."""
|
|
14
|
-
|
|
15
|
-
_persistent_mock_property: str | None = None
|
|
16
|
-
_transient_mock_property: bool = False
|
|
17
|
-
|
|
18
|
-
@property
|
|
19
|
-
def persistent_mock_property(self) -> str | None:
|
|
20
|
-
"""Mock persistent property."""
|
|
21
|
-
return self._persistent_mock_property
|
|
22
|
-
|
|
23
|
-
@persistent_mock_property.setter
|
|
24
|
-
@CLIContext.persistent
|
|
25
|
-
def persistent_mock_property(self, new_persistent_mock_property: str | None) -> None:
|
|
26
|
-
self._persistent_mock_property = new_persistent_mock_property
|
|
27
|
-
|
|
28
|
-
@property
|
|
29
|
-
def transient_mock_property(self) -> bool:
|
|
30
|
-
"""Mock transient property."""
|
|
31
|
-
return self._transient_mock_property
|
|
32
|
-
|
|
33
|
-
@transient_mock_property.setter
|
|
34
|
-
def transient_mock_property(self, new_transient_mock_property: bool) -> None:
|
|
35
|
-
self._transient_mock_property = new_transient_mock_property
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@pytest.fixture
|
|
39
|
-
def config_file(tmp_path: Path) -> Generator[Path, None, None]:
|
|
40
|
-
"""Fixture that yields an empty config file and cleans up after itself."""
|
|
41
|
-
config_file = tmp_path / "mock_config.json"
|
|
42
|
-
yield config_file
|
|
43
|
-
os.remove(config_file)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@pytest.fixture
|
|
47
|
-
def valid_mock_config_file(config_file: Path) -> Path:
|
|
48
|
-
"""Fixture that yields a valid mock config file."""
|
|
49
|
-
mock_config = {
|
|
50
|
-
"persistent_mock_property": "mock-value",
|
|
51
|
-
}
|
|
52
|
-
with open(config_file, "w") as f:
|
|
53
|
-
json.dump(mock_config, f)
|
|
54
|
-
|
|
55
|
-
return config_file
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@pytest.fixture
|
|
59
|
-
def invalid_json_mock_config_file(config_file: Path) -> Path:
|
|
60
|
-
"""Fixture that yields an invalid config file."""
|
|
61
|
-
config_file.write_text("Absolutely invalid JSON")
|
|
62
|
-
|
|
63
|
-
return config_file
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
@pytest.fixture
|
|
67
|
-
def invalid_properties_mock_config_file(config_file: Path) -> Path:
|
|
68
|
-
"""Fixture that yields a valid mock config file."""
|
|
69
|
-
mock_config = {
|
|
70
|
-
"unknown-property": "mock-value",
|
|
71
|
-
}
|
|
72
|
-
with open(config_file, "w") as f:
|
|
73
|
-
json.dump(mock_config, f)
|
|
74
|
-
|
|
75
|
-
return config_file
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def test_valid_load_from_file(valid_mock_config_file: Path) -> None:
|
|
79
|
-
"""Test loading a valid config file."""
|
|
80
|
-
context = CLIContextTestHelper()
|
|
81
|
-
context.load_from_file(valid_mock_config_file)
|
|
82
|
-
|
|
83
|
-
assert context.persistent_mock_property == "mock-value"
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def test_invalid_load_from_file(invalid_json_mock_config_file: Path) -> None:
|
|
87
|
-
"""Test loading an invalid config file aborts the execution."""
|
|
88
|
-
context = CLIContextTestHelper()
|
|
89
|
-
|
|
90
|
-
with pytest.raises(typer.Abort):
|
|
91
|
-
context.load_from_file(invalid_json_mock_config_file)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def test_load_invalid_property(invalid_properties_mock_config_file: Path) -> None:
|
|
95
|
-
"""Since we dynamically load the properties, this test ensures that unknown properties don't throw exceptions."""
|
|
96
|
-
context = CLIContextTestHelper()
|
|
97
|
-
|
|
98
|
-
context.load_from_file(invalid_properties_mock_config_file)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def test_config_persistence(valid_mock_config_file: Path) -> None:
|
|
102
|
-
"""Test marking a property with @persistent stores the value in the config file."""
|
|
103
|
-
context = CLIContextTestHelper()
|
|
104
|
-
context.load_from_file(valid_mock_config_file)
|
|
105
|
-
|
|
106
|
-
assert context.persistent_mock_property == "mock-value"
|
|
107
|
-
|
|
108
|
-
context.persistent_mock_property = "new-value"
|
|
109
|
-
|
|
110
|
-
# This won't ever happen but since the values are in memory, we need to create a new context instance,
|
|
111
|
-
# as if mimicking a new program launch
|
|
112
|
-
context_b = CLIContextTestHelper()
|
|
113
|
-
context_b.load_from_file(valid_mock_config_file)
|
|
114
|
-
|
|
115
|
-
assert context_b.persistent_mock_property == "new-value"
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def test_config_transience(valid_mock_config_file: Path) -> None:
|
|
119
|
-
"""Test the properties transient default."""
|
|
120
|
-
context = CLIContextTestHelper()
|
|
121
|
-
context.load_from_file(valid_mock_config_file)
|
|
122
|
-
|
|
123
|
-
assert context.transient_mock_property is False
|
|
124
|
-
context.transient_mock_property = True
|
|
125
|
-
|
|
126
|
-
# This won't ever happen but since the values are in memory, we need to create a new context instance,
|
|
127
|
-
# as if mimicking a new program launch
|
|
128
|
-
context_b = CLIContextTestHelper()
|
|
129
|
-
context_b.load_from_file(valid_mock_config_file)
|
|
130
|
-
|
|
131
|
-
assert context_b.transient_mock_property is False
|
canvas_cli/utils/print/tests.py
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from typing import Any
|
|
3
|
-
from unittest.mock import Mock
|
|
4
|
-
|
|
5
|
-
import pytest
|
|
6
|
-
from requests import Response
|
|
7
|
-
|
|
8
|
-
from canvas_cli.utils.print import print
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@pytest.mark.parametrize(
|
|
12
|
-
"message", ["a simple message", ["an array", "of messages"], {"one": "test"}]
|
|
13
|
-
)
|
|
14
|
-
def test_print_json_outputs_valid_json(message: Any, capfd: pytest.CaptureFixture[str]) -> None:
|
|
15
|
-
"""Test the output of print is always valid json."""
|
|
16
|
-
print.json(message)
|
|
17
|
-
output, _ = capfd.readouterr()
|
|
18
|
-
try:
|
|
19
|
-
json.loads(output)
|
|
20
|
-
except ValueError as exc:
|
|
21
|
-
assert AssertionError(f"{output} is not valid json: {exc}")
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def test_print_json_outputs_kwargs(capfd: pytest.CaptureFixture[str]) -> None:
|
|
25
|
-
"""Test the output of print contains all given kwargs."""
|
|
26
|
-
print.json("A message", status_code=200, a_string="a_value", an_array=[1, 2], a_dict={"one": 2})
|
|
27
|
-
output, _ = capfd.readouterr()
|
|
28
|
-
try:
|
|
29
|
-
json_dict = json.loads(output)
|
|
30
|
-
|
|
31
|
-
assert json_dict.get("a_string") == "a_value"
|
|
32
|
-
assert json_dict.get("an_array") == [1, 2]
|
|
33
|
-
assert json_dict.get("a_dict") == {"one": 2}
|
|
34
|
-
|
|
35
|
-
except ValueError as exc:
|
|
36
|
-
assert AssertionError(f"{output} is not valid json: {exc}")
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def test_print_overrides_default(capfd: pytest.CaptureFixture[str]) -> None:
|
|
40
|
-
"""Test using `print` defaults to Rich."""
|
|
41
|
-
message = "Testing print"
|
|
42
|
-
print(message)
|
|
43
|
-
output, _ = capfd.readouterr()
|
|
44
|
-
assert message + "\n" == output
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def test_print_response_non_json_text(capfd: pytest.CaptureFixture[str]) -> None:
|
|
48
|
-
"""Test print.response with a non-json response."""
|
|
49
|
-
response = Mock(spec=Response)
|
|
50
|
-
response.status_code = 200
|
|
51
|
-
response.text = "testing text"
|
|
52
|
-
response.json.side_effect = json.JSONDecodeError("", "", 0)
|
|
53
|
-
print.response(response)
|
|
54
|
-
output, _ = capfd.readouterr()
|
|
55
|
-
assert json.loads(output) == json.loads(
|
|
56
|
-
'{"status_code": 200, "success": true, "message": "testing text"}'
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def test_print_response_json_text(capfd: pytest.CaptureFixture[str]) -> None:
|
|
61
|
-
"""Test print.response with a json response."""
|
|
62
|
-
response = Mock(spec=Response)
|
|
63
|
-
response.status_code = 201
|
|
64
|
-
response.json.return_value = {"something": True}
|
|
65
|
-
print.response(response)
|
|
66
|
-
output, _ = capfd.readouterr()
|
|
67
|
-
assert json.loads(output) == json.loads(
|
|
68
|
-
'{"status_code": 201, "success": true, "message": {"something": true} }'
|
|
69
|
-
)
|
canvas_cli/utils/urls/tests.py
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
|
|
3
|
-
from canvas_cli.utils.urls import CoreEndpoint
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
@pytest.mark.parametrize("path", ["a-path", "/a-path", "/a-path/", "a-path/"])
|
|
7
|
-
def test_endpoint_builder(path: str) -> None:
|
|
8
|
-
"""Test that the endpoint is always generated with a trailing `/`."""
|
|
9
|
-
assert (
|
|
10
|
-
CoreEndpoint.LOG.build("https://test-host.com", path)
|
|
11
|
-
== "https://test-host.com/core/api/v1/logging/a-path/"
|
|
12
|
-
)
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
|
|
3
|
-
from canvas_cli.utils.validators import validate_manifest_file
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
@pytest.fixture
|
|
7
|
-
def protocol_manifest_example() -> dict:
|
|
8
|
-
"""Return a valid protocol manifest example."""
|
|
9
|
-
return {
|
|
10
|
-
"sdk_version": "0.3.1",
|
|
11
|
-
"plugin_version": "1.0.1",
|
|
12
|
-
"name": "Prompt to prescribe when assessing condition",
|
|
13
|
-
"description": "To assist in ....",
|
|
14
|
-
"components": {
|
|
15
|
-
"protocols": [
|
|
16
|
-
{
|
|
17
|
-
"class": "prompt_to_prescribe.protocols.prompt_when_assessing.PromptWhenAssessing",
|
|
18
|
-
"description": "probably the same as the plugin's description",
|
|
19
|
-
"data_access": {
|
|
20
|
-
"event": "",
|
|
21
|
-
"read": ["conditions"],
|
|
22
|
-
"write": ["commands"],
|
|
23
|
-
},
|
|
24
|
-
}
|
|
25
|
-
]
|
|
26
|
-
},
|
|
27
|
-
"tags": {"patient_sourcing_and_intake": ["symptom_triage"]},
|
|
28
|
-
"references": [],
|
|
29
|
-
"license": "",
|
|
30
|
-
"diagram": False,
|
|
31
|
-
"readme": "README.MD",
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def test_manifest_file_schema(protocol_manifest_example: dict) -> None:
|
|
36
|
-
"""Test that no exception raised when a valid manifest file is validated."""
|
|
37
|
-
validate_manifest_file(protocol_manifest_example)
|
|
File without changes
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
from collections.abc import Generator
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
from typing import cast
|
|
4
|
-
|
|
5
|
-
import pytest
|
|
6
|
-
|
|
7
|
-
import settings
|
|
8
|
-
from canvas_sdk.commands.tests.test_utils import (
|
|
9
|
-
COMMANDS,
|
|
10
|
-
MaskedValue,
|
|
11
|
-
clean_up_files_and_plugins,
|
|
12
|
-
create_new_note,
|
|
13
|
-
get_original_note_body_commands,
|
|
14
|
-
get_token,
|
|
15
|
-
install_plugin,
|
|
16
|
-
trigger_plugin_event,
|
|
17
|
-
wait_for_log,
|
|
18
|
-
write_protocol_code,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
@pytest.fixture(scope="session")
|
|
23
|
-
def token() -> MaskedValue:
|
|
24
|
-
"""Get a valid token."""
|
|
25
|
-
return get_token()
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@pytest.fixture(scope="session")
|
|
29
|
-
def new_note(token: MaskedValue) -> dict:
|
|
30
|
-
"""Create a new note."""
|
|
31
|
-
return create_new_note(token)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@pytest.fixture(scope="session")
|
|
35
|
-
def plugin_name() -> str:
|
|
36
|
-
"""The plugin name to be used."""
|
|
37
|
-
return f"commands{datetime.now().timestamp()}".replace(".", "")
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@pytest.fixture(scope="session")
|
|
41
|
-
def write_and_install_protocol_and_clean_up(
|
|
42
|
-
plugin_name: str, token: MaskedValue, new_note: dict
|
|
43
|
-
) -> Generator[None, None, None]:
|
|
44
|
-
"""Write the protocol code, install the plugin, and clean up after the test."""
|
|
45
|
-
write_protocol_code(new_note["externallyExposableId"], plugin_name, COMMANDS)
|
|
46
|
-
message_received_event, thread, ws = wait_for_log(
|
|
47
|
-
cast(str, settings.INTEGRATION_TEST_URL),
|
|
48
|
-
token.value,
|
|
49
|
-
f"Loading plugin '{plugin_name}",
|
|
50
|
-
)
|
|
51
|
-
install_plugin(plugin_name, token)
|
|
52
|
-
message_received_event.wait(timeout=15.0)
|
|
53
|
-
|
|
54
|
-
# unfortunately sometimes the log websocket just doesn't return any
|
|
55
|
-
# messages, so asserting on the state of the timeout here causes failures
|
|
56
|
-
# even though the delay itself will cause the waiting test to pass (because
|
|
57
|
-
# the plugin has been loaded).
|
|
58
|
-
# timeout_not_hit = message_received_event.wait(timeout=15.0)
|
|
59
|
-
# if not timeout_not_hit:
|
|
60
|
-
# ws.close()
|
|
61
|
-
# assert timeout_not_hit, f"plugin loading message timeout hit: Loading plugin '{plugin_name}"
|
|
62
|
-
|
|
63
|
-
yield
|
|
64
|
-
|
|
65
|
-
ws.close()
|
|
66
|
-
thread.join()
|
|
67
|
-
clean_up_files_and_plugins(plugin_name, token)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
@pytest.mark.integtest
|
|
71
|
-
def test_protocol_that_inserts_every_command(
|
|
72
|
-
write_and_install_protocol_and_clean_up: None, token: MaskedValue, new_note: dict
|
|
73
|
-
) -> None:
|
|
74
|
-
"""Test that the protocol inserts every command."""
|
|
75
|
-
trigger_plugin_event(token)
|
|
76
|
-
|
|
77
|
-
commands_in_body = get_original_note_body_commands(new_note["id"], token)
|
|
78
|
-
|
|
79
|
-
# TODO: Temporary workaround to ignore the updateGoal command until the integration test instance is fixed.
|
|
80
|
-
command_keys = [c.Meta.key for c in COMMANDS]
|
|
81
|
-
assert len(command_keys) == len(commands_in_body)
|
|
82
|
-
for i, command_key in enumerate(command_keys):
|
|
83
|
-
assert commands_in_body[i] == command_key
|
|
File without changes
|