Source registry¶
Every data source — file or live — registers here under a name, the one
registry shared by both. Built-in sources self-register on import; third-party
sources load through the ob_analytics.sources entry-point group (see
Extending). A registered
value is a Source class; construct it and use the capability
you need — OfflineSource for file replay (Pipeline(source=...)), LiveSource
for live capture.
Per-source configuration is a typed SourceSettings (a frozen pydantic model),
not an untyped dict — subclass it per source, e.g. CcxtSettings. A source
that needs an API key marks the field with Credential (see
Use an API key).
register_source ¶
Register a :class:~ob_analytics.protocols.Source class under name.
Case-insensitive; overwriting an existing registration is allowed (handy for tests and for a plug-in that intentionally shadows a built-in).
get_source ¶
Return the source class registered under name (case-insensitive).
Raises:
| Type | Description |
|---|---|
KeyError
|
If no source is registered under name; the message lists the registered names. |
load_source_plugins ¶
Discover and register sources advertised via entry points.
Scans the :data:ENTRY_POINT_GROUP entry-point group; each entry's value
is loaded to a :class:~ob_analytics.protocols.Source class and registered
under the entry-point name. This is what lets a source live in a separate
installable package without editing ob-analytics.
Idempotent: the scan runs once per process unless force is set (the test suite forces a re-scan after monkeypatching the entry points). A plug-in that fails to import is logged and skipped, so one broken package cannot stop the rest from loading.
Returns:
| Type | Description |
|---|---|
list of str
|
The names newly registered by this call. |
SourceSettings ¶
Bases: BaseModel
Base class for a data source's typed, immutable settings.
The typed replacement for the untyped per-source settings dict that live
capturers used to carry (CaptureConfig.extras). Every
:class:~ob_analytics.protocols.Source declares a settings value of
this type; a source that needs no configuration uses the empty base, and a
source with venue knobs subclasses it with typed, validated fields — e.g.
:class:~ob_analytics.live.ccxt_source.CcxtSettings (exchange /
depth_limit / poll_interval).
Frozen so a source's settings are fixed for the run, matching
:class:PipelineConfig.
A source that needs an API key declares it as a field marked with
:class:Credential. The settings read an unset credential from its
environment variable, and every credential's value is removed from the
files a capture writes.
credentials
classmethod
¶
The fields marked with :class:Credential, by field name.
remember_secrets ¶
Register every SecretStr value held here for redaction.
Validation does this already. A capture does it again as it starts,
for settings built without validation (model_copy(update=...)).
check_credentials ¶
Raise :class:~ob_analytics.exceptions.ConfigError if a credential is unset.
The message names each missing key's environment variable and where the venue issues keys. source is the source's name, for the message. The keys that are set are registered for redaction.
Credential
dataclass
¶
Marks a :class:SourceSettings field as a key the user supplies.
Put it on a SecretStr | None field with typing.Annotated. When the
field is not given, the settings read it from the environment variable
env. A key is never a command-line option, because a command line stays
in the shell history::
class VenueSettings(SourceSettings):
api_key: Annotated[
SecretStr | None,
Credential(env="VENUE_API_KEY", issued_at="https://venue.example/keys"),
] = None
An empty value counts as unset. A value shorter than eight characters is
refused, since no venue issues a key that short. A capture checks that
every credential is set before it writes anything
(:meth:SourceSettings.check_credentials).
Attributes:
| Name | Type | Description |
|---|---|---|
env |
str
|
The environment variable the key is read from. |
issued_at |
str
|
Where the venue issues keys, usually a URL. The error for a missing key names it. |
from_file |
bool
|
The variable holds the path of a file, and the field holds the file's
contents. For a private key, which lives in a file. From Python, pass
a :class: |