zosmfrestapi 0.1.0__tar.gz → 0.2.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.
Files changed (37) hide show
  1. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/PKG-INFO +20 -26
  2. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/README.md +16 -24
  3. zosmfrestapi-0.2.1/pyproject.toml +103 -0
  4. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/__init__.py +5 -3
  5. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/client.py +2 -1
  6. zosmfrestapi-0.2.1/zosmfrestapi/models/__init__.py +0 -0
  7. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/models/software.py +1 -1
  8. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/models/software_updates.py +1 -4
  9. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/models/topology.py +1 -4
  10. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/models/workflow.py +1 -3
  11. zosmfrestapi-0.2.1/zosmfrestapi/py.typed +0 -0
  12. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/services/__init__.py +29 -26
  13. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/services/authentication.py +7 -8
  14. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/services/software.py +6 -18
  15. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/services/software_updates.py +7 -21
  16. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/services/workflow.py +2 -6
  17. zosmfrestapi-0.2.1/zosmfrestapi/testing/__init__.py +11 -0
  18. zosmfrestapi-0.2.1/zosmfrestapi/testing/authentication.py +48 -0
  19. zosmfrestapi-0.2.1/zosmfrestapi/testing/helpers.py +9 -0
  20. zosmfrestapi-0.2.1/zosmfrestapi/testing/software.py +392 -0
  21. zosmfrestapi-0.2.1/zosmfrestapi/testing/software_updates.py +281 -0
  22. zosmfrestapi-0.2.1/zosmfrestapi/testing/topology.py +19 -0
  23. zosmfrestapi-0.2.1/zosmfrestapi/testing/workflows.py +320 -0
  24. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/utils.py +1 -3
  25. zosmfrestapi-0.2.1/zosmfrestapi/zcrypto.py +55 -0
  26. zosmfrestapi-0.2.1/zosmfrestapi/zcrypto_client.py +68 -0
  27. zosmfrestapi-0.1.0/pyproject.toml +0 -50
  28. zosmfrestapi-0.1.0/zosmfrestapi/models/__init__.py +0 -1
  29. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/LICENSE +0 -0
  30. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/exceptions/__init__.py +0 -0
  31. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/exceptions/authentication.py +0 -0
  32. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/exceptions/dataset.py +0 -0
  33. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/exceptions/software.py +0 -0
  34. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/exceptions/workflow.py +0 -0
  35. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/models/authentication.py +0 -0
  36. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/services/dataset.py +0 -0
  37. {zosmfrestapi-0.1.0 → zosmfrestapi-0.2.1}/zosmfrestapi/services/topology.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zosmfrestapi
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: A Python wrapper for the z/OSMF REST API
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -13,49 +13,43 @@ Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Topic :: Internet :: WWW/HTTP
15
15
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Provides-Extra: zcrypto
16
17
  Requires-Dist: dacite (>=1.9.2,<2.0.0)
17
18
  Requires-Dist: httpx2 (>=2.12.0,<3.0.0)
18
19
  Requires-Dist: pendulum (>=3.2.0,<4.0.0)
20
+ Requires-Dist: py_zcrypto ; extra == "zcrypto"
19
21
  Project-URL: Homepage, https://sr.ht/~ocurero/zosmfrestapi/
20
22
  Project-URL: PyPI, https://pypi.org/project/zosmfrestapi/
21
- Project-URL: Repository, https://sr.ht/~ocurero/zosmfrestapi/
23
+ Project-URL: Repository, https://git.sr.ht/~ocurero/zosmfrestapi
22
24
  Description-Content-Type: text/markdown
23
25
 
24
- A Python wrapper for the z/OSMF© REST API
25
- =========================================
26
+ # A Python wrapper for the z/OSMF© REST API
26
27
 
27
- [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) [![builds.sr.ht status](https://builds.sr.ht/~ocurero/zosmfrestapi/commits/main/.build.yml.svg)](https://builds.sr.ht/~ocurero/zosmfrestapi/commits/main/.build.yml?) ![z/OS](https://img.shields.io/badge/works%20on-z/OS-8A2BE2)
28
+ [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
29
+ [![builds.sr.ht status](https://builds.sr.ht/~ocurero/zosmfrestapi/commits/main/.build.yml.svg)](https://builds.sr.ht/~ocurero/zosmfrestapi/commits/main/.build.yml?)
30
+ ![z/OS](https://img.shields.io/badge/works%20on-z/OS-8A2BE2)
31
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
28
33
 
29
34
  * Open Source: MIT License.
30
35
  * Website: <https://sr.ht/~ocurero/zosmfrestapi/>
31
- * Pypi: <https://pypi.org/project/zosmfrestapi/>
36
+ * Repository: <https://git.sr.ht/~ocurero/zosmfrestapi>
37
+ * Changelog: <https://git.sr.ht/~ocurero/zosmfrestapi/tree/main/item/CHANGELOG.md>
38
+ * Contributing: <https://git.sr.ht/~ocurero/zosmfrestapi/tree/main/item/CONTRIBUTING.md>
39
+
40
+ Key features:
41
+ * **Pure Python**: Package and its dependencies are 100% pure Python (no C extensions required).
42
+ * **Cross-platform**: Works on Windows, Linux, macOS, and z/OS UNIX System Services.
43
+ * **Flexible authentication**: Supports user/password, LTPA and JWT tokens, and mutual TLS (mTLS).
44
+ * **Proxy ready**: Full support for standard HTTP/HTTPS proxies as well as authenticated proxies.
32
45
 
33
46
 
34
47
  Install
35
48
  -------
36
49
 
37
50
  **zosmfrestapi** requires Python 3.12 or newer and access to a z/OSMF server.
38
- You can check your Python version with:
39
-
40
- ```console
41
- python --version
42
- ```
43
-
44
- It is a good idea to use a virtual environment so this package does not affect
45
- other Python projects. From a terminal, create and activate one in your project
46
- folder:
47
-
48
- ```console
49
- # Windows (PowerShell)
50
- py -3.12 -m venv .venv
51
- .venv\Scripts\Activate.ps1
52
-
53
- # macOS or Linux
54
- python3 -m venv .venv
55
- source .venv/bin/activate
56
- ```
57
51
 
58
- Then install the package from PyPI:
52
+ Install the package from PyPI:
59
53
 
60
54
  ```console
61
55
  python -m pip install zosmfrestapi
@@ -1,38 +1,30 @@
1
- A Python wrapper for the z/OSMF© REST API
2
- =========================================
1
+ # A Python wrapper for the z/OSMF© REST API
3
2
 
4
- [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) [![builds.sr.ht status](https://builds.sr.ht/~ocurero/zosmfrestapi/commits/main/.build.yml.svg)](https://builds.sr.ht/~ocurero/zosmfrestapi/commits/main/.build.yml?) ![z/OS](https://img.shields.io/badge/works%20on-z/OS-8A2BE2)
3
+ [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
4
+ [![builds.sr.ht status](https://builds.sr.ht/~ocurero/zosmfrestapi/commits/main/.build.yml.svg)](https://builds.sr.ht/~ocurero/zosmfrestapi/commits/main/.build.yml?)
5
+ ![z/OS](https://img.shields.io/badge/works%20on-z/OS-8A2BE2)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
5
8
 
6
9
  * Open Source: MIT License.
7
10
  * Website: <https://sr.ht/~ocurero/zosmfrestapi/>
8
- * Pypi: <https://pypi.org/project/zosmfrestapi/>
11
+ * Repository: <https://git.sr.ht/~ocurero/zosmfrestapi>
12
+ * Changelog: <https://git.sr.ht/~ocurero/zosmfrestapi/tree/main/item/CHANGELOG.md>
13
+ * Contributing: <https://git.sr.ht/~ocurero/zosmfrestapi/tree/main/item/CONTRIBUTING.md>
14
+
15
+ Key features:
16
+ * **Pure Python**: Package and its dependencies are 100% pure Python (no C extensions required).
17
+ * **Cross-platform**: Works on Windows, Linux, macOS, and z/OS UNIX System Services.
18
+ * **Flexible authentication**: Supports user/password, LTPA and JWT tokens, and mutual TLS (mTLS).
19
+ * **Proxy ready**: Full support for standard HTTP/HTTPS proxies as well as authenticated proxies.
9
20
 
10
21
 
11
22
  Install
12
23
  -------
13
24
 
14
25
  **zosmfrestapi** requires Python 3.12 or newer and access to a z/OSMF server.
15
- You can check your Python version with:
16
-
17
- ```console
18
- python --version
19
- ```
20
-
21
- It is a good idea to use a virtual environment so this package does not affect
22
- other Python projects. From a terminal, create and activate one in your project
23
- folder:
24
-
25
- ```console
26
- # Windows (PowerShell)
27
- py -3.12 -m venv .venv
28
- .venv\Scripts\Activate.ps1
29
-
30
- # macOS or Linux
31
- python3 -m venv .venv
32
- source .venv/bin/activate
33
- ```
34
26
 
35
- Then install the package from PyPI:
27
+ Install the package from PyPI:
36
28
 
37
29
  ```console
38
30
  python -m pip install zosmfrestapi
@@ -0,0 +1,103 @@
1
+ [project]
2
+ name = "zosmfrestapi"
3
+ description = "A Python wrapper for the z/OSMF REST API"
4
+ readme = "README.md"
5
+ authors = [
6
+ {name = "Oscar Curero",email = "dev@curero.es"}
7
+ ]
8
+ license = "MIT"
9
+ requires-python = ">=3.12"
10
+ keywords = ["z/OSMF", "IBM Z", "mainframe", "REST API"]
11
+ classifiers = [
12
+ "Operating System :: OS Independent",
13
+ "Programming Language :: Python :: 3",
14
+ "Programming Language :: Python :: 3.12",
15
+ "Topic :: Internet :: WWW/HTTP",
16
+ "Topic :: Software Development :: Libraries :: Python Modules",
17
+ ]
18
+ dependencies = [
19
+ "httpx2 (>=2.12.0,<3.0.0)",
20
+ "pendulum (>=3.2.0,<4.0.0)",
21
+ "dacite (>=1.9.2,<2.0.0)",
22
+ ]
23
+ dynamic = []
24
+ version = "0.2.1"
25
+
26
+ [project.urls]
27
+ Homepage = "https://sr.ht/~ocurero/zosmfrestapi/"
28
+ Repository = "https://git.sr.ht/~ocurero/zosmfrestapi"
29
+ PyPI = "https://pypi.org/project/zosmfrestapi/"
30
+
31
+ [project.optional-dependencies]
32
+ zcrypto = [
33
+ "py_zcrypto",
34
+ ]
35
+
36
+ [dependency-groups]
37
+ dev = [
38
+ "pytest (>=9.1.1,<10.0.0)",
39
+ "black (>=26.5.1,<27.0.0)",
40
+ "pytest-recording (>=0.14.0,<0.15.0)",
41
+ "pytest-httpx2 (>=1.0.0,<2.0.0)",
42
+ "pytest-cov (>=7.1.0,<8.0.0)",
43
+ "flake8 (>=7.5.0,<8.0.0)",
44
+ "flake8-pyproject (>=1.2.4,<2.0.0)",
45
+ "mypy (>=2.4.1,<3.0.0)",
46
+ "poethepoet (>=0.49.0,<0.50.0)",
47
+ "pyright (>=1.1.414,<2.0.0)",
48
+ ]
49
+ zcrypto-dev = [
50
+ "cryptography (>=50.0.2,<51.0.0)"
51
+ ]
52
+
53
+ [tool.black]
54
+ line-length = 96
55
+
56
+ [tool.flake8]
57
+ max-line-length = 96
58
+ extend-ignore = ["E203", "W503"]
59
+ per-file-ignores = "tests/*.py:E501"
60
+
61
+ [tool.pytest.ini_options]
62
+ testpaths = ["tests"]
63
+ addopts = ["-ra",
64
+ "--record-mode=none",
65
+ "--cov-fail-under=100",
66
+ "--cov=zosmfrestapi",
67
+ ]
68
+
69
+
70
+ [tool.poe.tasks]
71
+ format = "black ."
72
+
73
+ lint = [
74
+ { cmd = "black --check ." },
75
+ { cmd = "flake8" },
76
+ { cmd = "mypy zosmfrestapi" },
77
+ { cmd = "pyright --warnings" }
78
+
79
+ ]
80
+
81
+ test = "pytest"
82
+
83
+ check = [
84
+ { cmd = "black --check ." },
85
+ { cmd = "flake8 zosmfrestapi" },
86
+ { cmd = "pyright --warnings" },
87
+ { cmd = "mypy zosmfrestapi" },
88
+ { cmd = "pytest" }
89
+ ]
90
+
91
+ [[tool.mypy.overrides]]
92
+ module = ["OpenSSL.*", "py_zcrypto.*"]
93
+ ignore_missing_imports = true
94
+
95
+ [tool.poetry]
96
+
97
+ [tool.poetry-dynamic-versioning]
98
+ enable = false
99
+
100
+ [build-system]
101
+ requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"]
102
+ build-backend = "poetry_dynamic_versioning.backend"
103
+
@@ -1,8 +1,8 @@
1
1
  """Synchronous Python client for the z/OSMF REST API.
2
2
 
3
- The package root re-exports :class:`ZosmfClient`, response models, and public
4
- exceptions. Create one client per server/configuration and use it as a context
5
- manager to close the shared HTTP session when finished.
3
+ The package root re-exports :class:`ZosmfClient`, :class:`ZosmfZcryptoClient`,
4
+ response models, and public exceptions. Create one client per server/configuration and
5
+ use it as a context manager to close the shared HTTP session when finished.
6
6
  """
7
7
 
8
8
  from zosmfrestapi.client import ZosmfClient
@@ -48,9 +48,11 @@ from zosmfrestapi.models.workflow import (
48
48
  WorkflowItem,
49
49
  WorkflowListItem,
50
50
  )
51
+ from zosmfrestapi.zcrypto_client import ZosmfZcryptoClient
51
52
 
52
53
  __all__ = [
53
54
  "ZosmfClient",
55
+ "ZosmfZcryptoClient",
54
56
  "LoginOk",
55
57
  "ZosmfDatasetNotFoundError",
56
58
  "ZosmfError",
@@ -41,6 +41,7 @@ class ZosmfClient(
41
41
 
42
42
  with ZosmfClient("https://zosmf.example",
43
43
  username="demouser", password="DEMOPASS",
44
- cert=("/path/to/cert", "/path/to/key")) as client:
44
+ cert=("/path/to/cert", "/path/to/key"),
45
+ key_password="secret") as client:
45
46
  systems = client.get_systems()
46
47
  """
File without changes
@@ -1,4 +1,4 @@
1
- from dataclasses import dataclass, field, fields, is_dataclass
1
+ from dataclasses import dataclass, field
2
2
  from typing import Any
3
3
 
4
4
  import pendulum
@@ -1,10 +1,7 @@
1
- from dataclasses import dataclass, field, fields, is_dataclass
2
- from typing import Any
1
+ from dataclasses import dataclass, field
3
2
 
4
3
  import pendulum
5
4
 
6
- from zosmfrestapi.models.software import DataSet
7
-
8
5
 
9
6
  @dataclass
10
7
  class UpdateSelection:
@@ -1,7 +1,4 @@
1
- from dataclasses import dataclass, field, fields, is_dataclass
2
- from typing import Any
3
-
4
- import pendulum
1
+ from dataclasses import dataclass, field
5
2
 
6
3
 
7
4
  @dataclass
@@ -1,8 +1,6 @@
1
- from dataclasses import dataclass, field, fields, is_dataclass
1
+ from dataclasses import dataclass, field
2
2
  from typing import Any
3
3
 
4
- import pendulum
5
-
6
4
 
7
5
  @dataclass
8
6
  class WorkflowAutomationStatus:
File without changes
@@ -1,12 +1,13 @@
1
1
  import logging
2
2
  import ssl
3
+ from importlib.metadata import version
3
4
  from types import TracebackType
4
5
  from typing import Literal, Self
5
6
 
6
7
  import httpx2
7
-
8
8
  from zosmfrestapi.exceptions import ZosmfAuthError, ZosmfError
9
9
 
10
+ __version__ = version("zosmfrestapi")
10
11
  logger = logging.getLogger(__name__)
11
12
 
12
13
 
@@ -25,6 +26,7 @@ class ZosmfBase:
25
26
  username: str | None = None,
26
27
  password: str | None = None,
27
28
  cert: str | tuple[str, str] | None = None,
29
+ key_password: str | None = None,
28
30
  ltpa_token: str | None = None,
29
31
  jwt_token: str | None = None,
30
32
  jwt_cookie_name: str = "jwtToken",
@@ -49,6 +51,8 @@ class ZosmfBase:
49
51
  PEM file containing both the certificate and private key, or
50
52
  a ``(certificate_path, private_key_path)`` tuple for separate
51
53
  files.
54
+ key_password: Optional private key password. Pass the private key
55
+ password if the key is password protected.
52
56
  ltpa_token: Optional LTPA token sent as the ``LtpaToken2`` cookie.
53
57
  jwt_token: Optional JWT sent as the cookie named by
54
58
  ``jwt_cookie_name``. If both token types are provided, both
@@ -69,45 +73,44 @@ class ZosmfBase:
69
73
  ZosmfError: If ``insecure`` is combined with ``cert`` or ``cafile``.
70
74
  """
71
75
  if insecure and (cafile or cert):
72
- raise ZosmfError(
73
- "Cannot set insecure mode when cafile or cert is provided."
74
- )
76
+ raise ZosmfError("Cannot set insecure mode when cafile or cert is provided.")
75
77
 
76
- ctx = ssl.create_default_context()
77
- if isinstance(cert, tuple):
78
- certfile, keyfile = cert
79
- ctx.load_cert_chain(certfile=certfile, keyfile=keyfile)
80
- elif cert:
81
- ctx.load_cert_chain(certfile=cert)
82
- if cafile:
83
- ctx.load_verify_locations(cafile=cafile)
78
+ verify: bool | ssl.SSLContext
84
79
  if insecure:
85
- logger.debug(
86
- "Insecure mode enabled, TLS certificate verification is disabled."
87
- )
88
- ctx = False
80
+ logger.debug("Insecure mode enabled, TLS certificate verification is disabled.")
81
+ verify = False
82
+ else:
83
+ ctx = ssl.create_default_context()
84
+ if isinstance(cert, tuple):
85
+ certfile, keyfile = cert
86
+ ctx.load_cert_chain(certfile=certfile, keyfile=keyfile, password=key_password)
87
+ elif cert:
88
+ ctx.load_cert_chain(certfile=cert)
89
+ if cafile:
90
+ ctx.load_verify_locations(cafile=cafile)
91
+ verify = ctx
92
+
89
93
  proxy_config: str | httpx2.Proxy | None = proxy
90
94
  if proxy:
91
95
  proxy_config = httpx2.Proxy(proxy)
92
96
  proxy_config.auth = (
93
- (proxyusername, proxypassword)
94
- if proxyusername or proxypassword
95
- else None
97
+ (proxyusername, proxypassword) if proxyusername or proxypassword else None
96
98
  )
97
99
  auth = (username, password) if username and password else None
98
- headers = {}
100
+ headers = {
101
+ "X-CSRF-ZOSMF-HEADER": "zosmfrestapi",
102
+ "User-Agent": f"zosmfrestapi/{__version__}",
103
+ }
99
104
  if ltpa_token:
100
- headers = {"Cookie": f"LtpaToken2={ltpa_token}"}
105
+ headers["Cookie"] = f"LtpaToken2={ltpa_token}"
101
106
  if jwt_token:
102
- headers = {"Cookie": f"{jwt_cookie_name}={jwt_token}"}
107
+ headers["Cookie"] = f"{jwt_cookie_name}={jwt_token}"
103
108
  if ltpa_token and jwt_token:
104
- headers = {
105
- "Cookie": f"LtpaToken2={ltpa_token}; {jwt_cookie_name}={jwt_token}"
106
- }
109
+ headers["Cookie"] = f"LtpaToken2={ltpa_token}; {jwt_cookie_name}={jwt_token}"
107
110
  self.http = httpx2.Client(
108
111
  base_url=server,
109
112
  proxy=proxy_config,
110
- verify=ctx,
113
+ verify=verify,
111
114
  auth=auth,
112
115
  headers=headers,
113
116
  )
@@ -26,18 +26,16 @@ class AuthenticationServices(ZosmfBase):
26
26
  token cookies.
27
27
 
28
28
  Returns:
29
- A ``LoginOk`` with the response return/reason codes and message,
30
- plus any LTPA or JWT tokens returned as response cookies, when the
31
- endpoint responds with HTTP 200. A successful non-200 response
32
- returns ``None``.
29
+ A ``LoginOk`` containing the response return/reason codes and
30
+ message, plus any LTPA or JWT tokens returned as response cookies.
33
31
 
34
32
  Raises:
35
33
  ZosmfLoginError: If z/OSMF responds with HTTP 401.
36
34
  ZosmfAuthError: If another unsuccessful HTTP status is returned.
37
35
  httpx2.RequestError: If the request fails before an HTTP response
38
- is received.
36
+ is received.
39
37
  """
40
- logger.debug(f"Authenticating with z/OSMF using all available methods")
38
+ logger.debug("Authenticating with z/OSMF using all available methods")
41
39
  resp = self.http.post("/zosmf/services/authenticate")
42
40
  if resp.status_code == 200:
43
41
  logger.debug("Authentication succeeded with z/OSMF")
@@ -47,7 +45,8 @@ class AuthenticationServices(ZosmfBase):
47
45
  jwt_token=resp.cookies.get(self.jwt_cookie_name, self.jwt_token),
48
46
  )
49
47
  elif resp.status_code == 401:
50
- logger.debug(f"Authentication failed with z/OSMF")
48
+ logger.debug("Authentication failed with z/OSMF")
51
49
  raise ZosmfLoginError(resp)
52
- logger.debug(f"Unexpected authentication failure with z/OSMF")
50
+ logger.debug("Unexpected authentication failure with z/OSMF")
53
51
  self._raise_for_status(resp, exc_handler=ZosmfAuthError)
52
+ raise AssertionError("Unreachable") # pragma: no cover
@@ -125,9 +125,7 @@ class SoftwareServices(ZosmfBase):
125
125
 
126
126
  def _get_swi_datasets(self, path: str) -> dict[
127
127
  str,
128
- list[SmpeManagedDataset]
129
- | list[SmpeManagedUnixDataset]
130
- | list[NonSmpeManagedDataset],
128
+ list[SmpeManagedDataset] | list[SmpeManagedUnixDataset] | list[NonSmpeManagedDataset],
131
129
  ]:
132
130
  resp = self.http.post(path)
133
131
  if resp.status_code == 404:
@@ -156,9 +154,7 @@ class SoftwareServices(ZosmfBase):
156
154
 
157
155
  def get_swi_datasets_by_uuid(self, swiuuid: str) -> dict[
158
156
  str,
159
- list[SmpeManagedDataset]
160
- | list[SmpeManagedUnixDataset]
161
- | list[NonSmpeManagedDataset],
157
+ list[SmpeManagedDataset] | list[SmpeManagedUnixDataset] | list[NonSmpeManagedDataset],
162
158
  ]:
163
159
  """Retrieve dataset inventories for a software instance by UUID.
164
160
 
@@ -185,9 +181,7 @@ class SoftwareServices(ZosmfBase):
185
181
 
186
182
  def get_swi_datasets_by_name(self, name: str, system: str) -> dict[
187
183
  str,
188
- list[SmpeManagedDataset]
189
- | list[SmpeManagedUnixDataset]
190
- | list[NonSmpeManagedDataset],
184
+ list[SmpeManagedDataset] | list[SmpeManagedUnixDataset] | list[NonSmpeManagedDataset],
191
185
  ]:
192
186
  """Retrieve dataset inventories for a software instance by name.
193
187
 
@@ -264,9 +258,7 @@ class SoftwareServices(ZosmfBase):
264
258
  else []
265
259
  ),
266
260
  "workflows": (
267
- [asdict(workflow) for workflow in swi.workflows]
268
- if swi.workflows
269
- else []
261
+ [asdict(workflow) for workflow in swi.workflows] if swi.workflows else []
270
262
  ),
271
263
  },
272
264
  )
@@ -333,9 +325,7 @@ class SoftwareServices(ZosmfBase):
333
325
  wait: bool,
334
326
  ) -> list[CsiEntry] | dict[str, Any]:
335
327
  if "*" in entries and len(entries) > 1:
336
- raise ZosmfSoftwareManagementError(
337
- "'*' cannot be combined with other entry types."
338
- )
328
+ raise ZosmfSoftwareManagementError("'*' cannot be combined with other entry types.")
339
329
  elif "*" in subentries and len(subentries) > 1:
340
330
  raise ZosmfSoftwareManagementError(
341
331
  "'*' cannot be combined with other subentry types."
@@ -484,6 +474,4 @@ class SoftwareServices(ZosmfBase):
484
474
  while status["status"] == "running":
485
475
  time.sleep(2)
486
476
  status = self._get_query_csi_status(statusurl)
487
- return [
488
- from_dict(data_class=CsiEntry, data=entry) for entry in status["entries"]
489
- ]
477
+ return [from_dict(data_class=CsiEntry, data=entry) for entry in status["entries"]]
@@ -47,9 +47,7 @@ class SoftwareUpdatesServices(ZosmfBase):
47
47
  for upd in resp.json()["update-processes"]
48
48
  ]
49
49
 
50
- def list_sw_updates_by_uuid(
51
- self, swiuuid: str, last: bool = False
52
- ) -> list[UpdateProcess]:
50
+ def list_sw_updates_by_uuid(self, swiuuid: str, last: bool = False) -> list[UpdateProcess]:
53
51
  """List update processes for a software instance identified by UUID.
54
52
 
55
53
  If z/OSMF reports that the software instance has no update-process
@@ -102,9 +100,7 @@ class SoftwareUpdatesServices(ZosmfBase):
102
100
  f"/zosmf/swmgmt/swi/{system}/{name}/swupdate{'' if last else '/all'}"
103
101
  )
104
102
 
105
- def get_sw_updates(
106
- self, process_id: int, wait: bool = False
107
- ) -> list[UpdateProcess]:
103
+ def get_sw_updates(self, process_id: int, wait: bool = False) -> list[UpdateProcess]:
108
104
  """Get the update-process records for a process ID.
109
105
 
110
106
  Args:
@@ -158,9 +154,7 @@ class SoftwareUpdatesServices(ZosmfBase):
158
154
  while status.json()["status"] == "running":
159
155
  time.sleep(2)
160
156
  status = self.http.get(status_monitor_url)
161
- self._raise_for_status(
162
- status, exc_handler=ZosmfSoftwareManagementRequestError
163
- )
157
+ self._raise_for_status(status, exc_handler=ZosmfSoftwareManagementRequestError)
164
158
  if updates:
165
159
  return {
166
160
  "lastholdrecvdate": pendulum.parse(status.json()["lastholdrecvdate"]),
@@ -396,9 +390,7 @@ class SoftwareUpdatesServices(ZosmfBase):
396
390
  while status.json()["status"] == "running":
397
391
  time.sleep(2)
398
392
  status = self.http.get(status_monitor_url)
399
- self._raise_for_status(
400
- status, exc_handler=ZosmfSoftwareManagementRequestError
401
- )
393
+ self._raise_for_status(status, exc_handler=ZosmfSoftwareManagementRequestError)
402
394
  return [
403
395
  from_dict(
404
396
  data_class=SoftwareUpdate,
@@ -658,9 +650,7 @@ class SoftwareUpdatesServices(ZosmfBase):
658
650
  httpx2.RequestError: If the request fails before an HTTP response
659
651
  is received.
660
652
  """
661
- return self._cancel_sw_update(
662
- f"/zosmf/swmgmt/swi/{system}/{name}/swupdate/cancel"
663
- )
653
+ return self._cancel_sw_update(f"/zosmf/swmgmt/swi/{system}/{name}/swupdate/cancel")
664
654
 
665
655
  def _resume_sw_update(
666
656
  self,
@@ -882,16 +872,12 @@ class SoftwareUpdatesServices(ZosmfBase):
882
872
  for process in resp.json()["update-processes"]
883
873
  ]
884
874
 
885
- def _copy_output_sw_update(
886
- self, path: str, output_dir: str
887
- ) -> list[dict[str, Any]]:
875
+ def _copy_output_sw_update(self, path: str, output_dir: str) -> list[dict[str, Any]]:
888
876
  resp = self.http.put(path, params={"dir": output_dir})
889
877
  self._raise_for_status(resp, exc_handler=ZosmfSoftwareManagementError)
890
878
  return resp.json()["files"]
891
879
 
892
- def copy_output_sw_update_by_uuid(
893
- self, uuid: str, output_dir: str
894
- ) -> list[dict[str, Any]]:
880
+ def copy_output_sw_update_by_uuid(self, uuid: str, output_dir: str) -> list[dict[str, Any]]:
895
881
  """Copy output files for a software instance identified by UUID.
896
882
 
897
883
  Args:
@@ -26,9 +26,7 @@ class WorkflowServices(ZosmfBase):
26
26
  an iterator so callers can observe each status update while polling.
27
27
  """
28
28
 
29
- def _get_workflow(
30
- self, workflow_id: str, steps: bool, variables: bool
31
- ) -> dict[str, Any]:
29
+ def _get_workflow(self, workflow_id: str, steps: bool, variables: bool) -> dict[str, Any]:
32
30
  """Fetch the raw workflow response, optionally including steps/variables.
33
31
 
34
32
  This internal helper returns the JSON object before model conversion.
@@ -187,9 +185,7 @@ class WorkflowServices(ZosmfBase):
187
185
  httpx2.RequestError: If either request fails before an HTTP response
188
186
  is received.
189
187
  """
190
- resp = self.http.post(
191
- "/zosmf/workflow/rest/1.0/workflows", json=to_dict(workflow)
192
- )
188
+ resp = self.http.post("/zosmf/workflow/rest/1.0/workflows", json=to_dict(workflow))
193
189
  self._raise_for_status(resp, exc_handler=ZosmfWorkflowError)
194
190
  return self.get_workflow(resp.json()["workflowKey"])
195
191
 
@@ -0,0 +1,11 @@
1
+ # flake8: noqa
2
+
3
+ from zosmfrestapi.testing.authentication import *
4
+ from zosmfrestapi.testing.software import *
5
+ from zosmfrestapi.testing.software_updates import *
6
+ from zosmfrestapi.testing.topology import *
7
+ from zosmfrestapi.testing.workflows import *
8
+
9
+ __all__ = [
10
+ name for name in globals() if name.startswith("make_")
11
+ ] # pyright: ignore[reportUnsupportedDunderAll]