uipath 2.0.63__py3-none-any.whl → 2.0.64__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.

Potentially problematic release.


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

@@ -0,0 +1,235 @@
1
+ import json
2
+ import logging
3
+ from pathlib import Path
4
+ from typing import Any, Dict, Optional, Union
5
+
6
+ from uipath import UiPath
7
+ from uipath.models.actions import Action
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class Escalation:
13
+ """Class to handle default escalation."""
14
+
15
+ def __init__(self, config_path: Union[str, Path] = "uipath.json"):
16
+ """Initialize the escalation with a config file path.
17
+
18
+ Args:
19
+ config_path: Path to the configuration file (string or Path object)
20
+ """
21
+ self.config_path = Path(config_path)
22
+ self._config = None
23
+ self._enabled = False
24
+ self._load_config()
25
+
26
+ def _load_config(self) -> None:
27
+ """Load and validate the default escalation from the config file.
28
+
29
+ If the 'defaultEscalation' section exists, validates required fields.
30
+ Raises error if required fields are missing.
31
+ """
32
+ try:
33
+ config_data = json.loads(self.config_path.read_text(encoding="utf-8"))
34
+ escalation_config = config_data.get("defaultEscalation")
35
+
36
+ if escalation_config:
37
+ required_fields = {"request", "title"}
38
+ missing_fields = [
39
+ field for field in required_fields if field not in escalation_config
40
+ ]
41
+
42
+ if not any(key in escalation_config for key in ("appName", "appKey")):
43
+ missing_fields.append("appName or appKey")
44
+
45
+ if missing_fields:
46
+ raise ValueError(
47
+ f"Missing required fields in configuration: {', '.join(missing_fields)}"
48
+ )
49
+
50
+ self._config = escalation_config
51
+ self._enabled = True
52
+ logger.debug("Escalation configuration loaded successfully")
53
+ else:
54
+ self._enabled = False
55
+
56
+ except FileNotFoundError:
57
+ logger.debug(f"Config file not found: {self.config_path}")
58
+ self._enabled = False
59
+
60
+ except json.JSONDecodeError:
61
+ logger.warning(
62
+ f"Failed to parse config file {self.config_path}: Invalid JSON"
63
+ )
64
+ self._enabled = False
65
+
66
+ except ValueError as e:
67
+ logger.error(str(e))
68
+ raise
69
+
70
+ except Exception as e:
71
+ logger.error(f"Unexpected error loading config {self.config_path}: {e}")
72
+ self._enabled = False
73
+
74
+ @property
75
+ def enabled(self) -> bool:
76
+ """Check if escalation is enabled.
77
+
78
+ Returns:
79
+ True if configuration is valid and loaded
80
+ """
81
+ return self._enabled
82
+
83
+ def prepare_data(self, value: Any) -> Dict[str, Any]:
84
+ """Prepare action data by replacing $VALUE placeholders with the provided value.
85
+
86
+ Args:
87
+ value: The value to substitute into the template
88
+
89
+ Returns:
90
+ Prepared data dictionary with substitutions applied
91
+ """
92
+ if not self.enabled or not self._config:
93
+ return {}
94
+
95
+ template = self._config.get("request", {})
96
+
97
+ if isinstance(value, str):
98
+ try:
99
+ value_obj = json.loads(value)
100
+ except json.JSONDecodeError:
101
+ value_obj = value
102
+ else:
103
+ value_obj = value
104
+
105
+ return self._substitute_values(template, value_obj)
106
+
107
+ def _substitute_values(
108
+ self, template: Dict[str, Any], value: Any
109
+ ) -> Dict[str, Any]:
110
+ """Replace template placeholders with actual values.
111
+
112
+ Args:
113
+ template: Template dictionary containing placeholders
114
+ value: Values to substitute into the template
115
+
116
+ Returns:
117
+ Template with values substituted
118
+ """
119
+
120
+ def process_value(template_value):
121
+ if isinstance(template_value, dict):
122
+ return {k: process_value(v) for k, v in template_value.items()}
123
+ elif isinstance(template_value, list):
124
+ return [process_value(item) for item in template_value]
125
+ elif isinstance(template_value, str):
126
+ if template_value == "$VALUE":
127
+ return value
128
+ elif template_value.startswith("$VALUE."):
129
+ return self._resolve_value_path(template_value, value)
130
+
131
+ return template_value
132
+
133
+ return process_value(template)
134
+
135
+ def _resolve_value_path(self, path_expr: str, value: Any) -> Any:
136
+ """Resolve a dot-notation path expression against a value.
137
+
138
+ Args:
139
+ path_expr: Path expression (e.g. "$VALUE.user.name")
140
+ value: Value object to extract data from
141
+
142
+ Returns:
143
+ Extracted value or None if path doesn't exist
144
+ """
145
+ path_parts = path_expr.replace("$VALUE.", "").split(".")
146
+ current = value
147
+
148
+ for part in path_parts:
149
+ if not isinstance(current, dict) or part not in current:
150
+ return None
151
+ current = current.get(part)
152
+
153
+ return current
154
+
155
+ def extract_response_value(self, action_data: Dict[str, Any]) -> Any:
156
+ if not self._config:
157
+ return ""
158
+
159
+ response_template = self._config.get("response")
160
+ if not response_template:
161
+ return ""
162
+
163
+ for key, template_value in response_template.items():
164
+ if key in action_data:
165
+ extracted_value = None
166
+
167
+ if template_value == "$VALUE":
168
+ extracted_value = action_data[key]
169
+ elif isinstance(template_value, str) and template_value.startswith(
170
+ "$VALUE."
171
+ ):
172
+ path_parts = template_value.replace("$VALUE.", "").split(".")
173
+ current = action_data[key]
174
+
175
+ valid_path = True
176
+ for part in path_parts:
177
+ if not isinstance(current, dict) or part not in current:
178
+ valid_path = False
179
+ break
180
+ current = current.get(part)
181
+
182
+ if valid_path:
183
+ extracted_value = current
184
+
185
+ if extracted_value is not None:
186
+ if isinstance(extracted_value, str):
187
+ if extracted_value.lower() == "true":
188
+ return True
189
+ elif extracted_value.lower() == "false":
190
+ return False
191
+
192
+ try:
193
+ if "." in extracted_value:
194
+ return float(extracted_value)
195
+ else:
196
+ return int(extracted_value)
197
+ except ValueError:
198
+ pass
199
+
200
+ return extracted_value
201
+
202
+ return action_data
203
+
204
+ async def create(self, value: Any) -> Optional[Action]:
205
+ """Create an escalation Action with the prepared data.
206
+
207
+ Args:
208
+ value: The dynamic value to be substituted into the template
209
+
210
+ Returns:
211
+ The created Action object or None if creation fails
212
+ """
213
+ if not self.enabled or not self._config:
214
+ return None
215
+
216
+ action_data = self.prepare_data(value)
217
+
218
+ if not action_data:
219
+ logger.warning("Action creation skipped: empty data after preparation")
220
+ return None
221
+
222
+ try:
223
+ uipath = UiPath()
224
+ action = uipath.actions.create(
225
+ title=self._config.get("title", "Default escalation"),
226
+ app_name=self._config.get("appName"),
227
+ app_key=self._config.get("appKey"),
228
+ app_version=self._config.get("appVersion", 1),
229
+ data=action_data,
230
+ )
231
+ logger.info(f"Action created successfully: {action.key}")
232
+ return action
233
+ except Exception as e:
234
+ logger.error(f"Error creating action: {e}")
235
+ return None
@@ -0,0 +1,194 @@
1
+ import json
2
+ import uuid
3
+ from dataclasses import dataclass
4
+ from functools import cached_property
5
+ from typing import Any, Optional
6
+
7
+ from uipath import UiPath
8
+ from uipath.models import CreateAction, InvokeProcess, WaitAction, WaitJob
9
+
10
+ from .._runtime._contracts import (
11
+ UiPathApiTrigger,
12
+ UiPathErrorCategory,
13
+ UiPathResumeTrigger,
14
+ UiPathResumeTriggerType,
15
+ UiPathRuntimeError,
16
+ UiPathRuntimeStatus,
17
+ )
18
+ from .._utils._common import serialize_object
19
+ from ._escalation import Escalation
20
+
21
+
22
+ def _try_convert_to_json_format(value: str) -> str:
23
+ try:
24
+ return json.loads(value)
25
+ except json.decoder.JSONDecodeError:
26
+ return value
27
+
28
+
29
+ default_escalation = Escalation()
30
+
31
+
32
+ class HitlReader:
33
+ @classmethod
34
+ async def read(cls, resume_trigger: UiPathResumeTrigger) -> Optional[str]:
35
+ uipath = UiPath()
36
+ match resume_trigger.trigger_type:
37
+ case UiPathResumeTriggerType.ACTION:
38
+ if resume_trigger.item_key:
39
+ action = await uipath.actions.retrieve_async(
40
+ resume_trigger.item_key,
41
+ app_folder_key=resume_trigger.folder_key,
42
+ app_folder_path=resume_trigger.folder_path,
43
+ )
44
+
45
+ if default_escalation.enabled:
46
+ return default_escalation.extract_response_value(action.data)
47
+
48
+ return action.data
49
+
50
+ case UiPathResumeTriggerType.JOB:
51
+ if resume_trigger.item_key:
52
+ job = await uipath.jobs.retrieve_async(
53
+ resume_trigger.item_key,
54
+ folder_key=resume_trigger.folder_key,
55
+ folder_path=resume_trigger.folder_path,
56
+ )
57
+ if (
58
+ job.state
59
+ and not job.state.lower()
60
+ == UiPathRuntimeStatus.SUCCESSFUL.value.lower()
61
+ ):
62
+ raise UiPathRuntimeError(
63
+ "INVOKED_PROCESS_FAILURE",
64
+ "Invoked process did not finish successfully.",
65
+ _try_convert_to_json_format(str(job.job_error or job.info)),
66
+ )
67
+ return job.output_arguments
68
+
69
+ case UiPathResumeTriggerType.API:
70
+ if resume_trigger.api_resume and resume_trigger.api_resume.inbox_id:
71
+ try:
72
+ return await uipath.jobs.retrieve_api_payload_async(
73
+ resume_trigger.api_resume.inbox_id
74
+ )
75
+ except Exception as e:
76
+ raise UiPathRuntimeError(
77
+ "API_CONNECTION_ERROR",
78
+ "Failed to get trigger payload",
79
+ f"Error fetching API trigger payload for inbox {resume_trigger.api_resume.inbox_id}: {str(e)}",
80
+ UiPathErrorCategory.SYSTEM,
81
+ ) from e
82
+ case _:
83
+ raise UiPathRuntimeError(
84
+ "UNKNOWN_TRIGGER_TYPE",
85
+ "Unexpected trigger type received",
86
+ f"Trigger type :{type(resume_trigger.trigger_type)} is invalid",
87
+ UiPathErrorCategory.USER,
88
+ )
89
+
90
+ raise UiPathRuntimeError(
91
+ "HITL_FEEDBACK_FAILURE",
92
+ "Failed to receive payload from HITL action",
93
+ detail="Failed to receive payload from HITL action",
94
+ category=UiPathErrorCategory.SYSTEM,
95
+ )
96
+
97
+
98
+ @dataclass
99
+ class HitlProcessor:
100
+ """Processes events in a Human-(Robot/Agent)-In-The-Loop scenario."""
101
+
102
+ value: Any
103
+
104
+ @cached_property
105
+ def type(self) -> UiPathResumeTriggerType:
106
+ """Returns the type of the interrupt value."""
107
+ if isinstance(self.value, CreateAction) or isinstance(self.value, WaitAction):
108
+ return UiPathResumeTriggerType.ACTION
109
+ if isinstance(self.value, InvokeProcess) or isinstance(self.value, WaitJob):
110
+ return UiPathResumeTriggerType.JOB
111
+ # default to API trigger
112
+ return UiPathResumeTriggerType.API
113
+
114
+ async def create_resume_trigger(self) -> UiPathResumeTrigger:
115
+ """Returns the resume trigger."""
116
+ uipath = UiPath()
117
+ try:
118
+ hitl_input = self.value
119
+ resume_trigger = UiPathResumeTrigger(
120
+ trigger_type=self.type, payload=serialize_object(hitl_input)
121
+ )
122
+
123
+ # check for default escalation config
124
+ if default_escalation.enabled and isinstance(hitl_input, str):
125
+ resume_trigger.trigger_type = UiPathResumeTriggerType.ACTION
126
+ action = await default_escalation.create(hitl_input)
127
+ if not action:
128
+ raise Exception("Failed to create default escalation")
129
+ resume_trigger.item_key = action.key
130
+ return resume_trigger
131
+
132
+ match self.type:
133
+ case UiPathResumeTriggerType.ACTION:
134
+ resume_trigger.folder_path = hitl_input.app_folder_path
135
+ resume_trigger.folder_key = hitl_input.app_folder_key
136
+ if isinstance(hitl_input, WaitAction):
137
+ resume_trigger.item_key = hitl_input.action.key
138
+ elif isinstance(hitl_input, CreateAction):
139
+ action = await uipath.actions.create_async(
140
+ title=hitl_input.title,
141
+ app_name=hitl_input.app_name if hitl_input.app_name else "",
142
+ app_folder_path=hitl_input.app_folder_path
143
+ if hitl_input.app_folder_path
144
+ else "",
145
+ app_folder_key=hitl_input.app_folder_key
146
+ if hitl_input.app_folder_key
147
+ else "",
148
+ app_key=hitl_input.app_key if hitl_input.app_key else "",
149
+ app_version=hitl_input.app_version
150
+ if hitl_input.app_version
151
+ else 1,
152
+ assignee=hitl_input.assignee if hitl_input.assignee else "",
153
+ data=hitl_input.data,
154
+ )
155
+ if not action:
156
+ raise Exception("Failed to create action")
157
+ resume_trigger.item_key = action.key
158
+
159
+ case UiPathResumeTriggerType.JOB:
160
+ resume_trigger.folder_path = hitl_input.process_folder_path
161
+ resume_trigger.folder_key = hitl_input.process_folder_key
162
+ if isinstance(hitl_input, WaitJob):
163
+ resume_trigger.item_key = hitl_input.job.key
164
+ elif isinstance(hitl_input, InvokeProcess):
165
+ job = await uipath.processes.invoke_async(
166
+ name=hitl_input.name,
167
+ input_arguments=hitl_input.input_arguments,
168
+ folder_path=hitl_input.process_folder_path,
169
+ folder_key=hitl_input.process_folder_key,
170
+ )
171
+ if not job:
172
+ raise Exception("Failed to invoke process")
173
+ resume_trigger.item_key = job.key
174
+
175
+ case UiPathResumeTriggerType.API:
176
+ resume_trigger.api_resume = UiPathApiTrigger(
177
+ inbox_id=str(uuid.uuid4()), request=serialize_object(hitl_input)
178
+ )
179
+ case _:
180
+ raise UiPathRuntimeError(
181
+ "UNKNOWN_HITL_MODEL",
182
+ "Unexpected model received",
183
+ f"{type(hitl_input)} is not a valid Human(Robot/Agent)-In-The-Loop model",
184
+ UiPathErrorCategory.USER,
185
+ )
186
+ except Exception as e:
187
+ raise UiPathRuntimeError(
188
+ "HITL_ACTION_CREATION_FAILED",
189
+ "Failed to create HITL action",
190
+ f"{str(e)}",
191
+ UiPathErrorCategory.SYSTEM,
192
+ ) from e
193
+
194
+ return resume_trigger
@@ -43,3 +43,29 @@ def get_env_vars(spinner: Optional[Spinner] = None) -> list[str | None]:
43
43
  click.get_current_context().exit(1)
44
44
 
45
45
  return [base_url, token]
46
+
47
+
48
+ def serialize_object(obj):
49
+ """Recursively serializes an object and all its nested components."""
50
+ # Handle Pydantic models
51
+ if hasattr(obj, "model_dump"):
52
+ return serialize_object(obj.model_dump(by_alias=True))
53
+ elif hasattr(obj, "dict"):
54
+ return serialize_object(obj.dict())
55
+ elif hasattr(obj, "to_dict"):
56
+ return serialize_object(obj.to_dict())
57
+ # Handle dictionaries
58
+ elif isinstance(obj, dict):
59
+ return {k: serialize_object(v) for k, v in obj.items()}
60
+ # Handle lists
61
+ elif isinstance(obj, list):
62
+ return [serialize_object(item) for item in obj]
63
+ # Handle other iterable objects (convert to dict first)
64
+ elif hasattr(obj, "__iter__") and not isinstance(obj, (str, bytes)):
65
+ try:
66
+ return serialize_object(dict(obj))
67
+ except (TypeError, ValueError):
68
+ return obj
69
+ # Return primitive types as is
70
+ else:
71
+ return obj
@@ -0,0 +1,52 @@
1
+ import datetime
2
+ import logging
3
+ from zoneinfo import ZoneInfo
4
+
5
+
6
+ class IgnoreSpecificUrl(logging.Filter):
7
+ def __init__(self, url_to_ignore):
8
+ super().__init__()
9
+ self.url_to_ignore = url_to_ignore
10
+
11
+ def filter(self, record):
12
+ try:
13
+ if record.msg == 'HTTP Request: %s %s "%s %d %s"':
14
+ # Ignore the log if the URL matches the one we want to ignore
15
+ method = record.args[0]
16
+ url = record.args[1]
17
+
18
+ if method == "POST" and url.path.endswith(self.url_to_ignore):
19
+ # Check if the URL contains the specific path we want to ignore
20
+ return True
21
+ return False
22
+
23
+ except Exception:
24
+ return False
25
+
26
+
27
+ def setup_tracer_httpx_logging(url: str):
28
+ # Create a custom logger for httpx
29
+ # Add the custom filter to the root logger
30
+ logging.getLogger("httpx").addFilter(IgnoreSpecificUrl(url))
31
+
32
+
33
+ def simple_serialize_defaults(obj):
34
+ if hasattr(obj, "model_dump"):
35
+ return obj.model_dump(exclude_none=True, mode="json")
36
+ if hasattr(obj, "dict"):
37
+ return obj.dict()
38
+ if hasattr(obj, "to_dict"):
39
+ return obj.to_dict()
40
+
41
+ if isinstance(obj, (set, tuple)):
42
+ if hasattr(obj, "_asdict") and callable(obj._asdict):
43
+ return obj._asdict()
44
+ return list(obj)
45
+
46
+ if isinstance(obj, datetime.datetime):
47
+ return obj.isoformat()
48
+
49
+ if isinstance(obj, (datetime.timezone, ZoneInfo)):
50
+ return obj.tzname(None)
51
+
52
+ return str(obj)
@@ -272,6 +272,59 @@ class JobsService(FolderContext, BaseService):
272
272
  response = response.json()
273
273
  return self._extract_first_inbox_id(response)
274
274
 
275
+ def retrieve_api_payload(self, inbox_id: str) -> Any:
276
+ """Fetch payload data for API triggers.
277
+
278
+ Args:
279
+ inbox_id: The Id of the inbox to fetch the payload for.
280
+
281
+ Returns:
282
+ The value field from the API response payload.
283
+ """
284
+ spec = self._retrieve_api_payload_spec(inbox_id=inbox_id)
285
+
286
+ response = self.request(
287
+ spec.method,
288
+ url=spec.endpoint,
289
+ headers=spec.headers,
290
+ )
291
+
292
+ data = response.json()
293
+ return data.get("payload")
294
+
295
+ async def retrieve_api_payload_async(self, inbox_id: str) -> Any:
296
+ """Asynchronously fetch payload data for API triggers.
297
+
298
+ Args:
299
+ inbox_id: The Id of the inbox to fetch the payload for.
300
+
301
+ Returns:
302
+ The value field from the API response payload.
303
+ """
304
+ spec = self._retrieve_api_payload_spec(inbox_id=inbox_id)
305
+
306
+ response = await self.request_async(
307
+ spec.method,
308
+ url=spec.endpoint,
309
+ headers=spec.headers,
310
+ )
311
+
312
+ data = response.json()
313
+ return data.get("payload")
314
+
315
+ def _retrieve_api_payload_spec(
316
+ self,
317
+ *,
318
+ inbox_id: str,
319
+ ) -> RequestSpec:
320
+ return RequestSpec(
321
+ method="GET",
322
+ endpoint=Endpoint(f"/orchestrator_/api/JobTriggers/GetPayload/{inbox_id}"),
323
+ headers={
324
+ **self.folder_headers,
325
+ },
326
+ )
327
+
275
328
  def _extract_first_inbox_id(self, response: Any) -> str:
276
329
  if len(response["value"]) > 0:
277
330
  return response["value"][0]["ItemKey"]
uipath/tracing/_traced.py CHANGED
@@ -11,7 +11,18 @@ from ._utils import _SpanUtils
11
11
 
12
12
  logger = logging.getLogger(__name__)
13
13
 
14
- tracer = trace.get_tracer(__name__)
14
+ _tracer_instance: Optional[trace.Tracer] = None
15
+
16
+
17
+ def get_tracer() -> trace.Tracer:
18
+ """Lazily initializes and returns the tracer instance."""
19
+ global _tracer_instance
20
+ if _tracer_instance is None:
21
+ logger.warning(
22
+ "Initializing tracer instance. This should only be done once per process."
23
+ )
24
+ _tracer_instance = trace.get_tracer(__name__)
25
+ return _tracer_instance
15
26
 
16
27
 
17
28
  class TracingManager:
@@ -22,13 +33,45 @@ class TracingManager:
22
33
  _traced_registry: List[Tuple[Callable[..., Any], Callable[..., Any], Any]] = []
23
34
 
24
35
  # Custom tracer implementation
25
- _custom_tracer_implementation = None
36
+ _custom_tracer_implementation = None # Custom span provider function
37
+ _current_span_provider: Optional[Callable[[], Any]] = None
26
38
 
27
39
  @classmethod
28
40
  def get_custom_tracer_implementation(cls):
29
41
  """Get the currently set custom tracer implementation."""
30
42
  return cls._custom_tracer_implementation
31
43
 
44
+ @classmethod
45
+ def register_current_span_provider(
46
+ cls, current_span_provider: Optional[Callable[[], Any]]
47
+ ):
48
+ """Register a custom current span provider function.
49
+
50
+ Args:
51
+ current_span_provider: A function that returns the current span from an external
52
+ tracing framework. If None, no custom span parenting will be used.
53
+ """
54
+ cls._current_span_provider = current_span_provider
55
+
56
+ @classmethod
57
+ def get_parent_context(cls):
58
+ """Get the parent context using the registered current span provider.
59
+
60
+ Returns:
61
+ Context object with the current span set, or None if no provider is registered.
62
+ """
63
+ if cls._current_span_provider is not None:
64
+ try:
65
+ current_span = cls._current_span_provider()
66
+ if current_span is not None:
67
+ from opentelemetry.trace import set_span_in_context
68
+
69
+ return set_span_in_context(current_span)
70
+ except Exception as e:
71
+ logger.warning(f"Error getting current span from provider: {e}")
72
+ return None
73
+ return None
74
+
32
75
  @classmethod
33
76
  def register_traced_function(cls, original_func, decorated_func, params):
34
77
  """Register a function decorated with @traced and its parameters.
@@ -137,7 +180,11 @@ def _opentelemetry_traced(
137
180
 
138
181
  @wraps(func)
139
182
  def sync_wrapper(*args, **kwargs):
140
- with tracer.start_as_current_span(trace_name) as span:
183
+ context = TracingManager.get_parent_context()
184
+
185
+ with get_tracer().start_as_current_span(
186
+ trace_name, context=context
187
+ ) as span:
141
188
  default_span_type = "function_call_sync"
142
189
  span.set_attribute(
143
190
  "span_type",
@@ -172,7 +219,11 @@ def _opentelemetry_traced(
172
219
 
173
220
  @wraps(func)
174
221
  async def async_wrapper(*args, **kwargs):
175
- with tracer.start_as_current_span(trace_name) as span:
222
+ context = TracingManager.get_parent_context()
223
+
224
+ with get_tracer().start_as_current_span(
225
+ trace_name, context=context
226
+ ) as span:
176
227
  default_span_type = "function_call_async"
177
228
  span.set_attribute(
178
229
  "span_type",
@@ -207,7 +258,12 @@ def _opentelemetry_traced(
207
258
 
208
259
  @wraps(func)
209
260
  def generator_wrapper(*args, **kwargs):
210
- with tracer.start_as_current_span(trace_name) as span:
261
+ context = TracingManager.get_parent_context()
262
+
263
+ with get_tracer().start_as_current_span(
264
+ trace_name, context=context
265
+ ) as span:
266
+ span.get_span_context()
211
267
  default_span_type = "function_call_generator_sync"
212
268
  span.set_attribute(
213
269
  "span_type",
@@ -248,7 +304,11 @@ def _opentelemetry_traced(
248
304
 
249
305
  @wraps(func)
250
306
  async def async_generator_wrapper(*args, **kwargs):
251
- with tracer.start_as_current_span(trace_name) as span:
307
+ context = TracingManager.get_parent_context()
308
+
309
+ with get_tracer().start_as_current_span(
310
+ trace_name, context=context
311
+ ) as span:
252
312
  default_span_type = "function_call_generator_async"
253
313
  span.set_attribute(
254
314
  "span_type",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uipath
3
- Version: 2.0.63
3
+ Version: 2.0.64
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
@@ -26,6 +26,8 @@ uipath/_cli/_auth/index.html,sha256=ML_xDOcKs0ETYucufJskiYfWSvdrD_E26C0Qd3qpGj8,
26
26
  uipath/_cli/_auth/localhost.crt,sha256=oGl9oLLOiouHubAt39B4zEfylFvKEtbtr_43SIliXJc,1226
27
27
  uipath/_cli/_auth/localhost.key,sha256=X31VYXD8scZtmGA837dGX5l6G-LXHLo5ItWJhZXaz3c,1679
28
28
  uipath/_cli/_runtime/_contracts.py,sha256=Rxs-uEOA490fLPNimB8LqZW7KI-72O0BLY4Jm7Fa1ms,14316
29
+ uipath/_cli/_runtime/_escalation.py,sha256=x3vI98qsfRA-fL_tNkRVTFXioM5Gv2w0GFcXJJ5eQtg,7981
30
+ uipath/_cli/_runtime/_hitl.py,sha256=zcyQmU-lTMklMpAPY8ifAbyo9Dv6ZDp6iCOoVFZxE0c,8331
29
31
  uipath/_cli/_runtime/_logging.py,sha256=lA2LsakOrcSLnJWgo80-BYzIQBUWfqzzJGI1M61Gu0s,7874
30
32
  uipath/_cli/_runtime/_runtime.py,sha256=-ZA7MZctX3e_YX_SN9XFjtsQKaCZCdBL3YRYFmsacN4,10162
31
33
  uipath/_cli/_templates/.psmdcp.template,sha256=C7pBJPt98ovEljcBvGtEUGoWjjQhu9jls1bpYjeLOKA,611
@@ -33,13 +35,14 @@ uipath/_cli/_templates/.rels.template,sha256=-fTcw7OA1AcymHr0LzBqbMAAtzZTRXLTNa_
33
35
  uipath/_cli/_templates/[Content_Types].xml.template,sha256=bYsKDz31PkIF9QksjgAY_bqm57YC8U_owsZeNZAiBxQ,584
34
36
  uipath/_cli/_templates/main.py.template,sha256=QB62qX5HKDbW4lFskxj7h9uuxBITnTWqu_DE6asCwcU,476
35
37
  uipath/_cli/_templates/package.nuspec.template,sha256=YZyLc-u_EsmIoKf42JsLQ55OGeFmb8VkIU2VF7DFbtw,359
36
- uipath/_cli/_utils/_common.py,sha256=h0-lvaAzz-4iM7WuEqZhlTo5QadBpsQyAdlggx73-PA,1123
38
+ uipath/_cli/_utils/_common.py,sha256=wQ0a_lGj0bsuNvwxUfnLwg6T3IdatdfkrPcZMoufJNU,2058
37
39
  uipath/_cli/_utils/_console.py,sha256=rj4V3yeR1wnJzFTHnaE6wcY9OoJV-PiIQnLg_p62ClQ,6664
38
40
  uipath/_cli/_utils/_constants.py,sha256=mCeSWLURgw_dOMXjzyYBAvxKN3Vcd1vf7XKHgbdrOds,25
39
41
  uipath/_cli/_utils/_folders.py,sha256=usjLNOMdhvelEv0wsJ-v6q-qiUR1tbwXJL4Sd_SOocI,970
40
42
  uipath/_cli/_utils/_input_args.py,sha256=pyQhEcQXHdFHYTVNzvfWp439aii5StojoptnmCv5lfs,4094
41
43
  uipath/_cli/_utils/_parse_ast.py,sha256=A-QToBIf-oP7yP2DQTHO6blkk6ik5z_IeaIwtEWO4e0,19516
42
44
  uipath/_cli/_utils/_processes.py,sha256=iCGNf1y_K_r3bdmX9VWA70UP20bdUzKlMRrAxkdkdm4,1669
45
+ uipath/_cli/_utils/_tracing.py,sha256=2igb03j3EHjF_A406UhtCKkPfudVfFPjUq5tXUEG4oo,1541
43
46
  uipath/_services/__init__.py,sha256=10xtw3ENC30yR9CCq_b94RMZ3YrUeyfHV33yWYUd8tU,896
44
47
  uipath/_services/_base_service.py,sha256=y-QATIRF9JnUFKIwmjOWMHlE2BrJYgD8y4sGAve2kEM,5338
45
48
  uipath/_services/actions_service.py,sha256=LYKvG4VxNGQgZ46AzGK9kI1Txb-YmVvZj5ScPOue8Ls,15989
@@ -50,7 +53,7 @@ uipath/_services/buckets_service.py,sha256=Ikqt1Cgs_o2-2kuzcogcaBkNceSQDXLEe63kz
50
53
  uipath/_services/connections_service.py,sha256=qh-HNL_GJsyPUD0wSJZRF8ZdrTE9l4HrIilmXGK6dDk,4581
51
54
  uipath/_services/context_grounding_service.py,sha256=zS991jW8C8CLkXvJwB2SuY3edTRG84SUOmiXpKId2Go,24381
52
55
  uipath/_services/folder_service.py,sha256=h0CWNqF2-8w2QLrfy-D8P3z_qA81Te689OXlFKtnby0,2001
53
- uipath/_services/jobs_service.py,sha256=JiqHhfpe-a9G7sQq_TyHUvGkce5I1e_Bda533b5LvkY,29406
56
+ uipath/_services/jobs_service.py,sha256=CnDd7BM4AMqcMIR1qqu5ohhxf9m0AF4dnGoF4EX38kw,30872
54
57
  uipath/_services/llm_gateway_service.py,sha256=ySg3sflIoXmY9K7txlSm7bkuI2qzBT0kAKmGlFBk5KA,12032
55
58
  uipath/_services/processes_service.py,sha256=b-c4ynjcgS0ymp130r0lI93z7DF989u8HWOmWCux754,5727
56
59
  uipath/_services/queues_service.py,sha256=VaG3dWL2QK6AJBOLoW2NQTpkPfZjsqsYPl9-kfXPFzA,13534
@@ -85,10 +88,10 @@ uipath/telemetry/_constants.py,sha256=RVymOX07CRzcGMn1OWzh-TR6bZMvLG3vdCA6fvRrrC
85
88
  uipath/telemetry/_track.py,sha256=v0e3hgwtetMsUco4yosBzNU00Ek5SI9RxUTumrTTNyo,3872
86
89
  uipath/tracing/__init__.py,sha256=GKRINyWdHVrDsI-8mrZDLdf0oey6GHGlNZTOADK-kgc,224
87
90
  uipath/tracing/_otel_exporters.py,sha256=x0PDPmDKJcxashsuehVsSsqBCzRr6WsNFaq_3_HS5F0,3014
88
- uipath/tracing/_traced.py,sha256=UL0TBqUexYb2PuUIY_am9l0TEeRGXFdxKEcDq5J-NXQ,16319
91
+ uipath/tracing/_traced.py,sha256=qeVDrds2OUnpdUIA0RhtF0kg2dlAZhyC1RRkI-qivTM,18528
89
92
  uipath/tracing/_utils.py,sha256=ZeensQexnw69jVcsVrGyED7mPlAU-L1agDGm6_1A3oc,10388
90
- uipath-2.0.63.dist-info/METADATA,sha256=5KVy_f28alxFsAHE2alkPSAa89ppEVaRm3ELkU9xV4c,6304
91
- uipath-2.0.63.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
92
- uipath-2.0.63.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
93
- uipath-2.0.63.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
94
- uipath-2.0.63.dist-info/RECORD,,
93
+ uipath-2.0.64.dist-info/METADATA,sha256=3wKXRRMa7h8XVtGrCXXr6S9YUkHwsr_C-MYQ2eSqn_k,6304
94
+ uipath-2.0.64.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
95
+ uipath-2.0.64.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
96
+ uipath-2.0.64.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
97
+ uipath-2.0.64.dist-info/RECORD,,