uipath 2.0.57__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/context_grounding_service.py +5 -2
- uipath/_services/folder_service.py +21 -15
- uipath/_services/jobs_service.py +293 -58
- uipath/_utils/constants.py +3 -0
- uipath/tracing/_utils.py +6 -5
- {uipath-2.0.57.dist-info → uipath-2.0.58.dist-info}/METADATA +1 -1
- {uipath-2.0.57.dist-info → uipath-2.0.58.dist-info}/RECORD +11 -11
- {uipath-2.0.57.dist-info → uipath-2.0.58.dist-info}/WHEEL +0 -0
- {uipath-2.0.57.dist-info → uipath-2.0.58.dist-info}/entry_points.txt +0 -0
- {uipath-2.0.57.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]:
|
|
@@ -3,6 +3,7 @@ from typing import Any, List, Optional, Tuple, Union
|
|
|
3
3
|
|
|
4
4
|
import httpx
|
|
5
5
|
from pydantic import TypeAdapter
|
|
6
|
+
from typing_extensions import deprecated
|
|
6
7
|
|
|
7
8
|
from .._config import Config
|
|
8
9
|
from .._execution_context import ExecutionContext
|
|
@@ -234,6 +235,7 @@ class ContextGroundingService(FolderContext, BaseService):
|
|
|
234
235
|
raise Exception("ContextGroundingIndex not found") from e
|
|
235
236
|
|
|
236
237
|
@traced(name="contextgrounding_retrieve_by_id", run_type="uipath")
|
|
238
|
+
@deprecated("Use retrieve instead")
|
|
237
239
|
def retrieve_by_id(
|
|
238
240
|
self,
|
|
239
241
|
id: str,
|
|
@@ -266,6 +268,7 @@ class ContextGroundingService(FolderContext, BaseService):
|
|
|
266
268
|
).json()
|
|
267
269
|
|
|
268
270
|
@traced(name="contextgrounding_retrieve_by_id", run_type="uipath")
|
|
271
|
+
@deprecated("Use retrieve_async instead")
|
|
269
272
|
async def retrieve_by_id_async(
|
|
270
273
|
self,
|
|
271
274
|
id: str,
|
|
@@ -656,11 +659,11 @@ class ContextGroundingService(FolderContext, BaseService):
|
|
|
656
659
|
|
|
657
660
|
def _resolve_folder_key(self, folder_key, folder_path):
|
|
658
661
|
if folder_key is None and folder_path is not None:
|
|
659
|
-
folder_key = self._folders_service.
|
|
662
|
+
folder_key = self._folders_service.retrieve_key(folder_path=folder_path)
|
|
660
663
|
|
|
661
664
|
if folder_key is None and folder_path is None:
|
|
662
665
|
folder_key = self._folder_key or (
|
|
663
|
-
self._folders_service.
|
|
666
|
+
self._folders_service.retrieve_key(folder_path=self._folder_path)
|
|
664
667
|
if self._folder_path
|
|
665
668
|
else None
|
|
666
669
|
)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
+
from typing_extensions import deprecated
|
|
4
|
+
|
|
3
5
|
from uipath.tracing._traced import traced
|
|
4
6
|
|
|
5
7
|
from .._config import Config
|
|
@@ -8,20 +10,6 @@ from .._utils import Endpoint, RequestSpec
|
|
|
8
10
|
from ._base_service import BaseService
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
def _retrieve_spec(folder_path: str) -> RequestSpec:
|
|
12
|
-
folder_name = folder_path.split("/")[-1]
|
|
13
|
-
return RequestSpec(
|
|
14
|
-
method="GET",
|
|
15
|
-
endpoint=Endpoint(
|
|
16
|
-
"orchestrator_/api/FoldersNavigation/GetFoldersForCurrentUser"
|
|
17
|
-
),
|
|
18
|
-
params={
|
|
19
|
-
"searchText": folder_name,
|
|
20
|
-
"take": 1,
|
|
21
|
-
},
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
|
|
25
13
|
class FolderService(BaseService):
|
|
26
14
|
"""Service for managing UiPath Folders.
|
|
27
15
|
|
|
@@ -34,8 +22,13 @@ class FolderService(BaseService):
|
|
|
34
22
|
super().__init__(config=config, execution_context=execution_context)
|
|
35
23
|
|
|
36
24
|
@traced(name="folder_retrieve_key_by_folder_path", run_type="uipath")
|
|
25
|
+
@deprecated("Use retrieve_key instead")
|
|
37
26
|
def retrieve_key_by_folder_path(self, folder_path: str) -> Optional[str]:
|
|
38
|
-
|
|
27
|
+
return self.retrieve_key(folder_path=folder_path)
|
|
28
|
+
|
|
29
|
+
@traced(name="folder_retrieve_key", run_type="uipath")
|
|
30
|
+
def retrieve_key(self, *, folder_path: str) -> Optional[str]:
|
|
31
|
+
spec = self._retrieve_spec(folder_path)
|
|
39
32
|
response = self.request(
|
|
40
33
|
spec.method,
|
|
41
34
|
url=spec.endpoint,
|
|
@@ -50,3 +43,16 @@ class FolderService(BaseService):
|
|
|
50
43
|
),
|
|
51
44
|
None,
|
|
52
45
|
)
|
|
46
|
+
|
|
47
|
+
def _retrieve_spec(self, folder_path: str) -> RequestSpec:
|
|
48
|
+
folder_name = folder_path.split("/")[-1]
|
|
49
|
+
return RequestSpec(
|
|
50
|
+
method="GET",
|
|
51
|
+
endpoint=Endpoint(
|
|
52
|
+
"orchestrator_/api/FoldersNavigation/GetFoldersForCurrentUser"
|
|
53
|
+
),
|
|
54
|
+
params={
|
|
55
|
+
"searchText": folder_name,
|
|
56
|
+
"take": 1,
|
|
57
|
+
},
|
|
58
|
+
)
|
uipath/_services/jobs_service.py
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
import tempfile
|
|
2
5
|
import uuid
|
|
3
|
-
from
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Dict, List, Optional, Union, cast, overload
|
|
4
8
|
|
|
5
9
|
from .._config import Config
|
|
6
10
|
from .._execution_context import ExecutionContext
|
|
7
11
|
from .._folder_context import FolderContext
|
|
8
12
|
from .._utils import Endpoint, RequestSpec, header_folder
|
|
9
|
-
from ..
|
|
13
|
+
from .._utils.constants import TEMP_ATTACHMENTS_FOLDER
|
|
10
14
|
from ..models.job import Job
|
|
11
15
|
from ..tracing._traced import traced
|
|
12
16
|
from ._base_service import BaseService
|
|
17
|
+
from .attachments_service import AttachmentsService
|
|
13
18
|
|
|
14
19
|
|
|
15
20
|
class JobsService(FolderContext, BaseService):
|
|
@@ -22,6 +27,10 @@ class JobsService(FolderContext, BaseService):
|
|
|
22
27
|
|
|
23
28
|
def __init__(self, config: Config, execution_context: ExecutionContext) -> None:
|
|
24
29
|
super().__init__(config=config, execution_context=execution_context)
|
|
30
|
+
self._attachments_service = AttachmentsService(config, execution_context)
|
|
31
|
+
# Define the temp directory path for local attachments
|
|
32
|
+
self._temp_dir = os.path.join(tempfile.gettempdir(), TEMP_ATTACHMENTS_FOLDER)
|
|
33
|
+
os.makedirs(self._temp_dir, exist_ok=True)
|
|
25
34
|
|
|
26
35
|
@overload
|
|
27
36
|
def resume(self, *, inbox_id: str, payload: Any) -> None: ...
|
|
@@ -212,7 +221,6 @@ class JobsService(FolderContext, BaseService):
|
|
|
212
221
|
|
|
213
222
|
def _extract_first_inbox_id(self, response: Any) -> str:
|
|
214
223
|
if len(response["value"]) > 0:
|
|
215
|
-
# FIXME: is this correct?
|
|
216
224
|
return response["value"][0]["ItemKey"]
|
|
217
225
|
else:
|
|
218
226
|
raise Exception("No inbox found")
|
|
@@ -275,7 +283,7 @@ class JobsService(FolderContext, BaseService):
|
|
|
275
283
|
job_key: uuid.UUID,
|
|
276
284
|
folder_key: Optional[str] = None,
|
|
277
285
|
folder_path: Optional[str] = None,
|
|
278
|
-
) -> List[
|
|
286
|
+
) -> List[str]:
|
|
279
287
|
"""List attachments associated with a specific job.
|
|
280
288
|
|
|
281
289
|
This method retrieves all attachments linked to a job by its key.
|
|
@@ -286,23 +294,10 @@ class JobsService(FolderContext, BaseService):
|
|
|
286
294
|
folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
|
|
287
295
|
|
|
288
296
|
Returns:
|
|
289
|
-
List[
|
|
297
|
+
List[str]: A list of attachment IDs associated with the job.
|
|
290
298
|
|
|
291
299
|
Raises:
|
|
292
300
|
Exception: If the retrieval fails.
|
|
293
|
-
|
|
294
|
-
Examples:
|
|
295
|
-
```python
|
|
296
|
-
from uipath import UiPath
|
|
297
|
-
|
|
298
|
-
client = UiPath()
|
|
299
|
-
|
|
300
|
-
attachments = client.jobs.list_attachments(
|
|
301
|
-
job_key=uuid.UUID("123e4567-e89b-12d3-a456-426614174000")
|
|
302
|
-
)
|
|
303
|
-
for attachment in attachments:
|
|
304
|
-
print(f"Attachment: {attachment.Name}, Key: {attachment.Key}")
|
|
305
|
-
```
|
|
306
301
|
"""
|
|
307
302
|
spec = self._list_job_attachments_spec(
|
|
308
303
|
job_key=job_key,
|
|
@@ -317,7 +312,7 @@ class JobsService(FolderContext, BaseService):
|
|
|
317
312
|
headers=spec.headers,
|
|
318
313
|
).json()
|
|
319
314
|
|
|
320
|
-
return [
|
|
315
|
+
return [item.get("attachmentId") for item in response]
|
|
321
316
|
|
|
322
317
|
@traced(name="jobs_list_attachments", run_type="uipath")
|
|
323
318
|
async def list_attachments_async(
|
|
@@ -326,7 +321,7 @@ class JobsService(FolderContext, BaseService):
|
|
|
326
321
|
job_key: uuid.UUID,
|
|
327
322
|
folder_key: Optional[str] = None,
|
|
328
323
|
folder_path: Optional[str] = None,
|
|
329
|
-
) -> List[
|
|
324
|
+
) -> List[str]:
|
|
330
325
|
"""List attachments associated with a specific job asynchronously.
|
|
331
326
|
|
|
332
327
|
This method asynchronously retrieves all attachments linked to a job by its key.
|
|
@@ -337,7 +332,7 @@ class JobsService(FolderContext, BaseService):
|
|
|
337
332
|
folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
|
|
338
333
|
|
|
339
334
|
Returns:
|
|
340
|
-
List[
|
|
335
|
+
List[str]: A list of attachment IDs associated with the job.
|
|
341
336
|
|
|
342
337
|
Raises:
|
|
343
338
|
Exception: If the retrieval fails.
|
|
@@ -353,8 +348,8 @@ class JobsService(FolderContext, BaseService):
|
|
|
353
348
|
attachments = await client.jobs.list_attachments_async(
|
|
354
349
|
job_key=uuid.UUID("123e4567-e89b-12d3-a456-426614174000")
|
|
355
350
|
)
|
|
356
|
-
for
|
|
357
|
-
print(f"Attachment
|
|
351
|
+
for attachment_id in attachments:
|
|
352
|
+
print(f"Attachment ID: {attachment_id}")
|
|
358
353
|
```
|
|
359
354
|
"""
|
|
360
355
|
spec = self._list_job_attachments_spec(
|
|
@@ -372,7 +367,7 @@ class JobsService(FolderContext, BaseService):
|
|
|
372
367
|
)
|
|
373
368
|
).json()
|
|
374
369
|
|
|
375
|
-
return [
|
|
370
|
+
return [item.get("attachmentId") for item in response]
|
|
376
371
|
|
|
377
372
|
@traced(name="jobs_link_attachment", run_type="uipath")
|
|
378
373
|
def link_attachment(
|
|
@@ -397,20 +392,6 @@ class JobsService(FolderContext, BaseService):
|
|
|
397
392
|
|
|
398
393
|
Raises:
|
|
399
394
|
Exception: If the link operation fails.
|
|
400
|
-
|
|
401
|
-
Examples:
|
|
402
|
-
```python
|
|
403
|
-
from uipath import UiPath
|
|
404
|
-
|
|
405
|
-
client = UiPath()
|
|
406
|
-
|
|
407
|
-
client.jobs.link_attachment(
|
|
408
|
-
attachment_key=uuid.UUID("123e4567-e89b-12d3-a456-426614174000"),
|
|
409
|
-
job_key=uuid.UUID("123e4567-e89b-12d3-a456-426614174001"),
|
|
410
|
-
category="Result"
|
|
411
|
-
)
|
|
412
|
-
print("Attachment linked to job successfully")
|
|
413
|
-
```
|
|
414
395
|
"""
|
|
415
396
|
spec = self._link_job_attachment_spec(
|
|
416
397
|
attachment_key=attachment_key,
|
|
@@ -419,8 +400,7 @@ class JobsService(FolderContext, BaseService):
|
|
|
419
400
|
folder_key=folder_key,
|
|
420
401
|
folder_path=folder_path,
|
|
421
402
|
)
|
|
422
|
-
|
|
423
|
-
return self.request(
|
|
403
|
+
self.request(
|
|
424
404
|
spec.method,
|
|
425
405
|
url=spec.endpoint,
|
|
426
406
|
headers=spec.headers,
|
|
@@ -450,22 +430,6 @@ class JobsService(FolderContext, BaseService):
|
|
|
450
430
|
|
|
451
431
|
Raises:
|
|
452
432
|
Exception: If the link operation fails.
|
|
453
|
-
|
|
454
|
-
Examples:
|
|
455
|
-
```python
|
|
456
|
-
import asyncio
|
|
457
|
-
from uipath import UiPath
|
|
458
|
-
|
|
459
|
-
client = UiPath()
|
|
460
|
-
|
|
461
|
-
async def main():
|
|
462
|
-
await client.jobs.link_attachment_async(
|
|
463
|
-
attachment_key=uuid.UUID("123e4567-e89b-12d3-a456-426614174000"),
|
|
464
|
-
job_key=uuid.UUID("123e4567-e89b-12d3-a456-426614174001"),
|
|
465
|
-
category="Result"
|
|
466
|
-
)
|
|
467
|
-
print("Attachment linked to job successfully")
|
|
468
|
-
```
|
|
469
433
|
"""
|
|
470
434
|
spec = self._link_job_attachment_spec(
|
|
471
435
|
attachment_key=attachment_key,
|
|
@@ -474,8 +438,7 @@ class JobsService(FolderContext, BaseService):
|
|
|
474
438
|
folder_key=folder_key,
|
|
475
439
|
folder_path=folder_path,
|
|
476
440
|
)
|
|
477
|
-
|
|
478
|
-
return await self.request_async(
|
|
441
|
+
await self.request_async(
|
|
479
442
|
spec.method,
|
|
480
443
|
url=spec.endpoint,
|
|
481
444
|
headers=spec.headers,
|
|
@@ -519,3 +482,275 @@ class JobsService(FolderContext, BaseService):
|
|
|
519
482
|
**header_folder(folder_key, folder_path),
|
|
520
483
|
},
|
|
521
484
|
)
|
|
485
|
+
|
|
486
|
+
@traced(name="jobs_create_attachment", run_type="uipath")
|
|
487
|
+
def create_attachment(
|
|
488
|
+
self,
|
|
489
|
+
*,
|
|
490
|
+
name: str,
|
|
491
|
+
content: Optional[Union[str, bytes]] = None,
|
|
492
|
+
source_path: Optional[Union[str, Path]] = None,
|
|
493
|
+
job_key: Optional[Union[str, uuid.UUID]] = None,
|
|
494
|
+
category: Optional[str] = None,
|
|
495
|
+
folder_key: Optional[str] = None,
|
|
496
|
+
folder_path: Optional[str] = None,
|
|
497
|
+
) -> uuid.UUID:
|
|
498
|
+
"""Create and upload an attachment, optionally linking it to a job.
|
|
499
|
+
|
|
500
|
+
This method handles creating an attachment from a file or memory data.
|
|
501
|
+
If a job key is provided or available in the execution context, the attachment
|
|
502
|
+
will be created in UiPath and linked to the job. If no job is available,
|
|
503
|
+
the file will be saved to a temporary storage folder.
|
|
504
|
+
|
|
505
|
+
Note:
|
|
506
|
+
The local storage functionality (when no job is available) is intended for
|
|
507
|
+
local development and debugging purposes only.
|
|
508
|
+
|
|
509
|
+
Args:
|
|
510
|
+
name (str): The name of the attachment file.
|
|
511
|
+
content (Optional[Union[str, bytes]]): The content to upload (string or bytes).
|
|
512
|
+
source_path (Optional[Union[str, Path]]): The local path of the file to upload.
|
|
513
|
+
job_key (Optional[Union[str, uuid.UUID]]): The key of the job to link the attachment to.
|
|
514
|
+
category (Optional[str]): Optional category for the attachment in the context of the job.
|
|
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
|
+
Returns:
|
|
519
|
+
uuid.UUID: The unique identifier for the created attachment, regardless of whether it was
|
|
520
|
+
uploaded to UiPath or stored locally.
|
|
521
|
+
|
|
522
|
+
Raises:
|
|
523
|
+
ValueError: If neither content nor source_path is provided, or if both are provided.
|
|
524
|
+
Exception: If the upload fails.
|
|
525
|
+
|
|
526
|
+
Examples:
|
|
527
|
+
```python
|
|
528
|
+
from uipath import UiPath
|
|
529
|
+
|
|
530
|
+
client = UiPath()
|
|
531
|
+
|
|
532
|
+
# Create attachment from file and link to job
|
|
533
|
+
attachment_id = client.jobs.create_attachment(
|
|
534
|
+
name="document.pdf",
|
|
535
|
+
source_path="path/to/local/document.pdf",
|
|
536
|
+
job_key="38073051"
|
|
537
|
+
)
|
|
538
|
+
print(f"Created and linked attachment: {attachment_id}")
|
|
539
|
+
|
|
540
|
+
# Create attachment from memory content (no job available - saves to temp storage)
|
|
541
|
+
attachment_id = client.jobs.create_attachment(
|
|
542
|
+
name="report.txt",
|
|
543
|
+
content="This is a text report"
|
|
544
|
+
)
|
|
545
|
+
print(f"Created attachment: {attachment_id}")
|
|
546
|
+
```
|
|
547
|
+
"""
|
|
548
|
+
# Validate input parameters
|
|
549
|
+
if not (content or source_path):
|
|
550
|
+
raise ValueError("Content or source_path is required")
|
|
551
|
+
if content and source_path:
|
|
552
|
+
raise ValueError("Content and source_path are mutually exclusive")
|
|
553
|
+
|
|
554
|
+
# Get job key from context if not explicitly provided
|
|
555
|
+
context_job_key = None
|
|
556
|
+
if job_key is None and hasattr(self._execution_context, "job_key"):
|
|
557
|
+
context_job_key = self._execution_context.job_key
|
|
558
|
+
|
|
559
|
+
# Check if a job is available
|
|
560
|
+
if job_key is not None or context_job_key is not None:
|
|
561
|
+
# Job is available - create attachment in UiPath and link to job
|
|
562
|
+
actual_job_key = job_key if job_key is not None else context_job_key
|
|
563
|
+
|
|
564
|
+
# Create the attachment using the attachments service
|
|
565
|
+
if content is not None:
|
|
566
|
+
attachment_key = self._attachments_service.upload(
|
|
567
|
+
name=name,
|
|
568
|
+
content=content,
|
|
569
|
+
folder_key=folder_key,
|
|
570
|
+
folder_path=folder_path,
|
|
571
|
+
)
|
|
572
|
+
else:
|
|
573
|
+
# source_path must be provided due to validation check above
|
|
574
|
+
attachment_key = self._attachments_service.upload(
|
|
575
|
+
name=name,
|
|
576
|
+
source_path=cast(str, source_path),
|
|
577
|
+
folder_key=folder_key,
|
|
578
|
+
folder_path=folder_path,
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
# Convert to UUID if string
|
|
582
|
+
if isinstance(actual_job_key, str):
|
|
583
|
+
actual_job_key = uuid.UUID(actual_job_key)
|
|
584
|
+
|
|
585
|
+
# Link attachment to job
|
|
586
|
+
self.link_attachment(
|
|
587
|
+
attachment_key=attachment_key,
|
|
588
|
+
job_key=cast(uuid.UUID, actual_job_key),
|
|
589
|
+
category=category,
|
|
590
|
+
folder_key=folder_key,
|
|
591
|
+
folder_path=folder_path,
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
return attachment_key
|
|
595
|
+
else:
|
|
596
|
+
# No job available - save to temp folder
|
|
597
|
+
# Generate a UUID to use as identifier
|
|
598
|
+
attachment_id = uuid.uuid4()
|
|
599
|
+
|
|
600
|
+
# Create destination file path
|
|
601
|
+
dest_path = os.path.join(self._temp_dir, f"{attachment_id}_{name}")
|
|
602
|
+
|
|
603
|
+
# If we have source_path, copy the file
|
|
604
|
+
if source_path is not None:
|
|
605
|
+
source_path_str = (
|
|
606
|
+
source_path if isinstance(source_path, str) else str(source_path)
|
|
607
|
+
)
|
|
608
|
+
shutil.copy2(source_path_str, dest_path)
|
|
609
|
+
# If we have content, write it to a file
|
|
610
|
+
elif content is not None:
|
|
611
|
+
# Convert string to bytes if needed
|
|
612
|
+
if isinstance(content, str):
|
|
613
|
+
content = content.encode("utf-8")
|
|
614
|
+
|
|
615
|
+
with open(dest_path, "wb") as f:
|
|
616
|
+
f.write(content)
|
|
617
|
+
|
|
618
|
+
# Return only the UUID
|
|
619
|
+
return attachment_id
|
|
620
|
+
|
|
621
|
+
@traced(name="jobs_create_attachment", run_type="uipath")
|
|
622
|
+
async def create_attachment_async(
|
|
623
|
+
self,
|
|
624
|
+
*,
|
|
625
|
+
name: str,
|
|
626
|
+
content: Optional[Union[str, bytes]] = None,
|
|
627
|
+
source_path: Optional[Union[str, Path]] = None,
|
|
628
|
+
job_key: Optional[Union[str, uuid.UUID]] = None,
|
|
629
|
+
category: Optional[str] = None,
|
|
630
|
+
folder_key: Optional[str] = None,
|
|
631
|
+
folder_path: Optional[str] = None,
|
|
632
|
+
) -> uuid.UUID:
|
|
633
|
+
"""Create and upload an attachment asynchronously, optionally linking it to a job.
|
|
634
|
+
|
|
635
|
+
This method asynchronously handles creating an attachment from a file or memory data.
|
|
636
|
+
If a job key is provided or available in the execution context, the attachment
|
|
637
|
+
will be created in UiPath and linked to the job. If no job is available,
|
|
638
|
+
the file will be saved to a temporary storage folder.
|
|
639
|
+
|
|
640
|
+
Note:
|
|
641
|
+
The local storage functionality (when no job is available) is intended for
|
|
642
|
+
local development and debugging purposes only.
|
|
643
|
+
|
|
644
|
+
Args:
|
|
645
|
+
name (str): The name of the attachment file.
|
|
646
|
+
content (Optional[Union[str, bytes]]): The content to upload (string or bytes).
|
|
647
|
+
source_path (Optional[Union[str, Path]]): The local path of the file to upload.
|
|
648
|
+
job_key (Optional[Union[str, uuid.UUID]]): The key of the job to link the attachment to.
|
|
649
|
+
category (Optional[str]): Optional category for the attachment in the context of the job.
|
|
650
|
+
folder_key (Optional[str]): The key of the folder. Override the default one set in the SDK config.
|
|
651
|
+
folder_path (Optional[str]): The path of the folder. Override the default one set in the SDK config.
|
|
652
|
+
|
|
653
|
+
Returns:
|
|
654
|
+
uuid.UUID: The unique identifier for the created attachment, regardless of whether it was
|
|
655
|
+
uploaded to UiPath or stored locally.
|
|
656
|
+
|
|
657
|
+
Raises:
|
|
658
|
+
ValueError: If neither content nor source_path is provided, or if both are provided.
|
|
659
|
+
Exception: If the upload fails.
|
|
660
|
+
|
|
661
|
+
Examples:
|
|
662
|
+
```python
|
|
663
|
+
import asyncio
|
|
664
|
+
from uipath import UiPath
|
|
665
|
+
|
|
666
|
+
client = UiPath()
|
|
667
|
+
|
|
668
|
+
async def main():
|
|
669
|
+
# Create attachment from file and link to job
|
|
670
|
+
attachment_id = await client.jobs.create_attachment_async(
|
|
671
|
+
name="document.pdf",
|
|
672
|
+
source_path="path/to/local/document.pdf",
|
|
673
|
+
job_key="38073051"
|
|
674
|
+
)
|
|
675
|
+
print(f"Created and linked attachment: {attachment_id}")
|
|
676
|
+
|
|
677
|
+
# Create attachment from memory content (no job available - saves to temp storage)
|
|
678
|
+
attachment_id = await client.jobs.create_attachment_async(
|
|
679
|
+
name="report.txt",
|
|
680
|
+
content="This is a text report"
|
|
681
|
+
)
|
|
682
|
+
print(f"Created attachment: {attachment_id}")
|
|
683
|
+
```
|
|
684
|
+
"""
|
|
685
|
+
# Validate input parameters
|
|
686
|
+
if not (content or source_path):
|
|
687
|
+
raise ValueError("Content or source_path is required")
|
|
688
|
+
if content and source_path:
|
|
689
|
+
raise ValueError("Content and source_path are mutually exclusive")
|
|
690
|
+
|
|
691
|
+
# Get job key from context if not explicitly provided
|
|
692
|
+
context_job_key = None
|
|
693
|
+
if job_key is None and hasattr(self._execution_context, "job_key"):
|
|
694
|
+
context_job_key = self._execution_context.job_key
|
|
695
|
+
|
|
696
|
+
# Check if a job is available
|
|
697
|
+
if job_key is not None or context_job_key is not None:
|
|
698
|
+
# Job is available - create attachment in UiPath and link to job
|
|
699
|
+
actual_job_key = job_key if job_key is not None else context_job_key
|
|
700
|
+
|
|
701
|
+
# Create the attachment using the attachments service
|
|
702
|
+
if content is not None:
|
|
703
|
+
attachment_key = await self._attachments_service.upload_async(
|
|
704
|
+
name=name,
|
|
705
|
+
content=content,
|
|
706
|
+
folder_key=folder_key,
|
|
707
|
+
folder_path=folder_path,
|
|
708
|
+
)
|
|
709
|
+
else:
|
|
710
|
+
# source_path must be provided due to validation check above
|
|
711
|
+
attachment_key = await self._attachments_service.upload_async(
|
|
712
|
+
name=name,
|
|
713
|
+
source_path=cast(str, source_path),
|
|
714
|
+
folder_key=folder_key,
|
|
715
|
+
folder_path=folder_path,
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
# Convert to UUID if string
|
|
719
|
+
if isinstance(actual_job_key, str):
|
|
720
|
+
actual_job_key = uuid.UUID(actual_job_key)
|
|
721
|
+
|
|
722
|
+
# Link attachment to job
|
|
723
|
+
await self.link_attachment_async(
|
|
724
|
+
attachment_key=attachment_key,
|
|
725
|
+
job_key=cast(uuid.UUID, actual_job_key),
|
|
726
|
+
category=category,
|
|
727
|
+
folder_key=folder_key,
|
|
728
|
+
folder_path=folder_path,
|
|
729
|
+
)
|
|
730
|
+
|
|
731
|
+
return attachment_key
|
|
732
|
+
else:
|
|
733
|
+
# No job available - save to temp folder
|
|
734
|
+
# Generate a UUID to use as identifier
|
|
735
|
+
attachment_id = uuid.uuid4()
|
|
736
|
+
|
|
737
|
+
# Create destination file path
|
|
738
|
+
dest_path = os.path.join(self._temp_dir, f"{attachment_id}_{name}")
|
|
739
|
+
|
|
740
|
+
# If we have source_path, copy the file
|
|
741
|
+
if source_path is not None:
|
|
742
|
+
source_path_str = (
|
|
743
|
+
source_path if isinstance(source_path, str) else str(source_path)
|
|
744
|
+
)
|
|
745
|
+
shutil.copy2(source_path_str, dest_path)
|
|
746
|
+
# If we have content, write it to a file
|
|
747
|
+
elif content is not None:
|
|
748
|
+
# Convert string to bytes if needed
|
|
749
|
+
if isinstance(content, str):
|
|
750
|
+
content = content.encode("utf-8")
|
|
751
|
+
|
|
752
|
+
with open(dest_path, "wb") as f:
|
|
753
|
+
f.write(content)
|
|
754
|
+
|
|
755
|
+
# Return only the UUID
|
|
756
|
+
return attachment_id
|
uipath/_utils/constants.py
CHANGED
uipath/tracing/_utils.py
CHANGED
|
@@ -134,16 +134,17 @@ class _SpanUtils:
|
|
|
134
134
|
if otel_span.parent is not None:
|
|
135
135
|
parent_id = _SpanUtils.span_id_to_uuid4(otel_span.parent.span_id)
|
|
136
136
|
|
|
137
|
-
# Map status
|
|
138
|
-
status = 1 # Default to OK
|
|
139
|
-
if otel_span.status.status_code == StatusCode.ERROR:
|
|
140
|
-
status = 2 # Error
|
|
141
|
-
|
|
142
137
|
# Convert attributes to a format compatible with UiPathSpan
|
|
143
138
|
attributes_dict: dict[str, Any] = (
|
|
144
139
|
dict(otel_span.attributes) if otel_span.attributes else {}
|
|
145
140
|
)
|
|
146
141
|
|
|
142
|
+
# Map status
|
|
143
|
+
status = 1 # Default to OK
|
|
144
|
+
if otel_span.status.status_code == StatusCode.ERROR:
|
|
145
|
+
status = 2 # Error
|
|
146
|
+
attributes_dict["error"] = otel_span.status.description
|
|
147
|
+
|
|
147
148
|
original_inputs = attributes_dict.get("inputs", None)
|
|
148
149
|
original_outputs = attributes_dict.get("outputs", None)
|
|
149
150
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: uipath
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.58
|
|
4
4
|
Summary: Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools.
|
|
5
5
|
Project-URL: Homepage, https://uipath.com
|
|
6
6
|
Project-URL: Repository, https://github.com/UiPath/uipath-python
|
|
@@ -44,12 +44,12 @@ uipath/_services/_base_service.py,sha256=y-QATIRF9JnUFKIwmjOWMHlE2BrJYgD8y4sGAve
|
|
|
44
44
|
uipath/_services/actions_service.py,sha256=LYKvG4VxNGQgZ46AzGK9kI1Txb-YmVvZj5ScPOue8Ls,15989
|
|
45
45
|
uipath/_services/api_client.py,sha256=hcof0EMa4-phEHD1WlO7Tdfzq6aL18Sbi2aBE7lJm1w,1821
|
|
46
46
|
uipath/_services/assets_service.py,sha256=gfQLCchT6evsmhip1-coX6oFbshoKUWlxwGrS6DGcHU,13200
|
|
47
|
-
uipath/_services/attachments_service.py,sha256=
|
|
47
|
+
uipath/_services/attachments_service.py,sha256=h2pEm5YcW0x5F6Ti3CKB7ufg2FBE7MYhyc1mRmuKca4,26372
|
|
48
48
|
uipath/_services/buckets_service.py,sha256=736isvj01_-Srh0JiorS02pOwjF0_Loaf-xR6u0B7Ww,14932
|
|
49
49
|
uipath/_services/connections_service.py,sha256=qh-HNL_GJsyPUD0wSJZRF8ZdrTE9l4HrIilmXGK6dDk,4581
|
|
50
|
-
uipath/_services/context_grounding_service.py,sha256=
|
|
51
|
-
uipath/_services/folder_service.py,sha256=
|
|
52
|
-
uipath/_services/jobs_service.py,sha256=
|
|
50
|
+
uipath/_services/context_grounding_service.py,sha256=Dd3mlsZB2CpZZLQ-1fBa6FygoSXZfeEDeZ7o4cDXnNY,24193
|
|
51
|
+
uipath/_services/folder_service.py,sha256=h0CWNqF2-8w2QLrfy-D8P3z_qA81Te689OXlFKtnby0,2001
|
|
52
|
+
uipath/_services/jobs_service.py,sha256=I2-iqjMJcfgz5sgVOMWF5PkGzch_1q1swUstdv2PpMo,27308
|
|
53
53
|
uipath/_services/llm_gateway_service.py,sha256=ySg3sflIoXmY9K7txlSm7bkuI2qzBT0kAKmGlFBk5KA,12032
|
|
54
54
|
uipath/_services/processes_service.py,sha256=12tflrzTNvtA0xGteQwrIZ0s-jCTinTv7gktder5tRE,5659
|
|
55
55
|
uipath/_services/queues_service.py,sha256=VaG3dWL2QK6AJBOLoW2NQTpkPfZjsqsYPl9-kfXPFzA,13534
|
|
@@ -62,7 +62,7 @@ uipath/_utils/_request_override.py,sha256=fIVHzgHVXITUlWcp8osNBwIafM1qm4_ejx0ng5
|
|
|
62
62
|
uipath/_utils/_request_spec.py,sha256=iCtBLqtbWUpFG5g1wtIZBzSupKsfaRLiQFoFc_4B70Q,747
|
|
63
63
|
uipath/_utils/_url.py,sha256=-4eluSrIZCUlnQ3qU17WPJkgaC2KwF9W5NeqGnTNGGo,2512
|
|
64
64
|
uipath/_utils/_user_agent.py,sha256=pVJkFYacGwaQBomfwWVAvBQgdBUo62e4n3-fLIajWUU,563
|
|
65
|
-
uipath/_utils/constants.py,sha256=
|
|
65
|
+
uipath/_utils/constants.py,sha256=fApisQxldGrnOFqwCLrQyNxBsReNBnCsp_9cmmL45s4,937
|
|
66
66
|
uipath/models/__init__.py,sha256=Kwqv1LzWNfSxJLMQrInVen3KDJ1z0eCcr6szQa0G0VE,1251
|
|
67
67
|
uipath/models/action_schema.py,sha256=lKDhP7Eix23fFvfQrqqNmSOiPyyNF6tiRpUu0VZIn_M,714
|
|
68
68
|
uipath/models/actions.py,sha256=ekSH4YUQR4KPOH-heBm9yOgOfirndx0In4_S4VYWeEU,2993
|
|
@@ -85,9 +85,9 @@ uipath/telemetry/_track.py,sha256=v0e3hgwtetMsUco4yosBzNU00Ek5SI9RxUTumrTTNyo,38
|
|
|
85
85
|
uipath/tracing/__init__.py,sha256=GimSzv6qkCOlHOG1WtjYKJsZqcXpA28IgoXfR33JhiA,139
|
|
86
86
|
uipath/tracing/_otel_exporters.py,sha256=x0PDPmDKJcxashsuehVsSsqBCzRr6WsNFaq_3_HS5F0,3014
|
|
87
87
|
uipath/tracing/_traced.py,sha256=GFxOp73jk0vGTN_H7YZOOsEl9rVLaEhXGztMiYKIA-8,16634
|
|
88
|
-
uipath/tracing/_utils.py,sha256=
|
|
89
|
-
uipath-2.0.
|
|
90
|
-
uipath-2.0.
|
|
91
|
-
uipath-2.0.
|
|
92
|
-
uipath-2.0.
|
|
93
|
-
uipath-2.0.
|
|
88
|
+
uipath/tracing/_utils.py,sha256=s0fQPlkrnd484_pcHuNvW6-ElHiZH8mkfMkYFBfwnCQ,10234
|
|
89
|
+
uipath-2.0.58.dist-info/METADATA,sha256=eRDwcjhk6BZCe6_XZs9IOyaOus8gNczSFlxMWusXAr8,6304
|
|
90
|
+
uipath-2.0.58.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
91
|
+
uipath-2.0.58.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
|
|
92
|
+
uipath-2.0.58.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
|
|
93
|
+
uipath-2.0.58.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|