Metadata-Version: 2.5
Name: canvas
Version: 0.253.0
Summary: SDK to customize event-driven actions in your Canvas instance
Author-email: Canvas Team <engineering@canvasmedical.com>
License-Expression: MIT
Requires-Python: <3.15,>=3.11
Requires-Dist: cookiecutter
Requires-Dist: cron-converter<2,>=1.2.1
Requires-Dist: cryptography>=45.0.5
Requires-Dist: defusedxml>=0.7.1
Requires-Dist: deprecation<3,>=2.1.0
Requires-Dist: django-stubs[compatible-mypy]<6,>=5.1.1
Requires-Dist: django-timezone-utils<0.16,>=0.15.0
Requires-Dist: django<6,>=5.1.1
Requires-Dist: env-tools<3,>=2.4.0
Requires-Dist: factory-boy>=3.3.3
Requires-Dist: frozendict>=2.4.6
Requires-Dist: grpcio<2,>=1.78.0
Requires-Dist: ipython<9,>=8.21.0
Requires-Dist: jsonschema<5,>=4.21.1
Requires-Dist: nh3<0.4,>=0.3.0
Requires-Dist: pathspec>=0.12.1
Requires-Dist: protobuf<7,>=6
Requires-Dist: psutil==7.2.2
Requires-Dist: psycopg[binary,pool]<4,>=3.3.3
Requires-Dist: pydantic<3,>=2.12.5
Requires-Dist: pyjwt==2.10.1
Requires-Dist: python-dotenv<2,>=1.0.1
Requires-Dist: python-logstash-async>=4.0.2
Requires-Dist: rapidfuzz<4,>=3.10.1
Requires-Dist: redis<6,>=5.0.4
Requires-Dist: requests
Requires-Dist: restrictedpython<8.3,>=8.0
Requires-Dist: sentry-sdk>=2.33.2
Requires-Dist: snowflake-connector-python==4.6.0
Requires-Dist: statsd<5,>=4.0.1
Requires-Dist: stripe>=14.1.0
Requires-Dist: typer
Requires-Dist: typing-extensions<5,>=4.14.1
Requires-Dist: websocket-client<2,>=1.7.0
Provides-Extra: test-utils
Requires-Dist: pytest-canvas; extra == 'test-utils'
Description-Content-Type: text/markdown

[![codecov](https://codecov.io/gh/canvas-medical/canvas-plugins/graph/badge.svg?token=P8JJUOJ8FH)](https://codecov.io/gh/canvas-medical/canvas-plugins)

### Getting Started

`pip install canvas`

### Authentication

The CLI authenticates in two ways, and which one a command uses depends on where it sends the request:

| | Canvas Platform sign-in | Instance API credentials |
| --- | --- | --- |
| Set up with | `canvas login`, in your browser, or a [service account token](#service-accounts-for-cicd) in `CANVAS_PLATFORM_TOKEN` | `~/.canvas/credentials.ini`, written by hand |
| Signs in as | you, as a member of your Canvas Platform organizations, or a service account of one organization | an OAuth client (`client_id` / `client_secret`) registered on one instance |
| Reaches | every instance your organizations can deploy to | the instance named by each section of the file |
| Stored in | `~/.canvas/platform-credentials.json`, or the `CANVAS_PLATFORM_TOKEN` environment variable | `credentials.ini`, with instance tokens cached in `~/.canvas/tokens.json` |
| Used by | `login`, `logout`, `init`, `deploy`, `clone`, and `config set` / `config unset` / `uninstall` for a plugin Canvas Platform manages | `install`, `enable`, `disable`, `list`, `config list`, `logs`, `namespace`, and `config set` / `config unset` / `uninstall` for a plugin Canvas Platform does not manage |

A machine can hold both at once, and the CLI picks per command and per plugin as described in [Which plugins go through Canvas Platform](#which-plugins-go-through-canvas-platform).

#### Migrating from `credentials.ini` to Canvas Platform

Installing plugins straight onto an instance with `credentials.ini` is deprecated in favor of deploying through Canvas Platform, and is no longer supported as of December 14, 2026. Until then it keeps working alongside `canvas login`. `canvas install` prints a deprecation warning on every run, and every other command points to this section at most once a day. To move a plugin over:

1. Run `canvas login`. It lists the prefix of each organization you belong to.
2. Rename the plugin to `<org prefix>__<package>`: the manifest `name`, the package folder, and the package's own imports.
3. Run `canvas deploy <plugin dir> --instance <instance>`, then set its variables with `canvas config set <name> KEY=VALUE --instance <instance>`.
4. The renamed plugin is a separate plugin from the one installed under the old name, so remove the old one from the instance with `canvas disable <old name> --host <instance>` and `canvas uninstall <old name> --host <instance>`.

#### Instance API credentials

Create a file `~/.canvas/credentials.ini` and add the client_id and client_secret credentials for each of your Canvas instances. You can define your default host with `is_default=true`. If no default is explicitly defined, the Canvas CLI will use the first instance in the file as the default for each of the CLI commands.

**Example:**

```
[my-canvas-instance]
client_id=myclientid
client_secret=myclientsecret

[my-dev-canvas-instance]
client_id=devclientid
client_secret=devclientsecret
is_default=true

[localhost]
client_id=localclientid
client_secret=localclientsecret
```

### Canvas Platform

Canvas Platform hosts a plugin's git repository and deploys it to the instances it manages. Sign in once per machine with `canvas login`, which opens your browser; the session is stored per platform in `~/.canvas/platform-credentials.json`, readable only by you, and refreshes itself. `canvas login --platform <url>` or `CANVAS_PLATFORM_URL` points the CLI at a platform other than https://platform.canvasmedical.com, and later commands keep using the platform you last signed in to.

A plugin deployed through Canvas Platform has a publisher-prefixed name, `<org prefix>__<package>` (for example `acme__intake`), used for the manifest `name`, the package folder and its imports. `canvas login` lists the prefix of each organization you belong to, and the prefix decides which organization publishes the plugin. `canvas install` and `canvas validate` accept names with or without a prefix.

#### Which plugins go through Canvas Platform

`canvas config set`, `canvas config unset` and `canvas uninstall` work for plugins Canvas Platform manages and for plugins installed straight onto an instance, and each decides per plugin:

- A name without a prefix, or a machine that is not signed in, goes straight to the instance, as `canvas install` always has.
- Otherwise the CLI asks platform for the plugin. If platform has it, the command goes through platform; if not, it goes to the instance.

`--host` names an instance for a plugin platform does not manage, and is refused for one it does. When an instance refuses `canvas install` because platform manages that plugin, the message names `canvas deploy`.

git signs in to platform's git server through `canvas git-credential`, a hidden command `canvas deploy`, `canvas init` and `canvas clone` register as the repository's credential helper. It mints a one-hour git token for the plugin named in the repository path, and the repository's configuration keeps any other credential helper, such as macOS's keychain, from answering for that server.

```console
$ canvas login
$ canvas init                                   # scaffolds acme__my_cool_plugin and registers it
$ canvas deploy my-cool-plugin/acme__my_cool_plugin --instance acme-staging
$ canvas config set acme__my_cool_plugin API_URL=https://api.example.com --instance acme-staging
```

#### Service accounts for CI/CD

A CI/CD pipeline (GitHub Actions, GitLab CI, and the like) signs in to Canvas Platform as a service account, an identity that belongs to an organization rather than to a person, so the pipeline keeps working when whoever set it up leaves, and Platform's audit log names the account behind each push and deploy. An organization admin, plugin developer or deploy manager creates one on the Credentials page in Canvas Platform. A service account can hold the plugin developer and deploy manager roles, and never more than its creator holds. Its token is shown once and is valid for a year.

Store the token as a CI secret and expose it to the job as `CANVAS_PLATFORM_TOKEN`; no `canvas login` is needed:

```yaml
- run: pip install canvas
- run: canvas deploy my-plugin/acme__my_plugin --instance acme-staging --yes
  env:
    CANVAS_PLATFORM_TOKEN: ${{ secrets.CANVAS_PLATFORM_TOKEN }}
```

- When `CANVAS_PLATFORM_TOKEN` is set, every command uses it in place of a `canvas login` session, including the git pushes `canvas deploy` makes, and it takes precedence over a session already stored on the machine.
- The token does not refresh. Rotating or revoking the service account on the Credentials page ends it, and the CLI's next request says so. `canvas logout` does not touch it.
- `--yes` commits uncommitted changes without prompting. A deployment that needs consent for another plugin's custom data exits non-zero and lists the requests, since only a person at a terminal answers those.
- `CANVAS_PLATFORM_URL` points the job at a platform other than https://platform.canvasmedical.com.

**Usage**:

```console
$ canvas [OPTIONS] COMMAND [ARGS]...
```

**Options**:

- `--version`
- `--help`: Show this message and exit.

**Commands**:

- `login`: Sign in to Canvas Platform through your browser
- `logout`: Sign out of Canvas Platform
- `whoami`: Show which Canvas Platform you are signed in to, and as whom
- `init`: Create a new plugin
- `deploy`: Publish a plugin to Canvas Platform and deploy it
- `clone`: Clone a plugin's repository from Canvas Platform
- `install`: Install a plugin into a Canvas instance
- `uninstall`: Uninstall a plugin
- `config`: List, set and clear plugin variables
- `disable`: Disable a plugin from a Canvas instance
- `enable`: Enable a plugin from a Canvas instance
- `list`: List all plugins from a Canvas instance
- `validate-manifest`: Validate the Canvas Manifest json file
- `logs`: Listen and print log streams from a Canvas instance

## `canvas login`

Sign in to Canvas Platform through your browser (OAuth authorization code with PKCE). The sign-in URL is also printed, for a machine without a browser.

**Usage**:

```console
$ canvas login [OPTIONS]
```

**Options**:

- `--platform TEXT`: Canvas Platform URL
- `--help`: Show this message and exit.

## `canvas logout`

Revoke this machine's Canvas Platform session and delete its stored tokens. A service account token in `CANVAS_PLATFORM_TOKEN` is left alone, and the command says that commands still act as that account.

**Usage**:

```console
$ canvas logout [OPTIONS]
```

**Options**:

- `--platform TEXT`: Canvas Platform URL
- `--help`: Show this message and exit.

## `canvas whoami`

Show the platform the CLI uses and where that choice came from (`--platform`, `CANVAS_PLATFORM_URL`, your last `canvas login`, or the default), then the account it signs in as, whether the credential is a `canvas login` session or `CANVAS_PLATFORM_TOKEN`, and each organization's plugin prefix and what you can do there. It asks platform, so a revoked or expired credential is reported rather than shown as signed in. No token is printed. Exits non-zero when not signed in.

**Usage**:

```console
$ canvas whoami [OPTIONS]
```

**Options**:

- `--platform TEXT`: Canvas Platform URL
- `--help`: Show this message and exit.

## `canvas init`

Create a new plugin. Signed in to Canvas Platform, the package is named `<org prefix>__<package>`, registered with platform, and given a git repository whose `origin` is platform. Signed out, it is named from the project name alone, and `init` says that `canvas deploy` refuses such a plugin until you run `canvas login` and `canvas init` again.

**Usage**:

```console
$ canvas init [OPTIONS] [PLUGIN_TYPE]
```

**Arguments**:

- `PLUGIN_TYPE`: `handler` (default) or `application`

**Options**:

- `--org TEXT`: Organization that publishes the plugin, when you can publish in several
- `--help`: Show this message and exit.

## `canvas deploy`

Publish a plugin's code to Canvas Platform and deploy it. The manifest `name` must be publisher-prefixed, and the package folder must have the same name, which deploy checks before committing or pushing. Deploy registers the plugin, points the repository's `origin` at platform with a credential helper, commits uncommitted changes after you confirm, pushes HEAD to `main`, deploys that commit and waits for each target's outcome. Consent requests for cross-plugin custom data access are answered inline at a terminal; under `--yes` or without a terminal, deploy lists them with the deployment id and exits non-zero without answering them. The repository is rooted at the directory containing the package. Without a terminal to confirm at, uncommitted changes are refused rather than committed unless `--yes` is passed.

**Usage**:

```console
$ canvas deploy [OPTIONS] PLUGIN_DIR
```

**Arguments**:

- `PLUGIN_DIR`: Path to the plugin package [required]

**Options**:

- `--instance TEXT`: Instance to deploy to, repeatable. Without it, deploy targets the only instance you can deploy to and otherwise lists the choices
- `--ref TEXT`: Deploy a pushed branch, tag or commit as-is, without pushing
- `--no-push`: Deploy the pushed `main` as-is, without pushing
- `--push-only`: Push HEAD to `main` without deploying it to any instance, so the plugin's code and its catalog listing are updated on Canvas Platform and no instance is needed. Takes no `--instance`, `--ref` or `--no-push`
- `-y, --yes`: Commit uncommitted changes without prompting, with the default message. Does not approve consent requests: a deployment that needs consent exits non-zero and lists them
- `--help`: Show this message and exit.

## `canvas clone`

Clone a plugin's repository from Canvas Platform with `origin` and the credential helper set, ready for `canvas deploy`.

**Usage**:

```console
$ canvas clone [OPTIONS] NAME [DIRECTORY]
```

**Arguments**:

- `NAME`: Plugin name, e.g. `acme__intake` [required]
- `DIRECTORY`: Where to clone it, a directory named after the plugin by default

## `canvas install`

Install a plugin into a Canvas instance.

**Usage**:

```console
$ canvas install [OPTIONS] PLUGIN_NAME
```

**Arguments**:

- `PLUGIN_NAME`: Path to plugin to install [required]

**Options**:

- `--host TEXT`: Canvas instance to connect to
- `--help`: Show this message and exit.

## `canvas uninstall`

Uninstall a plugin. A plugin Canvas Platform manages is removed by an uninstall deployment from each `--instance`, which is required. Any other plugin is removed from the instance directly.

**Usage**:

```console
$ canvas uninstall [OPTIONS] NAME
```

**Arguments**:

- `NAME`: Plugin name to uninstall [required]

**Options**:

- `--instance TEXT`: Instance to uninstall from, repeatable
- `--host TEXT`: Canvas instance to connect to, for a plugin Canvas Platform does not manage
- `--force`: Uninstall an enabled plugin from an instance directly
- `--help`: Show this message and exit.

## `canvas config set` / `canvas config unset`

Set or clear a plugin's variable values. For a plugin Canvas Platform manages, values are stored in platform and a configure deployment brings them to the running plugin; without `--instance`, the only instance it is installed on that you can configure is targeted. A variable's sensitivity comes from the manifest's `variables`, and `--secret` / `--variable` state it for a key no revision declares. For any other plugin, values are written to the instance directly, and `unset` sets them empty.

**Usage**:

```console
$ canvas config set [OPTIONS] PLUGIN_NAME [KEY=VALUE]...
$ canvas config unset [OPTIONS] PLUGIN_NAME KEY...
```

**Options**:

- `--instance TEXT`: Instance to configure, repeatable
- `--host TEXT`: Canvas instance to connect to, for a plugin Canvas Platform does not manage
- `--secret KEY=VALUE`, `--variable KEY=VALUE`: (`set` only) a sensitive or non-sensitive value for an undeclared key
- `--help`: Show this message and exit.

## `canvas enable`

Enable a plugin from a Canvas instance..

**Usage**:

```console
$ canvas enable [OPTIONS] NAME
```

**Arguments**:

- `NAME`: Plugin name to enable [required]

**Options**:

- `--host TEXT`: Canvas instance to connect to
- `--help`: Show this message and exit.

## `canvas disable`

Disable a plugin from a Canvas instance..

**Usage**:

```console
$ canvas disable [OPTIONS] NAME
```

**Arguments**:

- `NAME`: Plugin name to disable [required]

**Options**:

- `--host TEXT`: Canvas instance to connect to
- `--help`: Show this message and exit.

## `canvas list`

List all plugins from a Canvas instance.

**Usage**:

```console
$ canvas list [OPTIONS]
```

**Options**:

- `--host TEXT`: Canvas instance to connect to
- `--help`: Show this message and exit.

## `canvas validate-manifest`

Validate the Canvas Manifest json file.

**Usage**:

```console
$ canvas validate-manifest [OPTIONS] PACKAGE
```

**Arguments**:

- `PLUGIN_NAME`: Path to plugin to install [required]

**Options**:

- `--help`: Show this message and exit.

## `canvas logs`

Listens and prints log streams from the instance.

**Usage**:

```console
$ canvas logs [OPTIONS]
```

**Options**:

- `--host TEXT`: Canvas instance to connect to
- `--help`: Show this message and exit.
