Skip to content

Commit f5c00cc

Browse files
fix(platform): move ExternalApplicationService out of common to break identity↔common import cycle (#1787)
1 parent 53c894b commit f5c00cc

10 files changed

Lines changed: 45 additions & 76 deletions

File tree

packages/uipath-platform/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-platform"
3-
version = "0.1.90"
3+
version = "0.1.91"
44
description = "HTTP client library for programmatic access to UiPath Platform"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

packages/uipath-platform/src/uipath/platform/_uipath.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from .chat import ConversationsService, UiPathLlmChatService, UiPathOpenAIService
1313
from .common import (
1414
ApiClient,
15-
ExternalApplicationService,
1615
UiPathApiConfig,
1716
UiPathExecutionContext,
1817
)
@@ -22,6 +21,7 @@
2221
from .documents import DocumentsService
2322
from .entities import EntitiesService
2423
from .errors import BaseUrlMissingError, SecretMissingError
24+
from .external_applications import ExternalApplicationService
2525
from .governance import GovernanceService
2626
from .guardrails import GuardrailsService
2727
from .memory import MemoryService

packages/uipath-platform/src/uipath/platform/common/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
from ._config import UiPathApiConfig, UiPathConfig
1818
from ._endpoints_manager import EndpointManager
1919
from ._execution_context import ExecutionSourceContext, UiPathExecutionContext
20-
from ._external_application_service import ExternalApplicationService
2120
from ._folder_context import FolderContext, header_folder
2221
from ._http_config import get_ca_bundle_path, get_httpx_client_kwargs
2322
from ._models import Endpoint, RequestSpec
@@ -70,7 +69,6 @@
7069
"UiPathApiConfig",
7170
"UiPathExecutionContext",
7271
"ExecutionSourceContext",
73-
"ExternalApplicationService",
7472
"FolderContext",
7573
"TokenData",
7674
"UiPathConfig",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""UiPath External Applications."""
2+
3+
from ._external_application_service import ExternalApplicationService
4+
5+
__all__ = ["ExternalApplicationService"]

packages/uipath-platform/src/uipath/platform/common/_external_application_service.py renamed to packages/uipath-platform/src/uipath/platform/external_applications/_external_application_service.py

Lines changed: 30 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from collections.abc import Iterator
2+
from contextlib import contextmanager
13
from os import environ as env
24
from typing import Optional
35
from urllib.parse import urlparse
@@ -7,9 +9,9 @@
79

810
from uipath.platform.constants import ENV_BASE_URL
911

12+
from ..common.auth import TokenData
1013
from ..errors import EnrichedException
1114
from ..identity import IdentityService
12-
from .auth import TokenData
1315

1416

1517
class ExternalApplicationService:
@@ -72,6 +74,31 @@ def _extract_environment_from_base_url(self, base_url: str) -> str:
7274
# Default to cloud if parsing fails
7375
return "cloud"
7476

77+
@contextmanager
78+
def _translate_auth_errors(self) -> Iterator[None]:
79+
"""Translate token acquisition failures into authentication errors."""
80+
try:
81+
yield
82+
except HTTPStatusError as e:
83+
match e.response.status_code:
84+
case 400:
85+
message = "Invalid client credentials or request parameters."
86+
case 401:
87+
message = "Unauthorized: Invalid client credentials."
88+
case _:
89+
message = f"Authentication failed with unexpected status: {e.response.status_code}"
90+
raise EnrichedException(
91+
HTTPStatusError(
92+
message=message,
93+
request=e.request,
94+
response=e.response,
95+
)
96+
) from e
97+
except httpx.RequestError as e:
98+
raise Exception(f"Network error during authentication: {e}") from e
99+
except Exception as e:
100+
raise Exception(f"Unexpected error during authentication: {e}") from e
101+
75102
def get_token_data(
76103
self, client_id: str, client_secret: str, scope: Optional[str] = "OR.Execution"
77104
) -> TokenData:
@@ -85,42 +112,12 @@ def get_token_data(
85112
Returns:
86113
Token data if successful
87114
"""
88-
try:
115+
with self._translate_auth_errors():
89116
return self._identity_service.get_client_credentials_token(
90117
client_id=client_id,
91118
client_secret=client_secret,
92119
scope=scope,
93120
)
94-
except HTTPStatusError as e:
95-
match e.response.status_code:
96-
case 400:
97-
raise EnrichedException(
98-
HTTPStatusError(
99-
message="Invalid client credentials or request parameters.",
100-
request=e.request,
101-
response=e.response,
102-
)
103-
) from e
104-
case 401:
105-
raise EnrichedException(
106-
HTTPStatusError(
107-
message="Unauthorized: Invalid client credentials.",
108-
request=e.request,
109-
response=e.response,
110-
)
111-
) from e
112-
case _:
113-
raise EnrichedException(
114-
HTTPStatusError(
115-
message=f"Authentication failed with unexpected status: {e.response.status_code}",
116-
request=e.request,
117-
response=e.response,
118-
)
119-
) from e
120-
except httpx.RequestError as e:
121-
raise Exception(f"Network error during authentication: {e}") from e
122-
except Exception as e:
123-
raise Exception(f"Unexpected error during authentication: {e}") from e
124121

125122
async def get_token_data_async(
126123
self, client_id: str, client_secret: str, scope: Optional[str] = "OR.Execution"
@@ -135,39 +132,9 @@ async def get_token_data_async(
135132
Returns:
136133
Token data if successful
137134
"""
138-
try:
135+
with self._translate_auth_errors():
139136
return await self._identity_service.get_client_credentials_token_async(
140137
client_id=client_id,
141138
client_secret=client_secret,
142139
scope=scope,
143140
)
144-
except HTTPStatusError as e:
145-
match e.response.status_code:
146-
case 400:
147-
raise EnrichedException(
148-
HTTPStatusError(
149-
message="Invalid client credentials or request parameters.",
150-
request=e.request,
151-
response=e.response,
152-
)
153-
) from e
154-
case 401:
155-
raise EnrichedException(
156-
HTTPStatusError(
157-
message="Unauthorized: Invalid client credentials.",
158-
request=e.request,
159-
response=e.response,
160-
)
161-
) from e
162-
case _:
163-
raise EnrichedException(
164-
HTTPStatusError(
165-
message=f"Authentication failed with unexpected status: {e.response.status_code}",
166-
request=e.request,
167-
response=e.response,
168-
)
169-
) from e
170-
except httpx.RequestError as e:
171-
raise Exception(f"Network error during authentication: {e}") from e
172-
except Exception as e:
173-
raise Exception(f"Unexpected error during authentication: {e}") from e

packages/uipath-platform/tests/services/test_external_application_service.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
import httpx
44
import pytest
55

6-
from uipath.platform.common._external_application_service import (
7-
ExternalApplicationService,
8-
)
96
from uipath.platform.common.auth import TokenData
107
from uipath.platform.errors import EnrichedException
8+
from uipath.platform.external_applications import ExternalApplicationService
119

1210
IDENTITY_SERVICE_SYNC = (
1311
"uipath.platform.identity.IdentityService.get_client_credentials_token"

packages/uipath-platform/uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/uipath/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
[project]
22
name = "uipath"
3-
version = "2.12.6"
3+
version = "2.12.7"
44
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"
77
dependencies = [
88
"uipath-core>=0.5.26, <0.6.0",
99
"uipath-runtime>=0.11.7, <0.12.0",
10-
"uipath-platform>=0.1.89, <0.2.0",
10+
"uipath-platform>=0.1.91, <0.2.0",
1111
"click>=8.3.1",
1212
"httpx>=0.28.1",
1313
"pyjwt>=2.10.1",

packages/uipath/src/uipath/_cli/_auth/_auth_service.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
from uipath._cli._auth._utils import get_parsed_token_data
99
from uipath._cli._utils._console import ConsoleLogger
1010
from uipath._utils._auth import update_env_file
11-
from uipath.platform.common import ExternalApplicationService, TokenData
11+
from uipath.platform.common import TokenData
1212
from uipath.platform.constants import (
1313
ENV_BASE_URL,
1414
ENV_ORGANIZATION_ID,
1515
ENV_TENANT_ID,
1616
ENV_UIPATH_ACCESS_TOKEN,
1717
)
18+
from uipath.platform.external_applications import ExternalApplicationService
1819

1920
from ._utils import update_auth_file
2021

packages/uipath/uv.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)