Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion 2 src/uipath/_cli/_runtime/_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ def __init__(
if (
tb and tb.strip() != "NoneType: None"
): # Ensure there's an actual traceback
detail = f"{detail}\n\nTraceback:\n{tb}"
detail = f"{detail}\n\n{tb}"

if status is None:
status = self._extract_http_status()
Expand Down
186 changes: 46 additions & 140 deletions 186 src/uipath/_cli/cli_run.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# type: ignore
import asyncio
import os
import traceback
from os import environ as env
from typing import Optional, Tuple
from typing import Optional

import click

Expand All @@ -21,134 +20,11 @@
)
from ._runtime._runtime import UiPathScriptRuntime
from ._utils._console import ConsoleLogger
from .middlewares import MiddlewareResult, Middlewares
from .middlewares import Middlewares

console = ConsoleLogger()


def python_run_middleware(
entrypoint: Optional[str],
input: Optional[str],
resume: bool,
**kwargs,
) -> MiddlewareResult:
"""Middleware to handle Python script execution.

Args:
entrypoint: Path to the Python script to execute
input: JSON string with input data
resume: Flag indicating if this is a resume execution
debug: Enable debugging with debugpy
debug_port: Port for debug server (default: 5678)

Returns:
MiddlewareResult with execution status and messages
"""
if not entrypoint:
return MiddlewareResult(
should_continue=False,
error_message="""No entrypoint specified. Please provide a path to a Python script.
Usage: `uipath run <entrypoint_path> <input_arguments> [-f <input_json_file_path>]`""",
)

if not os.path.exists(entrypoint):
return MiddlewareResult(
should_continue=False,
error_message=f"""Script not found at path {entrypoint}.
Usage: `uipath run <entrypoint_path> <input_arguments> [-f <input_json_file_path>]`""",
)

try:
runtime_factory = UiPathRuntimeFactory(
UiPathScriptRuntime, UiPathRuntimeContext
)
context = (
UiPathRuntimeContextBuilder()
.with_defaults(**kwargs)
.with_entrypoint(entrypoint)
.with_input(input, input_file=kwargs.get("input_file"))
.with_resume(resume)
.build()
)

asyncio.run(runtime_factory.execute(context))

return MiddlewareResult(should_continue=False)

except UiPathRuntimeError as e:
return MiddlewareResult(
should_continue=False,
error_message=f"Error: {e.error_info.title} - {e.error_info.detail}",
should_include_stacktrace=False,
)
except Exception as e:
# Handle unexpected errors
return MiddlewareResult(
should_continue=False,
error_message=f"Error: Unexpected error occurred - {str(e)}",
should_include_stacktrace=True,
)


def run_core(
entrypoint: Optional[str],
resume: bool,
input: Optional[str] = None,
input_file: Optional[str] = None,
execution_output_file: Optional[str] = None,
logs_file: Optional[str] = None,
**kwargs,
) -> Tuple[bool, Optional[str], Optional[str]]:
"""Core execution logic that can be called programmatically.

Args:
entrypoint: Path to the Python script to execute
input: JSON string with input data
resume: Flag indicating if this is a resume execution
input_file: Path to input JSON file
execution_output_file: Path to execution output file
logs_file: Path where execution output will be written
**kwargs: Additional arguments to be forwarded to the middleware

Returns:
Tuple containing:
- success: True if execution was successful
- error_message: Error message if any
- info_message: Info message if any
"""
# Process through middleware chain
result = Middlewares.next(
"run",
entrypoint,
input,
resume,
input_file=input_file,
execution_output_file=execution_output_file,
logs_file=logs_file,
**kwargs,
)

if result.should_continue:
result = python_run_middleware(
entrypoint=entrypoint,
input=input,
resume=resume,
input_file=input_file,
execution_output_file=execution_output_file,
logs_file=logs_file,
**kwargs,
)

if result.should_continue:
return False, "Could not process the request with any available handler.", None

return (
not bool(result.error_message),
result.error_message,
result.info_message,
)


@click.command()
@click.argument("entrypoint", required=False)
@click.argument("input", required=False, default="{}")
Expand Down Expand Up @@ -200,27 +76,57 @@ def run(
if not setup_debugging(debug, debug_port):
console.error(f"Failed to start debug server on port {debug_port}")

success, error_message, info_message = run_core(
entrypoint=entrypoint,
input=input,
resume=resume,
result = Middlewares.next(
"run",
entrypoint,
input,
resume,
input_file=input_file,
execution_output_file=output_file,
debug=debug,
debug_port=debug_port,
)

if error_message:
console.error(error_message, include_traceback=True)
if not success: # If there was an error and execution failed
console.error(traceback.format_exc())
click.get_current_context().exit(1)

if info_message:
console.info(info_message)
if result.error_message:
console.error(result.error_message)

if success:
console.success("Successful execution.")
if result.should_continue:
if not entrypoint:
console.error("""No entrypoint specified. Please provide a path to a Python script.
Usage: `uipath run <entrypoint_path> <input_arguments> [-f <input_json_file_path>]`""")
cristipufu marked this conversation as resolved.
Show resolved Hide resolved
cristipufu marked this conversation as resolved.
Show resolved Hide resolved

if not os.path.exists(entrypoint):
console.error(f"""Script not found at path {entrypoint}.
Usage: `uipath run <entrypoint_path> <input_arguments> [-f <input_json_file_path>]`""")
cristipufu marked this conversation as resolved.
Show resolved Hide resolved

try:
runtime_factory = UiPathRuntimeFactory(
UiPathScriptRuntime, UiPathRuntimeContext
)
context = (
UiPathRuntimeContextBuilder()
.with_defaults(
execution_output_file=output_file,
debug=debug,
debug_port=debug_port,
)
.with_entrypoint(entrypoint)
.with_input(input, input_file=input_file)
.with_resume(resume)
.build()
)

asyncio.run(runtime_factory.execute(context))

except UiPathRuntimeError as e:
console.error(f"{e.error_info.title} - {e.error_info.detail}")
except Exception as e:
# Handle unexpected errors
console.error(
f"Error: Unexpected error occurred - {str(e)}", include_traceback=True
)

console.success("Successful execution.")


if __name__ == "__main__":
Expand Down
6 changes: 1 addition & 5 deletions 6 tests/cli/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ def test_run_input_file_success(
debug=False,
debug_port=5678,
execution_output_file=None,
logs_file=None,
)

class TestMiddleware:
Expand Down Expand Up @@ -220,10 +219,7 @@ def test_no_main_function_found(
f.write(uipath_json.to_json())
result = runner.invoke(cli, ["run", script_file_path, "{}"])
assert result.exit_code == 1
assert (
"No entry function found - No main function (main, run, or execute)"
in result.output
)
assert "No main function (main, run, or execute)" in result.output
assert "Successful execution." not in result.output

def test_middleware_error(
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.