uipath 2.0.53__py3-none-any.whl → 2.0.55__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.

Potentially problematic release.


This version of uipath might be problematic. Click here for more details.

@@ -0,0 +1,595 @@
1
+ import uuid
2
+ from typing import Any, Dict, Optional, Union, overload
3
+
4
+ from httpx import request
5
+
6
+ from .._config import Config
7
+ from .._execution_context import ExecutionContext
8
+ from .._folder_context import FolderContext
9
+ from .._utils import Endpoint, RequestSpec, header_folder
10
+ from ..tracing._traced import traced
11
+ from ._base_service import BaseService
12
+
13
+
14
+ def _upload_attachment_input_processor(inputs: Dict[str, Any]) -> Dict[str, Any]:
15
+ """Process attachment upload inputs to avoid logging large content."""
16
+ processed_inputs = inputs.copy()
17
+ if "source_path" in processed_inputs:
18
+ processed_inputs["source_path"] = f"<File at {processed_inputs['source_path']}>"
19
+ if "content" in processed_inputs:
20
+ if isinstance(processed_inputs["content"], str):
21
+ processed_inputs["content"] = "<Redacted String Content>"
22
+ else:
23
+ processed_inputs["content"] = "<Redacted Binary Content>"
24
+ return processed_inputs
25
+
26
+
27
+ class AttachmentsService(FolderContext, BaseService):
28
+ """Service for managing UiPath attachments.
29
+
30
+ Attachments allow you to upload and download files to be used within UiPath
31
+ processes, actions, and other UiPath services.
32
+
33
+ Reference: https://docs.uipath.com/orchestrator/reference/api-attachments
34
+ """
35
+
36
+ def __init__(self, config: Config, execution_context: ExecutionContext) -> None:
37
+ super().__init__(config=config, execution_context=execution_context)
38
+
39
+ @traced(name="attachments_download", run_type="uipath")
40
+ def download(
41
+ self,
42
+ *,
43
+ key: uuid.UUID,
44
+ destination_path: str,
45
+ folder_key: Optional[str] = None,
46
+ folder_path: Optional[str] = None,
47
+ ) -> str:
48
+ """Download an attachment.
49
+
50
+ This method downloads an attachment from UiPath to a local file.
51
+
52
+ Args:
53
+ key (uuid.UUID): The key of the attachment to download.
54
+ destination_path (str): The local path where the attachment will be saved.
55
+ folder_key (Optional[str]): The key of the folder. Override the default one set in the SDK config.
56
+ folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
57
+
58
+ Returns:
59
+ str: The name of the downloaded attachment.
60
+
61
+ Raises:
62
+ Exception: If the download fails.
63
+
64
+ Examples:
65
+ ```python
66
+ from uipath import UiPath
67
+
68
+ client = UiPath()
69
+
70
+ attachment_name = client.attachments.download(
71
+ key=uuid.UUID("123e4567-e89b-12d3-a456-426614174000"),
72
+ destination_path="path/to/save/document.pdf"
73
+ )
74
+ print(f"Downloaded attachment: {attachment_name}")
75
+ ```
76
+ """
77
+ spec = self._retrieve_download_uri_spec(
78
+ key=key,
79
+ folder_key=folder_key,
80
+ folder_path=folder_path,
81
+ )
82
+
83
+ result = self.request(
84
+ spec.method,
85
+ url=spec.endpoint,
86
+ params=spec.params,
87
+ headers=spec.headers,
88
+ ).json()
89
+
90
+ # Get the attachment name
91
+ attachment_name = result["Name"]
92
+
93
+ download_uri = result["BlobFileAccess"]["Uri"]
94
+ headers = {
95
+ key: value
96
+ for key, value in zip(
97
+ result["BlobFileAccess"]["Headers"]["Keys"],
98
+ result["BlobFileAccess"]["Headers"]["Values"],
99
+ strict=False,
100
+ )
101
+ }
102
+
103
+ with open(destination_path, "wb") as file:
104
+ if result["BlobFileAccess"]["RequiresAuth"]:
105
+ file_content = self.request(
106
+ "GET", download_uri, headers=headers
107
+ ).content
108
+ else:
109
+ file_content = request("GET", download_uri, headers=headers).content
110
+ file.write(file_content)
111
+
112
+ return attachment_name
113
+
114
+ @traced(name="attachments_download", run_type="uipath")
115
+ async def download_async(
116
+ self,
117
+ *,
118
+ key: uuid.UUID,
119
+ destination_path: str,
120
+ folder_key: Optional[str] = None,
121
+ folder_path: Optional[str] = None,
122
+ ) -> str:
123
+ """Download an attachment asynchronously.
124
+
125
+ This method asynchronously downloads an attachment from UiPath to a local file.
126
+
127
+ Args:
128
+ key (uuid.UUID): The key of the attachment to download.
129
+ destination_path (str): The local path where the attachment will be saved.
130
+ folder_key (Optional[str]): The key of the folder. Override the default one set in the SDK config.
131
+ folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
132
+
133
+ Returns:
134
+ str: The name of the downloaded attachment.
135
+
136
+ Raises:
137
+ Exception: If the download fails.
138
+
139
+ Examples:
140
+ ```python
141
+ import asyncio
142
+ from uipath import UiPath
143
+
144
+ client = UiPath()
145
+
146
+ async def main():
147
+ attachment_name = await client.attachments.download_async(
148
+ key=uuid.UUID("123e4567-e89b-12d3-a456-426614174000"),
149
+ destination_path="path/to/save/document.pdf"
150
+ )
151
+ print(f"Downloaded attachment: {attachment_name}")
152
+ ```
153
+ """
154
+ spec = self._retrieve_download_uri_spec(
155
+ key=key,
156
+ folder_key=folder_key,
157
+ folder_path=folder_path,
158
+ )
159
+
160
+ result = (
161
+ await self.request_async(
162
+ spec.method,
163
+ url=spec.endpoint,
164
+ params=spec.params,
165
+ headers=spec.headers,
166
+ )
167
+ ).json()
168
+
169
+ # Get the attachment name
170
+ attachment_name = result["Name"]
171
+
172
+ download_uri = result["BlobFileAccess"]["Uri"]
173
+ headers = {
174
+ key: value
175
+ for key, value in zip(
176
+ result["BlobFileAccess"]["Headers"]["Keys"],
177
+ result["BlobFileAccess"]["Headers"]["Values"],
178
+ strict=False,
179
+ )
180
+ }
181
+
182
+ with open(destination_path, "wb") as file:
183
+ if result["BlobFileAccess"]["RequiresAuth"]:
184
+ response = await self.request_async(
185
+ "GET", download_uri, headers=headers
186
+ )
187
+ file.write(response.content)
188
+ else:
189
+ file.write(request("GET", download_uri, headers=headers).content)
190
+
191
+ return attachment_name
192
+
193
+ @overload
194
+ def upload(
195
+ self,
196
+ *,
197
+ name: str,
198
+ content: Union[str, bytes],
199
+ folder_key: Optional[str] = None,
200
+ folder_path: Optional[str] = None,
201
+ ) -> uuid.UUID: ...
202
+
203
+ @overload
204
+ def upload(
205
+ self,
206
+ *,
207
+ name: str,
208
+ source_path: str,
209
+ folder_key: Optional[str] = None,
210
+ folder_path: Optional[str] = None,
211
+ ) -> uuid.UUID: ...
212
+
213
+ @traced(
214
+ name="attachments_upload",
215
+ run_type="uipath",
216
+ input_processor=_upload_attachment_input_processor,
217
+ )
218
+ def upload(
219
+ self,
220
+ *,
221
+ name: str,
222
+ content: Optional[Union[str, bytes]] = None,
223
+ source_path: Optional[str] = None,
224
+ folder_key: Optional[str] = None,
225
+ folder_path: Optional[str] = None,
226
+ ) -> uuid.UUID:
227
+ """Upload a file or content to UiPath as an attachment.
228
+
229
+ This method uploads content to UiPath and makes it available as an attachment.
230
+ You can either provide a file path or content in memory.
231
+
232
+ Args:
233
+ name (str): The name of the attachment file.
234
+ content (Optional[Union[str, bytes]]): The content to upload (string or bytes).
235
+ source_path (Optional[str]): The local path of the file to upload.
236
+ folder_key (Optional[str]): The key of the folder. Override the default one set in the SDK config.
237
+ folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
238
+
239
+ Returns:
240
+ uuid.UUID: The UUID of the created attachment.
241
+
242
+ Raises:
243
+ ValueError: If neither content nor source_path is provided, or if both are provided.
244
+ Exception: If the upload fails.
245
+
246
+ Examples:
247
+ ```python
248
+ from uipath import UiPath
249
+
250
+ client = UiPath()
251
+
252
+ # Upload a file from disk
253
+ attachment_key = client.attachments.upload(
254
+ name="my-document.pdf",
255
+ source_path="path/to/local/document.pdf",
256
+ )
257
+ print(f"Uploaded attachment with key: {attachment_key}")
258
+
259
+ # Upload content from memory
260
+ attachment_key = client.attachments.upload(
261
+ name="notes.txt",
262
+ content="This is a text file content",
263
+ )
264
+ print(f"Uploaded attachment with key: {attachment_key}")
265
+ ```
266
+ """
267
+ # Validate input parameters
268
+ if not (content or source_path):
269
+ raise ValueError("Content or source_path is required")
270
+ if content and source_path:
271
+ raise ValueError("Content and source_path are mutually exclusive")
272
+
273
+ spec = self._create_attachment_and_retrieve_upload_uri_spec(
274
+ name=name,
275
+ folder_key=folder_key,
276
+ folder_path=folder_path,
277
+ )
278
+
279
+ result = self.request(
280
+ spec.method,
281
+ url=spec.endpoint,
282
+ params=spec.params,
283
+ headers=spec.headers,
284
+ json=spec.json,
285
+ ).json()
286
+
287
+ # Get the ID from the response and convert to UUID
288
+ attachment_key = uuid.UUID(result["Id"])
289
+
290
+ upload_uri = result["BlobFileAccess"]["Uri"]
291
+ headers = {
292
+ key: value
293
+ for key, value in zip(
294
+ result["BlobFileAccess"]["Headers"]["Keys"],
295
+ result["BlobFileAccess"]["Headers"]["Values"],
296
+ strict=False,
297
+ )
298
+ }
299
+
300
+ if source_path:
301
+ # Upload from file
302
+ with open(source_path, "rb") as file:
303
+ if result["BlobFileAccess"]["RequiresAuth"]:
304
+ self.request(
305
+ "PUT", upload_uri, headers=headers, files={"file": file}
306
+ )
307
+ else:
308
+ request("PUT", upload_uri, headers=headers, files={"file": file})
309
+ else:
310
+ # Upload from memory
311
+ # Convert string to bytes if needed
312
+ if isinstance(content, str):
313
+ content = content.encode("utf-8")
314
+
315
+ if result["BlobFileAccess"]["RequiresAuth"]:
316
+ self.request("PUT", upload_uri, headers=headers, content=content)
317
+ else:
318
+ request("PUT", upload_uri, headers=headers, content=content)
319
+
320
+ return attachment_key
321
+
322
+ @overload
323
+ async def upload_async(
324
+ self,
325
+ *,
326
+ name: str,
327
+ content: Union[str, bytes],
328
+ folder_key: Optional[str] = None,
329
+ folder_path: Optional[str] = None,
330
+ ) -> uuid.UUID: ...
331
+
332
+ @overload
333
+ async def upload_async(
334
+ self,
335
+ *,
336
+ name: str,
337
+ source_path: str,
338
+ folder_key: Optional[str] = None,
339
+ folder_path: Optional[str] = None,
340
+ ) -> uuid.UUID: ...
341
+
342
+ @traced(
343
+ name="attachments_upload",
344
+ run_type="uipath",
345
+ input_processor=_upload_attachment_input_processor,
346
+ )
347
+ async def upload_async(
348
+ self,
349
+ *,
350
+ name: str,
351
+ content: Optional[Union[str, bytes]] = None,
352
+ source_path: Optional[str] = None,
353
+ folder_key: Optional[str] = None,
354
+ folder_path: Optional[str] = None,
355
+ ) -> uuid.UUID:
356
+ """Upload a file or content to UiPath as an attachment asynchronously.
357
+
358
+ This method asynchronously uploads content to UiPath and makes it available as an attachment.
359
+ You can either provide a file path or content in memory.
360
+
361
+ Args:
362
+ name (str): The name of the attachment file.
363
+ content (Optional[Union[str, bytes]]): The content to upload (string or bytes).
364
+ source_path (Optional[str]): The local path of the file to upload.
365
+ folder_key (Optional[str]): The key of the folder. Override the default one set in the SDK config.
366
+ folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
367
+
368
+ Returns:
369
+ uuid.UUID: The UUID of the created attachment.
370
+
371
+ Raises:
372
+ ValueError: If neither content nor source_path is provided, or if both are provided.
373
+ Exception: If the upload fails.
374
+
375
+ Examples:
376
+ ```python
377
+ import asyncio
378
+ from uipath import UiPath
379
+
380
+ client = UiPath()
381
+
382
+ async def main():
383
+ # Upload a file from disk
384
+ attachment_key = await client.attachments.upload_async(
385
+ name="my-document.pdf",
386
+ source_path="path/to/local/document.pdf",
387
+ )
388
+ print(f"Uploaded attachment with key: {attachment_key}")
389
+
390
+ # Upload content from memory
391
+ attachment_key = await client.attachments.upload_async(
392
+ name="notes.txt",
393
+ content="This is a text file content",
394
+ )
395
+ print(f"Uploaded attachment with key: {attachment_key}")
396
+ ```
397
+ """
398
+ # Validate input parameters
399
+ if not (content or source_path):
400
+ raise ValueError("Content or source_path is required")
401
+ if content and source_path:
402
+ raise ValueError("Content and source_path are mutually exclusive")
403
+
404
+ spec = self._create_attachment_and_retrieve_upload_uri_spec(
405
+ name=name,
406
+ folder_key=folder_key,
407
+ folder_path=folder_path,
408
+ )
409
+
410
+ result = (
411
+ await self.request_async(
412
+ spec.method,
413
+ url=spec.endpoint,
414
+ params=spec.params,
415
+ headers=spec.headers,
416
+ json=spec.json,
417
+ )
418
+ ).json()
419
+
420
+ # Get the ID from the response and convert to UUID
421
+ attachment_key = uuid.UUID(result["Id"])
422
+
423
+ upload_uri = result["BlobFileAccess"]["Uri"]
424
+ headers = {
425
+ key: value
426
+ for key, value in zip(
427
+ result["BlobFileAccess"]["Headers"]["Keys"],
428
+ result["BlobFileAccess"]["Headers"]["Values"],
429
+ strict=False,
430
+ )
431
+ }
432
+
433
+ if source_path:
434
+ # Upload from file
435
+ with open(source_path, "rb") as file:
436
+ if result["BlobFileAccess"]["RequiresAuth"]:
437
+ await self.request_async(
438
+ "PUT", upload_uri, headers=headers, files={"file": file}
439
+ )
440
+ else:
441
+ request("PUT", upload_uri, headers=headers, files={"file": file})
442
+ else:
443
+ # Upload from memory
444
+ # Convert string to bytes if needed
445
+ if isinstance(content, str):
446
+ content = content.encode("utf-8")
447
+
448
+ if result["BlobFileAccess"]["RequiresAuth"]:
449
+ await self.request_async(
450
+ "PUT", upload_uri, headers=headers, content=content
451
+ )
452
+ else:
453
+ request("PUT", upload_uri, headers=headers, content=content)
454
+
455
+ return attachment_key
456
+
457
+ @traced(name="attachments_delete", run_type="uipath")
458
+ def delete(
459
+ self,
460
+ *,
461
+ key: uuid.UUID,
462
+ folder_key: Optional[str] = None,
463
+ folder_path: Optional[str] = None,
464
+ ) -> None:
465
+ """Delete an attachment.
466
+
467
+ This method deletes an attachment from UiPath.
468
+
469
+ Args:
470
+ key (uuid.UUID): The key of the attachment to delete.
471
+ folder_key (Optional[str]): The key of the folder. Override the default one set in the SDK config.
472
+ folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
473
+
474
+ Raises:
475
+ Exception: If the deletion fails.
476
+
477
+ Examples:
478
+ ```python
479
+ from uipath import UiPath
480
+
481
+ client = UiPath()
482
+
483
+ client.attachments.delete(
484
+ key=uuid.UUID("123e4567-e89b-12d3-a456-426614174000")
485
+ )
486
+ print("Attachment deleted successfully")
487
+ ```
488
+ """
489
+ spec = self._delete_attachment_spec(
490
+ key=key,
491
+ folder_key=folder_key,
492
+ folder_path=folder_path,
493
+ )
494
+
495
+ self.request(
496
+ spec.method,
497
+ url=spec.endpoint,
498
+ headers=spec.headers,
499
+ )
500
+
501
+ @traced(name="attachments_delete", run_type="uipath")
502
+ async def delete_async(
503
+ self,
504
+ *,
505
+ key: uuid.UUID,
506
+ folder_key: Optional[str] = None,
507
+ folder_path: Optional[str] = None,
508
+ ) -> None:
509
+ """Delete an attachment asynchronously.
510
+
511
+ This method asynchronously deletes an attachment from UiPath.
512
+
513
+ Args:
514
+ key (uuid.UUID): The key of the attachment to delete.
515
+ folder_key (Optional[str]): The key of the folder. Override the default one set in the SDK config.
516
+ folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
517
+
518
+ Raises:
519
+ Exception: If the deletion fails.
520
+
521
+ Examples:
522
+ ```python
523
+ import asyncio
524
+ from uipath import UiPath
525
+
526
+ client = UiPath()
527
+
528
+ async def main():
529
+ await client.attachments.delete_async(
530
+ key=uuid.UUID("123e4567-e89b-12d3-a456-426614174000")
531
+ )
532
+ print("Attachment deleted successfully")
533
+ ```
534
+ """
535
+ spec = self._delete_attachment_spec(
536
+ key=key,
537
+ folder_key=folder_key,
538
+ folder_path=folder_path,
539
+ )
540
+
541
+ await self.request_async(
542
+ spec.method,
543
+ url=spec.endpoint,
544
+ headers=spec.headers,
545
+ )
546
+
547
+ @property
548
+ def custom_headers(self) -> Dict[str, str]:
549
+ """Return custom headers for API requests."""
550
+ return self.folder_headers
551
+
552
+ def _create_attachment_and_retrieve_upload_uri_spec(
553
+ self,
554
+ name: str,
555
+ folder_key: Optional[str] = None,
556
+ folder_path: Optional[str] = None,
557
+ ) -> RequestSpec:
558
+ return RequestSpec(
559
+ method="POST",
560
+ endpoint=Endpoint("/orchestrator_/odata/Attachments"),
561
+ json={
562
+ "Name": name,
563
+ },
564
+ headers={
565
+ **header_folder(folder_key, folder_path),
566
+ },
567
+ )
568
+
569
+ def _retrieve_download_uri_spec(
570
+ self,
571
+ key: uuid.UUID,
572
+ folder_key: Optional[str] = None,
573
+ folder_path: Optional[str] = None,
574
+ ) -> RequestSpec:
575
+ return RequestSpec(
576
+ method="GET",
577
+ endpoint=Endpoint(f"/orchestrator_/odata/Attachments({key})"),
578
+ headers={
579
+ **header_folder(folder_key, folder_path),
580
+ },
581
+ )
582
+
583
+ def _delete_attachment_spec(
584
+ self,
585
+ key: uuid.UUID,
586
+ folder_key: Optional[str] = None,
587
+ folder_path: Optional[str] = None,
588
+ ) -> RequestSpec:
589
+ return RequestSpec(
590
+ method="DELETE",
591
+ endpoint=Endpoint(f"/orchestrator_/odata/Attachments({key})"),
592
+ headers={
593
+ **header_folder(folder_key, folder_path),
594
+ },
595
+ )
@@ -55,7 +55,7 @@ class BucketsService(FolderContext, BaseService):
55
55
  name=name, key=key, folder_key=folder_key, folder_path=folder_path
56
56
  )
57
57
  spec = self._retrieve_readUri_spec(
58
- bucket, blob_file_path, folder_key=folder_key, folder_path=folder_path
58
+ bucket.id, blob_file_path, folder_key=folder_key, folder_path=folder_path
59
59
  )
60
60
  result = self.request(
61
61
  spec.method,
@@ -112,10 +112,8 @@ class BucketsService(FolderContext, BaseService):
112
112
  name=name, key=key, folder_key=folder_key, folder_path=folder_path
113
113
  )
114
114
 
115
- bucket_id = bucket["Id"]
116
-
117
115
  spec = self._retrieve_writeri_spec(
118
- bucket_id,
116
+ bucket.id,
119
117
  content_type,
120
118
  blob_file_path,
121
119
  folder_key=folder_key,
@@ -175,10 +173,8 @@ class BucketsService(FolderContext, BaseService):
175
173
  name=name, key=key, folder_key=folder_key, folder_path=folder_path
176
174
  )
177
175
 
178
- bucket_id = bucket["Id"]
179
-
180
176
  spec = self._retrieve_writeri_spec(
181
- bucket_id,
177
+ bucket.id,
182
178
  content_type,
183
179
  blob_file_path,
184
180
  folder_key=folder_key,
@@ -245,10 +241,9 @@ class BucketsService(FolderContext, BaseService):
245
241
  bucket = self.retrieve(
246
242
  name=name, key=key, folder_key=folder_key, folder_path=folder_path
247
243
  )
248
- bucket_id = bucket["Id"]
249
244
 
250
245
  spec = self._retrieve_writeri_spec(
251
- bucket_id,
246
+ bucket.id,
252
247
  content_type,
253
248
  blob_file_path,
254
249
  folder_key=folder_key,