fluidattacks_batch_client 0.2.1__tar.gz → 1.0.0__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 (34) hide show
  1. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/PKG-INFO +1 -1
  2. fluidattacks_batch_client-1.0.0/build/default.nix +27 -0
  3. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/flake.lock +4 -4
  4. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/flake.nix +1 -1
  5. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/__init__.py +5 -4
  6. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/_cli.py +52 -40
  7. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/_logger.py +3 -2
  8. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/_utils.py +22 -27
  9. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/api/_client_1/__init__.py +15 -15
  10. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/api/_client_1/_get_command.py +21 -25
  11. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/api/_client_1/_list_jobs.py +23 -24
  12. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/api/_client_1/_send_job.py +40 -39
  13. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/api/_core.py +13 -14
  14. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/core.py +33 -38
  15. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/decode.py +42 -42
  16. fluidattacks_batch_client-1.0.0/fluidattacks_batch_client/request.py +39 -0
  17. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/sender/__init__.py +2 -1
  18. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/sender/_core.py +10 -7
  19. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/sender/_send.py +28 -27
  20. fluidattacks_batch_client-1.0.0/ruff.toml +55 -0
  21. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/tests/arch/arch.py +11 -17
  22. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/tests/arch/test_arch.py +5 -4
  23. fluidattacks_batch_client-0.2.1/CLAUDE.md +0 -78
  24. fluidattacks_batch_client-0.2.1/build/default.nix +0 -13
  25. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/.envrc +0 -0
  26. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/build/filter.nix +0 -0
  27. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/api/__init__.py +0 -0
  28. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/fluidattacks_batch_client/py.typed +0 -0
  29. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/mypy.ini +0 -0
  30. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/pyproject.toml +0 -0
  31. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/tests/__init__.py +0 -0
  32. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/tests/arch/__init__.py +0 -0
  33. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/tests/py.typed +0 -0
  34. {fluidattacks_batch_client-0.2.1 → fluidattacks_batch_client-1.0.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fluidattacks_batch_client
3
- Version: 0.2.1
3
+ Version: 1.0.0
4
4
  Summary: AWS batch python client
5
5
  Author-email: Engineering Team <development@fluidattacks.com>
6
6
  Requires-Python: >=3.11
@@ -0,0 +1,27 @@
1
+ {
2
+ nixpkgs,
3
+ builders,
4
+ scripts,
5
+ src,
6
+ }:
7
+ let
8
+ build_bin =
9
+ bundle:
10
+ nixpkgs.writeShellApplication {
11
+ name = "batch-client";
12
+ runtimeInputs = [
13
+ bundle.env.runtime
14
+ nixpkgs.sops
15
+ ];
16
+ text = ''
17
+ batch-client "''${@}"
18
+ '';
19
+ };
20
+ in
21
+ {
22
+ inherit src;
23
+ root_path = "observes/common/batch-client";
24
+ module_name = "fluidattacks_batch_client";
25
+ pypi_token_var = "BATCH_CLIENT_TOKEN";
26
+ override = bundle: bundle // { bin = build_bin bundle; };
27
+ }
@@ -138,17 +138,17 @@
138
138
  },
139
139
  "locked": {
140
140
  "dir": "observes/common/std_flake_2",
141
- "lastModified": 1768584843,
142
- "narHash": "sha256-V0sEDoOEkxvnG6po+3Ve6OAqFA9H9SuvchW8ohY22Xo=",
141
+ "lastModified": 1773763194,
142
+ "narHash": "sha256-6mO8J5MTvf52xScV92c8Pa8ZR02HHy+ZIWMkvcVsdMo=",
143
143
  "ref": "refs/heads/trunk",
144
- "rev": "3fa54e41d48bd54a59a76f3b0495998663758538",
144
+ "rev": "46ca331f2ad5676a210651331e002ecd7c89ef04",
145
145
  "shallow": true,
146
146
  "type": "git",
147
147
  "url": "ssh://git@gitlab.com/fluidattacks/universe"
148
148
  },
149
149
  "original": {
150
150
  "dir": "observes/common/std_flake_2",
151
- "rev": "3fa54e41d48bd54a59a76f3b0495998663758538",
151
+ "rev": "46ca331f2ad5676a210651331e002ecd7c89ef04",
152
152
  "shallow": true,
153
153
  "type": "git",
154
154
  "url": "ssh://git@gitlab.com/fluidattacks/universe"
@@ -3,7 +3,7 @@
3
3
 
4
4
  inputs = {
5
5
  observes_flake_builder = {
6
- url = "git+ssh://git@gitlab.com/fluidattacks/universe?shallow=1&rev=3fa54e41d48bd54a59a76f3b0495998663758538&dir=observes/common/std_flake_2";
6
+ url = "git+ssh://git@gitlab.com/fluidattacks/universe?shallow=1&rev=46ca331f2ad5676a210651331e002ecd7c89ef04&dir=observes/common/std_flake_2";
7
7
  };
8
8
  };
9
9
 
@@ -1,9 +1,10 @@
1
- from ._logger import (
2
- setup_logger,
3
- )
4
1
  from fa_purity import (
5
2
  Unsafe,
6
3
  )
7
4
 
8
- __version__ = "0.2.1"
5
+ from ._logger import (
6
+ setup_logger,
7
+ )
8
+
9
+ __version__ = "1.0.0"
9
10
  Unsafe.compute(setup_logger(__name__))
@@ -1,16 +1,13 @@
1
1
  import dataclasses
2
-
3
- from fluidattacks_batch_client.decode import JobDefDecoder
4
- from fluidattacks_batch_client.sender import new_sender
5
- from .api import (
6
- new_client,
7
- )
8
- from .core import (
9
- AllowDuplicates,
10
- JobPipeline,
11
- JobRequest,
12
- JobName,
2
+ import logging
3
+ from collections.abc import Callable
4
+ from pathlib import Path
5
+ from typing import (
6
+ IO,
7
+ NoReturn,
8
+ TypeVar,
13
9
  )
10
+
14
11
  import click
15
12
  from fa_purity import (
16
13
  Bool,
@@ -30,49 +27,60 @@ from fa_purity.json import (
30
27
  UnfoldedFactory,
31
28
  Unfolder,
32
29
  )
33
- from typing import (
34
- IO,
35
- Callable,
36
- NoReturn,
37
- TypeVar,
38
- )
39
- import logging
30
+
31
+ from fluidattacks_batch_client.decode import JobDefDecoder
32
+ from fluidattacks_batch_client.sender import new_sender
33
+
40
34
  from . import _utils
35
+ from .api import (
36
+ new_client,
37
+ )
38
+ from .core import (
39
+ AllowDuplicates,
40
+ JobName,
41
+ JobPipeline,
42
+ JobRequest,
43
+ )
41
44
 
42
45
  LOG = logging.getLogger(__name__)
43
46
 
44
47
  _T = TypeVar("_T")
45
48
 
46
49
 
47
- def _read_file(file_path: str, transform: Callable[[IO[str]], _T]) -> Cmd[_T]:
50
+ def _read_file(file_path: Path, transform: Callable[[IO[str]], _T]) -> Cmd[_T]:
48
51
  def _action() -> _T:
49
- with open(file_path, "r", encoding="utf-8") as file:
52
+ with file_path.open("r", encoding="utf-8") as file:
50
53
  return transform(file)
51
54
 
52
55
  return Cmd.wrap_impure(_action)
53
56
 
54
57
 
55
- def _decode_json(file_path: str) -> Cmd[ResultE[JsonObj]]:
58
+ def _decode_json(file_path: Path) -> Cmd[ResultE[JsonObj]]:
56
59
  return _read_file(file_path, UnfoldedFactory.load)
57
60
 
58
61
 
59
- def _decode_json_list(file_path: str) -> Cmd[ResultE[FrozenList[JsonObj]]]:
62
+ def _decode_json_list(file_path: Path) -> Cmd[ResultE[FrozenList[JsonObj]]]:
60
63
  return _read_file(
61
64
  file_path,
62
65
  lambda file: JsonValueFactory.load(file).bind(
63
- lambda v: Unfolder.to_list_of(v, Unfolder.to_json)
66
+ lambda v: Unfolder.to_list_of(v, Unfolder.to_json),
64
67
  ),
65
68
  )
66
69
 
67
70
 
68
71
  @click.command()
69
- @click.option("--job", required=True, help="json encoded str defining a JobRequest")
72
+ @click.option(
73
+ "--job",
74
+ required=True,
75
+ type=click.Path(exists=True, dir_okay=False, path_type=Path),
76
+ help="json encoded file defining a JobRequest",
77
+ )
70
78
  @click.option("--allow-duplicates", is_flag=True)
71
79
  @click.option("--args-in-name", is_flag=True)
72
80
  @click.option("--dry-run", is_flag=True)
73
81
  @click.argument("args", nargs=-1) # additional args to append into the job command
74
82
  def submit_job(
75
- job: str,
83
+ job: Path,
76
84
  allow_duplicates: bool,
77
85
  args_in_name: bool,
78
86
  dry_run: bool,
@@ -87,16 +95,17 @@ def submit_job(
87
95
  if dry_run:
88
96
  return Cmd.wrap_impure(
89
97
  lambda: LOG.info(
90
- "[dry-run] the following batch job will be sent: %s", overriden_job
91
- )
98
+ "[dry-run] the following batch job will be sent: %s",
99
+ overriden_job,
100
+ ),
92
101
  )
93
102
  return (
94
103
  new_client()
95
104
  .map(new_sender)
96
105
  .bind(
97
- lambda s: s.send_single_job(
98
- overriden_job, AllowDuplicates(allow_duplicates)
99
- ).map(lambda r: r.alt(Unsafe.raise_exception).to_union())
106
+ lambda s: s.send_single_job(overriden_job, AllowDuplicates(allow_duplicates)).map(
107
+ lambda r: r.alt(Unsafe.raise_exception).to_union(),
108
+ ),
100
109
  )
101
110
  .map(lambda _: None)
102
111
  )
@@ -106,18 +115,21 @@ def submit_job(
106
115
  lambda decoder: _decode_json(job)
107
116
  .map(lambda r: r.bind(decoder.decode_job))
108
117
  .map(lambda r: r.alt(Unsafe.raise_exception).to_union())
109
- .bind(_execute)
118
+ .bind(_execute),
110
119
  )
111
120
  cmd.compute()
112
121
 
113
122
 
114
123
  @click.command()
115
124
  @click.option(
116
- "--pipeline", required=True, help="json encoded str defining a JobRequest"
125
+ "--pipeline",
126
+ required=True,
127
+ type=click.Path(exists=True, dir_okay=False, path_type=Path),
128
+ help="file encoding a list of JobRequest i.e. list of jsons",
117
129
  )
118
130
  @click.option("--dry-run", is_flag=True)
119
131
  def submit_pipeline(
120
- pipeline: str,
132
+ pipeline: Path,
121
133
  dry_run: bool,
122
134
  ) -> NoReturn:
123
135
  def _execute(job_pipeline: JobPipeline) -> Cmd[UnitType]:
@@ -125,7 +137,7 @@ def submit_pipeline(
125
137
  msg = Cmd.wrap_impure(
126
138
  lambda: LOG.info(
127
139
  "[dry-run] A batch pipeline will be sent",
128
- )
140
+ ),
129
141
  )
130
142
 
131
143
  msgs = NewFrozenList(tuple(enumerate(job_pipeline.jobs, start=1))).map(
@@ -134,8 +146,8 @@ def submit_pipeline(
134
146
  "[dry-run] [pipeline-job-#%s] this job will be sent: %s",
135
147
  j[0],
136
148
  j[1],
137
- )
138
- )
149
+ ),
150
+ ),
139
151
  )
140
152
  jobs_msgs = (
141
153
  PureIterFactory.from_list(msgs.items)
@@ -147,9 +159,9 @@ def submit_pipeline(
147
159
  new_client()
148
160
  .map(new_sender)
149
161
  .bind(
150
- lambda s: s.send_pipeline(
151
- PureIterFactory.from_list(job_pipeline.jobs.items)
152
- ).map(lambda r: r.alt(Unsafe.raise_exception).to_union())
162
+ lambda s: s.send_pipeline(PureIterFactory.from_list(job_pipeline.jobs.items)).map(
163
+ lambda r: r.alt(Unsafe.raise_exception).to_union(),
164
+ ),
153
165
  )
154
166
  )
155
167
 
@@ -158,7 +170,7 @@ def submit_pipeline(
158
170
  lambda decoder: _decode_json_list(pipeline)
159
171
  .map(lambda r: r.map(NewFrozenList).bind(decoder.decode_pipeline))
160
172
  .map(lambda r: r.alt(Unsafe.raise_exception).to_union())
161
- .bind(_execute)
173
+ .bind(_execute),
162
174
  )
163
175
  cmd.compute()
164
176
 
@@ -1,8 +1,9 @@
1
+ import logging
2
+ import sys
3
+
1
4
  from fa_purity import (
2
5
  Cmd,
3
6
  )
4
- import logging
5
- import sys
6
7
 
7
8
 
8
9
  def setup_logger(name: str) -> Cmd[None]:
@@ -2,30 +2,32 @@ from __future__ import (
2
2
  annotations,
3
3
  )
4
4
 
5
- from collections.abc import (
6
- Callable,
7
- )
5
+ import os
8
6
  from dataclasses import (
9
7
  dataclass,
10
8
  )
9
+ from typing import (
10
+ TYPE_CHECKING,
11
+ TypeVar,
12
+ )
13
+
11
14
  from fa_purity import (
12
15
  Cmd,
16
+ Coproduct,
17
+ CoproductFactory,
13
18
  FrozenDict,
14
19
  FrozenList,
15
20
  Maybe,
16
21
  PureIter,
17
22
  Result,
18
23
  ResultE,
19
- Coproduct,
20
- CoproductFactory,
21
24
  Unsafe,
22
25
  )
23
- from typing import (
24
- NoReturn,
25
- TypeVar,
26
- )
27
- import os
28
26
 
27
+ if TYPE_CHECKING:
28
+ from collections.abc import (
29
+ Callable,
30
+ )
29
31
  _T = TypeVar("_T")
30
32
 
31
33
 
@@ -34,9 +36,7 @@ class LibraryBug(Exception):
34
36
  traceback: Exception
35
37
 
36
38
  def __str__(self) -> str:
37
- return (
38
- "If raised then there is a bug in the `fluidattacks_batch_client` library"
39
- )
39
+ return "If raised then there is a bug in the `fluidattacks_batch_client` library"
40
40
 
41
41
 
42
42
  def str_to_int(raw: str) -> ResultE[int]:
@@ -50,21 +50,21 @@ def int_to_str(item: int) -> str:
50
50
  return str(item)
51
51
 
52
52
 
53
- def handle_value_error(transform: Callable[[], _T | NoReturn]) -> ResultE[_T]:
53
+ def handle_value_error(transform: Callable[[], _T]) -> ResultE[_T]:
54
54
  try:
55
55
  return Result.success(transform())
56
56
  except ValueError as err:
57
57
  return Result.failure(Exception(err))
58
58
 
59
59
 
60
- def handle_key_error(transform: Callable[[], _T | NoReturn]) -> ResultE[_T]:
60
+ def handle_key_error(transform: Callable[[], _T]) -> ResultE[_T]:
61
61
  try:
62
62
  return Result.success(transform())
63
63
  except KeyError as err:
64
64
  return Result.failure(Exception(err))
65
65
 
66
66
 
67
- def handle_index_error(transform: Callable[[], _T | NoReturn]) -> ResultE[_T]:
67
+ def handle_index_error(transform: Callable[[], _T]) -> ResultE[_T]:
68
68
  try:
69
69
  return Result.success(transform())
70
70
  except IndexError as err:
@@ -72,18 +72,15 @@ def handle_index_error(transform: Callable[[], _T | NoReturn]) -> ResultE[_T]:
72
72
 
73
73
 
74
74
  def get_index(items: FrozenList[_T], index: int) -> Maybe[_T]:
75
- return Maybe.from_result(
76
- handle_index_error(lambda: items[index]).alt(lambda _: None)
77
- )
75
+ return Maybe.from_result(handle_index_error(lambda: items[index]).alt(lambda _: None))
78
76
 
79
77
 
80
78
  def extract_single(items: PureIter[_T]) -> Coproduct[_T, PureIter[_T]]:
81
79
  _factory: CoproductFactory[_T, PureIter[_T]] = CoproductFactory()
82
80
  single_element = (
83
- items.enumerate(1)
84
- .find_first(lambda t: t[0] >= 2)
85
- .map(lambda _: False)
86
- .value_or(True)
81
+ items.enumerate(1).find_first(lambda t: t[0] >= 2).map(lambda _: False).value_or(True) # noqa: PLR2004
82
+ # PLR2004 reason: there is no magic value `2` here
83
+ # the intention is to find the second element of the iterable
87
84
  )
88
85
  if single_element:
89
86
  return _factory.inl(
@@ -92,11 +89,9 @@ def extract_single(items: PureIter[_T]) -> Coproduct[_T, PureIter[_T]]:
92
89
  .to_result()
93
90
  .alt(lambda _: LibraryBug(Exception("no first element")))
94
91
  .alt(Unsafe.raise_exception)
95
- .to_union()[1]
92
+ .to_union()[1],
96
93
  )
97
94
  return _factory.inr(items)
98
95
 
99
96
 
100
- get_environment = Cmd[FrozenDict[str, str]].wrap_impure(
101
- lambda: FrozenDict(dict(os.environ))
102
- )
97
+ get_environment = Cmd[FrozenDict[str, str]].wrap_impure(lambda: FrozenDict(dict(os.environ)))
@@ -1,29 +1,29 @@
1
1
  from __future__ import annotations
2
- from typing import TYPE_CHECKING
3
- from . import (
4
- _list_jobs,
5
- _send_job,
6
- _get_command,
7
- )
8
- from fluidattacks_batch_client.api._core import (
9
- ApiClient,
10
- )
2
+
11
3
  import boto3
12
4
  from fa_purity import (
13
5
  Cmd,
14
6
  )
7
+ from mypy_boto3_batch.client import (
8
+ BatchClient,
9
+ )
15
10
 
16
- if TYPE_CHECKING:
17
- from mypy_boto3_batch.client import (
18
- BatchClient,
19
- )
11
+ from fluidattacks_batch_client.api._core import (
12
+ ApiClient,
13
+ )
14
+
15
+ from . import (
16
+ _get_command,
17
+ _list_jobs,
18
+ _send_job,
19
+ )
20
20
 
21
21
 
22
22
  def _new_batch_client() -> Cmd[BatchClient]:
23
23
  def _action() -> BatchClient:
24
24
  return boto3.client("batch")
25
25
 
26
- return Cmd.wrap_impure(_action)
26
+ return Cmd[BatchClient].wrap_impure(_action)
27
27
 
28
28
 
29
29
  def new_client() -> Cmd[ApiClient]:
@@ -32,5 +32,5 @@ def new_client() -> Cmd[ApiClient]:
32
32
  lambda n, q, s: _list_jobs.list_jobs(client, n, q, s),
33
33
  lambda j: _send_job.send_job(client, j),
34
34
  lambda j: _get_command.get_command(client, j),
35
- )
35
+ ),
36
36
  )
@@ -1,22 +1,23 @@
1
1
  from __future__ import annotations
2
+
2
3
  from typing import TYPE_CHECKING, TypeVar
3
4
 
5
+ from fa_purity import (
6
+ Cmd,
7
+ FrozenList,
8
+ Maybe,
9
+ ResultE,
10
+ cast_exception,
11
+ )
4
12
  from mypy_boto3_batch.type_defs import (
5
13
  ContainerPropertiesOutputTypeDef,
6
14
  JobDefinitionTypeDef,
7
15
  )
16
+
8
17
  from fluidattacks_batch_client.core import (
9
18
  Command,
10
19
  JobDefinitionName,
11
20
  )
12
- from fa_purity import (
13
- Cmd,
14
- FrozenList,
15
- Maybe,
16
- Result,
17
- ResultE,
18
- cast_exception,
19
- )
20
21
 
21
22
  if TYPE_CHECKING:
22
23
  from mypy_boto3_batch.client import (
@@ -27,20 +28,16 @@ _T = TypeVar("_T")
27
28
 
28
29
 
29
30
  def _decode_command(raw: JobDefinitionTypeDef) -> Maybe[Command]:
30
- props: Maybe[ContainerPropertiesOutputTypeDef] = Maybe.from_optional(
31
- raw.get("containerProperties")
32
- )
33
- return props.bind_optional(lambda c: c.get("command")).map(
34
- lambda c: Command(tuple(c))
35
- )
31
+ props = Maybe[ContainerPropertiesOutputTypeDef].from_optional(raw.get("containerProperties"))
32
+ return props.bind_optional(lambda c: c.get("command")).map(lambda c: Command(tuple(c)))
36
33
 
37
34
 
38
35
  def _assert_one(items: FrozenList[_T]) -> ResultE[_T]:
39
36
  if len(items) == 0:
40
- return Result.failure(ValueError("list does not have elements"))
37
+ return ResultE[_T].failure(ValueError("list does not have elements"))
41
38
  if len(items) > 1:
42
- return Result.failure(ValueError("list has more than one element"))
43
- return Result.success(items[0])
39
+ return ResultE[_T].failure(ValueError("list has more than one element"))
40
+ return ResultE[_T].success(items[0])
44
41
 
45
42
 
46
43
  def get_command(
@@ -49,20 +46,19 @@ def get_command(
49
46
  ) -> Cmd[ResultE[Maybe[Command]]]:
50
47
  def _action() -> ResultE[Maybe[Command]]:
51
48
  try:
52
- result = client.describe_job_definitions(
53
- jobDefinitionName=job_def.raw, status="ACTIVE"
54
- )
55
- except Exception as e:
56
- return Result.failure(e)
49
+ result = client.describe_job_definitions(jobDefinitionName=job_def.raw, status="ACTIVE")
50
+ except Exception as e: # noqa: BLE001
51
+ # all errors are intended to be returned
52
+ return ResultE[Maybe[Command]].failure(e)
57
53
  return (
58
54
  _assert_one(tuple(result["jobDefinitions"]))
59
55
  .alt(
60
56
  lambda e: ValueError(
61
- f"Could not determine the current active job definition i.e. {e}"
62
- )
57
+ f"Could not determine the current active job definition i.e. {e}",
58
+ ),
63
59
  )
64
60
  .alt(cast_exception)
65
61
  .map(_decode_command)
66
62
  )
67
63
 
68
- return Cmd.wrap_impure(_action)
64
+ return Cmd[ResultE[Maybe[Command]]].wrap_impure(_action)
@@ -1,33 +1,36 @@
1
1
  from __future__ import annotations
2
- from typing import TYPE_CHECKING
3
- from fluidattacks_batch_client import (
4
- _utils,
5
- )
6
- from fluidattacks_batch_client.core import (
7
- BatchJob,
8
- BatchJobObj,
9
- JobArn,
10
- JobId,
11
- JobName,
12
- JobStatus,
13
- QueueName,
14
- )
2
+
15
3
  from dataclasses import (
16
4
  dataclass,
17
5
  )
6
+ from typing import TYPE_CHECKING
7
+
18
8
  from fa_purity import (
19
9
  Cmd,
20
10
  FrozenList,
21
11
  Maybe,
12
+ PureIterFactory,
22
13
  ResultE,
14
+ ResultTransform,
23
15
  Stream,
24
- PureIterFactory,
25
16
  StreamFactory,
26
17
  StreamTransform,
27
- ResultTransform,
28
18
  Unsafe,
29
19
  )
30
20
 
21
+ from fluidattacks_batch_client import (
22
+ _utils,
23
+ )
24
+ from fluidattacks_batch_client.core import (
25
+ BatchJob,
26
+ BatchJobObj,
27
+ JobArn,
28
+ JobId,
29
+ JobName,
30
+ JobStatus,
31
+ QueueName,
32
+ )
33
+
31
34
  if TYPE_CHECKING:
32
35
  from mypy_boto3_batch.client import (
33
36
  BatchClient,
@@ -48,7 +51,7 @@ def _decode_job(raw: JobSummaryTypeDef) -> ResultE[BatchJob]:
48
51
  Maybe.from_optional(raw.get("statusReason")),
49
52
  Maybe.from_optional(raw.get("startedAt")),
50
53
  Maybe.from_optional(raw.get("stoppedAt")),
51
- )
54
+ ),
52
55
  )
53
56
 
54
57
  return _utils.handle_key_error(_inner).bind(lambda x: x)
@@ -62,7 +65,7 @@ def _decode_job_obj(
62
65
  _id = JobId(raw["jobId"])
63
66
  _name = JobName.new(raw["jobName"])
64
67
  return _name.bind(
65
- lambda name: _decode_job(raw).map(lambda j: BatchJobObj(_id, _arn, name, j))
68
+ lambda name: _decode_job(raw).map(lambda j: BatchJobObj(_id, _arn, name, j)),
66
69
  )
67
70
 
68
71
  return _utils.handle_key_error(_inner).bind(lambda x: x)
@@ -76,9 +79,7 @@ class JobsPage:
76
79
 
77
80
  def _decode_respose(response: ListJobsResponseTypeDef) -> ResultE[JobsPage]:
78
81
  def _inner() -> ResultE[JobsPage]:
79
- items = PureIterFactory.from_list(response["jobSummaryList"]).map(
80
- _decode_job_obj
81
- )
82
+ items = PureIterFactory.from_list(response["jobSummaryList"]).map(_decode_job_obj)
82
83
  _next = Maybe.from_optional(response.get("nextToken"))
83
84
  return ResultTransform.all_ok(items.to_list()).map(lambda i: JobsPage(i, _next))
84
85
 
@@ -92,11 +93,9 @@ def _list_jobs_page(
92
93
  _next: Maybe[str],
93
94
  ) -> Cmd[JobsPage]:
94
95
  def _action() -> JobsPage:
95
- _filter: FrozenList[KeyValuesPairTypeDef] = (
96
- {"name": "JOB_NAME", "values": [name.raw]},
97
- )
96
+ _filter: FrozenList[KeyValuesPairTypeDef] = ({"name": "JOB_NAME", "values": [name.raw]},)
98
97
  result = _next.map(
99
- lambda n: client.list_jobs(jobQueue=queue.raw, filters=_filter, nextToken=n)
98
+ lambda n: client.list_jobs(jobQueue=queue.raw, filters=_filter, nextToken=n),
100
99
  ).or_else_call(lambda: client.list_jobs(jobQueue=queue.raw, filters=_filter))
101
100
  return _decode_respose(result).alt(Unsafe.raise_exception).to_union()
102
101