Spaces:
Sleeping
Sleeping
File size: 5,106 Bytes
e515383 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | 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"]) |