e1250's picture
fix: add config to backend
e515383
Raw
History Blame
5.11 kB
from pathlib import Path
from typing import Literal, List
from pydantic import BaseModel
from pydantic_settings import BaseSettings, DotEnvSettingsSource, EnvSettingsSource, SettingsConfigDict, PydanticBaseSettingsSource, YamlConfigSettingsSource
import yaml
def join_tag(loader, node):
"""
Help joining pathes in config.YAML directly.
"""
parts = loader.construct_sequence(node)
path = Path(*(str(part) for part in parts)).resolve()
return str(path)
# It didn't work before, After some research, .SafeLoaded is unmentioned must for my case.
yaml.SafeLoader.add_constructor("!join", join_tag)
class PathsConfig(BaseModel):
"""Contains paths of directories"""
project_dir: str
models_dir: str
logs_dir: str
class YoloConfig(BaseModel):
"""Contains yolo configurations"""
model_path: str
classes: List[str]
batch_size: int
epochs: int
wandb: bool
augment: bool
data_path: str
class SecurityDetector(BaseModel):
"Contains Security Detectors like Smoke - Fire"
model_path: str
classes: List[str]
class DepthConfig(BaseModel):
"Contains depths estimation configurations"
model_path: str
encoder: Literal["vits", "vitb", "vitl", "vitg"]
class IntervalsConfig(BaseModel):
system_metrics_seconds: float
frames_summary_every: int
realtime_updates_every: float
class AppConfig(BaseSettings):
"""
Main app Configuration
- Gets defaults from config.yaml (via load_config)
- Override values with .env
"""
# Note that it doesn't show error, Take care.
model_config = SettingsConfigDict(
env_file=Path(__file__).parent / ".env",
env_file_encoding="utf-8",
yaml_file=Path(__file__).parent / "config.yaml",
# case_sensitive=False, # default True
# env_prefix="YOLO_", # Means configs we are talking about starts with YOLO_
# env_nested_delimiter="__", # Means we use _ instead of spaces for the same var
extra="ignore" # Ignore other settings in yaml and env as they are not mentioedhere
)
project_name:str
project_desc:str
task: Literal["indoor", "outdoor"]
paths: PathsConfig
yolo: YoloConfig
security_detector: SecurityDetector
depth: DepthConfig
intervals: IntervalsConfig
# Backend
@classmethod
def settings_customise_sources(cls,
settings_cls: type[BaseSettings], # Base param.
# init_settings: PydanticBaseSettingsSource, # Values passed to __init__
# env_settings: PydanticBaseSettingsSource, # OS Env variables
# dotenv_settings: PydanticBaseSettingsSource,
# file_secret_settings: PydanticBaseSettingsSource # Secret Directories
**kwargs
) -> tuple[PydanticBaseSettingsSource, ...] :
"""
Once you use this, no need to use load_config, it is already the same.
But this time it fixs the priority part, order by parameters priority.
"""
# Order by priority
return (
DotEnvSettingsSource(settings_cls), # Most important
EnvSettingsSource(settings_cls), # This allow for ex. hugging face to override .env values with its values.
YamlConfigSettingsSource(settings_cls),
) # The return must be a tuple
# @classmethod
# def load_config(cls, yaml_path: Path | str = Path(__file__).parent / "config.yaml") -> "AppConfig":
# """Loading confiuration and settings from Config.yaml file then override using .env"""
# yaml_path = Path(yaml_path).resolve() # Absolute path
# if not yaml_path.is_file():
# raise FileNotFoundError(f"Config file not found: {yaml_path}")
# with yaml_path.open("r") as f:
# yaml_data = yaml.safe_load(f) or {}
# # env_data = cls() # This one loaded .env and not Yaml
# # When this project grow, you are going to create different types of .yaml files for products and debugging and so on
# # Feel free to stack them here, so we use the yaml required for our testing
# # Note that in debuging.yaml file, we only override the base, not starting from scratch.
# # return cls(**{
# # **yaml_data, # Loading config.yaml configurations
# # # **env_data.model_dump() # TODO(FIX) Overriding everything using .env
# # })
# return cls(**yaml_data)
if __name__ == "__main__":
# Note that we must use AppConfig without () to take .env in mind.
# Checking for YAML part.
# config = AppConfig.load_config()
# print(config.model_dump())
# print(config.model_dump()["project_name"])
# Checking for .env file.
# config = AppConfig()
# print(f".env Path we are talking about: {Path(__file__).parent / ".env"}")
# print(config.model_config)
# print(config.project_name)
# Trying to checking both yaml and .env. This works really fine now.
config = AppConfig()
print(config.model_dump())
print(config.model_dump()["project_name"])