uipath-dev 0.0.1__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/dev/__init__.py +329 -0
- uipath/dev/_demo/__init__.py +0 -0
- uipath/dev/_demo/mock_runtime.py +64 -0
- uipath/dev/_demo/run_dev_console.py +15 -0
- uipath/dev/_styles/terminal.tcss +261 -0
- uipath/dev/_utils/_exporter.py +119 -0
- uipath/dev/_utils/_logger.py +98 -0
- uipath/dev/components/details.py +453 -0
- uipath/dev/components/history.py +110 -0
- uipath/dev/components/json_input.py +27 -0
- uipath/dev/components/new.py +142 -0
- uipath/dev/models/execution.py +80 -0
- uipath/dev/models/messages.py +53 -0
- uipath/dev/py.typed +0 -0
- uipath_dev-0.0.1.dist-info/METADATA +59 -0
- uipath_dev-0.0.1.dist-info/RECORD +19 -0
- uipath_dev-0.0.1.dist-info/WHEEL +4 -0
- uipath_dev-0.0.1.dist-info/entry_points.txt +2 -0
- uipath_dev-0.0.1.dist-info/licenses/LICENSE +9 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Panel for displaying execution run history."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
from textual.app import ComposeResult
|
|
6
|
+
from textual.containers import Container, Vertical
|
|
7
|
+
from textual.widgets import (
|
|
8
|
+
Button,
|
|
9
|
+
ListItem,
|
|
10
|
+
ListView,
|
|
11
|
+
Static,
|
|
12
|
+
TabbedContent,
|
|
13
|
+
TabPane,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from uipath.dev.models.execution import ExecutionRun
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RunHistoryPanel(Container):
|
|
20
|
+
"""Left panel showing execution run history."""
|
|
21
|
+
|
|
22
|
+
def __init__(self, **kwargs):
|
|
23
|
+
"""Initialize RunHistoryPanel."""
|
|
24
|
+
super().__init__(**kwargs)
|
|
25
|
+
self.runs: List[ExecutionRun] = []
|
|
26
|
+
self.selected_run: Optional[ExecutionRun] = None
|
|
27
|
+
|
|
28
|
+
def compose(self) -> ComposeResult:
|
|
29
|
+
"""Compose the UI layout."""
|
|
30
|
+
with TabbedContent():
|
|
31
|
+
with TabPane("History", id="history-tab"):
|
|
32
|
+
with Vertical():
|
|
33
|
+
yield ListView(id="run-list", classes="run-list")
|
|
34
|
+
yield Button(
|
|
35
|
+
"+ New",
|
|
36
|
+
id="new-run-btn",
|
|
37
|
+
variant="primary",
|
|
38
|
+
classes="new-run-btn",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def on_mount(self) -> None:
|
|
42
|
+
"""Set up periodic refresh on mount."""
|
|
43
|
+
# Update only running items every 5 seconds
|
|
44
|
+
self.set_interval(5.0, self._refresh_running_items)
|
|
45
|
+
|
|
46
|
+
def add_run(self, run: ExecutionRun):
|
|
47
|
+
"""Add a new run to history."""
|
|
48
|
+
self.runs.insert(0, run) # Add to top
|
|
49
|
+
self.refresh_list()
|
|
50
|
+
|
|
51
|
+
def update_run(self, run: ExecutionRun):
|
|
52
|
+
"""Update an existing run."""
|
|
53
|
+
self.refresh_list()
|
|
54
|
+
|
|
55
|
+
def refresh_list(self):
|
|
56
|
+
"""Refresh the run list display."""
|
|
57
|
+
run_list = self.query_one("#run-list", ListView)
|
|
58
|
+
run_list.clear()
|
|
59
|
+
|
|
60
|
+
for run in self.runs:
|
|
61
|
+
item = ListItem(
|
|
62
|
+
Static(run.display_name), classes=f"run-item run-{run.status}"
|
|
63
|
+
)
|
|
64
|
+
# Store run id directly on the ListItem
|
|
65
|
+
item.run_id = run.id # type: ignore[attr-defined]
|
|
66
|
+
run_list.append(item)
|
|
67
|
+
|
|
68
|
+
def get_run_by_id(self, run_id: str) -> Optional[ExecutionRun]:
|
|
69
|
+
"""Get run by id."""
|
|
70
|
+
for run in self.runs:
|
|
71
|
+
if run.id == run_id:
|
|
72
|
+
return run
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
def clear_runs(self):
|
|
76
|
+
"""Clear all runs from history."""
|
|
77
|
+
self.runs.clear()
|
|
78
|
+
self.refresh_list()
|
|
79
|
+
|
|
80
|
+
def _refresh_running_items(self) -> None:
|
|
81
|
+
"""Refresh display names for running items only."""
|
|
82
|
+
if not any(run.status == "running" for run in self.runs):
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
run_list = self.query_one("#run-list", ListView)
|
|
87
|
+
except Exception:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
# Take a snapshot of items to avoid mid-iteration changes
|
|
91
|
+
items_snapshot = list(run_list.children)
|
|
92
|
+
|
|
93
|
+
for item in items_snapshot:
|
|
94
|
+
if not hasattr(item, "run_id"):
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
run = self.get_run_by_id(item.run_id)
|
|
98
|
+
if not run or run.status != "running":
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
# Check if item still exists in the list (wasn't removed)
|
|
102
|
+
if item not in run_list.children:
|
|
103
|
+
continue
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
static = item.query_one(Static)
|
|
107
|
+
static.update(run.display_name)
|
|
108
|
+
except Exception:
|
|
109
|
+
# Item structure changed or was removed
|
|
110
|
+
continue
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""TextArea component that validates JSON input."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from textual.widgets import TextArea
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class JsonInput(TextArea):
|
|
9
|
+
"""TextArea that validates JSON on change."""
|
|
10
|
+
|
|
11
|
+
def validate_json(self) -> bool:
|
|
12
|
+
"""Validate the current text as JSON."""
|
|
13
|
+
text = self.text.strip()
|
|
14
|
+
if not text:
|
|
15
|
+
self.remove_class("invalid")
|
|
16
|
+
return True
|
|
17
|
+
try:
|
|
18
|
+
json.loads(text)
|
|
19
|
+
self.remove_class("invalid")
|
|
20
|
+
return True
|
|
21
|
+
except json.JSONDecodeError:
|
|
22
|
+
self.add_class("invalid")
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
def on_text_area_changed(self, event: TextArea.Changed) -> None:
|
|
26
|
+
"""Validate JSON when the text changes."""
|
|
27
|
+
self.validate_json()
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""Panel for creating new runs with entrypoint selection and JSON input."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from typing import Any, Tuple, cast
|
|
6
|
+
|
|
7
|
+
from textual.app import ComposeResult
|
|
8
|
+
from textual.containers import Container, Horizontal, Vertical
|
|
9
|
+
from textual.reactive import reactive
|
|
10
|
+
from textual.widgets import Button, Select, TabbedContent, TabPane, TextArea
|
|
11
|
+
|
|
12
|
+
from uipath.dev.components.json_input import JsonInput
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def mock_json_from_schema(schema: dict[str, Any]) -> dict[str, Any]:
|
|
16
|
+
"""Generate a mock JSON object based on a given JSON schema."""
|
|
17
|
+
props: dict[str, Any] = schema.get("properties", {})
|
|
18
|
+
required = schema.get("required", [])
|
|
19
|
+
mock = {}
|
|
20
|
+
for key, info in props.items():
|
|
21
|
+
if "default" in info:
|
|
22
|
+
mock[key] = info["default"]
|
|
23
|
+
continue
|
|
24
|
+
t = info.get("type")
|
|
25
|
+
if t == "string":
|
|
26
|
+
mock[key] = f"example_{key}" if key in required else ""
|
|
27
|
+
elif t == "integer":
|
|
28
|
+
mock[key] = 0 if key in required else None
|
|
29
|
+
elif t == "boolean":
|
|
30
|
+
mock[key] = True if key in required else False
|
|
31
|
+
elif t == "array":
|
|
32
|
+
item_schema = info.get("items", {"type": "string"})
|
|
33
|
+
mock[key] = [mock_json_from_schema(item_schema)]
|
|
34
|
+
elif t == "object":
|
|
35
|
+
mock[key] = mock_json_from_schema(info)
|
|
36
|
+
else:
|
|
37
|
+
mock[key] = None
|
|
38
|
+
return mock
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class NewRunPanel(Container):
|
|
42
|
+
"""Panel for creating new runs with a Select entrypoint selector."""
|
|
43
|
+
|
|
44
|
+
selected_entrypoint = reactive("")
|
|
45
|
+
|
|
46
|
+
def __init__(self, **kwargs):
|
|
47
|
+
"""Initialize NewRunPanel with entrypoints from uipath.json."""
|
|
48
|
+
super().__init__(**kwargs)
|
|
49
|
+
json_path = os.path.join(os.getcwd(), "uipath.json")
|
|
50
|
+
data: dict[str, Any] = {}
|
|
51
|
+
if os.path.exists(json_path):
|
|
52
|
+
with open(json_path, "r") as f:
|
|
53
|
+
data = json.load(f)
|
|
54
|
+
|
|
55
|
+
self.entrypoints = data.get("entryPoints", [{"filePath": "default"}])
|
|
56
|
+
self.entrypoint_paths = [ep["filePath"] for ep in self.entrypoints]
|
|
57
|
+
self.conversational = False
|
|
58
|
+
self.selected_entrypoint = (
|
|
59
|
+
self.entrypoint_paths[0] if self.entrypoint_paths else ""
|
|
60
|
+
)
|
|
61
|
+
ep: dict[str, Any] = next(
|
|
62
|
+
(
|
|
63
|
+
ep
|
|
64
|
+
for ep in self.entrypoints
|
|
65
|
+
if ep["filePath"] == self.selected_entrypoint
|
|
66
|
+
),
|
|
67
|
+
{},
|
|
68
|
+
)
|
|
69
|
+
self.initial_input = json.dumps(
|
|
70
|
+
mock_json_from_schema(ep.get("input", {})), indent=2
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def compose(self) -> ComposeResult:
|
|
74
|
+
"""Compose the UI layout."""
|
|
75
|
+
with TabbedContent():
|
|
76
|
+
with TabPane("New run", id="new-tab"):
|
|
77
|
+
with Vertical():
|
|
78
|
+
options = [(path, path) for path in self.entrypoint_paths]
|
|
79
|
+
yield Select(
|
|
80
|
+
options,
|
|
81
|
+
id="entrypoint-select",
|
|
82
|
+
value=self.selected_entrypoint,
|
|
83
|
+
allow_blank=False,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
yield JsonInput(
|
|
87
|
+
text=self.initial_input,
|
|
88
|
+
language="json",
|
|
89
|
+
id="json-input",
|
|
90
|
+
classes="input-field json-input",
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
with Horizontal(classes="run-actions"):
|
|
94
|
+
yield Button(
|
|
95
|
+
"▶ Run",
|
|
96
|
+
id="execute-btn",
|
|
97
|
+
variant="primary",
|
|
98
|
+
classes="action-btn",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
async def on_select_changed(self, event: Select.Changed) -> None:
|
|
102
|
+
"""Update JSON input when user selects an entrypoint."""
|
|
103
|
+
self.selected_entrypoint = cast(str, event.value)
|
|
104
|
+
|
|
105
|
+
ep: dict[str, Any] = next(
|
|
106
|
+
(
|
|
107
|
+
ep
|
|
108
|
+
for ep in self.entrypoints
|
|
109
|
+
if ep["filePath"] == self.selected_entrypoint
|
|
110
|
+
),
|
|
111
|
+
{},
|
|
112
|
+
)
|
|
113
|
+
json_input = self.query_one("#json-input", TextArea)
|
|
114
|
+
json_input.text = json.dumps(
|
|
115
|
+
mock_json_from_schema(ep.get("input", {})), indent=2
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def get_input_values(self) -> Tuple[str, str, bool]:
|
|
119
|
+
"""Get the selected entrypoint and JSON input values."""
|
|
120
|
+
json_input = self.query_one("#json-input", TextArea)
|
|
121
|
+
return self.selected_entrypoint, json_input.text.strip(), self.conversational
|
|
122
|
+
|
|
123
|
+
def reset_form(self):
|
|
124
|
+
"""Reset selection and JSON input to defaults."""
|
|
125
|
+
self.selected_entrypoint = (
|
|
126
|
+
self.entrypoint_paths[0] if self.entrypoint_paths else ""
|
|
127
|
+
)
|
|
128
|
+
select = self.query_one("#entrypoint-select", Select)
|
|
129
|
+
select.value = self.selected_entrypoint
|
|
130
|
+
|
|
131
|
+
ep: dict[str, Any] = next(
|
|
132
|
+
(
|
|
133
|
+
ep
|
|
134
|
+
for ep in self.entrypoints
|
|
135
|
+
if ep["filePath"] == self.selected_entrypoint
|
|
136
|
+
),
|
|
137
|
+
{},
|
|
138
|
+
)
|
|
139
|
+
json_input = self.query_one("#json-input", TextArea)
|
|
140
|
+
json_input.text = json.dumps(
|
|
141
|
+
mock_json_from_schema(ep.get("input", {})), indent=2
|
|
142
|
+
)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Models for representing execution runs and their data."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, Optional, Union
|
|
6
|
+
from uuid import uuid4
|
|
7
|
+
|
|
8
|
+
from rich.text import Text
|
|
9
|
+
from uipath.runtime.errors import UiPathErrorContract
|
|
10
|
+
|
|
11
|
+
from uipath.dev.models.messages import LogMessage, TraceMessage
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ExecutionRun:
|
|
15
|
+
"""Represents a single execution run."""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
entrypoint: str,
|
|
20
|
+
input_data: Union[dict[str, Any]],
|
|
21
|
+
conversational: bool = False,
|
|
22
|
+
):
|
|
23
|
+
"""Initialize an ExecutionRun instance."""
|
|
24
|
+
self.id = str(uuid4())[:8]
|
|
25
|
+
self.entrypoint = entrypoint
|
|
26
|
+
self.input_data = input_data
|
|
27
|
+
self.conversational = conversational
|
|
28
|
+
self.resume_data: Optional[dict[str, Any]] = None
|
|
29
|
+
self.output_data: Optional[dict[str, Any]] = None
|
|
30
|
+
self.start_time = datetime.now()
|
|
31
|
+
self.end_time: Optional[datetime] = None
|
|
32
|
+
self.status = "pending" # pending, running, completed, failed, suspended
|
|
33
|
+
self.traces: list[TraceMessage] = []
|
|
34
|
+
self.logs: list[LogMessage] = []
|
|
35
|
+
self.error: Optional[UiPathErrorContract] = None
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def duration(self) -> str:
|
|
39
|
+
"""Get the duration of the run as a formatted string."""
|
|
40
|
+
if self.end_time:
|
|
41
|
+
delta = self.end_time - self.start_time
|
|
42
|
+
return f"{delta.total_seconds():.1f}s"
|
|
43
|
+
elif self.start_time:
|
|
44
|
+
delta = datetime.now() - self.start_time
|
|
45
|
+
return f"{delta.total_seconds():.1f}s"
|
|
46
|
+
return "0.0s"
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def display_name(self) -> Text:
|
|
50
|
+
"""Get a rich Text representation of the run for display."""
|
|
51
|
+
status_colors = {
|
|
52
|
+
"pending": "grey50",
|
|
53
|
+
"running": "yellow",
|
|
54
|
+
"suspended": "cyan",
|
|
55
|
+
"completed": "green",
|
|
56
|
+
"failed": "red",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
status_icon = {
|
|
60
|
+
"pending": "●",
|
|
61
|
+
"running": "▶",
|
|
62
|
+
"suspended": "⏸",
|
|
63
|
+
"completed": "✔",
|
|
64
|
+
"failed": "✖",
|
|
65
|
+
}.get(self.status, "?")
|
|
66
|
+
|
|
67
|
+
script_name = (
|
|
68
|
+
os.path.basename(self.entrypoint) if self.entrypoint else "untitled"
|
|
69
|
+
)
|
|
70
|
+
truncated_script = script_name[:8]
|
|
71
|
+
time_str = self.start_time.strftime("%H:%M:%S")
|
|
72
|
+
duration_str = self.duration[:6]
|
|
73
|
+
|
|
74
|
+
text = Text()
|
|
75
|
+
text.append(f"{status_icon:<2} ", style=status_colors.get(self.status, "white"))
|
|
76
|
+
text.append(f"{truncated_script:<8} ")
|
|
77
|
+
text.append(f"({time_str:<8}) ")
|
|
78
|
+
text.append(f"[{duration_str:<6}]")
|
|
79
|
+
|
|
80
|
+
return text
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Messages used for inter-component communication in the UiPath Developer Console."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any, Optional, Union
|
|
5
|
+
|
|
6
|
+
from rich.console import RenderableType
|
|
7
|
+
from textual.message import Message
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LogMessage(Message):
|
|
11
|
+
"""Message sent when a new log entry is created."""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
run_id: str,
|
|
16
|
+
level: str,
|
|
17
|
+
message: Union[str, RenderableType],
|
|
18
|
+
timestamp: Optional[datetime] = None,
|
|
19
|
+
):
|
|
20
|
+
"""Initialize a LogMessage instance."""
|
|
21
|
+
self.run_id = run_id
|
|
22
|
+
self.level = level
|
|
23
|
+
self.message = message
|
|
24
|
+
self.timestamp = timestamp or datetime.now()
|
|
25
|
+
super().__init__()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TraceMessage(Message):
|
|
29
|
+
"""Message sent when a new trace entry is created."""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
run_id: str,
|
|
34
|
+
span_name: str,
|
|
35
|
+
span_id: str,
|
|
36
|
+
parent_span_id: Optional[str] = None,
|
|
37
|
+
trace_id: Optional[str] = None,
|
|
38
|
+
status: str = "running",
|
|
39
|
+
duration_ms: Optional[float] = None,
|
|
40
|
+
timestamp: Optional[datetime] = None,
|
|
41
|
+
attributes: Optional[dict[str, Any]] = None,
|
|
42
|
+
):
|
|
43
|
+
"""Initialize a TraceMessage instance."""
|
|
44
|
+
self.run_id = run_id
|
|
45
|
+
self.span_name = span_name
|
|
46
|
+
self.span_id = span_id
|
|
47
|
+
self.parent_span_id = parent_span_id
|
|
48
|
+
self.trace_id = trace_id
|
|
49
|
+
self.status = status
|
|
50
|
+
self.duration_ms = duration_ms
|
|
51
|
+
self.timestamp = timestamp or datetime.now()
|
|
52
|
+
self.attributes = attributes or {}
|
|
53
|
+
super().__init__()
|
uipath/dev/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: uipath-dev
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: UiPath Dev Terminal
|
|
5
|
+
Project-URL: Homepage, https://uipath.com
|
|
6
|
+
Project-URL: Repository, https://github.com/UiPath/uipath-dev-python
|
|
7
|
+
Project-URL: Documentation, https://uipath.github.io/uipath-python/
|
|
8
|
+
Maintainer-email: Cristian Pufu <cristian.pufu@uipath.com>
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Requires-Dist: pyperclip>=1.11.0
|
|
17
|
+
Requires-Dist: textual>=6.5.0
|
|
18
|
+
Requires-Dist: uipath-runtime>=0.0.4
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# UiPath Developer Console
|
|
22
|
+
|
|
23
|
+
The **UiPath Developer Console** is an interactive terminal application for building, testing, and debugging UiPath Python runtimes, agents, and automation scripts.
|
|
24
|
+
|
|
25
|
+
## Overview
|
|
26
|
+
|
|
27
|
+
The Developer Console provides a local environment for developers who are building or experimenting with Python-based UiPath runtimes.
|
|
28
|
+
It integrates with the [`uipath-runtime`](https://pypi.org/project/uipath-runtime/) SDK to execute agents and visualize their behavior in real time using the [`textual`](https://github.com/Textualize/textual) framework.
|
|
29
|
+
|
|
30
|
+
This tool is designed for:
|
|
31
|
+
- Developers building **UiPath agents** or **custom runtime integrations**
|
|
32
|
+
- Python engineers testing **standalone automation scripts** before deployment
|
|
33
|
+
- Contributors exploring **runtime orchestration** and **execution traces**
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- Run and inspect Python runtimes interactively
|
|
38
|
+
- View structured logs, output, and OpenTelemetry traces
|
|
39
|
+
- Export and review execution history
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv add uipath-dev
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Development
|
|
48
|
+
|
|
49
|
+
Launch the Developer Console with mocked data:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
uv run uipath-dev
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
To run tests:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pytest
|
|
59
|
+
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
uipath/dev/__init__.py,sha256=TfVX-yiAQ7t6l8_vzRsxzBFzooqE-Hf6KTzCErD-L6c,12492
|
|
2
|
+
uipath/dev/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
uipath/dev/_demo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
uipath/dev/_demo/mock_runtime.py,sha256=xhnA88yjddqnNMiV_bACO_gAUdsdv-U_Iplb8c73h1M,1950
|
|
5
|
+
uipath/dev/_demo/run_dev_console.py,sha256=J7uEjKYkR9-hDs55rVUEyMLIdrwVDV6R96cxXgP1yXE,390
|
|
6
|
+
uipath/dev/_styles/terminal.tcss,sha256=ktVpKwXIXw2VZp8KIZD6fO9i9NTGvts_icCTxMdzEiY,3240
|
|
7
|
+
uipath/dev/_utils/_exporter.py,sha256=4jElOckC6dQh9qF-ArMnOBPXMMr9foG7uxmi8eyOLEU,4151
|
|
8
|
+
uipath/dev/_utils/_logger.py,sha256=7OByjJAWPEdOHfd6n6OSpsSX2OxK_I47HrGspAR2f-s,2950
|
|
9
|
+
uipath/dev/components/details.py,sha256=MExZBuiyjfEB530KSf8L6KeRUD15m9fbQptl00K5pm0,16483
|
|
10
|
+
uipath/dev/components/history.py,sha256=rCO5Gmnp9LZbVVWt8h8Mf0dyJktpTzTLa4U-xnF5iUI,3422
|
|
11
|
+
uipath/dev/components/json_input.py,sha256=vyvIi1m0yRLUBpXmwwM4InZ1taFJfmTy2Jx0vB_6Gvo,745
|
|
12
|
+
uipath/dev/components/new.py,sha256=QXc9SeEAeJ9M9pjCNLgD-6mY4N4-tWYfqP5oU6TNWlU,5128
|
|
13
|
+
uipath/dev/models/execution.py,sha256=KvODGsSTuWkYZ8zGW0_a_OreL-ByqqEq5tp291-Pz-Q,2606
|
|
14
|
+
uipath/dev/models/messages.py,sha256=3NxTpXrLaOpt7fJd0GJwLL6V_hUQS9_pM97L5zk-Qr8,1580
|
|
15
|
+
uipath_dev-0.0.1.dist-info/METADATA,sha256=hILtVjEM8z-5X3_XgHs5eRipUgxWqXNw4EDKpFfUtTY,1917
|
|
16
|
+
uipath_dev-0.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
17
|
+
uipath_dev-0.0.1.dist-info/entry_points.txt,sha256=xuRnlpKV3M6HE-47nOrLF_Y61OouvNen_8msafnuIb8,69
|
|
18
|
+
uipath_dev-0.0.1.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
|
|
19
|
+
uipath_dev-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright 2025 UiPath
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|