diff --git a/pyninja/auth.py b/pyninja/auth.py index 8b289d9..18613f1 100644 --- a/pyninja/auth.py +++ b/pyninja/auth.py @@ -22,7 +22,7 @@ async def authenticator(token: HTTPBasicCredentials = Depends(SECURITY)) -> None auth = token.model_dump().get("credentials", "") if auth.startswith("\\"): auth = bytes(auth, "utf-8").decode(encoding="unicode_escape") - if secrets.compare_digest(auth, squire.settings.apikey): + if secrets.compare_digest(auth, squire.env.apikey): return raise exceptions.APIResponse( status_code=HTTPStatus.UNAUTHORIZED.real, detail=HTTPStatus.UNAUTHORIZED.phrase diff --git a/pyninja/main.py b/pyninja/main.py index 2589a08..464ac46 100644 --- a/pyninja/main.py +++ b/pyninja/main.py @@ -9,8 +9,8 @@ def start(env_file: str = None) -> None: """Starter function for the API, which uses uvicorn server as trigger.""" - squire.settings = squire.Settings().from_env_file( - env_file=env_file + squire.env = squire.env_loader( + env_file or os.environ.get("env_file") or os.environ.get("ENV_FILE") or ".env" @@ -19,6 +19,4 @@ def start(env_file: str = None) -> None: routes=router.routes, title=f"Service monitor for {platform.uname().node}", ) - uvicorn.run( - host=squire.settings.monitor_host, port=squire.settings.monitor_port, app=app - ) + uvicorn.run(host=squire.env.monitor_host, port=squire.env.monitor_port, app=app) diff --git a/pyninja/squire.py b/pyninja/squire.py index 19b5c48..8860954 100644 --- a/pyninja/squire.py +++ b/pyninja/squire.py @@ -1,6 +1,10 @@ +import json +import os +import pathlib import socket from typing import Optional +import yaml from pydantic import BaseModel, PositiveInt from pydantic_settings import BaseSettings @@ -17,7 +21,7 @@ class ServiceStatus(BaseModel): description: str -class Settings(BaseSettings): +class EnvConfig(BaseSettings): """Object to load environment variables. >>> Settings @@ -30,7 +34,7 @@ class Settings(BaseSettings): apikey: str @classmethod - def from_env_file(cls, env_file: Optional[str]) -> "Settings": + def from_env_file(cls, env_file: Optional[str]) -> "EnvConfig": """Create Settings instance from environment file. Args: @@ -48,4 +52,35 @@ class Config: extra = "ignore" -settings = Settings +def env_loader(filename: str | os.PathLike) -> EnvConfig: + """Loads environment variables based on filetypes. + + Args: + filename: Filename from where env vars have to be loaded. + + Returns: + config.EnvConfig: + Returns a reference to the ``EnvConfig`` object. + """ + env_file = pathlib.Path(filename) + if env_file.suffix.lower() == ".json": + with open(env_file) as stream: + env_data = json.load(stream) + return EnvConfig(**{k.lower(): v for k, v in env_data.items()}) + elif env_file.suffix.lower() in (".yaml", ".yml"): + with open(env_file) as stream: + env_data = yaml.load(stream, yaml.FullLoader) + return EnvConfig(**{k.lower(): v for k, v in env_data.items()}) + elif not env_file.suffix or env_file.suffix.lower() in ( + ".text", + ".txt", + "", + ): + return EnvConfig.from_env_file(env_file) + else: + raise ValueError( + "\n\tUnsupported format for 'env_file', can be one of (.json, .yaml, .yml, .txt, .text, or null)" + ) + + +env = EnvConfig diff --git a/pyproject.toml b/pyproject.toml index 854a933..2b5ff42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ keywords = ["service-monitor", "PyNinja"] requires-python = ">=3.10" [tool.setuptools] -packages = ["monitor"] +packages = ["pyninja"] [tool.setuptools.dynamic] version = {attr = "pyninja.version"} diff --git a/requirements.txt b/requirements.txt index 009f065..1e1826f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,5 @@ fastapi==0.112.0 psutil==6.0.0 pydantic==2.8.2 pydantic-settings==2.4.0 +PyYaml==6.0.2 uvicorn==0.30.5