Skip to content

Commit c9cae12

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

14 files changed

Lines changed: 110 additions & 151 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 & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,46 @@
1414

1515
from __future__ import annotations
1616

17+
import abc
1718
import base64
1819
import json
1920
import math
2021
import typing
2122

2223
T = typing.TypeVar("T")
24+
M = typing.TypeVar("M", bound="JsonMessage")
2325

2426

25-
def json_serde(cls: type[T]) -> type[T]:
27+
class JsonMessage(abc.ABC):
2628
"""
27-
A decorator that adds "to_json" and "from_json" methods to a class.
29+
Abstract base class for protobuf messages with JSON serialization.
2830
"""
2931

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

3751
@classmethod
38-
def from_json(cls_inner: type[T], data: typing.Union[str, bytes]) -> T:
52+
def from_json(cls: type[M], data: typing.Union[str, bytes]) -> M:
3953
"""
4054
Deserialize from a JSON string or bytes.
4155
"""
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
56+
return cls.from_dict(json.loads(data))
4857

4958

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

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

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,38 +14,49 @@
1414

1515
from __future__ import annotations
1616

17+
import abc
1718
import base64
1819
import json
1920
import math
2021
import typing
2122

2223
T = typing.TypeVar("T")
24+
M = typing.TypeVar("M", bound="JsonMessage")
2325

2426

25-
def json_serde(cls: type[T]) -> type[T]:
27+
class JsonMessage(abc.ABC):
2628
"""
27-
A decorator that adds "to_json" and "from_json" methods to a class.
29+
Abstract base class for protobuf messages with JSON serialization.
2830
"""
2931

30-
def to_json(self: T) -> str:
32+
@abc.abstractmethod
33+
def to_dict(self) -> dict[str, typing.Any]:
34+
"""
35+
Convert this message to a dictionary.
36+
"""
37+
38+
@classmethod
39+
@abc.abstractmethod
40+
def from_dict(cls: type[M], data: dict[str, typing.Any]) -> M:
41+
"""
42+
Create an instance from a dictionary.
43+
"""
44+
45+
def to_json(self) -> str:
3146
"""
3247
Serialize this message to a JSON string.
3348
"""
3449
return json.dumps(self.to_dict())
3550

3651
@classmethod
37-
def from_json(cls_inner: type[T], data: typing.Union[str, bytes]) -> T:
52+
def from_json(cls: type[M], data: typing.Union[str, bytes]) -> M:
3853
"""
3954
Deserialize from a JSON string or bytes.
4055
"""
41-
return cls_inner.from_dict(json.loads(data))
42-
43-
cls.to_json = to_json # type: ignore[attr-defined]
44-
cls.from_json = from_json # type: ignore[attr-defined]
45-
return cls
56+
return cls.from_dict(json.loads(data))
4657

4758

48-
def encode_hex(value: bytes) -> str:
59+
def encode_hex(value: typing.Optional[bytes]) -> str:
4960
"""
5061
Encode bytes as hex string.
5162
@@ -57,7 +68,7 @@ def encode_hex(value: bytes) -> str:
5768
return value.hex() if value else ""
5869

5970

60-
def encode_base64(value: bytes) -> str:
71+
def encode_base64(value: typing.Optional[bytes]) -> str:
6172
"""
6273
Encode bytes as base64 string.
6374
Standard Proto3 JSON mapping for bytes.
@@ -130,9 +141,9 @@ def decode_hex(value: typing.Optional[str], field_name: str) -> bytes:
130141
validate_type(value, str, field_name)
131142
try:
132143
return bytes.fromhex(value)
133-
except ValueError as e:
144+
except ValueError as error:
134145
raise ValueError(
135-
f"Invalid hex string for field '{field_name}': {e}"
146+
f"Invalid hex string for field '{field_name}': {error}"
136147
) from None
137148

138149

@@ -151,9 +162,9 @@ def decode_base64(value: typing.Optional[str], field_name: str) -> bytes:
151162
validate_type(value, str, field_name)
152163
try:
153164
return base64.b64decode(value)
154-
except Exception as e:
165+
except Exception as error:
155166
raise ValueError(
156-
f"Invalid base64 string for field '{field_name}': {e}"
167+
f"Invalid base64 string for field '{field_name}': {error}"
157168
) from None
158169

159170

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)