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:
api_key=passed by the caller (an empty string counts as not given);a key bound for this provider in the current context with
using_credentials()– the bring-your-own-key seam a server uses withoutthreading a key through every call;
the environment:
env_varfirst, then the provider’s row ofprovider_env_vars, in order, without duplicates (withdotenv=Truea 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.envloader it writes toos.environ, so every later reader sees it);store: any mapping keyed by env-var name (aconfig2pystore, a dict); only a missing key moves on, any other error propagates;with
prompt_if_missing=Trueand an interactive terminal,getpass; the answer is written tostorewhen it is aMutableMapping, 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
openaireaches 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
ContextVarbinding, so it follows the context:asynciotasks andasyncio.to_threadsee it, but a barethreading.Thread,ThreadPoolExecutor.submitorloop.run_in_executorstart from an empty context and fall through to the environment (the operator’s key). Submitcontextvars.copy_context().runto 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 a provider's credential through the chain in the module docstring. |
|
The env vars the chain checks: |
|
A short, link-bearing "how to get a key" line for |
|
|
|
Bind provider keys for the |
The provider keys bound in this context by |
Exceptions
|
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:
RuntimeErrorA 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 carrynoteandget_key_url.- Return type:
- 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:
- ocracy.kit.credentials.current_credentials()[source]#
The provider keys bound in this context by
using_credentials()(a copy).- Return type:
- ocracy.kit.credentials.env_var_names(provider=None, *, env_var=None, provider_env_vars=None)[source]#
The env vars the chain checks:
env_varfirst, then the provider’s row.- Return type:
- 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 withgetpasswhen interactive (last resort).required (
bool) – Raise when nothing resolves; else returnNone.error (
Callable[[str],BaseException]) – The exception to raise, called with the message. When it builds aMissingCredentialError(or subclass), itsprovider,env_varsandget_key_urlattributes are filled in.hint (
str) – An extra sentence for the error message (why this key is needed).
- Return type:
- Returns:
The secret, or
Nonewhenrequired=Falseand nothing resolved.
- ocracy.kit.credentials.using_credentials(keys=None, /, **provider_keys)[source]#
Bind provider keys for the
withblock (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.>>> with using_credentials(acme="outer"): ... with using_credentials({"acme": "inner", "other": None}): ... inner = current_credentials() ... outer = current_credentials() >>> inner, outer ({'acme': 'inner'}, {'acme': 'outer'})