[feat] Docker-first configuration

This commit is contained in:
Zeva Rose 2024-03-04 18:43:53 -07:00
parent 0819d4bb85
commit b920ee56fb
4 changed files with 810 additions and 858 deletions

View file

@ -1,8 +1,27 @@
FROM python:3.10 FROM python:3.12-bookworm as builder
RUN pip install poetry==1.7.1
ENV POETRY_NO_INTERACTION=1 \
POETRY_VIRTUALENVS_IN_PROJECT=1 \
POETRY_VIRTUALENVS_CREATE=1 \
POETRY_CACHE_DIR=/tmp/poetry_cache
WORKDIR /app WORKDIR /app
COPY . /app COPY pyproject.toml poetry.lock README.md ./
RUN pip install --no-cache-dir .
RUN poetry install --without dev --no-root && rm -rf $POETRY_CACHE_DIR
FROM python:3.12-slim-bookworm as runtime
WORKDIR /app
ENV VIRTUAL_ENV=/app/.venv \
PATH="/app/.venv/bin:$PATH"
COPY --from=builder ${VIRTUAL_ENV} ${VIRTUAL_ENV}
COPY . /app/
CMD [ "python", "run.py" ] CMD [ "python", "run.py" ]

View file

@ -1,19 +1,9 @@
"""Task config.""" """Task config."""
from enum import Enum from enum import Enum
from os import environ
from pathlib import Path
from typing import Optional from typing import Optional
import orjson as json from pydantic_settings import BaseSettings, SettingsConfigDict
import yaml
from dotenv import load_dotenv
from jarvis_core.util import find_all
from pydantic import BaseModel
try:
from yaml import CLoader as Loader
except ImportError:
from yaml import Loader
class Environment(Enum): class Environment(Enum):
@ -23,7 +13,7 @@ class Environment(Enum):
develop = "develop" develop = "develop"
class Mongo(BaseModel): class Mongo(BaseSettings):
"""MongoDB config.""" """MongoDB config."""
host: list[str] | str = "localhost" host: list[str] | str = "localhost"
@ -32,76 +22,19 @@ class Mongo(BaseModel):
port: int = 27017 port: int = 27017
class Config(BaseModel): class Config(BaseSettings, case_sensitive=False):
"""Tasks config model.""" """Tasks config model."""
token: str token: str
mongo: Mongo mongo: Mongo = Mongo()
log_level: str = "INFO" log_level: str = "INFO"
environment: Environment = Environment.develop environment: Environment = Environment.develop
model_config = SettingsConfigDict(
_config: Config = None env_file=".env", env_file_encoding="utf-8", env_nested_delimiter="."
)
def _load_json() -> Config | None: def load_config() -> Config:
path = Path("config.json") """Load the config using the specified method first"""
if path.exists(): return Config()
with path.open() as f:
j = json.loads(f.read())
return Config(**j)
def _load_yaml() -> Config | None:
path = Path("config.yaml")
if path.exists():
with path.open() as f:
y = yaml.load(f.read(), Loader=Loader)
return Config(**y)
def _load_env() -> Config | None:
load_dotenv()
data = {}
mongo = {}
mongo_keys = find_all(lambda x: x.upper().startswith("MONGO"), environ.keys())
config_keys = mongo_keys + ["TOKEN", "LOG_LEVEL", "ENVIRONMENT"]
for item, value in environ.items():
if item not in config_keys:
continue
if item in mongo_keys:
key = "_".join(item.split("_")[1:]).lower()
mongo[key] = value
else:
data[item.lower()] = value
data["mongo"] = mongo
return Config(**data)
def load_config(method: Optional[str] = None) -> Config:
"""
Load the config using the specified method first
Args:
method: Method to use first
"""
global _config
if _config is not None:
return _config
methods = {"yaml": _load_yaml, "json": _load_json, "env": _load_env}
method_names = list(methods.keys())
if method and method in method_names:
method_names.remove(method)
method_names.insert(0, method)
for method in method_names:
if _config := methods[method]():
return _config
raise FileNotFoundError("Missing one of: config.yaml, config.json, .env")

1551
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,7 @@ pydantic = ">=2.3.0,<3"
# rocketry = "^2.5.1" # rocketry = "^2.5.1"
croniter = "^1.4.1" croniter = "^1.4.1"
beanie = ">=1.21.0" beanie = ">=1.21.0"
pydantic-settings = "^2.2.1"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "^7.1" pytest = "^7.1"