archivebox.config.collection

Module Contents

Functions

_coerce_to_str_dict

Project an arbitrary config payload to flat {UPPER_KEY: str} form.

_load_file_config_dict

Return (flat_dict, mtime) for ArchiveBox.conf (({}, None) if missing).

_resolve_section_for_key

_render_config_file_content

Render a flat config dict to INI text, grouped by inferred section.

_write_file_if_changed

Atomic-write ArchiveBox.conf only when contents actually differ.

mirror_machine_config_to_file

Rewrite ArchiveBox.conf so it mirrors Machine.config exactly.

_coerce_from_str_dict

Inverse of _coerce_to_str_dict: decode complex INI values to native.

_mirror_file_to_machine_config

Copy ArchiveBox.conf contents into Machine.config.

sync_machine_and_file

One-time-per-process reconciliation between the two stores.

write_config_file

Merge config into ArchiveBox.conf, validate, then mirror to Machine.config.

Data

CONFIG_FILE_HEADER

_MIRROR_IN_PROGRESS

_INITIAL_SYNC_DONE

API

archivebox.config.collection.CONFIG_FILE_HEADER = <Multiline-String>[source]
archivebox.config.collection._MIRROR_IN_PROGRESS: bool[source]

False

archivebox.config.collection._INITIAL_SYNC_DONE: bool[source]

False

archivebox.config.collection._coerce_to_str_dict(config: Any) dict[str, str][source]

Project an arbitrary config payload to flat {UPPER_KEY: str} form.

INI files only round-trip strings, so we normalize Machine.config values to strings on the way out and accept the same shape on the way back. Pydantic re-coerces types at read time inside get_config.

Composite values (dict / list / tuple) are JSON-encoded so they round-trip back through pydantic-settings — str(some_dict) would produce Python’s repr ({'k': 'v'} with single quotes), and pydantic-settings refuses to parse that as a dict field, causing e.g. ABX_INSTALL_CACHE to crash with ValidationError: Input should be a valid dictionary.

archivebox.config.collection._load_file_config_dict() tuple[dict[str, str], float | None][source]

Return (flat_dict, mtime) for ArchiveBox.conf (({}, None) if missing).

archivebox.config.collection._resolve_section_for_key(key: str, config_sections, plugin_configs) str[source]
archivebox.config.collection._render_config_file_content(config: dict[str, str]) str[source]

Render a flat config dict to INI text, grouped by inferred section.

archivebox.config.collection._write_file_if_changed(content: str) bool[source]

Atomic-write ArchiveBox.conf only when contents actually differ.

Skipping unchanged writes is the difference between every Machine.save in a hot autodetection loop costing one disk write vs. zero.

archivebox.config.collection.mirror_machine_config_to_file(config: Any) None[source]

Rewrite ArchiveBox.conf so it mirrors Machine.config exactly.

Called from Machine.save after the row is committed. Recursion-guarded so the matching write_config_file -> Machine.save bounce doesn’t loop.

archivebox.config.collection._coerce_from_str_dict(file_config: dict[str, str]) dict[str, Any][source]

Inverse of _coerce_to_str_dict: decode complex INI values to native.

mirror_machine_config_to_file JSON-encodes dict / list values so they round-trip through INI’s string-only storage. When reading the file back into Machine.config (a JSONField that holds native types) those strings have to be decoded — otherwise downstream consumers like _emit_machine_configMachineEvent → abx-dl see a JSON string where they expect a dict and raise TypeError. Declared fields go through pydantic-settings’ own field_is_complex / prepare_field_value so they’re decoded per annotation. Undeclared keys (e.g. ABX_INSTALL_CACHE, written dynamically by abx-dl) are JSON-decoded when their string starts with { or [ — the same shape _coerce_to_str_dict writes them as.

archivebox.config.collection._mirror_file_to_machine_config(file_config: dict[str, str]) None[source]

Copy ArchiveBox.conf contents into Machine.config.

Internal helper used by write_config_file and the startup sync — callers must hold the _MIRROR_IN_PROGRESS guard around it.

archivebox.config.collection.sync_machine_and_file(machine: Any = None) None[source]

One-time-per-process reconciliation between the two stores.

Cheap on the common case where they already agree (single stat + dict compare ≈ 1ms). When the two sides diverge we merge them: each side’s unique keys are preserved, and for keys present on both we let the newer side win (file mtime vs. Machine.modified_at). After the merge both stores hold the union, so every subsequent write keeps them in lockstep via the full-replace mirror functions.

Pass machine when the caller already has a current Machine instance (e.g. from Machine.current()) to skip the 10–15ms get_host_guid() round-trip on the cold path.

archivebox.config.collection.write_config_file(config: dict[str, str]) archivebox.misc.logging.AttrDict[source]

Merge config into ArchiveBox.conf, validate, then mirror to Machine.config.

Backwards-compatible signature: callers (CLI archivebox config --set and the init flow) pass a partial dict of keys to upsert.