Configuration

diveplan.core.config

Dive configuration — physical constants, planning parameters, gas limits.

Validation philosophy: reject physically impossible values (negative pressure, zero density) but impose no operational upper bounds — diveplan is an experimentation platform.

Default config loading — priority chain (highest to lowest)

  1. DIVEPLAN_CONFIG_FILE env var — path to a JSON config file

  2. ./diveplan.config.json — project-level config in CWD

  3. ~/.diveplan/config.json — user-level config in home directory

  4. factory defaults — built-in defaults

Set DIVEPLAN_NO_FILE_CONFIG=1 to skip steps 1-3 and always use factory defaults. Useful for CI, testing, or any environment where predictable defaults are required.

Invalid files at any level are skipped with a warning and the next level is tried.

Usage

# read and mutate the global config
from diveplan.core.config import DiveConfig

DiveConfig.current().physics.water_density = 1.0
DiveConfig.current().physics.surface_pressure_mbar = 800
DiveConfig.current().physics.gravity = 9.7

DiveConfig.current().planning.ascent_rate = 9.0
DiveConfig.current().planning.last_stop_m = 6.0
DiveConfig.current().planning.sample_rate_s = 2

DiveConfig.current().gas.max_ppo2_bar = 1.4
DiveConfig.current().gas.deco_ppo2_bar = 1.6
DiveConfig.current().gas.min_ppo2_bar = 0.18
DiveConfig.current().gas.max_ppn2_bar = 3.2
DiveConfig.current().gas.max_end_m = 30.0
DiveConfig.current().gas.sac_bottom = 20.0
DiveConfig.current().gas.sac_deco = 15.0
DiveConfig.current().gas.gas_switch_minutes = 1.0
DiveConfig.current().gas.gas_switch_at_stops_only = True

# permanent global replacement
custom = DiveConfig()
custom.gas.max_ppo2_bar = 1.2
custom.planning.ascent_rate = 8.0
DiveConfig.set_default(custom)

# scoped override — stack-based, supports nesting
altitude = DiveConfig()
altitude.physics.surface_pressure_mbar = 800
altitude.physics.water_density = 1.0

with altitude:
    DiveConfig.current().physics.surface_pressure_mbar  # 800
DiveConfig.current().physics.surface_pressure_mbar      # restored

# JSON round-trip
DiveConfig.current().to_json(path="my_config.json")
cfg = DiveConfig.from_json(path="my_config.json")
DiveConfig.set_default(cfg)
class diveplan.core.config.DiveConfig(**data)[source]

Bases: BaseModel

Root configuration object.

DiveConfig itself is frozen — sub-configs are swapped at construction time or via scoped overrides. Mutations happen inside sub-configs:

DiveConfig.current().gas.max_ppo2_bar = 2.0 # ✅ sub-config mutation DiveConfig.current().gas = GasConfig(…) # ❌ frozen, not allowed

See module docstring for the full default loading priority chain.

Parameters:
  • data (Any)

  • physics (_PhysicsConfig)

  • planning (_DivePlanningConfig)

  • gas (_GasConfig)

model_config: ClassVar[ConfigDict] = {'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

classmethod current()[source]

Return the active config — top of the (context-local) stack, or startup default.

Return type:

DiveConfig

classmethod set_default(config)[source]

Permanently replace the global default config.

Parameters:

config (DiveConfig)

Return type:

None

classmethod reset_default()[source]

Restore factory defaults and clear the stack — useful in tests.

Return type:

None

to_json(path=None, indent=2)[source]

Serialize to JSON string, optionally writing to file.

Parameters:
Return type:

str

classmethod from_json(data=None, path=None)[source]

Deserialize from JSON string or file path.

Parameters:
Return type:

DiveConfig