uipath 2.1.74__py3-none-any.whl → 2.1.76__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.
- uipath/_cli/_evals/_console_progress_reporter.py +241 -0
- uipath/_cli/_evals/_models/_exceptions.py +5 -0
- uipath/_cli/_evals/_models/_output.py +2 -0
- uipath/_cli/_evals/_progress_reporter.py +11 -5
- uipath/_cli/_evals/_runtime.py +150 -57
- uipath/_cli/_runtime/_contracts.py +4 -2
- uipath/_cli/_runtime/_logging.py +29 -0
- uipath/_cli/cli_eval.py +25 -10
- uipath/_cli/middlewares.py +3 -3
- uipath/_events/_events.py +18 -2
- uipath/_services/connections_service.py +218 -3
- uipath/_uipath.py +10 -1
- uipath/_utils/_infer_bindings.py +4 -2
- uipath/telemetry/_track.py +2 -2
- {uipath-2.1.74.dist-info → uipath-2.1.76.dist-info}/METADATA +1 -1
- {uipath-2.1.74.dist-info → uipath-2.1.76.dist-info}/RECORD +19 -17
- {uipath-2.1.74.dist-info → uipath-2.1.76.dist-info}/WHEEL +0 -0
- {uipath-2.1.74.dist-info → uipath-2.1.76.dist-info}/entry_points.txt +0 -0
- {uipath-2.1.74.dist-info → uipath-2.1.76.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,241 @@
|
|
1
|
+
"""Console progress reporter for evaluation runs with line-by-line output."""
|
2
|
+
|
3
|
+
import logging
|
4
|
+
from typing import Any, Dict
|
5
|
+
|
6
|
+
from rich.console import Console
|
7
|
+
from rich.rule import Rule
|
8
|
+
from rich.table import Table
|
9
|
+
|
10
|
+
from uipath._events._event_bus import EventBus
|
11
|
+
from uipath._events._events import (
|
12
|
+
EvalRunCreatedEvent,
|
13
|
+
EvalRunUpdatedEvent,
|
14
|
+
EvalSetRunCreatedEvent,
|
15
|
+
EvalSetRunUpdatedEvent,
|
16
|
+
EvaluationEvents,
|
17
|
+
)
|
18
|
+
from uipath.eval.evaluators import BaseEvaluator
|
19
|
+
from uipath.eval.models import ScoreType
|
20
|
+
|
21
|
+
logger = logging.getLogger(__name__)
|
22
|
+
|
23
|
+
|
24
|
+
class ConsoleProgressReporter:
|
25
|
+
"""Handles displaying evaluation progress to the console with line-by-line output."""
|
26
|
+
|
27
|
+
def __init__(self):
|
28
|
+
self.console = Console()
|
29
|
+
self.evaluators: Dict[str, BaseEvaluator[Any]] = {}
|
30
|
+
self.display_started = False
|
31
|
+
self.eval_results_by_name: Dict[str, list[Any]] = {}
|
32
|
+
|
33
|
+
def _convert_score_to_numeric(self, eval_result) -> float:
|
34
|
+
"""Convert evaluation result score to numeric value."""
|
35
|
+
score_value = eval_result.result.score
|
36
|
+
if eval_result.result.score_type == ScoreType.BOOLEAN:
|
37
|
+
score_value = 100 if score_value else 0
|
38
|
+
return score_value
|
39
|
+
|
40
|
+
def _get_evaluator_name(self, evaluator_id: str) -> str:
|
41
|
+
"""Get evaluator name from ID, with fallback."""
|
42
|
+
return self.evaluators.get(
|
43
|
+
evaluator_id,
|
44
|
+
type(
|
45
|
+
"obj",
|
46
|
+
(object,),
|
47
|
+
{"name": f"Evaluator {evaluator_id[:8]}"},
|
48
|
+
)(),
|
49
|
+
).name
|
50
|
+
|
51
|
+
def _display_successful_evaluation(self, eval_name: str, eval_results) -> None:
|
52
|
+
"""Display results for a successful evaluation."""
|
53
|
+
from rich.text import Text
|
54
|
+
|
55
|
+
if eval_results:
|
56
|
+
result = Text()
|
57
|
+
result.append("▌", style="bold green")
|
58
|
+
result.append(" ", style="")
|
59
|
+
result.append(eval_name, style="bold green")
|
60
|
+
self.console.print(result)
|
61
|
+
table = Table(show_header=False, box=None, padding=(0, 2, 0, 2))
|
62
|
+
|
63
|
+
for eval_result in eval_results:
|
64
|
+
evaluator_name = self._get_evaluator_name(eval_result.evaluator_id)
|
65
|
+
score_value = self._convert_score_to_numeric(eval_result)
|
66
|
+
table.add_row(
|
67
|
+
f"{evaluator_name}", f"[bold cyan]{score_value:.1f}[/bold cyan]"
|
68
|
+
)
|
69
|
+
|
70
|
+
self.console.print(table)
|
71
|
+
else:
|
72
|
+
result = Text()
|
73
|
+
result.append(" ✓ ", style="bold green")
|
74
|
+
result.append(eval_name, style="bold white")
|
75
|
+
result.append(" - No evaluators", style="dim")
|
76
|
+
self.console.print(result)
|
77
|
+
|
78
|
+
def _extract_error_message(self, payload: EvalRunUpdatedEvent) -> str:
|
79
|
+
return str(payload.exception_details.exception) or "Execution failed" # type: ignore
|
80
|
+
|
81
|
+
def _display_failed_evaluation(self, eval_name: str) -> None:
|
82
|
+
"""Display results for a failed evaluation."""
|
83
|
+
from rich.text import Text
|
84
|
+
|
85
|
+
result = Text()
|
86
|
+
result.append(" ✗ ", style="bold red")
|
87
|
+
result.append(eval_name, style="bold white")
|
88
|
+
self.console.print(result)
|
89
|
+
|
90
|
+
def start_display(self):
|
91
|
+
"""Start the display."""
|
92
|
+
if not self.display_started:
|
93
|
+
self.console.print()
|
94
|
+
self.console.print("→ [bold]Running Evaluations[/bold]")
|
95
|
+
self.console.print()
|
96
|
+
self.display_started = True
|
97
|
+
|
98
|
+
async def handle_create_eval_set_run(self, payload: EvalSetRunCreatedEvent) -> None:
|
99
|
+
"""Handle evaluation set run creation."""
|
100
|
+
try:
|
101
|
+
self.evaluators = {eval.id: eval for eval in payload.evaluators}
|
102
|
+
except Exception as e:
|
103
|
+
logger.error(f"Failed to handle create eval set run event: {e}")
|
104
|
+
|
105
|
+
async def handle_create_eval_run(self, payload: EvalRunCreatedEvent) -> None:
|
106
|
+
"""Handle individual evaluation run creation."""
|
107
|
+
try:
|
108
|
+
if not self.display_started:
|
109
|
+
self.start_display()
|
110
|
+
|
111
|
+
self.console.print(f" ○ [dim]{payload.eval_item.name}[/dim] - Running...")
|
112
|
+
except Exception as e:
|
113
|
+
logger.error(f"Failed to handle create eval run event: {e}")
|
114
|
+
|
115
|
+
def _display_logs_panel(self, eval_name: str, logs, error_msg: str = "") -> None:
|
116
|
+
"""Display execution logs panel with optional exception at the end."""
|
117
|
+
self.console.print(
|
118
|
+
Rule(
|
119
|
+
f"[dim italic]Execution Logs: {eval_name}[/dim italic]",
|
120
|
+
style="dim",
|
121
|
+
align="center",
|
122
|
+
)
|
123
|
+
)
|
124
|
+
|
125
|
+
if logs:
|
126
|
+
for record in logs:
|
127
|
+
self.console.print(f" [dim]{record.getMessage()}[/dim]")
|
128
|
+
elif not error_msg:
|
129
|
+
self.console.print(" [dim italic]No execution logs[/dim italic]")
|
130
|
+
|
131
|
+
if error_msg:
|
132
|
+
self.console.print(f" [red]{error_msg}[/red]")
|
133
|
+
|
134
|
+
self.console.print(Rule(style="dim"))
|
135
|
+
|
136
|
+
async def handle_update_eval_run(self, payload: EvalRunUpdatedEvent) -> None:
|
137
|
+
"""Handle evaluation run updates."""
|
138
|
+
try:
|
139
|
+
if payload.success:
|
140
|
+
self.eval_results_by_name[payload.eval_item.name] = payload.eval_results
|
141
|
+
self._display_successful_evaluation(
|
142
|
+
payload.eval_item.name, payload.eval_results
|
143
|
+
)
|
144
|
+
self._display_logs_panel(payload.eval_item.name, payload.logs)
|
145
|
+
else:
|
146
|
+
error_msg = self._extract_error_message(payload)
|
147
|
+
self._display_failed_evaluation(payload.eval_item.name)
|
148
|
+
|
149
|
+
if payload.exception_details.runtime_exception: # type: ignore
|
150
|
+
self._display_logs_panel(
|
151
|
+
payload.eval_item.name, payload.logs, error_msg
|
152
|
+
)
|
153
|
+
else:
|
154
|
+
self.console.print(f" [red]{error_msg}[/red]")
|
155
|
+
self.console.print()
|
156
|
+
except Exception as e:
|
157
|
+
logger.error(f"Console reporter error: {e}")
|
158
|
+
|
159
|
+
async def handle_update_eval_set_run(self, payload: EvalSetRunUpdatedEvent) -> None:
|
160
|
+
"""Handle evaluation set run completion."""
|
161
|
+
try:
|
162
|
+
self.final_results = payload.evaluator_scores
|
163
|
+
self.display_final_results()
|
164
|
+
except Exception as e:
|
165
|
+
logger.error(f"Console reporter error: {e}")
|
166
|
+
|
167
|
+
def display_final_results(self):
|
168
|
+
"""Display final results summary."""
|
169
|
+
self.console.print()
|
170
|
+
|
171
|
+
if hasattr(self, "final_results") and self.final_results:
|
172
|
+
from rich.table import Table
|
173
|
+
|
174
|
+
# Group evaluators by ID to organize display
|
175
|
+
evaluator_ids = list(self.final_results.keys())
|
176
|
+
|
177
|
+
# Print title
|
178
|
+
self.console.print("[bold]Evaluation Results[/bold]")
|
179
|
+
self.console.print()
|
180
|
+
|
181
|
+
# Create single summary table
|
182
|
+
summary_table = Table(show_header=True, padding=(0, 2))
|
183
|
+
summary_table.add_column("Evaluation", style="cyan")
|
184
|
+
|
185
|
+
# Add column for each evaluator
|
186
|
+
for evaluator_id in evaluator_ids:
|
187
|
+
evaluator_name = self._get_evaluator_name(evaluator_id)
|
188
|
+
summary_table.add_column(evaluator_name, justify="right")
|
189
|
+
|
190
|
+
# Add row for each evaluation
|
191
|
+
for eval_name, eval_results in self.eval_results_by_name.items():
|
192
|
+
row_values = [eval_name]
|
193
|
+
|
194
|
+
# Get score for each evaluator
|
195
|
+
for evaluator_id in evaluator_ids:
|
196
|
+
score_found = False
|
197
|
+
for eval_result in eval_results:
|
198
|
+
if eval_result.evaluator_id == evaluator_id:
|
199
|
+
score_value = self._convert_score_to_numeric(eval_result)
|
200
|
+
row_values.append(f"{score_value:.1f}")
|
201
|
+
score_found = True
|
202
|
+
break
|
203
|
+
|
204
|
+
if not score_found:
|
205
|
+
row_values.append("-")
|
206
|
+
|
207
|
+
summary_table.add_row(*row_values)
|
208
|
+
|
209
|
+
# Add separator row before average
|
210
|
+
summary_table.add_section()
|
211
|
+
|
212
|
+
# Add average row
|
213
|
+
avg_row_values = ["[bold]Average[/bold]"]
|
214
|
+
for evaluator_id in evaluator_ids:
|
215
|
+
avg_score = self.final_results[evaluator_id]
|
216
|
+
avg_row_values.append(f"[bold]{avg_score:.1f}[/bold]")
|
217
|
+
|
218
|
+
summary_table.add_row(*avg_row_values)
|
219
|
+
|
220
|
+
self.console.print(summary_table)
|
221
|
+
self.console.print()
|
222
|
+
else:
|
223
|
+
self.console.print(
|
224
|
+
"→ [bold green]All evaluations completed successfully![/bold green]"
|
225
|
+
)
|
226
|
+
self.console.print()
|
227
|
+
|
228
|
+
async def subscribe_to_eval_runtime_events(self, event_bus: EventBus) -> None:
|
229
|
+
"""Subscribe to evaluation runtime events."""
|
230
|
+
event_bus.subscribe(
|
231
|
+
EvaluationEvents.CREATE_EVAL_SET_RUN, self.handle_create_eval_set_run
|
232
|
+
)
|
233
|
+
event_bus.subscribe(
|
234
|
+
EvaluationEvents.CREATE_EVAL_RUN, self.handle_create_eval_run
|
235
|
+
)
|
236
|
+
event_bus.subscribe(
|
237
|
+
EvaluationEvents.UPDATE_EVAL_RUN, self.handle_update_eval_run
|
238
|
+
)
|
239
|
+
event_bus.subscribe(
|
240
|
+
EvaluationEvents.UPDATE_EVAL_SET_RUN, self.handle_update_eval_set_run
|
241
|
+
)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import logging
|
1
2
|
from typing import List, Optional
|
2
3
|
|
3
4
|
from opentelemetry.sdk.trace import ReadableSpan
|
@@ -15,6 +16,7 @@ class UiPathEvalRunExecutionOutput(BaseModel):
|
|
15
16
|
|
16
17
|
execution_time: float
|
17
18
|
spans: list[ReadableSpan]
|
19
|
+
logs: list[logging.LogRecord]
|
18
20
|
result: UiPathRuntimeResult
|
19
21
|
|
20
22
|
|
@@ -7,6 +7,7 @@ import os
|
|
7
7
|
from typing import Any, Dict, List
|
8
8
|
|
9
9
|
from opentelemetry import trace
|
10
|
+
from rich.console import Console
|
10
11
|
|
11
12
|
from uipath import UiPath
|
12
13
|
from uipath._cli._evals._models._evaluation_set import EvaluationItem, EvaluationStatus
|
@@ -68,6 +69,7 @@ class StudioWebProgressReporter:
|
|
68
69
|
|
69
70
|
self._client = uipath.api_client
|
70
71
|
self._console = console_logger
|
72
|
+
self._rich_console = Console()
|
71
73
|
self._project_id = os.getenv("UIPATH_PROJECT_ID", None)
|
72
74
|
if not self._project_id:
|
73
75
|
logger.warning(
|
@@ -79,6 +81,10 @@ class StudioWebProgressReporter:
|
|
79
81
|
self.evaluator_scores: Dict[str, List[float]] = {}
|
80
82
|
self.eval_run_ids: Dict[str, str] = {}
|
81
83
|
|
84
|
+
def _format_error_message(self, error: Exception, context: str) -> None:
|
85
|
+
"""Helper method to format and display error messages consistently."""
|
86
|
+
self._rich_console.print(f" • \u26a0 [dim]{context}: {error}[/dim]")
|
87
|
+
|
82
88
|
@gracefully_handle_errors
|
83
89
|
async def create_eval_set_run(
|
84
90
|
self,
|
@@ -182,7 +188,7 @@ class StudioWebProgressReporter:
|
|
182
188
|
logger.debug(f"Created eval set run with ID: {eval_set_run_id}")
|
183
189
|
|
184
190
|
except Exception as e:
|
185
|
-
|
191
|
+
self._format_error_message(e, "StudioWeb create eval set run error")
|
186
192
|
|
187
193
|
async def handle_create_eval_run(self, payload: EvalRunCreatedEvent) -> None:
|
188
194
|
try:
|
@@ -197,7 +203,7 @@ class StudioWebProgressReporter:
|
|
197
203
|
logger.warning("Cannot create eval run: eval_set_run_id not available")
|
198
204
|
|
199
205
|
except Exception as e:
|
200
|
-
|
206
|
+
self._format_error_message(e, "StudioWeb create eval run error")
|
201
207
|
|
202
208
|
async def handle_update_eval_run(self, payload: EvalRunUpdatedEvent) -> None:
|
203
209
|
try:
|
@@ -238,7 +244,7 @@ class StudioWebProgressReporter:
|
|
238
244
|
logger.debug(f"Updated eval run with ID: {eval_run_id}")
|
239
245
|
|
240
246
|
except Exception as e:
|
241
|
-
|
247
|
+
self._format_error_message(e, "StudioWeb reporting error")
|
242
248
|
|
243
249
|
async def handle_update_eval_set_run(self, payload: EvalSetRunUpdatedEvent) -> None:
|
244
250
|
try:
|
@@ -254,7 +260,7 @@ class StudioWebProgressReporter:
|
|
254
260
|
)
|
255
261
|
|
256
262
|
except Exception as e:
|
257
|
-
|
263
|
+
self._format_error_message(e, "StudioWeb update eval set run error")
|
258
264
|
|
259
265
|
async def subscribe_to_eval_runtime_events(self, event_bus: EventBus) -> None:
|
260
266
|
event_bus.subscribe(
|
@@ -270,7 +276,7 @@ class StudioWebProgressReporter:
|
|
270
276
|
EvaluationEvents.UPDATE_EVAL_SET_RUN, self.handle_update_eval_set_run
|
271
277
|
)
|
272
278
|
|
273
|
-
logger.
|
279
|
+
logger.debug("StudioWeb progress reporter subscribed to evaluation events")
|
274
280
|
|
275
281
|
def _extract_agent_snapshot(self, entrypoint: str) -> StudioWebAgentSnapshot:
|
276
282
|
try:
|
uipath/_cli/_evals/_runtime.py
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
import json
|
2
|
+
import logging
|
3
|
+
import uuid
|
2
4
|
from collections import defaultdict
|
3
5
|
from pathlib import Path
|
4
6
|
from time import time
|
@@ -9,6 +11,7 @@ from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
|
|
9
11
|
|
10
12
|
from ..._events._event_bus import EventBus
|
11
13
|
from ..._events._events import (
|
14
|
+
EvalItemExceptionDetails,
|
12
15
|
EvalRunCreatedEvent,
|
13
16
|
EvalRunUpdatedEvent,
|
14
17
|
EvalSetRunCreatedEvent,
|
@@ -25,9 +28,11 @@ from .._runtime._contracts import (
|
|
25
28
|
UiPathRuntimeResult,
|
26
29
|
UiPathRuntimeStatus,
|
27
30
|
)
|
31
|
+
from .._runtime._logging import ExecutionLogHandler
|
28
32
|
from .._utils._eval_set import EvalHelpers
|
29
33
|
from ._evaluator_factory import EvaluatorFactory
|
30
34
|
from ._models._evaluation_set import EvaluationItem, EvaluationSet
|
35
|
+
from ._models._exceptions import EvaluationRuntimeException
|
31
36
|
from ._models._output import (
|
32
37
|
EvaluationResultDto,
|
33
38
|
EvaluationRunResult,
|
@@ -72,6 +77,33 @@ class ExecutionSpanExporter(SpanExporter):
|
|
72
77
|
self.clear()
|
73
78
|
|
74
79
|
|
80
|
+
class ExecutionLogsExporter:
|
81
|
+
"""Custom exporter that stores multiple execution log handlers."""
|
82
|
+
|
83
|
+
def __init__(self):
|
84
|
+
self._log_handlers: dict[str, ExecutionLogHandler] = {}
|
85
|
+
|
86
|
+
def register(self, execution_id: str, handler: ExecutionLogHandler) -> None:
|
87
|
+
self._log_handlers[execution_id] = handler
|
88
|
+
|
89
|
+
def get_logs(self, execution_id: str) -> list[logging.LogRecord]:
|
90
|
+
"""Clear stored spans for one or all executions."""
|
91
|
+
log_handler = self._log_handlers.get(execution_id)
|
92
|
+
return log_handler.buffer if log_handler else []
|
93
|
+
|
94
|
+
def clear(self, execution_id: Optional[str] = None) -> None:
|
95
|
+
"""Clear stored spans for one or all executions."""
|
96
|
+
if execution_id:
|
97
|
+
self._log_handlers.pop(execution_id, None)
|
98
|
+
else:
|
99
|
+
self._log_handlers.clear()
|
100
|
+
|
101
|
+
def flush_logs(self, execution_id: str, target_handler: logging.Handler) -> None:
|
102
|
+
log_handler = self._log_handlers.get(execution_id)
|
103
|
+
if log_handler:
|
104
|
+
log_handler.flush_execution_logs(target_handler)
|
105
|
+
|
106
|
+
|
75
107
|
class UiPathEvalContext(UiPathRuntimeContext):
|
76
108
|
"""Context used for evaluation runs."""
|
77
109
|
|
@@ -96,6 +128,8 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
96
128
|
self.event_bus: EventBus = event_bus
|
97
129
|
self.span_exporter: ExecutionSpanExporter = ExecutionSpanExporter()
|
98
130
|
self.factory.add_span_exporter(self.span_exporter)
|
131
|
+
self.logs_exporter: ExecutionLogsExporter = ExecutionLogsExporter()
|
132
|
+
self.execution_id = str(uuid.uuid4())
|
99
133
|
|
100
134
|
@classmethod
|
101
135
|
def from_eval_context(
|
@@ -110,9 +144,6 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
110
144
|
if self.context.eval_set is None:
|
111
145
|
raise ValueError("eval_set must be provided for evaluation runs")
|
112
146
|
|
113
|
-
if not self.context.execution_id:
|
114
|
-
raise ValueError("execution_id must be provided for evaluation runs")
|
115
|
-
|
116
147
|
event_bus = self.event_bus
|
117
148
|
|
118
149
|
evaluation_set = EvalHelpers.load_eval_set(
|
@@ -126,7 +157,7 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
126
157
|
await event_bus.publish(
|
127
158
|
EvaluationEvents.CREATE_EVAL_SET_RUN,
|
128
159
|
EvalSetRunCreatedEvent(
|
129
|
-
execution_id=self.
|
160
|
+
execution_id=self.execution_id,
|
130
161
|
entrypoint=self.context.entrypoint or "",
|
131
162
|
eval_set_id=evaluation_set.id,
|
132
163
|
no_of_evals=len(evaluation_set.evaluations),
|
@@ -142,7 +173,7 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
142
173
|
await event_bus.publish(
|
143
174
|
EvaluationEvents.CREATE_EVAL_RUN,
|
144
175
|
EvalRunCreatedEvent(
|
145
|
-
execution_id=self.
|
176
|
+
execution_id=self.execution_id,
|
146
177
|
eval_item=eval_item,
|
147
178
|
),
|
148
179
|
)
|
@@ -153,60 +184,96 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
153
184
|
|
154
185
|
results.evaluation_set_results.append(evaluation_run_results)
|
155
186
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
187
|
+
try:
|
188
|
+
agent_execution_output = await self.execute_runtime(eval_item)
|
189
|
+
evaluation_item_results: list[EvalItemResult] = []
|
190
|
+
|
191
|
+
for evaluator in evaluators:
|
192
|
+
evaluation_result = await self.run_evaluator(
|
193
|
+
evaluator=evaluator,
|
194
|
+
execution_output=agent_execution_output,
|
195
|
+
eval_item=eval_item,
|
196
|
+
)
|
165
197
|
|
166
|
-
|
167
|
-
|
168
|
-
)
|
169
|
-
evaluator_counts[evaluator.id] += 1
|
170
|
-
count = evaluator_counts[evaluator.id]
|
171
|
-
evaluator_averages[evaluator.id] += (
|
172
|
-
dto_result.score - evaluator_averages[evaluator.id]
|
173
|
-
) / count
|
174
|
-
|
175
|
-
evaluation_run_results.evaluation_run_results.append(
|
176
|
-
EvaluationRunResultDto(
|
177
|
-
evaluator_name=evaluator.name,
|
178
|
-
result=dto_result,
|
198
|
+
dto_result = EvaluationResultDto.from_evaluation_result(
|
199
|
+
evaluation_result
|
179
200
|
)
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
201
|
+
evaluator_counts[evaluator.id] += 1
|
202
|
+
count = evaluator_counts[evaluator.id]
|
203
|
+
evaluator_averages[evaluator.id] += (
|
204
|
+
dto_result.score - evaluator_averages[evaluator.id]
|
205
|
+
) / count
|
206
|
+
|
207
|
+
evaluation_run_results.evaluation_run_results.append(
|
208
|
+
EvaluationRunResultDto(
|
209
|
+
evaluator_name=evaluator.name,
|
210
|
+
result=dto_result,
|
211
|
+
)
|
185
212
|
)
|
213
|
+
evaluation_item_results.append(
|
214
|
+
EvalItemResult(
|
215
|
+
evaluator_id=evaluator.id,
|
216
|
+
result=evaluation_result,
|
217
|
+
)
|
218
|
+
)
|
219
|
+
|
220
|
+
evaluation_run_results.compute_average_score()
|
221
|
+
|
222
|
+
await event_bus.publish(
|
223
|
+
EvaluationEvents.UPDATE_EVAL_RUN,
|
224
|
+
EvalRunUpdatedEvent(
|
225
|
+
execution_id=self.execution_id,
|
226
|
+
eval_item=eval_item,
|
227
|
+
eval_results=evaluation_item_results,
|
228
|
+
success=not agent_execution_output.result.error,
|
229
|
+
agent_output=agent_execution_output.result.output,
|
230
|
+
agent_execution_time=agent_execution_output.execution_time,
|
231
|
+
spans=agent_execution_output.spans,
|
232
|
+
logs=agent_execution_output.logs,
|
233
|
+
),
|
234
|
+
wait_for_completion=False,
|
186
235
|
)
|
236
|
+
except Exception as e:
|
237
|
+
exception_details = EvalItemExceptionDetails(exception=e)
|
187
238
|
|
188
|
-
|
239
|
+
for evaluator in evaluators:
|
240
|
+
evaluator_counts[evaluator.id] += 1
|
241
|
+
count = evaluator_counts[evaluator.id]
|
242
|
+
evaluator_averages[evaluator.id] += (
|
243
|
+
0.0 - evaluator_averages[evaluator.id]
|
244
|
+
) / count
|
189
245
|
|
190
|
-
|
191
|
-
|
192
|
-
EvalRunUpdatedEvent(
|
193
|
-
execution_id=self.context.execution_id,
|
246
|
+
eval_run_updated_event = EvalRunUpdatedEvent(
|
247
|
+
execution_id=self.execution_id,
|
194
248
|
eval_item=eval_item,
|
195
|
-
eval_results=
|
196
|
-
success=
|
197
|
-
agent_output=
|
198
|
-
agent_execution_time=
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
249
|
+
eval_results=[],
|
250
|
+
success=False,
|
251
|
+
agent_output={},
|
252
|
+
agent_execution_time=0.0,
|
253
|
+
exception_details=exception_details,
|
254
|
+
spans=[],
|
255
|
+
logs=[],
|
256
|
+
)
|
257
|
+
if isinstance(e, EvaluationRuntimeException):
|
258
|
+
eval_run_updated_event.spans = e.spans
|
259
|
+
eval_run_updated_event.logs = e.logs
|
260
|
+
eval_run_updated_event.exception_details.exception = ( # type: ignore
|
261
|
+
e.root_exception
|
262
|
+
)
|
263
|
+
eval_run_updated_event.exception_details.runtime_exception = True # type: ignore
|
264
|
+
|
265
|
+
await event_bus.publish(
|
266
|
+
EvaluationEvents.UPDATE_EVAL_RUN,
|
267
|
+
eval_run_updated_event,
|
268
|
+
wait_for_completion=False,
|
269
|
+
)
|
203
270
|
|
204
271
|
results.compute_average_score()
|
205
272
|
|
206
273
|
await event_bus.publish(
|
207
274
|
EvaluationEvents.UPDATE_EVAL_SET_RUN,
|
208
275
|
EvalSetRunUpdatedEvent(
|
209
|
-
execution_id=self.
|
276
|
+
execution_id=self.execution_id,
|
210
277
|
evaluator_scores=evaluator_averages,
|
211
278
|
),
|
212
279
|
wait_for_completion=False,
|
@@ -218,14 +285,30 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
218
285
|
)
|
219
286
|
return self.context.result
|
220
287
|
|
288
|
+
def _get_and_clear_execution_data(
|
289
|
+
self, execution_id: str
|
290
|
+
) -> tuple[List[ReadableSpan], list[logging.LogRecord]]:
|
291
|
+
spans = self.span_exporter.get_spans(execution_id)
|
292
|
+
self.span_exporter.clear(execution_id)
|
293
|
+
|
294
|
+
logs = self.logs_exporter.get_logs(execution_id)
|
295
|
+
self.logs_exporter.clear(execution_id)
|
296
|
+
|
297
|
+
return spans, logs
|
298
|
+
|
221
299
|
async def execute_runtime(
|
222
300
|
self, eval_item: EvaluationItem
|
223
301
|
) -> UiPathEvalRunExecutionOutput:
|
302
|
+
eval_item_id = eval_item.id
|
224
303
|
runtime_context: C = self.factory.new_context(
|
225
|
-
execution_id=
|
304
|
+
execution_id=eval_item_id,
|
226
305
|
input_json=eval_item.inputs,
|
227
306
|
is_eval_run=True,
|
307
|
+
log_handler=self._setup_execution_logging(eval_item_id),
|
228
308
|
)
|
309
|
+
if runtime_context.execution_id is None:
|
310
|
+
raise ValueError("execution_id must be set for eval runs")
|
311
|
+
|
229
312
|
attributes = {
|
230
313
|
"evalId": eval_item.id,
|
231
314
|
"span_type": "eval",
|
@@ -234,18 +317,22 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
234
317
|
attributes["execution.id"] = runtime_context.execution_id
|
235
318
|
|
236
319
|
start_time = time()
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
320
|
+
try:
|
321
|
+
result = await self.factory.execute_in_root_span(
|
322
|
+
runtime_context, root_span=eval_item.name, attributes=attributes
|
323
|
+
)
|
324
|
+
except Exception as e:
|
325
|
+
spans, logs = self._get_and_clear_execution_data(
|
326
|
+
runtime_context.execution_id
|
327
|
+
)
|
328
|
+
raise EvaluationRuntimeException(
|
329
|
+
spans=spans,
|
330
|
+
logs=logs,
|
331
|
+
root_exception=e,
|
332
|
+
) from e
|
241
333
|
|
242
334
|
end_time = time()
|
243
|
-
|
244
|
-
if runtime_context.execution_id is None:
|
245
|
-
raise ValueError("execution_id must be set for eval runs")
|
246
|
-
|
247
|
-
spans = self.span_exporter.get_spans(runtime_context.execution_id)
|
248
|
-
self.span_exporter.clear(runtime_context.execution_id)
|
335
|
+
spans, logs = self._get_and_clear_execution_data(runtime_context.execution_id)
|
249
336
|
|
250
337
|
if result is None:
|
251
338
|
raise ValueError("Execution result cannot be None for eval runs")
|
@@ -253,9 +340,15 @@ class UiPathEvalRuntime(UiPathBaseRuntime, Generic[T, C]):
|
|
253
340
|
return UiPathEvalRunExecutionOutput(
|
254
341
|
execution_time=end_time - start_time,
|
255
342
|
spans=spans,
|
343
|
+
logs=logs,
|
256
344
|
result=result,
|
257
345
|
)
|
258
346
|
|
347
|
+
def _setup_execution_logging(self, eval_item_id: str) -> ExecutionLogHandler:
|
348
|
+
execution_log_handler = ExecutionLogHandler(eval_item_id)
|
349
|
+
self.logs_exporter.register(eval_item_id, execution_log_handler)
|
350
|
+
return execution_log_handler
|
351
|
+
|
259
352
|
async def run_evaluator(
|
260
353
|
self,
|
261
354
|
evaluator: BaseEvaluator[Any],
|
@@ -519,7 +519,8 @@ class UiPathBaseRuntime(ABC):
|
|
519
519
|
|
520
520
|
await self.validate()
|
521
521
|
|
522
|
-
# Intercept all stdout/stderr/logs
|
522
|
+
# Intercept all stdout/stderr/logs
|
523
|
+
# write to file (runtime) or stdout (debug)
|
523
524
|
self.logs_interceptor = LogsInterceptor(
|
524
525
|
min_level=self.context.logs_min_level,
|
525
526
|
dir=self.context.runtime_dir,
|
@@ -649,7 +650,7 @@ class UiPathBaseRuntime(ABC):
|
|
649
650
|
raise
|
650
651
|
finally:
|
651
652
|
# Restore original logging
|
652
|
-
if self
|
653
|
+
if hasattr(self, "logs_interceptor"):
|
653
654
|
self.logs_interceptor.teardown()
|
654
655
|
|
655
656
|
await self.cleanup()
|
@@ -698,6 +699,7 @@ class UiPathRuntimeFactory(Generic[T, C]):
|
|
698
699
|
self.context_generator = context_generator
|
699
700
|
self.tracer_provider: TracerProvider = TracerProvider()
|
700
701
|
self.tracer_span_processors: List[SpanProcessor] = []
|
702
|
+
self.logs_exporter: Optional[Any] = None
|
701
703
|
trace.set_tracer_provider(self.tracer_provider)
|
702
704
|
|
703
705
|
def add_span_exporter(
|
uipath/_cli/_runtime/_logging.py
CHANGED
@@ -10,6 +10,35 @@ current_execution_id: ContextVar[Optional[str]] = ContextVar(
|
|
10
10
|
)
|
11
11
|
|
12
12
|
|
13
|
+
class ExecutionLogHandler(logging.Handler):
|
14
|
+
"""Handler for an execution unit."""
|
15
|
+
|
16
|
+
def __init__(self, execution_id: str):
|
17
|
+
"""Initialize the buffered handler."""
|
18
|
+
super().__init__()
|
19
|
+
self.execution_id: str = execution_id
|
20
|
+
self.buffer: list[logging.LogRecord] = []
|
21
|
+
self.setFormatter(logging.Formatter("[%(asctime)s][%(levelname)s] %(message)s"))
|
22
|
+
|
23
|
+
def emit(self, record: logging.LogRecord):
|
24
|
+
"""Store log record in buffer grouped by execution_id."""
|
25
|
+
self.buffer.append(record)
|
26
|
+
|
27
|
+
def flush_execution_logs(self, target_handler: logging.Handler) -> None:
|
28
|
+
"""Flush buffered logs to a target handler.
|
29
|
+
|
30
|
+
Args:
|
31
|
+
target_handler: The handler to write the logs to
|
32
|
+
"""
|
33
|
+
for record in self.buffer:
|
34
|
+
target_handler.handle(record)
|
35
|
+
target_handler.flush()
|
36
|
+
|
37
|
+
def clear_execution(self) -> None:
|
38
|
+
"""Clear buffered logs without writing them."""
|
39
|
+
self.buffer.clear()
|
40
|
+
|
41
|
+
|
13
42
|
class PersistentLogsHandler(logging.FileHandler):
|
14
43
|
"""A simple log handler that always writes to a single file without rotation."""
|
15
44
|
|
uipath/_cli/cli_eval.py
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
import ast
|
3
3
|
import asyncio
|
4
4
|
import os
|
5
|
-
import uuid
|
6
5
|
from typing import List, Optional
|
7
6
|
|
8
7
|
import click
|
9
8
|
|
9
|
+
from uipath._cli._evals._console_progress_reporter import ConsoleProgressReporter
|
10
10
|
from uipath._cli._evals._progress_reporter import StudioWebProgressReporter
|
11
11
|
from uipath._cli._evals._runtime import (
|
12
12
|
UiPathEvalContext,
|
@@ -17,6 +17,7 @@ from uipath._cli._runtime._contracts import (
|
|
17
17
|
UiPathRuntimeFactory,
|
18
18
|
)
|
19
19
|
from uipath._cli._runtime._runtime import UiPathScriptRuntime
|
20
|
+
from uipath._cli._utils._constants import UIPATH_PROJECT_ID
|
20
21
|
from uipath._cli._utils._folders import get_personal_workspace_key_async
|
21
22
|
from uipath._cli.middlewares import Middlewares
|
22
23
|
from uipath._events._event_bus import EventBus
|
@@ -39,6 +40,22 @@ class LiteralOption(click.Option):
|
|
39
40
|
raise click.BadParameter(value) from e
|
40
41
|
|
41
42
|
|
43
|
+
def setup_reporting_prereq(no_report: bool) -> bool:
|
44
|
+
if no_report:
|
45
|
+
return False
|
46
|
+
|
47
|
+
if not os.getenv(UIPATH_PROJECT_ID, False):
|
48
|
+
console.warning(
|
49
|
+
"UIPATH_PROJECT_ID environment variable not set. Results will no be reported to Studio Web."
|
50
|
+
)
|
51
|
+
return False
|
52
|
+
if not os.getenv("UIPATH_FOLDER_KEY"):
|
53
|
+
os.environ["UIPATH_FOLDER_KEY"] = asyncio.run(
|
54
|
+
get_personal_workspace_key_async()
|
55
|
+
)
|
56
|
+
return True
|
57
|
+
|
58
|
+
|
42
59
|
@click.command()
|
43
60
|
@click.argument("entrypoint", required=False)
|
44
61
|
@click.argument("eval_set", required=False)
|
@@ -79,10 +96,7 @@ def eval(
|
|
79
96
|
workers: Number of parallel workers for running evaluations
|
80
97
|
no_report: Do not report the evaluation results
|
81
98
|
"""
|
82
|
-
|
83
|
-
os.environ["UIPATH_FOLDER_KEY"] = asyncio.run(
|
84
|
-
get_personal_workspace_key_async()
|
85
|
-
)
|
99
|
+
should_register_progress_reporter = setup_reporting_prereq(no_report)
|
86
100
|
|
87
101
|
result = Middlewares.next(
|
88
102
|
"eval",
|
@@ -92,6 +106,7 @@ def eval(
|
|
92
106
|
no_report=no_report,
|
93
107
|
workers=workers,
|
94
108
|
execution_output_file=output_file,
|
109
|
+
register_progress_reporter=should_register_progress_reporter,
|
95
110
|
)
|
96
111
|
|
97
112
|
if result.error_message:
|
@@ -100,7 +115,7 @@ def eval(
|
|
100
115
|
if result.should_continue:
|
101
116
|
event_bus = EventBus()
|
102
117
|
|
103
|
-
if
|
118
|
+
if should_register_progress_reporter:
|
104
119
|
progress_reporter = StudioWebProgressReporter(LlmOpsHttpExporter())
|
105
120
|
asyncio.run(progress_reporter.subscribe_to_eval_runtime_events(event_bus))
|
106
121
|
|
@@ -114,7 +129,6 @@ def eval(
|
|
114
129
|
eval_context = UiPathEvalContext.with_defaults(
|
115
130
|
execution_output_file=output_file,
|
116
131
|
entrypoint=runtime_entrypoint,
|
117
|
-
execution_id=str(uuid.uuid4()),
|
118
132
|
)
|
119
133
|
|
120
134
|
eval_context.no_report = no_report
|
@@ -122,6 +136,9 @@ def eval(
|
|
122
136
|
eval_context.eval_set = eval_set or EvalHelpers.auto_discover_eval_set()
|
123
137
|
eval_context.eval_ids = eval_ids
|
124
138
|
|
139
|
+
console_reporter = ConsoleProgressReporter()
|
140
|
+
asyncio.run(console_reporter.subscribe_to_eval_runtime_events(event_bus))
|
141
|
+
|
125
142
|
try:
|
126
143
|
runtime_factory = UiPathRuntimeFactory(
|
127
144
|
UiPathScriptRuntime,
|
@@ -143,11 +160,9 @@ def eval(
|
|
143
160
|
asyncio.run(execute())
|
144
161
|
except Exception as e:
|
145
162
|
console.error(
|
146
|
-
f"Error:
|
163
|
+
f"Error occurred: {e or 'Execution failed'}", include_traceback=True
|
147
164
|
)
|
148
165
|
|
149
|
-
console.success("Evaluation completed successfully")
|
150
|
-
|
151
166
|
|
152
167
|
if __name__ == "__main__":
|
153
168
|
eval()
|
uipath/_cli/middlewares.py
CHANGED
@@ -121,20 +121,20 @@ class Middlewares:
|
|
121
121
|
]
|
122
122
|
|
123
123
|
if middlewares:
|
124
|
-
logger.
|
124
|
+
logger.debug(f"Found {len(middlewares)} middleware plugins")
|
125
125
|
|
126
126
|
for entry_point in middlewares:
|
127
127
|
try:
|
128
128
|
register_func = entry_point.load()
|
129
129
|
register_func()
|
130
|
-
logger.
|
130
|
+
logger.debug(f"Loaded middleware plugin: {entry_point.name}")
|
131
131
|
except Exception as e:
|
132
132
|
console.error(
|
133
133
|
f"Failed to load middleware plugin {entry_point.name}: {str(e)}",
|
134
134
|
include_traceback=True,
|
135
135
|
)
|
136
136
|
else:
|
137
|
-
logger.
|
137
|
+
logger.debug("No middleware plugins found")
|
138
138
|
|
139
139
|
except Exception as e:
|
140
140
|
logger.error(f"No middleware plugins loaded: {str(e)}")
|
uipath/_events/_events.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
import enum
|
2
|
-
|
2
|
+
import logging
|
3
|
+
from typing import Any, List, Optional, Union
|
3
4
|
|
4
5
|
from opentelemetry.sdk.trace import ReadableSpan
|
5
|
-
from pydantic import BaseModel, ConfigDict
|
6
|
+
from pydantic import BaseModel, ConfigDict, model_validator
|
6
7
|
|
7
8
|
from uipath._cli._evals._models._evaluation_set import EvaluationItem
|
8
9
|
from uipath.eval.models import EvalItemResult
|
@@ -28,6 +29,13 @@ class EvalRunCreatedEvent(BaseModel):
|
|
28
29
|
eval_item: EvaluationItem
|
29
30
|
|
30
31
|
|
32
|
+
class EvalItemExceptionDetails(BaseModel):
|
33
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
34
|
+
|
35
|
+
runtime_exception: bool = False
|
36
|
+
exception: Exception
|
37
|
+
|
38
|
+
|
31
39
|
class EvalRunUpdatedEvent(BaseModel):
|
32
40
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
33
41
|
|
@@ -38,6 +46,14 @@ class EvalRunUpdatedEvent(BaseModel):
|
|
38
46
|
agent_output: Any
|
39
47
|
agent_execution_time: float
|
40
48
|
spans: List[ReadableSpan]
|
49
|
+
logs: List[logging.LogRecord]
|
50
|
+
exception_details: Optional[EvalItemExceptionDetails] = None
|
51
|
+
|
52
|
+
@model_validator(mode="after")
|
53
|
+
def validate_exception_details(self):
|
54
|
+
if not self.success and self.exception_details is None:
|
55
|
+
raise ValueError("exception_details must be provided when success is False")
|
56
|
+
return self
|
41
57
|
|
42
58
|
|
43
59
|
class EvalSetRunUpdatedEvent(BaseModel):
|
@@ -1,14 +1,17 @@
|
|
1
1
|
import json
|
2
2
|
import logging
|
3
|
-
from typing import Any, Dict
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
|
+
|
5
|
+
from httpx import Response
|
4
6
|
|
5
7
|
from .._config import Config
|
6
8
|
from .._execution_context import ExecutionContext
|
7
|
-
from .._utils import Endpoint, RequestSpec, infer_bindings
|
9
|
+
from .._utils import Endpoint, RequestSpec, header_folder, infer_bindings
|
8
10
|
from ..models import Connection, ConnectionToken, EventArguments
|
9
11
|
from ..models.connections import ConnectionTokenType
|
10
12
|
from ..tracing._traced import traced
|
11
13
|
from ._base_service import BaseService
|
14
|
+
from .folder_service import FolderService
|
12
15
|
|
13
16
|
logger: logging.Logger = logging.getLogger("uipath")
|
14
17
|
|
@@ -20,9 +23,16 @@ class ConnectionsService(BaseService):
|
|
20
23
|
and secure token management.
|
21
24
|
"""
|
22
25
|
|
23
|
-
def __init__(
|
26
|
+
def __init__(
|
27
|
+
self,
|
28
|
+
config: Config,
|
29
|
+
execution_context: ExecutionContext,
|
30
|
+
folders_service: FolderService,
|
31
|
+
) -> None:
|
24
32
|
super().__init__(config=config, execution_context=execution_context)
|
33
|
+
self._folders_service = folders_service
|
25
34
|
|
35
|
+
@infer_bindings(resource_type="connection", name="key")
|
26
36
|
@traced(
|
27
37
|
name="connections_retrieve",
|
28
38
|
run_type="uipath",
|
@@ -45,6 +55,117 @@ class ConnectionsService(BaseService):
|
|
45
55
|
response = self.request(spec.method, url=spec.endpoint)
|
46
56
|
return Connection.model_validate(response.json())
|
47
57
|
|
58
|
+
@traced(name="connections_list", run_type="uipath")
|
59
|
+
def list(
|
60
|
+
self,
|
61
|
+
*,
|
62
|
+
name: Optional[str] = None,
|
63
|
+
folder_path: Optional[str] = None,
|
64
|
+
folder_key: Optional[str] = None,
|
65
|
+
connector_key: Optional[str] = None,
|
66
|
+
skip: Optional[int] = None,
|
67
|
+
top: Optional[int] = None,
|
68
|
+
) -> List[Connection]:
|
69
|
+
"""Lists all connections with optional filtering.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
name: Optional connection name to filter (supports partial matching)
|
73
|
+
folder_path: Optional folder path for filtering connections
|
74
|
+
folder_key: Optional folder key (mutually exclusive with folder_path)
|
75
|
+
connector_key: Optional connector key to filter by specific connector type
|
76
|
+
skip: Number of records to skip (for pagination)
|
77
|
+
top: Maximum number of records to return
|
78
|
+
|
79
|
+
Returns:
|
80
|
+
List[Connection]: List of connection instances
|
81
|
+
|
82
|
+
Raises:
|
83
|
+
ValueError: If both folder_path and folder_key are provided together, or if
|
84
|
+
folder_path is provided but cannot be resolved to a folder_key
|
85
|
+
|
86
|
+
Examples:
|
87
|
+
>>> # List all connections
|
88
|
+
>>> connections = sdk.connections.list()
|
89
|
+
|
90
|
+
>>> # Find connections by name
|
91
|
+
>>> salesforce_conns = sdk.connections.list(name="Salesforce")
|
92
|
+
|
93
|
+
>>> # List all Slack connections in Finance folder
|
94
|
+
>>> connections = sdk.connections.list(
|
95
|
+
... folder_path="Finance",
|
96
|
+
... connector_key="uipath-slack"
|
97
|
+
... )
|
98
|
+
"""
|
99
|
+
spec = self._list_spec(
|
100
|
+
name=name,
|
101
|
+
folder_path=folder_path,
|
102
|
+
folder_key=folder_key,
|
103
|
+
connector_key=connector_key,
|
104
|
+
skip=skip,
|
105
|
+
top=top,
|
106
|
+
)
|
107
|
+
response = self.request(
|
108
|
+
spec.method, url=spec.endpoint, params=spec.params, headers=spec.headers
|
109
|
+
)
|
110
|
+
|
111
|
+
return self._parse_and_validate_list_response(response)
|
112
|
+
|
113
|
+
@traced(name="connections_list", run_type="uipath")
|
114
|
+
async def list_async(
|
115
|
+
self,
|
116
|
+
*,
|
117
|
+
name: Optional[str] = None,
|
118
|
+
folder_path: Optional[str] = None,
|
119
|
+
folder_key: Optional[str] = None,
|
120
|
+
connector_key: Optional[str] = None,
|
121
|
+
skip: Optional[int] = None,
|
122
|
+
top: Optional[int] = None,
|
123
|
+
) -> List[Connection]:
|
124
|
+
"""Asynchronously lists all connections with optional filtering.
|
125
|
+
|
126
|
+
Args:
|
127
|
+
name: Optional connection name to filter (supports partial matching)
|
128
|
+
folder_path: Optional folder path for filtering connections
|
129
|
+
folder_key: Optional folder key (mutually exclusive with folder_path)
|
130
|
+
connector_key: Optional connector key to filter by specific connector type
|
131
|
+
skip: Number of records to skip (for pagination)
|
132
|
+
top: Maximum number of records to return
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
List[Connection]: List of connection instances
|
136
|
+
|
137
|
+
Raises:
|
138
|
+
ValueError: If both folder_path and folder_key are provided together, or if
|
139
|
+
folder_path is provided but cannot be resolved to a folder_key
|
140
|
+
|
141
|
+
Examples:
|
142
|
+
>>> # List all connections
|
143
|
+
>>> connections = await sdk.connections.list_async()
|
144
|
+
|
145
|
+
>>> # Find connections by name
|
146
|
+
>>> salesforce_conns = await sdk.connections.list_async(name="Salesforce")
|
147
|
+
|
148
|
+
>>> # List all Slack connections in Finance folder
|
149
|
+
>>> connections = await sdk.connections.list_async(
|
150
|
+
... folder_path="Finance",
|
151
|
+
... connector_key="uipath-slack"
|
152
|
+
... )
|
153
|
+
"""
|
154
|
+
spec = self._list_spec(
|
155
|
+
name=name,
|
156
|
+
folder_path=folder_path,
|
157
|
+
folder_key=folder_key,
|
158
|
+
connector_key=connector_key,
|
159
|
+
skip=skip,
|
160
|
+
top=top,
|
161
|
+
)
|
162
|
+
response = await self.request_async(
|
163
|
+
spec.method, url=spec.endpoint, params=spec.params, headers=spec.headers
|
164
|
+
)
|
165
|
+
|
166
|
+
return self._parse_and_validate_list_response(response)
|
167
|
+
|
168
|
+
@infer_bindings(resource_type="connection", name="key")
|
48
169
|
@traced(
|
49
170
|
name="connections_retrieve",
|
50
171
|
run_type="uipath",
|
@@ -213,3 +334,97 @@ class ConnectionsService(BaseService):
|
|
213
334
|
endpoint=Endpoint(f"/connections_/api/v1/Connections/{key}/token"),
|
214
335
|
params={"tokenType": token_type.value},
|
215
336
|
)
|
337
|
+
|
338
|
+
def _parse_and_validate_list_response(self, response: Response) -> List[Connection]:
|
339
|
+
"""Parse and validate the list response from the API.
|
340
|
+
|
341
|
+
Handles both OData response format (with 'value' field) and raw list responses.
|
342
|
+
|
343
|
+
Args:
|
344
|
+
response: The HTTP response from the API
|
345
|
+
|
346
|
+
Returns:
|
347
|
+
List of validated Connection instances
|
348
|
+
"""
|
349
|
+
data = response.json()
|
350
|
+
|
351
|
+
# Handle both OData responses (dict with 'value') and raw list responses
|
352
|
+
if isinstance(data, dict):
|
353
|
+
connections_data = data.get("value", [])
|
354
|
+
elif isinstance(data, list):
|
355
|
+
connections_data = data
|
356
|
+
else:
|
357
|
+
connections_data = []
|
358
|
+
|
359
|
+
return [Connection.model_validate(conn) for conn in connections_data]
|
360
|
+
|
361
|
+
def _list_spec(
|
362
|
+
self,
|
363
|
+
name: Optional[str] = None,
|
364
|
+
folder_path: Optional[str] = None,
|
365
|
+
folder_key: Optional[str] = None,
|
366
|
+
connector_key: Optional[str] = None,
|
367
|
+
skip: Optional[int] = None,
|
368
|
+
top: Optional[int] = None,
|
369
|
+
) -> RequestSpec:
|
370
|
+
"""Build the request specification for listing connections.
|
371
|
+
|
372
|
+
Args:
|
373
|
+
name: Optional connection name to filter (supports partial matching)
|
374
|
+
folder_path: Optional folder path for filtering connections
|
375
|
+
folder_key: Optional folder key (mutually exclusive with folder_path)
|
376
|
+
connector_key: Optional connector key to filter by specific connector type
|
377
|
+
skip: Number of records to skip (for pagination)
|
378
|
+
top: Maximum number of records to return
|
379
|
+
|
380
|
+
Returns:
|
381
|
+
RequestSpec with endpoint, params, and headers configured
|
382
|
+
|
383
|
+
Raises:
|
384
|
+
ValueError: If both folder_path and folder_key are provided together, or if
|
385
|
+
folder_path is provided but cannot be resolved to a folder_key
|
386
|
+
"""
|
387
|
+
# Validate mutual exclusivity of folder_path and folder_key
|
388
|
+
if folder_path is not None and folder_key is not None:
|
389
|
+
raise ValueError(
|
390
|
+
"folder_path and folder_key are mutually exclusive and cannot be provided together"
|
391
|
+
)
|
392
|
+
|
393
|
+
# Resolve folder_path to folder_key if needed
|
394
|
+
resolved_folder_key = folder_key
|
395
|
+
if not resolved_folder_key and folder_path:
|
396
|
+
resolved_folder_key = self._folders_service.retrieve_key(
|
397
|
+
folder_path=folder_path
|
398
|
+
)
|
399
|
+
if not resolved_folder_key:
|
400
|
+
raise ValueError(f"Folder with path '{folder_path}' not found")
|
401
|
+
|
402
|
+
# Build OData filters
|
403
|
+
filters = []
|
404
|
+
if name:
|
405
|
+
# Escape single quotes in name for OData
|
406
|
+
escaped_name = name.replace("'", "''")
|
407
|
+
filters.append(f"contains(Name, '{escaped_name}')")
|
408
|
+
if connector_key:
|
409
|
+
filters.append(f"connector/key eq '{connector_key}'")
|
410
|
+
|
411
|
+
params = {}
|
412
|
+
if filters:
|
413
|
+
params["$filter"] = " and ".join(filters)
|
414
|
+
if skip is not None:
|
415
|
+
params["$skip"] = str(skip)
|
416
|
+
if top is not None:
|
417
|
+
params["$top"] = str(top)
|
418
|
+
|
419
|
+
# Always expand connector and folder for complete information
|
420
|
+
params["$expand"] = "connector,folder"
|
421
|
+
|
422
|
+
# Use header_folder which handles validation
|
423
|
+
headers = header_folder(resolved_folder_key, None)
|
424
|
+
|
425
|
+
return RequestSpec(
|
426
|
+
method="GET",
|
427
|
+
endpoint=Endpoint("/connections_/api/v1/Connections"),
|
428
|
+
params=params,
|
429
|
+
headers=headers,
|
430
|
+
)
|
uipath/_uipath.py
CHANGED
@@ -60,6 +60,7 @@ class UiPath:
|
|
60
60
|
self._folders_service: Optional[FolderService] = None
|
61
61
|
self._buckets_service: Optional[BucketsService] = None
|
62
62
|
self._attachments_service: Optional[AttachmentsService] = None
|
63
|
+
self._connections_service: Optional[ConnectionsService] = None
|
63
64
|
|
64
65
|
setup_logging(debug)
|
65
66
|
self._execution_context = ExecutionContext()
|
@@ -98,7 +99,15 @@ class UiPath:
|
|
98
99
|
|
99
100
|
@property
|
100
101
|
def connections(self) -> ConnectionsService:
|
101
|
-
|
102
|
+
if not self._connections_service:
|
103
|
+
if not self._folders_service:
|
104
|
+
self._folders_service = FolderService(
|
105
|
+
self._config, self._execution_context
|
106
|
+
)
|
107
|
+
self._connections_service = ConnectionsService(
|
108
|
+
self._config, self._execution_context, self._folders_service
|
109
|
+
)
|
110
|
+
return self._connections_service
|
102
111
|
|
103
112
|
@property
|
104
113
|
def context_grounding(self) -> ContextGroundingService:
|
uipath/_utils/_infer_bindings.py
CHANGED
@@ -28,8 +28,10 @@ def infer_bindings(
|
|
28
28
|
all_args.get(name), # type: ignore
|
29
29
|
all_args.get(folder_path, None),
|
30
30
|
) as (name_overwrite_or_default, folder_path_overwrite_or_default):
|
31
|
-
|
32
|
-
|
31
|
+
if name in sig.parameters:
|
32
|
+
all_args[name] = name_overwrite_or_default
|
33
|
+
if folder_path in sig.parameters:
|
34
|
+
all_args[folder_path] = folder_path_overwrite_or_default
|
33
35
|
|
34
36
|
return func(**all_args)
|
35
37
|
|
uipath/telemetry/_track.py
CHANGED
@@ -2,7 +2,7 @@ import json
|
|
2
2
|
import os
|
3
3
|
from functools import wraps
|
4
4
|
from importlib.metadata import version
|
5
|
-
from logging import
|
5
|
+
from logging import WARNING, LogRecord, getLogger
|
6
6
|
from typing import Any, Callable, Dict, Optional, Union
|
7
7
|
|
8
8
|
from azure.monitor.opentelemetry import configure_azure_monitor
|
@@ -102,7 +102,7 @@ class _TelemetryClient:
|
|
102
102
|
)
|
103
103
|
|
104
104
|
_logger.addHandler(_AzureMonitorOpenTelemetryEventHandler())
|
105
|
-
_logger.setLevel(
|
105
|
+
_logger.setLevel(WARNING)
|
106
106
|
|
107
107
|
_TelemetryClient._initialized = True
|
108
108
|
except Exception:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: uipath
|
3
|
-
Version: 2.1.
|
3
|
+
Version: 2.1.76
|
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
|
@@ -2,14 +2,14 @@ uipath/__init__.py,sha256=IaeKItOOQXMa95avueJ3dAq-XcRHyZVNjcCGwlSB000,634
|
|
2
2
|
uipath/_config.py,sha256=pi3qxPzDTxMEstj_XkGOgKJqD6RTHHv7vYv8sS_-d5Q,92
|
3
3
|
uipath/_execution_context.py,sha256=Qo8VMUFgtiL-40KsZrvul5bGv1CRERle_fCw1ORCggY,2374
|
4
4
|
uipath/_folder_context.py,sha256=D-bgxdwpwJP4b_QdVKcPODYh15kMDrOar2xNonmMSm4,1861
|
5
|
-
uipath/_uipath.py,sha256=
|
5
|
+
uipath/_uipath.py,sha256=xvBwczfjrvrB96ZK7wo0IgDcPDQWuEqu4dioH9CKd4k,5021
|
6
6
|
uipath/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
7
|
uipath/_cli/README.md,sha256=GLtCfbeIKZKNnGTCsfSVqRQ27V1btT1i2bSAyW_xZl4,474
|
8
8
|
uipath/_cli/__init__.py,sha256=2RUgXYd8uJaYjA67xWb0w4IZuBmZoY8G1ccNmEQk9oM,2343
|
9
9
|
uipath/_cli/cli_auth.py,sha256=ZEA0Fwoo77Ez9ctpRAIq7sbAwj8F4OouAbMp1g1OvjM,2601
|
10
10
|
uipath/_cli/cli_deploy.py,sha256=KPCmQ0c_NYD5JofSDao5r6QYxHshVCRxlWDVnQvlp5w,645
|
11
11
|
uipath/_cli/cli_dev.py,sha256=nEfpjw1PZ72O6jmufYWVrueVwihFxDPOeJakdvNHdOA,2146
|
12
|
-
uipath/_cli/cli_eval.py,sha256=
|
12
|
+
uipath/_cli/cli_eval.py,sha256=Tg9mEf0T4qkp_YpcqJVxmPp69JkjHF68teX4CM061F0,5444
|
13
13
|
uipath/_cli/cli_init.py,sha256=Ac3-9tIH3rpikIX1ehWTo7InW5tjVNoz_w6fjvgLK4w,7052
|
14
14
|
uipath/_cli/cli_invoke.py,sha256=m-te-EjhDpk_fhFDkt-yQFzmjEHGo5lQDGEQWxSXisQ,4395
|
15
15
|
uipath/_cli/cli_new.py,sha256=9378NYUBc9j-qKVXV7oja-jahfJhXBg8zKVyaon7ctY,2102
|
@@ -18,7 +18,7 @@ uipath/_cli/cli_publish.py,sha256=DgyfcZjvfV05Ldy0Pk5y_Le_nT9JduEE_x-VpIc_Kq0,64
|
|
18
18
|
uipath/_cli/cli_pull.py,sha256=PZ2hkfsfN-ElNa3FHjNetTux8XH03tDY5kWWqydQ2OY,6832
|
19
19
|
uipath/_cli/cli_push.py,sha256=-j-gDIbT8GyU2SybLQqFl5L8KI9nu3CDijVtltDgX20,3132
|
20
20
|
uipath/_cli/cli_run.py,sha256=1FKv20EjxrrP1I5rNSnL_HzbWtOAIMjB3M--4RPA_Yo,3709
|
21
|
-
uipath/_cli/middlewares.py,sha256=
|
21
|
+
uipath/_cli/middlewares.py,sha256=0D9a-wphyetnH9T97F08o7-1OKWF1lMweFHHAR0xiOw,4979
|
22
22
|
uipath/_cli/spinner.py,sha256=bS-U_HA5yne11ejUERu7CQoXmWdabUD2bm62EfEdV8M,1107
|
23
23
|
uipath/_cli/_auth/_auth_server.py,sha256=22km0F1NFNXgyLbvtAx3ssiQlVGHroLdtDCWEqiCiMg,7106
|
24
24
|
uipath/_cli/_auth/_auth_service.py,sha256=Thtp2wXZQAHqossPPXuP6sAEe4Px9xThhZutMECRrdU,6386
|
@@ -44,13 +44,15 @@ uipath/_cli/_dev/_terminal/_styles/terminal.tcss,sha256=ktVpKwXIXw2VZp8KIZD6fO9i
|
|
44
44
|
uipath/_cli/_dev/_terminal/_utils/_chat.py,sha256=YUZxYVdmEManwHDuZsczJT1dWIYE1dVBgABlurwMFcE,8493
|
45
45
|
uipath/_cli/_dev/_terminal/_utils/_exporter.py,sha256=oI6D_eMwrh_2aqDYUh4GrJg8VLGrLYhDahR-_o0uJns,4144
|
46
46
|
uipath/_cli/_dev/_terminal/_utils/_logger.py,sha256=_ipTl_oAiMF9I7keGt2AAFAMz40DNLVMVkoiq-07UAU,2943
|
47
|
+
uipath/_cli/_evals/_console_progress_reporter.py,sha256=HgB6pdMyoS6YVwuI3EpM2LBcH3U69nrdaTyNgPG8ssg,9304
|
47
48
|
uipath/_cli/_evals/_evaluator_factory.py,sha256=Gycv94VtGOpMir_Gba-UoiAyrSRfbSfe8_pTfjzcA9Q,3875
|
48
|
-
uipath/_cli/_evals/_progress_reporter.py,sha256=
|
49
|
-
uipath/_cli/_evals/_runtime.py,sha256=
|
49
|
+
uipath/_cli/_evals/_progress_reporter.py,sha256=kX7rNSa-QCLXIzK-vb9Jjf-XLEtucdeiQPgPlSkpp2U,16778
|
50
|
+
uipath/_cli/_evals/_runtime.py,sha256=dz3mpZCLxwnLEdkwLo6W7qzBuVAklx6LMWtd4OMRk9w,15489
|
50
51
|
uipath/_cli/_evals/_models/_evaluation_set.py,sha256=XgPNLWciE4FgCYzZXV2kRYHzdtbc33FWSQmZQqVSdMk,4747
|
51
52
|
uipath/_cli/_evals/_models/_evaluator.py,sha256=fuC3UOYwPD4d_wdynHeLSCzbu82golNAnnPnxC8Y4rk,3315
|
52
53
|
uipath/_cli/_evals/_models/_evaluator_base_params.py,sha256=lTYKOV66tcjW85KHTyOdtF1p1VDaBNemrMAvH8bFIFc,382
|
53
|
-
uipath/_cli/_evals/_models/
|
54
|
+
uipath/_cli/_evals/_models/_exceptions.py,sha256=-oXLTDa4ab9Boa34ZxuUrCezf8ajIGrIEUVwZnmBASE,195
|
55
|
+
uipath/_cli/_evals/_models/_output.py,sha256=DmwFXh1YdLiMXyXmyoZr_4hgrrv3oiHbrrtIWMqGfsg,3145
|
54
56
|
uipath/_cli/_evals/_models/_sw_reporting.py,sha256=tSBLQFAdOIun8eP0vsqt56K6bmCZz_uMaWI3hskg_24,536
|
55
57
|
uipath/_cli/_evals/_models/_trajectory_span.py,sha256=8ukM8sB9rvzBMHfC_gnexAC3xlp4uMDevKZrRzcgrm4,3637
|
56
58
|
uipath/_cli/_evals/mocks/__init__.py,sha256=2WXwAy_oZw5bKp6L0HB13QygCJeftOB_Bget0AI6Gik,32
|
@@ -60,10 +62,10 @@ uipath/_cli/_evals/mocks/mocker_factory.py,sha256=V5QKSTtQxztTo4-fK1TyAaXw2Z3mHf
|
|
60
62
|
uipath/_cli/_evals/mocks/mockito_mocker.py,sha256=LtYT6lJM9vc3qtbSZJcUeCzDn4zarkBVj7In_EX7kYY,2087
|
61
63
|
uipath/_cli/_evals/mocks/mocks.py,sha256=WqjWtHqKQXAsO1Wwom3Zcr1T09GQygwBWVp-EsxdW8o,4443
|
62
64
|
uipath/_cli/_push/sw_file_handler.py,sha256=iE8Sk1Z-9hxmLFFj3j-k4kTK6TzNFP6hUCmxTudG6JQ,18251
|
63
|
-
uipath/_cli/_runtime/_contracts.py,sha256=
|
65
|
+
uipath/_cli/_runtime/_contracts.py,sha256=E8Is7EQfAu7_hCbeZI68gmTxSxo4X7_U4vcSl7D3Syg,28988
|
64
66
|
uipath/_cli/_runtime/_escalation.py,sha256=x3vI98qsfRA-fL_tNkRVTFXioM5Gv2w0GFcXJJ5eQtg,7981
|
65
67
|
uipath/_cli/_runtime/_hitl.py,sha256=VKbM021nVg1HEDnTfucSLJ0LsDn83CKyUtVzofS2qTU,11369
|
66
|
-
uipath/_cli/_runtime/_logging.py,sha256=
|
68
|
+
uipath/_cli/_runtime/_logging.py,sha256=jwBfsy0Hi4zkfPH-v9dQ7m5dcJeuE0j_OxdpI-DhHaw,13854
|
67
69
|
uipath/_cli/_runtime/_runtime.py,sha256=gby9-avNNlEATEfSXtY8FfJ8nREsSCGA4wMgDlSXTDE,2297
|
68
70
|
uipath/_cli/_runtime/_script_executor.py,sha256=PjbmEbyCMofGH2F85b8RFsxdV3Tqw0kVqdWOOk2ZLlI,9687
|
69
71
|
uipath/_cli/_templates/.psmdcp.template,sha256=C7pBJPt98ovEljcBvGtEUGoWjjQhu9jls1bpYjeLOKA,611
|
@@ -86,7 +88,7 @@ uipath/_cli/_utils/_tracing.py,sha256=2igb03j3EHjF_A406UhtCKkPfudVfFPjUq5tXUEG4o
|
|
86
88
|
uipath/_cli/_utils/_uv_helpers.py,sha256=6SvoLnZPoKIxW0sjMvD1-ENV_HOXDYzH34GjBqwT138,3450
|
87
89
|
uipath/_events/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
88
90
|
uipath/_events/_event_bus.py,sha256=4-VzstyX69cr7wT1EY7ywp-Ndyz2CyemD3Wk_-QmRpo,5496
|
89
|
-
uipath/_events/_events.py,sha256=
|
91
|
+
uipath/_events/_events.py,sha256=EzDfzpVm-EIH27Onad5mo8Go6-WB3S6_-6zZQ7qV58w,1811
|
90
92
|
uipath/_resources/AGENTS.md,sha256=YWhWuX9XIbyVhVT3PnPc4Of3_q6bsNJcuzYu3N8f_Ug,25850
|
91
93
|
uipath/_services/__init__.py,sha256=eYZElMfYDQTQU6MMjIke5J-GGT9pzLD5QfbwLiTQkEE,1037
|
92
94
|
uipath/_services/_base_service.py,sha256=x9-9jhPzn9Z16KRdFHhJNvV-FZHvTniMsDfxlS4Cutk,5782
|
@@ -95,7 +97,7 @@ uipath/_services/api_client.py,sha256=kGm04ijk9AOEQd2BMxvQg-2QoB8dmyoDwFFDPyutAG
|
|
95
97
|
uipath/_services/assets_service.py,sha256=pG0Io--SeiRRQmfUWPQPl1vq3csZlQgx30LBNKRmmF8,12145
|
96
98
|
uipath/_services/attachments_service.py,sha256=NPQYK7CGjfBaNT_1S5vEAfODmOChTbQZforllFM2ofU,26678
|
97
99
|
uipath/_services/buckets_service.py,sha256=5s8tuivd7GUZYj774DDUYTa0axxlUuesc4EBY1V5sdk,18496
|
98
|
-
uipath/_services/connections_service.py,sha256=
|
100
|
+
uipath/_services/connections_service.py,sha256=EbM4ywaJsvafPEhL5bLZDWLMOUK1UyDVLRc4vZgu3Fo,15905
|
99
101
|
uipath/_services/context_grounding_service.py,sha256=Pjx-QQQEiSKD-hY6ityj3QUSALN3fIcKLLHr_NZ0d_g,37117
|
100
102
|
uipath/_services/documents_service.py,sha256=UnFS8EpOZ_Ng2TZk3OiJJ3iNANvFs7QxuoG_v-lQj6c,24815
|
101
103
|
uipath/_services/entities_service.py,sha256=QKCLE6wRgq3HZraF-M2mljy-8il4vsNHrQhUgkewVVk,14028
|
@@ -106,7 +108,7 @@ uipath/_services/processes_service.py,sha256=O_uHgQ1rnwiV5quG0OQqabAnE6Rf6cWrMEN
|
|
106
108
|
uipath/_services/queues_service.py,sha256=VaG3dWL2QK6AJBOLoW2NQTpkPfZjsqsYPl9-kfXPFzA,13534
|
107
109
|
uipath/_utils/__init__.py,sha256=VdcpnENJIa0R6Y26NoxY64-wUVyvb4pKfTh1wXDQeMk,526
|
108
110
|
uipath/_utils/_endpoint.py,sha256=yYHwqbQuJIevpaTkdfYJS9CrtlFeEyfb5JQK5osTCog,2489
|
109
|
-
uipath/_utils/_infer_bindings.py,sha256=
|
111
|
+
uipath/_utils/_infer_bindings.py,sha256=eCxfUjd37fOFZ6vOfKl2BhWVUt7iSSJ-VQ0-nDTBcaA,1836
|
110
112
|
uipath/_utils/_logs.py,sha256=adfX_0UAn3YBeKJ8DQDeZs94rJyHGQO00uDfkaTpNWQ,510
|
111
113
|
uipath/_utils/_read_overwrites.py,sha256=OQgG9ycPpFnLub5ELQdX9V2Fyh6F9_zDR3xoYagJaMI,5287
|
112
114
|
uipath/_utils/_request_override.py,sha256=fIVHzgHVXITUlWcp8osNBwIafM1qm4_ejx0ng5UzfJ4,573
|
@@ -158,15 +160,15 @@ uipath/models/processes.py,sha256=bV31xTyF0hRWZmwy3bWj5L8dBD9wttWxfJjwzhjETmk,19
|
|
158
160
|
uipath/models/queues.py,sha256=gnbeEyYlHtdqdxBalio0lw8mq-78YBG9MPMSkv1BWOg,6934
|
159
161
|
uipath/telemetry/__init__.py,sha256=Wna32UFzZR66D-RzTKlPWlvji9i2HJb82NhHjCCXRjY,61
|
160
162
|
uipath/telemetry/_constants.py,sha256=uRDuEZayBYtBA0tMx-2AS_D-oiVA7oKgp9zid9jNats,763
|
161
|
-
uipath/telemetry/_track.py,sha256=
|
163
|
+
uipath/telemetry/_track.py,sha256=N7EMUJi8cnpZqlVL-B746MGvH1hk3urqWbV0T67UDB8,4660
|
162
164
|
uipath/tracing/__init__.py,sha256=GKRINyWdHVrDsI-8mrZDLdf0oey6GHGlNZTOADK-kgc,224
|
163
165
|
uipath/tracing/_otel_exporters.py,sha256=c0GKU_oUrAwrOrqbyu64c55z1TR6xk01d3y5fLUN1lU,3215
|
164
166
|
uipath/tracing/_traced.py,sha256=yBIY05PCCrYyx50EIHZnwJaKNdHPNx-YTR1sHQl0a98,19901
|
165
167
|
uipath/tracing/_utils.py,sha256=qd7N56tg6VXQ9pREh61esBgUWLNA0ssKsE0QlwrRWFM,11974
|
166
168
|
uipath/utils/__init__.py,sha256=VD-KXFpF_oWexFg6zyiWMkxl2HM4hYJMIUDZ1UEtGx0,105
|
167
169
|
uipath/utils/_endpoints_manager.py,sha256=iRTl5Q0XAm_YgcnMcJOXtj-8052sr6jpWuPNz6CgT0Q,8408
|
168
|
-
uipath-2.1.
|
169
|
-
uipath-2.1.
|
170
|
-
uipath-2.1.
|
171
|
-
uipath-2.1.
|
172
|
-
uipath-2.1.
|
170
|
+
uipath-2.1.76.dist-info/METADATA,sha256=zT48rJq2Cbsdva0uAbrjk7eNsLGxBiq2YTjp327fJg8,6593
|
171
|
+
uipath-2.1.76.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
172
|
+
uipath-2.1.76.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
|
173
|
+
uipath-2.1.76.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
|
174
|
+
uipath-2.1.76.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|