Skip to content

modosaic.cli.config

modosaic.cli.config

Configuration models and parsers for the Modosaic CLI.

ConstraintConfig dataclass

ConstraintConfig(enabled=True, text_siglip_minimum=0.6, segmentation_mask_quality_minimum=0.75, segmentation_boundary_minimum=0.2, depth_imagebind_minimum=0.55, depth_segmentation_boundary_minimum=0.2, normals_depth_agreement_minimum=0.35, normals_field_quality_minimum=0.5)

Validation-threshold configuration used as quality gates.

DatasetConfig dataclass

DatasetConfig(kind, root=None, parquet_path=None, recursive=True, extensions=(), image_column='image', id_column=None, extension_column=None, metadata_columns=(), batch_size=512)

Dataset configuration for a Modosaic run.

Attributes:

Name Type Description
kind DatasetKind

Dataset backend to use.

root Path | None

Local image-folder root when kind is local.

parquet_path Path | None

Parquet file or directory when kind is parquet.

recursive bool

Whether local folders are scanned recursively.

extensions tuple[str, ...]

Optional local-folder extensions to include.

image_column str

Parquet column or nested path containing image data.

id_column str | None

Optional parquet sample ID column.

extension_column str | None

Optional parquet extension column.

metadata_columns tuple[str, ...]

Optional parquet columns preserved as metadata.

batch_size int

Parquet read batch size.

DatasetKind

Bases: str, Enum

Dataset backend names accepted by CLI and config files.

DepthModelName

Bases: str, Enum

Depth model choices accepted by CLI and config files.

ModalityName

Bases: str, Enum

Modality names accepted by CLI and config files.

ModelConfig dataclass

ModelConfig(text=TextModelName.QWEN_2_2B, segmentation=SegmentationModelName.SAM3, depth=DepthModelName.DEPTH_ANYTHING_V2_SMALL, normals=NormalsModelName.OMNIDATA)

Model choices for generated modalities.

NormalsModelName

Bases: str, Enum

Surface-normal model choices accepted by CLI and config files.

RunConfig dataclass

RunConfig(dataset, modalities=DEFAULT_MODALITIES, models=ModelConfig(), validators=ValidatorConfig(), limit=None, experiment_root=Path('experiments'), experiment_name=None, log_path=DEFAULT_LOG_PATH, seed=42, json_summary=False)

Complete CLI/runtime configuration for one Modosaic run.

SegmentationModelName

Bases: str, Enum

Segmentation model choices accepted by CLI and config files.

TextModelName

Bases: str, Enum

Captioning model choices accepted by CLI and config files.

ValidatorConfig dataclass

ValidatorConfig(enabled=True, constraints=ConstraintConfig(), segmentation_boundary_thickness=1, segmentation_tolerance_radius=2, segmentation_rgb_edge_quantile=0.9, depth_boundary_thickness=1, depth_tolerance_radius=2, depth_edge_quantile=0.9, normals_eps=1e-06, normals_nz_min=0.1)

Validator and quality-gate options for a Modosaic run.

load_config_mapping

load_config_mapping(config_path)

Load a JSON, TOML, YAML, or YML config file.

Parameters:

Name Type Description Default
config_path Path

Path to the config file.

required

Returns:

Type Description
Mapping[str, Any]

Parsed top-level mapping.

Raises:

Type Description
ValueError

If the file extension is unsupported or the parsed payload is not a mapping.

Source code in modosaic/cli/config.py
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
def load_config_mapping(config_path: Path) -> Mapping[str, Any]:
    """Load a JSON, TOML, YAML, or YML config file.

    Args:
        config_path: Path to the config file.

    Returns:
        Parsed top-level mapping.

    Raises:
        ValueError: If the file extension is unsupported or the parsed payload
            is not a mapping.
    """
    suffix = config_path.suffix.lower()
    text = config_path.read_text(encoding="utf-8")

    if suffix == ".json":
        data = json.loads(text)
    elif suffix == ".toml":
        data = _load_toml(text)
    elif suffix in {".yaml", ".yml"}:
        data = _load_yaml(text)
    else:
        raise ValueError("Config file must end in .json, .toml, .yaml, or .yml.")

    if not isinstance(data, Mapping):
        raise ValueError("Pipeline config must contain a top-level mapping.")
    return data

normalize_modalities

normalize_modalities(modalities)

Return selected modalities in dependency-safe default order.

Parameters:

Name Type Description Default
modalities Sequence[ModalityName] | None

Requested modality subset. None or an empty sequence means all default modalities.

required

Returns:

Type Description
tuple[ModalityName, ...]

Ordered modality tuple.

Source code in modosaic/cli/config.py
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
def normalize_modalities(
        modalities: Sequence[ModalityName] | None,
) -> tuple[ModalityName, ...]:
    """Return selected modalities in dependency-safe default order.

    Args:
        modalities: Requested modality subset. `None` or an empty sequence means
            all default modalities.

    Returns:
        Ordered modality tuple.
    """
    if not modalities:
        return DEFAULT_MODALITIES

    requested = set(modalities)
    return tuple(name for name in DEFAULT_MODALITIES if name in requested)

run_config_from_mapping

run_config_from_mapping(data)

Build a RunConfig from a parsed config mapping.

Parameters:

Name Type Description Default
data Mapping[str, Any]

Parsed config data.

required

Returns:

Type Description
RunConfig

Normalized run configuration.

Raises:

Type Description
ValueError

If any section has an invalid shape or enum value.

Source code in modosaic/cli/config.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
def run_config_from_mapping(data: Mapping[str, Any]) -> RunConfig:
    """Build a `RunConfig` from a parsed config mapping.

    Args:
        data: Parsed config data.

    Returns:
        Normalized run configuration.

    Raises:
        ValueError: If any section has an invalid shape or enum value.
    """
    dataset_section = _mapping(data.get("dataset"), "dataset")
    modalities_section = data.get("modalities", {})
    validators_section = _mapping(data.get("validators", {}), "validators")
    run_section = _mapping(data.get("run", {}), "run")

    enabled_modalities, model_section = _read_modalities_section(modalities_section)
    constraint_section = _read_constraint_section(validators_section)

    return RunConfig(
        dataset=DatasetConfig(
            kind=_enum_value(
                DatasetKind,
                dataset_section.get("kind", dataset_section.get("type", DatasetKind.LOCAL.value)),
                "dataset.kind",
            ),
            root=_path_or_none(dataset_section.get("root", dataset_section.get("path"))),
            parquet_path=_path_or_none(dataset_section.get("parquet_path", dataset_section.get("path"))),
            recursive=bool(dataset_section.get("recursive", True)),
            extensions=tuple(_string_sequence(dataset_section.get("extensions", ()), "dataset.extensions")),
            image_column=str(dataset_section.get("image_column", "image")),
            id_column=_str_or_none(dataset_section.get("id_column")),
            extension_column=_str_or_none(dataset_section.get("extension_column")),
            metadata_columns=tuple(
                _string_sequence(dataset_section.get("metadata_columns", ()), "dataset.metadata_columns")
            ),
            batch_size=int(dataset_section.get("batch_size", 512)),
        ),
        modalities=normalize_modalities(
            [
                _enum_value(ModalityName, value, "modalities.enabled")
                for value in (enabled_modalities or ())
            ]
            if enabled_modalities is not None
            else None
        ),
        models=ModelConfig(
            text=_enum_value(
                TextModelName,
                model_section.get("text", TextModelName.QWEN_2_2B.value),
                "modalities.models.text",
            ),
            segmentation=_enum_value(
                SegmentationModelName,
                model_section.get("segmentation", SegmentationModelName.SAM3.value),
                "modalities.models.segmentation",
            ),
            depth=_enum_value(
                DepthModelName,
                model_section.get("depth", DepthModelName.DEPTH_ANYTHING_V2_SMALL.value),
                "modalities.models.depth",
            ),
            normals=_enum_value(
                NormalsModelName,
                model_section.get("normals", NormalsModelName.OMNIDATA.value),
                "modalities.models.normals",
            ),
        ),
        validators=ValidatorConfig(
            enabled=bool(validators_section.get("enabled", True)),
            constraints=ConstraintConfig(
                enabled=bool(constraint_section.get("enabled", True)),
                text_siglip_minimum=float(constraint_section.get("text_siglip_minimum", 0.60)),
                segmentation_mask_quality_minimum=float(
                    constraint_section.get("segmentation_mask_quality_minimum", 0.75)
                ),
                segmentation_boundary_minimum=float(
                    constraint_section.get("segmentation_boundary_minimum", 0.20)
                ),
                depth_imagebind_minimum=float(constraint_section.get("depth_imagebind_minimum", 0.55)),
                depth_segmentation_boundary_minimum=float(
                    constraint_section.get("depth_segmentation_boundary_minimum", 0.20)
                ),
                normals_depth_agreement_minimum=float(
                    constraint_section.get("normals_depth_agreement_minimum", 0.35)
                ),
                normals_field_quality_minimum=float(
                    constraint_section.get("normals_field_quality_minimum", 0.50)
                ),
            ),
            segmentation_boundary_thickness=int(
                validators_section.get("segmentation_boundary_thickness", 1)
            ),
            segmentation_tolerance_radius=int(
                validators_section.get("segmentation_tolerance_radius", 2)
            ),
            segmentation_rgb_edge_quantile=float(
                validators_section.get("segmentation_rgb_edge_quantile", 0.90)
            ),
            depth_boundary_thickness=int(validators_section.get("depth_boundary_thickness", 1)),
            depth_tolerance_radius=int(validators_section.get("depth_tolerance_radius", 2)),
            depth_edge_quantile=float(validators_section.get("depth_edge_quantile", 0.90)),
            normals_eps=float(validators_section.get("normals_eps", 1e-6)),
            normals_nz_min=float(validators_section.get("normals_nz_min", 0.1)),
        ),
        limit=_int_or_none(run_section.get("limit")),
        experiment_root=Path(run_section.get("experiment_root", "experiments")),
        experiment_name=_str_or_none(run_section.get("experiment_name")),
        log_path=_path_or_none(run_section.get("log_path", DEFAULT_LOG_PATH)),
        seed=int(run_section.get("seed", 42)),
        json_summary=bool(run_section.get("json_summary", False)),
    )