pubtools-pyxis 1.3.4__tar.gz → 1.3.6__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.
Files changed (44) hide show
  1. {pubtools-pyxis-1.3.4/pubtools_pyxis.egg-info → pubtools_pyxis-1.3.6}/PKG-INFO +31 -3
  2. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/CHANGELOG.rst +11 -0
  3. pubtools_pyxis-1.3.6/requirements-test.txt +8 -0
  4. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/requirements.txt +1 -0
  5. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/setup.py +11 -3
  6. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools/_pyxis/pyxis_authentication.py +14 -10
  7. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools/_pyxis/pyxis_client.py +48 -29
  8. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools/_pyxis/pyxis_ops.py +152 -20
  9. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools/_pyxis/pyxis_session.py +18 -11
  10. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools/_pyxis/utils.py +3 -2
  11. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src/pubtools_pyxis.egg-info}/PKG-INFO +31 -3
  12. pubtools_pyxis-1.3.6/src/pubtools_pyxis.egg-info/SOURCES.txt +40 -0
  13. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools_pyxis.egg-info/entry_points.txt +7 -0
  14. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools_pyxis.egg-info/requires.txt +1 -0
  15. pubtools_pyxis-1.3.6/tests/test_pyxis_authentication.py +124 -0
  16. pubtools_pyxis-1.3.6/tests/test_pyxis_client.py +325 -0
  17. pubtools_pyxis-1.3.6/tests/test_pyxis_ops.py +1012 -0
  18. pubtools_pyxis-1.3.6/tests/test_pyxis_session.py +58 -0
  19. pubtools-pyxis-1.3.4/pubtools/__init__.py +0 -1
  20. pubtools-pyxis-1.3.4/pubtools_pyxis.egg-info/SOURCES.txt +0 -37
  21. pubtools-pyxis-1.3.4/requirements-test.txt +0 -5
  22. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/LICENSE +0 -0
  23. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/MANIFEST.in +0 -0
  24. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/README.rst +0 -0
  25. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/Makefile +0 -0
  26. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/README.rst +0 -0
  27. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/conf.py +0 -0
  28. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/delete_signatures.rst +0 -0
  29. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/entrypoints_reference.rst +0 -0
  30. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/get_indices.rst +0 -0
  31. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/get_repo_metadata.rst +0 -0
  32. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/get_signatures.rst +0 -0
  33. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/index.rst +0 -0
  34. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/modules_reference.rst +0 -0
  35. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/ops_helpers.rst +0 -0
  36. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/pyxis_authentication.rst +0 -0
  37. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/pyxis_client.rst +0 -0
  38. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/pyxis_session.rst +0 -0
  39. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/docs/source/upload_signatures.rst +0 -0
  40. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6}/setup.cfg +0 -0
  41. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools/_pyxis/__init__.py +0 -0
  42. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools/_pyxis/constants.py +0 -0
  43. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools_pyxis.egg-info/dependency_links.txt +0 -0
  44. {pubtools-pyxis-1.3.4 → pubtools_pyxis-1.3.6/src}/pubtools_pyxis.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pubtools-pyxis
3
- Version: 1.3.4
3
+ Version: 1.3.6
4
4
  Summary: Pubtools-pyxis
5
5
  Home-page: https://github.com/release-engineering/pubtools-pyxis
6
6
  Author: Lubomir Gallovic
@@ -15,8 +15,25 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
15
15
  Classifier: Programming Language :: Python :: Implementation :: PyPy
16
16
  Requires-Python: >=3.6
17
17
  Description-Content-Type: text/x-rst
18
- Provides-Extra: reST
19
18
  License-File: LICENSE
19
+ Requires-Dist: setuptools
20
+ Requires-Dist: more-executors>=2.3.0
21
+ Requires-Dist: requests
22
+ Requires-Dist: requests-kerberos
23
+ Requires-Dist: urllib3<2
24
+ Provides-Extra: rest
25
+ Requires-Dist: Sphinx; extra == "rest"
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: license-file
33
+ Dynamic: provides-extra
34
+ Dynamic: requires-dist
35
+ Dynamic: requires-python
36
+ Dynamic: summary
20
37
 
21
38
  ===============
22
39
  pubtools-pyxis
@@ -128,6 +145,17 @@ Get signatures:
128
145
  ChangeLog
129
146
  =========
130
147
 
148
+ 1.3.6 (2025-03-06)
149
+ ------------------
150
+
151
+ * Splitted entrypoitnts to `console_scripts` and `mod`.
152
+
153
+
154
+ 1.3.5 (2023-03-14)
155
+ ------------------
156
+
157
+ * Delete signatures in parallel
158
+
131
159
  1.3.4 (2023-03-01)
132
160
  ------------------
133
161
 
@@ -1,6 +1,17 @@
1
1
  ChangeLog
2
2
  =========
3
3
 
4
+ 1.3.6 (2025-03-06)
5
+ ------------------
6
+
7
+ * Splitted entrypoitnts to `console_scripts` and `mod`.
8
+
9
+
10
+ 1.3.5 (2023-03-14)
11
+ ------------------
12
+
13
+ * Delete signatures in parallel
14
+
4
15
  1.3.4 (2023-03-01)
5
16
  ------------------
6
17
 
@@ -0,0 +1,8 @@
1
+ mock
2
+ requests-mock
3
+ pytest
4
+ pytest-pylint
5
+ pytest-cov
6
+ bandit==1.7.5
7
+ mypy
8
+ types-requests
@@ -2,3 +2,4 @@ setuptools
2
2
  more-executors>=2.3.0
3
3
  requests
4
4
  requests-kerberos
5
+ urllib3<2
@@ -7,7 +7,7 @@ import sys
7
7
 
8
8
  # import pkg_resources
9
9
  import sys
10
- from setuptools import setup, find_packages
10
+ from setuptools import setup, find_namespace_packages
11
11
  from setuptools.command.test import test as TestCommand
12
12
 
13
13
 
@@ -71,7 +71,7 @@ if os.environ.get("READTHEDOCS", None):
71
71
 
72
72
  setup(
73
73
  name="pubtools-pyxis",
74
- version="1.3.4",
74
+ version="1.3.6",
75
75
  description="Pubtools-pyxis",
76
76
  long_description=long_description,
77
77
  long_description_content_type='text/x-rst',
@@ -80,7 +80,8 @@ setup(
80
80
  url="https://github.com/release-engineering/pubtools-pyxis",
81
81
  classifiers=classifiers,
82
82
  python_requires='>=3.6',
83
- packages=find_packages(exclude=["tests"]),
83
+ packages=find_namespace_packages(where="src"),
84
+ package_dir={"": "src"},
84
85
  data_files=[],
85
86
  install_requires=get_requirements(),
86
87
  dependency_links=DEPENDENCY_LINKS,
@@ -91,6 +92,13 @@ setup(
91
92
  "pubtools-pyxis-upload-signatures = pubtools._pyxis.pyxis_ops:upload_signatures_main",
92
93
  "pubtools-pyxis-get-signatures = pubtools._pyxis.pyxis_ops:get_signatures_main",
93
94
  "pubtools-pyxis-delete-signatures = pubtools._pyxis.pyxis_ops:delete_signatures_main"
95
+ ],
96
+ "mod": [
97
+ "pubtools-pyxis-get-operator-indices = pubtools._pyxis.pyxis_ops:get_operator_indices_mod",
98
+ "pubtools-pyxis-get-repo-metadata = pubtools._pyxis.pyxis_ops:get_repo_metadata_mod",
99
+ "pubtools-pyxis-upload-signatures = pubtools._pyxis.pyxis_ops:upload_signatures_mod",
100
+ "pubtools-pyxis-get-signatures = pubtools._pyxis.pyxis_ops:get_signatures_mod",
101
+ "pubtools-pyxis-delete-signatures = pubtools._pyxis.pyxis_ops:delete_signatures_mod"
94
102
  ]
95
103
  },
96
104
  include_package_data=True,
@@ -3,15 +3,17 @@ import subprocess
3
3
 
4
4
  from requests_kerberos import HTTPKerberosAuth, OPTIONAL
5
5
 
6
+ from .pyxis_session import PyxisSession
6
7
 
7
- class PyxisAuth(object):
8
+
9
+ class PyxisAuth:
8
10
  """Base Auth class."""
9
11
 
10
- def __init__(self):
12
+ def __init__(self) -> None:
11
13
  """Initialize."""
12
14
  raise NotImplementedError # pragma: no cover"
13
15
 
14
- def apply_to_session(self, pyxis_session):
16
+ def apply_to_session(self, pyxis_session: PyxisSession) -> None:
15
17
  """Set up initialization in the Pyxis session."""
16
18
  raise NotImplementedError # pragma: no cover"
17
19
 
@@ -20,7 +22,7 @@ class PyxisSSLAuth(PyxisAuth):
20
22
  """SSL Auth provider to PyxisClient."""
21
23
 
22
24
  # pylint: disable=super-init-not-called
23
- def __init__(self, crt_path, key_path):
25
+ def __init__(self, crt_path: str, key_path: str) -> None:
24
26
  """
25
27
  Initialize.
26
28
 
@@ -33,7 +35,7 @@ class PyxisSSLAuth(PyxisAuth):
33
35
  self.crt_path = crt_path
34
36
  self.key_path = key_path
35
37
 
36
- def apply_to_session(self, pyxis_session):
38
+ def apply_to_session(self, pyxis_session: PyxisSession) -> None:
37
39
  """
38
40
  Set up PyxisSession with SSL auth.
39
41
 
@@ -47,7 +49,9 @@ class PyxisSSLAuth(PyxisAuth):
47
49
  class PyxisKrbAuth(PyxisAuth):
48
50
  """Kerberos authentication support for PyxisClient."""
49
51
 
50
- def __init__(self, krb_princ, service, ktfile=None, ccache_file=None):
52
+ def __init__(
53
+ self, krb_princ: str, service: str, ccache_file: str, ktfile: str | None = None
54
+ ) -> None:
51
55
  """
52
56
  Initialize.
53
57
 
@@ -56,17 +60,17 @@ class PyxisKrbAuth(PyxisAuth):
56
60
  Kerberos principal for obtaining ticket.
57
61
  service (str)
58
62
  URL of the service to apply the authentication to.
59
- ktfile (str)
60
- Kerberos client keytab file.
61
63
  ccache_file (str)
62
64
  Path to a file used for ccache. Only necessary if kinit will be used.
65
+ ktfile (str)
66
+ Kerberos client keytab file.
63
67
  """
64
68
  self.krb_princ = krb_princ
65
69
  self.service = service
66
70
  self.ktfile = ktfile
67
71
  self.ccache_file = ccache_file
68
72
 
69
- def _krb_auth(self):
73
+ def _krb_auth(self) -> HTTPKerberosAuth:
70
74
  retcode = subprocess.Popen(
71
75
  ["klist", "-s"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
72
76
  ).wait()
@@ -102,7 +106,7 @@ class PyxisKrbAuth(PyxisAuth):
102
106
  force_preemptive=True,
103
107
  )
104
108
 
105
- def apply_to_session(self, pyxis_session):
109
+ def apply_to_session(self, pyxis_session: PyxisSession) -> None:
106
110
  """Set up PyxisSession with Kerberos auth.
107
111
 
108
112
  Args:
@@ -3,27 +3,29 @@ from concurrent.futures import as_completed
3
3
  from functools import partial
4
4
  import math
5
5
  import threading
6
+ from typing import Callable, Any
6
7
 
7
8
  from more_executors import Executors
8
9
  from requests.exceptions import HTTPError
10
+ from requests import Response
9
11
 
10
12
  from .constants import DEFAULT_REQUEST_THREADS_LIMIT
11
13
  from .pyxis_session import PyxisSession
14
+ from .pyxis_authentication import PyxisAuth
12
15
 
13
16
 
14
- # pylint: disable=bad-option-value,useless-object-inheritance
15
- class PyxisClient(object):
17
+ class PyxisClient:
16
18
  """Pyxis requests wrapper."""
17
19
 
18
20
  def __init__(
19
21
  self,
20
- hostname,
21
- retries=5,
22
- auth=None,
23
- backoff_factor=5,
24
- verify=True,
25
- threads=DEFAULT_REQUEST_THREADS_LIMIT,
26
- ):
22
+ hostname: str,
23
+ retries: int = 5,
24
+ auth: PyxisAuth | None = None,
25
+ backoff_factor: int = 5,
26
+ verify: bool = True,
27
+ threads: int = DEFAULT_REQUEST_THREADS_LIMIT,
28
+ ) -> None:
27
29
  """
28
30
  Initialize.
29
31
 
@@ -53,7 +55,7 @@ class PyxisClient(object):
53
55
  self.threads_limit = threads
54
56
 
55
57
  @property
56
- def pyxis_session(self):
58
+ def pyxis_session(self) -> PyxisSession | Any:
57
59
  """
58
60
  Return a thread-local session for Pyxis requests.
59
61
 
@@ -64,13 +66,15 @@ class PyxisClient(object):
64
66
  self.thread_local.pyxis_session = self._make_session()
65
67
  return self.thread_local.pyxis_session
66
68
 
67
- def _make_session(self):
69
+ def _make_session(self) -> PyxisSession:
68
70
  session = self._session_factory()
69
71
  if self._auth:
70
72
  self._auth.apply_to_session(session)
71
73
  return session
72
74
 
73
- def get_operator_indices(self, ocp_versions_range, organization=None):
75
+ def get_operator_indices(
76
+ self, ocp_versions_range: str, organization: str | None = None
77
+ ) -> list[str] | Any:
74
78
  """Get a list of index images satisfying versioning and organization conditions.
75
79
 
76
80
  Args:
@@ -91,8 +95,12 @@ class PyxisClient(object):
91
95
  return resp.json()["data"]
92
96
 
93
97
  def get_repository_metadata(
94
- self, repo_name, custom_registry=None, only_internal=False, only_partner=False
95
- ):
98
+ self,
99
+ repo_name: str,
100
+ custom_registry: str | None = None,
101
+ only_internal: bool = False,
102
+ only_partner: bool = False,
103
+ ) -> dict[Any, Any] | Any:
96
104
  """Get metadata of a Comet repository.
97
105
 
98
106
  If checking only one registry hasn't been specified, check both with precedence on
@@ -130,19 +138,19 @@ class PyxisClient(object):
130
138
  resp.raise_for_status()
131
139
  return resp.json()
132
140
 
133
- def upload_signatures(self, signatures):
141
+ def upload_signatures(self, signatures: list[str]) -> list[Any]:
134
142
  """
135
143
  Upload signatures from given JSON string.
136
144
 
137
145
  Args:
138
- signatures (str)
146
+ signatures [str]
139
147
  JSON with signatures to upload. See Pyxis API for details.
140
148
 
141
149
  Returns:
142
150
  list: List of uploaded signatures including auto-populated fields.
143
151
  """
144
152
 
145
- def _send_post_request(data):
153
+ def _send_post_request(data: dict[Any, Any]) -> Response:
146
154
  response = self.pyxis_session.post("signatures", json=data)
147
155
  # SEE CLOUDDST-9698
148
156
  # Pyxis returns 500 error due to a potential sidecar config issue
@@ -156,11 +164,13 @@ class PyxisClient(object):
156
164
 
157
165
  return self._do_parallel_requests(_send_post_request, signatures)
158
166
 
159
- def _clear_session(self):
167
+ def _clear_session(self) -> None:
160
168
  self.thread_local.pyxis_session.close()
161
169
  delattr(self.thread_local, "pyxis_session")
162
170
 
163
- def _do_parallel_requests(self, make_request, data_items):
171
+ def _do_parallel_requests(
172
+ self, make_request: Callable[[Any], Any], data_items: list[Any]
173
+ ) -> list[Any] | Any:
164
174
  """
165
175
  Call given function with given data items in parallel, collect responses.
166
176
 
@@ -189,7 +199,7 @@ class PyxisClient(object):
189
199
 
190
200
  return [f.result() for f in as_completed(futures)]
191
201
 
192
- def _handle_json_response(self, response):
202
+ def _handle_json_response(self, response: Response) -> dict[Any, Any] | Any:
193
203
  """
194
204
  Get JSON from given response or raise an informative exception.
195
205
 
@@ -202,8 +212,14 @@ class PyxisClient(object):
202
212
  except ValueError: # Python 2.x compat
203
213
  data = {}
204
214
 
215
+ tolerate_codes = []
205
216
  # Uploaded data already exists in Pyxis
206
- if response.status_code == 409:
217
+ if response.request.method == "POST":
218
+ tolerate_codes = [409]
219
+ # Data already removed from Pyxis
220
+ elif response.request.method == "DELETE":
221
+ tolerate_codes = [404]
222
+ if response.status_code in tolerate_codes:
207
223
  return data
208
224
 
209
225
  try:
@@ -216,11 +232,13 @@ class PyxisClient(object):
216
232
  extra_msg = data["detail"] if "detail" in data else response.text
217
233
 
218
234
  # re-raise the exception with an extra message
219
- raise HTTPError("{0}\n{1}".format(e, extra_msg))
235
+ raise HTTPError("{0}\n{1}".format(e, extra_msg), response=response)
220
236
 
221
237
  return data
222
238
 
223
- def get_container_signatures(self, manifest_digests=None, references=None):
239
+ def get_container_signatures(
240
+ self, manifest_digests: str | None = None, references: str | None = None
241
+ ) -> list[str]:
224
242
  """Get a list of signature metadata matching given fields.
225
243
 
226
244
  Args:
@@ -248,7 +266,7 @@ class PyxisClient(object):
248
266
 
249
267
  return resp
250
268
 
251
- def _get_items_from_all_pages(self, endpoint, **kwargs):
269
+ def _get_items_from_all_pages(self, endpoint: str, **kwargs: Any) -> list[Any]:
252
270
  """
253
271
  Get response from all pages of pyxis.
254
272
 
@@ -277,16 +295,17 @@ class PyxisClient(object):
277
295
  all_resp.extend(resp.json()["data"])
278
296
  return all_resp
279
297
 
280
- def delete_container_signatures(self, signature_ids):
298
+ def delete_container_signatures(self, signature_ids: list[str]) -> list[Any]:
281
299
  """Delete signatures matching given fields.
282
300
 
283
301
  Args:
284
302
  signature_ids ([str])
285
303
  Internal Pyxis signature IDs of signatures which should be removed.
286
304
  """
287
- delete_endpoint = "signatures/id/{id}"
288
305
 
289
- for signature_id in signature_ids:
306
+ def _send_delete_request(signature_id: str) -> Response:
307
+ delete_endpoint = "signatures/id/{id}"
290
308
  resp = self.pyxis_session.delete(delete_endpoint.format(id=signature_id))
291
- if resp.status_code != 404:
292
- resp.raise_for_status()
309
+ return resp
310
+
311
+ return self._do_parallel_requests(_send_delete_request, signature_ids)
@@ -1,9 +1,11 @@
1
1
  import json
2
2
  import sys
3
3
  import tempfile
4
+ from argparse import ArgumentParser, Namespace
5
+ from typing import Any
4
6
 
5
7
  from .constants import DEFAULT_REQUEST_THREADS_LIMIT
6
- from .pyxis_authentication import PyxisKrbAuth, PyxisSSLAuth
8
+ from .pyxis_authentication import PyxisKrbAuth, PyxisSSLAuth, PyxisAuth
7
9
  from .pyxis_client import PyxisClient
8
10
  from .utils import setup_arg_parser
9
11
 
@@ -108,9 +110,15 @@ DELETE_SIGNATURES_ARGS[("--ids",)] = {
108
110
  "required": True,
109
111
  "type": str,
110
112
  }
113
+ DELETE_SIGNATURES_ARGS[("--request-threads",)] = {
114
+ "help": "Maximum number of threads to use for parallel requests",
115
+ "required": False,
116
+ "default": DEFAULT_REQUEST_THREADS_LIMIT,
117
+ "type": int,
118
+ }
111
119
 
112
120
 
113
- def setup_pyxis_client(args, ccache_file):
121
+ def setup_pyxis_client(args: Namespace, ccache_file: str) -> PyxisClient:
114
122
  """
115
123
  Set up a PyxisClient instance according to specified parameters.
116
124
 
@@ -125,11 +133,11 @@ def setup_pyxis_client(args, ccache_file):
125
133
  """
126
134
  # If both auths are specified, Kerberos is preferred
127
135
  if args.pyxis_krb_principal:
128
- auth = PyxisKrbAuth(
136
+ auth: PyxisAuth = PyxisKrbAuth(
129
137
  args.pyxis_krb_principal,
130
138
  args.pyxis_server,
131
- args.pyxis_krb_ktfile,
132
139
  ccache_file,
140
+ args.pyxis_krb_ktfile,
133
141
  )
134
142
  elif args.pyxis_ssl_crtfile and args.pyxis_ssl_keyfile:
135
143
  auth = PyxisSSLAuth(args.pyxis_ssl_crtfile, args.pyxis_ssl_keyfile)
@@ -150,12 +158,12 @@ def setup_pyxis_client(args, ccache_file):
150
158
  return PyxisClient(args.pyxis_server, auth=auth, verify=not args.pyxis_insecure)
151
159
 
152
160
 
153
- def set_get_operator_indices_args():
161
+ def set_get_operator_indices_args() -> ArgumentParser:
154
162
  """Set up argparser without extra parameters, this method is used for auto doc generation."""
155
163
  return setup_arg_parser(GET_OPERATORS_INDICES_ARGS)
156
164
 
157
165
 
158
- def get_operator_indices_main(sysargs=None):
166
+ def _get_operator_indices(sysargs: list[str] | None = None) -> list[str] | Any:
159
167
  """
160
168
  Entrypoint for getting operator indices.
161
169
 
@@ -173,17 +181,41 @@ def get_operator_indices_main(sysargs=None):
173
181
  resp = pyxis_client.get_operator_indices(
174
182
  args.ocp_versions_range, args.organization
175
183
  )
184
+ return resp
185
+
176
186
 
187
+ def get_operator_indices_main(sysargs: list[str] | None = None) -> int:
188
+ """
189
+ Entrypoint for getting operator indices.
190
+
191
+ Returns:
192
+ int: Exit code (0 for success).
193
+ """
194
+ try:
195
+ resp = _get_operator_indices(sysargs)
177
196
  json.dump(resp, sys.stdout, sort_keys=True, indent=4, separators=(",", ": "))
178
- return resp
197
+ return 0
198
+ except Exception as e:
199
+ print(f"Error getting operator indices: {e}", file=sys.stderr)
200
+ return 1
201
+
179
202
 
203
+ def get_operator_indices_mod(sysargs: list[str] | None = None) -> list[str] | Any:
204
+ """
205
+ Entrypoint for getting operator indices in module mode.
180
206
 
181
- def set_get_repo_metadata_args():
207
+ This function is used when running the script as a module.
208
+ It does not return an exit code, but rather prints the result directly.
209
+ """
210
+ return _get_operator_indices(sysargs)
211
+
212
+
213
+ def set_get_repo_metadata_args() -> ArgumentParser:
182
214
  """Set up argparser without extra parameters, this method is used for auto doc generation."""
183
215
  return setup_arg_parser(GET_REPO_METADATA_ARGS)
184
216
 
185
217
 
186
- def get_repo_metadata_main(sysargs=None):
218
+ def _get_repo_metadata(sysargs: list[str] | None = None) -> dict[Any, Any] | Any:
187
219
  """
188
220
  Entrypoint for getting repository metadata.
189
221
 
@@ -210,17 +242,42 @@ def get_repo_metadata_main(sysargs=None):
210
242
  args.only_internal_registry,
211
243
  args.only_partner_registry,
212
244
  )
245
+ return res
213
246
 
247
+
248
+ def get_repo_metadata_main(sysargs: list[str] | None = None) -> dict[Any, Any] | Any:
249
+ """
250
+ Entrypoint for getting repository metadata.
251
+
252
+ Returns:
253
+ int: Exit code (0 for success).
254
+ """
255
+ try:
256
+ res = _get_repo_metadata(sysargs)
214
257
  json.dump(res, sys.stdout, sort_keys=True, indent=4, separators=(",", ": "))
215
- return res
258
+ return 0
259
+ except Exception as e:
260
+ print(f"Error getting repository metadata: {e}", file=sys.stderr)
261
+ return 1
262
+
263
+
264
+ def get_repo_metadata_mod(sysargs: list[str] | None = None) -> dict[Any, Any] | Any:
265
+ """
266
+ Entrypoint for getting repository metadata in module mode.
267
+
268
+ This function is used when running the script as a module.
269
+ It does not return an exit code, but rather prints the result directly.
270
+ """
271
+ return _get_repo_metadata(sysargs)
272
+ # No return value, output is printed directly
216
273
 
217
274
 
218
- def set_upload_signatures_args():
275
+ def set_upload_signatures_args() -> ArgumentParser:
219
276
  """Set up argparser without extra parameters, this method is used for auto doc generation."""
220
277
  return setup_arg_parser(UPLOAD_SIGNATURES_ARGS)
221
278
 
222
279
 
223
- def upload_signatures_main(sysargs=None):
280
+ def _upload_signatures(sysargs: list[str] | None = None) -> list[Any]:
224
281
  """
225
282
  Entrypoint for uploading signatures from JSON or a file.
226
283
 
@@ -238,13 +295,37 @@ def upload_signatures_main(sysargs=None):
238
295
  with tempfile.NamedTemporaryFile() as tmpfile:
239
296
  pyxis_client = setup_pyxis_client(args, tmpfile.name)
240
297
  resp = pyxis_client.upload_signatures(signatures_json)
298
+ return resp
299
+
241
300
 
301
+ def upload_signatures_main(sysargs: list[str] | None = None) -> int:
302
+ """
303
+ Entrypoint for uploading signatures from JSON or a file.
304
+
305
+ Returns:
306
+ int: Exit code (0 for success).
307
+ """
308
+ try:
309
+ resp = _upload_signatures(sysargs)
242
310
  json.dump(resp, sys.stdout, sort_keys=True, indent=4, separators=(",", ": "))
311
+ return 0
312
+ except Exception as e:
313
+ print(f"Error uploading signatures: {e}", file=sys.stderr)
314
+ return 1
243
315
 
244
- return resp
316
+
317
+ def upload_signatures_mod(sysargs: list[str] | None = None) -> list[Any]:
318
+ """
319
+ Entrypoint for uploading signatures from JSON or a file in module mode.
320
+
321
+ This function is used when running the script as a module.
322
+ It does not return an exit code, but rather prints the result directly.
323
+ """
324
+ return _upload_signatures(sysargs)
325
+ # No return value, output is printed directly
245
326
 
246
327
 
247
- def deserialize_list_from_arg(value, csv_input=False):
328
+ def deserialize_list_from_arg(value: str, csv_input: bool = False) -> list[Any] | Any:
248
329
  """
249
330
  Conditionally load contents of a file if specified in argument value.
250
331
 
@@ -269,17 +350,17 @@ def deserialize_list_from_arg(value, csv_input=False):
269
350
  return json.load(f)
270
351
 
271
352
 
272
- def serialize_to_csv_from_list(list_value):
353
+ def serialize_to_csv_from_list(list_value: list[Any]) -> str:
273
354
  """Convert a list to comma separated string."""
274
355
  return ",".join(list_value)
275
356
 
276
357
 
277
- def set_get_signatures_args():
358
+ def set_get_signatures_args() -> ArgumentParser:
278
359
  """Set up argparser without extra parameters, this method is used for auto doc generation."""
279
360
  return setup_arg_parser(GET_SIGNATURES_ARGS)
280
361
 
281
362
 
282
- def get_signatures_main(sysargs=None):
363
+ def _get_signatures(sysargs: list[str] | None = None) -> list[str]:
283
364
  """
284
365
  Entrypoint for getting container signature metadata.
285
366
 
@@ -309,17 +390,42 @@ def get_signatures_main(sysargs=None):
309
390
  res = pyxis_client.get_container_signatures(
310
391
  csv_manifest_digests, csv_references
311
392
  )
393
+ return res
394
+
312
395
 
396
+ def get_signatures_main(sysargs: list[str] | None = None) -> int:
397
+ """
398
+ Entrypoint for getting container signature metadata.
399
+
400
+ Returns:
401
+ int: Exit code (0 for success).
402
+ """
403
+ try:
404
+ res = _get_signatures(sysargs)
313
405
  json.dump(res, sys.stdout, sort_keys=True, indent=4, separators=(",", ": "))
314
- return res
406
+ return 0
407
+ except Exception as e:
408
+ print(f"Error getting signatures: {e}", file=sys.stderr)
409
+ return 1
315
410
 
316
411
 
317
- def set_delete_signatures_args():
412
+ def get_signatures_mod(sysargs: list[str] | None = None) -> list[str]:
413
+ """
414
+ Entrypoint for getting container signature metadata in module mode.
415
+
416
+ This function is used when running the script as a module.
417
+ It does not return an exit code, but rather prints the result directly.
418
+ """
419
+ return _get_signatures(sysargs)
420
+ # No return value, output is printed directly
421
+
422
+
423
+ def set_delete_signatures_args() -> ArgumentParser:
318
424
  """Set up argparser without extra parameters, this method is used for auto doc generation."""
319
425
  return setup_arg_parser(DELETE_SIGNATURES_ARGS)
320
426
 
321
427
 
322
- def delete_signatures_main(sysargs=None):
428
+ def _delete_signatures(sysargs: list[str] | None = None) -> None:
323
429
  """
324
430
  Entrypoint for removing existing signatures.
325
431
 
@@ -338,3 +444,29 @@ def delete_signatures_main(sysargs=None):
338
444
  with tempfile.NamedTemporaryFile() as tmpfile:
339
445
  pyxis_client = setup_pyxis_client(args, tmpfile.name)
340
446
  pyxis_client.delete_container_signatures(signature_ids)
447
+
448
+
449
+ def delete_signatures_main(sysargs: list[str] | None = None) -> int:
450
+ """
451
+ Entrypoint for removing existing signatures.
452
+
453
+ Returns:
454
+ int: Exit code (0 for success).
455
+ """
456
+ try:
457
+ _delete_signatures(sysargs)
458
+ return 0
459
+ except Exception as e:
460
+ print(f"Error deleting signatures: {e}", file=sys.stderr)
461
+ return 1
462
+
463
+
464
+ def delete_signatures_mod(sysargs: list[str] | None = None) -> None:
465
+ """
466
+ Entrypoint for removing existing signatures in module mode.
467
+
468
+ This function is used when running the script as a module.
469
+ It does not return an exit code, but rather prints the result directly.
470
+ """
471
+ return _delete_signatures(sysargs)
472
+ # No return value, output is printed directly