uipath 2.1.53__py3-none-any.whl → 2.1.55__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.
@@ -319,7 +319,7 @@ class UiPathRuntimeContext(BaseModel):
319
319
  chat_handler: Optional[UiPathConversationHandler] = None
320
320
  is_conversational: Optional[bool] = None
321
321
 
322
- model_config = {"arbitrary_types_allowed": True}
322
+ model_config = {"arbitrary_types_allowed": True, "extra": "allow"}
323
323
 
324
324
  @classmethod
325
325
  def with_defaults(cls: type[C], config_path: Optional[str] = None, **kwargs) -> C:
@@ -1,6 +1,7 @@
1
1
  import json
2
2
  import os
3
3
  from functools import wraps
4
+ from pathlib import PurePath
4
5
  from typing import Any, Callable, List, Optional, Union
5
6
 
6
7
  from pydantic import BaseModel, ConfigDict, Field, field_validator
@@ -103,7 +104,7 @@ class ProjectFolder(BaseModel):
103
104
  return v
104
105
 
105
106
 
106
- class ProjectStructure(BaseModel):
107
+ class ProjectStructure(ProjectFolder):
107
108
  """Model representing the complete file structure of a UiPath project.
108
109
 
109
110
  Attributes:
@@ -114,34 +115,7 @@ class ProjectStructure(BaseModel):
114
115
  folder_type: The type of the root folder (optional)
115
116
  """
116
117
 
117
- model_config = ConfigDict(
118
- validate_by_name=True,
119
- validate_by_alias=True,
120
- use_enum_values=True,
121
- arbitrary_types_allowed=True,
122
- extra="allow",
123
- )
124
-
125
- id: Optional[str] = Field(default=None, alias="id")
126
- name: Optional[str] = Field(default=None, alias="name")
127
- folders: List[ProjectFolder] = Field(default_factory=list)
128
- files: List[ProjectFile] = Field(default_factory=list)
129
- folder_type: Optional[str] = Field(default=None, alias="folderType")
130
-
131
- @field_validator("folder_type", mode="before")
132
- @classmethod
133
- def convert_folder_type(cls, v: Union[str, int, None]) -> Optional[str]:
134
- """Convert numeric folder type to string.
135
-
136
- Args:
137
- v: The value to convert
138
-
139
- Returns:
140
- Optional[str]: The converted value or None
141
- """
142
- if isinstance(v, int):
143
- return str(v)
144
- return v
118
+ pass
145
119
 
146
120
 
147
121
  class LockInfo(BaseModel):
@@ -174,6 +148,33 @@ def get_folder_by_name(
174
148
  return None
175
149
 
176
150
 
151
+ def resolve_path(
152
+ folder: ProjectFolder,
153
+ path: PurePath,
154
+ ) -> ProjectFile | ProjectFolder:
155
+ """Resolve a path relative to the folder.
156
+
157
+ Args:
158
+ folder: Project folder
159
+ path: Path relative to the folder
160
+
161
+ Returns: The resolved folder or file. If resolution fails, an assertion is raised.
162
+ """
163
+ root = path.parts
164
+ while len(root) > 1:
165
+ child = next(
166
+ (folder for folder in folder.folders if folder.name == root[0]), None
167
+ )
168
+ assert child, "Path not found."
169
+ folder = child
170
+ root = root[1:]
171
+ file = next((f for f in folder.files if f.name == root[0]), None)
172
+ child = next((folder for folder in folder.folders if folder.name == root[0]), None)
173
+ resolved = file or child
174
+ assert resolved, "Path not found."
175
+ return resolved
176
+
177
+
177
178
  class AddedResource(BaseModel):
178
179
  """Represents a new file to be added during a structural migration."""
179
180
 
uipath/tracing/_traced.py CHANGED
@@ -2,25 +2,28 @@ import importlib
2
2
  import inspect
3
3
  import json
4
4
  import logging
5
+ from contextvars import ContextVar
5
6
  from functools import wraps
6
7
  from typing import Any, Callable, List, Optional, Tuple
7
8
 
8
- from opentelemetry import trace
9
+ from opentelemetry import context, trace
10
+ from opentelemetry.trace import set_span_in_context
9
11
 
10
12
  from ._utils import _SpanUtils
11
13
 
12
14
  logger = logging.getLogger(__name__)
13
15
 
14
16
  _tracer_instance: Optional[trace.Tracer] = None
17
+ # ContextVar to track the currently active span for nesting
18
+ _active_traced_span: ContextVar[Optional[trace.Span]] = ContextVar(
19
+ "_active_traced_span", default=None
20
+ )
15
21
 
16
22
 
17
23
  def get_tracer() -> trace.Tracer:
18
24
  """Lazily initializes and returns the tracer instance."""
19
25
  global _tracer_instance
20
26
  if _tracer_instance is None:
21
- logger.warning(
22
- "Initializing tracer instance. This should only be done once per process."
23
- )
24
27
  _tracer_instance = trace.get_tracer(__name__)
25
28
  return _tracer_instance
26
29
 
@@ -53,24 +56,24 @@ class TracingManager:
53
56
  """
54
57
  cls._current_span_provider = current_span_provider
55
58
 
56
- @classmethod
57
- def get_parent_context(cls):
58
- """Get the parent context using the registered current span provider.
59
+ @staticmethod
60
+ def get_parent_context():
61
+ # Always use the currently active OTel span if valid (recursion / children)
62
+ current_span = trace.get_current_span()
63
+ if current_span is not None and current_span.get_span_context().is_valid:
64
+ return set_span_in_context(current_span)
59
65
 
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:
66
+ # Only for the very top-level call, fallback to LangGraph span
67
+ if TracingManager._current_span_provider is not None:
64
68
  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)
69
+ external_span = TracingManager._current_span_provider()
70
+ if external_span is not None:
71
+ return set_span_in_context(external_span)
70
72
  except Exception as e:
71
73
  logger.warning(f"Error getting current span from provider: {e}")
72
- return None
73
- return None
74
+
75
+ # Last fallback
76
+ return context.get_current()
74
77
 
75
78
  @classmethod
76
79
  def register_traced_function(cls, original_func, decorated_func, params):
@@ -176,176 +179,169 @@ def _opentelemetry_traced(
176
179
  """Default tracer implementation using OpenTelemetry."""
177
180
 
178
181
  def decorator(func):
179
- trace_name = name if name is not None else func.__name__
182
+ trace_name = name or func.__name__
183
+
184
+ def get_parent_context():
185
+ """Return a context object for starting the new span."""
186
+ current_span = _active_traced_span.get()
187
+ if current_span is not None and current_span.get_span_context().is_valid:
188
+ return set_span_in_context(current_span)
180
189
 
190
+ if TracingManager._current_span_provider is not None:
191
+ try:
192
+ external_span = TracingManager._current_span_provider()
193
+ if external_span is not None:
194
+ return set_span_in_context(external_span)
195
+ except Exception as e:
196
+ logger.warning(f"Error getting current span from provider: {e}")
197
+
198
+ return context.get_current()
199
+
200
+ # --------- Sync wrapper ---------
181
201
  @wraps(func)
182
202
  def sync_wrapper(*args, **kwargs):
183
- context = TracingManager.get_parent_context()
184
-
185
- with get_tracer().start_as_current_span(
186
- trace_name, context=context
187
- ) as span:
188
- default_span_type = "function_call_sync"
189
- span.set_attribute(
190
- "span_type",
191
- span_type if span_type is not None else default_span_type,
192
- )
203
+ ctx = get_parent_context()
204
+ span_cm = get_tracer().start_as_current_span(trace_name, context=ctx)
205
+ span = span_cm.__enter__()
206
+ token = _active_traced_span.set(span)
207
+ try:
208
+ span.set_attribute("span_type", span_type or "function_call_sync")
193
209
  if run_type is not None:
194
210
  span.set_attribute("run_type", run_type)
195
211
 
196
- # Format arguments for tracing
197
212
  inputs = _SpanUtils.format_args_for_trace_json(
198
213
  inspect.signature(func), *args, **kwargs
199
214
  )
200
- # Apply input processor if provided
201
- if input_processor is not None:
215
+ if input_processor:
202
216
  processed_inputs = input_processor(json.loads(inputs))
203
217
  inputs = json.dumps(processed_inputs, default=str)
204
218
  span.set_attribute("inputs", inputs)
205
- try:
206
- result = func(*args, **kwargs)
207
- # Process output if processor is provided
208
- output = result
209
- if output_processor is not None:
210
- output = output_processor(result)
211
- span.set_attribute("output", json.dumps(output, default=str))
212
- return result
213
- except Exception as e:
214
- span.record_exception(e)
215
- span.set_status(
216
- trace.status.Status(trace.status.StatusCode.ERROR, str(e))
217
- )
218
- raise
219
219
 
220
+ result = func(*args, **kwargs)
221
+ output = output_processor(result) if output_processor else result
222
+ span.set_attribute("output", json.dumps(output, default=str))
223
+ return result
224
+ except Exception as e:
225
+ span.record_exception(e)
226
+ span.set_status(
227
+ trace.status.Status(trace.status.StatusCode.ERROR, str(e))
228
+ )
229
+ raise
230
+ finally:
231
+ _active_traced_span.reset(token)
232
+ span_cm.__exit__(None, None, None)
233
+
234
+ # --------- Async wrapper ---------
220
235
  @wraps(func)
221
236
  async def async_wrapper(*args, **kwargs):
222
- context = TracingManager.get_parent_context()
223
-
224
- with get_tracer().start_as_current_span(
225
- trace_name, context=context
226
- ) as span:
227
- default_span_type = "function_call_async"
228
- span.set_attribute(
229
- "span_type",
230
- span_type if span_type is not None else default_span_type,
231
- )
237
+ ctx = get_parent_context()
238
+ span_cm = get_tracer().start_as_current_span(trace_name, context=ctx)
239
+ span = span_cm.__enter__()
240
+ token = _active_traced_span.set(span)
241
+ try:
242
+ span.set_attribute("span_type", span_type or "function_call_async")
232
243
  if run_type is not None:
233
244
  span.set_attribute("run_type", run_type)
234
245
 
235
- # Format arguments for tracing
236
246
  inputs = _SpanUtils.format_args_for_trace_json(
237
247
  inspect.signature(func), *args, **kwargs
238
248
  )
239
- # Apply input processor if provided
240
- if input_processor is not None:
249
+ if input_processor:
241
250
  processed_inputs = input_processor(json.loads(inputs))
242
251
  inputs = json.dumps(processed_inputs, default=str)
243
252
  span.set_attribute("inputs", inputs)
244
- try:
245
- result = await func(*args, **kwargs)
246
- # Process output if processor is provided
247
- output = result
248
- if output_processor is not None:
249
- output = output_processor(result)
250
- span.set_attribute("output", json.dumps(output, default=str))
251
- return result
252
- except Exception as e:
253
- span.record_exception(e)
254
- span.set_status(
255
- trace.status.Status(trace.status.StatusCode.ERROR, str(e))
256
- )
257
- raise
258
253
 
254
+ result = await func(*args, **kwargs)
255
+ output = output_processor(result) if output_processor else result
256
+ span.set_attribute("output", json.dumps(output, default=str))
257
+ return result
258
+ except Exception as e:
259
+ span.record_exception(e)
260
+ span.set_status(
261
+ trace.status.Status(trace.status.StatusCode.ERROR, str(e))
262
+ )
263
+ raise
264
+ finally:
265
+ _active_traced_span.reset(token)
266
+ span_cm.__exit__(None, None, None)
267
+
268
+ # --------- Generator wrapper ---------
259
269
  @wraps(func)
260
270
  def generator_wrapper(*args, **kwargs):
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()
267
- default_span_type = "function_call_generator_sync"
271
+ ctx = get_parent_context()
272
+ span_cm = get_tracer().start_as_current_span(trace_name, context=ctx)
273
+ span = span_cm.__enter__()
274
+ token = _active_traced_span.set(span)
275
+ try:
268
276
  span.set_attribute(
269
- "span_type",
270
- span_type if span_type is not None else default_span_type,
277
+ "span_type", span_type or "function_call_generator_sync"
271
278
  )
272
279
  if run_type is not None:
273
280
  span.set_attribute("run_type", run_type)
274
281
 
275
- # Format arguments for tracing
276
282
  inputs = _SpanUtils.format_args_for_trace_json(
277
283
  inspect.signature(func), *args, **kwargs
278
284
  )
279
- # Apply input processor if provided
280
- if input_processor is not None:
285
+ if input_processor:
281
286
  processed_inputs = input_processor(json.loads(inputs))
282
287
  inputs = json.dumps(processed_inputs, default=str)
283
288
  span.set_attribute("inputs", inputs)
289
+
284
290
  outputs = []
285
- try:
286
- for item in func(*args, **kwargs):
287
- outputs.append(item)
288
- span.add_event(f"Yielded: {item}") # Add event for each yield
289
- yield item
290
-
291
- # Process output if processor is provided
292
- output_to_record = outputs
293
- if output_processor is not None:
294
- output_to_record = output_processor(outputs)
295
- span.set_attribute(
296
- "output", json.dumps(output_to_record, default=str)
297
- )
298
- except Exception as e:
299
- span.record_exception(e)
300
- span.set_status(
301
- trace.status.Status(trace.status.StatusCode.ERROR, str(e))
302
- )
303
- raise
291
+ for item in func(*args, **kwargs):
292
+ outputs.append(item)
293
+ span.add_event(f"Yielded: {item}")
294
+ yield item
295
+ output = output_processor(outputs) if output_processor else outputs
296
+ span.set_attribute("output", json.dumps(output, default=str))
297
+ except Exception as e:
298
+ span.record_exception(e)
299
+ span.set_status(
300
+ trace.status.Status(trace.status.StatusCode.ERROR, str(e))
301
+ )
302
+ raise
303
+ finally:
304
+ _active_traced_span.reset(token)
305
+ span_cm.__exit__(None, None, None)
304
306
 
307
+ # --------- Async generator wrapper ---------
305
308
  @wraps(func)
306
309
  async def async_generator_wrapper(*args, **kwargs):
307
- context = TracingManager.get_parent_context()
308
-
309
- with get_tracer().start_as_current_span(
310
- trace_name, context=context
311
- ) as span:
312
- default_span_type = "function_call_generator_async"
310
+ ctx = get_parent_context()
311
+ span_cm = get_tracer().start_as_current_span(trace_name, context=ctx)
312
+ span = span_cm.__enter__()
313
+ token = _active_traced_span.set(span)
314
+ try:
313
315
  span.set_attribute(
314
- "span_type",
315
- span_type if span_type is not None else default_span_type,
316
+ "span_type", span_type or "function_call_generator_async"
316
317
  )
317
318
  if run_type is not None:
318
319
  span.set_attribute("run_type", run_type)
319
320
 
320
- # Format arguments for tracing
321
321
  inputs = _SpanUtils.format_args_for_trace_json(
322
322
  inspect.signature(func), *args, **kwargs
323
323
  )
324
- # Apply input processor if provided
325
- if input_processor is not None:
324
+ if input_processor:
326
325
  processed_inputs = input_processor(json.loads(inputs))
327
326
  inputs = json.dumps(processed_inputs, default=str)
328
327
  span.set_attribute("inputs", inputs)
328
+
329
329
  outputs = []
330
- try:
331
- async for item in func(*args, **kwargs):
332
- outputs.append(item)
333
- span.add_event(f"Yielded: {item}") # Add event for each yield
334
- yield item
335
-
336
- # Process output if processor is provided
337
- output_to_record = outputs
338
- if output_processor is not None:
339
- output_to_record = output_processor(outputs)
340
- span.set_attribute(
341
- "output", json.dumps(output_to_record, default=str)
342
- )
343
- except Exception as e:
344
- span.record_exception(e)
345
- span.set_status(
346
- trace.status.Status(trace.status.StatusCode.ERROR, str(e))
347
- )
348
- raise
330
+ async for item in func(*args, **kwargs):
331
+ outputs.append(item)
332
+ span.add_event(f"Yielded: {item}")
333
+ yield item
334
+ output = output_processor(outputs) if output_processor else outputs
335
+ span.set_attribute("output", json.dumps(output, default=str))
336
+ except Exception as e:
337
+ span.record_exception(e)
338
+ span.set_status(
339
+ trace.status.Status(trace.status.StatusCode.ERROR, str(e))
340
+ )
341
+ raise
342
+ finally:
343
+ _active_traced_span.reset(token)
344
+ span_cm.__exit__(None, None, None)
349
345
 
350
346
  if inspect.iscoroutinefunction(func):
351
347
  return async_wrapper
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uipath
3
- Version: 2.1.53
3
+ Version: 2.1.55
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
@@ -50,7 +50,7 @@ uipath/_cli/_evals/_models/_evaluation_set.py,sha256=mwcTstHuyHd7ys_nLzgCNKBAsS4
50
50
  uipath/_cli/_evals/_models/_evaluator_base_params.py,sha256=lTYKOV66tcjW85KHTyOdtF1p1VDaBNemrMAvH8bFIFc,382
51
51
  uipath/_cli/_evals/_models/_output.py,sha256=TTQ0hhmD3dTkIbj_Ly_rDCGSnpZsHwdmCsl7FLdoZD0,2634
52
52
  uipath/_cli/_push/sw_file_handler.py,sha256=AX4TKM-q6CNGw3JyBW02M8ktPZuFMcAU9LN3Ii0Q2QI,18202
53
- uipath/_cli/_runtime/_contracts.py,sha256=FziI4E1GF-brOwkYSGEUvRAKhLJUQ_2ZwUMefynl944,28764
53
+ uipath/_cli/_runtime/_contracts.py,sha256=ZK572viY3Ydnip21rzmJ3R6F3cXpHVtDTuvwcEciy3I,28782
54
54
  uipath/_cli/_runtime/_escalation.py,sha256=x3vI98qsfRA-fL_tNkRVTFXioM5Gv2w0GFcXJJ5eQtg,7981
55
55
  uipath/_cli/_runtime/_hitl.py,sha256=VKbM021nVg1HEDnTfucSLJ0LsDn83CKyUtVzofS2qTU,11369
56
56
  uipath/_cli/_runtime/_logging.py,sha256=MGklGKPjYKjs7J5Jy9eplA9zCDsdtEbkZdCbTwgut_4,8311
@@ -71,7 +71,7 @@ uipath/_cli/_utils/_input_args.py,sha256=3LGNqVpJItvof75VGm-ZNTUMUH9-c7-YgleM5b2
71
71
  uipath/_cli/_utils/_parse_ast.py,sha256=8Iohz58s6bYQ7rgWtOTjrEInLJ-ETikmOMZzZdIY2Co,20072
72
72
  uipath/_cli/_utils/_processes.py,sha256=q7DfEKHISDWf3pngci5za_z0Pbnf_shWiYEcTOTCiyk,1855
73
73
  uipath/_cli/_utils/_project_files.py,sha256=sulh3xZhDDw_rBOrn_XSUfVSD6sUu47ZK4n_lF5BKkQ,13197
74
- uipath/_cli/_utils/_studio_project.py,sha256=HvzcpIIIA4hUIvMbId1dsAhmFLMuhnS2ZtyNdcpXJ8c,15422
74
+ uipath/_cli/_utils/_studio_project.py,sha256=4aoRFj5FazUPpPltfr3jvyjoLsUd4hyl9We4SAuKFh4,15376
75
75
  uipath/_cli/_utils/_tracing.py,sha256=2igb03j3EHjF_A406UhtCKkPfudVfFPjUq5tXUEG4oo,1541
76
76
  uipath/_cli/_utils/_uv_helpers.py,sha256=6SvoLnZPoKIxW0sjMvD1-ENV_HOXDYzH34GjBqwT138,3450
77
77
  uipath/_resources/AGENTS.md,sha256=YWhWuX9XIbyVhVT3PnPc4Of3_q6bsNJcuzYu3N8f_Ug,25850
@@ -144,12 +144,12 @@ uipath/telemetry/_constants.py,sha256=uRDuEZayBYtBA0tMx-2AS_D-oiVA7oKgp9zid9jNat
144
144
  uipath/telemetry/_track.py,sha256=G_Pyq8n8iMvoCWhUpWedlptXUSuUSbQBBzGxsh4DW9c,4654
145
145
  uipath/tracing/__init__.py,sha256=GKRINyWdHVrDsI-8mrZDLdf0oey6GHGlNZTOADK-kgc,224
146
146
  uipath/tracing/_otel_exporters.py,sha256=X7cnuGqvxGbACZuFD2XYTWXwIse8pokOEAjeTPE6DCQ,3158
147
- uipath/tracing/_traced.py,sha256=qeVDrds2OUnpdUIA0RhtF0kg2dlAZhyC1RRkI-qivTM,18528
147
+ uipath/tracing/_traced.py,sha256=CsuNMy67R5HCunuu84LnRNwcadNLhtHLMEawGaNsTYs,18435
148
148
  uipath/tracing/_utils.py,sha256=wJRELaPu69iY0AhV432Dk5QYf_N_ViRU4kAUG1BI1ew,10384
149
149
  uipath/utils/__init__.py,sha256=VD-KXFpF_oWexFg6zyiWMkxl2HM4hYJMIUDZ1UEtGx0,105
150
150
  uipath/utils/_endpoints_manager.py,sha256=iRTl5Q0XAm_YgcnMcJOXtj-8052sr6jpWuPNz6CgT0Q,8408
151
- uipath-2.1.53.dist-info/METADATA,sha256=QYSNjKWwpoLp7Vuc_HWzFplKDGJu_40CGdIhmf9SxFE,6482
152
- uipath-2.1.53.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
153
- uipath-2.1.53.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
154
- uipath-2.1.53.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
155
- uipath-2.1.53.dist-info/RECORD,,
151
+ uipath-2.1.55.dist-info/METADATA,sha256=0UGc_4eyMBFBfvxTpNmIMWXNvZHsXb71382nbXbWJ4w,6482
152
+ uipath-2.1.55.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
153
+ uipath-2.1.55.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
154
+ uipath-2.1.55.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
155
+ uipath-2.1.55.dist-info/RECORD,,