ADR-007: Optional Format Dependencies with Lazy Imports
Status: Accepted
Date: 2024-01-01
Deciders: Calibra core team
Context
Calibra supports five dataset formats, each requiring a different set of heavy third-party dependencies:
| Format | Dependencies |
|---|---|
| LeRobot | datasets, pyarrow, duckdb |
| RLDS | tensorflow, tensorflow-datasets |
| HDF5 | h5py |
| MCAP | mcap, mcap-ros2-support |
| Isaac Lab | (subset of above) |
tensorflow alone is ~500 MB. Requiring all dependencies for all formats
would make Calibra impractical for users who only work with, for example,
LeRobot datasets and do not have a TensorFlow-compatible environment.
Calibra's core value (analyzers, reports, comparison) has no dependency on any of these format libraries. Only the ingestion adapters depend on them.
Decision
Format-specific dependencies are declared as optional extras in
pyproject.toml:
calibra[hdf5] → h5py
calibra[lerobot] → datasets, pyarrow, duckdb
calibra[rlds] → tensorflow, tensorflow-datasets
calibra[mcap] → mcap, mcap-ros2-support
calibra[all] → all of the above
Inside each adapter, format-specific imports are performed lazily inside
helper functions (e.g. _require_datasets(), _require_duckdb()) that
raise ImportError with a clear installation hint if the dependency is
missing. These helpers are called at the top of read(), not at module
import time.
The top-level calibra package (calibra/__init__.py) does not import any
adapter. Adapters are only imported when calibra.ingestion.registry is
imported (e.g. when load() is called). This means that importing
calibra.pipeline or calibra.schema does not trigger any format-specific
import.
Alternatives Considered
Single required dependency set
Declare all format dependencies as required.
Rejected: makes pip install calibra-robotics fail in environments without
TensorFlow, CUDA-related libraries, or ROS 2. The robotics ecosystem is
fragmented enough that no single environment has all tools available.
Separate packages per format (e.g. calibra-lerobot, calibra-rlds)
Split each adapter into its own installable package.
Rejected: complicates the import structure, versioning, and documentation;
users need to know to install calibra-lerobot in addition to calibra.
The extras model is the standard Python approach for this pattern.
Dynamic import of adapters via importlib at runtime
Discover adapter modules by scanning the adapters/ directory and importing
each with a try/except around the format dependencies.
Rejected: makes adapter registration implicit and difficult to audit; any
module-level syntax error in an adapter becomes a silent registration failure
rather than an import error. The current approach — can_read registers
even with missing dependencies, read raises ImportError — is more explicit.
Constraints
- The
_require_<lib>()pattern must be used consistently. A bareimport duckdbat module level in an adapter is a bug — it makes the adapter unimportable when the dependency is absent, which silently removes it from the registry. - Error messages from
_require_<lib>()must include the exactpip installcommand needed. TYPE_CHECKINGguards (if TYPE_CHECKING: import ...) may be used for type annotations without triggering runtime imports.
Consequences
Positive:
- pip install calibra-robotics (bare) installs in any Python 3.10+
environment, with only pydantic and numpy as hard dependencies.
- Users who work exclusively with one format install only what they need.
- Adapter unit tests can mock the format library and verify that the
ImportError message is correct.
Negative: - Contributors must remember the lazy import pattern. A module-level import of a format library in an adapter will not be caught by tests unless the CI environment lacks that dependency. The pattern is documented in the adapter authoring guide and enforced by code review.
References
pyproject.toml— optional extras definitionscalibra/ingestion/adapters/lerobot.py—_require_datasets(),_require_duckdb()patterncalibra/ingestion/registry.py— import-time registration