uipath 2.1.93__py3-none-any.whl → 2.1.95__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/_cli/__init__.py +2 -1
- uipath/_cli/_debug/_bridge.py +416 -0
- uipath/_cli/_debug/_runtime.py +134 -0
- uipath/_cli/_runtime/_contracts.py +8 -2
- uipath/_cli/_runtime/_runtime.py +0 -5
- uipath/_cli/cli_debug.py +142 -0
- uipath/_cli/cli_run.py +6 -1
- uipath/_cli/middlewares.py +1 -0
- {uipath-2.1.93.dist-info → uipath-2.1.95.dist-info}/METADATA +2 -1
- {uipath-2.1.93.dist-info → uipath-2.1.95.dist-info}/RECORD +13 -10
- {uipath-2.1.93.dist-info → uipath-2.1.95.dist-info}/WHEEL +0 -0
- {uipath-2.1.93.dist-info → uipath-2.1.95.dist-info}/entry_points.txt +0 -0
- {uipath-2.1.93.dist-info → uipath-2.1.95.dist-info}/licenses/LICENSE +0 -0
uipath/_cli/__init__.py
CHANGED
|
@@ -5,6 +5,7 @@ import click
|
|
|
5
5
|
|
|
6
6
|
from ._utils._common import add_cwd_to_path, load_environment_variables
|
|
7
7
|
from .cli_auth import auth as auth
|
|
8
|
+
from .cli_debug import debug as debug # type: ignore
|
|
8
9
|
from .cli_deploy import deploy as deploy # type: ignore
|
|
9
10
|
from .cli_dev import dev as dev
|
|
10
11
|
from .cli_eval import eval as eval # type: ignore
|
|
@@ -74,4 +75,4 @@ cli.add_command(push)
|
|
|
74
75
|
cli.add_command(pull)
|
|
75
76
|
cli.add_command(eval)
|
|
76
77
|
cli.add_command(dev)
|
|
77
|
-
cli.add_command(
|
|
78
|
+
cli.add_command(debug)
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from typing import Any, Dict, Optional
|
|
7
|
+
|
|
8
|
+
from pysignalr.client import SignalRClient
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.syntax import Syntax
|
|
11
|
+
|
|
12
|
+
from uipath._cli._runtime._contracts import (
|
|
13
|
+
UiPathBreakpointResult,
|
|
14
|
+
UiPathRuntimeContext,
|
|
15
|
+
UiPathRuntimeResult,
|
|
16
|
+
)
|
|
17
|
+
from uipath._events._events import UiPathAgentStateEvent
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class UiPathDebugBridge(ABC):
|
|
23
|
+
"""Abstract interface for debug communication.
|
|
24
|
+
|
|
25
|
+
Implementations: SignalR, Console, WebSocket, etc.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
async def connect(self) -> None:
|
|
30
|
+
"""Establish connection to debugger."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
async def disconnect(self) -> None:
|
|
35
|
+
"""Close connection to debugger."""
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
async def emit_execution_started(self, execution_id: str, **kwargs) -> None:
|
|
40
|
+
"""Notify debugger that execution started."""
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
@abstractmethod
|
|
44
|
+
async def emit_state_update(self, state_event: UiPathAgentStateEvent) -> None:
|
|
45
|
+
"""Notify debugger of agent state update."""
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
async def emit_breakpoint_hit(
|
|
50
|
+
self, breakpoint_result: UiPathBreakpointResult
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Notify debugger that a breakpoint was hit."""
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
async def emit_execution_completed(
|
|
57
|
+
self,
|
|
58
|
+
runtime_result: UiPathRuntimeResult,
|
|
59
|
+
) -> None:
|
|
60
|
+
"""Notify debugger that execution completed."""
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
@abstractmethod
|
|
64
|
+
async def emit_execution_error(
|
|
65
|
+
self,
|
|
66
|
+
execution_id: str,
|
|
67
|
+
error: str,
|
|
68
|
+
) -> None:
|
|
69
|
+
"""Notify debugger that an error occurred."""
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
@abstractmethod
|
|
73
|
+
async def wait_for_resume(self) -> Any:
|
|
74
|
+
"""Wait for resume command from debugger."""
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class ConsoleDebugBridge(UiPathDebugBridge):
|
|
79
|
+
"""Console-based debug bridge for local development."""
|
|
80
|
+
|
|
81
|
+
def __init__(self, verbose: bool = True):
|
|
82
|
+
"""Initialize console debug bridge.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
verbose: If True, show state updates. If False, only show breakpoints.
|
|
86
|
+
"""
|
|
87
|
+
self.console = Console()
|
|
88
|
+
self.verbose = verbose
|
|
89
|
+
|
|
90
|
+
async def connect(self) -> None:
|
|
91
|
+
"""Connect to console debugger."""
|
|
92
|
+
self.console.print()
|
|
93
|
+
self.console.print("[bold cyan]─" * 40)
|
|
94
|
+
self.console.print("[bold cyan]Debug Mode")
|
|
95
|
+
self.console.print("[dim]Press ENTER to continue | Type 'quit' to exit")
|
|
96
|
+
self.console.print("[bold cyan]─" * 40)
|
|
97
|
+
self.console.print()
|
|
98
|
+
|
|
99
|
+
async def disconnect(self) -> None:
|
|
100
|
+
"""Cleanup."""
|
|
101
|
+
self.console.print()
|
|
102
|
+
self.console.print("[dim]─" * 40)
|
|
103
|
+
self.console.print("[green]Debug session completed")
|
|
104
|
+
self.console.print("[dim]─" * 40)
|
|
105
|
+
|
|
106
|
+
async def emit_execution_started(self, execution_id: str, **kwargs) -> None:
|
|
107
|
+
"""Print execution started."""
|
|
108
|
+
self.console.print("[green]▶ Started[/green] [dim]")
|
|
109
|
+
self.console.print()
|
|
110
|
+
|
|
111
|
+
async def emit_state_update(self, state_event: UiPathAgentStateEvent) -> None:
|
|
112
|
+
"""Print agent state update."""
|
|
113
|
+
if not self.verbose:
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
self.console.print(f"[yellow]●[/yellow] [bold]{state_event.node_name}[/bold]")
|
|
117
|
+
if state_event.payload:
|
|
118
|
+
self._print_json(state_event.payload, label="State")
|
|
119
|
+
|
|
120
|
+
async def emit_breakpoint_hit(
|
|
121
|
+
self, breakpoint_result: UiPathBreakpointResult
|
|
122
|
+
) -> None:
|
|
123
|
+
"""Print breakpoint info."""
|
|
124
|
+
self.console.print()
|
|
125
|
+
self.console.print("[red]─" * 40)
|
|
126
|
+
self.console.print(
|
|
127
|
+
f"[red]■ BREAKPOINT[/red] [bold]{breakpoint_result.breakpoint_node}[/bold] "
|
|
128
|
+
f"[dim]({breakpoint_result.breakpoint_type})"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if breakpoint_result.next_nodes:
|
|
132
|
+
self.console.print(f"[dim]Next: {', '.join(breakpoint_result.next_nodes)}")
|
|
133
|
+
|
|
134
|
+
self.console.print("[red]─" * 40)
|
|
135
|
+
|
|
136
|
+
# Display current state
|
|
137
|
+
if breakpoint_result.current_state:
|
|
138
|
+
self._print_json(breakpoint_result.current_state, label="State")
|
|
139
|
+
|
|
140
|
+
async def emit_execution_completed(
|
|
141
|
+
self,
|
|
142
|
+
runtime_result: "UiPathRuntimeResult",
|
|
143
|
+
) -> None:
|
|
144
|
+
"""Print completion."""
|
|
145
|
+
self.console.print()
|
|
146
|
+
|
|
147
|
+
status_upper = runtime_result.status.value.upper()
|
|
148
|
+
if status_upper == "SUCCESSFUL":
|
|
149
|
+
color = "green"
|
|
150
|
+
symbol = "✓"
|
|
151
|
+
elif status_upper == "SUSPENDED":
|
|
152
|
+
color = "yellow"
|
|
153
|
+
symbol = "■"
|
|
154
|
+
else:
|
|
155
|
+
color = "blue"
|
|
156
|
+
symbol = "●"
|
|
157
|
+
|
|
158
|
+
self.console.print(
|
|
159
|
+
f"[{color}]{symbol} Completed[/{color}] [bold]{status_upper}[/bold]"
|
|
160
|
+
)
|
|
161
|
+
if runtime_result.output:
|
|
162
|
+
self._print_json(runtime_result.output, label="Output")
|
|
163
|
+
|
|
164
|
+
async def emit_execution_error(
|
|
165
|
+
self,
|
|
166
|
+
execution_id: str,
|
|
167
|
+
error: str,
|
|
168
|
+
) -> None:
|
|
169
|
+
"""Print error."""
|
|
170
|
+
self.console.print()
|
|
171
|
+
self.console.print("[red]─" * 40)
|
|
172
|
+
self.console.print(f"[red]✗ Error[/red] [dim]{execution_id}")
|
|
173
|
+
self.console.print("[red]─" * 40)
|
|
174
|
+
|
|
175
|
+
# Truncate very long errors
|
|
176
|
+
error_display = error
|
|
177
|
+
if len(error) > 500:
|
|
178
|
+
error_display = error[:500] + "\n[dim]... (truncated)"
|
|
179
|
+
|
|
180
|
+
self.console.print(f"[white]{error_display}[/white]")
|
|
181
|
+
self.console.print("[red]─" * 40)
|
|
182
|
+
|
|
183
|
+
async def wait_for_resume(self) -> Any:
|
|
184
|
+
"""Wait for user to press Enter or type commands."""
|
|
185
|
+
self.console.print()
|
|
186
|
+
self.console.print("[cyan]> [/cyan]", end="")
|
|
187
|
+
|
|
188
|
+
# Run input() in executor to not block async loop
|
|
189
|
+
loop = asyncio.get_running_loop()
|
|
190
|
+
user_input = await loop.run_in_executor(None, input)
|
|
191
|
+
|
|
192
|
+
if user_input.strip().lower() == "quit":
|
|
193
|
+
raise KeyboardInterrupt("User requested exit")
|
|
194
|
+
|
|
195
|
+
self.console.print()
|
|
196
|
+
return user_input
|
|
197
|
+
|
|
198
|
+
def _print_json(self, data: Dict[str, Any], label: str = "Data") -> None:
|
|
199
|
+
"""Print JSON data in a readable format."""
|
|
200
|
+
try:
|
|
201
|
+
json_str = json.dumps(data, indent=2, default=str)
|
|
202
|
+
|
|
203
|
+
# Limit output if too large
|
|
204
|
+
is_truncated = False
|
|
205
|
+
if len(json_str) > 2000:
|
|
206
|
+
json_str = json_str[:2000] + "\n..."
|
|
207
|
+
is_truncated = True
|
|
208
|
+
|
|
209
|
+
syntax = Syntax(
|
|
210
|
+
json_str,
|
|
211
|
+
"json",
|
|
212
|
+
theme="monokai",
|
|
213
|
+
line_numbers=False,
|
|
214
|
+
background_color="default",
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
self.console.print()
|
|
218
|
+
truncated_text = " (truncated)" if is_truncated else ""
|
|
219
|
+
self.console.print(f"[dim]{label}{truncated_text}:")
|
|
220
|
+
self.console.print(syntax)
|
|
221
|
+
self.console.print()
|
|
222
|
+
except Exception:
|
|
223
|
+
# Fallback to simple print
|
|
224
|
+
self.console.print()
|
|
225
|
+
self.console.print(f"[dim]{label}:")
|
|
226
|
+
self.console.print(str(data))
|
|
227
|
+
self.console.print()
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class SignalRDebugBridge(UiPathDebugBridge):
|
|
231
|
+
"""SignalR-based debug bridge for remote debugging.
|
|
232
|
+
|
|
233
|
+
Communicates with a SignalR hub server.
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
def __init__(
|
|
237
|
+
self,
|
|
238
|
+
hub_url: str,
|
|
239
|
+
access_token: Optional[str] = None,
|
|
240
|
+
headers: Optional[Dict[str, str]] = None,
|
|
241
|
+
):
|
|
242
|
+
self.hub_url = hub_url
|
|
243
|
+
self.access_token = access_token
|
|
244
|
+
self.headers = headers or {}
|
|
245
|
+
self._client: Optional[SignalRClient] = None
|
|
246
|
+
self._connected_event = asyncio.Event()
|
|
247
|
+
self._resume_event: Optional[asyncio.Event] = None
|
|
248
|
+
self._resume_data: Any = None
|
|
249
|
+
|
|
250
|
+
async def connect(self) -> None:
|
|
251
|
+
"""Establish SignalR connection."""
|
|
252
|
+
all_headers = {**self.headers}
|
|
253
|
+
if self.access_token:
|
|
254
|
+
all_headers["Authorization"] = f"Bearer {self.access_token}"
|
|
255
|
+
|
|
256
|
+
self._client = SignalRClient(self.hub_url, headers=all_headers)
|
|
257
|
+
|
|
258
|
+
# Register event handlers
|
|
259
|
+
self._client.on("ResumeExecution", self._handle_resume)
|
|
260
|
+
self._client.on_open(self._handle_open)
|
|
261
|
+
self._client.on_close(self._handle_close)
|
|
262
|
+
self._client.on_error(self._handle_error)
|
|
263
|
+
|
|
264
|
+
# Start connection in background
|
|
265
|
+
asyncio.create_task(self._client.run())
|
|
266
|
+
|
|
267
|
+
# Wait for connection to establish
|
|
268
|
+
await asyncio.wait_for(self._connected_event.wait(), timeout=30.0)
|
|
269
|
+
|
|
270
|
+
async def disconnect(self) -> None:
|
|
271
|
+
"""Close SignalR connection."""
|
|
272
|
+
if self._client and hasattr(self._client, "_transport"):
|
|
273
|
+
transport = self._client._transport
|
|
274
|
+
if transport and hasattr(transport, "_ws") and transport._ws:
|
|
275
|
+
try:
|
|
276
|
+
await transport._ws.close()
|
|
277
|
+
except Exception as e:
|
|
278
|
+
logger.warning(f"Error closing SignalR WebSocket: {e}")
|
|
279
|
+
|
|
280
|
+
async def emit_execution_started(self, execution_id: str, **kwargs) -> None:
|
|
281
|
+
"""Send execution started event."""
|
|
282
|
+
logger.info(f"Execution started: {execution_id}")
|
|
283
|
+
await self._send("OnExecutionStarted", {"executionId": execution_id, **kwargs})
|
|
284
|
+
|
|
285
|
+
async def emit_state_update(self, state_event: UiPathAgentStateEvent) -> None:
|
|
286
|
+
"""Send agent state update to remote debugger."""
|
|
287
|
+
logger.info(f"State update: {state_event.node_name}")
|
|
288
|
+
await self._send(
|
|
289
|
+
"OnStateUpdate",
|
|
290
|
+
{
|
|
291
|
+
"executionId": state_event.execution_id,
|
|
292
|
+
"nodeName": state_event.node_name,
|
|
293
|
+
"state": state_event.payload,
|
|
294
|
+
},
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
async def emit_breakpoint_hit(
|
|
298
|
+
self, breakpoint_result: UiPathBreakpointResult
|
|
299
|
+
) -> None:
|
|
300
|
+
"""Send breakpoint hit event."""
|
|
301
|
+
logger.info(
|
|
302
|
+
f"Breakpoint hit: {breakpoint_result.breakpoint_node} "
|
|
303
|
+
f"({breakpoint_result.breakpoint_type})"
|
|
304
|
+
)
|
|
305
|
+
await self._send(
|
|
306
|
+
"OnBreakpointHit",
|
|
307
|
+
{
|
|
308
|
+
"node": breakpoint_result.breakpoint_node,
|
|
309
|
+
"type": breakpoint_result.breakpoint_type,
|
|
310
|
+
"state": breakpoint_result.current_state,
|
|
311
|
+
"nextNodes": breakpoint_result.next_nodes,
|
|
312
|
+
},
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
async def emit_execution_completed(
|
|
316
|
+
self,
|
|
317
|
+
runtime_result: UiPathRuntimeResult,
|
|
318
|
+
) -> None:
|
|
319
|
+
"""Send execution completed event."""
|
|
320
|
+
logger.info(f"Execution completed: {runtime_result.status}")
|
|
321
|
+
await self._send(
|
|
322
|
+
"OnExecutionCompleted",
|
|
323
|
+
{
|
|
324
|
+
"status": runtime_result.status,
|
|
325
|
+
},
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
async def emit_execution_error(
|
|
329
|
+
self,
|
|
330
|
+
execution_id: str,
|
|
331
|
+
error: str,
|
|
332
|
+
) -> None:
|
|
333
|
+
"""Send execution error event."""
|
|
334
|
+
logger.error(f"Execution error: {execution_id} - {error}")
|
|
335
|
+
await self._send(
|
|
336
|
+
"OnExecutionError",
|
|
337
|
+
{
|
|
338
|
+
"executionId": execution_id,
|
|
339
|
+
"error": error,
|
|
340
|
+
},
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
async def wait_for_resume(self) -> Any:
|
|
344
|
+
"""Wait for resume command from server."""
|
|
345
|
+
logger.info("Waiting for resume command...")
|
|
346
|
+
self._resume_event = asyncio.Event()
|
|
347
|
+
await self._resume_event.wait()
|
|
348
|
+
logger.info("Resume command received")
|
|
349
|
+
return self._resume_data
|
|
350
|
+
|
|
351
|
+
async def _send(self, method: str, data: Dict[str, Any]) -> None:
|
|
352
|
+
"""Send message to SignalR hub."""
|
|
353
|
+
if not self._client:
|
|
354
|
+
raise RuntimeError("SignalR client not connected")
|
|
355
|
+
|
|
356
|
+
await self._client.send(method=method, arguments=[data])
|
|
357
|
+
|
|
358
|
+
async def _handle_resume(self, args: list[Any]) -> None:
|
|
359
|
+
"""Handle resume command from SignalR server."""
|
|
360
|
+
if self._resume_event and len(args) > 0:
|
|
361
|
+
self._resume_data = args[0]
|
|
362
|
+
self._resume_event.set()
|
|
363
|
+
|
|
364
|
+
async def _handle_open(self) -> None:
|
|
365
|
+
"""Handle SignalR connection open."""
|
|
366
|
+
logger.info("SignalR connection established")
|
|
367
|
+
self._connected_event.set()
|
|
368
|
+
|
|
369
|
+
async def _handle_close(self) -> None:
|
|
370
|
+
"""Handle SignalR connection close."""
|
|
371
|
+
logger.info("SignalR connection closed")
|
|
372
|
+
self._connected_event.clear()
|
|
373
|
+
|
|
374
|
+
async def _handle_error(self, error: Any) -> None:
|
|
375
|
+
"""Handle SignalR error."""
|
|
376
|
+
logger.error(f"SignalR error: {error}")
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def get_remote_debug_bridge(context: UiPathRuntimeContext) -> UiPathDebugBridge:
|
|
380
|
+
"""Factory to get SignalR debug bridge for remote debugging."""
|
|
381
|
+
uipath_url = os.environ.get("UIPATH_URL")
|
|
382
|
+
if not uipath_url or not context.job_id:
|
|
383
|
+
raise ValueError(
|
|
384
|
+
"UIPATH_URL and UIPATH_JOB_KEY are required for remote debugging"
|
|
385
|
+
)
|
|
386
|
+
if not context.trace_context:
|
|
387
|
+
raise ValueError("trace_context is required for remote debugging")
|
|
388
|
+
|
|
389
|
+
signalr_url = uipath_url + "/agenthub_/wsstunnel?jobId=" + context.job_id
|
|
390
|
+
return SignalRDebugBridge(
|
|
391
|
+
hub_url=signalr_url,
|
|
392
|
+
access_token=os.environ.get("UIPATH_ACCESS_TOKEN"),
|
|
393
|
+
headers={
|
|
394
|
+
"X-UiPath-Internal-TenantId": context.trace_context.tenant_id or "",
|
|
395
|
+
"X-UiPath-Internal-AccountId": context.trace_context.org_id or "",
|
|
396
|
+
"X-UiPath-FolderKey": context.trace_context.folder_key or "",
|
|
397
|
+
},
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def get_debug_bridge(
|
|
402
|
+
context: UiPathRuntimeContext, verbose: bool = True
|
|
403
|
+
) -> UiPathDebugBridge:
|
|
404
|
+
"""Factory to get appropriate debug bridge based on context.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
context: The runtime context containing debug configuration.
|
|
408
|
+
verbose: If True, console bridge shows all state updates. If False, only breakpoints.
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
An instance of UiPathDebugBridge suitable for the context.
|
|
412
|
+
"""
|
|
413
|
+
if context.job_id:
|
|
414
|
+
return get_remote_debug_bridge(context)
|
|
415
|
+
else:
|
|
416
|
+
return ConsoleDebugBridge(verbose=verbose)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Generic, Optional, TypeVar
|
|
3
|
+
|
|
4
|
+
from uipath._events._events import (
|
|
5
|
+
UiPathAgentStateEvent,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
from .._runtime._contracts import (
|
|
9
|
+
UiPathBaseRuntime,
|
|
10
|
+
UiPathBreakpointResult,
|
|
11
|
+
UiPathRuntimeContext,
|
|
12
|
+
UiPathRuntimeFactory,
|
|
13
|
+
UiPathRuntimeResult,
|
|
14
|
+
UiPathRuntimeStreamNotSupportedError,
|
|
15
|
+
)
|
|
16
|
+
from ._bridge import UiPathDebugBridge
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
T = TypeVar("T", bound=UiPathBaseRuntime)
|
|
21
|
+
C = TypeVar("C", bound=UiPathRuntimeContext)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class UiPathDebugRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
25
|
+
"""Specialized runtime for debug runs that streams events to a debug bridge."""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
context: UiPathRuntimeContext,
|
|
30
|
+
factory: UiPathRuntimeFactory[T, C],
|
|
31
|
+
debug_bridge: UiPathDebugBridge,
|
|
32
|
+
):
|
|
33
|
+
super().__init__(context)
|
|
34
|
+
self.context: UiPathRuntimeContext = context
|
|
35
|
+
self.factory: UiPathRuntimeFactory[T, C] = factory
|
|
36
|
+
self.debug_bridge: UiPathDebugBridge = debug_bridge
|
|
37
|
+
self._inner_runtime: Optional[T] = None
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def from_debug_context(
|
|
41
|
+
cls,
|
|
42
|
+
context: UiPathRuntimeContext,
|
|
43
|
+
factory: UiPathRuntimeFactory[T, C],
|
|
44
|
+
debug_bridge: UiPathDebugBridge,
|
|
45
|
+
) -> "UiPathDebugRuntime[T, C]":
|
|
46
|
+
return cls(context, factory, debug_bridge)
|
|
47
|
+
|
|
48
|
+
async def execute(self) -> Optional[UiPathRuntimeResult]:
|
|
49
|
+
"""Execute the workflow with debug support."""
|
|
50
|
+
try:
|
|
51
|
+
await self.debug_bridge.connect()
|
|
52
|
+
|
|
53
|
+
self._inner_runtime = self.factory.new_runtime()
|
|
54
|
+
|
|
55
|
+
if not self._inner_runtime:
|
|
56
|
+
raise RuntimeError("Failed to create inner runtime")
|
|
57
|
+
|
|
58
|
+
await self.debug_bridge.emit_execution_started(
|
|
59
|
+
execution_id=self.context.execution_id or "default"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Try to stream events from inner runtime
|
|
63
|
+
try:
|
|
64
|
+
self.context.result = await self._stream_and_debug()
|
|
65
|
+
except UiPathRuntimeStreamNotSupportedError:
|
|
66
|
+
# Fallback to regular execute if streaming not supported
|
|
67
|
+
logger.debug(
|
|
68
|
+
f"Runtime {self._inner_runtime.__class__.__name__} does not support "
|
|
69
|
+
"streaming, falling back to execute()"
|
|
70
|
+
)
|
|
71
|
+
self.context.result = await self._inner_runtime.execute()
|
|
72
|
+
|
|
73
|
+
if self.context.result:
|
|
74
|
+
await self.debug_bridge.emit_execution_completed(self.context.result)
|
|
75
|
+
|
|
76
|
+
return self.context.result
|
|
77
|
+
|
|
78
|
+
except Exception as e:
|
|
79
|
+
# Emit execution error
|
|
80
|
+
await self.debug_bridge.emit_execution_error(
|
|
81
|
+
execution_id=self.context.execution_id or "default",
|
|
82
|
+
error=str(e),
|
|
83
|
+
)
|
|
84
|
+
raise
|
|
85
|
+
|
|
86
|
+
async def _stream_and_debug(self) -> Optional[UiPathRuntimeResult]:
|
|
87
|
+
"""Stream events from inner runtime and handle debug interactions."""
|
|
88
|
+
if not self._inner_runtime:
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
final_result: Optional[UiPathRuntimeResult] = None
|
|
92
|
+
execution_completed = False
|
|
93
|
+
|
|
94
|
+
# Keep streaming until execution completes (not just paused at breakpoint)
|
|
95
|
+
while not execution_completed:
|
|
96
|
+
# Stream events from inner runtime
|
|
97
|
+
async for event in self._inner_runtime.stream():
|
|
98
|
+
# Handle final result
|
|
99
|
+
if isinstance(event, UiPathRuntimeResult):
|
|
100
|
+
final_result = event
|
|
101
|
+
|
|
102
|
+
# Check if it's a breakpoint result
|
|
103
|
+
if isinstance(event, UiPathBreakpointResult):
|
|
104
|
+
# Hit a breakpoint - wait for resume and continue
|
|
105
|
+
await self.debug_bridge.emit_breakpoint_hit(event)
|
|
106
|
+
await self.debug_bridge.wait_for_resume()
|
|
107
|
+
self._inner_runtime.context.resume = True
|
|
108
|
+
else:
|
|
109
|
+
# Normal completion or suspension with dynamic interrupt
|
|
110
|
+
execution_completed = True
|
|
111
|
+
# Handle dynamic interrupts if present
|
|
112
|
+
# Maybe poll for resume trigger completion here in future
|
|
113
|
+
|
|
114
|
+
# Handle state update events - send to debug bridge
|
|
115
|
+
elif isinstance(event, UiPathAgentStateEvent):
|
|
116
|
+
await self.debug_bridge.emit_state_update(event)
|
|
117
|
+
|
|
118
|
+
return final_result
|
|
119
|
+
|
|
120
|
+
async def validate(self) -> None:
|
|
121
|
+
"""Validate runtime configuration."""
|
|
122
|
+
if self._inner_runtime:
|
|
123
|
+
await self._inner_runtime.validate()
|
|
124
|
+
|
|
125
|
+
async def cleanup(self) -> None:
|
|
126
|
+
"""Cleanup runtime resources."""
|
|
127
|
+
try:
|
|
128
|
+
if self._inner_runtime:
|
|
129
|
+
await self._inner_runtime.cleanup()
|
|
130
|
+
finally:
|
|
131
|
+
try:
|
|
132
|
+
await self.debug_bridge.disconnect()
|
|
133
|
+
except Exception as e:
|
|
134
|
+
logger.warning(f"Error disconnecting debug bridge: {e}")
|
|
@@ -488,6 +488,12 @@ class UiPathRuntimeError(Exception):
|
|
|
488
488
|
return self.error_info.model_dump()
|
|
489
489
|
|
|
490
490
|
|
|
491
|
+
class UiPathRuntimeStreamNotSupportedError(NotImplementedError):
|
|
492
|
+
"""Raised when a runtime does not support streaming."""
|
|
493
|
+
|
|
494
|
+
pass
|
|
495
|
+
|
|
496
|
+
|
|
491
497
|
class UiPathBaseRuntime(ABC):
|
|
492
498
|
"""Base runtime class implementing the async context manager protocol.
|
|
493
499
|
|
|
@@ -591,7 +597,7 @@ class UiPathBaseRuntime(ABC):
|
|
|
591
597
|
Final yield: UiPathRuntimeResult (or its subclass UiPathBreakpointResult)
|
|
592
598
|
|
|
593
599
|
Raises:
|
|
594
|
-
|
|
600
|
+
UiPathRuntimeStreamNotSupportedError: If the runtime doesn't support streaming
|
|
595
601
|
RuntimeError: If execution fails
|
|
596
602
|
|
|
597
603
|
Example:
|
|
@@ -607,7 +613,7 @@ class UiPathBaseRuntime(ABC):
|
|
|
607
613
|
# Handle state update
|
|
608
614
|
print(f"State updated by: {event.node_name}")
|
|
609
615
|
"""
|
|
610
|
-
raise
|
|
616
|
+
raise UiPathRuntimeStreamNotSupportedError(
|
|
611
617
|
f"{self.__class__.__name__} does not implement streaming. "
|
|
612
618
|
"Use execute() instead."
|
|
613
619
|
)
|
uipath/_cli/_runtime/_runtime.py
CHANGED
|
@@ -45,11 +45,6 @@ class UiPathRuntime(UiPathBaseRuntime):
|
|
|
45
45
|
try:
|
|
46
46
|
script_result = await self.executor(self.context.input_json)
|
|
47
47
|
|
|
48
|
-
if self.context.job_id is None and not getattr(
|
|
49
|
-
self.context, "is_eval_run", False
|
|
50
|
-
):
|
|
51
|
-
logger.info(script_result)
|
|
52
|
-
|
|
53
48
|
self.context.result = UiPathRuntimeResult(
|
|
54
49
|
output=script_result, status=UiPathRuntimeStatus.SUCCESSFUL
|
|
55
50
|
)
|
uipath/_cli/cli_debug.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# type: ignore
|
|
2
|
+
import asyncio
|
|
3
|
+
import os
|
|
4
|
+
import uuid
|
|
5
|
+
from os import environ as env
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from uipath._cli._utils._debug import setup_debugging
|
|
11
|
+
from uipath.tracing import LlmOpsHttpExporter
|
|
12
|
+
|
|
13
|
+
from .._utils.constants import (
|
|
14
|
+
ENV_JOB_ID,
|
|
15
|
+
)
|
|
16
|
+
from ..telemetry import track
|
|
17
|
+
from ._debug._bridge import UiPathDebugBridge, get_debug_bridge
|
|
18
|
+
from ._debug._runtime import UiPathDebugRuntime
|
|
19
|
+
from ._runtime._contracts import (
|
|
20
|
+
UiPathRuntimeContext,
|
|
21
|
+
UiPathRuntimeFactory,
|
|
22
|
+
)
|
|
23
|
+
from ._runtime._runtime import UiPathScriptRuntime
|
|
24
|
+
from ._utils._console import ConsoleLogger
|
|
25
|
+
from .middlewares import Middlewares
|
|
26
|
+
|
|
27
|
+
console = ConsoleLogger()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@click.command()
|
|
31
|
+
@click.argument("entrypoint", required=False)
|
|
32
|
+
@click.argument("input", required=False, default="{}")
|
|
33
|
+
@click.option("--resume", is_flag=True, help="Resume execution from a previous state")
|
|
34
|
+
@click.option(
|
|
35
|
+
"-f",
|
|
36
|
+
"--file",
|
|
37
|
+
required=False,
|
|
38
|
+
type=click.Path(exists=True),
|
|
39
|
+
help="File path for the .json input",
|
|
40
|
+
)
|
|
41
|
+
@click.option(
|
|
42
|
+
"--input-file",
|
|
43
|
+
required=False,
|
|
44
|
+
type=click.Path(exists=True),
|
|
45
|
+
help="Alias for '-f/--file' arguments",
|
|
46
|
+
)
|
|
47
|
+
@click.option(
|
|
48
|
+
"--output-file",
|
|
49
|
+
required=False,
|
|
50
|
+
type=click.Path(exists=False),
|
|
51
|
+
help="File path where the output will be written",
|
|
52
|
+
)
|
|
53
|
+
@click.option(
|
|
54
|
+
"--debug",
|
|
55
|
+
is_flag=True,
|
|
56
|
+
help="Enable debugging with debugpy. The process will wait for a debugger to attach.",
|
|
57
|
+
)
|
|
58
|
+
@click.option(
|
|
59
|
+
"--debug-port",
|
|
60
|
+
type=int,
|
|
61
|
+
default=5678,
|
|
62
|
+
help="Port for the debug server (default: 5678)",
|
|
63
|
+
)
|
|
64
|
+
@track(when=lambda *_a, **_kw: env.get(ENV_JOB_ID) is None)
|
|
65
|
+
def debug(
|
|
66
|
+
entrypoint: Optional[str],
|
|
67
|
+
input: Optional[str],
|
|
68
|
+
resume: bool,
|
|
69
|
+
file: Optional[str],
|
|
70
|
+
input_file: Optional[str],
|
|
71
|
+
output_file: Optional[str],
|
|
72
|
+
debug: bool,
|
|
73
|
+
debug_port: int,
|
|
74
|
+
) -> None:
|
|
75
|
+
"""Execute the project."""
|
|
76
|
+
input_file = file or input_file
|
|
77
|
+
# Setup debugging if requested
|
|
78
|
+
if not setup_debugging(debug, debug_port):
|
|
79
|
+
console.error(f"Failed to start debug server on port {debug_port}")
|
|
80
|
+
|
|
81
|
+
result = Middlewares.next(
|
|
82
|
+
"debug",
|
|
83
|
+
entrypoint,
|
|
84
|
+
input,
|
|
85
|
+
resume,
|
|
86
|
+
input_file=input_file,
|
|
87
|
+
execution_output_file=output_file,
|
|
88
|
+
debug=debug,
|
|
89
|
+
debug_port=debug_port,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if result.error_message:
|
|
93
|
+
console.error(result.error_message)
|
|
94
|
+
|
|
95
|
+
if result.should_continue:
|
|
96
|
+
if not entrypoint:
|
|
97
|
+
console.error("""No entrypoint specified. Please provide a path to a Python script.
|
|
98
|
+
Usage: `uipath debug <entrypoint_path> <input_arguments> [-f <input_json_file_path>]`""")
|
|
99
|
+
|
|
100
|
+
if not os.path.exists(entrypoint):
|
|
101
|
+
console.error(f"""Script not found at path {entrypoint}.
|
|
102
|
+
Usage: `uipath debug <entrypoint_path> <input_arguments> [-f <input_json_file_path>]`""")
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
debug_context = UiPathRuntimeContext.with_defaults(
|
|
106
|
+
entrypoint=entrypoint,
|
|
107
|
+
input=input,
|
|
108
|
+
input_file=input_file,
|
|
109
|
+
resume=resume,
|
|
110
|
+
execution_output_file=output_file,
|
|
111
|
+
debug=debug,
|
|
112
|
+
)
|
|
113
|
+
debug_context.execution_id = debug_context.job_id or str(uuid.uuid4())
|
|
114
|
+
|
|
115
|
+
runtime_factory = UiPathRuntimeFactory(
|
|
116
|
+
UiPathScriptRuntime,
|
|
117
|
+
UiPathRuntimeContext,
|
|
118
|
+
context_generator=lambda: debug_context,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
debug_bridge: UiPathDebugBridge = get_debug_bridge(debug_context)
|
|
122
|
+
|
|
123
|
+
if debug_context.job_id:
|
|
124
|
+
runtime_factory.add_span_exporter(LlmOpsHttpExporter())
|
|
125
|
+
|
|
126
|
+
async def execute():
|
|
127
|
+
async with UiPathDebugRuntime.from_debug_context(
|
|
128
|
+
factory=runtime_factory,
|
|
129
|
+
context=debug_context,
|
|
130
|
+
debug_bridge=debug_bridge,
|
|
131
|
+
) as debug_runtime:
|
|
132
|
+
await debug_runtime.execute()
|
|
133
|
+
|
|
134
|
+
asyncio.run(execute())
|
|
135
|
+
except Exception as e:
|
|
136
|
+
console.error(
|
|
137
|
+
f"Error occurred: {e or 'Execution failed'}", include_traceback=True
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
if __name__ == "__main__":
|
|
142
|
+
debug()
|
uipath/_cli/cli_run.py
CHANGED
|
@@ -115,7 +115,12 @@ def run(
|
|
|
115
115
|
if context.job_id:
|
|
116
116
|
runtime_factory.add_span_exporter(LlmOpsHttpExporter())
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
async def execute_runtime():
|
|
119
|
+
result = await runtime_factory.execute(context)
|
|
120
|
+
if not context.job_id:
|
|
121
|
+
console.info(result.output)
|
|
122
|
+
|
|
123
|
+
asyncio.run(execute_runtime())
|
|
119
124
|
|
|
120
125
|
except UiPathRuntimeError as e:
|
|
121
126
|
console.error(f"{e.error_info.title} - {e.error_info.detail}")
|
uipath/_cli/middlewares.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: uipath
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.95
|
|
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
|
|
@@ -25,6 +25,7 @@ Requires-Dist: pathlib>=1.0.1
|
|
|
25
25
|
Requires-Dist: pydantic-function-models>=0.1.10
|
|
26
26
|
Requires-Dist: pydantic>=2.11.1
|
|
27
27
|
Requires-Dist: pyperclip>=1.9.0
|
|
28
|
+
Requires-Dist: pysignalr==1.3.0
|
|
28
29
|
Requires-Dist: python-dotenv>=1.0.1
|
|
29
30
|
Requires-Dist: rich>=13.0.0
|
|
30
31
|
Requires-Dist: tenacity>=9.0.0
|
|
@@ -5,8 +5,9 @@ uipath/_folder_context.py,sha256=D-bgxdwpwJP4b_QdVKcPODYh15kMDrOar2xNonmMSm4,186
|
|
|
5
5
|
uipath/_uipath.py,sha256=mhtdu36-A-2WhPGNFFrTmQWbE07Bn4IV_Vrqgf6kuVM,4900
|
|
6
6
|
uipath/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
uipath/_cli/README.md,sha256=GLtCfbeIKZKNnGTCsfSVqRQ27V1btT1i2bSAyW_xZl4,474
|
|
8
|
-
uipath/_cli/__init__.py,sha256=
|
|
8
|
+
uipath/_cli/__init__.py,sha256=RZtYzThMGEKEwmiUwwm6TUU5KxDpfTuez2qSFD78J8w,2345
|
|
9
9
|
uipath/_cli/cli_auth.py,sha256=CzetSRqSUvMs02PtI4w5Vi_0fv_ETA307bB2vXalWzY,2628
|
|
10
|
+
uipath/_cli/cli_debug.py,sha256=-0ZWMe3aKfVZSiZCe7U2K_Xpai1fKxZpaETu_7ewj2s,4163
|
|
10
11
|
uipath/_cli/cli_deploy.py,sha256=KPCmQ0c_NYD5JofSDao5r6QYxHshVCRxlWDVnQvlp5w,645
|
|
11
12
|
uipath/_cli/cli_dev.py,sha256=nEfpjw1PZ72O6jmufYWVrueVwihFxDPOeJakdvNHdOA,2146
|
|
12
13
|
uipath/_cli/cli_eval.py,sha256=oOMywGSUrHDQ1W_54ccbekzCeduPf-KHRyu_r0Dezd0,5444
|
|
@@ -17,8 +18,8 @@ uipath/_cli/cli_pack.py,sha256=U5rXVbUnHFgdEsXyhkjmWza8dfob1wU9lyl4yrYnUss,11076
|
|
|
17
18
|
uipath/_cli/cli_publish.py,sha256=DgyfcZjvfV05Ldy0Pk5y_Le_nT9JduEE_x-VpIc_Kq0,6471
|
|
18
19
|
uipath/_cli/cli_pull.py,sha256=muX2gR-W-bSrNI3pIO0zbhZAP0VBOSsOY2-yrq8HgAw,2433
|
|
19
20
|
uipath/_cli/cli_push.py,sha256=_JbjI45uJaobBDaz--NlzAXYJNwHX_XGLa8eC9wN-Cg,3166
|
|
20
|
-
uipath/_cli/cli_run.py,sha256=
|
|
21
|
-
uipath/_cli/middlewares.py,sha256=
|
|
21
|
+
uipath/_cli/cli_run.py,sha256=dLEFu_sFOKeKN9juscFt-PKnTl4-mTF1PNP_44skG-0,3887
|
|
22
|
+
uipath/_cli/middlewares.py,sha256=tb0c4sU1SCYi0PNs956Qmk24NDk0C0mBfVQmTcyORE0,5000
|
|
22
23
|
uipath/_cli/spinner.py,sha256=bS-U_HA5yne11ejUERu7CQoXmWdabUD2bm62EfEdV8M,1107
|
|
23
24
|
uipath/_cli/_auth/_auth_server.py,sha256=v_b8KNwn0tAv8jxpeKdllOVzl31q9AcdwpE_koAK_w4,7235
|
|
24
25
|
uipath/_cli/_auth/_auth_service.py,sha256=gyOtaHnDmjYccW0R1HVmFgV69a7w53Dx1Mq-PM0uVag,5405
|
|
@@ -31,6 +32,8 @@ uipath/_cli/_auth/auth_config.json,sha256=o8J5BBFwiEtjZLHpJ_64lvnTeYeRIHaJ-Bhg0Q
|
|
|
31
32
|
uipath/_cli/_auth/index.html,sha256=uGK0CDTP8Rys_p4O_Pbd2x4tz0frKNVcumjrXnal5Nc,22814
|
|
32
33
|
uipath/_cli/_auth/localhost.crt,sha256=oGl9oLLOiouHubAt39B4zEfylFvKEtbtr_43SIliXJc,1226
|
|
33
34
|
uipath/_cli/_auth/localhost.key,sha256=X31VYXD8scZtmGA837dGX5l6G-LXHLo5ItWJhZXaz3c,1679
|
|
35
|
+
uipath/_cli/_debug/_bridge.py,sha256=l2k-jIyWTSEx8uvmYRvtlh72gaZBKOV0HiNbdPbqSMQ,13896
|
|
36
|
+
uipath/_cli/_debug/_runtime.py,sha256=fwpxmBFAhhMjanBQaCQdI-YuvMC6vhS8SSS8pvw_PJw,4946
|
|
34
37
|
uipath/_cli/_dev/_terminal/__init__.py,sha256=di_RiN9Mcp9wqyKRRqXag28vbSw8_78mCnQZNn9H-Ss,14027
|
|
35
38
|
uipath/_cli/_dev/_terminal/_components/_chat.py,sha256=NLRoy49QScHiI-q0FGykkaU8ajv1d23fx7issSALcFA,4119
|
|
36
39
|
uipath/_cli/_dev/_terminal/_components/_details.py,sha256=FbLYtJ56gqHV6CIrpzO_n9Sk_YNg4nzRKTSsbj-DBPQ,17257
|
|
@@ -63,11 +66,11 @@ uipath/_cli/_evals/mocks/mocker_factory.py,sha256=V5QKSTtQxztTo4-fK1TyAaXw2Z3mHf
|
|
|
63
66
|
uipath/_cli/_evals/mocks/mockito_mocker.py,sha256=AO2BmFwA6hz3Lte-STVr7aJDPvMCqKNKa4j2jeNZ_U4,2677
|
|
64
67
|
uipath/_cli/_evals/mocks/mocks.py,sha256=HY0IaSqqO8hioBB3rp5XwAjSpQE4K5hoH6oJQ-sH72I,2207
|
|
65
68
|
uipath/_cli/_push/sw_file_handler.py,sha256=voZVfJeJTqkvf5aFZvxAHQ_qa7dX_Cz7wRsfhLKL9Ag,17884
|
|
66
|
-
uipath/_cli/_runtime/_contracts.py,sha256=
|
|
69
|
+
uipath/_cli/_runtime/_contracts.py,sha256=zNbBbnEPW3hzUcgAsPQSmH8SUsEME1PtJDJbjFXcsCc,31607
|
|
67
70
|
uipath/_cli/_runtime/_escalation.py,sha256=x3vI98qsfRA-fL_tNkRVTFXioM5Gv2w0GFcXJJ5eQtg,7981
|
|
68
71
|
uipath/_cli/_runtime/_hitl.py,sha256=VKbM021nVg1HEDnTfucSLJ0LsDn83CKyUtVzofS2qTU,11369
|
|
69
72
|
uipath/_cli/_runtime/_logging.py,sha256=srjAi3Cy6g7b8WNHiYNjaZT4t40F3XRqquuoGd2kh4Y,14019
|
|
70
|
-
uipath/_cli/_runtime/_runtime.py,sha256=
|
|
73
|
+
uipath/_cli/_runtime/_runtime.py,sha256=Gs75gZMwohO4x_TDkw_XPH_zVmKM3qCHhUj0mI2Bna4,2209
|
|
71
74
|
uipath/_cli/_runtime/_script_executor.py,sha256=PjbmEbyCMofGH2F85b8RFsxdV3Tqw0kVqdWOOk2ZLlI,9687
|
|
72
75
|
uipath/_cli/_templates/.psmdcp.template,sha256=C7pBJPt98ovEljcBvGtEUGoWjjQhu9jls1bpYjeLOKA,611
|
|
73
76
|
uipath/_cli/_templates/.rels.template,sha256=-fTcw7OA1AcymHr0LzBqbMAAtzZTRXLTNa_ljq087Jk,406
|
|
@@ -184,8 +187,8 @@ uipath/tracing/_utils.py,sha256=X-LFsyIxDeNOGuHPvkb6T5o9Y8ElYhr_rP3CEBJSu4s,1383
|
|
|
184
187
|
uipath/utils/__init__.py,sha256=VD-KXFpF_oWexFg6zyiWMkxl2HM4hYJMIUDZ1UEtGx0,105
|
|
185
188
|
uipath/utils/_endpoints_manager.py,sha256=iRTl5Q0XAm_YgcnMcJOXtj-8052sr6jpWuPNz6CgT0Q,8408
|
|
186
189
|
uipath/utils/dynamic_schema.py,sha256=w0u_54MoeIAB-mf3GmwX1A_X8_HDrRy6p998PvX9evY,3839
|
|
187
|
-
uipath-2.1.
|
|
188
|
-
uipath-2.1.
|
|
189
|
-
uipath-2.1.
|
|
190
|
-
uipath-2.1.
|
|
191
|
-
uipath-2.1.
|
|
190
|
+
uipath-2.1.95.dist-info/METADATA,sha256=KzgAYNHE2yGDV2LXNYOzbhDcl41TUjRrnp1Qa6r5pgs,6625
|
|
191
|
+
uipath-2.1.95.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
192
|
+
uipath-2.1.95.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
|
|
193
|
+
uipath-2.1.95.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
|
|
194
|
+
uipath-2.1.95.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|