[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
COPY . /app
RUN pip install --no-cache-dir .
COPY pyproject.toml poetry.lock README.md ./
CMD [ "python", "run.py" ]
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" ]

View file

@ -1,19 +1,9 @@
"""Task config."""
from enum import Enum
from os import environ
from pathlib import Path
from typing import Optional
import orjson as json
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
from pydantic_settings import BaseSettings, SettingsConfigDict
class Environment(Enum):
@ -23,7 +13,7 @@ class Environment(Enum):
develop = "develop"
class Mongo(BaseModel):
class Mongo(BaseSettings):
"""MongoDB config."""
host: list[str] | str = "localhost"
@ -32,76 +22,19 @@ class Mongo(BaseModel):
port: int = 27017
class Config(BaseModel):
class Config(BaseSettings, case_sensitive=False):
"""Tasks config model."""
token: str
mongo: Mongo
mongo: Mongo = Mongo()
log_level: str = "INFO"
environment: Environment = Environment.develop
_config: Config = None
model_config = SettingsConfigDict(
env_file=".env", env_file_encoding="utf-8", env_nested_delimiter="."
)
def _load_json() -> Config | None:
path = Path("config.json")
if path.exists():
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")
def load_config() -> Config:
"""Load the config using the specified method first"""
return Config()

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"
croniter = "^1.4.1"
beanie = ">=1.21.0"
pydantic-settings = "^2.2.1"
[tool.poetry.dev-dependencies]
pytest = "^7.1"