peak-sdk 1.13.0__py3-none-any.whl → 1.14.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- peak/_version.py +1 -1
- peak/cli/resources/alerts/emails.py +8 -4
- peak/cli/resources/artifacts.py +6 -0
- peak/handler.py +56 -16
- peak/resources/alerts.py +10 -2
- peak/resources/artifacts.py +39 -3
- peak/sample_yaml/resources/artifacts/create_artifact.yaml +3 -0
- peak/sample_yaml/resources/artifacts/create_artifact_version.yaml +2 -0
- peak/sample_yaml/resources/emails/send_email.yaml +3 -0
- peak/session.py +4 -1
- peak/telemetry.py +4 -1
- {peak_sdk-1.13.0.dist-info → peak_sdk-1.14.0.dist-info}/METADATA +3 -3
- {peak_sdk-1.13.0.dist-info → peak_sdk-1.14.0.dist-info}/RECORD +16 -16
- {peak_sdk-1.13.0.dist-info → peak_sdk-1.14.0.dist-info}/LICENSE +0 -0
- {peak_sdk-1.13.0.dist-info → peak_sdk-1.14.0.dist-info}/WHEEL +0 -0
- {peak_sdk-1.13.0.dist-info → peak_sdk-1.14.0.dist-info}/entry_points.txt +0 -0
peak/_version.py
CHANGED
@@ -55,6 +55,7 @@ _BCC = typer.Option(None, help="The email addresses of the recipients to be BCC'
|
|
55
55
|
_LIST_TEMPLATE_NAME = typer.Option(None, help="Email Template Name to search for.")
|
56
56
|
_LIST_TEMPLATE_SCOPE = typer.Option(None, help="List of type of template to filter the templates by.")
|
57
57
|
_DESCRIBE_TEMPLATE_NAME = typer.Argument(None, help="The name of the email template.")
|
58
|
+
_ATTACHMENTS = typer.Option(None, help="The path of files to be sent as the mail attachments.")
|
58
59
|
|
59
60
|
|
60
61
|
@app.command("list", short_help="List all emails.")
|
@@ -132,6 +133,7 @@ def send_email(
|
|
132
133
|
subject: Optional[str] = _SUBJECT,
|
133
134
|
template_name: Optional[str] = _TEMPLATE_NAME,
|
134
135
|
template_parameters: Optional[str] = _TEMPLATE_PARAMETERS,
|
136
|
+
attachments: Optional[List[str]] = _ATTACHMENTS,
|
135
137
|
paging: Optional[bool] = PAGING, # noqa: ARG001
|
136
138
|
output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
|
137
139
|
) -> None:
|
@@ -147,9 +149,10 @@ def send_email(
|
|
147
149
|
subject (str | required: true): The subject of the email.
|
148
150
|
templateName (str | required: true): The name of the email template.
|
149
151
|
templateParameters (map | required: false): The parameters for the email template.
|
152
|
+
attachments (list(str) | required: false): The path of files to be sent as email attachments. A maximum of 3 files can be included, with each file not exceeding 10 MB. Supported file formats are: .pdf, .docx, .doc, .csv, .txt, .xlsx, .xls, and .zip.
|
150
153
|
```
|
151
154
|
|
152
|
-
|
155
|
+
\b
|
153
156
|
📝 ***Example usage:***
|
154
157
|
```bash
|
155
158
|
peak alerts emails send '/path/to/email.yaml' --params-file '/path/to/values.yaml'
|
@@ -160,7 +163,7 @@ def send_email(
|
|
160
163
|
\b
|
161
164
|
📝 ***Example usage without yaml:***
|
162
165
|
```bash
|
163
|
-
peak alerts emails send --recipients <recipient_email_1> --recipients <recipient_email_2> --subject <email_subject> --template-name <template_name> --template-parameters '{"key": "value"}'
|
166
|
+
peak alerts emails send --recipients <recipient_email_1> --recipients <recipient_email_2> --subject <email_subject> --template-name <template_name> --template-parameters '{"key": "value"}' --attachments model.txt --attachments outputs
|
164
167
|
```
|
165
168
|
|
166
169
|
\b
|
@@ -191,6 +194,7 @@ def send_email(
|
|
191
194
|
body = helpers.remove_unknown_args(body, alert_client.send_email)
|
192
195
|
|
193
196
|
updated_body = combine_dictionaries(body.get("body") or {}, user_options)
|
197
|
+
final_attachments = body.get("attachments", attachments)
|
194
198
|
|
195
199
|
if recipients:
|
196
200
|
updated_body["recipients"] = parse_list_of_strings(recipients)
|
@@ -209,7 +213,7 @@ def send_email(
|
|
209
213
|
)
|
210
214
|
|
211
215
|
with writer.pager():
|
212
|
-
response: Dict[str, Any] = alert_client.send_email(body=updated_body)
|
216
|
+
response: Dict[str, Any] = alert_client.send_email(body=updated_body, attachments=final_attachments)
|
213
217
|
writer.write(response)
|
214
218
|
|
215
219
|
|
@@ -250,7 +254,7 @@ def describe(
|
|
250
254
|
}
|
251
255
|
],
|
252
256
|
"subject": "Hello, world!",
|
253
|
-
"templateName": "template_name"
|
257
|
+
"templateName": "template_name"
|
254
258
|
}
|
255
259
|
```
|
256
260
|
|
peak/cli/resources/artifacts.py
CHANGED
@@ -19,6 +19,7 @@
|
|
19
19
|
# # along with this program. If not, see <https://apache.org/licenses/LICENSE-2.0>
|
20
20
|
#
|
21
21
|
"""Peak Artifacts service commands."""
|
22
|
+
|
22
23
|
from typing import Any, Dict, List, Optional
|
23
24
|
|
24
25
|
import typer
|
@@ -179,6 +180,9 @@ def create(
|
|
179
180
|
```yaml
|
180
181
|
name (str): Name of the artifact.
|
181
182
|
description (str): Description of the artifact.
|
183
|
+
source (str | required: false): Source of the artifact.
|
184
|
+
scan (bool | required: false): Whether to scan the artifact for vulnerabilities.
|
185
|
+
validate (bool | required: false): Whether to validate the artifact. Source needs to be provided for the validation to work.
|
182
186
|
artifact (map):
|
183
187
|
path (str): Path to the artifact.
|
184
188
|
ignore_files (list(str) | required: false): Ignore files to use when creating artifact.
|
@@ -305,6 +309,8 @@ def create_version(
|
|
305
309
|
\b
|
306
310
|
🧩 ***Input file schema(yaml):***<br/>
|
307
311
|
```yaml
|
312
|
+
scan (bool | required: false): Whether to scan the artifact for vulnerabilities.
|
313
|
+
validate (bool | required: false): Whether to validate the artifact. Source needs to be present in the artifact for the validation to work.
|
308
314
|
artifact (map):
|
309
315
|
path (str): Path to the artifact.
|
310
316
|
ignore_files (list(str) | required: false): Ignore files to use when creating artifact.
|
peak/handler.py
CHANGED
@@ -24,7 +24,11 @@ from __future__ import annotations
|
|
24
24
|
|
25
25
|
import contextlib
|
26
26
|
import json
|
27
|
+
import mimetypes
|
27
28
|
from abc import ABC, ABCMeta, abstractmethod
|
29
|
+
from io import BufferedReader
|
30
|
+
from pathlib import Path
|
31
|
+
from tempfile import SpooledTemporaryFile
|
28
32
|
from typing import Any, Callable, ClassVar, Dict, Iterator, List, Optional, Tuple, Type, TypeVar, Union
|
29
33
|
|
30
34
|
import requests
|
@@ -118,9 +122,10 @@ class HandlerUtils(AuthRetrySession):
|
|
118
122
|
@contextlib.contextmanager
|
119
123
|
def make_artifact(
|
120
124
|
self,
|
121
|
-
path: Optional[str],
|
125
|
+
path: Optional[str | list[str]],
|
122
126
|
body: Dict[str, Any],
|
123
127
|
ignore_files: Optional[list[str]],
|
128
|
+
file_key: Optional[str] = "artifact",
|
124
129
|
) -> Iterator[MultipartEncoderMonitor]:
|
125
130
|
"""Create a multipart/form-data encoded file with given body and path as file.
|
126
131
|
|
@@ -128,23 +133,46 @@ class HandlerUtils(AuthRetrySession):
|
|
128
133
|
path (Optional[str]): path to the file or folder that will be compressed and used as artifact
|
129
134
|
ignore_files(Optional[list[str]]): Ignore files to be used when creating artifact
|
130
135
|
body (Dict[str, Any]): body content to be sent with artifact
|
136
|
+
file_key (Optional[str]): the field in which the files must be uploaded
|
131
137
|
|
132
138
|
Yields:
|
133
139
|
MultipartEncoderMonitor: MultipartEncoderMonitor generator object
|
134
140
|
"""
|
135
141
|
if path:
|
136
|
-
with
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
+
with contextlib.ExitStack() as stack:
|
143
|
+
files: list[tuple[str, SpooledTemporaryFile[bytes] | BufferedReader, str | None]] = []
|
144
|
+
if isinstance(path, list):
|
145
|
+
for p in path:
|
146
|
+
file_path = Path(p)
|
147
|
+
if file_path.is_dir():
|
148
|
+
context = compress(p)
|
149
|
+
compressed_file = stack.enter_context(context)
|
150
|
+
file_name = f"{file_path.name}.zip"
|
151
|
+
files.append((file_name, compressed_file, "application/zip"))
|
152
|
+
else:
|
153
|
+
fh = open(p, "rb") # noqa: SIM115, PTH123
|
154
|
+
stack.push(fh)
|
155
|
+
file_name = file_path.name
|
156
|
+
files.append((file_name, fh, mimetypes.guess_type(file_name)[0]))
|
157
|
+
else:
|
158
|
+
context = compress(path, ignore_files)
|
159
|
+
file = stack.enter_context(context)
|
160
|
+
check_file_size(file)
|
161
|
+
files.append(
|
162
|
+
(
|
142
163
|
"artifact.zip",
|
143
|
-
|
164
|
+
file,
|
144
165
|
"application/zip",
|
145
166
|
),
|
146
|
-
|
167
|
+
)
|
168
|
+
|
169
|
+
files_object = [(file_key, file) for file in files]
|
170
|
+
body_array = list(body.items())
|
171
|
+
|
172
|
+
encoder = MultipartEncoder(
|
173
|
+
files_object + body_array,
|
147
174
|
)
|
175
|
+
|
148
176
|
callback = self._default_callback(encoder)
|
149
177
|
monitor = MultipartEncoderMonitor(encoder, callback)
|
150
178
|
yield monitor
|
@@ -226,9 +254,10 @@ class BaseHandler(ABC, HandlerUtils, metaclass=_CombinedMeta):
|
|
226
254
|
headers: Dict[str, str],
|
227
255
|
params: Optional[Dict[str, Any]],
|
228
256
|
body: Optional[Dict[str, Any]],
|
229
|
-
path: Optional[str],
|
257
|
+
path: Optional[str | list[str]],
|
230
258
|
ignore_files: Optional[list[str]],
|
231
259
|
request_kwargs: OptionalSerializable,
|
260
|
+
file_key: Optional[str],
|
232
261
|
) -> requests.Response:
|
233
262
|
"""Placeholder handle method."""
|
234
263
|
...
|
@@ -244,11 +273,12 @@ class MultipartFormDataHandler(BaseHandler):
|
|
244
273
|
url: str,
|
245
274
|
method: HttpMethods,
|
246
275
|
*,
|
247
|
-
path: Optional[str],
|
276
|
+
path: Optional[str | list[str]],
|
248
277
|
headers: Dict[str, str],
|
249
278
|
body: Optional[Dict[str, Any]],
|
250
279
|
params: Optional[Dict[str, Any]] = None, # noqa: ARG002
|
251
280
|
ignore_files: Optional[list[str]] = None,
|
281
|
+
file_key: Optional[str] = "artifact",
|
252
282
|
request_kwargs: OptionalSerializable = None,
|
253
283
|
) -> requests.Response:
|
254
284
|
"""Handle multipart/form-data requests.
|
@@ -262,13 +292,14 @@ class MultipartFormDataHandler(BaseHandler):
|
|
262
292
|
path (Optional[str]): path to the file or folder that will be compressed and used as artifact
|
263
293
|
request_kwargs (OptionalSerializable): extra arguments to be passed when making the request, defaults to None
|
264
294
|
ignore_files(Optional[list[str]]): Ignore files to be used when creating artifact
|
295
|
+
file_key (Optional[str]): the field in which the files must be uploaded
|
265
296
|
|
266
297
|
Returns:
|
267
298
|
requests.Response: response of the request
|
268
299
|
"""
|
269
300
|
self._add_retries()
|
270
301
|
|
271
|
-
with self.make_artifact(path, self.parse_args(body or {}), ignore_files) as monitor:
|
302
|
+
with self.make_artifact(path, self.parse_args(body or {}), ignore_files, file_key) as monitor:
|
272
303
|
headers = {**headers, "Content-Type": monitor.content_type}
|
273
304
|
response: Any = getattr(self, method.value)(url, data=monitor, headers=headers, **request_kwargs)
|
274
305
|
return self.handle_response(response)
|
@@ -287,8 +318,9 @@ class ApplicationJsonHandler(BaseHandler):
|
|
287
318
|
headers: Dict[str, str],
|
288
319
|
params: Optional[Dict[str, Any]],
|
289
320
|
body: Optional[Dict[str, Any]],
|
290
|
-
path: Optional[str] = None, # noqa: ARG002
|
321
|
+
path: Optional[str | list[str]] = None, # noqa: ARG002
|
291
322
|
ignore_files: Optional[list[str]] = None, # noqa: ARG002
|
323
|
+
file_key: Optional[str] = "artifact", # noqa: ARG002
|
292
324
|
request_kwargs: OptionalSerializable = None,
|
293
325
|
) -> requests.Response:
|
294
326
|
"""Handle application/json requests.
|
@@ -302,6 +334,7 @@ class ApplicationJsonHandler(BaseHandler):
|
|
302
334
|
path (Optional[str]): path to the file or folder that will be compressed and used as artifact, not used in application/json handler
|
303
335
|
request_kwargs (OptionalSerializable): extra arguments to be passed when making the request, defaults to None
|
304
336
|
ignore_files(Optional[list[str]]): Ignore files to be used when creating artifact
|
337
|
+
file_key (Optional[str]): the field in which the files must be uploaded
|
305
338
|
|
306
339
|
Returns:
|
307
340
|
requests.Response: response of the request.
|
@@ -328,14 +361,18 @@ class Handler:
|
|
328
361
|
def _pretty_print_request(
|
329
362
|
*_: Any,
|
330
363
|
content_type: str,
|
331
|
-
path: Optional[str] = None,
|
364
|
+
path: Optional[str | list[str]] = None,
|
332
365
|
ignore_files: Optional[list[str]] = None,
|
333
366
|
**kwargs: Any,
|
334
367
|
) -> None:
|
335
368
|
writer.write(f"\nSample request: {json.dumps(kwargs, indent=2)}\n")
|
336
369
|
if content_type == ContentType.MULTIPART_FORM_DATA.value and path is not None:
|
337
370
|
writer.write("\nArtifact file tree:")
|
338
|
-
|
371
|
+
if isinstance(path, list):
|
372
|
+
for p in path:
|
373
|
+
print_file_tree(get_files_to_include(p, ignore_files))
|
374
|
+
else:
|
375
|
+
print_file_tree(get_files_to_include(path, ignore_files))
|
339
376
|
|
340
377
|
@telemetry
|
341
378
|
def make_request(
|
@@ -346,9 +383,10 @@ class Handler:
|
|
346
383
|
headers: Optional[Dict[str, str]] = None,
|
347
384
|
params: Optional[Dict[str, Any]] = None,
|
348
385
|
body: Optional[Dict[str, Any]] = None,
|
349
|
-
path: Optional[str] = None,
|
386
|
+
path: Optional[str | list[str]] = None,
|
350
387
|
request_kwargs: Optional[Dict[str, int | bool | str | float]] = None,
|
351
388
|
ignore_files: Optional[list[str]] = None,
|
389
|
+
file_key: Optional[str] = "artifact",
|
352
390
|
) -> requests.Response:
|
353
391
|
"""Redirects the request to the appropriate strategy based on the content type.
|
354
392
|
|
@@ -362,6 +400,7 @@ class Handler:
|
|
362
400
|
path (Optional[str]): path to the file or folder that will be compressed and used as artifact, defaults to None
|
363
401
|
request_kwargs(Dict[str, int | bool | str | float] | None): extra arguments to be passed when making the request.
|
364
402
|
ignore_files(Optional[list[str]]): Ignore files to be used when creating artifact
|
403
|
+
file_key (Optional[str]): the field in which the files must be uploaded
|
365
404
|
|
366
405
|
Returns:
|
367
406
|
requests.Response: response json
|
@@ -395,6 +434,7 @@ class Handler:
|
|
395
434
|
path=path,
|
396
435
|
request_kwargs=request_kwargs,
|
397
436
|
ignore_files=ignore_files,
|
437
|
+
file_key=file_key,
|
398
438
|
)
|
399
439
|
|
400
440
|
|
peak/resources/alerts.py
CHANGED
@@ -23,6 +23,7 @@
|
|
23
23
|
|
24
24
|
from __future__ import annotations
|
25
25
|
|
26
|
+
import json
|
26
27
|
from typing import Any, Dict, Iterator, List, Literal, Optional, overload
|
27
28
|
|
28
29
|
from peak.base_client import BaseClient
|
@@ -126,6 +127,7 @@ class Alert(BaseClient):
|
|
126
127
|
def send_email(
|
127
128
|
self,
|
128
129
|
body: Dict[str, Any],
|
130
|
+
attachments: Optional[list[str]] = None,
|
129
131
|
) -> Dict[str, Any]:
|
130
132
|
"""Send an email to the specified recipients using the specified template.
|
131
133
|
|
@@ -134,6 +136,8 @@ class Alert(BaseClient):
|
|
134
136
|
|
135
137
|
Args:
|
136
138
|
body (Dict[str, Any]): A dictionary containing the details of the email to send.
|
139
|
+
attachments (Optional[list[str]]): A list of file paths to attach to the email.
|
140
|
+
When a directory is provided, a zip is automatically created for the same.
|
137
141
|
|
138
142
|
Returns:
|
139
143
|
Dict[str, Any]: A dictionary containing the ID of the email sent.
|
@@ -161,11 +165,15 @@ class Alert(BaseClient):
|
|
161
165
|
"""
|
162
166
|
method, endpoint = HttpMethods.POST, f"{self.BASE_ENDPOINT}/emails"
|
163
167
|
|
168
|
+
parsed_body = {k: json.dumps(v) if not isinstance(v, str) else v for (k, v) in body.items()}
|
169
|
+
|
164
170
|
return self.session.create_request( # type: ignore[no-any-return]
|
165
171
|
endpoint,
|
166
172
|
method,
|
167
|
-
body=
|
168
|
-
content_type=ContentType.
|
173
|
+
body=parsed_body,
|
174
|
+
content_type=ContentType.MULTIPART_FORM_DATA,
|
175
|
+
path=attachments,
|
176
|
+
file_key="attachments",
|
169
177
|
)
|
170
178
|
|
171
179
|
def describe_email(self, email_id: int) -> Dict[str, Any]:
|
peak/resources/artifacts.py
CHANGED
@@ -19,12 +19,14 @@
|
|
19
19
|
# # along with this program. If not, see <https://apache.org/licenses/LICENSE-2.0>
|
20
20
|
#
|
21
21
|
"""Artifact client module."""
|
22
|
+
|
22
23
|
from __future__ import annotations
|
23
24
|
|
24
25
|
from typing import Any, Dict, Iterator, List, Literal, Optional, overload
|
25
26
|
|
26
27
|
from peak.base_client import BaseClient
|
27
28
|
from peak.constants import ArtifactInfo, ContentType, HttpMethods
|
29
|
+
from peak.helpers import parse_body_for_multipart_request
|
28
30
|
from peak.session import Session
|
29
31
|
|
30
32
|
|
@@ -104,6 +106,9 @@ class Artifact(BaseClient):
|
|
104
106
|
name: str,
|
105
107
|
artifact: ArtifactInfo,
|
106
108
|
description: Optional[str] = None,
|
109
|
+
source: Optional[str] = None,
|
110
|
+
scan: Optional[bool] = None,
|
111
|
+
validate: Optional[bool] = None,
|
107
112
|
) -> Dict[str, Any]:
|
108
113
|
"""Create a new artifact.
|
109
114
|
|
@@ -115,6 +120,9 @@ class Artifact(BaseClient):
|
|
115
120
|
artifact (ArtifactInfo): Mapping of artifact attributes that specifies how the artifact will be generated,
|
116
121
|
it accepts two keys `path`, which is required and `ignore_files` which is optional, and defaults to `.dockerignore`, it is strongly advised that users use `ignore_files` when generating artifacts to avoid copying any extra files in artifact.
|
117
122
|
description (str | None): A brief description of the artifact.
|
123
|
+
source (str | None): The source of the artifact.
|
124
|
+
scan (bool | None): Whether to scan the artifact for vulnerabilities.
|
125
|
+
validate (bool | None): Whether to validate the artifact. Source needs to be provided for the validation to work.
|
118
126
|
|
119
127
|
Returns:
|
120
128
|
Dict[str, Any]: `Id` and `Version` of the created artifact.
|
@@ -127,13 +135,27 @@ class Artifact(BaseClient):
|
|
127
135
|
InternalServerErrorException: The server failed to process the request.
|
128
136
|
"""
|
129
137
|
method, endpoint = HttpMethods.POST, f"{self.BASE_ENDPOINT}/artifacts/"
|
130
|
-
body: Dict[str, Any] = {
|
138
|
+
body: Dict[str, Any] = {
|
139
|
+
"name": name,
|
140
|
+
"description": description,
|
141
|
+
}
|
142
|
+
|
143
|
+
if source is not None:
|
144
|
+
body["source"] = source
|
145
|
+
|
146
|
+
if scan is not None:
|
147
|
+
body["scan"] = scan
|
148
|
+
|
149
|
+
if validate is not None:
|
150
|
+
body["validate"] = validate
|
151
|
+
|
152
|
+
updated_body = parse_body_for_multipart_request(body)
|
131
153
|
|
132
154
|
return self.session.create_request( # type: ignore[no-any-return]
|
133
155
|
endpoint,
|
134
156
|
method,
|
135
157
|
content_type=ContentType.MULTIPART_FORM_DATA,
|
136
|
-
body=
|
158
|
+
body=updated_body,
|
137
159
|
path=artifact["path"],
|
138
160
|
ignore_files=artifact.get("ignore_files"),
|
139
161
|
)
|
@@ -205,6 +227,8 @@ class Artifact(BaseClient):
|
|
205
227
|
self,
|
206
228
|
artifact_id: str,
|
207
229
|
artifact: ArtifactInfo,
|
230
|
+
scan: Optional[bool] = None,
|
231
|
+
validate: Optional[bool] = None,
|
208
232
|
) -> Dict[str, int]:
|
209
233
|
"""Create a new version of the artifact.
|
210
234
|
|
@@ -215,6 +239,8 @@ class Artifact(BaseClient):
|
|
215
239
|
artifact_id (str): ID of the artifact for which a new version is to be created.
|
216
240
|
artifact (ArtifactInfo): Mapping of artifact attributes that specifies how the artifact will be generated,
|
217
241
|
it accepts two keys `path`, which is required and `ignore_files` which is optional, and defaults to `.dockerignore`, it is strongly advised that users use `ignore_files` when generating artifacts to avoid copying any extra files in artifact.
|
242
|
+
scan (bool | None): Whether to scan the artifact for vulnerabilities.
|
243
|
+
validate (bool | None): Whether to validate the artifact. Source needs to be present in the artifact for the validation to work.
|
218
244
|
|
219
245
|
Returns:
|
220
246
|
Dict[str, int]: version number.
|
@@ -229,11 +255,21 @@ class Artifact(BaseClient):
|
|
229
255
|
"""
|
230
256
|
method, endpoint = HttpMethods.PUT, f"{self.BASE_ENDPOINT}/artifacts/{artifact_id}"
|
231
257
|
|
258
|
+
body = {}
|
259
|
+
|
260
|
+
if scan is not None:
|
261
|
+
body["scan"] = scan
|
262
|
+
|
263
|
+
if validate is not None:
|
264
|
+
body["validate"] = validate
|
265
|
+
|
266
|
+
updated_body = parse_body_for_multipart_request(body)
|
267
|
+
|
232
268
|
return self.session.create_request( # type: ignore[no-any-return]
|
233
269
|
endpoint,
|
234
270
|
method,
|
235
271
|
content_type=ContentType.MULTIPART_FORM_DATA,
|
236
|
-
body=
|
272
|
+
body=updated_body,
|
237
273
|
path=artifact["path"],
|
238
274
|
ignore_files=artifact.get("ignore_files"),
|
239
275
|
)
|
peak/session.py
CHANGED
@@ -87,9 +87,10 @@ class Session:
|
|
87
87
|
*,
|
88
88
|
params: Optional[Dict[str, Any]] = None,
|
89
89
|
body: Optional[Dict[str, Any]] = None,
|
90
|
-
path: Optional[str] = None,
|
90
|
+
path: Optional[str | list[str]] = None,
|
91
91
|
ignore_files: Optional[list[str]] = None,
|
92
92
|
subdomain: Optional[str] = "service",
|
93
|
+
file_key: Optional[str] = "artifact",
|
93
94
|
) -> Any:
|
94
95
|
"""Prepares a request to be sent over the network.
|
95
96
|
|
@@ -105,6 +106,7 @@ class Session:
|
|
105
106
|
path (Optional[str] optional): path to the file or folder that will be compressed and used as artifact, required for multipart requests.
|
106
107
|
ignore_files(Optional[list[str]]): Ignore files to be used when creating artifact, used only for multipart requests.
|
107
108
|
subdomain (Optional[str]): Subdomain for the endpoint. Defaults to `service`.
|
109
|
+
file_key (Optional[str]): the field in which the files must be uploaded
|
108
110
|
|
109
111
|
Returns:
|
110
112
|
Any: response dict object.
|
@@ -124,6 +126,7 @@ class Session:
|
|
124
126
|
session_meta={
|
125
127
|
"stage": self.stage,
|
126
128
|
},
|
129
|
+
file_key=file_key,
|
127
130
|
).json()
|
128
131
|
|
129
132
|
def create_generator_request(
|
peak/telemetry.py
CHANGED
@@ -103,10 +103,11 @@ def telemetry(make_request: F) -> F:
|
|
103
103
|
headers: Optional[Dict[str, str]] = None,
|
104
104
|
params: Optional[Dict[str, Any]] = None,
|
105
105
|
body: Optional[Dict[str, Any]] = None,
|
106
|
-
path: Optional[str] = None,
|
106
|
+
path: Optional[str | list[str]] = None,
|
107
107
|
request_kwargs: Optional[Dict[str, int | bool | str | float]] = None,
|
108
108
|
ignore_files: Optional[list[str]] = None,
|
109
109
|
session_meta: Optional[Dict[str, Any]] = None,
|
110
|
+
file_key: Optional[str] = "artifact",
|
110
111
|
) -> requests.Response:
|
111
112
|
"""A decorator that wraps over the make_request function to send telemetry requests as required.
|
112
113
|
|
@@ -122,6 +123,7 @@ def telemetry(make_request: F) -> F:
|
|
122
123
|
request_kwargs(Dict[str, int | bool | str | float] | None): extra arguments to be passed when making the request.
|
123
124
|
ignore_files(Optional[list[str]]): Ignore files to be used when creating artifact
|
124
125
|
session_meta(Dict[str, Any]): Metadata about the session object, like - stage
|
126
|
+
file_key (Optional[str]): the field in which the files must be uploaded
|
125
127
|
|
126
128
|
Returns:
|
127
129
|
requests.Response: response json
|
@@ -192,6 +194,7 @@ def telemetry(make_request: F) -> F:
|
|
192
194
|
path=path,
|
193
195
|
ignore_files=ignore_files,
|
194
196
|
request_kwargs=request_kwargs,
|
197
|
+
file_key=file_key,
|
195
198
|
)
|
196
199
|
|
197
200
|
trigger_usage_collection(res=res)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: peak-sdk
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.14.0
|
4
4
|
Summary: Python SDK for interacting with the Peak platform
|
5
5
|
Home-page: https://docs.peak.ai/sdk/latest/
|
6
6
|
License: Apache-2.0
|
@@ -106,7 +106,7 @@ Follow these steps to create a virtual environment using Python's built-in `venv
|
|
106
106
|
This should return a response of the following format
|
107
107
|
|
108
108
|
```bash
|
109
|
-
peak-cli==1.
|
109
|
+
peak-cli==1.14.0
|
110
110
|
Python==3.12.3
|
111
111
|
System==Darwin(23.6.0)
|
112
112
|
```
|
@@ -122,7 +122,7 @@ Follow these steps to create a virtual environment using Python's built-in `venv
|
|
122
122
|
This should print the version of the SDK
|
123
123
|
|
124
124
|
```
|
125
|
-
1.
|
125
|
+
1.14.0
|
126
126
|
```
|
127
127
|
|
128
128
|
### Using the SDK and CLI
|
@@ -1,6 +1,6 @@
|
|
1
1
|
peak/__init__.py,sha256=lxS3Xqyj9yvZdI3DVWbfn8i_Lw4t2Ujw9HbKe44-LY8,1284
|
2
2
|
peak/_metadata.py,sha256=ongQ3I77xv-3nZSLemYk_UKYLiMAwfM60-K_vcqRMBI,30528
|
3
|
-
peak/_version.py,sha256=
|
3
|
+
peak/_version.py,sha256=q_w6UYjTZ96mhm0Vg6AXepEKgyu-XGfEAbNB40N3tlI,887
|
4
4
|
peak/auth.py,sha256=KcqCqovY6sFiMGNAGP9k3AtCAXrZ-tYd7QP-PFYorX0,904
|
5
5
|
peak/base_client.py,sha256=3cS8hZApONkojwdgzt_tbwSxwpFcn3xGwzVcmxkgOJc,1808
|
6
6
|
peak/callbacks.py,sha256=k_p2Av5_ZWD8bDzcSPhbYaAS2xHQpVI1cSkAecnmuqU,3775
|
@@ -21,8 +21,8 @@ peak/cli/press/deployments.py,sha256=xr46ZWwmOE9IIRb9U9zNSIfDN6_jAbQce-wvjgfm-VI
|
|
21
21
|
peak/cli/press/specs.py,sha256=7XFWmgOuNBM8N482InvtQiZoQOldHqcQghLyHCmLHHI,4737
|
22
22
|
peak/cli/resources/__init__.py,sha256=ThMYJ-QNULjTWOmAGUzhKWuqDcHq73DxzgTV2r5-uLs,883
|
23
23
|
peak/cli/resources/alerts/__init__.py,sha256=TyeLPOGiA4qvOKORV3Ejlx8n6lGfX1G2GcU-bpYsgPE,1197
|
24
|
-
peak/cli/resources/alerts/emails.py,sha256=
|
25
|
-
peak/cli/resources/artifacts.py,sha256=
|
24
|
+
peak/cli/resources/alerts/emails.py,sha256=Z2qhub2eFhGLjVY_koto_SoqB1nQ3uWvdW_Zft1ukAU,12435
|
25
|
+
peak/cli/resources/artifacts.py,sha256=iYx29_FUdohxmm5zwwRtrOAedVSFgjVo8iVA7CTmtgE,12619
|
26
26
|
peak/cli/resources/images.py,sha256=SwZC0y6pw3mq1HMiO9nPV3YzykbMuSIGt2TD47ZTZ1Y,43133
|
27
27
|
peak/cli/resources/services.py,sha256=ZiWX4OyR9bMDglhRJNF8fY9YjGfH4ZDqxeNvCO88s4Q,25666
|
28
28
|
peak/cli/resources/tenants.py,sha256=1vmNOwmLQdNV9RSVNaOZBRcAzHkOzIcVNz5ZH390O0c,4066
|
@@ -35,7 +35,7 @@ peak/compression.py,sha256=XPYjtREe93Gxlnn9YkSnBwaFKTIJSZ6MOPeuqwi3qTs,7894
|
|
35
35
|
peak/config.py,sha256=FZ6aIN0gwA52noh-8HJkGnUr8HEOpyNFk6uR4QWt65o,1146
|
36
36
|
peak/constants.py,sha256=TDMN4cXXKyR_Q8maeo8Ukvprl_Bz0YtYytD3yuHBZKs,3312
|
37
37
|
peak/exceptions.py,sha256=xAPgn8KHsKEEiHoViGPrF3TF1Ma_lSk6tgki2Yv_yEY,7491
|
38
|
-
peak/handler.py,sha256=
|
38
|
+
peak/handler.py,sha256=9HFbVtxJ6bEBgvpF8PmlPYa6EOHLKejWMBL3SJd26VM,17229
|
39
39
|
peak/helpers.py,sha256=J2q1syT-2V5eD8gkgcH8mk6gNLsEvPa7qFcB390O6V0,9879
|
40
40
|
peak/logger.py,sha256=bPq_7mdbhFoUcnV_LCi8hRDrb7INwf8PHHEx2z83bFU,1548
|
41
41
|
peak/metrics/__init__.py,sha256=g5ufdcpozE7C6jJVbzo9XQNK3o9dNTy31wgIaRBmrHQ,1057
|
@@ -48,8 +48,8 @@ peak/press/deployments.py,sha256=lfWSkrJ6nEWiA8bO0d5u675mGJakRgNuQEbqXpLgbJc,848
|
|
48
48
|
peak/press/specs.py,sha256=GH9-SACctAlcBZznXEmsIqneOwIJoE55mD4aHQymMrM,10915
|
49
49
|
peak/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
50
50
|
peak/resources/__init__.py,sha256=CkLWMygz8mr_isA8uMGQn2uut-BilCydLwx5sYniPIA,1242
|
51
|
-
peak/resources/alerts.py,sha256
|
52
|
-
peak/resources/artifacts.py,sha256=
|
51
|
+
peak/resources/alerts.py,sha256=Ey1TUtCD7L0X5N03B5EijrGkFWxrarNi8QBv9_x6eBI,12792
|
52
|
+
peak/resources/artifacts.py,sha256=Ga6D-axCq_Gn5sq8eH7MZrWCMCwBK8xO-iaUapGdM2U,15648
|
53
53
|
peak/resources/images.py,sha256=7UB-jNEkE3HaqGLiTkv5wf5SU_9Y-jeFoMG_aMPT-y8,46715
|
54
54
|
peak/resources/services.py,sha256=JXZrPf3TXL-MhcjzduN6dNbMJe4PrbALUYffJviOnbY,17176
|
55
55
|
peak/resources/tenants.py,sha256=amTs39KZ5hxDd7h3h1qo3TgYJOY1Eql0EhRgDBPlQ6Y,4380
|
@@ -77,10 +77,10 @@ peak/sample_yaml/press/blocks/specs/update_block_spec_metadata.yaml,sha256=WsfYG
|
|
77
77
|
peak/sample_yaml/press/blocks/specs/workflow/create_block_spec.yaml,sha256=k4RePPB0wEiTwq91Lg2NY0MTTWr90zHPluxKsxAEpA4,4564
|
78
78
|
peak/sample_yaml/press/blocks/specs/workflow/create_block_spec_release.yaml,sha256=70tGyUmrP-h_MweS7LzoYcltV8cNvBuDYxgexed7GxI,4208
|
79
79
|
peak/sample_yaml/press/patch_parameters.yaml,sha256=8eD8X2XNVQ9_TNDFXd-XPiZ5CK2upqpv1QCEiWvDGBs,139
|
80
|
-
peak/sample_yaml/resources/artifacts/create_artifact.yaml,sha256=
|
81
|
-
peak/sample_yaml/resources/artifacts/create_artifact_version.yaml,sha256=
|
80
|
+
peak/sample_yaml/resources/artifacts/create_artifact.yaml,sha256=8sFU7VV2vv292THRsGNzTItWbhP7F4YMACM4jkVisRU,194
|
81
|
+
peak/sample_yaml/resources/artifacts/create_artifact_version.yaml,sha256=Mru6TdS0z34--r4nhx0-ZBUgR6Ylj0Gp_JRy3-Kb7pk,131
|
82
82
|
peak/sample_yaml/resources/artifacts/update_artifact_metadata.yaml,sha256=nvV84lOBtoekXl3kWrMTIU3tbsVn-gVIx4cLRI8jevw,99
|
83
|
-
peak/sample_yaml/resources/emails/send_email.yaml,sha256=
|
83
|
+
peak/sample_yaml/resources/emails/send_email.yaml,sha256=YWv0PDq-4g0krsbtZdte9oV9PlluKuytEIwR8Ck6hyk,295
|
84
84
|
peak/sample_yaml/resources/images/dockerfile/create_image.yaml,sha256=kHLlrnDJZX_sFcgxbu0wbmTjsVCqsJxe1G1__jZZeLs,384
|
85
85
|
peak/sample_yaml/resources/images/dockerfile/create_image_version.yaml,sha256=fq51FEdHbe1kp6ozpZUkeGBguqYRroo8W2YvXf-L_Xg,353
|
86
86
|
peak/sample_yaml/resources/images/dockerfile/update_version.yaml,sha256=XPHAp-5vD2IdDglalqnbknwJA8FEQM3GQ2_SCa0y5eA,318
|
@@ -110,8 +110,8 @@ peak/sample_yaml/resources/workflows/workflow_input_parameters.yaml,sha256=kM52m
|
|
110
110
|
peak/sample_yaml/resources/workflows/workflow_input_parameters_inherit.yaml,sha256=6sA-CsVB0xS31G_2YE9W4vtZvupA9zDO97UCJKJlJiQ,1426
|
111
111
|
peak/sample_yaml/resources/workflows/workflow_output_parameters.yaml,sha256=S9twG4lSB2HAt4ZL6zy5beKD-XY1Jik4asyHy4DG5Cs,913
|
112
112
|
peak/sample_yaml/resources/workflows/workflow_skippable_steps.yaml,sha256=Ei1wGqJC-LqDPpQfqh_CmMmJ_DI5kQfuGTK4koQsiVk,1418
|
113
|
-
peak/session.py,sha256=
|
114
|
-
peak/telemetry.py,sha256=
|
113
|
+
peak/session.py,sha256=4Wi6uBmJSv6vAV0d6SweZCV59jpMr3Zkc-84aUTrn7U,10360
|
114
|
+
peak/telemetry.py,sha256=LSrqSir-2WKPDwhjs_hG-oSjSIVnojptN124hPPR5i0,7263
|
115
115
|
peak/template.py,sha256=VezqlvPxJKW_e4lh3GqsUX1mjUJsW9WRGLC1oMK2UwE,10839
|
116
116
|
peak/tools/__init__.py,sha256=qK30qBi0MNvob6UkyzcfhI0s8nfSwGC4167A_2URBnY,1048
|
117
117
|
peak/tools/logging/__init__.py,sha256=tIKis2HbtFzXY9gEsjcFipHxoGbieDtV2cYKP7Z9Ibw,1513
|
@@ -120,8 +120,8 @@ peak/tools/logging/log_level.py,sha256=Xtv4zZnYk4QBix_MfCRGim4yJbv7w2tTbNKe_s4Qm
|
|
120
120
|
peak/tools/logging/logger.py,sha256=Jow5D3hqek-n0kHWNeL2nKbC9NfpfkWFT_FmPp-skTw,15653
|
121
121
|
peak/tools/logging/utils.py,sha256=qmjdBbCc1Y6JDbSgNXfdnLnpkx7fb9kPw9u8uO3AAII,3330
|
122
122
|
peak/validators.py,sha256=_nVAXF_AB443voKNjyQsCTQBAVVAqn7xCbCbBguohIs,2715
|
123
|
-
peak_sdk-1.
|
124
|
-
peak_sdk-1.
|
125
|
-
peak_sdk-1.
|
126
|
-
peak_sdk-1.
|
127
|
-
peak_sdk-1.
|
123
|
+
peak_sdk-1.14.0.dist-info/LICENSE,sha256=W0jszenKx7YdFA7BDnyg8xDKXzCP8AperJb_PHh9paQ,11340
|
124
|
+
peak_sdk-1.14.0.dist-info/METADATA,sha256=7zHFOJ0bEqwu2_NEDS3jJ2ig9kJjDSw2Kv_IUHEdqv0,7978
|
125
|
+
peak_sdk-1.14.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
126
|
+
peak_sdk-1.14.0.dist-info/entry_points.txt,sha256=zHCEjuOTjkfmqivgEZQsPGm4zFA4W3Q_vKCjPr7W6lE,47
|
127
|
+
peak_sdk-1.14.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|