uipath 2.0.13__tar.gz → 2.0.14__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.
- {uipath-2.0.13 → uipath-2.0.14}/PKG-INFO +1 -1
- {uipath-2.0.13 → uipath-2.0.14}/pyproject.toml +1 -1
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/cli_run.py +2 -2
- uipath-2.0.14/src/uipath/tracing/__init__.py +3 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/tracing/_traced.py +116 -38
- uipath-2.0.14/tests/tracing/test_tracing_manager.py +165 -0
- {uipath-2.0.13 → uipath-2.0.14}/uv.lock +1509 -1509
- uipath-2.0.13/src/uipath/tracing/__init__.py +0 -3
- {uipath-2.0.13 → uipath-2.0.14}/.cursorrules +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.editorconfig +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.gitattributes +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.github/workflows/build.yml +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.github/workflows/cd.yml +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.github/workflows/ci.yml +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.github/workflows/commitlint.yml +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.github/workflows/lint.yml +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.github/workflows/test.yml +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.gitignore +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.pre-commit-config.yaml +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.python-version +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.vscode/extensions.json +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/.vscode/settings.json +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/CONTRIBUTING.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/LICENSE +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/README.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/CONTRIBUTING.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/actions.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/assets/uipath-logo.svg +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/assets.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/buckets.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/connections.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/context_grounding.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/getting_started_agent.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/getting_started_cli.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/getting_started_cloud.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/getting_started_sdk.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/index.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/jobs.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/processes.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/queues.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/docs/sdk.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/justfile +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/mkdocs.yml +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/py.typed +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/__init__.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/README.md +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/__init__.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_auth/_auth_server.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_auth/_models.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_auth/_oidc_utils.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_auth/_portal_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_auth/_utils.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_auth/auth_config.json +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_auth/index.html +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_auth/localhost.crt +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_auth/localhost.key +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_runtime/_contracts.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_runtime/_logging.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_runtime/_runtime.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_templates/.psmdcp.template +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_templates/.rels.template +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_templates/[Content_Types].xml.template +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_templates/main.py.template +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_templates/package.nuspec.template +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_utils/_common.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_utils/_input_args.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/_utils/_parse_ast.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/cli_auth.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/cli_deploy.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/cli_init.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/cli_new.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/cli_pack.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/cli_publish.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_cli/middlewares.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_config.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_execution_context.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_folder_context.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/__init__.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/_base_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/actions_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/api_client.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/assets_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/buckets_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/connections_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/connections_service.pyi +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/context_grounding_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/folder_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/jobs_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/llm_gateway_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/processes_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_services/queues_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_uipath.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_utils/__init__.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_utils/_endpoint.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_utils/_infer_bindings.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_utils/_logs.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_utils/_request_override.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_utils/_request_spec.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_utils/_user_agent.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/_utils/constants.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/__init__.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/action_schema.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/actions.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/assets.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/connections.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/context_grounding.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/context_grounding_index.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/exceptions.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/interrupt_models.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/job.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/llm_gateway.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/processes.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/models/queues.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/py.typed +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/tracing/_otel_exporters.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/src/uipath/tracing/_utils.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/tests/__init__.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/tests/cli/test_init.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/tests/conftest.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/tests/sdk/services/test_llm_integration.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/tests/sdk/services/test_llm_service.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/tests/sdk/services/test_uipath_llm_integration.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/tests/sdk/test_config.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/tests/tracing/test_otel_exporters.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/tests/tracing/test_span_utils.py +0 -0
- {uipath-2.0.13 → uipath-2.0.14}/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.
|
|
3
|
+
Version: 2.0.14
|
|
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.
|
|
3
|
+
version = "2.0.14"
|
|
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"
|
|
@@ -115,9 +115,9 @@ def run(entrypoint: Optional[str], input: Optional[str], resume: bool) -> None:
|
|
|
115
115
|
|
|
116
116
|
# Handle result from middleware
|
|
117
117
|
if result.error_message:
|
|
118
|
-
click.echo(result.error_message)
|
|
118
|
+
click.echo(result.error_message, err=True)
|
|
119
119
|
if result.should_include_stacktrace:
|
|
120
|
-
click.echo(traceback.format_exc())
|
|
120
|
+
click.echo(traceback.format_exc(), err=True)
|
|
121
121
|
click.get_current_context().exit(1)
|
|
122
122
|
|
|
123
123
|
if result.info_message:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import importlib
|
|
1
2
|
import inspect
|
|
2
3
|
import json
|
|
3
4
|
import logging
|
|
4
5
|
from functools import wraps
|
|
5
|
-
from typing import Any, Callable, Optional
|
|
6
|
+
from typing import Any, Callable, List, Optional, Tuple
|
|
6
7
|
|
|
7
8
|
from opentelemetry import trace
|
|
8
9
|
from opentelemetry.sdk.trace import TracerProvider
|
|
@@ -18,9 +19,94 @@ trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(LlmOpsHttpExpo
|
|
|
18
19
|
tracer = trace.get_tracer(__name__)
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
"""
|
|
23
|
-
|
|
22
|
+
class TracingManager:
|
|
23
|
+
"""Static utility class to manage tracing implementations and decorated functions."""
|
|
24
|
+
|
|
25
|
+
# Registry to track original functions, decorated functions, and their parameters
|
|
26
|
+
# Each entry is (original_func, decorated_func, params)
|
|
27
|
+
_traced_registry: List[Tuple[Callable[..., Any], Callable[..., Any], Any]] = []
|
|
28
|
+
|
|
29
|
+
# Custom tracer implementation
|
|
30
|
+
_custom_tracer_implementation = None
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def get_custom_tracer_implementation(cls):
|
|
34
|
+
"""Get the currently set custom tracer implementation."""
|
|
35
|
+
return cls._custom_tracer_implementation
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def register_traced_function(cls, original_func, decorated_func, params):
|
|
39
|
+
"""Register a function decorated with @traced and its parameters.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
original_func: The original function before decoration
|
|
43
|
+
decorated_func: The function after decoration
|
|
44
|
+
params: The parameters used for tracing
|
|
45
|
+
"""
|
|
46
|
+
cls._traced_registry.append((original_func, decorated_func, params))
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def reapply_traced_decorator(cls, tracer_implementation):
|
|
50
|
+
"""Reapply a different tracer implementation to all functions previously decorated with @traced.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
tracer_implementation: A function that takes the same parameters as _opentelemetry_traced
|
|
54
|
+
and returns a decorator
|
|
55
|
+
"""
|
|
56
|
+
cls._custom_tracer_implementation = tracer_implementation
|
|
57
|
+
|
|
58
|
+
# Work with a copy of the registry to avoid modifying it during iteration
|
|
59
|
+
registry_copy = cls._traced_registry.copy()
|
|
60
|
+
|
|
61
|
+
for original_func, decorated_func, params in registry_copy:
|
|
62
|
+
# Apply the new decorator with the same parameters
|
|
63
|
+
new_decorated_func = tracer_implementation(**params)(original_func)
|
|
64
|
+
|
|
65
|
+
logger.debug(
|
|
66
|
+
f"Reapplying decorator to {original_func.__name__}, from {decorated_func.__name__}"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# If this is a method on a class, we need to update the class
|
|
70
|
+
if hasattr(original_func, "__self__") and hasattr(
|
|
71
|
+
original_func, "__func__"
|
|
72
|
+
):
|
|
73
|
+
setattr(
|
|
74
|
+
original_func.__self__.__class__,
|
|
75
|
+
original_func.__name__,
|
|
76
|
+
new_decorated_func.__get__(
|
|
77
|
+
original_func.__self__, original_func.__self__.__class__
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
else:
|
|
81
|
+
# Replace the function in its module
|
|
82
|
+
if hasattr(original_func, "__module__") and hasattr(
|
|
83
|
+
original_func, "__qualname__"
|
|
84
|
+
):
|
|
85
|
+
try:
|
|
86
|
+
module = importlib.import_module(original_func.__module__)
|
|
87
|
+
parts = original_func.__qualname__.split(".")
|
|
88
|
+
|
|
89
|
+
# Handle nested objects
|
|
90
|
+
obj = module
|
|
91
|
+
for part in parts[:-1]:
|
|
92
|
+
obj = getattr(obj, part)
|
|
93
|
+
|
|
94
|
+
setattr(obj, parts[-1], new_decorated_func)
|
|
95
|
+
|
|
96
|
+
# Update the registry entry for this function
|
|
97
|
+
# Find the index and replace with updated entry
|
|
98
|
+
for i, (orig, _dec, _p) in enumerate(cls._traced_registry):
|
|
99
|
+
if orig is original_func:
|
|
100
|
+
cls._traced_registry[i] = (
|
|
101
|
+
original_func,
|
|
102
|
+
new_decorated_func,
|
|
103
|
+
params,
|
|
104
|
+
)
|
|
105
|
+
break
|
|
106
|
+
except (ImportError, AttributeError) as e:
|
|
107
|
+
# Log the error but continue processing other functions
|
|
108
|
+
logger.warning(f"Error reapplying decorator: {e}")
|
|
109
|
+
continue
|
|
24
110
|
|
|
25
111
|
|
|
26
112
|
def _default_input_processor(inputs):
|
|
@@ -33,23 +119,9 @@ def _default_output_processor(outputs):
|
|
|
33
119
|
return {"redacted": "Output data not logged for privacy/security"}
|
|
34
120
|
|
|
35
121
|
|
|
36
|
-
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
_decorators: dict[str, Any] = {}
|
|
40
|
-
_active_decorator = "opentelemetry"
|
|
41
|
-
|
|
42
|
-
@classmethod
|
|
43
|
-
def register_decorator(cls, name, decorator_factory):
|
|
44
|
-
"""Register a decorator factory function with a name."""
|
|
45
|
-
cls._decorators[name] = decorator_factory
|
|
46
|
-
cls._active_decorator = name
|
|
47
|
-
return cls
|
|
48
|
-
|
|
49
|
-
@classmethod
|
|
50
|
-
def get_decorator(cls):
|
|
51
|
-
"""Get the currently active decorator factory."""
|
|
52
|
-
return cls._decorators.get(cls._active_decorator)
|
|
122
|
+
def wait_for_tracers():
|
|
123
|
+
"""Wait for all tracers to finish."""
|
|
124
|
+
trace.get_tracer_provider().shutdown() # type: ignore
|
|
53
125
|
|
|
54
126
|
|
|
55
127
|
def _opentelemetry_traced(
|
|
@@ -58,6 +130,8 @@ def _opentelemetry_traced(
|
|
|
58
130
|
input_processor: Optional[Callable[..., Any]] = None,
|
|
59
131
|
output_processor: Optional[Callable[..., Any]] = None,
|
|
60
132
|
):
|
|
133
|
+
"""Default tracer implementation using OpenTelemetry."""
|
|
134
|
+
|
|
61
135
|
def decorator(func):
|
|
62
136
|
@wraps(func)
|
|
63
137
|
def sync_wrapper(*args, **kwargs):
|
|
@@ -78,9 +152,7 @@ def _opentelemetry_traced(
|
|
|
78
152
|
if input_processor is not None:
|
|
79
153
|
processed_inputs = input_processor(json.loads(inputs))
|
|
80
154
|
inputs = json.dumps(processed_inputs, default=str)
|
|
81
|
-
|
|
82
155
|
span.set_attribute("inputs", inputs)
|
|
83
|
-
|
|
84
156
|
try:
|
|
85
157
|
result = func(*args, **kwargs)
|
|
86
158
|
# Process output if processor is provided
|
|
@@ -115,9 +187,7 @@ def _opentelemetry_traced(
|
|
|
115
187
|
if input_processor is not None:
|
|
116
188
|
processed_inputs = input_processor(json.loads(inputs))
|
|
117
189
|
inputs = json.dumps(processed_inputs, default=str)
|
|
118
|
-
|
|
119
190
|
span.set_attribute("inputs", inputs)
|
|
120
|
-
|
|
121
191
|
try:
|
|
122
192
|
result = await func(*args, **kwargs)
|
|
123
193
|
# Process output if processor is provided
|
|
@@ -152,9 +222,7 @@ def _opentelemetry_traced(
|
|
|
152
222
|
if input_processor is not None:
|
|
153
223
|
processed_inputs = input_processor(json.loads(inputs))
|
|
154
224
|
inputs = json.dumps(processed_inputs, default=str)
|
|
155
|
-
|
|
156
225
|
span.set_attribute("inputs", inputs)
|
|
157
|
-
|
|
158
226
|
outputs = []
|
|
159
227
|
try:
|
|
160
228
|
for item in func(*args, **kwargs):
|
|
@@ -195,9 +263,7 @@ def _opentelemetry_traced(
|
|
|
195
263
|
if input_processor is not None:
|
|
196
264
|
processed_inputs = input_processor(json.loads(inputs))
|
|
197
265
|
inputs = json.dumps(processed_inputs, default=str)
|
|
198
|
-
|
|
199
266
|
span.set_attribute("inputs", inputs)
|
|
200
|
-
|
|
201
267
|
outputs = []
|
|
202
268
|
try:
|
|
203
269
|
async for item in func(*args, **kwargs):
|
|
@@ -254,16 +320,28 @@ def traced(
|
|
|
254
320
|
# Apply default processors selectively based on hide flags
|
|
255
321
|
if hide_input:
|
|
256
322
|
input_processor = _default_input_processor
|
|
257
|
-
|
|
258
323
|
if hide_output:
|
|
259
324
|
output_processor = _default_output_processor
|
|
260
325
|
|
|
261
|
-
|
|
326
|
+
# Store the parameters for later reapplication
|
|
327
|
+
params = {
|
|
328
|
+
"run_type": run_type,
|
|
329
|
+
"span_type": span_type,
|
|
330
|
+
"input_processor": input_processor,
|
|
331
|
+
"output_processor": output_processor,
|
|
332
|
+
}
|
|
262
333
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
334
|
+
# Check for custom implementation first
|
|
335
|
+
custom_implementation = TracingManager.get_custom_tracer_implementation()
|
|
336
|
+
tracer_impl: Any = (
|
|
337
|
+
custom_implementation if custom_implementation else _opentelemetry_traced
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
def decorator(func):
|
|
341
|
+
# Decorate the function
|
|
342
|
+
decorated_func = tracer_impl(**params)(func)
|
|
343
|
+
# Register both original and decorated function with parameters
|
|
344
|
+
TracingManager.register_traced_function(func, decorated_func, params)
|
|
345
|
+
return decorated_func
|
|
346
|
+
|
|
347
|
+
return decorator
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
|
|
3
|
+
from uipath.tracing._traced import TracingManager, traced
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Custom wrapper that does nothing
|
|
7
|
+
def donothing_custom_tracer(**kwargs):
|
|
8
|
+
def decorator(func):
|
|
9
|
+
@wraps(func)
|
|
10
|
+
def wrapper(*args, **kwargs):
|
|
11
|
+
# Simple implementation that just adds a marker to the result
|
|
12
|
+
result = func(*args, **kwargs)
|
|
13
|
+
return result
|
|
14
|
+
|
|
15
|
+
return wrapper
|
|
16
|
+
|
|
17
|
+
return decorator
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Helper function for testing custom tracer
|
|
21
|
+
def simple_custom_tracer(**kwargs):
|
|
22
|
+
def decorator(func):
|
|
23
|
+
@wraps(func)
|
|
24
|
+
def wrapper(*args, **kwargs):
|
|
25
|
+
# Simple implementation that just adds a marker to the result
|
|
26
|
+
result = func(*args, **kwargs)
|
|
27
|
+
if isinstance(result, dict):
|
|
28
|
+
result["custom_tracer_used"] = True
|
|
29
|
+
return result
|
|
30
|
+
|
|
31
|
+
return wrapper
|
|
32
|
+
|
|
33
|
+
return decorator
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Helper function for testing custom tracer with method
|
|
37
|
+
def custom_method_tracer(**kwargs):
|
|
38
|
+
def decorator(func):
|
|
39
|
+
@wraps(func)
|
|
40
|
+
def wrapper(*args, **kwargs):
|
|
41
|
+
result = func(*args, **kwargs)
|
|
42
|
+
if isinstance(result, dict):
|
|
43
|
+
result["custom_method_tracer_used"] = True
|
|
44
|
+
return result
|
|
45
|
+
|
|
46
|
+
return wrapper
|
|
47
|
+
|
|
48
|
+
return decorator
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# Helper function for testing with counter
|
|
52
|
+
def custom_tracer_with_counter(call_counter, **kwargs):
|
|
53
|
+
def decorator(func):
|
|
54
|
+
@wraps(func)
|
|
55
|
+
def wrapper(*args, **kwargs):
|
|
56
|
+
call_counter["count"] += 1
|
|
57
|
+
result = func(*args, **kwargs)
|
|
58
|
+
if isinstance(result, dict):
|
|
59
|
+
result["custom_tracer_id"] = call_counter["count"]
|
|
60
|
+
return result
|
|
61
|
+
|
|
62
|
+
return wrapper
|
|
63
|
+
|
|
64
|
+
return decorator
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Define the test classes
|
|
68
|
+
class TestClassForMethodTest:
|
|
69
|
+
@traced()
|
|
70
|
+
def sample_method(self, x, y):
|
|
71
|
+
return {"product": x * y}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# Module level functions for function test
|
|
75
|
+
@traced()
|
|
76
|
+
def func1_for_test(x):
|
|
77
|
+
return {"result": x * 2}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@traced()
|
|
81
|
+
def func2_for_test(x):
|
|
82
|
+
return {"result": x * 3}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# Define a function with @traced
|
|
86
|
+
@traced()
|
|
87
|
+
def sample_function():
|
|
88
|
+
return {"status": "success"}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_tracing_manager_custom_implementation():
|
|
92
|
+
"""Test setting and getting a custom tracer implementation."""
|
|
93
|
+
# Set the custom implementation
|
|
94
|
+
TracingManager.reapply_traced_decorator(simple_custom_tracer)
|
|
95
|
+
|
|
96
|
+
# Get the implementation and verify it's the same one
|
|
97
|
+
impl = TracingManager.get_custom_tracer_implementation()
|
|
98
|
+
assert impl is simple_custom_tracer
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_traced_with_custom_implementation():
|
|
102
|
+
"""Test that @traced uses a custom implementation when provided."""
|
|
103
|
+
# Set the custom implementation
|
|
104
|
+
TracingManager.reapply_traced_decorator(simple_custom_tracer)
|
|
105
|
+
|
|
106
|
+
# Call the function and verify the custom implementation was used
|
|
107
|
+
result = sample_function()
|
|
108
|
+
assert "custom_tracer_used" in result
|
|
109
|
+
assert result["custom_tracer_used"] is True
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_reapply_traced_decorator_to_class_method():
|
|
113
|
+
"""Test reapply_traced_decorator with class methods."""
|
|
114
|
+
TracingManager.reapply_traced_decorator(donothing_custom_tracer)
|
|
115
|
+
|
|
116
|
+
# Create instance and call with default implementation
|
|
117
|
+
instance = TestClassForMethodTest()
|
|
118
|
+
result1 = instance.sample_method(2, 3)
|
|
119
|
+
assert result1 == {"product": 6}
|
|
120
|
+
|
|
121
|
+
# Apply our custom implementation
|
|
122
|
+
TracingManager.reapply_traced_decorator(custom_method_tracer)
|
|
123
|
+
|
|
124
|
+
# Create a NEW instance which will use the updated class method
|
|
125
|
+
new_instance = TestClassForMethodTest()
|
|
126
|
+
result2 = new_instance.sample_method(2, 3)
|
|
127
|
+
|
|
128
|
+
# Verify the result
|
|
129
|
+
assert "product" in result2
|
|
130
|
+
assert result2["product"] == 6
|
|
131
|
+
assert "custom_method_tracer_used" in result2
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_reapply_to_module_level_functions():
|
|
135
|
+
"""Test reapply_traced_decorator with module level functions."""
|
|
136
|
+
|
|
137
|
+
TracingManager.reapply_traced_decorator(donothing_custom_tracer)
|
|
138
|
+
|
|
139
|
+
# First call with default implementation
|
|
140
|
+
assert func1_for_test(5) == {"result": 10}
|
|
141
|
+
assert func2_for_test(5) == {"result": 15}
|
|
142
|
+
|
|
143
|
+
# Counter to track custom tracer calls
|
|
144
|
+
call_counter = {"count": 0}
|
|
145
|
+
|
|
146
|
+
# Reapply with the custom implementation
|
|
147
|
+
TracingManager.reapply_traced_decorator(
|
|
148
|
+
lambda **kwargs: custom_tracer_with_counter(call_counter, **kwargs)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Call the functions directly - they should now use the updated implementation
|
|
152
|
+
result1 = func1_for_test(5)
|
|
153
|
+
result2 = func2_for_test(5)
|
|
154
|
+
|
|
155
|
+
# Verify the custom implementation was applied
|
|
156
|
+
assert "result" in result1
|
|
157
|
+
assert result1["result"] == 10
|
|
158
|
+
assert "custom_tracer_id" in result1
|
|
159
|
+
|
|
160
|
+
assert "result" in result2
|
|
161
|
+
assert result2["result"] == 15
|
|
162
|
+
assert "custom_tracer_id" in result2
|
|
163
|
+
|
|
164
|
+
# Verify both functions were processed
|
|
165
|
+
assert call_counter["count"] == 2
|