model2service 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2
+ // README at: https://github.com/devcontainers/templates/tree/main/src/python
3
+ {
4
+ "name": "Python 3",
5
+ // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6
+ "build": {
7
+ "dockerfile": "../Dockerfile"
8
+ },
9
+ // Features to add to the dev container. More info: https://containers.dev/features.
10
+ // "features": {},
11
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
12
+ // "forwardPorts": [],
13
+ // Use 'postCreateCommand' to run commands after the container is created.
14
+ // "postCreateCommand": "pip3 install --user -r requirements.txt",
15
+ // Configure tool-specific properties.
16
+ "customizations": {
17
+ "vscode": {
18
+ "extensions": [
19
+ "ms-python.black-formatter",
20
+ "ms-python.vscode-python-envs",
21
+ "ms-python.debugpy",
22
+ "ms-python.python",
23
+ "ms-python.vscode-pylance",
24
+ "eamodio.gitlens",
25
+ "ms-toolsai.datawrangler",
26
+ "esbenp.prettier-vscode",
27
+ "ms-toolsai.jupyter",
28
+ "ms-vsliveshare.vsliveshare"
29
+ ],
30
+ }
31
+ }
32
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
33
+ // "remoteUser": "root"
34
+ }
@@ -0,0 +1,70 @@
1
+ # This workflow will upload a Python Package to PyPI when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3
+
4
+ # This workflow uses actions that are not certified by GitHub.
5
+ # They are provided by a third-party and are governed by
6
+ # separate terms of service, privacy policy, and support
7
+ # documentation.
8
+
9
+ name: Upload Python Package
10
+
11
+ on:
12
+ release:
13
+ types: [published]
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ release-build:
20
+ runs-on: ubuntu-latest
21
+
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.x"
28
+
29
+ - name: Build release distributions
30
+ run: |
31
+ # NOTE: put your own distribution build steps here.
32
+ python -m pip install build
33
+ python -m build
34
+
35
+ - name: Upload distributions
36
+ uses: actions/upload-artifact@v4
37
+ with:
38
+ name: release-dists
39
+ path: dist/
40
+
41
+ pypi-publish:
42
+ runs-on: ubuntu-latest
43
+ needs:
44
+ - release-build
45
+ permissions:
46
+ # IMPORTANT: this permission is mandatory for trusted publishing
47
+ id-token: write
48
+
49
+ # Dedicated environments with protections for publishing are strongly recommended.
50
+ # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
51
+ environment:
52
+ name: pypi
53
+ # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
54
+ # url: https://pypi.org/p/YOURPROJECT
55
+ #
56
+ # ALTERNATIVE: if your GitHub Release name is the PyPI project version string
57
+ # ALTERNATIVE: exactly, uncomment the following line instead:
58
+ # url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }}
59
+
60
+ steps:
61
+ - name: Retrieve release distributions
62
+ uses: actions/download-artifact@v4
63
+ with:
64
+ name: release-dists
65
+ path: dist/
66
+
67
+ - name: Publish release distributions to PyPI
68
+ uses: pypa/gh-action-pypi-publish@release/v1
69
+ with:
70
+ packages-dir: dist/
File without changes
@@ -0,0 +1,3 @@
1
+ {
2
+ "python-envs.defaultEnvManager": "ms-python.python:system"
3
+ }
@@ -0,0 +1,17 @@
1
+ FROM python:3.10-slim
2
+ RUN apt-get update && \
3
+ apt-get upgrade -y && \
4
+ apt-get install -y build-essential \
5
+ git \
6
+ curl \
7
+ wget \
8
+ && apt-get clean \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+
12
+ WORKDIR /workspace
13
+
14
+ COPY requirements.txt .
15
+ RUN pip install --no-cache-dir -r requirements.txt
16
+
17
+ RUN pip install --upgrade pip
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: model2service
3
+ Version: 0.0.1
4
+ Author-email: Diego Pinheiro <diego.silva@unicap.br>
5
+ Project-URL: Homepage, https://github.com/projeto-carcara/model2service
6
+ Keywords: service
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: pydantic==2.13.2
13
+ Requires-Dist: debugpy==1.8.20
14
+ Requires-Dist: pika==1.3.2
15
+ Requires-Dist: redis==7.4.0
16
+
17
+ # model2service
@@ -0,0 +1 @@
1
+ # model2service
@@ -0,0 +1,9 @@
1
+ from .src import *
2
+
3
+ def service2model_mlflowredis(cls) -> Model2Service:
4
+ return Model2Service(
5
+ service_registry=RedisServices(),
6
+ model_repository=MlflowRepository()
7
+ )
8
+
9
+ DefaultModel2Service: Model2Service = service2model_mlflowredis()
@@ -0,0 +1,5 @@
1
+ from .model_repositories import *
2
+ from .service_registries import *
3
+ from .model2service import *
4
+
5
+
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ import abc
4
+ from .service_registries import ServiceRegistry, ModelServiceRegistry
5
+ from .model_repositories import ModelRepository, Model
6
+
7
+ from pydantic import BaseModel
8
+
9
+ # class Model2ServiceMapping(BaseModel):
10
+ # service_registry: ServiceRegistry
11
+ # model_repository: ModelRepository
12
+
13
+
14
+ class Model2Service():
15
+
16
+ def __init__(self,
17
+ service_registry: ServiceRegistry,
18
+ model_repository: ModelRepository
19
+ ):
20
+ self.mode
21
+
22
+ def model_save(self, model: Model):
23
+ self.model_repository.save(model)
24
+
25
+ def model_load(self, model_name: str) -> Model:
26
+ return self.model_repository.load(model_name)
27
+
28
+ def service_register(self, model_service_registry: ModelServiceRegistry):
29
+ self.service_registry.register(model_service_registry)
30
+
31
+ def service_discover(self, model_name: str) -> ModelServiceRegistry:
32
+ return self.service_registry.discovery(model_name)
33
+
@@ -0,0 +1,2 @@
1
+ from .model_repository import *
2
+ from .mlflow_repository import *
@@ -0,0 +1,12 @@
1
+ from mlflow.pyfunc.model import PythonModel, PythonModelContext
2
+ from .model_repository import Model
3
+
4
+ from .model_repository import ModelRepository
5
+
6
+ class MlflowRepository(ModelRepository):
7
+ def save(self, model: Model):
8
+ pass
9
+
10
+ def load(self) -> Model:
11
+ pass
12
+
@@ -0,0 +1,12 @@
1
+ import abc
2
+
3
+ class Model:
4
+ name: str
5
+
6
+ class ModelRepository(abc.ABC):
7
+
8
+ @abc.abstractmethod
9
+ def save(self, model: Model): ...
10
+
11
+ @abc.abstractmethod
12
+ def load(self, model_name: str) -> Model: ...
@@ -0,0 +1,2 @@
1
+ from .service_registry import *
2
+ from .redis_registry import *
@@ -0,0 +1,39 @@
1
+ from .service_registry import ServiceRegistry, ModelServiceRegistry
2
+ import redis
3
+ import os
4
+ from typing import Optional
5
+
6
+ ENVIRONMENT_VARIABLE_HOST = "REDIS_HOST"
7
+ ENVIRONMENT_VARIABLE_PORT = "REDIS_PORT"
8
+
9
+ class RedisServices(ServiceRegistry):
10
+ _instace = None
11
+
12
+ def __new__(cls):
13
+ if cls._instance is None:
14
+ instance = super().__new__(cls)
15
+ instance.client = redis.Redis(
16
+ host=instance.host,
17
+ port=int(instance.port),
18
+ decode_responses=True
19
+ )
20
+ cls._instance = instance
21
+ return cls._instance
22
+
23
+ def register(self, model_service: ModelServiceRegistry):
24
+ # registra o nome do modelo e a fila no serviço
25
+ key = f"model_queue:{model_service.service_name}"
26
+ self.client.set(key, model_service.queue_name)
27
+
28
+ def discovery(self, service_name: str) -> Optional[str]:
29
+ # retorna o nome da fila associada ao modelo
30
+ key = f"model_queue:{service_name}"
31
+ return self.client.get(key)
32
+
33
+ @property
34
+ def host(self):
35
+ return os.getenv(ENVIRONMENT_VARIABLE_HOST)
36
+
37
+ @property
38
+ def port(self):
39
+ return os.getenv(ENVIRONMENT_VARIABLE_PORT)
@@ -0,0 +1,27 @@
1
+ import abc
2
+ from pydantic import BaseModel
3
+ from collections.abc import Callable
4
+ from typing import Optional
5
+ from pika.spec import BasicProperties
6
+
7
+
8
+ #TODO this class does not belong in this file, maybe a MessageConsumer interface
9
+ class CallBackArguments(BaseModel):
10
+ body : bytes
11
+ #TODO make less coupling, maybe use dict[str, Any] for now
12
+ properties: BasicProperties
13
+
14
+ class ModelServiceRegistry(BaseModel):
15
+ service_name: str
16
+ queue_name: str
17
+ #TODO 'process' does not belong in this class, this class is only for registration
18
+ process: Callable[[CallBackArguments], Optional[BaseModel]]
19
+
20
+ @abc.abstractmethod
21
+ class ServiceRegistry(abc.ABC):
22
+
23
+ @abc.abstractmethod
24
+ def register(self, model_service: ModelServiceRegistry): ...
25
+
26
+ @abc.abstractmethod
27
+ def discovery(self, service_name: str) -> Optional[str]: ...
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: model2service
3
+ Version: 0.0.1
4
+ Author-email: Diego Pinheiro <diego.silva@unicap.br>
5
+ Project-URL: Homepage, https://github.com/projeto-carcara/model2service
6
+ Keywords: service
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: pydantic==2.13.2
13
+ Requires-Dist: debugpy==1.8.20
14
+ Requires-Dist: pika==1.3.2
15
+ Requires-Dist: redis==7.4.0
16
+
17
+ # model2service
@@ -0,0 +1,23 @@
1
+ .gitignore
2
+ Dockerfile
3
+ README.md
4
+ pyproject.toml
5
+ requirements.txt
6
+ .devcontainer/devcontainer.json
7
+ .github/workflows/python-publish.yml
8
+ .vscode/settings.json
9
+ model2service/__init__.py
10
+ model2service.egg-info/PKG-INFO
11
+ model2service.egg-info/SOURCES.txt
12
+ model2service.egg-info/dependency_links.txt
13
+ model2service.egg-info/requires.txt
14
+ model2service.egg-info/top_level.txt
15
+ model2service/src/__init__.py
16
+ model2service/src/model2service.py
17
+ model2service/src/model_repositories/__init__.py
18
+ model2service/src/model_repositories/mlflow_repository.py
19
+ model2service/src/model_repositories/model_repository.py
20
+ model2service/src/service_registries/__init__.py
21
+ model2service/src/service_registries/redis_registry.py
22
+ model2service/src/service_registries/service_registry.py
23
+ tests/client.py
@@ -0,0 +1,4 @@
1
+ pydantic==2.13.2
2
+ debugpy==1.8.20
3
+ pika==1.3.2
4
+ redis==7.4.0
@@ -0,0 +1 @@
1
+ model2service
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["setuptools", "wheel", "setuptools-scm[toml]>=6.2"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "model2service"
7
+ dynamic = ["version"]
8
+ authors = [
9
+ { name="Diego Pinheiro", email="diego.silva@unicap.br" },
10
+ ]
11
+ description = ""
12
+ readme = "README.md"
13
+ license = { file = "LICENSE" }
14
+ requires-python = ">=3.9"
15
+ keywords = ["service"]
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ ]
21
+
22
+ dependencies = [
23
+ "pydantic==2.13.2",
24
+ "debugpy==1.8.20",
25
+ "pika==1.3.2",
26
+ "redis==7.4.0"
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/projeto-carcara/model2service"
33
+
34
+ [tool.setuptools.packages.find]
35
+ include = ["model2service", "model2service.*"]
36
+
37
+ [tool.setuptools_scm]
38
+ version_scheme = "guess-next-dev"
39
+ local_scheme = "node-and-date"
@@ -0,0 +1,4 @@
1
+ pydantic==2.13.2
2
+ debugpy==1.8.20
3
+ pika==1.3.2
4
+ redis==7.4.0
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,28 @@
1
+ from model2service import *
2
+ from typing import List
3
+
4
+ # 1: Save Model Save Model After Training
5
+
6
+ model = Model()
7
+ DefaultModel2Service.model_save(model)
8
+
9
+ # 2: Register Models When Container Starts
10
+
11
+ service_name = "myservice"
12
+ def mymodels() -> List[Model]:
13
+ pass
14
+
15
+ for model in mymodels():
16
+ model_service_registry: ModelServiceRegistry = ModelServiceRegistry(
17
+ model_name=model.name,
18
+ service_name="service_name"
19
+ )
20
+ DefaultModel2Service.service_register(model_service_registry=model)
21
+
22
+ # 3: Discover service for a given model_name
23
+ model_name: str = "mymodel"
24
+ serviceResgistry: ServiceRegistry = DefaultModel2Service.service_discover(model_name=model_name)
25
+
26
+ # 4: Load model within the container provisioning the service for a given model
27
+ model_name = "mymodel"
28
+ model: Model = DefaultModel2Service.model_load(model_name=model_name)