poetry-plugin-ivcap 0.2.6__tar.gz → 0.2.8__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.
- {poetry_plugin_ivcap-0.2.6 → poetry_plugin_ivcap-0.2.8}/PKG-INFO +1 -1
- poetry_plugin_ivcap-0.2.8/poetry_plugin_ivcap/constants.py +47 -0
- {poetry_plugin_ivcap-0.2.6 → poetry_plugin_ivcap-0.2.8}/poetry_plugin_ivcap/docker.py +13 -49
- {poetry_plugin_ivcap-0.2.6 → poetry_plugin_ivcap-0.2.8}/poetry_plugin_ivcap/ivcap.py +11 -9
- {poetry_plugin_ivcap-0.2.6 → poetry_plugin_ivcap-0.2.8}/poetry_plugin_ivcap/plugin.py +18 -15
- {poetry_plugin_ivcap-0.2.6 → poetry_plugin_ivcap-0.2.8}/pyproject.toml +1 -1
- {poetry_plugin_ivcap-0.2.6 → poetry_plugin_ivcap-0.2.8}/AUTHORS.md +0 -0
- {poetry_plugin_ivcap-0.2.6 → poetry_plugin_ivcap-0.2.8}/LICENSE +0 -0
- {poetry_plugin_ivcap-0.2.6 → poetry_plugin_ivcap-0.2.8}/README.md +0 -0
- {poetry_plugin_ivcap-0.2.6 → poetry_plugin_ivcap-0.2.8}/poetry_plugin_ivcap/util.py +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2025 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
|
|
3
|
+
# Use of this source code is governed by a BSD-style license that can be
|
|
4
|
+
# found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
PLUGIN_NAME = "poetry-plugin-ivcap"
|
|
8
|
+
PLUGIN_CMD = "ivcap"
|
|
9
|
+
|
|
10
|
+
SERVICE_ID_OPT = "service-id"
|
|
11
|
+
SERVICE_FILE_OPT = "service-file"
|
|
12
|
+
SERVICE_TYPE_OPT = "service-type"
|
|
13
|
+
PORT_OPT = "port"
|
|
14
|
+
POLICY_OPT = "policy"
|
|
15
|
+
|
|
16
|
+
DOCKER_RUN_TEMPLATE_OPT = "docker-run-template"
|
|
17
|
+
DOCKER_RUN_OPT = "docker-run-opts"
|
|
18
|
+
DOCKER_BUILD_TEMPLATE_OPT = "docker-build-template"
|
|
19
|
+
|
|
20
|
+
DEF_POLICY = "urn:ivcap:policy:ivcap.base.metadata"
|
|
21
|
+
DEF_PORT = 8000
|
|
22
|
+
|
|
23
|
+
DOCKER_BUILD_TEMPLATE = """
|
|
24
|
+
docker buildx build
|
|
25
|
+
-t #DOCKER_NAME#
|
|
26
|
+
--platform linux/#ARCH#
|
|
27
|
+
--build-arg VERSION=#VERSION#
|
|
28
|
+
--build-arg BUILD_PLATFORM=linux/#ARCH#
|
|
29
|
+
-f #PROJECT_DIR#/#DOCKERFILE#
|
|
30
|
+
--load #PROJECT_DIR#
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
DOCKER_LAMBDA_RUN_TEMPLATE = """
|
|
34
|
+
docker run -it
|
|
35
|
+
-p #PORT#:#PORT#
|
|
36
|
+
--platform=linux/#ARCH#
|
|
37
|
+
--rm \
|
|
38
|
+
#NAME#_#ARCH#:#TAG#
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
DOCKER_BATCH_RUN_TEMPLATE = """
|
|
42
|
+
docker run -it
|
|
43
|
+
--platform=linux/#ARCH#
|
|
44
|
+
-v #PROJECT_DIR#:/data
|
|
45
|
+
--rm \
|
|
46
|
+
#NAME#_#ARCH#:#TAG#
|
|
47
|
+
"""
|
|
@@ -12,34 +12,9 @@ from typing import Dict, List, Optional
|
|
|
12
12
|
from pydantic import BaseModel, Field
|
|
13
13
|
import subprocess
|
|
14
14
|
|
|
15
|
+
from .constants import DEF_PORT, DOCKER_BATCH_RUN_TEMPLATE, DOCKER_BUILD_TEMPLATE, DOCKER_BUILD_TEMPLATE_OPT, DOCKER_LAMBDA_RUN_TEMPLATE, DOCKER_RUN_OPT, DOCKER_RUN_TEMPLATE_OPT, PLUGIN_NAME, SERVICE_TYPE_OPT
|
|
15
16
|
from .util import command_exists, get_name, get_version
|
|
16
17
|
|
|
17
|
-
DOCKER_BUILD_TEMPLATE = """
|
|
18
|
-
docker buildx build
|
|
19
|
-
-t #DOCKER_NAME#
|
|
20
|
-
--platform linux/#ARCH#
|
|
21
|
-
--build-arg VERSION=#VERSION#
|
|
22
|
-
--build-arg BUILD_PLATFORM=linux/#ARCH#
|
|
23
|
-
-f #PROJECT_DIR#/#DOCKERFILE#
|
|
24
|
-
--load #PROJECT_DIR#
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
DOCKER_LAMBDA_RUN_TEMPLATE = """
|
|
28
|
-
docker run -it
|
|
29
|
-
-p #PORT#:#PORT#
|
|
30
|
-
--platform=linux/#ARCH#
|
|
31
|
-
--rm \
|
|
32
|
-
#NAME#_#ARCH#:#TAG#
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
DOCKER_BATCH_RUN_TEMPLATE = """
|
|
36
|
-
docker run -it
|
|
37
|
-
--platform=linux/#ARCH#
|
|
38
|
-
-v #PROJECT_DIR#:/data
|
|
39
|
-
--rm \
|
|
40
|
-
#NAME#_#ARCH#:#TAG#
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
18
|
class DockerConfig(BaseModel):
|
|
44
19
|
name: Optional[str] = Field(None)
|
|
45
20
|
tag: Optional[str] = Field(None)
|
|
@@ -53,8 +28,8 @@ class DockerConfig(BaseModel):
|
|
|
53
28
|
return f"{self.name}_{self.arch}:{self.tag}"
|
|
54
29
|
|
|
55
30
|
def from_build_template(self, data: dict) -> str:
|
|
56
|
-
pdata = data.get("tool", {}).get(
|
|
57
|
-
template = pdata.get(
|
|
31
|
+
pdata = data.get("tool", {}).get(PLUGIN_NAME, {})
|
|
32
|
+
template = pdata.get(DOCKER_BUILD_TEMPLATE_OPT, DOCKER_BUILD_TEMPLATE).strip()
|
|
58
33
|
t = template.strip()\
|
|
59
34
|
.replace("#DOCKER_NAME#", self.docker_name)\
|
|
60
35
|
.replace("#NAME#", self.name)\
|
|
@@ -67,35 +42,29 @@ class DockerConfig(BaseModel):
|
|
|
67
42
|
return t
|
|
68
43
|
|
|
69
44
|
def from_run_template(self, data, args, line) -> List[any]:
|
|
70
|
-
pdata = data.get("tool", {}).get(
|
|
71
|
-
template = pdata.get(
|
|
45
|
+
pdata = data.get("tool", {}).get(PLUGIN_NAME, {})
|
|
46
|
+
template = pdata.get(DOCKER_RUN_TEMPLATE_OPT)
|
|
47
|
+
smode = pdata.get(SERVICE_TYPE_OPT)
|
|
48
|
+
if smode is None:
|
|
49
|
+
line(f"<error>ERROR: 'service-type' is not defined in [{PLUGIN_NAME}]</error>")
|
|
50
|
+
sys.exit(1)
|
|
72
51
|
if template is None:
|
|
73
|
-
smode = pdata.get("service-type")
|
|
74
|
-
if smode is None:
|
|
75
|
-
line("<error>ERROR: 'service-type' is not defined in [poetry-plugin-ivcap]</error>")
|
|
76
|
-
sys.exit(1)
|
|
77
52
|
if smode == "lambda":
|
|
78
53
|
template = DOCKER_LAMBDA_RUN_TEMPLATE
|
|
79
54
|
elif smode == "batch":
|
|
80
55
|
template = DOCKER_BATCH_RUN_TEMPLATE
|
|
81
56
|
else:
|
|
82
|
-
line(f"<error>ERROR: Unknown service type '{smode}' in [
|
|
57
|
+
line(f"<error>ERROR: Unknown service type '{smode}' in [{PLUGIN_NAME}]</error>")
|
|
83
58
|
sys.exit(1)
|
|
84
59
|
|
|
85
|
-
opts = pdata.get(
|
|
60
|
+
opts = pdata.get(DOCKER_RUN_OPT, [])
|
|
86
61
|
port = get_port_value(args)
|
|
87
62
|
port_in_args = True
|
|
88
63
|
if not port:
|
|
89
64
|
port = get_port_value(opts)
|
|
90
65
|
if not port:
|
|
91
66
|
port_in_args = False
|
|
92
|
-
port = str(pdata.get("port",
|
|
93
|
-
|
|
94
|
-
# elif opts.get('port') is not None:
|
|
95
|
-
# opts['port'] = opts.get('port')
|
|
96
|
-
# elif '--port' in template:
|
|
97
|
-
# # If the template has a port but no port is provided, use a default
|
|
98
|
-
# opts['port'] = '8000'
|
|
67
|
+
port = str(pdata.get("port", DEF_PORT))
|
|
99
68
|
|
|
100
69
|
t = template.strip()\
|
|
101
70
|
.replace("#NAME#", self.name)\
|
|
@@ -105,11 +74,6 @@ class DockerConfig(BaseModel):
|
|
|
105
74
|
.replace("#VERSION#", self.version)\
|
|
106
75
|
.replace("#PROJECT_DIR#", self.project_dir)
|
|
107
76
|
|
|
108
|
-
# for key, value in opts.items():
|
|
109
|
-
# if key != "port":
|
|
110
|
-
# t = t.replace(f"#{key.upper()}#", str(value))
|
|
111
|
-
|
|
112
|
-
|
|
113
77
|
cmd = t.split()
|
|
114
78
|
cmd.extend(opts)
|
|
115
79
|
cmd.extend(args)
|
|
@@ -146,7 +110,7 @@ def docker_run(data: dict, args, line) -> None:
|
|
|
146
110
|
def docker_cfg(data: dict, line, arch = None) -> DockerConfig:
|
|
147
111
|
name = get_name(data)
|
|
148
112
|
|
|
149
|
-
pdata = data.get("tool", {}).get(
|
|
113
|
+
pdata = data.get("tool", {}).get(PLUGIN_NAME, {})
|
|
150
114
|
config = DockerConfig(name=name, **pdata.get("docker", {}))
|
|
151
115
|
if arch:
|
|
152
116
|
# override architecture if provided
|
|
@@ -11,8 +11,10 @@ import tempfile
|
|
|
11
11
|
import uuid
|
|
12
12
|
import humanize
|
|
13
13
|
|
|
14
|
+
from .constants import DEF_POLICY, PLUGIN_NAME, POLICY_OPT, SERVICE_FILE_OPT, SERVICE_ID_OPT
|
|
15
|
+
|
|
14
16
|
from .docker import docker_cfg, docker_build, docker_push
|
|
15
|
-
from .util import command_exists,
|
|
17
|
+
from .util import command_exists, get_name, string_to_number
|
|
16
18
|
|
|
17
19
|
def docker_publish(data, line):
|
|
18
20
|
check_ivcap_cmd(line)
|
|
@@ -29,11 +31,11 @@ def docker_publish(data, line):
|
|
|
29
31
|
|
|
30
32
|
def service_register(data, line):
|
|
31
33
|
check_ivcap_cmd(line)
|
|
32
|
-
config = data.get("tool", {}).get(
|
|
34
|
+
config = data.get("tool", {}).get(PLUGIN_NAME, {})
|
|
33
35
|
|
|
34
|
-
service = config.get(
|
|
36
|
+
service = config.get(SERVICE_FILE_OPT)
|
|
35
37
|
if not service:
|
|
36
|
-
line("<error>Missing '
|
|
38
|
+
line(f"<error>Missing '{SERVICE_FILE_OPT}' in [tool.{PLUGIN_NAME}]</error>")
|
|
37
39
|
return
|
|
38
40
|
|
|
39
41
|
dcfg = docker_cfg(data, line, "amd64")
|
|
@@ -74,11 +76,11 @@ def service_register(data, line):
|
|
|
74
76
|
|
|
75
77
|
def tool_register(data, line):
|
|
76
78
|
check_ivcap_cmd(line)
|
|
77
|
-
config = data.get("tool", {}).get(
|
|
79
|
+
config = data.get("tool", {}).get(PLUGIN_NAME, {})
|
|
78
80
|
|
|
79
81
|
service = config.get("service-file")
|
|
80
82
|
if not service:
|
|
81
|
-
line("<error>Missing 'service-file' in [tool.
|
|
83
|
+
line(f"<error>Missing 'service-file' in [tool.{PLUGIN_NAME}]</error>")
|
|
82
84
|
return
|
|
83
85
|
|
|
84
86
|
cmd = ["poetry", "run", "python", service, "--print-tool-description"]
|
|
@@ -109,7 +111,7 @@ def tool_register(data, line):
|
|
|
109
111
|
os.remove(tmp_path)
|
|
110
112
|
|
|
111
113
|
def get_service_id(data, is_silent, line):
|
|
112
|
-
service_id = data.get("tool", {}).get(
|
|
114
|
+
service_id = data.get("tool", {}).get(PLUGIN_NAME, {}).get(SERVICE_ID_OPT)
|
|
113
115
|
if not service_id:
|
|
114
116
|
service_id = create_service_id(data, is_silent, line)
|
|
115
117
|
return service_id
|
|
@@ -122,9 +124,9 @@ def create_service_id(data, is_silent, line):
|
|
|
122
124
|
return f"urn:ivcap:service:{id}"
|
|
123
125
|
|
|
124
126
|
def get_policy(data, line):
|
|
125
|
-
policy = data.get("tool", {}).get(
|
|
127
|
+
policy = data.get("tool", {}).get(PLUGIN_NAME, {}).get(POLICY_OPT)
|
|
126
128
|
if not policy:
|
|
127
|
-
policy =
|
|
129
|
+
policy = DEF_POLICY
|
|
128
130
|
return policy
|
|
129
131
|
|
|
130
132
|
def get_account_id(data, line, is_silent=False):
|
|
@@ -10,6 +10,7 @@ from cleo.helpers import argument, option
|
|
|
10
10
|
import subprocess
|
|
11
11
|
from importlib.metadata import version
|
|
12
12
|
|
|
13
|
+
from poetry_plugin_ivcap.constants import DOCKER_BUILD_TEMPLATE_OPT, DOCKER_RUN_TEMPLATE_OPT, PLUGIN_CMD, PLUGIN_NAME, PORT_OPT, SERVICE_FILE_OPT, SERVICE_ID_OPT, SERVICE_TYPE_OPT
|
|
13
14
|
from poetry_plugin_ivcap.util import get_version
|
|
14
15
|
|
|
15
16
|
from .ivcap import create_service_id, get_service_id, service_register, tool_register
|
|
@@ -18,8 +19,8 @@ from .ivcap import docker_publish
|
|
|
18
19
|
|
|
19
20
|
class IvcapCommand(Command):
|
|
20
21
|
name = "ivcap"
|
|
21
|
-
description = "IVCAP plugin `poetry
|
|
22
|
-
help = """\
|
|
22
|
+
description = f"IVCAP plugin `poetry {PLUGIN_CMD} <subcommand>`"
|
|
23
|
+
help = f"""\
|
|
23
24
|
|
|
24
25
|
IVCAP plugin
|
|
25
26
|
|
|
@@ -34,19 +35,21 @@ Available subcommands:
|
|
|
34
35
|
create-service-id Create a unique service ID for the service
|
|
35
36
|
get-service-id Return the service ID for the service
|
|
36
37
|
tool-register Register the service as an AI Tool with IVCAP
|
|
38
|
+
version Print the version of this plugin
|
|
37
39
|
|
|
38
40
|
Example:
|
|
39
|
-
poetry
|
|
41
|
+
poetry {PLUGIN_CMD} run -- --port 8080
|
|
40
42
|
|
|
41
43
|
Configurable options in pyproject.toml:
|
|
42
44
|
|
|
43
|
-
[tool.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
[tool.{PLUGIN_NAME}]
|
|
46
|
+
{SERVICE_FILE_OPT} = "service.py" # The Python file that implements the service
|
|
47
|
+
{SERVICE_ID_OPT} = "urn:ivcap:service:ac158a1f-dfb4-5dac-bf2e-9bf15e0f2cc7" # A unique identifier for the service
|
|
48
|
+
{SERVICE_TYPE_OPT} = "lambda
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
# Optional
|
|
51
|
+
{DOCKER_BUILD_TEMPLATE_OPT} = "docker buildx build -t #DOCKER_NAME# ."
|
|
52
|
+
{DOCKER_RUN_TEMPLATE_OPT} = "docker run -rm -p #PORT#:#PORT#"
|
|
50
53
|
"""
|
|
51
54
|
arguments = [
|
|
52
55
|
argument("subcommand", optional=True, description="Subcommand: run, deploy, etc."),
|
|
@@ -64,7 +67,7 @@ Configurable options in pyproject.toml:
|
|
|
64
67
|
sub = self.argument("subcommand")
|
|
65
68
|
if sub == "version":
|
|
66
69
|
#v = poetry.get_plugin('ivcap').version
|
|
67
|
-
v = version(
|
|
70
|
+
v = version(PLUGIN_NAME)
|
|
68
71
|
print(f"IVCAP plugin (version {v})")
|
|
69
72
|
return
|
|
70
73
|
|
|
@@ -99,15 +102,15 @@ Configurable options in pyproject.toml:
|
|
|
99
102
|
print(self.help)
|
|
100
103
|
|
|
101
104
|
def run_service(self, data, args, line):
|
|
102
|
-
config = data.get("tool", {}).get(
|
|
105
|
+
config = data.get("tool", {}).get(PLUGIN_NAME, {})
|
|
103
106
|
|
|
104
|
-
service = config.get(
|
|
107
|
+
service = config.get(SERVICE_FILE_OPT)
|
|
105
108
|
if not service:
|
|
106
|
-
self.line("<error>Missing '
|
|
109
|
+
self.line(f"<error>Missing '{SERVICE_FILE_OPT}' in [tool.{PLUGIN_NAME}]</error>")
|
|
107
110
|
return
|
|
108
111
|
|
|
109
112
|
if not '--port' in args:
|
|
110
|
-
port = config.get(
|
|
113
|
+
port = config.get(PORT_OPT)
|
|
111
114
|
if port:
|
|
112
115
|
args.extend(["--port", str(port)])
|
|
113
116
|
|
|
@@ -121,4 +124,4 @@ Configurable options in pyproject.toml:
|
|
|
121
124
|
|
|
122
125
|
class IvcapPlugin(ApplicationPlugin):
|
|
123
126
|
def activate(self, application):
|
|
124
|
-
application.command_loader.register_factory(
|
|
127
|
+
application.command_loader.register_factory(PLUGIN_CMD, lambda: IvcapCommand())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|