uipath 2.0.12__tar.gz → 2.0.13__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 (124) hide show
  1. {uipath-2.0.12 → uipath-2.0.13}/PKG-INFO +1 -1
  2. {uipath-2.0.12 → uipath-2.0.13}/pyproject.toml +1 -1
  3. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/tracing/_otel_exporters.py +32 -12
  4. uipath-2.0.13/tests/tracing/test_otel_exporters.py +190 -0
  5. {uipath-2.0.12 → uipath-2.0.13}/uv.lock +1 -1
  6. {uipath-2.0.12 → uipath-2.0.13}/.cursorrules +0 -0
  7. {uipath-2.0.12 → uipath-2.0.13}/.editorconfig +0 -0
  8. {uipath-2.0.12 → uipath-2.0.13}/.gitattributes +0 -0
  9. {uipath-2.0.12 → uipath-2.0.13}/.github/workflows/build.yml +0 -0
  10. {uipath-2.0.12 → uipath-2.0.13}/.github/workflows/cd.yml +0 -0
  11. {uipath-2.0.12 → uipath-2.0.13}/.github/workflows/ci.yml +0 -0
  12. {uipath-2.0.12 → uipath-2.0.13}/.github/workflows/commitlint.yml +0 -0
  13. {uipath-2.0.12 → uipath-2.0.13}/.github/workflows/lint.yml +0 -0
  14. {uipath-2.0.12 → uipath-2.0.13}/.github/workflows/test.yml +0 -0
  15. {uipath-2.0.12 → uipath-2.0.13}/.gitignore +0 -0
  16. {uipath-2.0.12 → uipath-2.0.13}/.pre-commit-config.yaml +0 -0
  17. {uipath-2.0.12 → uipath-2.0.13}/.python-version +0 -0
  18. {uipath-2.0.12 → uipath-2.0.13}/.vscode/extensions.json +0 -0
  19. {uipath-2.0.12 → uipath-2.0.13}/.vscode/settings.json +0 -0
  20. {uipath-2.0.12 → uipath-2.0.13}/CONTRIBUTING.md +0 -0
  21. {uipath-2.0.12 → uipath-2.0.13}/LICENSE +0 -0
  22. {uipath-2.0.12 → uipath-2.0.13}/README.md +0 -0
  23. {uipath-2.0.12 → uipath-2.0.13}/docs/CONTRIBUTING.md +0 -0
  24. {uipath-2.0.12 → uipath-2.0.13}/docs/actions.md +0 -0
  25. {uipath-2.0.12 → uipath-2.0.13}/docs/assets/uipath-logo.svg +0 -0
  26. {uipath-2.0.12 → uipath-2.0.13}/docs/assets.md +0 -0
  27. {uipath-2.0.12 → uipath-2.0.13}/docs/buckets.md +0 -0
  28. {uipath-2.0.12 → uipath-2.0.13}/docs/connections.md +0 -0
  29. {uipath-2.0.12 → uipath-2.0.13}/docs/context_grounding.md +0 -0
  30. {uipath-2.0.12 → uipath-2.0.13}/docs/getting_started_agent.md +0 -0
  31. {uipath-2.0.12 → uipath-2.0.13}/docs/getting_started_cli.md +0 -0
  32. {uipath-2.0.12 → uipath-2.0.13}/docs/getting_started_cloud.md +0 -0
  33. {uipath-2.0.12 → uipath-2.0.13}/docs/getting_started_sdk.md +0 -0
  34. {uipath-2.0.12 → uipath-2.0.13}/docs/index.md +0 -0
  35. {uipath-2.0.12 → uipath-2.0.13}/docs/jobs.md +0 -0
  36. {uipath-2.0.12 → uipath-2.0.13}/docs/processes.md +0 -0
  37. {uipath-2.0.12 → uipath-2.0.13}/docs/queues.md +0 -0
  38. {uipath-2.0.12 → uipath-2.0.13}/docs/sdk.md +0 -0
  39. {uipath-2.0.12 → uipath-2.0.13}/justfile +0 -0
  40. {uipath-2.0.12 → uipath-2.0.13}/mkdocs.yml +0 -0
  41. {uipath-2.0.12 → uipath-2.0.13}/py.typed +0 -0
  42. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/__init__.py +0 -0
  43. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/README.md +0 -0
  44. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/__init__.py +0 -0
  45. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_auth/_auth_server.py +0 -0
  46. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_auth/_models.py +0 -0
  47. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_auth/_oidc_utils.py +0 -0
  48. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_auth/_portal_service.py +0 -0
  49. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_auth/_utils.py +0 -0
  50. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_auth/auth_config.json +0 -0
  51. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_auth/index.html +0 -0
  52. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_auth/localhost.crt +0 -0
  53. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_auth/localhost.key +0 -0
  54. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_runtime/_contracts.py +0 -0
  55. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_runtime/_logging.py +0 -0
  56. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_runtime/_runtime.py +0 -0
  57. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_templates/.psmdcp.template +0 -0
  58. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_templates/.rels.template +0 -0
  59. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_templates/[Content_Types].xml.template +0 -0
  60. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_templates/main.py.template +0 -0
  61. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_templates/package.nuspec.template +0 -0
  62. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_utils/_common.py +0 -0
  63. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_utils/_input_args.py +0 -0
  64. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/_utils/_parse_ast.py +0 -0
  65. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/cli_auth.py +0 -0
  66. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/cli_deploy.py +0 -0
  67. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/cli_init.py +0 -0
  68. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/cli_new.py +0 -0
  69. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/cli_pack.py +0 -0
  70. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/cli_publish.py +0 -0
  71. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/cli_run.py +0 -0
  72. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_cli/middlewares.py +0 -0
  73. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_config.py +0 -0
  74. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_execution_context.py +0 -0
  75. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_folder_context.py +0 -0
  76. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/__init__.py +0 -0
  77. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/_base_service.py +0 -0
  78. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/actions_service.py +0 -0
  79. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/api_client.py +0 -0
  80. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/assets_service.py +0 -0
  81. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/buckets_service.py +0 -0
  82. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/connections_service.py +0 -0
  83. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/connections_service.pyi +0 -0
  84. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/context_grounding_service.py +0 -0
  85. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/folder_service.py +0 -0
  86. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/jobs_service.py +0 -0
  87. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/llm_gateway_service.py +0 -0
  88. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/processes_service.py +0 -0
  89. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_services/queues_service.py +0 -0
  90. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_uipath.py +0 -0
  91. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_utils/__init__.py +0 -0
  92. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_utils/_endpoint.py +0 -0
  93. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_utils/_infer_bindings.py +0 -0
  94. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_utils/_logs.py +0 -0
  95. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_utils/_request_override.py +0 -0
  96. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_utils/_request_spec.py +0 -0
  97. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_utils/_user_agent.py +0 -0
  98. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/_utils/constants.py +0 -0
  99. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/__init__.py +0 -0
  100. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/action_schema.py +0 -0
  101. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/actions.py +0 -0
  102. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/assets.py +0 -0
  103. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/connections.py +0 -0
  104. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/context_grounding.py +0 -0
  105. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/context_grounding_index.py +0 -0
  106. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/exceptions.py +0 -0
  107. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/interrupt_models.py +0 -0
  108. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/job.py +0 -0
  109. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/llm_gateway.py +0 -0
  110. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/processes.py +0 -0
  111. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/models/queues.py +0 -0
  112. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/py.typed +0 -0
  113. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/tracing/__init__.py +0 -0
  114. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/tracing/_traced.py +0 -0
  115. {uipath-2.0.12 → uipath-2.0.13}/src/uipath/tracing/_utils.py +0 -0
  116. {uipath-2.0.12 → uipath-2.0.13}/tests/__init__.py +0 -0
  117. {uipath-2.0.12 → uipath-2.0.13}/tests/cli/test_init.py +0 -0
  118. {uipath-2.0.12 → uipath-2.0.13}/tests/conftest.py +0 -0
  119. {uipath-2.0.12 → uipath-2.0.13}/tests/sdk/services/test_llm_integration.py +0 -0
  120. {uipath-2.0.12 → uipath-2.0.13}/tests/sdk/services/test_llm_service.py +0 -0
  121. {uipath-2.0.12 → uipath-2.0.13}/tests/sdk/services/test_uipath_llm_integration.py +0 -0
  122. {uipath-2.0.12 → uipath-2.0.13}/tests/sdk/test_config.py +0 -0
  123. {uipath-2.0.12 → uipath-2.0.13}/tests/tracing/test_span_utils.py +0 -0
  124. {uipath-2.0.12 → uipath-2.0.13}/tests/tracing/test_traced.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uipath
3
- Version: 2.0.12
3
+ Version: 2.0.13
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "uipath"
3
- version = "2.0.12"
3
+ version = "2.0.13"
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"
@@ -1,7 +1,8 @@
1
1
  import json
2
2
  import logging
3
3
  import os
4
- from typing import Sequence
4
+ import time
5
+ from typing import Any, Dict, Sequence
5
6
 
6
7
  from httpx import Client
7
8
  from opentelemetry.sdk.trace import ReadableSpan
@@ -30,7 +31,7 @@ class LlmOpsHttpExporter(SpanExporter):
30
31
 
31
32
  self.http_client = Client(headers=self.headers)
32
33
 
33
- def export(self, spans: Sequence[ReadableSpan]):
34
+ def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
34
35
  """Export spans to UiPath LLM Ops."""
35
36
  logger.debug(
36
37
  f"Exporting {len(spans)} spans to {self.base_url}/llmopstenant_/api/Traces/spans"
@@ -39,23 +40,42 @@ class LlmOpsHttpExporter(SpanExporter):
39
40
  span_list = [
40
41
  _SpanUtils.otel_span_to_uipath_span(span).to_dict() for span in spans
41
42
  ]
43
+ url = self._build_url(span_list)
42
44
 
43
- trace_id = str(span_list[0]["TraceId"])
44
- url = f"{self.base_url}/llmopstenant_/api/Traces/spans?traceId={trace_id}&source=Robots"
45
-
46
- logger.debug("payload: ", json.dumps(span_list))
47
-
48
- res = self.http_client.post(url, json=span_list)
45
+ logger.debug("Payload: %s", json.dumps(span_list))
49
46
 
50
- if res.status_code == 200:
51
- return SpanExportResult.SUCCESS
52
- else:
53
- return SpanExportResult.FAILURE
47
+ return self._send_with_retries(url, span_list)
54
48
 
55
49
  def force_flush(self, timeout_millis: int = 30000) -> bool:
56
50
  """Force flush the exporter."""
57
51
  return True
58
52
 
53
+ def _build_url(self, span_list: list[Dict[str, Any]]) -> str:
54
+ """Construct the URL for the API request."""
55
+ trace_id = str(span_list[0]["TraceId"])
56
+ return f"{self.base_url}/llmopstenant_/api/Traces/spans?traceId={trace_id}&source=Robots"
57
+
58
+ def _send_with_retries(
59
+ self, url: str, payload: list[Dict[str, Any]], max_retries: int = 4
60
+ ) -> SpanExportResult:
61
+ """Send the HTTP request with retry logic."""
62
+ for attempt in range(max_retries):
63
+ try:
64
+ response = self.http_client.post(url, json=payload)
65
+ if response.status_code == 200:
66
+ return SpanExportResult.SUCCESS
67
+ else:
68
+ logger.warning(
69
+ f"Attempt {attempt + 1} failed with status code {response.status_code}: {response.text}"
70
+ )
71
+ except Exception as e:
72
+ logger.error(f"Attempt {attempt + 1} failed with exception: {e}")
73
+
74
+ if attempt < max_retries - 1:
75
+ time.sleep(1.5**attempt) # Exponential backoff
76
+
77
+ return SpanExportResult.FAILURE
78
+
59
79
  def _get_base_url(self) -> str:
60
80
  uipath_url = (
61
81
  os.environ.get("UIPATH_URL")
@@ -0,0 +1,190 @@
1
+ import os
2
+ from unittest.mock import MagicMock, patch
3
+
4
+ import pytest
5
+ from opentelemetry.sdk.trace import ReadableSpan
6
+ from opentelemetry.sdk.trace.export import SpanExportResult
7
+
8
+ from uipath.tracing._otel_exporters import LlmOpsHttpExporter
9
+
10
+
11
+ @pytest.fixture
12
+ def mock_env_vars():
13
+ """Fixture to set and clean up environment variables for testing."""
14
+ original_values = {}
15
+
16
+ # Save original values
17
+ for var in ["UIPATH_URL", "UIPATH_ACCESS_TOKEN"]:
18
+ original_values[var] = os.environ.get(var)
19
+
20
+ # Set test values
21
+ os.environ["UIPATH_URL"] = "https://test.uipath.com/org/tenant/"
22
+ os.environ["UIPATH_ACCESS_TOKEN"] = "test-token"
23
+
24
+ yield
25
+
26
+ # Restore original values
27
+ for var, value in original_values.items():
28
+ if value is None:
29
+ if var in os.environ:
30
+ del os.environ[var]
31
+ else:
32
+ os.environ[var] = value
33
+
34
+
35
+ @pytest.fixture
36
+ def mock_span():
37
+ """Create a mock ReadableSpan for testing."""
38
+ span = MagicMock(spec=ReadableSpan)
39
+ return span
40
+
41
+
42
+ @pytest.fixture
43
+ def exporter(mock_env_vars):
44
+ """Create an exporter instance for testing."""
45
+ with patch("uipath.tracing._otel_exporters.Client"):
46
+ exporter = LlmOpsHttpExporter()
47
+ # Mock _build_url to include query parameters as in the actual implementation
48
+ exporter._build_url = MagicMock( # type: ignore
49
+ return_value="https://test.uipath.com/org/tenant/llmopstenant_/api/Traces/spans?traceId=test-trace-id&source=Robots"
50
+ )
51
+ yield exporter
52
+
53
+
54
+ def test_init_with_env_vars(mock_env_vars):
55
+ """Test initialization with environment variables."""
56
+ with patch("uipath.tracing._otel_exporters.Client"):
57
+ exporter = LlmOpsHttpExporter()
58
+
59
+ assert exporter.base_url == "https://test.uipath.com/org/tenant"
60
+ assert exporter.auth_token == "test-token"
61
+ assert exporter.headers == {
62
+ "Content-Type": "application/json",
63
+ "Authorization": "Bearer test-token",
64
+ }
65
+
66
+
67
+ def test_init_with_default_url():
68
+ """Test initialization with default URL when environment variable is not set."""
69
+ with (
70
+ patch("uipath.tracing._otel_exporters.Client"),
71
+ patch.dict(os.environ, {"UIPATH_ACCESS_TOKEN": "test-token"}, clear=True),
72
+ ):
73
+ exporter = LlmOpsHttpExporter()
74
+
75
+ assert exporter.base_url == "https://cloud.uipath.com/dummyOrg/dummyTennant"
76
+ assert exporter.auth_token == "test-token"
77
+
78
+
79
+ def test_export_success(exporter, mock_span):
80
+ """Test successful export of spans."""
81
+ mock_uipath_span = MagicMock()
82
+ mock_uipath_span.to_dict.return_value = {"span": "data", "TraceId": "test-trace-id"}
83
+
84
+ with patch(
85
+ "uipath.tracing._otel_exporters._SpanUtils.otel_span_to_uipath_span",
86
+ return_value=mock_uipath_span,
87
+ ):
88
+ mock_response = MagicMock()
89
+ mock_response.status_code = 200
90
+ exporter.http_client.post.return_value = mock_response
91
+
92
+ result = exporter.export([mock_span])
93
+
94
+ assert result == SpanExportResult.SUCCESS
95
+ exporter._build_url.assert_called_once_with(
96
+ [{"span": "data", "TraceId": "test-trace-id"}]
97
+ )
98
+ exporter.http_client.post.assert_called_once_with(
99
+ "https://test.uipath.com/org/tenant/llmopstenant_/api/Traces/spans?traceId=test-trace-id&source=Robots",
100
+ json=[{"span": "data", "TraceId": "test-trace-id"}],
101
+ )
102
+
103
+
104
+ def test_export_failure(exporter, mock_span):
105
+ """Test export failure with multiple retries."""
106
+ mock_uipath_span = MagicMock()
107
+ mock_uipath_span.to_dict.return_value = {"span": "data"}
108
+
109
+ with patch(
110
+ "uipath.tracing._otel_exporters._SpanUtils.otel_span_to_uipath_span",
111
+ return_value=mock_uipath_span,
112
+ ):
113
+ mock_response = MagicMock()
114
+ mock_response.status_code = 500
115
+ mock_response.text = "Internal Server Error"
116
+ exporter.http_client.post.return_value = mock_response
117
+
118
+ with patch("uipath.tracing._otel_exporters.time.sleep") as mock_sleep:
119
+ result = exporter.export([mock_span])
120
+
121
+ assert result == SpanExportResult.FAILURE
122
+ assert exporter.http_client.post.call_count == 4 # Default max_retries is 3
123
+ assert (
124
+ mock_sleep.call_count == 3
125
+ ) # Should sleep between retries (except after the last one)
126
+
127
+
128
+ def test_export_exception(exporter, mock_span):
129
+ """Test export with exceptions during HTTP request."""
130
+ mock_uipath_span = MagicMock()
131
+ mock_uipath_span.to_dict.return_value = {"span": "data"}
132
+
133
+ with patch(
134
+ "uipath.tracing._otel_exporters._SpanUtils.otel_span_to_uipath_span",
135
+ return_value=mock_uipath_span,
136
+ ):
137
+ exporter.http_client.post.side_effect = Exception("Connection error")
138
+
139
+ with patch("uipath.tracing._otel_exporters.time.sleep"):
140
+ result = exporter.export([mock_span])
141
+
142
+ assert result == SpanExportResult.FAILURE
143
+ assert exporter.http_client.post.call_count == 4 # Default max_retries is 3
144
+
145
+
146
+ def test_force_flush(exporter):
147
+ """Test force_flush returns True."""
148
+ assert exporter.force_flush() is True
149
+
150
+
151
+ def test_get_base_url():
152
+ """Test _get_base_url method with different environment configurations."""
153
+ # Test with environment variable set
154
+ with patch.dict(
155
+ os.environ, {"UIPATH_URL": "https://custom.uipath.com/org/tenant/"}, clear=True
156
+ ):
157
+ with patch("uipath.tracing._otel_exporters.Client"):
158
+ exporter = LlmOpsHttpExporter()
159
+ assert exporter.base_url == "https://custom.uipath.com/org/tenant"
160
+
161
+ # Test with environment variable set but with no trailing slash
162
+ with patch.dict(
163
+ os.environ, {"UIPATH_URL": "https://custom.uipath.com/org/tenant"}, clear=True
164
+ ):
165
+ with patch("uipath.tracing._otel_exporters.Client"):
166
+ exporter = LlmOpsHttpExporter()
167
+ assert exporter.base_url == "https://custom.uipath.com/org/tenant"
168
+
169
+ # Test with no environment variable
170
+ with patch.dict(os.environ, {}, clear=True):
171
+ with patch("uipath.tracing._otel_exporters.Client"):
172
+ exporter = LlmOpsHttpExporter()
173
+ assert exporter.base_url == "https://cloud.uipath.com/dummyOrg/dummyTennant"
174
+
175
+
176
+ def test_send_with_retries_success():
177
+ """Test _send_with_retries method with successful response."""
178
+ with patch("uipath.tracing._otel_exporters.Client"):
179
+ exporter = LlmOpsHttpExporter()
180
+
181
+ mock_response = MagicMock()
182
+ mock_response.status_code = 200
183
+ exporter.http_client.post.return_value = mock_response # type: ignore
184
+
185
+ result = exporter._send_with_retries("http://example.com", [{"span": "data"}])
186
+
187
+ assert result == SpanExportResult.SUCCESS
188
+ exporter.http_client.post.assert_called_once_with( # type: ignore
189
+ "http://example.com", json=[{"span": "data"}]
190
+ )
@@ -2393,7 +2393,7 @@ wheels = [
2393
2393
 
2394
2394
  [[package]]
2395
2395
  name = "uipath"
2396
- version = "2.0.12"
2396
+ version = "2.0.13"
2397
2397
  source = { editable = "." }
2398
2398
  dependencies = [
2399
2399
  { name = "click" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes