API Reference¶
Auto-generated from source docstrings.
Clients¶
ConfigClient¶
opendecree.ConfigClient(target, *, subject=None, role='superadmin', tenant_id=None, token=None, insecure=True, credentials=None, timeout=10.0, retry=None, check_version=False, interceptors=None, otel=False)
¶
Synchronous client for reading and writing OpenDecree configuration values.
Use as a context manager for clean channel lifecycle::
with ConfigClient("localhost:9090", subject="myapp") as client:
val = client.get("tenant-id", "payments.fee")
retries = client.get("tenant-id", "payments.retries", int)
Create a new ConfigClient.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
str
|
gRPC server address (e.g., |
required |
subject
|
str | None
|
Identity for |
None
|
role
|
str
|
Role for |
'superadmin'
|
tenant_id
|
str | None
|
Default tenant for |
None
|
token
|
str | None
|
Bearer token. When set, metadata headers are not sent.
On a TLS channel the token is embedded via
|
None
|
insecure
|
bool
|
Use plaintext (no TLS). Defaults to True for local dev. Do not combine with token in production. |
True
|
credentials
|
ChannelCredentials | None
|
TLS channel credentials. Overrides insecure. |
None
|
timeout
|
float
|
Default per-RPC timeout in seconds. Defaults to 10. |
10.0
|
retry
|
RetryConfig | None
|
Retry configuration. Defaults to |
None
|
check_version
|
bool
|
When True, run :meth: |
False
|
interceptors
|
list[Any] | None
|
Optional list of
:class: |
None
|
otel
|
bool
|
When True, wire an OpenTelemetry gRPC client interceptor so
get/set/watch RPCs appear in your application traces. Requires
|
False
|
server_version
property
¶
Deprecated. Use :meth:get_server_version instead.
check_compatibility()
¶
Check that the server version is compatible with this SDK.
Fetches the server version (cached) and compares it against
opendecree.SUPPORTED_SERVER_VERSION.
Raises:
| Type | Description |
|---|---|
IncompatibleServerError
|
If the server version is outside the supported range. |
UnavailableError
|
If the server is unreachable. |
close()
¶
Close the underlying gRPC channel.
get(tenant_id, field_path, value_type=None, *, nullable=False)
¶
Get a config value, optionally converting to a specific type.
Without a type argument, returns the raw string value. With a type argument, converts and returns the typed value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str
|
Tenant UUID. |
required |
field_path
|
str
|
Dot-separated field path (e.g., "payments.fee"). |
required |
value_type
|
type | None
|
Target type (str, int, float, bool, timedelta). Defaults to str. |
None
|
nullable
|
bool
|
If True, return None for null/unset values instead of raising. |
False
|
Returns:
| Type | Description |
|---|---|
object
|
The config value, converted to the requested type. |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the field has no value (and nullable is False). |
TypeMismatchError
|
If the value cannot be converted to the requested type. |
get_all(tenant_id)
¶
Get all config values for a tenant.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str
|
Tenant UUID. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
A dict mapping field paths to their string values. |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the tenant does not exist. |
get_server_version()
¶
Fetch the server's version, cached after first call.
Returns:
| Type | Description |
|---|---|
ServerVersion
|
ServerVersion with version and commit strings. |
Raises:
| Type | Description |
|---|---|
UnavailableError
|
If the server is unreachable. |
set(tenant_id, field_path, value, *, description=None, value_description=None, expected_checksum=None, idempotency_key=None)
¶
Set a config value.
value is a native Python value — str, int, float,
bool, datetime, timedelta, dict, list, or URL
(for url-typed fields; a plain str targets string-typed
fields). The SDK picks the wire representation matching value's
runtime type, which the server then validates against the field's
declared schema type — passing the wrong Python type raises
InvalidArgumentError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str
|
Tenant UUID. |
required |
field_path
|
str
|
Dot-separated field path (e.g., |
required |
value
|
ConfigValue
|
The value, as a Python type matching the field's schema type. |
required |
description
|
str | None
|
Optional version-level description for the audit log. |
None
|
value_description
|
str | None
|
Optional description stored with this specific value. |
None
|
expected_checksum
|
str | None
|
When set, the server rejects the write if the current value's checksum does not match (optimistic concurrency). |
None
|
idempotency_key
|
str | None
|
When provided, the request is retried on
|
None
|
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the field does not exist in the schema. |
LockedError
|
If the field is locked. |
InvalidArgumentError
|
If the value fails validation. |
ChecksumMismatchError
|
If |
set_many(tenant_id, updates, *, description=None, idempotency_key=None)
¶
Atomically set multiple config values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str
|
Tenant UUID. |
required |
updates
|
list[FieldUpdate]
|
List of :class: |
required |
description
|
str | None
|
Optional version-level description for the audit log. |
None
|
idempotency_key
|
str | None
|
When provided, the request is retried on
|
None
|
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If a field does not exist in the schema. |
LockedError
|
If any field is locked. |
InvalidArgumentError
|
If any value fails validation. |
ChecksumMismatchError
|
If any |
set_null(tenant_id, field_path, *, idempotency_key=None)
¶
Set a config field to null.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str
|
Tenant UUID. |
required |
field_path
|
str
|
Dot-separated field path. |
required |
idempotency_key
|
str | None
|
When provided, the request is retried on
|
None
|
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the field does not exist in the schema. |
LockedError
|
If the field is locked. |
watch(tenant_id)
¶
Create a config watcher for a tenant.
Use as a context manager — auto-starts on enter, auto-stops on exit::
with client.watch("tenant-id") as watcher:
fee = watcher.field("payments.fee", float, default=0.01)
print(fee.value)
The watcher uses the client's gRPC channel and auth settings.
AsyncConfigClient¶
opendecree.AsyncConfigClient(target, *, subject=None, role='superadmin', tenant_id=None, token=None, insecure=True, credentials=None, timeout=10.0, retry=None, check_version=False, interceptors=None, otel=False)
¶
Asynchronous client for reading and writing OpenDecree configuration values.
Use as an async context manager::
async with AsyncConfigClient("localhost:9090", subject="myapp") as client:
val = await client.get("tenant-id", "payments.fee")
retries = await client.get("tenant-id", "payments.retries", int)
Create a new AsyncConfigClient.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
str
|
gRPC server address (e.g., |
required |
subject
|
str | None
|
Identity for |
None
|
role
|
str
|
Role for |
'superadmin'
|
tenant_id
|
str | None
|
Default tenant for |
None
|
token
|
str | None
|
Bearer token. When set, metadata headers are not sent.
On a TLS channel the token is embedded via
|
None
|
insecure
|
bool
|
Use plaintext (no TLS). Defaults to True for local dev. Do not combine with token in production. |
True
|
credentials
|
ChannelCredentials | None
|
TLS channel credentials. Overrides insecure. |
None
|
timeout
|
float
|
Default per-RPC timeout in seconds. Defaults to 10. |
10.0
|
retry
|
RetryConfig | None
|
Retry configuration. Defaults to |
None
|
check_version
|
bool
|
When True, run :meth: |
False
|
interceptors
|
list[Any] | None
|
Optional list of :class: |
None
|
otel
|
bool
|
When True, wire an OpenTelemetry gRPC client interceptor so
get/set/watch RPCs appear in your application traces. Requires
|
False
|
check_compatibility()
async
¶
Check that the server version is compatible with this SDK.
Fetches the server version (cached) and compares it against
opendecree.SUPPORTED_SERVER_VERSION.
Raises:
| Type | Description |
|---|---|
IncompatibleServerError
|
If the server version is outside the supported range. |
UnavailableError
|
If the server is unreachable. |
close()
async
¶
Close the underlying gRPC channel.
get(tenant_id, field_path, value_type=None, *, nullable=False)
async
¶
Get a config value, optionally converting to a specific type.
Without a type argument, returns the raw string value. With a type argument, converts and returns the typed value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str
|
Tenant UUID. |
required |
field_path
|
str
|
Dot-separated field path (e.g., "payments.fee"). |
required |
value_type
|
type | None
|
Target type (str, int, float, bool, timedelta). Defaults to str. |
None
|
nullable
|
bool
|
If True, return None for null/unset values instead of raising. |
False
|
Returns:
| Type | Description |
|---|---|
object
|
The config value, converted to the requested type. |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the field has no value (and nullable is False). |
TypeMismatchError
|
If the value cannot be converted to the requested type. |
get_all(tenant_id)
async
¶
Get all config values for a tenant.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str
|
Tenant UUID. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
A dict mapping field paths to their string values. |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the tenant does not exist. |
get_server_version()
async
¶
Fetch the server's version, cached after first call.
Returns:
| Type | Description |
|---|---|
ServerVersion
|
ServerVersion with version and commit strings. |
Raises:
| Type | Description |
|---|---|
UnavailableError
|
If the server is unreachable. |
set(tenant_id, field_path, value, *, description=None, value_description=None, expected_checksum=None, idempotency_key=None)
async
¶
Set a config value.
value is a native Python value — str, int, float,
bool, datetime, timedelta, dict, list, or URL
(for url-typed fields; a plain str targets string-typed
fields). The SDK picks the wire representation matching value's
runtime type, which the server then validates against the field's
declared schema type — passing the wrong Python type raises
InvalidArgumentError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str
|
Tenant UUID. |
required |
field_path
|
str
|
Dot-separated field path (e.g., |
required |
value
|
ConfigValue
|
The value, as a Python type matching the field's schema type. |
required |
description
|
str | None
|
Optional version-level description for the audit log. |
None
|
value_description
|
str | None
|
Optional description stored with this specific value. |
None
|
expected_checksum
|
str | None
|
When set, the server rejects the write if the current value's checksum does not match (optimistic concurrency). |
None
|
idempotency_key
|
str | None
|
When provided, the request is retried on
|
None
|
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the field does not exist in the schema. |
LockedError
|
If the field is locked. |
InvalidArgumentError
|
If the value fails validation. |
ChecksumMismatchError
|
If |
set_many(tenant_id, updates, *, description=None, idempotency_key=None)
async
¶
Atomically set multiple config values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str
|
Tenant UUID. |
required |
updates
|
list[FieldUpdate]
|
List of :class: |
required |
description
|
str | None
|
Optional version-level description for the audit log. |
None
|
idempotency_key
|
str | None
|
When provided, the request is retried on
|
None
|
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If a field does not exist in the schema. |
LockedError
|
If any field is locked. |
InvalidArgumentError
|
If any value fails validation. |
ChecksumMismatchError
|
If any |
set_null(tenant_id, field_path, *, idempotency_key=None)
async
¶
Set a config field to null.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str
|
Tenant UUID. |
required |
field_path
|
str
|
Dot-separated field path. |
required |
idempotency_key
|
str | None
|
When provided, the request is retried on
|
None
|
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the field does not exist in the schema. |
LockedError
|
If the field is locked. |
watch(tenant_id)
¶
Create an async config watcher for a tenant.
Use as an async context manager — auto-starts on enter, auto-stops on exit::
async with client.watch("tenant-id") as watcher:
fee = watcher.field("payments.fee", float, default=0.01)
print(fee.value)
The watcher uses the client's gRPC channel and auth settings.
Watchers¶
ConfigWatcher¶
opendecree.ConfigWatcher(stub, pb2, tenant_id, timeout)
¶
Watches a tenant's configuration for live changes.
Created via client.watch(). Use as a context manager — auto-starts on enter, auto-stops on exit.
field(path, type_, *, default, on_callback_error=None, max_queue_size=_DEFAULT_MAX_QUEUE_SIZE)
¶
Register a field to watch.
Must be called before the watcher is started (before enter).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Dot-separated field path (e.g., "payments.fee"). |
required |
type_
|
type[T]
|
Python type to convert values to (str, int, float, bool, timedelta). |
required |
default
|
T
|
Default value when the field is null or not set. |
required |
on_callback_error
|
Callable[[Exception], None] | None
|
Optional hook called with the exception when an on_change callback raises. If not set, the exception is logged. The hook may re-raise to terminate the watcher's background loop. |
None
|
max_queue_size
|
int
|
Maximum number of unread changes buffered. When the
queue is full, the oldest entry is dropped and |
_DEFAULT_MAX_QUEUE_SIZE
|
Returns:
| Type | Description |
|---|---|
WatchedField[T]
|
A WatchedField that tracks the live value. |
start()
¶
Start watching — loads initial snapshot and subscribes to changes.
stop()
¶
Stop watching and clean up the background thread.
WatchedField¶
opendecree.WatchedField(path, type_, default, *, on_callback_error=None, max_queue_size=_DEFAULT_MAX_QUEUE_SIZE)
¶
Bases: _WatchedFieldBase[T]
A live, thread-safe configuration field with a typed value.
Attributes are updated automatically by the watcher's background thread.
dropped_changes
property
¶
Number of changes dropped because the queue was full.
value
property
¶
The current value — always fresh, thread-safe.
changes()
¶
Blocking iterator that yields Change events for this field.
Blocks until a change arrives or the watcher is stopped. Yields Change objects with old_value and new_value as strings.
AsyncConfigWatcher¶
opendecree.AsyncConfigWatcher(stub, pb2, tenant_id, timeout, metadata=None)
¶
Watches a tenant's configuration for live changes (async variant).
Created via async_client.watch(). Use as an async context manager — auto-starts on enter, auto-stops on exit.
field(path, type_, *, default, on_callback_error=None, max_queue_size=_DEFAULT_MAX_QUEUE_SIZE)
¶
Register a field to watch.
Must be called before the watcher is started (before aenter).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Dot-separated field path (e.g., "payments.fee"). |
required |
type_
|
type[T]
|
Python type to convert values to (str, int, float, bool, timedelta). |
required |
default
|
T
|
Default value when the field is null or not set. |
required |
on_callback_error
|
Callable[[Exception], None] | None
|
Optional hook called with the exception when an on_change callback raises. If not set, the exception is logged. The hook may re-raise to terminate the watcher's background task. |
None
|
max_queue_size
|
int
|
Maximum number of unread changes buffered. When the
queue is full, the oldest entry is dropped and |
_DEFAULT_MAX_QUEUE_SIZE
|
Returns:
| Type | Description |
|---|---|
AsyncWatchedField[T]
|
An AsyncWatchedField that tracks the live value. |
start()
async
¶
Start watching — loads initial snapshot and subscribes to changes.
stop()
async
¶
Stop watching and cancel the background task.
AsyncWatchedField¶
opendecree.AsyncWatchedField(path, type_, default, *, on_callback_error=None, max_queue_size=_DEFAULT_MAX_QUEUE_SIZE)
¶
Bases: _WatchedFieldBase[T]
A live configuration field with a typed value (async variant).
Updated automatically by the watcher's asyncio task.
Data Types¶
Change¶
opendecree.Change(field_path, old_value, new_value, version, changed_by='')
dataclass
¶
A configuration change event from a subscription.
Attributes:
| Name | Type | Description |
|---|---|---|
field_path |
str
|
Dot-separated field path that changed. |
old_value |
str | None
|
Previous value as a string, or |
new_value |
str | None
|
New value as a string, or |
version |
int
|
Config version number after this change. |
changed_by |
str
|
Identity of who made the change. |
FieldUpdate¶
opendecree.FieldUpdate(field_path, value, expected_checksum=None, value_description=None)
dataclass
¶
A single field update for use with :meth:ConfigClient.set_many.
Attributes:
| Name | Type | Description |
|---|---|---|
field_path |
str
|
Dot-separated field path (e.g., |
value |
ConfigValue
|
The value as a native Python type matching the field's schema
type — |
expected_checksum |
str | None
|
When set, the server rejects the write if the current value's checksum does not match (optimistic concurrency). |
value_description |
str | None
|
Optional description stored with this specific value. |
ServerVersion¶
opendecree.ServerVersion(version, commit)
dataclass
¶
Server version information from the ServerService.
Attributes:
| Name | Type | Description |
|---|---|---|
version |
str
|
Semantic version string (e.g., |
commit |
str
|
Git commit hash of the server build. |
RetryConfig¶
opendecree.RetryConfig(max_attempts=3, initial_backoff=0.1, max_backoff=5.0, multiplier=2.0, retryable_codes=(grpc.StatusCode.UNAVAILABLE, grpc.StatusCode.DEADLINE_EXCEEDED, grpc.StatusCode.RESOURCE_EXHAUSTED), total_timeout=None)
dataclass
¶
Configuration for retry behavior.
Attributes:
| Name | Type | Description |
|---|---|---|
max_attempts |
int
|
Maximum number of attempts (including the first). |
initial_backoff |
float
|
Initial backoff duration in seconds. |
max_backoff |
float
|
Maximum backoff duration in seconds. |
multiplier |
float
|
Backoff multiplier between attempts. |
retryable_codes |
tuple[StatusCode, ...]
|
gRPC status codes that trigger a retry. |
total_timeout |
float | None
|
Overall wall-clock budget in seconds shared across all attempts. When set, backoff sleeps are clipped to the remaining budget and no further attempt is made once the budget is exhausted. None means no global limit (original behavior). |
Exceptions¶
DecreeError¶
opendecree.DecreeError(message, code=None, *, trailing_metadata=None, retry_after=None)
¶
Bases: Exception
Base exception for all OpenDecree SDK errors.