Skip to content

Commit c73d2c7

Browse files
authored
Add/dockerfile (#182)
* implement `generate_dockerfile` function * `CHANGELOG.md` updated * fix docstring issue * add ability to set `Dockerfile` name * add static Dockerfiles for `generate_dockerfile` testcase * add `generate_dockerfile` testcases * `CHANGELOG.md` updated * remove generated Dockerfiles after testcase execution * remove `\n` from the beginning of the line and add `\n` at the end of the file * update docstring * apply `autopep8.sh`
1 parent c80c513 commit c73d2c7

File tree

5 files changed

+125
-1
lines changed

5 files changed

+125
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
66

77
## [Unreleased]
88
### Added
9+
- `generate_dockerfile` testcases
10+
- `generate_dockerfile` function in `streaming.util.py`
911
- `cite` section in `README.md`
1012
- `CLI` handler
1113
- `print_supported_ml_models` function in `pymilo_func.py`

pymilo/streaming/util.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# -*- coding: utf-8 -*-
22
"""ML Streaming utility module."""
3+
import os
34
import re
5+
from ..pymilo_param import URL_REGEX
46

57

68
def validate_websocket_url(url: str) -> str:
@@ -39,3 +41,71 @@ def validate_http_url(url: str) -> str:
3941
if not re.match(full_pattern, url):
4042
return False, None
4143
return True, url
44+
45+
46+
def generate_dockerfile(
47+
dockerfile_name="Dockerfile",
48+
model_path=None,
49+
compression='NULL',
50+
protocol='REST',
51+
port=8000,
52+
init_model=None,
53+
bare=False
54+
):
55+
"""
56+
Generate a Dockerfile for running a PyMilo server with specified configurations.
57+
58+
:param dockerfile_name: Name of the dockerfile.
59+
:type dockerfile_name: str
60+
:param model_path: Path or URL to the exported model JSON file.
61+
:type model_path: str
62+
:param compression: Compression method (default: NULL).
63+
:type compression: str
64+
:param protocol: Communication protocol (default: REST).
65+
:type protocol: str
66+
:param port: Port for the PyMilo server (default: 8000).
67+
:type port: int
68+
:param init_model: The model that the server initialized with.
69+
:type init_model: boolean
70+
:param bare: A flag that sets if the server runs without an internal ML model.
71+
:type bare: boolean
72+
"""
73+
dockerfile_content = f"""# Use an official Python runtime as a parent image
74+
FROM python:3.11-slim
75+
76+
# Set the working directory in the container
77+
WORKDIR /app
78+
79+
# Install pymilo
80+
RUN pip install pymilo[streaming]
81+
"""
82+
is_url = False
83+
if model_path:
84+
if re.match(URL_REGEX, model_path):
85+
is_url = True
86+
else:
87+
dockerfile_content += f"\nCOPY {os.path.basename(model_path)} /app/model.json"
88+
89+
# Expose the specified port
90+
dockerfile_content += f"\nEXPOSE {port}"
91+
92+
cmd = "CMD [\"python\", \"-m\", \"pymilo\""
93+
cmd += f", \"--compression\", \"{compression}\""
94+
cmd += f", \"--protocol\", \"{protocol}\""
95+
cmd += f", \"--port\", \"{port}\""
96+
97+
if model_path:
98+
if is_url:
99+
cmd += f", \"--load\", \"{model_path}\""
100+
else:
101+
cmd += f", \"--load\", \"/app/model.json\""
102+
elif init_model:
103+
cmd += f", \"--init\" \"{init_model}\""
104+
elif bare:
105+
cmd += f", \"--bare\""
106+
107+
cmd += "]"
108+
dockerfile_content += f"\n{cmd}\n"
109+
110+
with open(dockerfile_name, 'w') as f:
111+
f.write(dockerfile_content)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Use an official Python runtime as a parent image
2+
FROM python:3.11-slim
3+
4+
# Set the working directory in the container
5+
WORKDIR /app
6+
7+
# Install pymilo
8+
RUN pip install pymilo[streaming]
9+
10+
EXPOSE 8000
11+
CMD ["python", "-m", "pymilo", "--compression", "NULL", "--protocol", "REST", "--port", "8000", "--load", "https://raw.githubusercontent.com/openscilab/pymilo/main/tests/test_exceptions/valid_jsons/linear_regression.json"]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Use an official Python runtime as a parent image
2+
FROM python:3.11-slim
3+
4+
# Set the working directory in the container
5+
WORKDIR /app
6+
7+
# Install pymilo
8+
RUN pip install pymilo[streaming]
9+
10+
COPY linear_regression.json /app/model.json
11+
EXPOSE 8000
12+
CMD ["python", "-m", "pymilo", "--compression", "NULL", "--protocol", "REST", "--port", "8000", "--load", "/app/model.json"]

tests/test_ml_streaming/test_streaming.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
import time
33
import pytest
44
import subprocess
5+
from filecmp import cmp
56
from sys import executable
67
from scenarios.scenario1 import scenario1
78
from scenarios.scenario2 import scenario2
89
from scenarios.scenario3 import scenario3
9-
10+
from pymilo.streaming.util import generate_dockerfile
1011

1112
@pytest.fixture(
1213
scope="session",
@@ -94,3 +95,31 @@ def test2(prepare_bare_server):
9495
def test3(prepare_ml_server):
9596
compression_method, communication_protocol = prepare_ml_server
9697
assert scenario3(compression_method, communication_protocol) == 0
98+
99+
100+
def test_dockerfile():
101+
docker_files_folder = os.path.join(
102+
os.getcwd(),
103+
"tests",
104+
"test_ml_streaming",
105+
"docker_files",
106+
)
107+
generate_dockerfile(
108+
dockerfile_name="Dockerfile",
109+
model_path="https://raw.githubusercontent.com/openscilab/pymilo/main/tests/test_exceptions/valid_jsons/linear_regression.json")
110+
r1 = cmp('Dockerfile', os.path.join(
111+
docker_files_folder,
112+
"Dockerfile1"
113+
)
114+
)
115+
generate_dockerfile(
116+
dockerfile_name="Dockerfile",
117+
model_path="linear_regression.json",
118+
)
119+
r2 = cmp('Dockerfile', os.path.join(
120+
docker_files_folder,
121+
"Dockerfile2"
122+
)
123+
)
124+
os.remove(path='Dockerfile')
125+
assert r1 and r2

0 commit comments

Comments
 (0)