Skip to content

Commit ab4bed2

Browse files
committed
update to use inheritence for common JSON serialization/deserialization methods
1 parent 2bf60bc commit ab4bed2

14 files changed

Lines changed: 110 additions & 163 deletions

File tree

codegen/opentelemetry-codegen-json/src/opentelemetry/codegen/json/generator.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,10 +454,8 @@ def _generate_message_class(
454454
codec = self._get_codec_module_path()
455455
with writer.dataclass(
456456
msg_desc.name,
457-
decorators=(
458-
"typing.final",
459-
f"{codec}.json_serde",
460-
),
457+
bases=(f"{codec}.JsonMessage",),
458+
decorators=("typing.final",),
461459
decorator_name="_dataclass",
462460
):
463461
if msg_desc.field or msg_desc.nested_type or msg_desc.enum_type:

codegen/opentelemetry-codegen-json/src/opentelemetry/codegen/json/runtime/json_codec.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from __future__ import annotations
1616

17+
import abc
1718
import base64
1819
import json
1920
import math
@@ -22,29 +23,31 @@
2223
T = typing.TypeVar("T")
2324

2425

25-
def json_serde(cls: type[T]) -> type[T]:
26+
class JsonMessage(abc.ABC):
2627
"""
27-
A decorator that adds "to_json" and "from_json" methods to a class.
28+
Abstract base class for protobuf messages with JSON serialization.
29+
30+
Subclasses must implement ``to_dict`` and ``from_dict``.
31+
Provides ``to_json`` and ``from_json`` based on those methods.
2832
"""
2933

30-
def to_json(self: typing.Any) -> str:
31-
"""
32-
Serialize this message to a JSON string.
33-
"""
34-
# pylint: disable-next=no-member
35-
return json.dumps(self.to_dict()) # type: ignore
34+
@abc.abstractmethod
35+
def to_dict(self) -> dict[str, typing.Any]:
36+
"""Convert this message to a dictionary."""
37+
38+
@classmethod
39+
@abc.abstractmethod
40+
def from_dict(cls: type[T], data: dict[str, typing.Any]) -> T:
41+
"""Create an instance from a dictionary."""
42+
43+
def to_json(self) -> str:
44+
"""Serialize this message to a JSON string."""
45+
return json.dumps(self.to_dict())
3646

3747
@classmethod
38-
def from_json(cls_inner: type[T], data: typing.Union[str, bytes]) -> T:
39-
"""
40-
Deserialize from a JSON string or bytes.
41-
"""
42-
# pylint: disable-next=no-member
43-
return cls_inner.from_dict(json.loads(data)) # type: ignore
44-
45-
cls.to_json = to_json # type: ignore[attr-defined]
46-
cls.from_json = from_json # type: ignore[attr-defined]
47-
return cls
48+
def from_json(cls: type[T], data: typing.Union[str, bytes]) -> T:
49+
"""Deserialize from a JSON string or bytes."""
50+
return cls.from_dict(json.loads(data)) # type: ignore[return-value]
4851

4952

5053
def encode_hex(value: typing.Optional[bytes]) -> str:

opentelemetry-proto-json/src/opentelemetry/proto_json/_json_codec.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from __future__ import annotations
1616

17+
import abc
1718
import base64
1819
import json
1920
import math
@@ -22,30 +23,34 @@
2223
T = typing.TypeVar("T")
2324

2425

25-
def json_serde(cls: type[T]) -> type[T]:
26+
class JsonMessage(abc.ABC):
2627
"""
27-
A decorator that adds "to_json" and "from_json" methods to a class.
28+
Abstract base class for protobuf messages with JSON serialization.
29+
30+
Subclasses must implement ``to_dict`` and ``from_dict``.
31+
Provides ``to_json`` and ``from_json`` based on those methods.
2832
"""
2933

30-
def to_json(self: T) -> str:
31-
"""
32-
Serialize this message to a JSON string.
33-
"""
34-
return json.dumps(self.to_dict())
34+
@abc.abstractmethod
35+
def to_dict(self) -> dict[str, typing.Any]:
36+
"""Convert this message to a dictionary."""
3537

3638
@classmethod
37-
def from_json(cls_inner: type[T], data: typing.Union[str, bytes]) -> T:
38-
"""
39-
Deserialize from a JSON string or bytes.
40-
"""
41-
return cls_inner.from_dict(json.loads(data))
39+
@abc.abstractmethod
40+
def from_dict(cls: type[T], data: dict[str, typing.Any]) -> T:
41+
"""Create an instance from a dictionary."""
4242

43-
cls.to_json = to_json # type: ignore[attr-defined]
44-
cls.from_json = from_json # type: ignore[attr-defined]
45-
return cls
43+
def to_json(self) -> str:
44+
"""Serialize this message to a JSON string."""
45+
return json.dumps(self.to_dict())
46+
47+
@classmethod
48+
def from_json(cls: type[T], data: typing.Union[str, bytes]) -> T:
49+
"""Deserialize from a JSON string or bytes."""
50+
return cls.from_dict(json.loads(data)) # type: ignore[return-value]
4651

4752

48-
def encode_hex(value: bytes) -> str:
53+
def encode_hex(value: typing.Optional[bytes]) -> str:
4954
"""
5055
Encode bytes as hex string.
5156
@@ -57,7 +62,7 @@ def encode_hex(value: bytes) -> str:
5762
return value.hex() if value else ""
5863

5964

60-
def encode_base64(value: bytes) -> str:
65+
def encode_base64(value: typing.Optional[bytes]) -> str:
6166
"""
6267
Encode bytes as base64 string.
6368
Standard Proto3 JSON mapping for bytes.
@@ -130,9 +135,9 @@ def decode_hex(value: typing.Optional[str], field_name: str) -> bytes:
130135
validate_type(value, str, field_name)
131136
try:
132137
return bytes.fromhex(value)
133-
except ValueError as e:
138+
except ValueError as error:
134139
raise ValueError(
135-
f"Invalid hex string for field '{field_name}': {e}"
140+
f"Invalid hex string for field '{field_name}': {error}"
136141
) from None
137142

138143

@@ -151,9 +156,9 @@ def decode_base64(value: typing.Optional[str], field_name: str) -> bytes:
151156
validate_type(value, str, field_name)
152157
try:
153158
return base64.b64decode(value)
154-
except Exception as e:
159+
except Exception as error:
155160
raise ValueError(
156-
f"Invalid base64 string for field '{field_name}': {e}"
161+
f"Invalid base64 string for field '{field_name}': {error}"
157162
) from None
158163

159164

opentelemetry-proto-json/src/opentelemetry/proto_json/collector/logs/v1/logs_service.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@
3333

3434

3535
@typing.final
36-
@opentelemetry.proto_json._json_codec.json_serde
3736
@_dataclass
38-
class ExportLogsServiceRequest:
37+
class ExportLogsServiceRequest(opentelemetry.proto_json._json_codec.JsonMessage):
3938
"""
4039
Generated from protobuf message ExportLogsServiceRequest
4140
"""
@@ -75,9 +74,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "ExportLogs
7574

7675

7776
@typing.final
78-
@opentelemetry.proto_json._json_codec.json_serde
7977
@_dataclass
80-
class ExportLogsServiceResponse:
78+
class ExportLogsServiceResponse(opentelemetry.proto_json._json_codec.JsonMessage):
8179
"""
8280
Generated from protobuf message ExportLogsServiceResponse
8381
"""
@@ -117,9 +115,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "ExportLogs
117115

118116

119117
@typing.final
120-
@opentelemetry.proto_json._json_codec.json_serde
121118
@_dataclass
122-
class ExportLogsPartialSuccess:
119+
class ExportLogsPartialSuccess(opentelemetry.proto_json._json_codec.JsonMessage):
123120
"""
124121
Generated from protobuf message ExportLogsPartialSuccess
125122
"""

opentelemetry-proto-json/src/opentelemetry/proto_json/collector/metrics/v1/metrics_service.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@
3333

3434

3535
@typing.final
36-
@opentelemetry.proto_json._json_codec.json_serde
3736
@_dataclass
38-
class ExportMetricsServiceRequest:
37+
class ExportMetricsServiceRequest(opentelemetry.proto_json._json_codec.JsonMessage):
3938
"""
4039
Generated from protobuf message ExportMetricsServiceRequest
4140
"""
@@ -75,9 +74,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "ExportMetr
7574

7675

7776
@typing.final
78-
@opentelemetry.proto_json._json_codec.json_serde
7977
@_dataclass
80-
class ExportMetricsServiceResponse:
78+
class ExportMetricsServiceResponse(opentelemetry.proto_json._json_codec.JsonMessage):
8179
"""
8280
Generated from protobuf message ExportMetricsServiceResponse
8381
"""
@@ -117,9 +115,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "ExportMetr
117115

118116

119117
@typing.final
120-
@opentelemetry.proto_json._json_codec.json_serde
121118
@_dataclass
122-
class ExportMetricsPartialSuccess:
119+
class ExportMetricsPartialSuccess(opentelemetry.proto_json._json_codec.JsonMessage):
123120
"""
124121
Generated from protobuf message ExportMetricsPartialSuccess
125122
"""

opentelemetry-proto-json/src/opentelemetry/proto_json/collector/profiles/v1development/profiles_service.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@
3333

3434

3535
@typing.final
36-
@opentelemetry.proto_json._json_codec.json_serde
3736
@_dataclass
38-
class ExportProfilesServiceRequest:
37+
class ExportProfilesServiceRequest(opentelemetry.proto_json._json_codec.JsonMessage):
3938
"""
4039
Generated from protobuf message ExportProfilesServiceRequest
4140
"""
@@ -80,9 +79,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "ExportProf
8079

8180

8281
@typing.final
83-
@opentelemetry.proto_json._json_codec.json_serde
8482
@_dataclass
85-
class ExportProfilesServiceResponse:
83+
class ExportProfilesServiceResponse(opentelemetry.proto_json._json_codec.JsonMessage):
8684
"""
8785
Generated from protobuf message ExportProfilesServiceResponse
8886
"""
@@ -122,9 +120,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "ExportProf
122120

123121

124122
@typing.final
125-
@opentelemetry.proto_json._json_codec.json_serde
126123
@_dataclass
127-
class ExportProfilesPartialSuccess:
124+
class ExportProfilesPartialSuccess(opentelemetry.proto_json._json_codec.JsonMessage):
128125
"""
129126
Generated from protobuf message ExportProfilesPartialSuccess
130127
"""

opentelemetry-proto-json/src/opentelemetry/proto_json/collector/trace/v1/trace_service.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@
3333

3434

3535
@typing.final
36-
@opentelemetry.proto_json._json_codec.json_serde
3736
@_dataclass
38-
class ExportTraceServiceRequest:
37+
class ExportTraceServiceRequest(opentelemetry.proto_json._json_codec.JsonMessage):
3938
"""
4039
Generated from protobuf message ExportTraceServiceRequest
4140
"""
@@ -75,9 +74,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "ExportTrac
7574

7675

7776
@typing.final
78-
@opentelemetry.proto_json._json_codec.json_serde
7977
@_dataclass
80-
class ExportTraceServiceResponse:
78+
class ExportTraceServiceResponse(opentelemetry.proto_json._json_codec.JsonMessage):
8179
"""
8280
Generated from protobuf message ExportTraceServiceResponse
8381
"""
@@ -117,9 +115,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "ExportTrac
117115

118116

119117
@typing.final
120-
@opentelemetry.proto_json._json_codec.json_serde
121118
@_dataclass
122-
class ExportTracePartialSuccess:
119+
class ExportTracePartialSuccess(opentelemetry.proto_json._json_codec.JsonMessage):
123120
"""
124121
Generated from protobuf message ExportTracePartialSuccess
125122
"""

opentelemetry-proto-json/src/opentelemetry/proto_json/common/v1/common.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@
3232

3333

3434
@typing.final
35-
@opentelemetry.proto_json._json_codec.json_serde
3635
@_dataclass
37-
class AnyValue:
36+
class AnyValue(opentelemetry.proto_json._json_codec.JsonMessage):
3837
"""
3938
Generated from protobuf message AnyValue
4039
"""
@@ -106,9 +105,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "AnyValue":
106105

107106

108107
@typing.final
109-
@opentelemetry.proto_json._json_codec.json_serde
110108
@_dataclass
111-
class ArrayValue:
109+
class ArrayValue(opentelemetry.proto_json._json_codec.JsonMessage):
112110
"""
113111
Generated from protobuf message ArrayValue
114112
"""
@@ -148,9 +146,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "ArrayValue
148146

149147

150148
@typing.final
151-
@opentelemetry.proto_json._json_codec.json_serde
152149
@_dataclass
153-
class KeyValueList:
150+
class KeyValueList(opentelemetry.proto_json._json_codec.JsonMessage):
154151
"""
155152
Generated from protobuf message KeyValueList
156153
"""
@@ -190,9 +187,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "KeyValueLi
190187

191188

192189
@typing.final
193-
@opentelemetry.proto_json._json_codec.json_serde
194190
@_dataclass
195-
class KeyValue:
191+
class KeyValue(opentelemetry.proto_json._json_codec.JsonMessage):
196192
"""
197193
Generated from protobuf message KeyValue
198194
"""
@@ -238,9 +234,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "KeyValue":
238234

239235

240236
@typing.final
241-
@opentelemetry.proto_json._json_codec.json_serde
242237
@_dataclass
243-
class InstrumentationScope:
238+
class InstrumentationScope(opentelemetry.proto_json._json_codec.JsonMessage):
244239
"""
245240
Generated from protobuf message InstrumentationScope
246241
"""
@@ -298,9 +293,8 @@ def from_dict(cls, data: builtins.dict[builtins.str, typing.Any]) -> "Instrument
298293

299294

300295
@typing.final
301-
@opentelemetry.proto_json._json_codec.json_serde
302296
@_dataclass
303-
class EntityRef:
297+
class EntityRef(opentelemetry.proto_json._json_codec.JsonMessage):
304298
"""
305299
Generated from protobuf message EntityRef
306300
"""

0 commit comments

Comments
 (0)