Clients¶
Kubex separates the API layer (Api[T]) from the HTTP transport layer. You can swap transports without changing any application code.
create_client()¶
The create_client() factory is the recommended way to get a client. It auto-detects which HTTP library is installed and returns an async context manager — async with ensures the underlying connection pool is closed cleanly:
from kubex.client import create_client
async with await create_client() as client:
# use the client
...
Auto-detection order: aiohttp is tried first, then httpx. If neither is installed, create_client() raises ImportError.
To force a specific client:
from kubex.client import create_client, ClientChoise
# Force aiohttp
client = await create_client(client_class=ClientChoise.AIOHTTP)
# Force httpx
client = await create_client(client_class=ClientChoise.HTTPX)
Pass a pre-built ClientConfiguration to skip the auto-loading of kubeconfig / in-cluster credentials:
from kubex.configuration import ClientConfiguration
config = ClientConfiguration(url="https://my-cluster:6443", token="my-token")
client = await create_client(configuration=config)
Pass options= to control how the client behaves at request time (timeouts, proxy, pool size, etc.). See ClientOptions below for details:
from kubex.client import ClientOptions, create_client
from kubex.core.params import Timeout
client = await create_client(
configuration=config,
options=ClientOptions(timeout=Timeout(total=30.0), log_api_warnings=False),
)
ClientOptions¶
ClientOptions carries per-process choices about how the HTTP client behaves. These settings have nothing to do with kubeconfig or the in-cluster environment — connection parameters live on ClientConfiguration.
from kubex.client import ClientOptions
from kubex.core.params import Timeout
options = ClientOptions(
timeout=Timeout(total=30.0),
log_api_warnings=True, # default
)
timeout¶
Controls the default HTTP timeout applied to every request made by this client. Accepted values:
| Value | Meaning |
|---|---|
... (the default) |
Use the HTTP library's own default (httpx: 5 s total; aiohttp: 300 s total, 30 s sock_connect) |
None |
Disable timeouts entirely |
int or float |
Treat as a total timeout in seconds; coerced to Timeout automatically |
Timeout(...) |
Use as-is for fine-grained per-phase control |
Individual calls can override this via the request_timeout= parameter. See Timeouts for the full picture.
log_api_warnings¶
When True (the default), kubex emits a Python UserWarning for every Warning: HTTP response header returned by the API server. The Kubernetes API server uses these headers to flag deprecated API usage (e.g. calling a removed API version). Set to False to silence them.
proxy¶
Configures an outbound HTTP proxy for all requests. Accepted values:
| Value | Meaning |
|---|---|
None (the default) |
No proxy |
str |
Single proxy URL for all requests, e.g. "http://proxy.corp.example.com:8080" |
dict[str, str] |
Per-scheme map with "http" and/or "https" keys |
# Single proxy URL (basic auth via userinfo)
options = ClientOptions(proxy="http://user:[email protected]:8080")
# Per-scheme map
options = ClientOptions(proxy={"https": "http://proxy.corp.example.com:8080"})
keep_alive¶
Whether to reuse idle connections (connection keep-alive). Set to False to close each connection immediately after use.
keep_alive_timeout¶
Idle-connection lifetime in seconds. Uses the three-state sentinel pattern:
| Value | Meaning |
|---|---|
... (the default) |
Library default (httpx: 5 s; aiohttp: 15 s) |
None |
Keep idle connections indefinitely (httpx only; aiohttp warns) |
float >= 0 |
Explicit lifetime in seconds |
# Keep idle connections for 60 seconds
options = ClientOptions(keep_alive_timeout=60.0)
# Indefinite (httpx only)
options = ClientOptions(keep_alive_timeout=None)
buffer_size¶
HTTP-response read buffer size in bytes. Uses the three-state sentinel pattern:
| Value | Meaning |
|---|---|
... (the default) |
Kubex default of 2**21 bytes (preserves current aiohttp behavior) |
None |
Library default (aiohttp: 2**16 bytes) |
int > 0 |
Explicit buffer size in bytes |
# Use a 1 MiB read buffer
options = ClientOptions(buffer_size=1024 * 1024)
# Use aiohttp's own default
options = ClientOptions(buffer_size=None)
httpx asymmetry
httpx has no equivalent buffer-size knob. Setting buffer_size to anything other
than ... on an httpx-backed client emits a UserWarning and is otherwise ignored.
ws_max_message_size¶
Maximum WebSocket frame size in bytes for exec, attach, and portforward. Uses the three-state sentinel pattern:
| Value | Meaning |
|---|---|
... (the default) |
Kubex default of 2**21 bytes (preserves current behavior on both backends) |
None |
No cap (passes 0 on the wire) |
int > 0 |
Explicit cap in bytes |
# Allow frames up to 8 MiB (for large exec output)
options = ClientOptions(ws_max_message_size=8 * 1024 * 1024)
# No cap
options = ClientOptions(ws_max_message_size=None)
pool_size¶
Total connection pool size (all hosts combined). Uses the three-state sentinel pattern:
| Value | Meaning |
|---|---|
... (the default) |
Library default (both backends: 100) |
None |
Unlimited |
int > 0 |
Explicit connection limit |
# Reduce pool to 10 connections total
options = ClientOptions(pool_size=10)
# Unlimited
options = ClientOptions(pool_size=None)
pool_size_per_host¶
Per-host connection pool size. Uses the three-state sentinel pattern:
| Value | Meaning |
|---|---|
... (the default) |
Library default (aiohttp: 0, meaning no per-host limit) |
None |
Unlimited |
int > 0 |
Explicit per-host limit |
httpx asymmetry
httpx has no per-host pool limit. Setting pool_size_per_host to anything other
than ... on an httpx-backed client emits a UserWarning and is otherwise ignored.
trust_env¶
When True, kubex enables environment-driven proxy configuration on both backends:
| Env var | Effect |
|---|---|
HTTP_PROXY / HTTPS_PROXY / ALL_PROXY |
Select an outbound proxy for matching requests |
NO_PROXY |
Exclude specific hosts from proxy routing |
~/.netrc (or $NETRC) |
Supply basic-auth credentials for the proxy host when the env proxy URL carries no embedded user:pass |
The default is False. This matches aiohttp's library default and overrides httpx's library default of True, making behavior symmetric across both backends out of the box.
# Read HTTPS_PROXY / HTTP_PROXY / NO_PROXY from the environment
options = ClientOptions(trust_env=True)
Canonical flow — HTTPS proxy with netrc credentials:
export HTTPS_PROXY=http://proxy.corp.example.com:3128
# ~/.netrc
# machine proxy.corp.example.com
# login alice
# password s3cret
options = ClientOptions(trust_env=True)
# Kubex reads HTTPS_PROXY, finds no user:pass in the URL, looks up
# proxy.corp.example.com in ~/.netrc, and configures the proxy with
# auth=("alice", "s3cret").
async with await create_client(options=options) as client:
...
Netrc scope: netrc is used for proxy credentials only. Kubex's per-request Authorization: Bearer … header always takes priority over any netrc-derived target-host Basic auth.
Conflict with options.proxy: when both trust_env=True and options.proxy are set, the explicit options.proxy wins and a UserWarning is emitted at client construction. The effective behavior is trust_env=False passed to the backend, so NO_PROXY cannot silently exempt the explicit proxy.
Backend asymmetries
WS_PROXY/WSS_PROXYenv vars are read by aiohttp only. On httpx,wss://upgrades useHTTPS_PROXY.SSL_CERT_FILE/SSL_CERT_DIRenv vars are read by httpx only (when no custom CA is configured). aiohttp does not read these.
Snapshot semantics (httpx only)
When a proxy env var (HTTPS_PROXY, HTTP_PROXY, ALL_PROXY, etc.) is set at construction time, Kubex's proxy-netrc resolver materializes it into an explicit httpx.Proxy(auth=...). Mutations to those env vars after create_client() returns are not reflected on the httpx backend.
When no proxy env var is set at construction time, httpx receives trust_env=True directly and re-reads env vars on every request (httpx's own default behavior).
The aiohttp backend always retains its native per-request env lookup regardless of whether a proxy was found at construction.
If snapshot behavior is unwanted on httpx, use the Custom underlying HTTP client escape hatch.
Backend asymmetries¶
Some ClientOptions fields behave differently (or are unsupported) depending on which HTTP backend is in use. A UserWarning is emitted on first use when a field has no effect.
| Field | httpx | aiohttp |
|---|---|---|
proxy=str |
proxy=str on AsyncClient |
proxy=str on ClientSession |
proxy=dict |
All entries applied via mounts= |
Only the entry matching the API server's URL scheme is used; other entries are dropped with a warning |
keep_alive=False |
Limits(max_keepalive_connections=0) |
TCPConnector(force_close=True) |
keep_alive_timeout |
Limits(keepalive_expiry=float\|None) |
TCPConnector(keepalive_timeout=float) — None is unsupported; warning emitted |
buffer_size |
Ignored — warning emitted | ClientSession(read_bufsize=int) |
ws_max_message_size |
aconnect_ws(max_message_size_bytes=int) |
ws_connect(max_msg_size=int) |
pool_size |
Limits(max_connections=int\|None) |
TCPConnector(limit=int) — None maps to 0 (unlimited) |
pool_size_per_host |
Ignored — warning emitted | TCPConnector(limit_per_host=int) — None maps to 0 (unlimited) |
trust_env=True |
If a proxy env var is found at construction, it is materialized into httpx.Proxy(auth=...) (snapshot). If none is found, httpx receives trust_env=True and re-reads env vars per-request. |
Env vars read per-request (aiohttp native behavior) |
Cross-reference: see Timeouts for the note on Timeout.write and Timeout.pool being httpx-only fields.
AioHttpClient¶
Requires: pip install "kubex[aiohttp]"
aiohttp has WebSocket support built in — no extra package needed for exec, attach, and portforward. Supports asyncio only.
HttpxClient¶
Requires: pip install "kubex[httpx]"
WebSocket support requires the extra httpx-ws package:
pip install "kubex[httpx-ws]" (includes httpx).
The httpx client is the only client that supports trio (in addition to asyncio).
Client selection trade-offs¶
| Feature | aiohttp | httpx |
|---|---|---|
| asyncio support | yes | yes |
| trio support | no | yes |
| WebSocket (exec/attach/portforward) | built-in | requires httpx-ws extra |
| Auto-detection priority | 1st | 2nd |
For detailed guidance on choosing a client and runtime, see Clients & Runtimes.
Custom underlying HTTP client¶
Kubex prioritizes predictable defaults over knob coverage. When the built-in ClientOptions wiring is insufficient — for example, you need target-host Basic auth from netrc, a custom retry policy, a custom TLS transport, or per-request env reads on httpx — you can subclass HttpxClient or AioHttpClient and override _create_inner_client().
When this escape hatch is used, the subclass is fully responsible for mapping all options and configuration. ClientOptions proxy, timeout, pool, and trust_env fields are no longer applied automatically.
httpx example:
import httpx
from kubex.client.httpx import HttpxClient
from kubex.client import ClientOptions
class MyHttpxClient(HttpxClient):
def _create_inner_client(self) -> httpx.AsyncClient:
# Full control: target-host NetRCAuth, custom transport, retry policy, etc.
return httpx.AsyncClient(
base_url=str(self.configuration.base_url),
verify=True,
trust_env=True, # per-request env reads
auth=httpx.NetRCAuth(file=None), # target-host Basic auth from netrc
)
client = MyHttpxClient(configuration=cfg, options=ClientOptions())
aiohttp example:
import ssl
import aiohttp
from kubex.client.aiohttp import AioHttpClient
from kubex.client import ClientOptions
class MyAioHttpClient(AioHttpClient):
def _create_inner_client(self) -> aiohttp.ClientSession:
ssl_context = ssl.create_default_context()
connector = aiohttp.TCPConnector(ssl=ssl_context)
return aiohttp.ClientSession(
base_url=str(self.configuration.base_url),
connector=connector,
trust_env=True,
)
client = MyAioHttpClient(configuration=cfg, options=ClientOptions())
Warning
Overriding _create_inner_client() means ClientOptions proxy, timeout, pool, and trust_env fields are no longer applied automatically. The subclass is fully responsible for all HTTP client configuration.