degenbot.config¶

Python’s view of the Rust-owned configuration cascade.

degenbot-config owns the operator file, the environment, and the resolution order end to end (ADR-062 D7/D10). The Python driver is a consumer of that verdict, never a second authority: this module translates the FFI surface into the shapes Python callers use and adds nothing to the resolution itself.

The verdict is ONE frozen object – resolved_config() – built from the load published at FFI module init. The helpers here are translation (a wider int/str signature, the RpcNotConfiguredError the driver catches, the retired-keyword refusal) over that one object; none of them re-derives a layer or re-reads a key. A config key the driver wants that has no helper yet is a named property off the typed seam projection, resolved_config().values.<section>.<field> – reading one does not require an edit anywhere, which is the point of the verdict.

The cascade has four layers – an explicit override, the environment, the operator file, and a declared default – and reports the layer that won. The config is installed once at FFI module init, so a process resolves the same file and the same environment as the Rust console no matter which entry path started it.

Two doors exist, and using the wrong one is a tautology: degenbot._ffi.resolve_hypothetical answers HOW the cascade resolves a captured environment + file (a pure function that installs nothing, reachable only from the raw FFI seam and deliberately not re-exported here), while the installed resolved_config() answers WHAT this process installed.

Package Contents¶

degenbot.config.resolved_config() → degenbot._ffi.ResolvedConfig¶

Return the whole resolved configuration for this process.

The one object the driver reads: every declared key with its typed value (values), the layer each came from (provenance), and the resolutions that take a capability or an override. Frozen, and built from the load published at FFI module init, so it cannot drift from what the console read.

Returns:

The installed verdict.

exception degenbot.config.RpcNotConfiguredError¶

Bases: ValueError

No endpoint configured for a chain in any cascade layer.

Subclasses ValueError so callers that already catch a misconfigured endpoint keep working. The core’s refusal names the scope, the transports it consulted, the layers each was read through, and what to declare or export, so a fresh environment fails fast with a pointer at what to set instead of silently degrading.

degenbot.config.resolve_node(chain_id: degenbot.types.aliases.ChainId, scope: str, *, node: str | None = None) → degenbot._ffi.ResolvedNodeUri¶

Resolve one endpoint for chain_id and report the layer that won.

The full verdict: the endpoint plus its Source (default, file, env, or cli), so a diagnostic can name the layer rather than re-deriving it. scope is the caller’s capability – "request" or "subscription" – and a subscription never selects an http entry.

Parameters:
  • chain_id – The chain the endpoint serves.

  • scope – "request" or "subscription".

  • node – The explicit override, classified by its own value.

Returns:

The endpoint and the layer that supplied it.

Raises:

RpcNotConfiguredError – When no layer supplied an endpoint for the chain.

degenbot.config.resolve_http_rpc_uri(chain_id: degenbot.types.aliases.ChainId, /, *, node: str | None = None, **retired: object) → str¶

Resolve the request-scope endpoint for chain_id.

Request scope is what a pool read, an eth_callMany, or a transaction submission needs; it prefers an IPC socket, then a WS endpoint, then HTTP. A caller that must not depend on a subscription (a CLI pool update) resolves through this one rather than resolve_rpc_uris().

Parameters:
  • chain_id – The chain the endpoint serves.

  • node – The explicit override, classified by its own value.

  • **retired – A pre-0.6 per-transport override spelling. Carrying a value raises TypeError that names the scheme-classified node argument replacing it; the catch-all exists so the hard cutover fails loudly instead of silently ignoring a spelling no layer reads.

Returns:

The resolved request endpoint as a string.

Raises:

RpcNotConfiguredError – When no layer supplied one.

degenbot.config.resolve_ws_rpc_uri(chain_id: degenbot.types.aliases.ChainId, /, *, node: str | None = None, **retired: object) → str¶

Resolve the subscription-scope endpoint for chain_id.

The subscription scope is the transports a feed can hold open – IPC or WS – and never an HTTP entry, so a poll-only endpoint is refused here instead of being handed to a subscriber that would silently degrade.

Parameters:
  • chain_id – The chain the endpoint serves.

  • node – The explicit override, classified by its own value.

  • **retired – A pre-0.6 per-transport override spelling. Carrying a value raises TypeError that names the scheme-classified node argument replacing it; the catch-all exists so the hard cutover fails loudly instead of silently ignoring a spelling no layer reads.

Returns:

The resolved subscription endpoint as a string.

Raises:

RpcNotConfiguredError – When no layer supplied one.

degenbot.config.resolve_rpc_uris(chain_id: degenbot.types.aliases.ChainId, /, *, node: str | None = None, **retired: object) → tuple[str, str]¶

Resolve the (request, subscription) endpoint pair for chain_id.

The two capabilities resolve independently, each through the same four layers, so a session can take its request endpoint from the file and its subscription endpoint from the environment. There is no localhost default: a chain with no endpoint in any layer raises.

Parameters:
  • chain_id – The chain the endpoints serve.

  • node – The explicit override, classified by its own value.

  • **retired – A pre-0.6 per-transport override spelling. Carrying a value raises TypeError that names the scheme-classified node argument replacing it; the catch-all exists so the hard cutover fails loudly instead of silently ignoring a spelling no layer reads.

Returns:

The resolved (request_uri, subscription_uri) pair.

Raises:

RpcNotConfiguredError – When either capability is unresolved.

degenbot.config.resolve_chain_id(chain_id: int | str | None = None) → int¶

Resolve the session chain id.

Refuses with a ValueError – naming what to declare, export, or pass – both when no layer named a chain and when the explicit value is not an integer.

Parameters:

chain_id – The explicit override; the core parses it as text so a non-integer is refused by the layer that owns the spelling.

Returns:

The chain id the session targets.

degenbot.config.resolve_database_path(database: str | None = None) → str¶

Resolve the database path a session opens.

The winning value already has ~ and the XDG state home expanded by the resolver, so a caller needs no second expansion.

Parameters:

database – The explicit override.

Returns:

The resolved database path.

degenbot.config.config_file_path() → str | None¶

Return the operator file the loader selected.

A free-form reader (the deployment-registry overlay) reads the same file the typed load read. None means the process has no file layer, which is contractually the schema defaults.

Returns:

The selected file’s path, or None.

degenbot.config.declared_database_path() → str¶

Return the declared database.path key, with no cascade.

The value the operator wrote, with no ~ expansion. A caller that wants the path a session opens asks resolve_database_path().

Returns:

The declared database.path value.