Official Python SDK for the smplkit platform
Project description
smplkit Python SDK
The official Python SDK for smplkit — simple application infrastructure that just works.
Installation
pip install smplkit-sdk
Requirements
- Python 3.10+
Quick Start
The SDK ships two top-level clients, each with a clearly-scoped purpose:
| Client | Use case | Construction side effects |
|---|---|---|
SmplClient / AsyncSmplClient |
Runtime instrumentation — flag evaluation, config reads, log emission | Auto-registers a service context, starts a metrics thread, opens a websocket |
SmplManagementClient / AsyncSmplManagementClient |
Management / CRUD — setup scripts, CI/CD, admin tooling | None — pure HTTP setup |
Runtime: SmplClient
from smplkit import Context, SmplClient
with SmplClient(api_key="sk_api_...", environment="production", service="my-svc") as client:
# Resolve config values for the current environment
db = client.config.get("database") # {"host": "...", "port": 5432}
# Set the current request's context once (typically from middleware) —
# contextvars provides per-request / per-thread isolation automatically.
client.set_context([
Context("user", request.user.id, plan=request.user.plan),
Context("account", request.account.id, region=request.account.region),
])
# Evaluate a flag — picks up the context set above.
checkout_v2 = client.flags.boolean_flag("checkout-v2", default=False)
if checkout_v2.get():
...
# Opt in to runtime logging level control
client.logging.install()
# Need to reach the management API from a runtime context?
# Every SmplClient owns an internal management client at `client.manage`.
cfg = client.manage.config.get("database")
set_context() returns a scope object that doubles as a with block, so you can override context for a single block (e.g. impersonation):
with client.set_context([Context("user", "u-impersonated", plan="enterprise")]):
if checkout_v2.get():
...
# original context restored here
For deterministic startup — pre-fetch all flags + configs and wait for the live-updates websocket before serving traffic — call client.wait_until_ready() once at boot.
Management: SmplManagementClient
from smplkit import SmplManagementClient
with SmplManagementClient(api_key="sk_api_...") as mgmt:
# Configs
cfg = mgmt.config.new("my_service", name="My Service")
cfg.save()
configs = mgmt.config.list()
# Flags
flag = mgmt.flags.new_boolean_flag("checkout-v2", default=False)
flag.save()
flags = mgmt.flags.list()
# Loggers + log groups
logger = mgmt.loggers.new("sql", name="SQL Logger")
logger.save()
grp = mgmt.log_groups.new("databases", name="Databases")
grp.save()
# App-service-owned resources
for env in mgmt.environments.list():
print(env.id)
mgmt.contexts.register([...])
settings = mgmt.account_settings.get()
The management client takes only api_key (plus optional profile, base_domain, scheme, debug) — environment and service have no meaning for CRUD work and are deliberately rejected.
For async usage, swap SmplClient → AsyncSmplClient and SmplManagementClient → AsyncSmplManagementClient; method bodies become await-able:
from smplkit import AsyncSmplClient, AsyncSmplManagementClient
async with AsyncSmplClient(api_key="sk_api_...", environment="prod", service="svc") as client:
db = await client.config.get("database")
async with AsyncSmplManagementClient(api_key="sk_api_...") as mgmt:
cfg = await mgmt.config.get("my_service")
configs = await mgmt.config.list()
Which client should I use?
- Inside a request handler / running service →
SmplClient. You want lazy-fetched runtime state, the context registration loop, metrics, and the live-update websocket. - In a setup script / CI job / admin CLI / seeder →
SmplManagementClient. No runtime side effects, no auto-registered service rows leaking into target accounts, no websocket dangling open.
The two clients can be used together in the same process — e.g. a runtime app that occasionally needs to reach into the management API for an admin endpoint. To save you from juggling two clients, every SmplClient exposes a built-in management client at client.manage (sharing HTTP transports under the hood); reach for SmplManagementClient directly only for setup scripts, CI jobs, and admin tooling that have no runtime side effects to begin with.
Management namespaces
SmplManagementClient (and client.manage on the runtime client) exposes eight flat namespaces (one per resource family):
| Namespace | Resource |
|---|---|
manage.contexts |
Context instances (register / list / get / delete) |
manage.context_types |
Targeting-rule entity schemas |
manage.environments |
Environments (built-ins + AD_HOC) |
manage.account_settings |
Per-account settings |
manage.config |
Smpl Config CRUD |
manage.flags |
Smpl Flags CRUD |
manage.loggers |
Smpl Logging logger CRUD |
manage.log_groups |
Smpl Logging log-group CRUD |
Logging Adapters
client.logging.install() auto-loads adapters for every supported framework it finds installed. Two adapters ship with the SDK:
| Adapter | Covers |
|---|---|
stdlib-logging |
Python logging.getLogger(...) — discovered and managed automatically |
loguru |
The loguru library — requires pip install smplkit-sdk[loguru] |
Both are registered as smplkit.logging.adapters entry points in pyproject.toml, so they are discovered via importlib.metadata at install() time with no extra wiring.
Adding a custom adapter — implement LoggingAdapter and register it before install():
from smplkit.logging.adapters.base import LoggingAdapter
class StructlogAdapter(LoggingAdapter):
@property
def name(self) -> str:
return "structlog"
def discover(self): ...
def apply_level(self, name, level): ...
def install_hook(self, on_new_logger): ...
def uninstall_hook(self): ...
client.logging.register_adapter(StructlogAdapter())
client.logging.install()
Calling register_adapter() disables auto-loading — only the adapters you register are used.
Packaging an adapter for auto-discovery — declare the entry point in your package's pyproject.toml so it is picked up without any caller code change:
[project.entry-points."smplkit.logging.adapters"]
structlog = "my_package.adapter:StructlogAdapter"
Configuration
All settings are resolved from three sources, in order of precedence:
- Constructor arguments — highest priority, always wins.
- Environment variables — e.g.
SMPLKIT_API_KEY,SMPLKIT_ENVIRONMENT. - Configuration file (
~/.smplkit) — INI-format with profile support. - Defaults — built-in SDK defaults.
Configuration File
The ~/.smplkit file supports a [common] section (applied to all profiles) and named profiles:
[common]
environment = production
service = my-app
[default]
api_key = sk_api_abc123
[local]
base_domain = localhost
scheme = http
api_key = sk_api_local_xyz
environment = development
debug = true
Constructor Examples
# Use a named profile
client = SmplClient(profile="local")
# Or configure explicitly
client = SmplClient(
api_key="sk_api_...",
environment="production",
service="my-service",
)
For the complete configuration reference, see the Configuration Guide.
Error Handling
All SDK errors extend smplkit.Error:
from smplkit import Error, NotFoundError
try:
config = mgmt.config.get("nonexistent")
except NotFoundError:
print("Config not found")
except Error as e:
print(f"SDK error: {e}")
The error classes shadow built-ins (ConnectionError, TimeoutError, ValidationError), so import them from smplkit rather than relying on from smplkit import *, or alias on import (e.g. from smplkit import NotFoundError as SmplNotFound) if that collides with your own names.
| Exception | Cause |
|---|---|
NotFoundError |
Resource not found |
ConflictError |
Conflict (e.g., has children) |
ValidationError |
Validation error |
TimeoutError |
Request timed out |
ConnectionError |
Network connectivity issue |
Error |
Any other SDK error |
Debug Logging
Set SMPLKIT_DEBUG=1 to enable verbose diagnostic output to stderr. This is useful for troubleshooting real-time level changes, WebSocket connectivity, and SDK initialization. Debug output bypasses the managed logging framework and writes directly to stderr.
SMPLKIT_DEBUG=1 python my_app.py
Accepted values: 1, true, yes (case-insensitive). Any other value (or unset) disables debug output.
Documentation
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file smplkit_sdk-3.2.37.tar.gz.
File metadata
- Download URL: smplkit_sdk-3.2.37.tar.gz
- Upload date:
- Size: 366.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c03f1acbce0673781f5fe006c435d8adc6a13ebfa87ad62e3ceadddad7ceddec
|
|
| MD5 |
a9be0406ac58ca26fcf9ebfb0b9970d2
|
|
| BLAKE2b-256 |
164670330b47e67942293cf8cefe7710fe3cffe375e187573196120be192ef7d
|
Provenance
The following attestation bundles were made for smplkit_sdk-3.2.37.tar.gz:
Publisher:
ci-cd.yml on smplkit/python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
smplkit_sdk-3.2.37.tar.gz -
Subject digest:
c03f1acbce0673781f5fe006c435d8adc6a13ebfa87ad62e3ceadddad7ceddec - Sigstore transparency entry: 1506883479
- Sigstore integration time:
-
Permalink:
smplkit/python-sdk@00c757a186b1dab40f00e809623d91f178564d6d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/smplkit
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci-cd.yml@00c757a186b1dab40f00e809623d91f178564d6d -
Trigger Event:
push
-
Statement type:
File details
Details for the file smplkit_sdk-3.2.37-py3-none-any.whl.
File metadata
- Download URL: smplkit_sdk-3.2.37-py3-none-any.whl
- Upload date:
- Size: 555.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
729bab3d5ba6ff279a4bd7c637b583784cee10ca60424d88928d8fb4d49ddbeb
|
|
| MD5 |
3a134a247a3f9238a2a6754daf2ee073
|
|
| BLAKE2b-256 |
437206b0347dfda9af78efdd80bba3cb85ed5f0a776417c2903c4ad86e82b2c3
|
Provenance
The following attestation bundles were made for smplkit_sdk-3.2.37-py3-none-any.whl:
Publisher:
ci-cd.yml on smplkit/python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
smplkit_sdk-3.2.37-py3-none-any.whl -
Subject digest:
729bab3d5ba6ff279a4bd7c637b583784cee10ca60424d88928d8fb4d49ddbeb - Sigstore transparency entry: 1506883569
- Sigstore integration time:
-
Permalink:
smplkit/python-sdk@00c757a186b1dab40f00e809623d91f178564d6d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/smplkit
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci-cd.yml@00c757a186b1dab40f00e809623d91f178564d6d -
Trigger Event:
push
-
Statement type: