uipath 2.0.0.dev2__py3-none-any.whl → 2.0.1.dev1__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/__init__.py +24 -0
- uipath/_cli/README.md +11 -0
- uipath/_cli/__init__.py +54 -0
- uipath/_cli/_auth/_auth_server.py +165 -0
- uipath/_cli/_auth/_models.py +51 -0
- uipath/_cli/_auth/_oidc_utils.py +69 -0
- uipath/_cli/_auth/_portal_service.py +163 -0
- uipath/_cli/_auth/_utils.py +51 -0
- uipath/_cli/_auth/auth_config.json +6 -0
- uipath/_cli/_auth/index.html +167 -0
- uipath/_cli/_auth/localhost.crt +25 -0
- uipath/_cli/_auth/localhost.key +27 -0
- uipath/_cli/_runtime/_contracts.py +429 -0
- uipath/_cli/_runtime/_logging.py +193 -0
- uipath/_cli/_runtime/_runtime.py +264 -0
- uipath/_cli/_templates/.psmdcp.template +9 -0
- uipath/_cli/_templates/.rels.template +5 -0
- uipath/_cli/_templates/[Content_Types].xml.template +9 -0
- uipath/_cli/_templates/main.py.template +25 -0
- uipath/_cli/_templates/package.nuspec.template +10 -0
- uipath/_cli/_utils/_common.py +24 -0
- uipath/_cli/_utils/_input_args.py +126 -0
- uipath/_cli/_utils/_parse_ast.py +542 -0
- uipath/_cli/cli_auth.py +97 -0
- uipath/_cli/cli_deploy.py +13 -0
- uipath/_cli/cli_init.py +113 -0
- uipath/_cli/cli_new.py +76 -0
- uipath/_cli/cli_pack.py +337 -0
- uipath/_cli/cli_publish.py +113 -0
- uipath/_cli/cli_run.py +133 -0
- uipath/_cli/middlewares.py +113 -0
- uipath/_config.py +6 -0
- uipath/_execution_context.py +83 -0
- uipath/_folder_context.py +62 -0
- uipath/_models/__init__.py +37 -0
- uipath/_models/action_schema.py +26 -0
- uipath/_models/actions.py +64 -0
- uipath/_models/assets.py +48 -0
- uipath/_models/connections.py +51 -0
- uipath/_models/context_grounding.py +18 -0
- uipath/_models/context_grounding_index.py +60 -0
- uipath/_models/exceptions.py +6 -0
- uipath/_models/interrupt_models.py +28 -0
- uipath/_models/job.py +66 -0
- uipath/_models/llm_gateway.py +101 -0
- uipath/_models/processes.py +48 -0
- uipath/_models/queues.py +167 -0
- uipath/_services/__init__.py +26 -0
- uipath/_services/_base_service.py +250 -0
- uipath/_services/actions_service.py +271 -0
- uipath/_services/api_client.py +89 -0
- uipath/_services/assets_service.py +257 -0
- uipath/_services/buckets_service.py +268 -0
- uipath/_services/connections_service.py +185 -0
- uipath/_services/connections_service.pyi +50 -0
- uipath/_services/context_grounding_service.py +402 -0
- uipath/_services/folder_service.py +49 -0
- uipath/_services/jobs_service.py +265 -0
- uipath/_services/llm_gateway_service.py +311 -0
- uipath/_services/processes_service.py +168 -0
- uipath/_services/queues_service.py +314 -0
- uipath/_uipath.py +98 -0
- uipath/_utils/__init__.py +17 -0
- uipath/_utils/_endpoint.py +79 -0
- uipath/_utils/_infer_bindings.py +30 -0
- uipath/_utils/_logs.py +15 -0
- uipath/_utils/_request_override.py +18 -0
- uipath/_utils/_request_spec.py +23 -0
- uipath/_utils/_user_agent.py +16 -0
- uipath/_utils/constants.py +25 -0
- uipath/py.typed +0 -0
- {uipath-2.0.0.dev2.dist-info → uipath-2.0.1.dev1.dist-info}/METADATA +2 -3
- uipath-2.0.1.dev1.dist-info/RECORD +75 -0
- uipath-2.0.0.dev2.dist-info/RECORD +0 -4
- {uipath-2.0.0.dev2.dist-info → uipath-2.0.1.dev1.dist-info}/WHEEL +0 -0
- {uipath-2.0.0.dev2.dist-info → uipath-2.0.1.dev1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
from typing import Dict, Optional
|
|
2
|
+
|
|
3
|
+
from httpx import Response
|
|
4
|
+
|
|
5
|
+
from .._config import Config
|
|
6
|
+
from .._execution_context import ExecutionContext
|
|
7
|
+
from .._folder_context import FolderContext
|
|
8
|
+
from .._models import UserAsset
|
|
9
|
+
from .._utils import Endpoint, RequestSpec, header_folder, infer_bindings
|
|
10
|
+
from ._base_service import BaseService
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AssetsService(FolderContext, BaseService):
|
|
14
|
+
"""Service for managing UiPath assets.
|
|
15
|
+
|
|
16
|
+
Assets are key-value pairs that can be used to store configuration data,
|
|
17
|
+
credentials, and other settings used by automation processes.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, config: Config, execution_context: ExecutionContext) -> None:
|
|
21
|
+
super().__init__(config=config, execution_context=execution_context)
|
|
22
|
+
|
|
23
|
+
@infer_bindings()
|
|
24
|
+
def retrieve(
|
|
25
|
+
self,
|
|
26
|
+
name: str,
|
|
27
|
+
*,
|
|
28
|
+
folder_key: Optional[str] = None,
|
|
29
|
+
folder_path: Optional[str] = None,
|
|
30
|
+
) -> UserAsset:
|
|
31
|
+
"""Retrieve an asset by its name.
|
|
32
|
+
|
|
33
|
+
Related Activity: [Get Asset](https://docs.uipath.com/activities/other/latest/workflow/get-robot-asset)
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
name (str): The name of the asset.
|
|
37
|
+
folder_key (Optional[str]): The key of the folder to execute the process in. Override the default one set in the SDK config.
|
|
38
|
+
folder_path (Optional[str]): The path of the folder to execute the process in. Override the default one set in the SDK config.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
UserAsset: The asset data.
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
```python
|
|
45
|
+
from uipath import UiPath
|
|
46
|
+
|
|
47
|
+
client = UiPath()
|
|
48
|
+
|
|
49
|
+
client.assets.retrieve(name="MyAsset")
|
|
50
|
+
```
|
|
51
|
+
"""
|
|
52
|
+
spec = self._retrieve_spec(name, folder_key=folder_key, folder_path=folder_path)
|
|
53
|
+
response = self.request(
|
|
54
|
+
spec.method, url=spec.endpoint, content=spec.content, headers=spec.headers
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return UserAsset.model_validate(response.json())
|
|
58
|
+
|
|
59
|
+
async def retrieve_async(
|
|
60
|
+
self,
|
|
61
|
+
name: str,
|
|
62
|
+
*,
|
|
63
|
+
folder_key: Optional[str] = None,
|
|
64
|
+
folder_path: Optional[str] = None,
|
|
65
|
+
) -> UserAsset:
|
|
66
|
+
"""Asynchronously retrieve an asset by its name.
|
|
67
|
+
|
|
68
|
+
Related Activity: [Get Asset](https://docs.uipath.com/activities/other/latest/workflow/get-robot-asset)
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
name (str): The name of the asset.
|
|
72
|
+
folder_key (Optional[str]): The key of the folder to execute the process in. Override the default one set in the SDK config.
|
|
73
|
+
folder_path (Optional[str]): The path of the folder to execute the process in. Override the default one set in the SDK config.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
UserAsset: The asset data.
|
|
77
|
+
"""
|
|
78
|
+
spec = self._retrieve_spec(name, folder_key=folder_key, folder_path=folder_path)
|
|
79
|
+
response = await self.request_async(
|
|
80
|
+
spec.method, url=spec.endpoint, content=spec.content, headers=spec.headers
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
return UserAsset.model_validate(response.json())
|
|
84
|
+
|
|
85
|
+
@infer_bindings()
|
|
86
|
+
def retrieve_credential(
|
|
87
|
+
self,
|
|
88
|
+
name: str,
|
|
89
|
+
*,
|
|
90
|
+
folder_key: Optional[str] = None,
|
|
91
|
+
folder_path: Optional[str] = None,
|
|
92
|
+
) -> Optional[str]:
|
|
93
|
+
"""Gets a specified Orchestrator credential.
|
|
94
|
+
|
|
95
|
+
The robot id is retrieved from the execution context (`UIPATH_ROBOT_KEY` environment variable)
|
|
96
|
+
|
|
97
|
+
Related Activity: [Get Credential](https://docs.uipath.com/activities/other/latest/workflow/get-robot-credential)
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
name (str): The name of the credential asset.
|
|
101
|
+
folder_key (Optional[str]): The key of the folder to execute the process in. Override the default one set in the SDK config.
|
|
102
|
+
folder_path (Optional[str]): The path of the folder to execute the process in. Override the default one set in the SDK config.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Optional[str]: The decrypted credential password.
|
|
106
|
+
"""
|
|
107
|
+
spec = self._retrieve_spec(name, folder_key=folder_key, folder_path=folder_path)
|
|
108
|
+
|
|
109
|
+
response = self.request(
|
|
110
|
+
spec.method,
|
|
111
|
+
url=spec.endpoint,
|
|
112
|
+
content=spec.content,
|
|
113
|
+
headers=spec.headers,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
user_asset = UserAsset.model_validate(response.json())
|
|
117
|
+
|
|
118
|
+
return user_asset.credential_password
|
|
119
|
+
|
|
120
|
+
@infer_bindings()
|
|
121
|
+
async def retrieve_credential_async(
|
|
122
|
+
self,
|
|
123
|
+
name: str,
|
|
124
|
+
*,
|
|
125
|
+
folder_key: Optional[str] = None,
|
|
126
|
+
folder_path: Optional[str] = None,
|
|
127
|
+
) -> Optional[str]:
|
|
128
|
+
"""Asynchronously gets a specified Orchestrator credential.
|
|
129
|
+
|
|
130
|
+
The robot id is retrieved from the execution context (`UIPATH_ROBOT_KEY` environment variable)
|
|
131
|
+
|
|
132
|
+
Related Activity: [Get Credential](https://docs.uipath.com/activities/other/latest/workflow/get-robot-credential)
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
name (str): The name of the credential asset.
|
|
136
|
+
folder_key (Optional[str]): The key of the folder to execute the process in. Override the default one set in the SDK config.
|
|
137
|
+
folder_path (Optional[str]): The path of the folder to execute the process in. Override the default one set in the SDK config.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
Optional[str]: The decrypted credential password.
|
|
141
|
+
|
|
142
|
+
"""
|
|
143
|
+
spec = self._retrieve_spec(name, folder_key=folder_key, folder_path=folder_path)
|
|
144
|
+
|
|
145
|
+
response = await self.request_async(
|
|
146
|
+
spec.method,
|
|
147
|
+
url=spec.endpoint,
|
|
148
|
+
content=spec.content,
|
|
149
|
+
headers=spec.headers,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
user_asset = UserAsset.model_validate(response.json())
|
|
153
|
+
|
|
154
|
+
return user_asset.credential_password
|
|
155
|
+
|
|
156
|
+
def update(
|
|
157
|
+
self,
|
|
158
|
+
robot_asset: UserAsset,
|
|
159
|
+
*,
|
|
160
|
+
folder_key: Optional[str] = None,
|
|
161
|
+
folder_path: Optional[str] = None,
|
|
162
|
+
) -> Response:
|
|
163
|
+
"""Update an asset's value.
|
|
164
|
+
|
|
165
|
+
Related Activity: [Set Asset](https://docs.uipath.com/activities/other/latest/workflow/set-asset)
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
robot_asset (UserAsset): The asset object containing the updated values.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Response: The HTTP response confirming the update.
|
|
172
|
+
"""
|
|
173
|
+
spec = self._update_spec(
|
|
174
|
+
robot_asset, folder_key=folder_key, folder_path=folder_path
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
return self.request(
|
|
178
|
+
spec.method,
|
|
179
|
+
url=spec.endpoint,
|
|
180
|
+
content=spec.content,
|
|
181
|
+
headers=spec.headers,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
async def update_async(
|
|
185
|
+
self,
|
|
186
|
+
robot_asset: UserAsset,
|
|
187
|
+
*,
|
|
188
|
+
folder_key: Optional[str] = None,
|
|
189
|
+
folder_path: Optional[str] = None,
|
|
190
|
+
) -> Response:
|
|
191
|
+
"""Asynchronously update an asset's value.
|
|
192
|
+
|
|
193
|
+
Related Activity: [Set Asset](https://docs.uipath.com/activities/other/latest/workflow/set-asset)
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
robot_asset (UserAsset): The asset object containing the updated values.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Response: The HTTP response confirming the update.
|
|
200
|
+
"""
|
|
201
|
+
spec = self._update_spec(
|
|
202
|
+
robot_asset, folder_key=folder_key, folder_path=folder_path
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
return await self.request_async(
|
|
206
|
+
spec.method,
|
|
207
|
+
url=spec.endpoint,
|
|
208
|
+
content=spec.content,
|
|
209
|
+
headers=spec.headers,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def custom_headers(self) -> Dict[str, str]:
|
|
214
|
+
return self.folder_headers
|
|
215
|
+
|
|
216
|
+
def _retrieve_spec(
|
|
217
|
+
self,
|
|
218
|
+
name: str,
|
|
219
|
+
*,
|
|
220
|
+
folder_key: Optional[str] = None,
|
|
221
|
+
folder_path: Optional[str] = None,
|
|
222
|
+
) -> RequestSpec:
|
|
223
|
+
return RequestSpec(
|
|
224
|
+
method="POST",
|
|
225
|
+
endpoint=Endpoint(
|
|
226
|
+
"/orchestrator_/odata/Assets/UiPath.Server.Configuration.OData.GetRobotAssetByNameForRobotKey"
|
|
227
|
+
),
|
|
228
|
+
content=str(
|
|
229
|
+
{"assetName": name, "robotKey": self._execution_context.robot_key}
|
|
230
|
+
),
|
|
231
|
+
headers={
|
|
232
|
+
**header_folder(folder_key, folder_path),
|
|
233
|
+
},
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
def _update_spec(
|
|
237
|
+
self,
|
|
238
|
+
robot_asset: UserAsset,
|
|
239
|
+
*,
|
|
240
|
+
folder_key: Optional[str] = None,
|
|
241
|
+
folder_path: Optional[str] = None,
|
|
242
|
+
) -> RequestSpec:
|
|
243
|
+
return RequestSpec(
|
|
244
|
+
method="POST",
|
|
245
|
+
endpoint=Endpoint(
|
|
246
|
+
"/orchestrator_/odata/Assets/UiPath.Server.Configuration.OData.SetRobotAssetByRobotKey"
|
|
247
|
+
),
|
|
248
|
+
content=str(
|
|
249
|
+
{
|
|
250
|
+
"robotKey": self._execution_context.robot_key,
|
|
251
|
+
"robotAsset": robot_asset,
|
|
252
|
+
}
|
|
253
|
+
),
|
|
254
|
+
headers={
|
|
255
|
+
**header_folder(folder_key, folder_path),
|
|
256
|
+
},
|
|
257
|
+
)
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional, Union
|
|
2
|
+
|
|
3
|
+
from httpx import request
|
|
4
|
+
|
|
5
|
+
from .._config import Config
|
|
6
|
+
from .._execution_context import ExecutionContext
|
|
7
|
+
from .._folder_context import FolderContext
|
|
8
|
+
from .._utils import Endpoint, RequestSpec, infer_bindings
|
|
9
|
+
from ._base_service import BaseService
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BucketsService(FolderContext, BaseService):
|
|
13
|
+
"""Service for managing UiPath storage buckets.
|
|
14
|
+
|
|
15
|
+
Buckets are cloud storage containers that can be used to store and manage files
|
|
16
|
+
used by automation processes.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, config: Config, execution_context: ExecutionContext) -> None:
|
|
20
|
+
super().__init__(config=config, execution_context=execution_context)
|
|
21
|
+
|
|
22
|
+
def download(
|
|
23
|
+
self,
|
|
24
|
+
bucket_key: str,
|
|
25
|
+
blob_file_path: str,
|
|
26
|
+
destination_path: str,
|
|
27
|
+
) -> None:
|
|
28
|
+
"""Download a file from a bucket.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
bucket_key: The key of the bucket
|
|
32
|
+
blob_file_path: The path to the file in the bucket
|
|
33
|
+
destination_path: The local path where the file will be saved
|
|
34
|
+
"""
|
|
35
|
+
bucket = self.retrieve_by_key(bucket_key)
|
|
36
|
+
bucket_id = bucket["Id"]
|
|
37
|
+
|
|
38
|
+
endpoint = Endpoint(
|
|
39
|
+
f"/orchestrator_/odata/Buckets({bucket_id})/UiPath.Server.Configuration.OData.GetReadUri"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
result = self.request("GET", endpoint, params={"path": blob_file_path}).json()
|
|
43
|
+
read_uri = result["Uri"]
|
|
44
|
+
|
|
45
|
+
headers = {
|
|
46
|
+
key: value
|
|
47
|
+
for key, value in zip(
|
|
48
|
+
result["Headers"]["Keys"], result["Headers"]["Values"], strict=False
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
with open(destination_path, "wb") as file:
|
|
53
|
+
# the self.request adds auth bearer token
|
|
54
|
+
if result["RequiresAuth"]:
|
|
55
|
+
file_content = self.request("GET", read_uri, headers=headers).content
|
|
56
|
+
else:
|
|
57
|
+
file_content = request("GET", read_uri, headers=headers).content
|
|
58
|
+
file.write(file_content)
|
|
59
|
+
|
|
60
|
+
def upload(
|
|
61
|
+
self,
|
|
62
|
+
*,
|
|
63
|
+
bucket_key: Optional[str] = None,
|
|
64
|
+
bucket_name: Optional[str] = None,
|
|
65
|
+
blob_file_path: str,
|
|
66
|
+
content_type: str,
|
|
67
|
+
source_path: str,
|
|
68
|
+
) -> None:
|
|
69
|
+
"""Upload a file to a bucket.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
bucket_key: The key of the bucket
|
|
73
|
+
bucket_name: The name of the bucket
|
|
74
|
+
blob_file_path: The path where the file will be stored in the bucket
|
|
75
|
+
content_type: The MIME type of the file
|
|
76
|
+
source_path: The local path of the file to upload
|
|
77
|
+
"""
|
|
78
|
+
if bucket_key:
|
|
79
|
+
bucket = self.retrieve_by_key(bucket_key)
|
|
80
|
+
elif bucket_name:
|
|
81
|
+
bucket = self.retrieve(bucket_name)
|
|
82
|
+
else:
|
|
83
|
+
raise ValueError("Must specify a bucket name or bucket key")
|
|
84
|
+
|
|
85
|
+
bucket_id = bucket["Id"]
|
|
86
|
+
|
|
87
|
+
endpoint = Endpoint(
|
|
88
|
+
f"/orchestrator_/odata/Buckets({bucket_id})/UiPath.Server.Configuration.OData.GetWriteUri"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
result = self.request(
|
|
92
|
+
"GET",
|
|
93
|
+
endpoint,
|
|
94
|
+
params={"path": blob_file_path, "contentType": content_type},
|
|
95
|
+
).json()
|
|
96
|
+
write_uri = result["Uri"]
|
|
97
|
+
|
|
98
|
+
headers = {
|
|
99
|
+
key: value
|
|
100
|
+
for key, value in zip(
|
|
101
|
+
result["Headers"]["Keys"], result["Headers"]["Values"], strict=False
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
with open(source_path, "rb") as file:
|
|
106
|
+
if result["RequiresAuth"]:
|
|
107
|
+
self.request("PUT", write_uri, headers=headers, files={"file": file})
|
|
108
|
+
else:
|
|
109
|
+
request("PUT", write_uri, headers=headers, files={"file": file})
|
|
110
|
+
|
|
111
|
+
def upload_from_memory(
|
|
112
|
+
self,
|
|
113
|
+
*,
|
|
114
|
+
bucket_key: Optional[str] = None,
|
|
115
|
+
bucket_name: Optional[str] = None,
|
|
116
|
+
blob_file_path: str,
|
|
117
|
+
content_type: str,
|
|
118
|
+
content: Union[str, bytes],
|
|
119
|
+
) -> None:
|
|
120
|
+
"""Upload content from memory to a bucket.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
bucket_key: The key of the bucket
|
|
124
|
+
bucket_name: The name of the bucket
|
|
125
|
+
blob_file_path: The path where the content will be stored in the bucket
|
|
126
|
+
content_type: The MIME type of the content
|
|
127
|
+
content: The content to upload (string or bytes)
|
|
128
|
+
"""
|
|
129
|
+
if bucket_key:
|
|
130
|
+
bucket = self.retrieve_by_key(bucket_key)
|
|
131
|
+
elif bucket_name:
|
|
132
|
+
bucket = self.retrieve(bucket_name)
|
|
133
|
+
else:
|
|
134
|
+
raise ValueError("Must specify a bucket name or bucket key")
|
|
135
|
+
|
|
136
|
+
bucket_id = bucket["Id"]
|
|
137
|
+
|
|
138
|
+
endpoint = Endpoint(
|
|
139
|
+
f"/orchestrator_/odata/Buckets({bucket_id})/UiPath.Server.Configuration.OData.GetWriteUri"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
result = self.request(
|
|
143
|
+
"GET",
|
|
144
|
+
endpoint,
|
|
145
|
+
params={"path": blob_file_path, "contentType": content_type},
|
|
146
|
+
).json()
|
|
147
|
+
write_uri = result["Uri"]
|
|
148
|
+
|
|
149
|
+
headers = {
|
|
150
|
+
key: value
|
|
151
|
+
for key, value in zip(
|
|
152
|
+
result["Headers"]["Keys"], result["Headers"]["Values"], strict=False
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# Convert string to bytes if needed
|
|
157
|
+
if isinstance(content, str):
|
|
158
|
+
content = content.encode("utf-8")
|
|
159
|
+
|
|
160
|
+
if result["RequiresAuth"]:
|
|
161
|
+
self.request("PUT", write_uri, headers=headers, content=content)
|
|
162
|
+
else:
|
|
163
|
+
request("PUT", write_uri, headers=headers, content=content)
|
|
164
|
+
|
|
165
|
+
@infer_bindings()
|
|
166
|
+
def retrieve(self, name: str) -> Any:
|
|
167
|
+
"""Retrieve bucket information by its name.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
name (str): The name of the bucket to retrieve.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Response: The HTTP response containing the bucket details, including
|
|
174
|
+
its ID, name, and configuration.
|
|
175
|
+
"""
|
|
176
|
+
spec = self._retrieve_spec(name)
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
response = self.request(
|
|
180
|
+
spec.method,
|
|
181
|
+
url=spec.endpoint,
|
|
182
|
+
params=spec.params,
|
|
183
|
+
)
|
|
184
|
+
except Exception as e:
|
|
185
|
+
raise Exception(f"Bucket with name {name} not found") from e
|
|
186
|
+
|
|
187
|
+
return response.json()["value"][0]
|
|
188
|
+
|
|
189
|
+
@infer_bindings()
|
|
190
|
+
async def retrieve_async(self, name: str) -> Any:
|
|
191
|
+
"""Asynchronously retrieve bucket information by its name.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
name (str): The name of the bucket to retrieve.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Response: The HTTP response containing the bucket details, including
|
|
198
|
+
its ID, name, and configuration.
|
|
199
|
+
"""
|
|
200
|
+
spec = self._retrieve_spec(name)
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
response = await self.request_async(
|
|
204
|
+
spec.method,
|
|
205
|
+
url=spec.endpoint,
|
|
206
|
+
params=spec.params,
|
|
207
|
+
)
|
|
208
|
+
except Exception as e:
|
|
209
|
+
raise Exception(f"Bucket with name {name} not found") from e
|
|
210
|
+
|
|
211
|
+
return response.json()["value"][0]
|
|
212
|
+
|
|
213
|
+
def retrieve_by_key(self, key: str) -> Any:
|
|
214
|
+
"""Retrieve bucket information by its key.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
key (str): The key of the bucket
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
Response: The HTTP response containing the bucket details, including
|
|
221
|
+
its ID, name, and configuration.
|
|
222
|
+
"""
|
|
223
|
+
spec = self._retrieve_by_key_spec(key)
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
response = self.request(spec.method, url=spec.endpoint)
|
|
227
|
+
except Exception as e:
|
|
228
|
+
raise Exception(f"Bucket with key {key} not found") from e
|
|
229
|
+
|
|
230
|
+
return response.json()
|
|
231
|
+
|
|
232
|
+
async def retrieve_by_key_async(self, key: str) -> Any:
|
|
233
|
+
"""Asynchronously retrieve bucket information by its key.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
key (str): The key of the bucket
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
Response: The HTTP response containing the bucket details, including
|
|
240
|
+
its ID, name, and configuration.
|
|
241
|
+
"""
|
|
242
|
+
spec = self._retrieve_by_key_spec(key)
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
response = await self.request_async(spec.method, url=spec.endpoint)
|
|
246
|
+
except Exception as e:
|
|
247
|
+
raise Exception(f"Bucket with key {key} not found") from e
|
|
248
|
+
|
|
249
|
+
return response.json()
|
|
250
|
+
|
|
251
|
+
@property
|
|
252
|
+
def custom_headers(self) -> Dict[str, str]:
|
|
253
|
+
return self.folder_headers
|
|
254
|
+
|
|
255
|
+
def _retrieve_spec(self, name: str) -> RequestSpec:
|
|
256
|
+
return RequestSpec(
|
|
257
|
+
method="GET",
|
|
258
|
+
endpoint=Endpoint("/orchestrator_/odata/Buckets"),
|
|
259
|
+
params={"$filter": f"Name eq '{name}'", "$top": 1},
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
def _retrieve_by_key_spec(self, key: str) -> RequestSpec:
|
|
263
|
+
return RequestSpec(
|
|
264
|
+
method="GET",
|
|
265
|
+
endpoint=Endpoint(
|
|
266
|
+
f"/orchestrator_/odata/Buckets/UiPath.Server.Configuration.OData.GetByKey(identifier={key})"
|
|
267
|
+
),
|
|
268
|
+
)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Any, Dict, Protocol, TypeVar, Union
|
|
4
|
+
|
|
5
|
+
from .._config import Config
|
|
6
|
+
from .._execution_context import ExecutionContext
|
|
7
|
+
from .._models import Connection, ConnectionToken
|
|
8
|
+
from .._utils import Endpoint, RequestSpec
|
|
9
|
+
from .._utils.constants import ENTRYPOINT
|
|
10
|
+
from ._base_service import BaseService
|
|
11
|
+
|
|
12
|
+
T_co = TypeVar("T_co", covariant=True)
|
|
13
|
+
|
|
14
|
+
logger: logging.Logger = logging.getLogger("uipath")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PluginNotFoundError(AttributeError):
|
|
18
|
+
"""Raised when a plugin is not installed or failed to load."""
|
|
19
|
+
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Connector(Protocol[T_co]):
|
|
24
|
+
def __call__(self, *, client: Any, instance_id: Union[str, int]) -> T_co: ...
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ConnectionsService(BaseService):
|
|
28
|
+
"""Service for managing UiPath external service connections.
|
|
29
|
+
|
|
30
|
+
This service provides methods to retrieve and manage connections to external
|
|
31
|
+
systems and services that your automation processes interact with. It supports
|
|
32
|
+
both direct connection information retrieval and secure token management.
|
|
33
|
+
|
|
34
|
+
The service implements a flexible connector system that allows for type-safe
|
|
35
|
+
instantiation of specific service connectors, making it easier to interact
|
|
36
|
+
with different types of external services.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, config: Config, execution_context: ExecutionContext) -> None:
|
|
40
|
+
super().__init__(config=config, execution_context=execution_context)
|
|
41
|
+
self._plugins: Dict[str, Any] = {}
|
|
42
|
+
self._plugins_loaded = False
|
|
43
|
+
self._load_connectors()
|
|
44
|
+
|
|
45
|
+
def __call__(self, connector: Connector[T_co], key: str) -> T_co:
|
|
46
|
+
connection = self.retrieve(key)
|
|
47
|
+
return connector(client=self.client, instance_id=connection.element_instance_id)
|
|
48
|
+
|
|
49
|
+
def __getattr__(self, name: str) -> Any:
|
|
50
|
+
"""Get a plugin by name.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
name: The name of the plugin to get
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
The plugin instance
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
PluginNotFoundError: If the plugin is not installed
|
|
60
|
+
ImportError: If the plugin fails to load
|
|
61
|
+
"""
|
|
62
|
+
if not self._plugins_loaded:
|
|
63
|
+
self._load_connectors()
|
|
64
|
+
|
|
65
|
+
if name in self._plugins:
|
|
66
|
+
return self._plugins[name]
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
plugin: Any = getattr(self.client, name)
|
|
70
|
+
self._plugins[name] = plugin
|
|
71
|
+
return plugin
|
|
72
|
+
except AttributeError as e:
|
|
73
|
+
raise PluginNotFoundError(f"Plugin '{name}' is not installed") from e
|
|
74
|
+
|
|
75
|
+
def retrieve(self, key: str) -> Connection:
|
|
76
|
+
"""Retrieve connection details by its key.
|
|
77
|
+
|
|
78
|
+
This method fetches the configuration and metadata for a connection,
|
|
79
|
+
which can be used to establish communication with an external service.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
key (str): The unique identifier of the connection to retrieve.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Connection: The connection details, including configuration parameters
|
|
86
|
+
and authentication information.
|
|
87
|
+
"""
|
|
88
|
+
spec = self._retrieve_spec(key)
|
|
89
|
+
response = self.request(spec.method, url=spec.endpoint)
|
|
90
|
+
return Connection.model_validate(response.json())
|
|
91
|
+
|
|
92
|
+
async def retrieve_async(self, key: str) -> Connection:
|
|
93
|
+
"""Asynchronously retrieve connection details by its key.
|
|
94
|
+
|
|
95
|
+
This method fetches the configuration and metadata for a connection,
|
|
96
|
+
which can be used to establish communication with an external service.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
key (str): The unique identifier of the connection to retrieve.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Connection: The connection details, including configuration parameters
|
|
103
|
+
and authentication information.
|
|
104
|
+
"""
|
|
105
|
+
spec = self._retrieve_spec(key)
|
|
106
|
+
response = await self.request_async(spec.method, url=spec.endpoint)
|
|
107
|
+
return Connection.model_validate(response.json())
|
|
108
|
+
|
|
109
|
+
def retrieve_token(self, key: str) -> ConnectionToken:
|
|
110
|
+
"""Retrieve an authentication token for a connection.
|
|
111
|
+
|
|
112
|
+
This method obtains a fresh authentication token that can be used to
|
|
113
|
+
communicate with the external service. This is particularly useful for
|
|
114
|
+
services that use token-based authentication.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
key (str): The unique identifier of the connection.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
ConnectionToken: The authentication token details, including the token
|
|
121
|
+
value and any associated metadata.
|
|
122
|
+
"""
|
|
123
|
+
spec = self._retrieve_token_spec(key)
|
|
124
|
+
response = self.request(spec.method, url=spec.endpoint, params=spec.params)
|
|
125
|
+
return ConnectionToken.model_validate(response.json())
|
|
126
|
+
|
|
127
|
+
async def retrieve_token_async(self, key: str) -> ConnectionToken:
|
|
128
|
+
"""Asynchronously retrieve an authentication token for a connection.
|
|
129
|
+
|
|
130
|
+
This method obtains a fresh authentication token that can be used to
|
|
131
|
+
communicate with the external service. This is particularly useful for
|
|
132
|
+
services that use token-based authentication.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
key (str): The unique identifier of the connection.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
ConnectionToken: The authentication token details, including the token
|
|
139
|
+
value and any associated metadata.
|
|
140
|
+
"""
|
|
141
|
+
spec = self._retrieve_token_spec(key)
|
|
142
|
+
response = await self.request_async(
|
|
143
|
+
spec.method, url=spec.endpoint, params=spec.params
|
|
144
|
+
)
|
|
145
|
+
return ConnectionToken.model_validate(response.json())
|
|
146
|
+
|
|
147
|
+
def _retrieve_spec(self, key: str) -> RequestSpec:
|
|
148
|
+
return RequestSpec(
|
|
149
|
+
method="GET",
|
|
150
|
+
endpoint=Endpoint(f"/connections_/api/v1/Connections/{key}"),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def _retrieve_token_spec(self, key: str) -> RequestSpec:
|
|
154
|
+
return RequestSpec(
|
|
155
|
+
method="GET",
|
|
156
|
+
endpoint=Endpoint(f"/connections_/api/v1/Connections/{key}/token"),
|
|
157
|
+
params={"type": "direct"},
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
def _load_connectors(self) -> None:
|
|
161
|
+
"""Load all available connector plugins.
|
|
162
|
+
|
|
163
|
+
Raises:
|
|
164
|
+
ImportError: If a plugin fails to load
|
|
165
|
+
"""
|
|
166
|
+
try:
|
|
167
|
+
entry_points: Any = importlib.metadata.entry_points()
|
|
168
|
+
if hasattr(entry_points, "select"):
|
|
169
|
+
connectors = list(entry_points.select(group=ENTRYPOINT))
|
|
170
|
+
else:
|
|
171
|
+
connectors = list(entry_points.get(ENTRYPOINT, []))
|
|
172
|
+
|
|
173
|
+
for entry_point in connectors:
|
|
174
|
+
try:
|
|
175
|
+
register_func = entry_point.load()
|
|
176
|
+
register_func(self)
|
|
177
|
+
except Exception as e:
|
|
178
|
+
logger.error(
|
|
179
|
+
f"[ERROR] Failed to load plugin {entry_point.name}: {str(e)}"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
self._plugins_loaded = True
|
|
183
|
+
except Exception as e:
|
|
184
|
+
self._plugins_loaded = False
|
|
185
|
+
raise ImportError(f"Failed to load plugins: {str(e)}") from e
|