Skip to content

Catalog

A catalog is the set of component definitions available to a process: sources, connections, configs, destinations, jobs and hooks, keyed by component key. It answers "what exists and how is it configured" without instantiating or executing anything, and it is what key references in specs resolve against.

Building a catalog

import interloper as il

il.Catalog.discover()                      # everything installed packages declare
il.Catalog.from_settings()                 # what this deployment enables
il.Catalog.from_paths(["my_package.sources.Shop", "my_package.sources.Finance"])
il.Catalog.from_assets([Shop, Finance])

Discovery reads the interloper.components entry-point group of every installed package. Each entry names a component class, or a module whose public attributes are scanned for component classes. The scan is cached for the process.

Settings narrow the universe: when catalog in interloper.yaml (or INTERLOPER_CATALOG) lists import paths, the catalog holds those components, everything they depend on, and the framework's own components. An empty list means everything installed.

Dependencies come along. Enabling a source pulls in its resource classes and, through its assets, their resources and destination classes, transitively. A catalog therefore never carries a relation slot whose key it cannot resolve. Framework components (cron_job, trigger_hook, webhook_hook) are present in every catalog.

Paths that fail to import are skipped with a warning. A component whose kind has no registered anchor raises ConfigError; see Entry points.

Registering components

Declare your components in your package's pyproject.toml:

[project.entry-points."interloper.components"]
my_package = "my_package.sources"          # a module: every component class in it

or one entry per class. Nothing else is needed: installation is registration.

Reading a catalog

catalog.components                              # key -> ComponentDefinition
catalog.get("facebook_ads")                     # a SourceDefinition, or None
catalog.get("ads_stats", parent_key="facebook_ads")   # a source-owned asset's definition
catalog.vocabulary("hook", "trigger_hook")      # relation type -> RelationDefinition
catalog.to_paths()                              # sorted import paths, for another process
catalog.dump()                                  # JSON-serializable definitions

Assets are not top-level entries: they belong to their source and are reached through SourceDefinition.assets or get(key, parent_key=...).

Definitions

Every component class describes itself through definition():

Field Content
kind, key, path Identity and import path.
name, icon, description, tags Display metadata; the description is the docstring.
config_schema JSON Schema of the user-facing configuration fields.
state_schema JSON Schema of the machine-owned state model, when the kind has one.
relations The relation vocabulary with its slots (resource slots, dependency slots, allowed destination keys).

Kind-specific definitions add to this: SourceDefinition.assets, AssetDefinition.asset_schema and partitioning, ResourceDefinition.provider, checkable, renewable. This metadata is what UIs render forms and pickers from.

Resolving keys

il.Source.resolve_key("facebook_ads", catalog) turns a catalog key into the class, enforcing the kind. Unknown keys raise CatalogKeyError. Spec reconstruction uses the same path for every key reference.