uipath 2.0.20__tar.gz → 2.0.22__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of uipath might be problematic. Click here for more details.

Files changed (130) hide show
  1. uipath-2.0.22/.github/workflows/publish-dev.yml +109 -0
  2. {uipath-2.0.20 → uipath-2.0.22}/PKG-INFO +2 -1
  3. {uipath-2.0.20 → uipath-2.0.22}/pyproject.toml +5 -1
  4. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/__init__.py +12 -1
  5. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_auth/_auth_server.py +3 -2
  6. uipath-2.0.22/src/uipath/_cli/_utils/_common.py +45 -0
  7. uipath-2.0.22/src/uipath/_cli/_utils/_folders.py +29 -0
  8. uipath-2.0.22/src/uipath/_cli/_utils/_processes.py +49 -0
  9. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/cli_auth.py +25 -15
  10. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/cli_init.py +11 -8
  11. uipath-2.0.22/src/uipath/_cli/cli_invoke.py +105 -0
  12. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/cli_new.py +11 -5
  13. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/cli_pack.py +30 -16
  14. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/cli_publish.py +49 -36
  15. uipath-2.0.22/src/uipath/_cli/spinner.py +40 -0
  16. {uipath-2.0.20 → uipath-2.0.22}/uv.lock +3 -1
  17. uipath-2.0.20/src/uipath/_cli/_utils/_common.py +0 -24
  18. {uipath-2.0.20 → uipath-2.0.22}/.cursorrules +0 -0
  19. {uipath-2.0.20 → uipath-2.0.22}/.editorconfig +0 -0
  20. {uipath-2.0.20 → uipath-2.0.22}/.gitattributes +0 -0
  21. {uipath-2.0.20 → uipath-2.0.22}/.github/workflows/build.yml +0 -0
  22. {uipath-2.0.20 → uipath-2.0.22}/.github/workflows/cd.yml +0 -0
  23. {uipath-2.0.20 → uipath-2.0.22}/.github/workflows/ci.yml +0 -0
  24. {uipath-2.0.20 → uipath-2.0.22}/.github/workflows/commitlint.yml +0 -0
  25. {uipath-2.0.20 → uipath-2.0.22}/.github/workflows/lint.yml +0 -0
  26. {uipath-2.0.20 → uipath-2.0.22}/.github/workflows/test.yml +0 -0
  27. {uipath-2.0.20 → uipath-2.0.22}/.gitignore +0 -0
  28. {uipath-2.0.20 → uipath-2.0.22}/.pre-commit-config.yaml +0 -0
  29. {uipath-2.0.20 → uipath-2.0.22}/.python-version +0 -0
  30. {uipath-2.0.20 → uipath-2.0.22}/.vscode/extensions.json +0 -0
  31. {uipath-2.0.20 → uipath-2.0.22}/.vscode/settings.json +0 -0
  32. {uipath-2.0.20 → uipath-2.0.22}/CONTRIBUTING.md +0 -0
  33. {uipath-2.0.20 → uipath-2.0.22}/LICENSE +0 -0
  34. {uipath-2.0.20 → uipath-2.0.22}/README.md +0 -0
  35. {uipath-2.0.20 → uipath-2.0.22}/docs/CONTRIBUTING.md +0 -0
  36. {uipath-2.0.20 → uipath-2.0.22}/docs/actions.md +0 -0
  37. {uipath-2.0.20 → uipath-2.0.22}/docs/assets/uipath-logo.svg +0 -0
  38. {uipath-2.0.20 → uipath-2.0.22}/docs/assets.md +0 -0
  39. {uipath-2.0.20 → uipath-2.0.22}/docs/buckets.md +0 -0
  40. {uipath-2.0.20 → uipath-2.0.22}/docs/connections.md +0 -0
  41. {uipath-2.0.20 → uipath-2.0.22}/docs/context_grounding.md +0 -0
  42. {uipath-2.0.20 → uipath-2.0.22}/docs/getting_started_agent.md +0 -0
  43. {uipath-2.0.20 → uipath-2.0.22}/docs/getting_started_cli.md +0 -0
  44. {uipath-2.0.20 → uipath-2.0.22}/docs/getting_started_sdk.md +0 -0
  45. {uipath-2.0.20 → uipath-2.0.22}/docs/index.md +0 -0
  46. {uipath-2.0.20 → uipath-2.0.22}/docs/jobs.md +0 -0
  47. {uipath-2.0.20 → uipath-2.0.22}/docs/processes.md +0 -0
  48. {uipath-2.0.20 → uipath-2.0.22}/docs/queues.md +0 -0
  49. {uipath-2.0.20 → uipath-2.0.22}/docs/sdk.md +0 -0
  50. {uipath-2.0.20 → uipath-2.0.22}/justfile +0 -0
  51. {uipath-2.0.20 → uipath-2.0.22}/mkdocs.yml +0 -0
  52. {uipath-2.0.20 → uipath-2.0.22}/py.typed +0 -0
  53. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/__init__.py +0 -0
  54. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/README.md +0 -0
  55. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_auth/_models.py +0 -0
  56. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_auth/_oidc_utils.py +0 -0
  57. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_auth/_portal_service.py +0 -0
  58. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_auth/_utils.py +0 -0
  59. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_auth/auth_config.json +0 -0
  60. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_auth/index.html +0 -0
  61. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_auth/localhost.crt +0 -0
  62. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_auth/localhost.key +0 -0
  63. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_runtime/_contracts.py +0 -0
  64. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_runtime/_logging.py +0 -0
  65. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_runtime/_runtime.py +0 -0
  66. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_templates/.psmdcp.template +0 -0
  67. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_templates/.rels.template +0 -0
  68. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_templates/[Content_Types].xml.template +0 -0
  69. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_templates/main.py.template +0 -0
  70. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_templates/package.nuspec.template +0 -0
  71. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_utils/_input_args.py +0 -0
  72. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/_utils/_parse_ast.py +0 -0
  73. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/cli_deploy.py +0 -0
  74. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/cli_run.py +0 -0
  75. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_cli/middlewares.py +0 -0
  76. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_config.py +0 -0
  77. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_execution_context.py +0 -0
  78. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_folder_context.py +0 -0
  79. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/__init__.py +0 -0
  80. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/_base_service.py +0 -0
  81. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/actions_service.py +0 -0
  82. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/api_client.py +0 -0
  83. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/assets_service.py +0 -0
  84. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/buckets_service.py +0 -0
  85. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/connections_service.py +0 -0
  86. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/connections_service.pyi +0 -0
  87. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/context_grounding_service.py +0 -0
  88. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/folder_service.py +0 -0
  89. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/jobs_service.py +0 -0
  90. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/llm_gateway_service.py +0 -0
  91. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/processes_service.py +0 -0
  92. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_services/queues_service.py +0 -0
  93. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_uipath.py +0 -0
  94. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_utils/__init__.py +0 -0
  95. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_utils/_endpoint.py +0 -0
  96. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_utils/_infer_bindings.py +0 -0
  97. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_utils/_logs.py +0 -0
  98. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_utils/_request_override.py +0 -0
  99. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_utils/_request_spec.py +0 -0
  100. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_utils/_user_agent.py +0 -0
  101. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/_utils/constants.py +0 -0
  102. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/__init__.py +0 -0
  103. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/action_schema.py +0 -0
  104. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/actions.py +0 -0
  105. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/assets.py +0 -0
  106. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/connections.py +0 -0
  107. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/context_grounding.py +0 -0
  108. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/context_grounding_index.py +0 -0
  109. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/exceptions.py +0 -0
  110. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/interrupt_models.py +0 -0
  111. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/job.py +0 -0
  112. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/llm_gateway.py +0 -0
  113. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/processes.py +0 -0
  114. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/models/queues.py +0 -0
  115. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/py.typed +0 -0
  116. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/tracing/__init__.py +0 -0
  117. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/tracing/_otel_exporters.py +0 -0
  118. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/tracing/_traced.py +0 -0
  119. {uipath-2.0.20 → uipath-2.0.22}/src/uipath/tracing/_utils.py +0 -0
  120. {uipath-2.0.20 → uipath-2.0.22}/tests/__init__.py +0 -0
  121. {uipath-2.0.20 → uipath-2.0.22}/tests/cli/test_init.py +0 -0
  122. {uipath-2.0.20 → uipath-2.0.22}/tests/conftest.py +0 -0
  123. {uipath-2.0.20 → uipath-2.0.22}/tests/sdk/services/test_llm_integration.py +0 -0
  124. {uipath-2.0.20 → uipath-2.0.22}/tests/sdk/services/test_llm_service.py +0 -0
  125. {uipath-2.0.20 → uipath-2.0.22}/tests/sdk/services/test_uipath_llm_integration.py +0 -0
  126. {uipath-2.0.20 → uipath-2.0.22}/tests/sdk/test_config.py +0 -0
  127. {uipath-2.0.20 → uipath-2.0.22}/tests/tracing/test_otel_exporters.py +0 -0
  128. {uipath-2.0.20 → uipath-2.0.22}/tests/tracing/test_span_utils.py +0 -0
  129. {uipath-2.0.20 → uipath-2.0.22}/tests/tracing/test_traced.py +0 -0
  130. {uipath-2.0.20 → uipath-2.0.22}/tests/tracing/test_tracing_manager.py +0 -0
@@ -0,0 +1,109 @@
1
+ name: Publish Dev Build
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened, labeled]
6
+ secrets:
7
+ PYPI_TOKEN:
8
+ required: true
9
+ TESTPYPI_TOKEN:
10
+ required: true
11
+
12
+
13
+ jobs:
14
+ publish-dev:
15
+ runs-on: ubuntu-latest
16
+
17
+ # Only run if PR has the build:dev label
18
+ if: contains(github.event.pull_request.labels.*.name, 'build:dev')
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - uses: astral-sh/setup-uv@v5
24
+
25
+ - uses: actions/setup-python@v5
26
+ with:
27
+ python-version-file: ".python-version"
28
+
29
+ - name: Setup venv
30
+ run: |
31
+ uv venv
32
+ uv sync --all-extras
33
+
34
+ - name: Set development version
35
+ shell: pwsh
36
+ env:
37
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38
+ run: |
39
+ $pyprojcontent = Get-Content pyproject.toml -Raw
40
+
41
+ $PROJECT_NAME = ($pyprojcontent | Select-String -Pattern '(?m)^\[(project|tool\.poetry)\][^\[]*?name\s*=\s*"([^"]*)"' -AllMatches).Matches[0].Groups[2].Value
42
+ $CURRENT_VERSION = ($pyprojcontent | Select-String -Pattern '(?m)^\[(project|tool\.poetry)\][^\[]*?version\s*=\s*"([^"]*)"' -AllMatches).Matches[0].Groups[2].Value
43
+ $NIGHTLY_NAME = "$PROJECT_NAME-nightly"
44
+
45
+
46
+ # Get PR number and run number with proper padding
47
+ $PR_NUM = [int]"${{ github.event.pull_request.number }}"
48
+ $PADDED_PR = "{0:D5}" -f [int]"${{ github.event.pull_request.number }}"
49
+ $PADDED_RUN = "{0:D4}" -f [int]"${{ github.run_number }}"
50
+ $PADDED_NEXT_PR = "{0:D5}" -f ($PR_NUM + 1)
51
+
52
+ # Create version range strings for PR
53
+ $MIN_VERSION = "$CURRENT_VERSION.dev1$PADDED_PR" + "0000"
54
+ $MAX_VERSION = "$CURRENT_VERSION.dev1$PADDED_NEXT_PR" + "0000"
55
+
56
+ # Create unique dev version with PR number and run ID
57
+ $DEV_VERSION = "$CURRENT_VERSION.dev1$PADDED_PR$PADDED_RUN"
58
+
59
+ # Update version in pyproject.toml
60
+ (Get-Content pyproject.toml) -replace "version = `"$CURRENT_VERSION`"", "version = `"$DEV_VERSION`"" | Set-Content pyproject.toml
61
+
62
+ # Update project name in pyproject.toml
63
+ (Get-Content pyproject.toml) -replace "name = `"$PROJECT_NAME`"", "name = `"$NIGHTLY_NAME`"" | Set-Content pyproject.toml
64
+
65
+
66
+ Write-Output "Package version set to $DEV_VERSION"
67
+
68
+ $dependencyMessage = @"
69
+ - Add this package as a dependency in your pyproject.toml:
70
+
71
+ ``````toml
72
+ [project]
73
+ dependencies = [
74
+ # Exact version:
75
+ "$NIGHTLY_NAME==$DEV_VERSION",
76
+
77
+ # Any version from PR
78
+ "$NIGHTLY_NAME>=$MIN_VERSION,<$MAX_VERSION"
79
+ ]
80
+ ``````
81
+ "@
82
+ Write-Output $dependencyMessage
83
+
84
+ # Post comment to GitHub PR
85
+ $owner = "${{ github.repository_owner }}"
86
+ $repo = "${{ github.repository }}".Split('/')[1]
87
+ $issueNumber = $PR_NUM
88
+
89
+ $body = @{
90
+ body = $dependencyMessage
91
+ } | ConvertTo-Json
92
+
93
+ # Create the comment using GitHub REST API
94
+ $uri = "https://api.github.com/repos/$owner/$repo/issues/$issueNumber/comments"
95
+ $headers = @{
96
+ Authorization = "token $env:GITHUB_TOKEN"
97
+ Accept = "application/vnd.github.v3+json"
98
+ }
99
+
100
+ Invoke-RestMethod -Uri $uri -Method Post -Body $body -Headers $headers -ContentType "application/json"
101
+
102
+ - name: Build package
103
+ run: uv build
104
+
105
+ - name: Publish
106
+ run: |
107
+ uv publish
108
+ env:
109
+ UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uipath
3
- Version: 2.0.20
3
+ Version: 2.0.22
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
@@ -21,6 +21,7 @@ Requires-Dist: pydantic>=2.11.1
21
21
  Requires-Dist: pytest-asyncio>=0.25.3
22
22
  Requires-Dist: python-dotenv>=1.0.1
23
23
  Requires-Dist: requests>=2.32.3
24
+ Requires-Dist: rich>=13.0.0
24
25
  Requires-Dist: tenacity>=9.0.0
25
26
  Requires-Dist: tomli>=2.2.1
26
27
  Requires-Dist: types-requests>=2.32.0.20250306
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "uipath"
3
- version = "2.0.20"
3
+ version = "2.0.22"
4
4
  description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
5
5
  readme = { file = "README.md", content-type = "text/markdown" }
6
6
  requires-python = ">=3.10"
@@ -16,6 +16,7 @@ dependencies = [
16
16
  "tomli>=2.2.1",
17
17
  "types-requests>=2.32.0.20250306",
18
18
  "pathlib>=1.0.1",
19
+ "rich>=13.0.0",
19
20
  ]
20
21
  classifiers = [
21
22
  "Development Status :: 3 - Alpha",
@@ -60,6 +61,9 @@ dev = [
60
61
  [project.optional-dependencies]
61
62
  langchain = ["uipath-langchain>=0.0.88,<0.1.0"]
62
63
 
64
+ [tool.hatch.build.targets.wheel]
65
+ packages = ["src/uipath"]
66
+
63
67
  [tool.ruff]
64
68
  line-length = 88
65
69
  indent-width = 4
@@ -6,15 +6,25 @@ import click
6
6
  from .cli_auth import auth as auth # type: ignore
7
7
  from .cli_deploy import deploy as deploy # type: ignore
8
8
  from .cli_init import init as init # type: ignore
9
+ from .cli_invoke import invoke as invoke # type: ignore
9
10
  from .cli_new import new as new # type: ignore
10
11
  from .cli_pack import pack as pack # type: ignore
11
12
  from .cli_publish import publish as publish # type: ignore
12
13
  from .cli_run import run as run # type: ignore
13
14
 
14
15
 
16
+ def _get_safe_version() -> str:
17
+ """Get the version of the uipath package."""
18
+ try:
19
+ version = importlib.metadata.version("uipath")
20
+ return version
21
+ except importlib.metadata.PackageNotFoundError:
22
+ return "unknown"
23
+
24
+
15
25
  @click.group(invoke_without_command=True)
16
26
  @click.version_option(
17
- importlib.metadata.version("uipath"),
27
+ _get_safe_version(),
18
28
  prog_name="uipath",
19
29
  message="%(prog)s version %(version)s",
20
30
  )
@@ -52,3 +62,4 @@ cli.add_command(publish)
52
62
  cli.add_command(run)
53
63
  cli.add_command(deploy)
54
64
  cli.add_command(auth)
65
+ cli.add_command(invoke)
@@ -5,6 +5,7 @@ import socketserver
5
5
  import ssl
6
6
  import time
7
7
 
8
+ import click
8
9
  from dotenv import load_dotenv
9
10
 
10
11
  from ._oidc_utils import get_auth_config
@@ -38,7 +39,7 @@ def make_request_handler_class(state, code_verifier, token_callback, domain):
38
39
  content_length = int(self.headers["Content-Length"])
39
40
  post_data = self.rfile.read(content_length)
40
41
  token_data = json.loads(post_data.decode("utf-8"))
41
- print("Received authentication information")
42
+ click.echo("Received authentication information")
42
43
 
43
44
  self.send_response(200)
44
45
  self.end_headers()
@@ -179,7 +180,7 @@ class HTTPSServer:
179
180
  while not self.should_shutdown:
180
181
  self.httpd.handle_request()
181
182
  except KeyboardInterrupt:
182
- print("Process interrupted by user")
183
+ click.echo("Process interrupted by user")
183
184
  finally:
184
185
  self.stop()
185
186
 
@@ -0,0 +1,45 @@
1
+ import os
2
+ from typing import Optional
3
+
4
+ import click
5
+
6
+ from ..spinner import Spinner
7
+
8
+
9
+ def environment_options(function):
10
+ function = click.option(
11
+ "--alpha",
12
+ "domain",
13
+ flag_value="alpha",
14
+ help="Use alpha environment",
15
+ )(function)
16
+ function = click.option(
17
+ "--staging",
18
+ "domain",
19
+ flag_value="staging",
20
+ help="Use staging environment",
21
+ )(function)
22
+ function = click.option(
23
+ "--cloud",
24
+ "domain",
25
+ flag_value="cloud",
26
+ default=True,
27
+ help="Use production environment",
28
+ )(function)
29
+ return function
30
+
31
+
32
+ def get_env_vars(spinner: Optional[Spinner] = None) -> list[str | None]:
33
+ base_url = os.environ.get("UIPATH_URL")
34
+ token = os.environ.get("UIPATH_ACCESS_TOKEN")
35
+
36
+ if not all([base_url, token]):
37
+ if spinner:
38
+ spinner.stop()
39
+ click.echo(
40
+ "❌ Missing required environment variables. Please check your .env file contains:"
41
+ )
42
+ click.echo("UIPATH_URL, UIPATH_ACCESS_TOKEN")
43
+ click.get_current_context().exit(1)
44
+
45
+ return [base_url, token]
@@ -0,0 +1,29 @@
1
+ from typing import Optional, Tuple
2
+
3
+ import click
4
+ import requests
5
+
6
+ from ..spinner import Spinner
7
+
8
+
9
+ def get_personal_workspace_info(
10
+ base_url: str, token: str, spinner: Optional[Spinner] = None
11
+ ) -> Tuple[str, str]:
12
+ user_url = f"{base_url}/orchestrator_/odata/Users/UiPath.Server.Configuration.OData.GetCurrentUserExtended?$expand=PersonalWorkspace"
13
+ user_response = requests.get(user_url, headers={"Authorization": f"Bearer {token}"})
14
+
15
+ if user_response.status_code != 200:
16
+ if spinner:
17
+ spinner.stop()
18
+ click.echo("❌ Failed to get user info. Please try reauthenticating.")
19
+ click.get_current_context().exit(1)
20
+
21
+ user_data = user_response.json()
22
+ feed_id = user_data.get("PersonalWorskpaceFeedId")
23
+ folder_id = user_data["PersonalWorkspace"].get("Id")
24
+ if not (feed_id and folder_id):
25
+ if spinner:
26
+ spinner.stop()
27
+ click.echo("❌ No personal workspace found for user")
28
+ click.get_current_context().exit(1)
29
+ return feed_id, folder_id
@@ -0,0 +1,49 @@
1
+ import json
2
+ import urllib.parse
3
+ from typing import Any, Optional
4
+
5
+ import click
6
+ import requests
7
+
8
+ from ..spinner import Spinner
9
+
10
+
11
+ def get_release_info(
12
+ base_url: str,
13
+ token: str,
14
+ package_name: str,
15
+ folder_id: str,
16
+ spinner: Optional[Spinner] = None,
17
+ ) -> None | tuple[Any, Any] | tuple[None, None]:
18
+ headers = {
19
+ "Authorization": f"Bearer {token}",
20
+ "x-uipath-organizationunitid": str(folder_id),
21
+ }
22
+
23
+ release_url = f"{base_url}/orchestrator_/odata/Releases/UiPath.Server.Configuration.OData.ListReleases?$select=Id,Key&$top=1&$filter=(contains(Name,%27{urllib.parse.quote(package_name)}%27))&$orderby=Name%20asc"
24
+ response = requests.get(release_url, headers=headers)
25
+ if response.status_code == 200:
26
+ try:
27
+ data = json.loads(response.text)
28
+ release_id = data["value"][0]["Id"]
29
+ release_key = data["value"][0]["Key"]
30
+ return release_id, release_key
31
+ except KeyError:
32
+ if spinner:
33
+ spinner.stop()
34
+ click.echo("\n⚠️ Warning: Failed to deserialize release data")
35
+ return None, None
36
+ except IndexError:
37
+ if spinner:
38
+ spinner.stop()
39
+ click.echo(
40
+ "\n❌ Process not found in your workspace. Try publishing it first."
41
+ )
42
+ click.get_current_context().exit(1)
43
+
44
+ else:
45
+ if spinner:
46
+ spinner.stop()
47
+ click.echo("\n⚠️ Warning: Failed to fetch release info")
48
+ click.echo(f"Status code: {response.status_code}")
49
+ return None, None
@@ -12,6 +12,7 @@ from ._auth._oidc_utils import get_auth_config, get_auth_url
12
12
  from ._auth._portal_service import PortalService, select_tenant
13
13
  from ._auth._utils import update_auth_file, update_env_file
14
14
  from ._utils._common import environment_options
15
+ from .spinner import Spinner
15
16
 
16
17
  load_dotenv()
17
18
 
@@ -37,7 +38,7 @@ def set_port():
37
38
  if is_port_in_use(port_option_two):
38
39
  if is_port_in_use(port_option_three):
39
40
  raise RuntimeError(
40
- "All configured ports are in use. Please close applications using ports or configure different ports."
41
+ "All configured ports are in use. Please close applications using ports or configure different ports."
41
42
  )
42
43
  else:
43
44
  port = port_option_three
@@ -56,6 +57,8 @@ def set_port():
56
57
  @environment_options
57
58
  def auth(domain="alpha"):
58
59
  """Authenticate with UiPath Cloud Platform."""
60
+ spinner = Spinner("Authenticating with UiPath...")
61
+ spinner.start()
59
62
  portal_service = PortalService(domain)
60
63
  if (
61
64
  os.getenv("UIPATH_URL")
@@ -64,9 +67,13 @@ def auth(domain="alpha"):
64
67
  ):
65
68
  try:
66
69
  portal_service.ensure_valid_token()
67
- click.echo("Authentication successful")
70
+ spinner.stop()
71
+ click.echo(
72
+ click.style("✓ ", fg="green", bold=True) + "Authentication successful"
73
+ )
68
74
  return
69
75
  except Exception:
76
+ spinner.stop()
70
77
  click.echo(
71
78
  "Authentication not found or expired. Please authenticate again."
72
79
  )
@@ -75,23 +82,26 @@ def auth(domain="alpha"):
75
82
 
76
83
  webbrowser.open(auth_url, 1)
77
84
  auth_config = get_auth_config()
78
-
85
+ spinner.stop()
79
86
  print(
80
87
  "If a browser window did not open, please open the following URL in your browser:"
81
88
  )
82
89
  print(auth_url)
90
+
83
91
  server = HTTPSServer(port=auth_config["port"])
84
92
  token_data = server.start(state, code_verifier, domain)
85
- try:
86
- if token_data:
87
- portal_service.update_token_data(token_data)
88
- update_auth_file(token_data)
89
- access_token = token_data["access_token"]
90
- update_env_file({"UIPATH_ACCESS_TOKEN": access_token})
91
93
 
92
- tenants_and_organizations = portal_service.get_tenants_and_organizations()
93
- select_tenant(domain, tenants_and_organizations)
94
- else:
95
- click.echo("Authentication failed")
96
- except Exception as e:
97
- click.echo(f"Authentication failed: {e}")
94
+ if token_data:
95
+ portal_service.update_token_data(token_data)
96
+ update_auth_file(token_data)
97
+ access_token = token_data["access_token"]
98
+ update_env_file({"UIPATH_ACCESS_TOKEN": access_token})
99
+
100
+ tenants_and_organizations = portal_service.get_tenants_and_organizations()
101
+ select_tenant(domain, tenants_and_organizations)
102
+ click.echo(
103
+ click.style("✓ ", fg="green", bold=True)
104
+ + "Authentication completed successfully!"
105
+ )
106
+ else:
107
+ click.echo("❌ Authentication failed")
@@ -11,6 +11,7 @@ import click
11
11
  from ._utils._input_args import generate_args
12
12
  from ._utils._parse_ast import generate_bindings_json
13
13
  from .middlewares import Middlewares
14
+ from .spinner import Spinner
14
15
 
15
16
 
16
17
  def generate_env_file(target_directory):
@@ -51,6 +52,7 @@ def get_user_script(directory: str, entrypoint: Optional[str] = None) -> Optiona
51
52
  @click.argument("entrypoint", required=False, default=None)
52
53
  def init(entrypoint: str) -> None:
53
54
  """Initialize a uipath.json configuration file for the script."""
55
+ spinner = Spinner("Initializing UiPath project...")
54
56
  current_directory = os.getcwd()
55
57
  generate_env_file(current_directory)
56
58
 
@@ -67,12 +69,11 @@ def init(entrypoint: str) -> None:
67
69
 
68
70
  if not result.should_continue:
69
71
  return
70
-
71
72
  script_path = get_user_script(current_directory, entrypoint=entrypoint)
72
73
 
73
74
  if not script_path:
74
75
  click.get_current_context().exit(1)
75
-
76
+ spinner.start()
76
77
  try:
77
78
  args = generate_args(script_path)
78
79
 
@@ -94,21 +95,23 @@ def init(entrypoint: str) -> None:
94
95
  # Generate bindings JSON based on the script path
95
96
  try:
96
97
  bindings_data = generate_bindings_json(script_path)
97
-
98
98
  # Add bindings to the config data
99
99
  config_data["bindings"] = bindings_data
100
-
101
- click.echo("Bindings generated successfully.")
102
100
  except Exception as e:
103
- click.echo(f"Warning: Could not generate bindings: {str(e)}")
101
+ click.echo(f"⚠️ Warning: Could not generate bindings: {str(e)}")
104
102
 
105
103
  config_path = "uipath.json"
106
104
  with open(config_path, "w") as config_file:
107
105
  json.dump(config_data, config_file, indent=4)
108
106
 
109
- click.echo(f"Configuration file {config_path} created successfully.")
107
+ spinner.stop()
108
+ click.echo(
109
+ click.style("✓ ", fg="green", bold=True)
110
+ + f"Configuration file {config_path} created successfully."
111
+ )
110
112
 
111
113
  except Exception as e:
112
- click.echo(f"Error generating configuration: {str(e)}")
114
+ spinner.stop()
115
+ click.echo(f"❌ Error generating configuration: {str(e)}")
113
116
  click.echo(traceback.format_exc())
114
117
  click.get_current_context().exit(1)
@@ -0,0 +1,105 @@
1
+ # type: ignore
2
+ import logging
3
+ import os
4
+ from typing import Optional
5
+
6
+ import click
7
+ import requests
8
+ from dotenv import load_dotenv
9
+
10
+ from .spinner import Spinner
11
+
12
+ try:
13
+ import tomllib
14
+ except ImportError:
15
+ import tomli as tomllib
16
+
17
+ from ._utils._common import get_env_vars
18
+ from ._utils._folders import get_personal_workspace_info
19
+ from ._utils._processes import get_release_info
20
+
21
+ logger = logging.getLogger(__name__)
22
+ load_dotenv()
23
+
24
+
25
+ def _read_project_name() -> str:
26
+ current_path = os.getcwd()
27
+ toml_path = os.path.join(current_path, "pyproject.toml")
28
+ if not os.path.isfile(toml_path):
29
+ raise Exception("pyproject.toml not found")
30
+
31
+ with open(toml_path, "rb") as f:
32
+ content = tomllib.load(f)
33
+ if "project" not in content:
34
+ raise Exception("pyproject.toml is missing the required field: project")
35
+ if "name" not in content["project"]:
36
+ raise Exception(
37
+ "pyproject.toml is missing the required field: project.name"
38
+ )
39
+
40
+ return content["project"]["name"]
41
+
42
+
43
+ @click.command()
44
+ @click.argument("entrypoint", required=False)
45
+ @click.argument("input", required=False, default="{}")
46
+ def invoke(entrypoint: Optional[str], input: Optional[str]) -> None:
47
+ """Invoke a remote agent with JSON input."""
48
+ spinner = Spinner("Starting job...")
49
+ spinner.start()
50
+
51
+ current_path = os.getcwd()
52
+ load_dotenv(os.path.join(current_path, ".env"), override=True)
53
+ [base_url, token] = get_env_vars(spinner)
54
+
55
+ url = f"{base_url}/orchestrator_/odata/Jobs/UiPath.Server.Configuration.OData.StartJobs"
56
+ _, personal_workspace_folder_id = get_personal_workspace_info(
57
+ base_url, token, spinner
58
+ )
59
+ project_name = _read_project_name()
60
+
61
+ _, release_key = get_release_info(
62
+ base_url, token, project_name, personal_workspace_folder_id, spinner
63
+ )
64
+ payload = {
65
+ "StartInfo": {
66
+ "ReleaseKey": str(release_key),
67
+ "RunAsMe": True,
68
+ "InputArguments": input,
69
+ "EntryPointPath": entrypoint,
70
+ }
71
+ }
72
+ headers = {
73
+ "Authorization": f"Bearer {token}",
74
+ "x-uipath-organizationunitid": str(personal_workspace_folder_id),
75
+ }
76
+
77
+ response = requests.post(url, json=payload, headers=headers)
78
+ spinner.stop()
79
+
80
+ if response.status_code == 201:
81
+ job_key = None
82
+ try:
83
+ job_key = response.json()["value"][0]["Key"]
84
+ except KeyError:
85
+ click.echo("Error: Failed to get job key from response")
86
+ click.Abort()
87
+ if job_key:
88
+ job_url = f"{base_url}/orchestrator_/jobs(sidepanel:sidepanel/jobs/{job_key}/details)?fid={personal_workspace_folder_id}"
89
+ click.echo("\n✨ Job started successfully!")
90
+ click.echo(
91
+ "\n🔗 Monitor your job here: "
92
+ + click.style(
93
+ f"\u001b]8;;{job_url}\u001b\\{job_url}\u001b]8;;\u001b\\",
94
+ fg="bright_blue",
95
+ bold=True,
96
+ )
97
+ + "\n"
98
+ )
99
+ else:
100
+ click.echo(f"\n❌ Error starting job: {response.text}")
101
+ click.Abort()
102
+
103
+
104
+ if __name__ == "__main__":
105
+ invoke()
@@ -6,6 +6,7 @@ import traceback
6
6
  import click
7
7
 
8
8
  from .middlewares import Middlewares
9
+ from .spinner import Spinner
9
10
 
10
11
 
11
12
  def generate_script(target_directory):
@@ -37,6 +38,7 @@ requires-python = ">=3.9"
37
38
  @click.command()
38
39
  @click.argument("name", type=str, default="")
39
40
  def new(name: str):
41
+ spinner = Spinner("Creating new project...")
40
42
  directory = os.getcwd()
41
43
 
42
44
  if not name:
@@ -44,12 +46,15 @@ def new(name: str):
44
46
  "Please specify a name for your project\n`uipath new hello-world`"
45
47
  )
46
48
 
47
- click.echo(f"Initializing project {name} in current directory..")
49
+ click.echo(
50
+ click.style("✓ ", fg="green", bold=True)
51
+ + f"Initializing project {name} in current directory.."
52
+ )
48
53
 
49
54
  result = Middlewares.next("new", name)
50
55
 
51
56
  if result.error_message:
52
- click.echo(result.error_message)
57
+ click.echo("❌ " + result.error_message)
53
58
  if result.should_include_stacktrace:
54
59
  click.echo(traceback.format_exc())
55
60
  click.get_current_context().exit(1)
@@ -61,13 +66,14 @@ def new(name: str):
61
66
  return
62
67
 
63
68
  generate_script(directory)
64
- click.echo("Created main.py file.")
69
+ click.echo(click.style("✓ ", fg="green", bold=True) + "Created main.py file")
65
70
  generate_pyproject(directory, name)
66
- click.echo("Created pyproject.toml file.")
67
-
71
+ click.echo(click.style("✓ ", fg="green", bold=True) + "Created pyproject.toml file")
72
+ spinner.start()
68
73
  ctx = click.get_current_context()
69
74
  init_cmd = ctx.parent.command.get_command(ctx, "init")
70
75
  ctx.invoke(init_cmd)
76
+ spinner.stop()
71
77
 
72
78
  click.echo("""` uipath run main.py '{"message": "Hello World!"}' `""")
73
79