# `sandloom.sdk.tenant`

Tenant binding and isolation, and the tenant kind (spec §7.1).

Public API 1.0 (spec §2.2, Appendix C).

`from sandloom.sdk.tenant import <name>`. Signatures in a terminal: `sandloom docs <name>`. Beginner names are the ones generated code and the examples use; any other name is advanced (mark its import line `# sandloom: advanced <reason>` in generated code and examples).

## Advanced

| Name | Kind | Summary |
| --- | --- | --- |
| [`bind_tenant`](<#bind_tenant>) | function | Bind `tenant_id` for the duration of the block. |
| [`current_tenant_id`](<#current_tenant_id>) | function | Return the tenant bound in the current context, or raise (fail closed). |
| [`current_tenant_id_optional`](<#current_tenant_id_optional>) | function | Return the bound tenant or `None` (does not raise). |
| [`scoped`](<#scoped>) | function | Add a fail-closed tenant filter to `stmt` for `model`. |
| [`tenant_filter`](<#tenant_filter>) | function | A `model.tenant_id == <current tenant>` clause (raises if unbound). |
| [`tenant_kind`](<#tenant_kind>) | async function | The kind of `tenant_id` from authoritative sources only (spec §7.1), memoised per request: `canonical` under `TENANCY_MODE=single`, \`pers... |
| [`TenantKind`](<#tenantkind>) | callable |  |
| [`unscoped`](<#unscoped>) | function | Disable tenant enforcement for deliberate admin/system work. |

## Advanced names

### `bind_tenant`

```
def bind_tenant(tenant_id: uuid.UUID) -> Iterator[uuid.UUID]
```

Bind `tenant_id` for the duration of the block.

### `current_tenant_id`

```
def current_tenant_id() -> uuid.UUID
```

Return the tenant bound in the current context, or raise (fail closed).

### `current_tenant_id_optional`

```
def current_tenant_id_optional() -> uuid.UUID | None
```

Return the bound tenant or `None` (does not raise).

### `scoped`

```
def scoped(stmt: Any, model: Any) -> Any
```

Add a fail-closed tenant filter to `stmt` for `model`.

`scoped(select(Task), Task)` is the explicit, hard-to-misuse read path: forgetting it is visible, and it raises rather than returning unscoped rows when no tenant is bound.

### `tenant_filter`

```
def tenant_filter(model: Any) -> Any
```

A `model.tenant_id == <current tenant>` clause (raises if unbound).

### `tenant_kind`

```
async def tenant_kind(tenant_id: UUID, *, ctx: AuthzContext | None = None) -> TenantKind
```

The kind of `tenant_id` from authoritative sources only (spec §7.1), memoised per request: `canonical` under `TENANCY_MODE=single`, `personal` when it is the caller's user id, `organization` when the membership contract confirms the caller's membership, else `unknown`. Without `ctx` it uses the request `current_context` authenticated.

### `TenantKind`

```
def TenantKind(*args, **kwargs)
```

*(no docstring)*

### `unscoped`

```
def unscoped() -> Iterator[None]
```

Disable tenant enforcement for deliberate admin/system work.

## Examples and related guides

- [Tenant isolation](<https://sandloom.dev/docs/modules/database/multi-tenancy/index.md>)
- [Python API overview](<https://sandloom.dev/docs/reference/sdk/index.md>)
