poetry-plugin-ivcap 0.5.2__py3-none-any.whl → 0.6.1__py3-none-any.whl

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.
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2025 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
2
+ # Copyright (c) 2025-2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
3
3
  # Use of this source code is governed by a BSD-style license that can be
4
4
  # found in the LICENSE file. See the AUTHORS file for names of contributors.
5
5
  #
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2025 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
2
+ # Copyright (c) 2025-2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
3
3
  # Use of this source code is governed by a BSD-style license that can be
4
4
  # found in the LICENSE file. See the AUTHORS file for names of contributors.
5
5
  #
@@ -145,7 +145,7 @@ def docker_cfg(data: dict, line, arch = None) -> DockerConfig:
145
145
  config.arch = subprocess.check_output(['uname', '-m']).decode().strip()
146
146
  except Exception as e:
147
147
  line(f"<error>ERROR: cannot obtain build architecture: {e}</error>")
148
- os.exit(1)
148
+ sys.exit(1)
149
149
 
150
150
  return config
151
151
 
@@ -173,9 +173,9 @@ def docker_push(docker_img, line):
173
173
  line(f"<error>ERROR: package push failed with exit code {exit_code}</error>")
174
174
  sys.exit(1)
175
175
 
176
- # Lookginf for "45a06508-5c3a-4678-8e6d-e6399bf27538/gene_onology_term_mapper_amd64:9a9a7cc pushed\n"
176
+ # Looking for "45a06508-5c3a-4678-8e6d-e6399bf27538/gene_onology_term_mapper_amd64:9a9a7cc pushed\n"
177
177
  pattern = re.compile(
178
- r'([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/[^\s]+) pushed'
178
+ r'(?:(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12})/)?([^\s]+) pushed'
179
179
  )
180
180
  package_name = None
181
181
  with open(tmp_path, 'r') as f:
@@ -1,8 +1,9 @@
1
1
  #
2
- # Copyright (c) 2025 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
2
+ # Copyright (c) 2025-2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
3
3
  # Use of this source code is governed by a BSD-style license that can be
4
4
  # found in the LICENSE file. See the AUTHORS file for names of contributors.
5
5
  #
6
+ from typing import Optional
6
7
  import argparse
7
8
  import os
8
9
  import re
@@ -35,6 +36,30 @@ def docker_publish(data, line):
35
36
  pkg_name = docker_push(dname, line)
36
37
 
37
38
  def service_register(data, line):
39
+ svc = service_description(data, line)
40
+
41
+ with tempfile.NamedTemporaryFile(mode='w+', delete=False) as tmp:
42
+ tmp.write(svc)
43
+ tmp_path = tmp.name # Save the file name for subprocess
44
+
45
+ try:
46
+ policy = get_policy(data, line)
47
+ service_id = get_service_id(data, False, line)
48
+ up_cmd = ["ivcap", "aspect", "update", "--policy", policy, service_id, "-f", tmp_path]
49
+ try:
50
+ line(f"<debug>Running: {' '.join(up_cmd)} </debug>")
51
+ jaid = subprocess.check_output(up_cmd).decode().strip()
52
+ p = re.compile(r'.*(urn:[^"]*)')
53
+ aid = p.search(jaid).group(1)
54
+ line(f"<info>INFO: service definition successfully uploaded - {aid}</info>")
55
+ except Exception as e:
56
+ line(f"<error>ERROR: cannot upload service definitiion: {e}</error>")
57
+ sys.exit(1)
58
+ finally:
59
+ if os.path.exists(tmp_path):
60
+ os.remove(tmp_path)
61
+
62
+ def service_description(data, line):
38
63
  check_ivcap_cmd(line)
39
64
  config = data.get("tool", {}).get(PLUGIN_NAME, {})
40
65
 
@@ -60,6 +85,10 @@ def service_register(data, line):
60
85
 
61
86
  svc = svc.replace("#DOCKER_IMG#", pkg.strip())\
62
87
  .replace("#SERVICE_ID#", service_id)
88
+ return svc
89
+
90
+ def tool_register(data, line):
91
+ svc = tool_description(data, line)
63
92
 
64
93
  with tempfile.NamedTemporaryFile(mode='w+', delete=False) as tmp:
65
94
  tmp.write(svc)
@@ -67,21 +96,22 @@ def service_register(data, line):
67
96
 
68
97
  try:
69
98
  policy = get_policy(data, line)
99
+ service_id = get_service_id(data, False, line)
70
100
  up_cmd = ["ivcap", "aspect", "update", "--policy", policy, service_id, "-f", tmp_path]
71
101
  try:
72
102
  line(f"<debug>Running: {' '.join(up_cmd)} </debug>")
73
103
  jaid = subprocess.check_output(up_cmd).decode().strip()
74
104
  p = re.compile(r'.*(urn:[^"]*)')
75
105
  aid = p.search(jaid).group(1)
76
- line(f"<info>INFO: service definition successfully uploaded - {aid}</info>")
106
+ line(f"<info>INFO: tool description successfully uploaded - {aid}</info>")
77
107
  except Exception as e:
78
- line(f"<error>ERROR: cannot upload service definitiion: {e}</error>")
108
+ line(f"<error>ERROR: cannot upload tool description: {e}</error>")
79
109
  sys.exit(1)
80
110
  finally:
81
111
  if os.path.exists(tmp_path):
82
112
  os.remove(tmp_path)
83
113
 
84
- def tool_register(data, line):
114
+ def tool_description(data, line) -> str:
85
115
  check_ivcap_cmd(line)
86
116
  config = data.get("tool", {}).get(PLUGIN_NAME, {})
87
117
 
@@ -98,26 +128,7 @@ def tool_register(data, line):
98
128
 
99
129
  service_id = get_service_id(data, False, line)
100
130
  svc = svc.replace("#SERVICE_ID#", service_id)
101
-
102
- with tempfile.NamedTemporaryFile(mode='w+', delete=False) as tmp:
103
- tmp.write(svc)
104
- tmp_path = tmp.name # Save the file name for subprocess
105
-
106
- try:
107
- policy = get_policy(data, line)
108
- up_cmd = ["ivcap", "aspect", "update", "--policy", policy, service_id, "-f", tmp_path]
109
- try:
110
- line(f"<debug>Running: {' '.join(up_cmd)} </debug>")
111
- jaid = subprocess.check_output(up_cmd).decode().strip()
112
- p = re.compile(r'.*(urn:[^"]*)')
113
- aid = p.search(jaid).group(1)
114
- line(f"<info>INFO: tool description successfully uploaded - {aid}</info>")
115
- except Exception as e:
116
- line(f"<error>ERROR: cannot upload tool description: {e}</error>")
117
- sys.exit(1)
118
- finally:
119
- if os.path.exists(tmp_path):
120
- os.remove(tmp_path)
131
+ return svc
121
132
 
122
133
  def get_service_id(data, is_silent, line):
123
134
  service_id = data.get("tool", {}).get(PLUGIN_NAME, {}).get(SERVICE_ID_OPT)
@@ -399,4 +410,24 @@ def check_ivcap_cmd(line, is_silent=False):
399
410
  if not command_exists("ivcap"):
400
411
  line("<error>'ivcap' command not found. Please install the IVCAP CLI tool.</error>")
401
412
  line("<error>... see https://github.com/ivcap-works/ivcap-cli?tab=readme-ov-file#install-released-binaries for instructions</error>")
402
- os.exit(1)
413
+ sys.exit(1)
414
+
415
+ def ivcap_cli_version() -> Optional[str]:
416
+ # Best-effort: also report the installed external `ivcap` CLI version.
417
+ # Expected output:
418
+ # ivcap version 0.47.0|a4f9b30|2026-01-30T04:45:00Z
419
+ ivcap_version = None
420
+ try:
421
+ res = subprocess.run(
422
+ ["ivcap", "--version"],
423
+ capture_output=True,
424
+ text=True,
425
+ check=False,
426
+ )
427
+ raw = (res.stdout or res.stderr or "").strip()
428
+ m = re.search(r"\bivcap\s+version\s+([0-9]+(?:\.[0-9]+)+)", raw)
429
+ if m:
430
+ return m.group(1)
431
+ except FileNotFoundError:
432
+ # `ivcap` is not installed / not on PATH
433
+ return
@@ -1,9 +1,10 @@
1
1
  #
2
- # Copyright (c) 2025 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
2
+ # Copyright (c) 2025-2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
3
3
  # Use of this source code is governed by a BSD-style license that can be
4
4
  # found in the LICENSE file. See the AUTHORS file for names of contributors.
5
5
  #
6
6
  import os
7
+ import re
7
8
  from poetry.plugins.application_plugin import ApplicationPlugin
8
9
  from cleo.commands.command import Command
9
10
  from cleo.helpers import argument, option
@@ -17,7 +18,32 @@ from poetry_plugin_ivcap.util import get_version
17
18
 
18
19
  from .ivcap import create_service_id, exec_job, get_service_id, service_register, tool_register
19
20
  from .docker import docker_build, docker_run
20
- from .ivcap import docker_publish
21
+ from .ivcap import docker_publish, ivcap_cli_version, service_description, tool_description
22
+
23
+
24
+ _SUBCOMMANDS = [
25
+ ("run", "Run the service locally"),
26
+ ("docker-build", "Build the docker image for this service"),
27
+ ("docker-run", "Run the service's docker image locally for testing"),
28
+ (
29
+ "deploy",
30
+ "Deploy the service to IVCAP (calls docker-publish, service-register and tool-register)",
31
+ ),
32
+ ("job-exec file_name", "Execute a job defined in 'file_name'"),
33
+ ("docker-publish", "Publish the service's docker image to IVCAP"),
34
+ ("service-register", "Register the service with IVCAP"),
35
+ ("tool-register", "Register the service as an AI Tool with IVCAP"),
36
+ ("create-service-id", "Create a unique service ID for the service"),
37
+ ("get-service-id", "Return the service ID for the service"),
38
+ ("get-service-description", "Return the service description as json"),
39
+ ("get-tool-description", "Return the tool description as json"),
40
+ ("version", "Print the version of this plugin"),
41
+ ]
42
+
43
+ _SUBCOMMANDS_COL_WIDTH = max(len(cmd) for cmd, _ in _SUBCOMMANDS)
44
+ _SUBCOMMANDS_HELP = "\n".join(
45
+ f" {cmd.ljust(_SUBCOMMANDS_COL_WIDTH)} {desc}" for cmd, desc in _SUBCOMMANDS
46
+ )
21
47
 
22
48
  class IvcapCommand(Command):
23
49
  name = "ivcap"
@@ -29,21 +55,12 @@ IVCAP plugin
29
55
  Supporting the development of services and tools for the IVCAP platform
30
56
 
31
57
  Available subcommands:
32
- run Run the service locally
33
- docker-build Build the docker image for this service
34
- docker-run Run the service's docker image locally for testing
35
- deploy Deploy the service to IVCAP (calls docker-publish, service-register and tool-register)
36
- job-exec file_name Execute a job defined in 'file_name'
37
- docker-publish Publish the service's docker image to IVCAP
38
- service-register Register the service with IVCAP
39
- create-service-id Create a unique service ID for the service
40
- get-service-id Return the service ID for the service
41
- tool-register Register the service as an AI Tool with IVCAP
42
- version Print the version of this plugin
58
+ {_SUBCOMMANDS_HELP}
43
59
 
44
60
  Example:
45
61
  poetry {PLUGIN_CMD} run -- --port 8080
46
62
  poetry {PLUGIN_CMD} job-exec request.json -- --timeout 0 # don't wait for result
63
+ poetry {PLUGIN_CMD} job-exec request.json -- --watch # shows all the events produced by the service
47
64
 
48
65
  Configurable options in pyproject.toml:
49
66
 
@@ -71,15 +88,18 @@ Configurable options in pyproject.toml:
71
88
  def handle(self):
72
89
 
73
90
  sub = self.argument("subcommand")
91
+ poetry = self.application.poetry
92
+
74
93
  if sub == "version":
75
- #v = poetry.get_plugin('ivcap').version
76
94
  v = version(PLUGIN_NAME)
77
- print(f"IVCAP plugin (version {v})")
95
+ ivcap_version = ivcap_cli_version()
96
+ if ivcap_version:
97
+ print(f"IVCAP plugin (version {v} - cli {ivcap_version})")
98
+ else:
99
+ print(f"IVCAP plugin (version {v})")
78
100
  return
79
101
 
80
- poetry = self.application.poetry
81
102
  data = poetry.pyproject.data
82
-
83
103
  args = self.argument("args")
84
104
  is_silent = self.option("silent")
85
105
 
@@ -105,6 +125,12 @@ Configurable options in pyproject.toml:
105
125
  elif sub == "get-service-id":
106
126
  sid = get_service_id(data, is_silent, self.line)
107
127
  print(sid)
128
+ elif sub == "get-service-description":
129
+ sd = service_description(data, self.line)
130
+ print(sd)
131
+ elif sub == "get-tool-description":
132
+ td = tool_description(data, self.line)
133
+ print(td)
108
134
  elif sub == "tool-register":
109
135
  tool_register(data, self.line)
110
136
 
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2025 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
2
+ # Copyright (c) 2025-2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
3
3
  # Use of this source code is governed by a BSD-style license that can be
4
4
  # found in the LICENSE file. See the AUTHORS file for names of contributors.
5
5
  #
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2025 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
2
+ # Copyright (c) 2025-2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
3
3
  # Use of this source code is governed by a BSD-style license that can be
4
4
  # found in the LICENSE file. See the AUTHORS file for names of contributors.
5
5
  #
@@ -1,14 +1,13 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: poetry-plugin-ivcap
3
- Version: 0.5.2
3
+ Version: 0.6.1
4
4
  Summary: A custom Poetry command for IVCAP deployments
5
5
  License: MIT
6
6
  Author: Max Ott
7
7
  Author-email: max.ott@csiro.au
8
- Requires-Python: >=3.9
8
+ Requires-Python: >=3.10,<4.0
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.9
12
11
  Classifier: Programming Language :: Python :: 3.10
13
12
  Classifier: Programming Language :: Python :: 3.11
14
13
  Classifier: Programming Language :: Python :: 3.12
@@ -84,6 +83,27 @@ Configurable optiosn in pyproject.toml:
84
83
 
85
84
  ## Development
86
85
 
86
+ ### Test the plugin as part of the "global" installed poetry
87
+
88
+ ```shell
89
+ # 1) remove any existing installed copy first
90
+ poetry self remove poetry-plugin-ivcap
91
+
92
+ # 2) install this checkout as an editable plugin
93
+ poetry self add -e $PWD
94
+
95
+ # 3) verify Poetry sees the plugin
96
+ poetry self show plugins
97
+ ```
98
+
99
+
100
+ Switch back:
101
+
102
+ ```
103
+ poetry self remove poetry-plugin-ivcap
104
+ poetry self add poetry-plugin-ivcap@latest
105
+ ```
106
+
87
107
  ### Build the Plugin Package
88
108
 
89
109
  ```bash
@@ -0,0 +1,12 @@
1
+ poetry_plugin_ivcap/constants.py,sha256=NllPHV4w3YDQmEPBz_rKveXiwOqGowih17XoEgkKJrM,1331
2
+ poetry_plugin_ivcap/docker.py,sha256=CIPKbHJ9yQDZMYqKPFZRGz3wpmrHvIoIZgPyluiryCU,7711
3
+ poetry_plugin_ivcap/ivcap.py,sha256=zAqrv5987rD2bcNH5R1wm-JWiGsZnT3qh7BlF9o4PSQ,16454
4
+ poetry_plugin_ivcap/plugin.py,sha256=gZ92h3ZRFpj9cM8ZqRxWF4gHmEir4B0nXBprLDMGYdw,6567
5
+ poetry_plugin_ivcap/types.py,sha256=m8UEziKacHBe2LLV-UlkNYwn3vZ4CnEDtxDwPkraR8c,1356
6
+ poetry_plugin_ivcap/util.py,sha256=5mKL5sCmtHe2e0pENda2HZNxpwe6VUMC-cOWEIrL2Bc,3434
7
+ poetry_plugin_ivcap-0.6.1.dist-info/AUTHORS.md,sha256=s9xR4_HAHQgbNlj505LViebt5AtACQmhPf92aJvNYgg,88
8
+ poetry_plugin_ivcap-0.6.1.dist-info/LICENSE,sha256=dsQrDPPwW7iJs9pxahgJKDW8RNPf5FyXG70MFUlxcuk,1587
9
+ poetry_plugin_ivcap-0.6.1.dist-info/METADATA,sha256=l53tGbI8BiLLXfdqiYkWwoQOhU60-3gEhkovx8dFhOE,3390
10
+ poetry_plugin_ivcap-0.6.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
11
+ poetry_plugin_ivcap-0.6.1.dist-info/entry_points.txt,sha256=3xagEFBkGgrVe8WyjmhlHLr4JDEWPN_W4DwxnIBWbNY,74
12
+ poetry_plugin_ivcap-0.6.1.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- poetry_plugin_ivcap/constants.py,sha256=jD8j_kBwo0i-IupEGBJRvI_Uwyfde_IaRghYASxf4tA,1326
2
- poetry_plugin_ivcap/docker.py,sha256=QR3DJRn6l3RFxCiAvn8Kai_6e_mJ3YVuR_Pmnd1szqY,7714
3
- poetry_plugin_ivcap/ivcap.py,sha256=yRS_mhS5P8sbIEofE9f7PRfsuZNGeyRrfjSNRg8shFY,15464
4
- poetry_plugin_ivcap/plugin.py,sha256=hBsJaQzOlYnTjoBcS7AVSpsD2v0MtzcAabP70-cG2cs,5627
5
- poetry_plugin_ivcap/types.py,sha256=gpoMnKZgO8JV-RFJs67cymuSj3d1RrLDJ8160_7NsKY,1351
6
- poetry_plugin_ivcap/util.py,sha256=bcjjbKoV_pAgeuC7Ws9XbJa3phFpNVyrRAlFJ1VubRg,3429
7
- poetry_plugin_ivcap-0.5.2.dist-info/AUTHORS.md,sha256=s9xR4_HAHQgbNlj505LViebt5AtACQmhPf92aJvNYgg,88
8
- poetry_plugin_ivcap-0.5.2.dist-info/LICENSE,sha256=dsQrDPPwW7iJs9pxahgJKDW8RNPf5FyXG70MFUlxcuk,1587
9
- poetry_plugin_ivcap-0.5.2.dist-info/METADATA,sha256=wUm9lrn8ZZokYRXBXp603XVEGHvG-B0AXcIsudrhSrY,3032
10
- poetry_plugin_ivcap-0.5.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
11
- poetry_plugin_ivcap-0.5.2.dist-info/entry_points.txt,sha256=3xagEFBkGgrVe8WyjmhlHLr4JDEWPN_W4DwxnIBWbNY,74
12
- poetry_plugin_ivcap-0.5.2.dist-info/RECORD,,