---
title: Variables
description: Variables in the dltHub Runtime Python SDK (dlthub_sdk)
keywords: [dlthub, runtime, python sdk, dlthub_sdk, api]
---
# Variables

<!-- generated from dlthub-client 0.28.8a3, do not edit -->

New to the SDK? [Getting started](getting-started.md) shows how to connect and use it.

## `Variables` {#variables}

The variables of one workspace, across its scopes.

A whole scope is read at once — there is no paging and no per-variable
address.

### `Variables.list()` {#variables-list}

```python
list(*, profile: str | None | Keep = KEEP) -> tuple[VariableScope, ...]
```

Read the workspace's variables, by scope.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `profile` | <code>str &#124; None &#124; <a href="client#keep">Keep</a></code> | Omit for every scope. Pass a profile name for that profile's scope, or [`WORKSPACE_PROFILE`](#WORKSPACE_PROFILE) for the workspace-level one. |

**Returns:** <code>tuple[<a href="#variablescope">VariableScope</a>, ...]</code> — One entry per scope read, always as scopes even when one was selected; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`BadRequest`](errors.md#badrequest) | The request was rejected as invalid; `message`, `code` and `fields` say why. |
| [`DataplaneTokenRejected`](errors.md#dataplanetokenrejected) | The data plane rejected the token the platform issued for it. |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

### `Variables.apply()` {#variables-apply}

```python
apply(
    *,
    profile: str | None,
    upserts: Mapping[str, str] | None = None,
    secrets: Mapping[str, str] | None = None,
    deletes: Sequence[str] | None = None,
) -> tuple[VariableChange, ...]
```

Store and remove variables in one scope, in a single request.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `profile` | <code>str &#124; None</code> | The scope to write to, or [`WORKSPACE_PROFILE`](#WORKSPACE_PROFILE) for the workspace-level one. Required: a write always names one scope. |
| `upserts` | <code>Mapping[str, str] &#124; None</code> | Names and values to store as plain text. |
| `secrets` | <code>Mapping[str, str] &#124; None</code> | Names and values to store as secrets. |
| `deletes` | <code>Sequence[str] &#124; None</code> | Names to remove. Removing an absent name is reported, not raised. |

**Returns:** <code>tuple[<a href="#variablechange">VariableChange</a>, ...]</code> — One result per name in the request; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`BadRequest`](errors.md#badrequest) | The request was rejected as invalid; `message`, `code` and `fields` say why. |
| [`Conflict`](errors.md#conflict) | The current state does not allow the call, e.g. the workspace is archived; `code` and `message` say why. |
| [`DataplaneTokenRejected`](errors.md#dataplanetokenrejected) | The data plane rejected the token the platform issued for it. |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |
| `ValueError` | Nothing to do, or a name appears in more than one of the three arguments, where the outcome would be undefined. |

### `Variables.set()` {#variables-set}

```python
set(name: str, value: str, *, profile: str | None, secret: bool = False) -> VariableChange
```

Store one variable.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `name` | <code>str</code> | The variable's name. |
| `value` | <code>str</code> | Its value. |
| `profile` | <code>str &#124; None</code> | The scope to write to, or [`WORKSPACE_PROFILE`](#WORKSPACE_PROFILE). |
| `secret` | <code>bool</code> | Store it as a secret, so reads never return the value. |

**Returns:** <code><a href="#variablechange">VariableChange</a></code> — What the platform did with it; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`BadRequest`](errors.md#badrequest) | The request was rejected as invalid; `message`, `code` and `fields` say why. |
| [`Conflict`](errors.md#conflict) | The current state does not allow the call, e.g. the workspace is archived; `code` and `message` say why. |
| [`DataplaneTokenRejected`](errors.md#dataplanetokenrejected) | The data plane rejected the token the platform issued for it. |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

### `Variables.delete()` {#variables-delete}

```python
delete(name: str, *, profile: str | None) -> VariableChange
```

Remove one variable.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `name` | <code>str</code> | The variable's name. |
| `profile` | <code>str &#124; None</code> | The scope to remove it from, or [`WORKSPACE_PROFILE`](#WORKSPACE_PROFILE). |

**Returns:** <code><a href="#variablechange">VariableChange</a></code> — What the platform did; a name that was not there comes back as attr:`VariableChangeStatus.NOT_FOUND` rather than raising. Awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`BadRequest`](errors.md#badrequest) | The request was rejected as invalid; `message`, `code` and `fields` say why. |
| [`Conflict`](errors.md#conflict) | The current state does not allow the call, e.g. the workspace is archived; `code` and `message` say why. |
| [`DataplaneTokenRejected`](errors.md#dataplanetokenrejected) | The data plane rejected the token the platform issued for it. |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

### `Variables.get()` {#variables-get}

```python
get(name: str, *, profile: str | None) -> Variable
```

Return one variable from one scope.

There is no single-variable endpoint, so this reads the whole scope.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `name` | <code>str</code> | The variable's name. |
| `profile` | <code>str &#124; None</code> | The scope to read, or [`WORKSPACE_PROFILE`](#WORKSPACE_PROFILE). |

**Returns:** <code><a href="#variable">Variable</a></code> — The variable; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`BadRequest`](errors.md#badrequest) | The request was rejected as invalid; `message`, `code` and `fields` say why. |
| [`DataplaneTokenRejected`](errors.md#dataplanetokenrejected) | The data plane rejected the token the platform issued for it. |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`NotFound`](errors.md#notfound) | No variable of that name in that scope. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

## `Variable` {#variable}

One variable, as the platform reports it.

A secret's `value` is `None` because it is withheld, not empty.

**Attributes**

| Name | Type | Description |
| --- | --- | --- |
| `name` | <code>str</code> | Environment variable name. |
| `secret` | <code>bool</code> | Whether the platform stores it as a secret. |
| `value` | <code>str &#124; None</code> | The value, or `None` for a secret. |
| `created_at` | <code>datetime</code> | When the variable was created. |
| `created_by` | <code>str</code> | ID of the user who created the variable. |
| `updated_at` | <code>datetime</code> | When the variable was last updated. |
| `updated_by` | <code>str</code> | ID of the user who last updated the variable. |

## `VariableChange` {#variablechange}

What a change did to one name.

**Attributes**

| Name | Type | Description |
| --- | --- | --- |
| `name` | <code>str</code> | Environment variable name. |
| `status` | <code><a href="#variablechangestatus">VariableChangeStatus</a></code> | What happened to this variable: `upserted` (created or updated), `removed`, or `not_found` (a delete named a variable that does not exist). |

## `VariableScope` {#variablescope}

The variables one profile sees, or the workspace-level set.

**Attributes**

| Name | Type | Description |
| --- | --- | --- |
| `profile` | <code>str &#124; None</code> | Profile owning this scope; `None` is the workspace-wide scope. |
| `variables` | <code>tuple[<a href="#variable">Variable</a>, ...]</code> | Variables in this scope, secrets redacted. |

## `VariableChangeStatus` {#variablechangestatus}

What became of one name in a change.

**Members**

| Member | Value | Description |
| --- | --- | --- |
| `UPSERTED` | `'upserted'` | Stored, whether it existed before or not. |
| `REMOVED` | `'removed'` | Deleted. |
| `NOT_FOUND` | `'not_found'` | Asked to be deleted, but was not there. |
| `UNKNOWN` | `'unknown'` | A status this SDK version does not know. |

## `WORKSPACE_PROFILE` {#WORKSPACE_PROFILE}

```python
WORKSPACE_PROFILE = None
```

The workspace-level variable scope, which every profile inherits.

Pass it as `profile` to read or write only that scope.
