Configuration
NDAstro engine is configurable via environment variables or at runtime using configure(). All settings are collected in the EngineSettings dataclass and can be selectively overridden without restarting the process.
Settings Reference
| Setting | Env variable | Default | Valid values |
|---|---|---|---|
position_reference |
NDASTRO_POSITION_REFERENCE |
geocentric |
geocentric, topocentric |
node_type |
NDASTRO_NODE_TYPE |
true |
true, mean |
ayanamsa_delta |
NDASTRO_AYANAMSA_DELTA |
0.0 |
any float (degrees) |
dasa_year_length |
NDASTRO_DASA_YEAR_LENGTH |
365.25 |
any float (days) |
apply_nutation |
NDASTRO_APPLY_NUTATION |
true |
true, false |
apply_aberration |
NDASTRO_APPLY_ABERRATION |
true |
true, false |
apply_grav_deflection |
NDASTRO_APPLY_GRAV_DEFLECTION |
true |
true, false |
sunrise_definition |
NDASTRO_SUNRISE_DEFINITION |
geometric |
geometric, disc_centre |
Environment Variables
Set settings via a .env file or shell environment before importing the package:
# .env
NDASTRO_POSITION_REFERENCE=geocentric
NDASTRO_NODE_TYPE=true
NDASTRO_AYANAMSA_DELTA=0.0
NDASTRO_DASA_YEAR_LENGTH=365.25
NDASTRO_SUNRISE_DEFINITION=geometric
These are read once at import time via EngineSettings.from_env().
Runtime Configuration
Use configure() to change settings at runtime without restarting:
from ndastro_engine.config import configure, EngineSettingsOverride
# Override specific settings — unset fields keep their env/default values
configure(EngineSettingsOverride(
node_type="mean",
position_reference="geocentric",
))
Only the fields you set in EngineSettingsOverride are applied; everything else stays as loaded from the environment.
Loading a .env file at runtime
from pathlib import Path
from ndastro_engine.config import configure
configure(env_file=Path("/path/to/my.env"))
You can combine both:
from ndastro_engine.config import configure, EngineSettingsOverride
configure(
EngineSettingsOverride(node_type="true"),
env_file=Path(".env.production"),
)
EngineSettings Dataclass
EngineSettings is a plain dataclass — read the active settings at any time:
from ndastro_engine.config import settings
print(settings.position_reference) # "geocentric"
print(settings.node_type) # "true"
print(settings.ayanamsa_delta) # 0.0
Per-Request Overrides
configure() changes the global settings singleton and affects every subsequent call on all threads. For web servers handling concurrent requests, use override_settings() instead — it applies a temporary override scoped to the current asyncio task (or OS thread) only, with zero effect on any other concurrent request.
override_settings()
from ndastro_engine.config import override_settings, EngineSettingsOverride
with override_settings(EngineSettingsOverride(node_type="mean")) as s:
# Inside this block, get_effective_settings().node_type == "mean"
# All other settings are inherited from the global settings.
results = get_lunar_node_positions(dt)
# Outside the block, global settings are fully restored.
Fields not set in EngineSettingsOverride inherit from the currently active settings. Overrides can be nested:
with override_settings(EngineSettingsOverride(position_reference="topocentric")):
with override_settings(EngineSettingsOverride(node_type="mean")):
# Both overrides are active here
...
# node_type restored; position_reference still "topocentric"
get_effective_settings()
Engine internals use get_effective_settings() as the single authoritative accessor. It returns the per-request override if one is active, otherwise the global settings:
from ndastro_engine.config import get_effective_settings
s = get_effective_settings()
print(s.node_type) # per-request override value, or global default
print(s.position_reference) # same
You can call this in your own code if you need to read whichever settings are currently in effect without worrying about whether an override is active.
Concurrency safety
override_settings() stores the override in a contextvars.ContextVar, which is automatically scoped to the current asyncio task. Two concurrent FastAPI requests each get their own isolated context — neither can observe the other's override.
Don't use configure() per-request
configure() mutates the global settings module attribute. Calling it inside a request handler in a concurrent server will race with every other in-flight request. Use override_settings() for request-scoped changes.
Performance
| Path | Cost |
|---|---|
get_effective_settings() (no override active) |
~90 ns — one ContextVar.get() |
override_settings() with values |
~4.6 µs — one dataclasses.replace() + ContextVar set/reset |
override_settings() with no changed fields |
~1.5 µs — fast path, skips object allocation |
These costs are negligible compared to the 5–50 ms Skyfield ephemeris lookups they wrap.
EngineSettingsOverride Dataclass
All fields are None by default. Set only the fields you want to change:
from ndastro_engine.config import EngineSettingsOverride
# Only change node type; everything else stays unchanged
override = EngineSettingsOverride(node_type="mean")
Position Reference
geocentric (default) measures planet positions from the centre of the Earth. topocentric corrects for the observer's actual location on the Earth's surface — the difference is most significant for the Moon (~1°).
from ndastro_engine.config import configure, EngineSettingsOverride
# Geocentric (default)
configure(EngineSettingsOverride(position_reference="geocentric"))
# Topocentric (observer on Earth's surface)
configure(EngineSettingsOverride(position_reference="topocentric"))
Lunar Node Type
true (default) uses the osculating (instantaneous) node — what JHora and most modern software use. mean uses the smoothed IAU 2006 polynomial (Meeus Ch. 22), which matches software such as AstroSage.
True and mean nodes can differ by up to ~1.5°.
from ndastro_engine.config import configure, EngineSettingsOverride
# True (osculating) nodes — matches JHora
configure(EngineSettingsOverride(node_type="true"))
# Mean nodes — matches AstroSage and older software
configure(EngineSettingsOverride(node_type="mean"))
Ayanamsa Delta
Apply a personal correction on top of the selected ayanamsa system:
from ndastro_engine.config import configure, EngineSettingsOverride
# Add 0.25° correction to every ayanamsa result
configure(EngineSettingsOverride(ayanamsa_delta=0.25))
Sunrise Definition
geometric (default) uses the geometric centre of the Sun crossing the horizon. disc_centre is an alias for the same centre-of-disc calculation. Future versions may add a upper_limb option.
from ndastro_engine.config import configure, EngineSettingsOverride
configure(EngineSettingsOverride(sunrise_definition="disc_centre"))
Integration with ndastro-api
When using ndastro-api, configure() is called from the FastAPI lifespan using the API's own .env file:
# ndastro_api/main.py (simplified)
from ndastro_engine.config import configure
from ndastro_api.core.config import env_path
configure(env_file=env_path)
All NDASTRO_* variables in the API's .env are forwarded to the engine automatically.