foley.sources.registry

Live-source adapter registry: auto-discovery + lazy loading (arioso’s registry, ported).

Scans foley.sources for sub-packages that declare a SOURCE_CONFIG (a config.py with the plugin declaration), registers them, and lazily imports + instantiates each adapter only on first use. Mirrors arioso.registry / PLATFORM_CONFIG (report 10 §4.1).

This is the live-source registry (Freesound; hosted generators in #6) — a separate registry from the bulk-corpus foley.sources.base.CORPUS_REGISTRY. The two adapter kinds have different contracts (search / get / download vs iter_clips / resolve_license) and different façades (foley.add_from() vs foley.bootstrap()). They stay disjoint by construction: discovery only picks up sub-packages (ispkg and not _-prefixed), so the flat bulk-corpus modules (fsd50k.py …) and the flat helper modules here (base, http, pull, registry) are never cross-captured.

Out-of-tree plugins — and test doubles — register directly via register_source() (no package needed).

foley.sources.registry.SOURCE_REGISTRY = {}

Public read alias of the registry (callers/tests inspect discovered sources).

foley.sources.registry.discover_sources() list[str][source]

Scan foley.sources sub-packages for a SOURCE_CONFIG and register them.

A valid live source is a sub-package of foley.sources (ispkg and not _-prefixed) whose config.py defines a SOURCE_CONFIG dict with a name. Flat modules (bulk-corpus adapters + helpers) are skipped, so this never cross-captures the corpus adapters. Only config.py is imported here (stdlib-cheap); the adapter loads lazily in get_source(). Idempotent — an already-registered name (e.g. a test double) is never overwritten.

Returns:

The list of discovered source names.

foley.sources.registry.get_source(name: str) dict[source]

Return the {'config', 'adapter'} entry for name, lazily building the adapter.

Runs a discovery pass if name is not yet known, then instantiates the adapter on first use (cached in the entry).

Parameters:

name – The source name.

Returns:

The registry entry ({'config': dict, 'adapter': SourceAdapter, ...}).

Raises:

KeyError – If no such source is registered (after discovery).

foley.sources.registry.list_sources(*, egress_allow: frozenset | None = None) list[str][source]

Return the names of registered live sources (runs discovery first).

Parameters:

egress_allow – If given, keep only sources whose declared config['data_egress'] is in this set (the local-first / offline filter — see foley.runtime.RuntimeConfig). A source that does not declare data_egress is excluded (fail-closed).

foley.sources.registry.local_sources() list[str][source]

The names of sources that run entirely on-device (data_egress == 'local').

foley.sources.registry.register_source(name: str, config: dict, adapter=None) None[source]

Register a live source directly (out-of-tree plugin or a test double).

Overwrites any existing entry for name — the seam a test uses to inject a fake-transport-backed adapter. If adapter is None it is lazily built from config on first get_source() (the source must then be an importable foley.sources.<name> package).

Parameters:
  • name – The source name (the add_from() / get_source() key).

  • config – The SOURCE_CONFIG declaration.

  • adapter – An optional pre-instantiated adapter (bypasses lazy loading).

foley.sources.registry.source_egress(name: str) str | None[source]

The declared data_egress class of source name (None if undeclared).