Skip to content
This repository was archived by the owner on Mar 4, 2026. It is now read-only.

Commit 057b70c

Browse files
committed
feat: simple serialization defaults
1 parent c88d5da commit 057b70c

5 files changed

Lines changed: 744 additions & 53 deletions

File tree

src/uipath/core/tracing/_utils.py

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,11 @@
33
import inspect
44
import json
55
from collections.abc import Callable
6-
from dataclasses import asdict, is_dataclass
7-
from datetime import datetime, timezone
8-
from enum import Enum
9-
from typing import Any, Mapping, Optional, cast
10-
from zoneinfo import ZoneInfo
6+
from typing import Any, Mapping, Optional
117

128
from opentelemetry.trace import Span
13-
from pydantic import BaseModel
9+
10+
from uipath.core.utils.serialization import simple_serialize_defaults
1411

1512

1613
def get_supported_params(
@@ -31,64 +28,19 @@ def get_supported_params(
3128
return supported
3229

3330

34-
def _simple_serialize_defaults(
35-
obj: Any,
36-
) -> dict[str, Any] | list[Any] | str | int | float | bool | None:
37-
# Handle Pydantic BaseModel instances
38-
if hasattr(obj, "model_dump") and not isinstance(obj, type):
39-
return obj.model_dump(exclude_none=True, mode="json")
40-
41-
# Handle classes - convert to schema representation
42-
if isinstance(obj, type) and issubclass(obj, BaseModel):
43-
return {
44-
"__class__": obj.__name__,
45-
"__module__": obj.__module__,
46-
"schema": obj.model_json_schema(),
47-
}
48-
if hasattr(obj, "dict") and not isinstance(obj, type):
49-
return obj.dict()
50-
if hasattr(obj, "to_dict") and not isinstance(obj, type):
51-
return obj.to_dict()
52-
53-
# Handle dataclasses
54-
if is_dataclass(obj) and not isinstance(obj, type):
55-
return asdict(obj)
56-
57-
# Handle enums
58-
if isinstance(obj, Enum):
59-
return _simple_serialize_defaults(obj.value)
60-
61-
if isinstance(obj, (set, tuple)):
62-
if hasattr(obj, "_asdict") and callable(obj._asdict): # pyright: ignore[reportAttributeAccessIssue]
63-
return cast(dict[str, Any], obj._asdict()) # pyright: ignore[reportAttributeAccessIssue]
64-
return list(obj)
65-
66-
if isinstance(obj, datetime):
67-
return obj.isoformat()
68-
69-
if isinstance(obj, (timezone, ZoneInfo)):
70-
return obj.tzname(None)
71-
72-
# Allow JSON-serializable primitives to pass through unchanged
73-
if obj is None or isinstance(obj, (bool, int, float, str)):
74-
return obj
75-
76-
return str(obj)
77-
78-
7931
def format_args_for_trace_json(
8032
signature: inspect.Signature, *args: Any, **kwargs: Any
8133
) -> str:
8234
"""Return a JSON string of inputs from the function signature."""
8335
result = format_args_for_trace(signature, *args, **kwargs)
84-
return json.dumps(result, default=_simple_serialize_defaults)
36+
return json.dumps(result, default=simple_serialize_defaults)
8537

8638

8739
def format_object_for_trace_json(
8840
input_object: Any,
8941
) -> str:
9042
"""Return a JSON string of inputs from the function signature."""
91-
return json.dumps(input_object, default=_simple_serialize_defaults)
43+
return json.dumps(input_object, default=simple_serialize_defaults)
9244

9345

9446
def format_args_for_trace(

src/uipath/core/utils/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""Utility functions for uipath.core."""
2+
3+
from .serialization import simple_serialize_defaults
4+
5+
__all__ = ["simple_serialize_defaults"]
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
"""Serialization utilities for converting Python objects to JSON-serializable formats."""
2+
3+
from dataclasses import asdict, is_dataclass
4+
from datetime import datetime, timezone
5+
from enum import Enum
6+
from typing import Any, cast
7+
from zoneinfo import ZoneInfo
8+
9+
from pydantic import BaseModel
10+
11+
12+
def simple_serialize_defaults(
13+
obj: Any,
14+
) -> dict[str, Any] | list[Any] | str | int | float | bool | None:
15+
"""Convert Python objects to JSON-serializable formats.
16+
17+
Handles common Python types that are not natively JSON-serializable:
18+
- Pydantic models (v1 and v2)
19+
- Dataclasses
20+
- Enums
21+
- Datetime objects
22+
- Timezone objects
23+
- Named tuples
24+
- Sets and tuples
25+
26+
This function is designed to be used as the `default` parameter in json.dumps():
27+
```python
28+
import json
29+
result = json.dumps(obj, default=simple_serialize_defaults)
30+
```
31+
32+
Args:
33+
obj: The object to serialize
34+
35+
Returns:
36+
A JSON-serializable representation of the object:
37+
- Pydantic models: dict from model_dump()
38+
- Dataclasses: dict from asdict()
39+
- Enums: the enum value (recursively serialized)
40+
- datetime: ISO format string
41+
- timezone/ZoneInfo: timezone name
42+
- sets/tuples: converted to lists
43+
- named tuples: converted to dict
44+
- Primitives (None, bool, int, float, str): returned unchanged
45+
- Other types: converted to string with str()
46+
47+
Examples:
48+
>>> from datetime import datetime
49+
>>> from pydantic import BaseModel
50+
>>>
51+
>>> class User(BaseModel):
52+
... name: str
53+
... created_at: datetime
54+
>>>
55+
>>> user = User(name="Alice", created_at=datetime.now())
56+
>>> import json
57+
>>> json.dumps(user, default=simple_serialize_defaults)
58+
'{"name": "Alice", "created_at": "2024-01-01T12:00:00"}'
59+
"""
60+
# Handle Pydantic BaseModel instances
61+
if hasattr(obj, "model_dump") and not isinstance(obj, type):
62+
return obj.model_dump(exclude_none=True, mode="json")
63+
64+
# Handle Pydantic model classes - convert to schema representation
65+
if isinstance(obj, type) and issubclass(obj, BaseModel):
66+
return {
67+
"__class__": obj.__name__,
68+
"__module__": obj.__module__,
69+
"schema": obj.model_json_schema(),
70+
}
71+
72+
# Handle Pydantic v1 models
73+
if hasattr(obj, "dict") and not isinstance(obj, type):
74+
return obj.dict()
75+
76+
# Handle objects with to_dict method
77+
if hasattr(obj, "to_dict") and not isinstance(obj, type):
78+
return obj.to_dict()
79+
80+
# Handle dataclasses
81+
if is_dataclass(obj) and not isinstance(obj, type):
82+
return asdict(obj)
83+
84+
# Handle enums - recursively serialize the value
85+
if isinstance(obj, Enum):
86+
return simple_serialize_defaults(obj.value)
87+
88+
# Handle sets and tuples
89+
if isinstance(obj, (set, tuple)):
90+
# Check if it's a named tuple (has _asdict method)
91+
if hasattr(obj, "_asdict") and callable(
92+
obj._asdict # pyright: ignore[reportAttributeAccessIssue]
93+
):
94+
return cast(
95+
dict[str, Any],
96+
obj._asdict(), # pyright: ignore[reportAttributeAccessIssue]
97+
)
98+
# Convert to list
99+
return list(obj)
100+
101+
# Handle datetime objects
102+
if isinstance(obj, datetime):
103+
return obj.isoformat()
104+
105+
# Handle timezone objects
106+
if isinstance(obj, (timezone, ZoneInfo)):
107+
return obj.tzname(None)
108+
109+
# Allow JSON-serializable primitives to pass through unchanged
110+
if obj is None or isinstance(obj, (bool, int, float, str, list, dict)):
111+
return obj
112+
113+
# Fallback: convert to string
114+
return str(obj)

tests/utils/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Tests for uipath.core.utils."""

0 commit comments

Comments
 (0)