Skip to content
This repository was archived by the owner on Jun 9, 2025. It is now read-only.

Commit 733420b

Browse files
committed
Change wrapping mechanism
1 parent 1fbc952 commit 733420b

File tree

3 files changed

+27
-19
lines changed

3 files changed

+27
-19
lines changed

src/betterproto2_compiler/compile/importing.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,6 @@ def get_type_reference(
8181
necessary. Unwraps well known type if required.
8282
"""
8383
if unwrap:
84-
if source_type in WRAPPER_TYPES:
85-
wrapped_type = type(WRAPPER_TYPES[source_type]().value)
86-
return f"{wrapped_type.__name__} | None"
87-
8884
if source_type == ".google.protobuf.Duration":
8985
return "datetime.timedelta"
9086

src/betterproto2_compiler/known_types/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from .any import Any
44
from .duration import Duration
5+
from .google_values import BoolValue, StringValue
56
from .timestamp import Timestamp
67

78
# For each (package, message name), lists the methods that should be added to the message definition.
@@ -11,4 +12,12 @@
1112
("google.protobuf", "Any"): [Any.pack, Any.unpack, Any.to_dict],
1213
("google.protobuf", "Timestamp"): [Timestamp.from_datetime, Timestamp.to_datetime, Timestamp.timestamp_to_json],
1314
("google.protobuf", "Duration"): [Duration.from_timedelta, Duration.to_timedelta, Duration.delta_to_json],
15+
("google.protobuf", "BoolValue"): [BoolValue.from_wrapped, BoolValue.to_wrapped],
16+
("google.protobuf", "StringValue"): [StringValue.from_wrapped, StringValue.to_wrapped],
17+
}
18+
19+
# A wrapped type is the type of a message that is automatically replaced by a known Python type.
20+
WRAPPED_TYPES: dict[tuple[str, str], str] = {
21+
("google.protobuf", "BoolValue"): "bool",
22+
("google.protobuf", "StringValue"): "str",
1423
}

src/betterproto2_compiler/plugin/models.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,12 @@
2626

2727
import builtins
2828
import inspect
29-
import re
3029
from collections.abc import Iterator
3130
from dataclasses import (
3231
dataclass,
3332
field,
3433
)
3534

36-
import betterproto2
3735
from betterproto2 import unwrap
3836

3937
from betterproto2_compiler.compile.importing import get_type_reference, parse_source_type_name
@@ -43,7 +41,7 @@
4341
pythonize_field_name,
4442
pythonize_method_name,
4543
)
46-
from betterproto2_compiler.known_types import KNOWN_METHODS
44+
from betterproto2_compiler.known_types import KNOWN_METHODS, WRAPPED_TYPES
4745
from betterproto2_compiler.lib.google.protobuf import (
4846
DescriptorProto,
4947
EnumDescriptorProto,
@@ -318,8 +316,15 @@ def get_field_string(self) -> str:
318316
@property
319317
def betterproto_field_args(self) -> list[str]:
320318
args = []
321-
if self.field_wraps:
322-
args.append(f"wraps={self.field_wraps}")
319+
320+
if self.proto_obj.type == FieldDescriptorProtoType.TYPE_MESSAGE:
321+
type_package, type_name = parse_source_type_name(self.proto_obj.type_name, self.output_file.parent_request)
322+
323+
if (type_package, type_name) in WRAPPED_TYPES:
324+
# Without the lambda function, the type is evaluated right away, which fails since the corresponding
325+
# import is placed at the end of the file to avoid circular imports.
326+
args.append(f"wrap=lambda: {self.py_type}")
327+
323328
if self.optional:
324329
args.append("optional=True")
325330
elif self.repeated:
@@ -338,16 +343,6 @@ def use_builtins(self) -> bool:
338343
self.py_type == self.py_name and self.py_name in dir(builtins)
339344
)
340345

341-
@property
342-
def field_wraps(self) -> str | None:
343-
"""Returns betterproto wrapped field type or None."""
344-
match_wrapper = re.match(r"\.google\.protobuf\.(.+)Value$", self.proto_obj.type_name)
345-
if match_wrapper:
346-
wrapped_type = "TYPE_" + match_wrapper.group(1).upper()
347-
if hasattr(betterproto2, wrapped_type):
348-
return f"betterproto2.{wrapped_type}"
349-
return None
350-
351346
@property
352347
def repeated(self) -> bool:
353348
return self.proto_obj.label == FieldDescriptorProtoLabel.LABEL_REPEATED
@@ -405,6 +400,14 @@ def py_type(self) -> str:
405400
@property
406401
def annotation(self) -> str:
407402
py_type = self.py_type
403+
404+
# Replace by the wrapping type if needed
405+
if self.proto_obj.type == FieldDescriptorProtoType.TYPE_MESSAGE:
406+
type_package, type_name = parse_source_type_name(self.proto_obj.type_name, self.output_file.parent_request)
407+
408+
if wrapped_type := WRAPPED_TYPES.get((type_package, type_name)):
409+
py_type = wrapped_type
410+
408411
if self.use_builtins:
409412
py_type = f"builtins.{py_type}"
410413
if self.repeated:

0 commit comments

Comments
 (0)