Configuration#
This page explains, in usage order, the full public functionality of Lactuca’s global configuration object:
The top-level alias
config— the recommended interface for all user code.The class
Config— available for type annotations and advanced use cases.
Both reference the same process-level singleton. config is a dynamic proxy that always
delegates to the active singleton, so it remains valid even after Config.reset().
Mental model#
Think of configuration in three layers:
Current in-memory state (what calculations use immediately).
Persistent TOML file (optional on-disk state).
Singleton lifecycle (one shared object per Python process).
Most user confusion disappears if you keep these three layers separate.
Accessing the singleton#
The recommended way is to import config directly:
from lactuca import config
config.decimals.annuities = 4
config is a transparent proxy: every attribute access delegates to the active
singleton at call time. It is always safe to use, even after Config.reset().
For type annotations or direct singleton construction, import Config:
from lactuca import Config
cfg1 = Config()
cfg2 = Config()
print(cfg1 is cfg2) # True
Note
Any change to config or Config() applies immediately to all subsequent
calculations in the same Python process.
Reading configuration values#
Read one key: get#
from lactuca import Config
cfg = Config()
mode = cfg.get("calculation_mode")
print(mode) # 'discrete_precision'
If the key does not exist and no fallback is provided, get raises KeyError.
from lactuca import Config
cfg = Config()
value = cfg.get("non_existing_key", "fallback")
print(value) # 'fallback'
Read all keys: as_dict#
from lactuca import Config
cfg = Config()
snapshot = cfg.as_dict()
print("calculation_mode" in snapshot) # True
as_dict() returns a shallow snapshot of the current validated state.
Iterate key/value pairs#
Config is iterable:
from lactuca import Config
cfg = Config()
for key, value in cfg:
if key in {"calculation_mode", "lx_interpolation"}:
print(key, value)
Updating values#
Update one key: set#
from lactuca import config
config.set("calculation_mode", "continuous_precision")
print(config.calculation_mode) # 'continuous_precision'
config.reset_to_defaults() # restore defaults after example
Update many keys atomically: set_many#
from lactuca import config
config.set_many({
"calculation_mode": "discrete_simplified",
"lx_interpolation": "exponential",
"decimals_annuities": 8,
})
print(config.calculation_mode) # 'discrete_simplified'
print(config.lx_interpolation) # 'exponential'
print(config.decimals.annuities) # 8
config.reset_to_defaults() # restore defaults after example
set_many is all-or-nothing: if one value is invalid, none of the changes are applied.
It is also thread-safe; concurrent calls from multiple threads are serialized automatically.
Property style (shortcut)#
For common settings, properties are available:
from lactuca import config
config.calculation_mode = "discrete_precision"
config.lx_interpolation = "linear"
config.force_integer_ts = False
config.reset_to_defaults() # restore defaults after example
Decimal settings via decimals proxy#
Use the grouped proxy for autocompletion and readability:
from lactuca import config
config.decimals.qx = 8
config.decimals.lx = 12
config.decimals.annuities = 8
print(config.decimals.qx) # 8
print(config.decimals.annuities) # 8
config.reset_to_defaults() # restore defaults after example
Equivalent flat-key form:
from lactuca import config
config.set("decimals_qx", 8)
print(config.decimals.qx) # 8
config.reset_to_defaults() # restore defaults after example
For full rounding semantics and table-specific availability, see Decimal Precision and Rounding.
Persistence methods (TOML)#
config_path and path#
Both properties expose the current target file path:
from lactuca import Config
cfg = Config()
print(cfg.config_path)
print(cfg.path) # alias of config_path
save(file_path=None, overwrite=False)#
Serializes current in-memory config to TOML.
Writes atomically.
Raises
FileExistsErrorif target exists with different content andoverwrite=False.
from lactuca import config
config.set("calculation_mode", "continuous_precision")
config.save("./my_config.toml", overwrite=True)
config.reset_to_defaults() # restore defaults after example
save_as(file_path, overwrite=False)#
Convenience wrapper around save for explicit “save to new path” intent.
from lactuca import config
config.save_as("./backup_config.toml", overwrite=True)
save_if_changed(file_path=None)#
Writes only when on-disk content differs. Returns True if a write occurred, False otherwise.
from lactuca import config
changed = config.save_if_changed("./my_config.toml")
print(changed) # True or False
load(file_path=None)#
Loads TOML values and merges them over the current in-memory state. Only keys present in the file are overwritten.
from lactuca import config
config.load("./my_config.toml")
print(config.calculation_mode)
Note
Config(config_path="...") is honored only on first singleton creation.
If the singleton already exists, use config.load("...") to switch to another file explicitly.
Reset methods and singleton lifecycle#
reset_to_defaults() (instance method)#
Restores factory defaults in memory.
Keeps the same singleton object identity.
Does not write to disk automatically.
from lactuca import config
config.reset_to_defaults()
Config.reset() (class method)#
Clears the singleton instance.
Next
Config()call creates a fresh object.config(the proxy) automatically picks up the new singleton on next access.Variables bound directly to
Config()(e.g.cfg = Config()) become stale.
from lactuca import Config, config
Config.reset()
# config proxy is still valid — it creates a new singleton on next access
print(config.decimals.annuities) # reads from newly created singleton
Use Config.reset() mainly in tests and controlled bootstrap scenarios.
For notebooks and scripts, reset_to_defaults() is usually safer.
Recommended usage patterns#
Pattern A: Notebook/session work#
from lactuca import config
config.reset_to_defaults()
config.calculation_mode = "discrete_precision"
config.lx_interpolation = "linear"
Pattern B: Batch update + persist once#
from lactuca import config
config.set_many({
"calculation_mode": "continuous_precision",
"lx_interpolation": "exponential",
"decimals_annuities": 10,
})
config.save_if_changed("./pricing_config.toml")
config.reset_to_defaults() # optional cleanup for shared sessions
Pattern C: Test isolation#
from lactuca import Config, config
Config.reset() # destroy singleton; next access via config recreates it
config.reset_to_defaults() # deterministic baseline on the fresh singleton
Settings reference#
Table path#
Setting |
Default |
Allowed values / type |
Purpose |
|---|---|---|---|
|
|
path-like / string |
Directory for |
See Bundled Actuarial Tables for installation and usage of bundled tables.
Calculation controls#
Setting |
Default |
Allowed values |
Purpose |
|---|---|---|---|
|
|
|
Selects valuation engine behavior for annuities, insurances, and pure endowments. All four modes are actuarially coherent (same product/conventions) but not numerically identical — see Actuarial coherence across modes. |
|
|
|
Fractional-age survival between integer ages (UDD / CFM); affects \({}_tp_x\), annuity grids, \({}_n E_x\) — not insurance \(\delta_m\). |
|
|
|
Method used by force-of-mortality routines (continuous modes only). |
|
|
|
Death-benefit payment timing within each sub-period ( |
|
|
|
If |
Note
Two independent mortality settings: lx_interpolation bridges fractional ages for
survival probabilities; mortality_placement sets insurance benefit discount timing only.
Neither substitutes for the other. See Two independent mortality settings in Calculation Modes.
See:
Calendar and date parsing#
Setting |
Default |
Allowed values |
Purpose |
|---|---|---|---|
|
|
|
Parsing order for ambiguous date strings and default format for date formatting helpers. |
|
|
|
Calendar constant for date-based age/fraction conversions. |
|
|
|
Weekly conversion constant. |
"ymd_int" accepts 8-digit YYYYMMDD input as integer (example: 19650315) or numeric string (example: "19650315").
See Date Utilities Guide for all accepted date input forms.
Decimal precision#
All decimal settings accept non-negative integers.
Setting |
Default |
|---|---|
|
15 |
|
15 |
|
15 |
|
15 |
|
15 |
|
15 |
|
15 |
|
15 |
|
15 |
|
15 |
|
15 |
|
10 |
|
10 |
|
10 |
|
10 |
|
10 |
|
10 |
|
10 |
|
10 |
For rounding pipeline details and per-table availability, see Decimal Precision and Rounding.
TOML file layout#
Config recognizes a canonical section layout for TOML files:
[paths][calculation][calendar][mortality][decimals]
In this context, canonical means that these are the standard section names used by Lactuca when reading and writing TOML configuration files. It does not mean that the example below is an exhaustive list of every supported key.
The following example is intentionally abbreviated to show the expected
structure. In particular, the [decimals] section may contain all supported
decimal keys, not just the four shown below.
[paths]
actuarial_tables = "/data/my_actuarial_tables"
[calculation]
calculation_mode = "discrete_precision"
lx_interpolation = "linear"
force_integer_ts = false
[calendar]
date_format = "ymd"
days_per_year = 365.25
weeks_per_year = 52.1775
[mortality]
force_mortality_method = "finite_difference"
mortality_placement = "mid"
[decimals]
lx = 15
qx = 8
annuities = 8
insurances = 8
When you call load(), omitted keys are left unchanged if a configuration is
already loaded, or keep their library defaults if they were never overridden.
When you call save() or save_if_changed(), Lactuca writes the full current
configuration using the canonical section layout, including all decimal fields
present in Config.
See also#
Calculation Modes — engine behavior by calculation mode
lx Interpolation — UDD vs CFM interpolation assumptions
Force of Mortality Methods — force-of-mortality method comparison
Decimal Precision and Rounding — decimal write semantics and rounding pipeline
Date Utilities Guide — accepted date formats and date parsing behavior
Bundled Actuarial Tables — bundled table installation and paths