Spaces:
Sleeping
Sleeping
| 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 | |
| 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"]) |