11"""Configuration loading and validation."""
2- import os
3- from pathlib import Path
2+
43from typing import Optional
54
6- import tomllib
7- from dotenv import load_dotenv
85from loguru import logger
9- from pydantic import BaseModel , validator
10-
11- load_dotenv ()
6+ from pydantic import BaseModel
7+ from pydantic_settings import BaseSettings
128
139
14- # All the locations where we might find a config file
15- CONFIG_PATHS = [
16- "./olli.toml" ,
17- "/config/olli.toml" ,
18- "/olli/config.toml" ,
19- "/etc/olli/config.toml"
20- ]
10+ class EnvConfig (
11+ BaseSettings ,
12+ env_file = ".env" ,
13+ env_file_encoding = "utf-8" ,
14+ env_nested_delimiter = "__" ,
15+ extra = "ignore" ,
16+ ):
17+ """Our default configuration for models that should load from .env files."""
2118
2219
23- class TokenConfig (BaseModel ):
24- """Class representing a token config entry."""
25-
26- token : str
27- color : Optional [str ] = "#7289DA"
28- case_sensitive : Optional [bool ] = False
29-
30-
31- class LokiConfig (BaseModel ):
20+ class _LokiConfig (EnvConfig , env_prefix = "loki_" ):
3221 """Loki specific configuration."""
3322
3423 api_url : str
3524 jobs : list [str ]
3625 max_logs : Optional [int ] = 5_000
3726
3827
39- class DiscordConfig (BaseModel ):
28+ LOKI_CONFIG = _LokiConfig ()
29+
30+
31+ class _DiscordConfig (EnvConfig , env_prefix = "discord_" ):
4032 """Configuration for Discord alerting."""
4133
4234 webhook_url : Optional [str ]
4335
44- @validator ("webhook_url" , always = True )
45- def env_provided_webhook (cls , value : Optional [str ]) -> str :
46- """
47- If no webhook is specified in the config, try fetch from environment.
4836
49- If not found in the environment either then raise a validation error.
50- """
51- if value :
52- return value
37+ DISCORD_CONFIG = _DiscordConfig ()
5338
54- if webhook := os .environ .get ("WEBHOOK_URL" ):
55- return webhook
5639
57- raise ValueError (
58- "Must specify webhook_url under [discord] or WEBHOOK_URL env var"
59- )
40+ class TokenConfig (BaseModel ):
41+ """Class representing a token config entry."""
6042
43+ token : str
44+ color : Optional [str ] = "#7289DA"
45+ case_sensitive : Optional [bool ] = False
6146
62- class ServiceConfig (BaseModel ):
47+
48+ class _ServiceConfig (EnvConfig , env_prefix = "service_" ):
6349 """Configuration of the Olli status."""
6450
6551 interval_minutes : int
@@ -81,40 +67,10 @@ def warn_above_ten(cls, value: list[TokenConfig]) -> list[TokenConfig]:
8167 This is because we cannot handle more than 10 token triggers at once until we
8268 batch triggers into groups of 10 to distribute to the webhook.
8369 """
84- if len (value ) > 10 :
85- logger .warning (
86- "More than 10 token triggers in one period cannot be handled, be careful."
87- )
70+ if len (value ) > 10 : # noqa: PLR2004
71+ logger .warning ("More than 10 token triggers in one period cannot be handled, be careful." )
8872
8973 return value
9074
9175
92- class OlliConfig (BaseModel ):
93- """Class representing root Olli config."""
94-
95- loki : LokiConfig
96- olli : ServiceConfig
97- discord : DiscordConfig = DiscordConfig ()
98-
99-
100- def get_config () -> OlliConfig :
101- """Open the config file, parse the TOML and convert to Pydantic objects."""
102- logger .info ("Searching for config file" )
103-
104- path = None
105-
106- for file_path in CONFIG_PATHS :
107- if (config_file := Path (file_path )).exists ():
108- path = config_file
109- logger .info (f"Found config at { file_path } " )
110- break
111-
112- if not path :
113- logger .critical ("Could not find a config file. Please refer to the documentation." )
114- raise SystemExit (1 )
115-
116- with open (config_file , "rb" ) as conf_file :
117- return OlliConfig (** tomllib .load (conf_file ))
118-
119-
120- CONFIG = get_config ()
76+ SERVICE_CONFIG = _ServiceConfig ()
0 commit comments