uipath 2.0.56__py3-none-any.whl → 2.0.58__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.
- uipath/_services/attachments_service.py +236 -96
- uipath/_services/buckets_service.py +55 -145
- uipath/_services/context_grounding_service.py +9 -6
- uipath/_services/folder_service.py +21 -15
- uipath/_services/jobs_service.py +293 -58
- uipath/_utils/constants.py +3 -0
- uipath/telemetry/_constants.py +1 -1
- uipath/tracing/_utils.py +6 -5
- {uipath-2.0.56.dist-info → uipath-2.0.58.dist-info}/METADATA +1 -1
- {uipath-2.0.56.dist-info → uipath-2.0.58.dist-info}/RECORD +13 -13
- {uipath-2.0.56.dist-info → uipath-2.0.58.dist-info}/WHEEL +0 -0
- {uipath-2.0.56.dist-info → uipath-2.0.58.dist-info}/entry_points.txt +0 -0
- {uipath-2.0.56.dist-info → uipath-2.0.58.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,12 +1,17 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
import tempfile
|
|
1
4
|
import uuid
|
|
5
|
+
from pathlib import Path
|
|
2
6
|
from typing import Any, Dict, Optional, Union, overload
|
|
3
7
|
|
|
4
|
-
|
|
8
|
+
import httpx
|
|
5
9
|
|
|
6
10
|
from .._config import Config
|
|
7
11
|
from .._execution_context import ExecutionContext
|
|
8
12
|
from .._folder_context import FolderContext
|
|
9
13
|
from .._utils import Endpoint, RequestSpec, header_folder
|
|
14
|
+
from .._utils.constants import TEMP_ATTACHMENTS_FOLDER
|
|
10
15
|
from ..tracing._traced import traced
|
|
11
16
|
from ._base_service import BaseService
|
|
12
17
|
|
|
@@ -35,6 +40,7 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
35
40
|
|
|
36
41
|
def __init__(self, config: Config, execution_context: ExecutionContext) -> None:
|
|
37
42
|
super().__init__(config=config, execution_context=execution_context)
|
|
43
|
+
self._temp_dir = os.path.join(tempfile.gettempdir(), TEMP_ATTACHMENTS_FOLDER)
|
|
38
44
|
|
|
39
45
|
@traced(name="attachments_download", run_type="uipath")
|
|
40
46
|
def download(
|
|
@@ -48,6 +54,12 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
48
54
|
"""Download an attachment.
|
|
49
55
|
|
|
50
56
|
This method downloads an attachment from UiPath to a local file.
|
|
57
|
+
If the attachment is not found in UiPath (404 error), it will check
|
|
58
|
+
for a local file in the temporary directory that matches the UUID.
|
|
59
|
+
|
|
60
|
+
Note:
|
|
61
|
+
The local file fallback functionality is intended for local development
|
|
62
|
+
and debugging purposes only.
|
|
51
63
|
|
|
52
64
|
Args:
|
|
53
65
|
key (uuid.UUID): The key of the attachment to download.
|
|
@@ -59,7 +71,7 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
59
71
|
str: The name of the downloaded attachment.
|
|
60
72
|
|
|
61
73
|
Raises:
|
|
62
|
-
Exception: If the download fails.
|
|
74
|
+
Exception: If the download fails and no local file is found.
|
|
63
75
|
|
|
64
76
|
Examples:
|
|
65
77
|
```python
|
|
@@ -74,42 +86,75 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
74
86
|
print(f"Downloaded attachment: {attachment_name}")
|
|
75
87
|
```
|
|
76
88
|
"""
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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,
|
|
89
|
+
try:
|
|
90
|
+
spec = self._retrieve_download_uri_spec(
|
|
91
|
+
key=key,
|
|
92
|
+
folder_key=folder_key,
|
|
93
|
+
folder_path=folder_path,
|
|
100
94
|
)
|
|
101
|
-
}
|
|
102
95
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
96
|
+
result = self.request(
|
|
97
|
+
spec.method,
|
|
98
|
+
url=spec.endpoint,
|
|
99
|
+
params=spec.params,
|
|
100
|
+
headers=spec.headers,
|
|
101
|
+
).json()
|
|
102
|
+
|
|
103
|
+
# Get the attachment name
|
|
104
|
+
attachment_name = result["Name"]
|
|
105
|
+
|
|
106
|
+
download_uri = result["BlobFileAccess"]["Uri"]
|
|
107
|
+
headers = {
|
|
108
|
+
key: value
|
|
109
|
+
for key, value in zip(
|
|
110
|
+
result["BlobFileAccess"]["Headers"]["Keys"],
|
|
111
|
+
result["BlobFileAccess"]["Headers"]["Values"],
|
|
112
|
+
strict=False,
|
|
113
|
+
)
|
|
114
|
+
}
|
|
111
115
|
|
|
112
|
-
|
|
116
|
+
with open(destination_path, "wb") as file:
|
|
117
|
+
if result["BlobFileAccess"]["RequiresAuth"]:
|
|
118
|
+
response = self.request(
|
|
119
|
+
"GET", download_uri, headers=headers, stream=True
|
|
120
|
+
)
|
|
121
|
+
for chunk in response.iter_bytes(chunk_size=8192):
|
|
122
|
+
file.write(chunk)
|
|
123
|
+
else:
|
|
124
|
+
with httpx.Client() as client:
|
|
125
|
+
with client.stream(
|
|
126
|
+
"GET", download_uri, headers=headers
|
|
127
|
+
) as response:
|
|
128
|
+
for chunk in response.iter_bytes(chunk_size=8192):
|
|
129
|
+
file.write(chunk)
|
|
130
|
+
|
|
131
|
+
return attachment_name
|
|
132
|
+
except Exception as e:
|
|
133
|
+
# If not found in UiPath, check local storage
|
|
134
|
+
if "404" in str(e):
|
|
135
|
+
# Check if file exists in temp directory
|
|
136
|
+
if os.path.exists(self._temp_dir):
|
|
137
|
+
# Look for any file starting with our UUID
|
|
138
|
+
pattern = f"{key}_*"
|
|
139
|
+
matching_files = list(Path(self._temp_dir).glob(pattern))
|
|
140
|
+
|
|
141
|
+
if matching_files:
|
|
142
|
+
# Get the full filename
|
|
143
|
+
local_file = matching_files[0]
|
|
144
|
+
|
|
145
|
+
# Extract the original name from the filename (part after UUID_)
|
|
146
|
+
file_name = os.path.basename(local_file)
|
|
147
|
+
original_name = file_name[len(f"{key}_") :]
|
|
148
|
+
|
|
149
|
+
# Copy the file to the destination
|
|
150
|
+
shutil.copy2(local_file, destination_path)
|
|
151
|
+
|
|
152
|
+
return original_name
|
|
153
|
+
|
|
154
|
+
# Re-raise the original exception if we can't find it locally
|
|
155
|
+
raise Exception(
|
|
156
|
+
f"Attachment with key {key} not found in UiPath or local storage"
|
|
157
|
+
) from e
|
|
113
158
|
|
|
114
159
|
@traced(name="attachments_download", run_type="uipath")
|
|
115
160
|
async def download_async(
|
|
@@ -123,6 +168,12 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
123
168
|
"""Download an attachment asynchronously.
|
|
124
169
|
|
|
125
170
|
This method asynchronously downloads an attachment from UiPath to a local file.
|
|
171
|
+
If the attachment is not found in UiPath (404 error), it will check
|
|
172
|
+
for a local file in the temporary directory that matches the UUID.
|
|
173
|
+
|
|
174
|
+
Note:
|
|
175
|
+
The local file fallback functionality is intended for local development
|
|
176
|
+
and debugging purposes only.
|
|
126
177
|
|
|
127
178
|
Args:
|
|
128
179
|
key (uuid.UUID): The key of the attachment to download.
|
|
@@ -134,7 +185,7 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
134
185
|
str: The name of the downloaded attachment.
|
|
135
186
|
|
|
136
187
|
Raises:
|
|
137
|
-
Exception: If the download fails.
|
|
188
|
+
Exception: If the download fails and no local file is found.
|
|
138
189
|
|
|
139
190
|
Examples:
|
|
140
191
|
```python
|
|
@@ -151,44 +202,77 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
151
202
|
print(f"Downloaded attachment: {attachment_name}")
|
|
152
203
|
```
|
|
153
204
|
"""
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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,
|
|
205
|
+
try:
|
|
206
|
+
spec = self._retrieve_download_uri_spec(
|
|
207
|
+
key=key,
|
|
208
|
+
folder_key=folder_key,
|
|
209
|
+
folder_path=folder_path,
|
|
179
210
|
)
|
|
180
|
-
}
|
|
181
211
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
212
|
+
result = (
|
|
213
|
+
await self.request_async(
|
|
214
|
+
spec.method,
|
|
215
|
+
url=spec.endpoint,
|
|
216
|
+
params=spec.params,
|
|
217
|
+
headers=spec.headers,
|
|
186
218
|
)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
219
|
+
).json()
|
|
220
|
+
|
|
221
|
+
# Get the attachment name
|
|
222
|
+
attachment_name = result["Name"]
|
|
223
|
+
|
|
224
|
+
download_uri = result["BlobFileAccess"]["Uri"]
|
|
225
|
+
headers = {
|
|
226
|
+
key: value
|
|
227
|
+
for key, value in zip(
|
|
228
|
+
result["BlobFileAccess"]["Headers"]["Keys"],
|
|
229
|
+
result["BlobFileAccess"]["Headers"]["Values"],
|
|
230
|
+
strict=False,
|
|
231
|
+
)
|
|
232
|
+
}
|
|
190
233
|
|
|
191
|
-
|
|
234
|
+
with open(destination_path, "wb") as file:
|
|
235
|
+
if result["BlobFileAccess"]["RequiresAuth"]:
|
|
236
|
+
response = await self.request_async(
|
|
237
|
+
"GET", download_uri, headers=headers, stream=True
|
|
238
|
+
)
|
|
239
|
+
async for chunk in response.aiter_bytes(chunk_size=8192):
|
|
240
|
+
file.write(chunk)
|
|
241
|
+
else:
|
|
242
|
+
async with httpx.AsyncClient() as client:
|
|
243
|
+
async with client.stream(
|
|
244
|
+
"GET", download_uri, headers=headers
|
|
245
|
+
) as response:
|
|
246
|
+
async for chunk in response.aiter_bytes(chunk_size=8192):
|
|
247
|
+
file.write(chunk)
|
|
248
|
+
|
|
249
|
+
return attachment_name
|
|
250
|
+
except Exception as e:
|
|
251
|
+
# If not found in UiPath, check local storage
|
|
252
|
+
if "404" in str(e):
|
|
253
|
+
# Check if file exists in temp directory
|
|
254
|
+
if os.path.exists(self._temp_dir):
|
|
255
|
+
# Look for any file starting with our UUID
|
|
256
|
+
pattern = f"{key}_*"
|
|
257
|
+
matching_files = list(Path(self._temp_dir).glob(pattern))
|
|
258
|
+
|
|
259
|
+
if matching_files:
|
|
260
|
+
# Get the full filename
|
|
261
|
+
local_file = matching_files[0]
|
|
262
|
+
|
|
263
|
+
# Extract the original name from the filename (part after UUID_)
|
|
264
|
+
file_name = os.path.basename(local_file)
|
|
265
|
+
original_name = file_name[len(f"{key}_") :]
|
|
266
|
+
|
|
267
|
+
# Copy the file to the destination
|
|
268
|
+
shutil.copy2(local_file, destination_path)
|
|
269
|
+
|
|
270
|
+
return original_name
|
|
271
|
+
|
|
272
|
+
# Re-raise the original exception if we can't find it locally
|
|
273
|
+
raise Exception(
|
|
274
|
+
f"Attachment with key {key} not found in UiPath or local storage"
|
|
275
|
+
) from e
|
|
192
276
|
|
|
193
277
|
@overload
|
|
194
278
|
def upload(
|
|
@@ -305,7 +389,8 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
305
389
|
"PUT", upload_uri, headers=headers, files={"file": file}
|
|
306
390
|
)
|
|
307
391
|
else:
|
|
308
|
-
|
|
392
|
+
with httpx.Client() as client:
|
|
393
|
+
client.put(upload_uri, headers=headers, files={"file": file})
|
|
309
394
|
else:
|
|
310
395
|
# Upload from memory
|
|
311
396
|
# Convert string to bytes if needed
|
|
@@ -315,7 +400,8 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
315
400
|
if result["BlobFileAccess"]["RequiresAuth"]:
|
|
316
401
|
self.request("PUT", upload_uri, headers=headers, content=content)
|
|
317
402
|
else:
|
|
318
|
-
|
|
403
|
+
with httpx.Client() as client:
|
|
404
|
+
client.put(upload_uri, headers=headers, content=content)
|
|
319
405
|
|
|
320
406
|
return attachment_key
|
|
321
407
|
|
|
@@ -438,7 +524,8 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
438
524
|
"PUT", upload_uri, headers=headers, files={"file": file}
|
|
439
525
|
)
|
|
440
526
|
else:
|
|
441
|
-
|
|
527
|
+
with httpx.Client() as client:
|
|
528
|
+
client.put(upload_uri, headers=headers, files={"file": file})
|
|
442
529
|
else:
|
|
443
530
|
# Upload from memory
|
|
444
531
|
# Convert string to bytes if needed
|
|
@@ -450,7 +537,8 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
450
537
|
"PUT", upload_uri, headers=headers, content=content
|
|
451
538
|
)
|
|
452
539
|
else:
|
|
453
|
-
|
|
540
|
+
with httpx.Client() as client:
|
|
541
|
+
client.put(upload_uri, headers=headers, content=content)
|
|
454
542
|
|
|
455
543
|
return attachment_key
|
|
456
544
|
|
|
@@ -465,6 +553,12 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
465
553
|
"""Delete an attachment.
|
|
466
554
|
|
|
467
555
|
This method deletes an attachment from UiPath.
|
|
556
|
+
If the attachment is not found in UiPath (404 error), it will check
|
|
557
|
+
for a local file in the temporary directory that matches the UUID.
|
|
558
|
+
|
|
559
|
+
Note:
|
|
560
|
+
The local file fallback functionality is intended for local development
|
|
561
|
+
and debugging purposes only.
|
|
468
562
|
|
|
469
563
|
Args:
|
|
470
564
|
key (uuid.UUID): The key of the attachment to delete.
|
|
@@ -472,7 +566,7 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
472
566
|
folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
|
|
473
567
|
|
|
474
568
|
Raises:
|
|
475
|
-
Exception: If the deletion fails.
|
|
569
|
+
Exception: If the deletion fails and no local file is found.
|
|
476
570
|
|
|
477
571
|
Examples:
|
|
478
572
|
```python
|
|
@@ -486,17 +580,37 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
486
580
|
print("Attachment deleted successfully")
|
|
487
581
|
```
|
|
488
582
|
"""
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
583
|
+
try:
|
|
584
|
+
spec = self._delete_attachment_spec(
|
|
585
|
+
key=key,
|
|
586
|
+
folder_key=folder_key,
|
|
587
|
+
folder_path=folder_path,
|
|
588
|
+
)
|
|
494
589
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
590
|
+
self.request(
|
|
591
|
+
spec.method,
|
|
592
|
+
url=spec.endpoint,
|
|
593
|
+
headers=spec.headers,
|
|
594
|
+
)
|
|
595
|
+
except Exception as e:
|
|
596
|
+
# If not found in UiPath, check local storage
|
|
597
|
+
if "404" in str(e):
|
|
598
|
+
# Check if file exists in temp directory
|
|
599
|
+
if os.path.exists(self._temp_dir):
|
|
600
|
+
# Look for any file starting with our UUID
|
|
601
|
+
pattern = f"{key}_*"
|
|
602
|
+
matching_files = list(Path(self._temp_dir).glob(pattern))
|
|
603
|
+
|
|
604
|
+
if matching_files:
|
|
605
|
+
# Delete all matching files
|
|
606
|
+
for file_path in matching_files:
|
|
607
|
+
os.remove(file_path)
|
|
608
|
+
return
|
|
609
|
+
|
|
610
|
+
# Re-raise the original exception if we can't find it locally
|
|
611
|
+
raise Exception(
|
|
612
|
+
f"Attachment with key {key} not found in UiPath or local storage"
|
|
613
|
+
) from e
|
|
500
614
|
|
|
501
615
|
@traced(name="attachments_delete", run_type="uipath")
|
|
502
616
|
async def delete_async(
|
|
@@ -509,6 +623,12 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
509
623
|
"""Delete an attachment asynchronously.
|
|
510
624
|
|
|
511
625
|
This method asynchronously deletes an attachment from UiPath.
|
|
626
|
+
If the attachment is not found in UiPath (404 error), it will check
|
|
627
|
+
for a local file in the temporary directory that matches the UUID.
|
|
628
|
+
|
|
629
|
+
Note:
|
|
630
|
+
The local file fallback functionality is intended for local development
|
|
631
|
+
and debugging purposes only.
|
|
512
632
|
|
|
513
633
|
Args:
|
|
514
634
|
key (uuid.UUID): The key of the attachment to delete.
|
|
@@ -516,7 +636,7 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
516
636
|
folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
|
|
517
637
|
|
|
518
638
|
Raises:
|
|
519
|
-
Exception: If the deletion fails.
|
|
639
|
+
Exception: If the deletion fails and no local file is found.
|
|
520
640
|
|
|
521
641
|
Examples:
|
|
522
642
|
```python
|
|
@@ -532,17 +652,37 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
532
652
|
print("Attachment deleted successfully")
|
|
533
653
|
```
|
|
534
654
|
"""
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
655
|
+
try:
|
|
656
|
+
spec = self._delete_attachment_spec(
|
|
657
|
+
key=key,
|
|
658
|
+
folder_key=folder_key,
|
|
659
|
+
folder_path=folder_path,
|
|
660
|
+
)
|
|
540
661
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
662
|
+
await self.request_async(
|
|
663
|
+
spec.method,
|
|
664
|
+
url=spec.endpoint,
|
|
665
|
+
headers=spec.headers,
|
|
666
|
+
)
|
|
667
|
+
except Exception as e:
|
|
668
|
+
# If not found in UiPath, check local storage
|
|
669
|
+
if "404" in str(e):
|
|
670
|
+
# Check if file exists in temp directory
|
|
671
|
+
if os.path.exists(self._temp_dir):
|
|
672
|
+
# Look for any file starting with our UUID
|
|
673
|
+
pattern = f"{key}_*"
|
|
674
|
+
matching_files = list(Path(self._temp_dir).glob(pattern))
|
|
675
|
+
|
|
676
|
+
if matching_files:
|
|
677
|
+
# Delete all matching files
|
|
678
|
+
for file_path in matching_files:
|
|
679
|
+
os.remove(file_path)
|
|
680
|
+
return
|
|
681
|
+
|
|
682
|
+
# Re-raise the original exception if we can't find it locally
|
|
683
|
+
raise Exception(
|
|
684
|
+
f"Attachment with key {key} not found in UiPath or local storage"
|
|
685
|
+
) from e
|
|
546
686
|
|
|
547
687
|
@property
|
|
548
688
|
def custom_headers(self) -> Dict[str, str]:
|