From 38dae9f0c34fa2073210415d69bdb0e179e321dc Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Fri, 20 Sep 2024 15:18:53 +0530 Subject: [PATCH 1/6] allow installing plugs from env --- install_plugins.py | 12 ++++++++++++ plugs/manager.py | 21 ++++++++++++++------- plugs/plug.py | 17 ++++++++--------- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/install_plugins.py b/install_plugins.py index 8324ff795b..1676f43d21 100644 --- a/install_plugins.py +++ b/install_plugins.py @@ -1,3 +1,15 @@ +import json +import os + from plug_config import manager +from plugs.plug import Plug + +if ADDITIONAL_PLUGS := os.getenv("ADDITIONAL_PLUGS"): + try: + for plug in json.loads(ADDITIONAL_PLUGS): + manager.add_plug(Plug(**plug)) + except json.JSONDecodeError: + print("ADDITIONAL_PLUGS is not a valid JSON") + manager.install() diff --git a/plugs/manager.py b/plugs/manager.py index c9216b31e6..7a34db349c 100644 --- a/plugs/manager.py +++ b/plugs/manager.py @@ -2,27 +2,34 @@ import sys from collections import defaultdict +from plugs.plug import Plug + class PlugManager: """ Manager to manage plugs in care """ - def __init__(self, plugs): - self.plugs = plugs + def __init__(self, plugs: list[Plug]): + self.plugs: list[Plug] = plugs - def install(self): - packages = [x.package_name + x.version for x in self.plugs] + def install(self) -> None: + packages: list[str] = [x.package_name + x.version for x in self.plugs] if packages: subprocess.check_call( [sys.executable, "-m", "pip", "install", " ".join(packages)] ) - def get_apps(self): + def add_plug(self, plug: Plug) -> None: + if not isinstance(plug, Plug): + raise ValueError("plug must be an instance of Plug") + self.plugs.append(plug) + + def get_apps(self) -> list[str]: return [plug.name for plug in self.plugs] - def get_config(self): - configs = defaultdict(dict) + def get_config(self) -> defaultdict[str, dict]: + configs: defaultdict[str, dict] = defaultdict(dict) for plug in self.plugs: for key, value in plug.configs.items(): configs[plug.name][key] = value diff --git a/plugs/plug.py b/plugs/plug.py index 043dfe5063..71b61befa5 100644 --- a/plugs/plug.py +++ b/plugs/plug.py @@ -1,10 +1,9 @@ -class Plug: - """ - Abstraction of a plugin - """ +from dataclasses import dataclass + - def __init__(self, name, package_name, version, configs): - self.name = name - self.package_name = package_name - self.version = version - self.configs = configs +@dataclass +class Plug: + name: str + package_name: str + version: str + configs: dict From 8d1810b35d8be2cc41dceb077412c9e7913ed6f7 Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Fri, 20 Sep 2024 15:29:55 +0530 Subject: [PATCH 2/6] allow defaults for plugs --- plugs/manager.py | 2 ++ plugs/plug.py | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/plugs/manager.py b/plugs/manager.py index 7a34db349c..0453d34878 100644 --- a/plugs/manager.py +++ b/plugs/manager.py @@ -31,6 +31,8 @@ def get_apps(self) -> list[str]: def get_config(self) -> defaultdict[str, dict]: configs: defaultdict[str, dict] = defaultdict(dict) for plug in self.plugs: + if plug.config is None: + continue for key, value in plug.configs.items(): configs[plug.name][key] = value return configs diff --git a/plugs/plug.py b/plugs/plug.py index 71b61befa5..dc8ee7902c 100644 --- a/plugs/plug.py +++ b/plugs/plug.py @@ -1,9 +1,17 @@ -from dataclasses import dataclass +from dataclasses import _MISSING_TYPE, dataclass, fields -@dataclass +@dataclass(slots=True) class Plug: name: str package_name: str - version: str - configs: dict + version: str = "@main" + configs: dict = {} + + def __post_init__(self) -> None: + for field in fields(self): + if ( + not isinstance(field.default, _MISSING_TYPE) + and getattr(self, field.name) is None + ): + setattr(self, field.name, field.default) From 3cbe8812a42fdd47f52674d2f9386ffb06d6eefb Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Fri, 20 Sep 2024 19:32:51 +0530 Subject: [PATCH 3/6] fix dataclass --- plugs/plug.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/plugs/plug.py b/plugs/plug.py index dc8ee7902c..16750ccee0 100644 --- a/plugs/plug.py +++ b/plugs/plug.py @@ -1,4 +1,4 @@ -from dataclasses import _MISSING_TYPE, dataclass, fields +from dataclasses import _MISSING_TYPE, dataclass, field, fields @dataclass(slots=True) @@ -6,12 +6,21 @@ class Plug: name: str package_name: str version: str = "@main" - configs: dict = {} + configs: dict = field(default_factory=dict) - def __post_init__(self) -> None: - for field in fields(self): + def __post_init__(self): + for _field in fields(self): if ( - not isinstance(field.default, _MISSING_TYPE) - and getattr(self, field.name) is None + not isinstance(_field.default, _MISSING_TYPE) + and getattr(self, _field.name) is None ): - setattr(self, field.name, field.default) + setattr(self, _field.name, _field.default) + + if not isinstance(self.name, str): + raise ValueError("name must be a string") + if not isinstance(self.package_name, str): + raise ValueError("package_name must be a string") + if not isinstance(self.version, str): + raise ValueError("version must be a string") + if not isinstance(self.configs, dict): + raise ValueError("configs must be a dictionary") From 9a5c1ff04949e2a1da409a5d796765deda088efe Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Mon, 23 Sep 2024 20:45:46 +0530 Subject: [PATCH 4/6] cleanup and fixes --- docker/prod.Dockerfile | 2 ++ install_plugins.py | 7 +++++-- plugs/__init__.py | 0 plugs/manager.py | 9 ++++----- plugs/plug.py | 14 +++++++++----- 5 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 plugs/__init__.py diff --git a/docker/prod.Dockerfile b/docker/prod.Dockerfile index 82e17739ae..79579bf56a 100644 --- a/docker/prod.Dockerfile +++ b/docker/prod.Dockerfile @@ -5,9 +5,11 @@ ARG TYPST_VERSION=0.11.0 ARG BUILD_ENVIRONMENT="production" ARG APP_VERSION="unknown" +ARG ADDITIONAL_PLUGS="{}" ENV BUILD_ENVIRONMENT=$BUILD_ENVIRONMENT ENV APP_VERSION=$APP_VERSION +ENV ADDITIONAL_PLUGS=$ADDITIONAL_PLUGS ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 ENV PATH=/venv/bin:$PATH diff --git a/install_plugins.py b/install_plugins.py index 1676f43d21..b320f0caaf 100644 --- a/install_plugins.py +++ b/install_plugins.py @@ -1,15 +1,18 @@ import json +import logging import os from plug_config import manager from plugs.plug import Plug +logger = logging.getLogger(__name__) + + if ADDITIONAL_PLUGS := os.getenv("ADDITIONAL_PLUGS"): try: for plug in json.loads(ADDITIONAL_PLUGS): manager.add_plug(Plug(**plug)) except json.JSONDecodeError: - print("ADDITIONAL_PLUGS is not a valid JSON") - + logger.error("ADDITIONAL_PLUGS is not a valid JSON") manager.install() diff --git a/plugs/__init__.py b/plugs/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugs/manager.py b/plugs/manager.py index 0453d34878..bd21eca9ab 100644 --- a/plugs/manager.py +++ b/plugs/manager.py @@ -14,15 +14,14 @@ def __init__(self, plugs: list[Plug]): self.plugs: list[Plug] = plugs def install(self) -> None: - packages: list[str] = [x.package_name + x.version for x in self.plugs] + packages: list[str] = [f"{x.package_name}{x.version}" for x in self.plugs] if packages: - subprocess.check_call( - [sys.executable, "-m", "pip", "install", " ".join(packages)] - ) + subprocess.check_call([sys.executable, "-m", "pip", "install", *packages]) # noqa: S603 def add_plug(self, plug: Plug) -> None: if not isinstance(plug, Plug): - raise ValueError("plug must be an instance of Plug") + msg = "plug must be an instance of Plug" + raise ValueError(msg) self.plugs.append(plug) def get_apps(self) -> list[str]: diff --git a/plugs/plug.py b/plugs/plug.py index 16750ccee0..c8db40e314 100644 --- a/plugs/plug.py +++ b/plugs/plug.py @@ -5,7 +5,7 @@ class Plug: name: str package_name: str - version: str = "@main" + version: str = field(default="@main") configs: dict = field(default_factory=dict) def __post_init__(self): @@ -17,10 +17,14 @@ def __post_init__(self): setattr(self, _field.name, _field.default) if not isinstance(self.name, str): - raise ValueError("name must be a string") + msg = "name must be a string" + raise ValueError(msg) if not isinstance(self.package_name, str): - raise ValueError("package_name must be a string") + msg = "package_name must be a string" + raise ValueError(msg) if not isinstance(self.version, str): - raise ValueError("version must be a string") + msg = "version must be a string" + raise ValueError(msg) if not isinstance(self.configs, dict): - raise ValueError("configs must be a dictionary") + msg = "configs must be a dictionary" + raise ValueError(msg) From 6249e85e0f3340e45efa9157f32e553e4e2d11ef Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Mon, 23 Sep 2024 20:52:46 +0530 Subject: [PATCH 5/6] fix --- plugs/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugs/manager.py b/plugs/manager.py index bd21eca9ab..dfdac9fa93 100644 --- a/plugs/manager.py +++ b/plugs/manager.py @@ -30,7 +30,7 @@ def get_apps(self) -> list[str]: def get_config(self) -> defaultdict[str, dict]: configs: defaultdict[str, dict] = defaultdict(dict) for plug in self.plugs: - if plug.config is None: + if plug.configs is None: continue for key, value in plug.configs.items(): configs[plug.name][key] = value From 1584e0eb588ce7665ae5f1f7729f8569dadabeae Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Mon, 23 Sep 2024 20:53:52 +0530 Subject: [PATCH 6/6] update default ADDITIONAL_PLUGS arg --- docker/prod.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/prod.Dockerfile b/docker/prod.Dockerfile index 79579bf56a..877478c3a9 100644 --- a/docker/prod.Dockerfile +++ b/docker/prod.Dockerfile @@ -5,7 +5,7 @@ ARG TYPST_VERSION=0.11.0 ARG BUILD_ENVIRONMENT="production" ARG APP_VERSION="unknown" -ARG ADDITIONAL_PLUGS="{}" +ARG ADDITIONAL_PLUGS="" ENV BUILD_ENVIRONMENT=$BUILD_ENVIRONMENT ENV APP_VERSION=$APP_VERSION