Skip to content

Commit 5da4ecc

Browse files
authored
Merge pull request #2 from UiPath/fix/tests_lint
fix: tracing mock data
2 parents 091dbd0 + 9c81076 commit 5da4ecc

File tree

3 files changed

+378
-8
lines changed

3 files changed

+378
-8
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# UiPath Developer Console
22

3-
The **UiPath Developer Console** is an interactive terminal application for building, testing, and debugging UiPath Python runtimes, agents, and automation scripts.
3+
[![PyPI downloads](https://img.shields.io/pypi/dm/uipath-dev.svg)](https://pypi.org/project/uipath-dev/)
4+
[![Python versions](https://img.shields.io/pypi/pyversions/uipath-dev.svg)](https://pypi.org/project/uipath-dev/)
5+
6+
7+
Interactive terminal application for building, testing, and debugging UiPath Python runtimes, agents, and automation scripts.
48

59
## Overview
610

@@ -12,6 +16,8 @@ This tool is designed for:
1216
- Python engineers testing **standalone automation scripts** before deployment
1317
- Contributors exploring **runtime orchestration** and **execution traces**
1418

19+
![Runtime Trace Demo](https://raw.githubusercontent.com/UiPath/uipath-dev-python/main/docs/demo_traces.svg)
20+
1521
## Features
1622

1723
- Run and inspect Python runtimes interactively

docs/demo_traces.svg

Lines changed: 172 additions & 0 deletions
Loading

src/uipath/dev/_demo/mock_runtime.py

Lines changed: 199 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Minimal demo script to run UiPathDevTerminal with mock runtimes."""
22

33
import asyncio
4+
import logging
45
from typing import Any, Optional
56

7+
from opentelemetry import trace
68
from uipath.runtime import (
79
UiPathBaseRuntime,
810
UiPathExecuteOptions,
@@ -12,9 +14,11 @@
1214
)
1315
from uipath.runtime.schema import UiPathRuntimeSchema
1416

17+
logger = logging.getLogger(__name__)
18+
1519

1620
class MockRuntime(UiPathBaseRuntime):
17-
"""A simple mock runtime that echoes its input."""
21+
"""A mock runtime that simulates a multi-step workflow with rich telemetry."""
1822

1923
async def get_schema(self) -> UiPathRuntimeSchema:
2024
return UiPathRuntimeSchema(
@@ -39,19 +43,207 @@ async def execute(
3943
options: Optional[UiPathExecuteOptions] = None,
4044
) -> UiPathRuntimeResult:
4145
payload = input or {}
42-
# Simulate some async work
43-
await asyncio.sleep(0.2)
46+
47+
tracer = trace.get_tracer("uipath.dev.mock-runtime")
48+
49+
execution_id = getattr(self.context, "job_id", None) or "mock-execution"
50+
entrypoint = getattr(self.context, "entrypoint", None) or "mock-entrypoint"
51+
message = str(payload.get("message", ""))
52+
message_length = len(message)
53+
54+
with tracer.start_as_current_span(
55+
"mock-runtime.execute",
56+
attributes={
57+
"uipath.runtime.name": "MockRuntime",
58+
"uipath.runtime.type": "agent",
59+
"uipath.execution.id": execution_id,
60+
"uipath.runtime.entrypoint": entrypoint,
61+
"uipath.input.message.length": message_length,
62+
"uipath.input.has_message": "message" in payload,
63+
},
64+
) as root_span:
65+
logger.info(
66+
"MockRuntime: starting execution",
67+
extra={
68+
"uipath.execution.id": execution_id,
69+
"uipath.runtime.entrypoint": entrypoint,
70+
},
71+
)
72+
print(f"[MockRuntime] Starting execution (execution_id={execution_id})")
73+
74+
# Stage 1: Initialization
75+
with tracer.start_as_current_span(
76+
"initialize.environment",
77+
attributes={
78+
"uipath.step.name": "initialize-environment",
79+
"uipath.step.kind": "init",
80+
"uipath.execution.id": execution_id,
81+
},
82+
):
83+
logger.info("MockRuntime: initializing environment")
84+
print("[MockRuntime] Initializing environment...")
85+
await asyncio.sleep(0.5)
86+
87+
# Stage 2: Validation
88+
with tracer.start_as_current_span(
89+
"validate.input",
90+
attributes={
91+
"uipath.step.name": "validate-input",
92+
"uipath.step.kind": "validation",
93+
"uipath.execution.id": execution_id,
94+
"uipath.input.has_message": "message" in payload,
95+
},
96+
) as validate_span:
97+
logger.info("MockRuntime: validating input")
98+
print("[MockRuntime] Validating input...")
99+
await asyncio.sleep(0.5)
100+
101+
if "message" not in payload:
102+
logger.warning("MockRuntime: missing 'message' in payload")
103+
validate_span.set_attribute(
104+
"uipath.validation.missing_field", "message"
105+
)
106+
107+
# Stage 3: Preprocessing
108+
with tracer.start_as_current_span(
109+
"preprocess.data",
110+
attributes={
111+
"uipath.step.name": "preprocess-data",
112+
"uipath.step.kind": "preprocess",
113+
"uipath.execution.id": execution_id,
114+
"uipath.input.size.bytes": len(str(payload).encode("utf-8")),
115+
},
116+
):
117+
logger.info("MockRuntime: preprocessing data")
118+
print("[MockRuntime] Preprocessing data...")
119+
await asyncio.sleep(0.5)
120+
121+
# Stage 4: Compute / reasoning
122+
with tracer.start_as_current_span(
123+
"compute.result",
124+
attributes={
125+
"uipath.step.name": "compute-result",
126+
"uipath.step.kind": "compute",
127+
"uipath.execution.id": execution_id,
128+
},
129+
):
130+
logger.info("MockRuntime: compute phase started")
131+
print("[MockRuntime] Compute phase...")
132+
133+
# Subtask: embedding computation
134+
with tracer.start_as_current_span(
135+
"compute.embeddings",
136+
attributes={
137+
"uipath.step.name": "compute-embeddings",
138+
"uipath.step.kind": "compute-subtask",
139+
"uipath.execution.id": execution_id,
140+
},
141+
):
142+
logger.info("MockRuntime: computing embeddings")
143+
print("[MockRuntime] Computing embeddings...")
144+
await asyncio.sleep(0.5)
145+
146+
# Subtask: KB query
147+
with tracer.start_as_current_span(
148+
"query.knowledgebase",
149+
attributes={
150+
"uipath.step.name": "query-knowledgebase",
151+
"uipath.step.kind": "io",
152+
"uipath.execution.id": execution_id,
153+
"uipath.kb.query.length": message_length,
154+
},
155+
):
156+
logger.info("MockRuntime: querying knowledge base")
157+
print("[MockRuntime] Querying knowledge base...")
158+
await asyncio.sleep(0.5)
159+
160+
# Stage 5: Post-processing
161+
with tracer.start_as_current_span(
162+
"postprocess.results",
163+
attributes={
164+
"uipath.step.name": "postprocess-results",
165+
"uipath.step.kind": "postprocess",
166+
"uipath.execution.id": execution_id,
167+
},
168+
):
169+
logger.info("MockRuntime: post-processing results")
170+
print("[MockRuntime] Post-processing results...")
171+
await asyncio.sleep(0.4)
172+
173+
with tracer.start_as_current_span(
174+
"generate.output",
175+
attributes={
176+
"uipath.step.name": "generate-output",
177+
"uipath.step.kind": "postprocess-subtask",
178+
"uipath.execution.id": execution_id,
179+
},
180+
):
181+
logger.info("MockRuntime: generating structured output")
182+
print("[MockRuntime] Generating output...")
183+
await asyncio.sleep(0.4)
184+
185+
# Stage 6: Persistence
186+
with tracer.start_as_current_span(
187+
"persist.artifacts",
188+
attributes={
189+
"uipath.step.name": "persist-artifacts",
190+
"uipath.step.kind": "io",
191+
"uipath.execution.id": execution_id,
192+
"uipath.persistence.enabled": False,
193+
},
194+
):
195+
logger.info("MockRuntime: persisting artifacts (mock)")
196+
print("[MockRuntime] Persisting artifacts (mock)...")
197+
await asyncio.sleep(0.4)
198+
199+
# Stage 7: Cleanup
200+
with tracer.start_as_current_span(
201+
"cleanup.resources",
202+
attributes={
203+
"uipath.step.name": "cleanup-resources",
204+
"uipath.step.kind": "cleanup",
205+
"uipath.execution.id": execution_id,
206+
},
207+
):
208+
logger.info("MockRuntime: cleaning up resources")
209+
print("[MockRuntime] Cleaning up resources...")
210+
await asyncio.sleep(0.3)
211+
212+
result_payload = {
213+
"result": f"Mock runtime processed: {payload.get('message', '<no message>')}",
214+
"metadata": {
215+
"execution_id": execution_id,
216+
"entrypoint": entrypoint,
217+
"message_length": message_length,
218+
},
219+
}
220+
221+
root_span.set_attribute("uipath.runtime.status", "success")
222+
root_span.set_attribute("uipath.runtime.duration.approx", "5s")
223+
root_span.set_attribute("uipath.output.has_error", False)
224+
root_span.set_attribute(
225+
"uipath.output.message_length", len(str(result_payload))
226+
)
227+
228+
logger.info(
229+
"MockRuntime: execution completed successfully",
230+
extra={
231+
"uipath.execution.id": execution_id,
232+
"uipath.runtime.status": "success",
233+
},
234+
)
235+
print(f"[MockRuntime] Finished successfully with result={result_payload!r}")
236+
44237
return UiPathRuntimeResult(
45-
output={"result": f"Mock runtime got: {payload!r}"},
238+
output=result_payload,
46239
status=UiPathRuntimeStatus.SUCCESSFUL,
47240
)
48241

49242
async def cleanup(self) -> None:
50-
# Nothing to clean up in this mock
51-
pass
243+
logger.info("MockRuntime: cleanup() invoked")
244+
print("[MockRuntime] cleanup() invoked")
52245

53246

54-
# 2) Mock runtime factory
55247
class MockRuntimeFactory(UiPathRuntimeFactory[MockRuntime]):
56248
"""Runtime factory compatible with UiPathDevTerminal expectations."""
57249

0 commit comments

Comments
 (0)