poetry-plugin-ivcap 0.5.2__tar.gz → 0.6.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.
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/PKG-INFO +23 -3
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/README.md +21 -0
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/poetry_plugin_ivcap/constants.py +1 -1
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/poetry_plugin_ivcap/docker.py +4 -4
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/poetry_plugin_ivcap/ivcap.py +56 -25
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/poetry_plugin_ivcap/plugin.py +43 -17
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/poetry_plugin_ivcap/types.py +1 -1
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/poetry_plugin_ivcap/util.py +1 -1
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/pyproject.toml +7 -2
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/AUTHORS.md +0 -0
- {poetry_plugin_ivcap-0.5.2 → poetry_plugin_ivcap-0.6.1}/LICENSE +0 -0
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: poetry-plugin-ivcap
|
|
3
|
-
Version: 0.
|
|
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.
|
|
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
|
|
@@ -65,6 +65,27 @@ Configurable optiosn in pyproject.toml:
|
|
|
65
65
|
|
|
66
66
|
## Development
|
|
67
67
|
|
|
68
|
+
### Test the plugin as part of the "global" installed poetry
|
|
69
|
+
|
|
70
|
+
```shell
|
|
71
|
+
# 1) remove any existing installed copy first
|
|
72
|
+
poetry self remove poetry-plugin-ivcap
|
|
73
|
+
|
|
74
|
+
# 2) install this checkout as an editable plugin
|
|
75
|
+
poetry self add -e $PWD
|
|
76
|
+
|
|
77
|
+
# 3) verify Poetry sees the plugin
|
|
78
|
+
poetry self show plugins
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
Switch back:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
poetry self remove poetry-plugin-ivcap
|
|
86
|
+
poetry self add poetry-plugin-ivcap@latest
|
|
87
|
+
```
|
|
88
|
+
|
|
68
89
|
### Build the Plugin Package
|
|
69
90
|
|
|
70
91
|
```bash
|
|
@@ -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
|
-
|
|
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
|
-
#
|
|
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}
|
|
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:
|
|
106
|
+
line(f"<info>INFO: tool description successfully uploaded - {aid}</info>")
|
|
77
107
|
except Exception as e:
|
|
78
|
-
line(f"<error>ERROR: cannot upload
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "poetry-plugin-ivcap"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.6.1"
|
|
4
4
|
description = "A custom Poetry command for IVCAP deployments"
|
|
5
5
|
authors = ["Max Ott <max.ott@csiro.au>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -8,13 +8,18 @@ readme = "README.md"
|
|
|
8
8
|
packages = [{ include = "poetry_plugin_ivcap" }]
|
|
9
9
|
|
|
10
10
|
[tool.poetry.dependencies]
|
|
11
|
-
python = ">=3.
|
|
11
|
+
python = ">=3.10,<4.0"
|
|
12
12
|
pydantic = "^2.11.5"
|
|
13
13
|
humanize = "^4.12.3"
|
|
14
14
|
|
|
15
15
|
[tool.poetry.plugins."poetry.application.plugin"]
|
|
16
16
|
ivcap = "poetry_plugin_ivcap.plugin:IvcapPlugin"
|
|
17
17
|
|
|
18
|
+
|
|
19
|
+
[tool.poetry.group.dev.dependencies]
|
|
20
|
+
poetry = "^2.3.2"
|
|
21
|
+
cleo = "^2.1.0"
|
|
22
|
+
|
|
18
23
|
[build-system]
|
|
19
24
|
requires = ["poetry-core"]
|
|
20
25
|
build-backend = "poetry.core.masonry.api"
|
|
File without changes
|
|
File without changes
|