Files
2026-06-27 16:21:30 -07:00

94 lines
2.5 KiB
Python

"""Dotenv file discovery and explicit dotenv override helpers."""
from __future__ import annotations
import os
from collections.abc import Mapping
from pathlib import Path
from typing import Any
from dotenv import dotenv_values
from .paths import managed_env_path
ANTHROPIC_AUTH_TOKEN_ENV = "ANTHROPIC_AUTH_TOKEN"
def repo_env_path() -> Path:
"""Return the repo-local env path."""
return Path(".env")
def explicit_env_path(env: Mapping[str, str] | None = None) -> Path | None:
"""Return the explicit FCC_ENV_FILE path, when configured."""
source = env if env is not None else os.environ
if explicit := source.get("FCC_ENV_FILE"):
return Path(explicit)
return None
def settings_env_files(env: Mapping[str, str] | None = None) -> tuple[Path, ...]:
"""Return Settings dotenv files in low-to-high precedence order."""
files: list[Path] = [
repo_env_path(),
managed_env_path(),
]
if explicit := explicit_env_path(env):
files.append(explicit)
return tuple(files)
def configured_env_files(model_config: Mapping[str, Any]) -> tuple[Path, ...]:
"""Return the env files currently configured for a Settings model."""
configured = model_config.get("env_file")
if configured is None:
return ()
if isinstance(configured, (str, Path)):
return (Path(configured),)
return tuple(Path(item) for item in configured)
def env_file_value(path: Path, key: str) -> str | None:
"""Return a dotenv value when the file explicitly defines the key."""
if not path.is_file():
return None
try:
values = dotenv_values(path)
except OSError:
return None
if key not in values:
return None
value = values[key]
return "" if value is None else value
def env_file_override(model_config: Mapping[str, Any], key: str) -> str | None:
"""Return the last configured dotenv value that explicitly defines a key."""
configured_value: str | None = None
for env_file in configured_env_files(model_config):
value = env_file_value(env_file, key)
if value is not None:
configured_value = value
return configured_value
def process_env_key_is_effective(
model_config: Mapping[str, Any],
key: str,
env: Mapping[str, str] | None = None,
) -> bool:
"""Return whether a key is coming from process env instead of configured dotenv."""
source = env if env is not None else os.environ
if env_file_override(model_config, key) is not None:
return False
return key in source