ocracy.kit.credentials#

One credential chain for every facade: explicit -> bound -> env -> store -> prompt.

resolve_credential() looks for a provider’s secret in this order and stops at the first non-empty value:

  1. api_key= passed by the caller (an empty string counts as not given);

  2. a key bound for this provider in the current context with using_credentials() – the bring-your-own-key seam a server uses without

    threading a key through every call;

  3. the environment: env_var first, then the provider’s row of provider_env_vars, in order, without duplicates (with dotenv=True a project .env, found from the current directory, is loaded on a miss and the environment checked again; it never overrides a variable that is already set, and like any .env loader it writes to os.environ, so every later reader sees it);

  4. store: any mapping keyed by env-var name (a config2py store, a dict); only a missing key moves on, any other error propagates;

  5. with prompt_if_missing=True and an interactive terminal, getpass; the answer is written to store when it is a MutableMapping, else to the process environment.

When nothing resolves and required=True, it raises error (default MissingCredentialError) with a message naming every env var it tried and, from guidance, where to get a key:

>>> resolve_credential("acme", api_key="explicit")
'explicit'
>>> with using_credentials(acme="bound"):
...     resolve_credential("acme")
'bound'
>>> resolve_credential("acme", env_var="ACME_SURELY_UNSET_KEY", required=False) is None
True

Two properties of the binding (step 2) that a server must know:

  • It is shared by provider id across every package using the kit. A key bound as openai reaches ocracy, aix and any other facade calling OpenAI in that context. That is the point of a bring-your-own-key binding, so pick provider ids that name the account (openai, fal, elevenlabs), not the facade.

  • It is a ContextVar binding, so it follows the context: asyncio tasks and asyncio.to_thread see it, but a bare threading.Thread, ThreadPoolExecutor.submit or loop.run_in_executor start from an empty context and fall through to the environment (the operator’s key). Submit contextvars.copy_context().run to keep the binding.

A package binds its own tables once, with functools.partial() or a thin wrapper, and keeps its public names; ocracy’s ocracy.credentials is the worked example. Stdlib only; imports nothing else from ocracy.

Functions

resolve_credential([provider, api_key, ...])

Resolve a provider's credential through the chain in the module docstring.

env_var_names([provider, env_var, ...])

The env vars the chain checks: env_var first, then the provider's row.

credential_help(provider, *[, guidance])

A short, link-bearing "how to get a key" line for provider (or '').

credential_lines(env_var, provider, *[, ...])

export VAR  (get a key: URL) lines for an install plan (empty if no var).

using_credentials([keys])

Bind provider keys for the with block (overlaying any outer binding).

current_credentials()

The provider keys bound in this context by using_credentials() (a copy).

Exceptions

MissingCredentialError([message, provider, ...])

A required credential could not be resolved; the message says how to get one.

exception ocracy.kit.credentials.MissingCredentialError(message='', *, provider=None, env_vars=(), get_key_url=None)[source]#

Bases: RuntimeError

A required credential could not be resolved; the message says how to get one.

provider#

The provider id asked for (or None).

env_vars#

The env vars that were checked, in order.

get_key_url#

Where to get a key, when the guidance table knows.

ocracy.kit.credentials.credential_help(provider, *, guidance=None)[source]#

A short, link-bearing “how to get a key” line for provider (or '').

guidance[provider] may carry note and get_key_url.

Return type:

str

ocracy.kit.credentials.credential_lines(env_var, provider, *, guidance=None)[source]#

export VAR  (get a key: URL) lines for an install plan (empty if no var).

Several env vars (alternatives) are shown as A / B.

Return type:

list

ocracy.kit.credentials.current_credentials()[source]#

The provider keys bound in this context by using_credentials() (a copy).

Return type:

dict

ocracy.kit.credentials.env_var_names(provider=None, *, env_var=None, provider_env_vars=None)[source]#

The env vars the chain checks: env_var first, then the provider’s row.

Return type:

list

ocracy.kit.credentials.resolve_credential(provider=None, *, api_key=None, env_var=None, provider_env_vars=None, guidance=None, store=None, dotenv=False, prompt_if_missing=False, required=True, error=<class 'ocracy.kit.credentials.MissingCredentialError'>, hint='')[source]#

Resolve a provider’s credential through the chain in the module docstring.

Parameters:
  • provider (Optional[str]) – The provider id, used for bindings, table rows and messages.

  • api_key (Optional[str]) – An explicit value; wins when non-empty.

  • env_var (Union[str, Sequence[str], None]) – Env var name(s) checked before the provider’s table row.

  • provider_env_vars (Optional[Mapping[str, Union[str, Sequence[str], None]]]) – The package’s provider -> env var(s) table.

  • guidance (Optional[Mapping]) – The package’s provider -> {note, get_key_url} table.

  • store (Optional[Mapping[str, str]]) – A mapping keyed by env-var name, read after the environment.

  • dotenv (bool) – On an environment miss, load a project .env (searched from the current directory, never overriding) and look again.

  • prompt_if_missing (bool) – Ask with getpass when interactive (last resort).

  • required (bool) – Raise when nothing resolves; else return None.

  • error (Callable[[str], BaseException]) – The exception to raise, called with the message. When it builds a MissingCredentialError (or subclass), its provider, env_vars and get_key_url attributes are filled in.

  • hint (str) – An extra sentence for the error message (why this key is needed).

Return type:

Optional[str]

Returns:

The secret, or None when required=False and nothing resolved.

ocracy.kit.credentials.using_credentials(keys=None, /, **provider_keys)[source]#

Bind provider keys for the with block (overlaying any outer binding).

Pass a mapping for provider ids that are not identifiers ("google-vision") or keywords for the rest. Falsy values are ignored, so an optional request header can be passed straight through.

Return type:

Iterator[dict]

>>> with using_credentials(acme="outer"):
...     with using_credentials({"acme": "inner", "other": None}):
...         inner = current_credentials()
...     outer = current_credentials()
>>> inner, outer
({'acme': 'inner'}, {'acme': 'outer'})