8000 Remove placeholders · AdrienVannson/python-betterproto@7138ff8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7138ff8

Browse files
committed
Remove placeholders
1 parent c44b4ac commit 7138ff8

File tree

1 file changed

+50
-109
lines changed

1 file changed

+50
-109
lines changed

src/betterproto/__init__.py

Lines changed: 50 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -169,24 +169,6 @@ class Casing(builtin_enum.Enum):
169169
SNAKE = snake_case #: A snake_case sterilization function.
170170

171171

172-
class Placeholder:
173-
__slots__ = ()
174-
175-
def __repr__(self) -> str:
176-
return "<PLACEHOLDER>"
177-
178-
def __copy__(self) -> Self:
179-
return self
180-
181-
def __deepcopy__(self, _) -> Self:
182-
return self
183-
184-
185-
# We can't simply use object() here because pydantic automatically performs deep-copy of mutable default values
186-
# See #606
187-
PLACEHOLDER: Any = Placeholder()
188-
189-
190172
@dataclasses.dataclass(frozen=True)
191173
class FieldMetadata:
192174
"""Stores internal metadata used for parsing & serialization."""
@@ -213,6 +195,7 @@ def get(field: dataclasses.Field) -> "FieldMetadata":
213195
def dataclass_field(
214196
number: int,
215197
proto_type: str,
198+
default_factory: Callable[[], Any],
216199
*,
217200
map_types: Optional[Tuple[str, str]] = None,
218201
group: Optional[str] = None,
@@ -221,8 +204,15 @@ def dataclass_field(
221204
repeated: bool = False,
222205
) -> dataclasses.Field:
223206
"""Creates a dataclass field with attached protobuf metadata."""
207+
if optional:
208+
def default_factory():
209+
return None
210+
elif repeated:
211+
def default_factory():
212+
return []
213+
224214
return dataclasses.field(
225-
default=None if optional else PLACEHOLDER, # type: ignore
215+
default_factory=default_factory,
226216
metadata={
227217
"betterproto": FieldMetadata(
228218
number, proto_type, map_types, group, wraps, optional
@@ -236,96 +226,96 @@ def dataclass_field(
236226
# out at runtime. The generated dataclass variables are still typed correctly.
237227

238228

239-
def enum_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,) -> Any:
240-
return dataclass_field(number, TYPE_ENUM, group=group, optional=optional, repeated=repeated)
229+
def enum_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any:
230+
return dataclass_field(number, TYPE_ENUM, lambda: 0, optional=optional, repeated=repeated)
241231

242232

243-
def bool_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,) -> Any:
244-
return dataclass_field(number, TYPE_BOOL, group=group, optional=optional, repeated=repeated)
233+
def bool_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any:
234+
return dataclass_field(number, TYPE_BOOL, lambda: False, group=group, optional=optional, repeated=repeated)
245235

246236

247237
def int32_field(
248238
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
249239
) -> Any:
250-
return dataclass_field(number, TYPE_INT32, group=group, optional=optional, repeated=repeated)
240+
return dataclass_field(number, TYPE_INT32, lambda: 0, group=group, optional=optional, repeated=repeated)
251241

252242

253243
def int64_field(
254244
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
255245
) -> Any:
256-
return dataclass_field(number, TYPE_INT64, group=group, optional=optional, repeated=repeated)
246+
return dataclass_field(number, TYPE_INT64, lambda: 0, group=group, optional=optional, repeated=repeated)
257247

258248

259249
def uint32_field(
260250
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
261251
) -> Any:
262-
return dataclass_field(number, TYPE_UINT32, group=group, optional=optional, repeated=repeated)
252+
return dataclass_field(number, TYPE_UINT32, lambda: 0, group=group, optional=optional, repeated=repeated)
263253

264254

265255
def uint64_field(
266256
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
267257
) -> Any:
268-
return dataclass_field(number, TYPE_UINT64, group=group, optional=optional, repeated=repeated)
258+
return dataclass_field(number, TYPE_UINT64, lambda: 0, group=group, optional=optional, repeated=repeated)
269259

270260

271261
def sint32_field(
272262
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
273263
) -> Any:
274-
return dataclass_field(number, TYPE_SINT32, group=group, optional=optional, repeated=repeated)
264+
return dataclass_field(number, TYPE_SINT32, lambda: 0, group=group, optional=optional, repeated=repeated)
275265

276266

277267
def sint64_field(
278268
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
279269
) -> Any:
280-
return dataclass_field(number, TYPE_SINT64, group=group, optional=optional, repeated=repeated)
270+
return dataclass_field(number, TYPE_SINT64, lambda: 0, group=group, optional=optional, repeated=repeated)
281271

282272

283273
def float_field(
284274
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
285275
) -> Any:
286-
return dataclass_field(number, TYPE_FLOAT, group=group, optional=optional, repeated=repeated)
276+
return dataclass_field(number, TYPE_FLOAT, lambda: 0., group=group, optional=optional, repeated=repeated)
287277

288278

289279
def double_field(
290280
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
291281
) -> Any:
292-
return dataclass_field(number, TYPE_DOUBLE, group=group, optional=optional, repeated=repeated)
282+
return dataclass_field(number, TYPE_DOUBLE, lambda: 0., group=group, optional=optional, repeated=repeated)
293283

294284

295285
def fixed32_field(
296286
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
297287
) -> Any:
298-
return dataclass_field(number, TYPE_FIXED32, group=group, optional=optional, repeated=repeated)
288+
return dataclass_field(number, TYPE_FIXED32, lambda: 0., group=group, optional=optional, repeated=repeated)
299289

300290

301291
def fixed64_field(
302292
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
303293
) -> Any:
304-
return dataclass_field(number, TYPE_FIXED64, group=group, optional=optional, repeated=repeated)
294+
return dataclass_field(number, TYPE_FIXED64, lambda: 0., group=group, optional=optional, repeated=repeated)
305295

306296

307297
def sfixed32_field(
308298
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
309299
) -> Any:
310-
return dataclass_field(number, TYPE_SFIXED32, group=group, optional=optional, repeated=repeated)
300+
return dataclass_field(number, TYPE_SFIXED32, lambda: 0., group=group, optional=optional, repeated=repeated)
311301

312302

313303
def sfixed64_field(
314304
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
315305
) -> Any:
316-
return dataclass_field(number, TYPE_SFIXED64, group=group, optional=optional, repeated=repeated)
306+
return dataclass_field(number, TYPE_SFIXED64, lambda: 0., group=group, optional=optional, repeated=repeated)
317307

318308

319309
def string_field(
320310
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
321311
) -> Any:
322-
return dataclass_field(number, TYPE_STRING, group=group, optional=optional, repeated=repeated)
312+
return dataclass_field(number, TYPE_STRING, lambda: "", group=group, optional=optional, repeated=repeated)
323313

324314

325315
def bytes_field(
326316
number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,
327317
) -> Any:
328-
return dataclass_field(number, TYPE_BYTES, group=group, optional=optional, repeated=repeated)
318+
return dataclass_field(number, TYPE_BYTES, lambda: b"", group=group, optional=optional, repeated=repeated)
329319

330320

331321
def message_field(
@@ -336,15 +326,15 @@ def message_field(
336326
repeated: bool = False,
337327
) -> Any:
338328
return dataclass_field(
339-
number, TYPE_MESSAGE, group=group, wraps=wraps, optional=optional
329+
number, TYPE_MESSAGE, lambda: None, group=group, wraps=wraps, optional=optional, repeated=repeated
340330
)
341331

342332

343333
def map_field(
344334
number: int, key_type: str, value_type: str, group: Optional[str] = None
345335
) -> Any:
346336
return dataclass_field(
347-
number, TYPE_MAP, map_types=(key_type, value_type), group=group
337+
number, TYPE_MAP, lambda: dict(), map_types=(key_type, value_type), group=group
348338
)
349339

350340

@@ -729,8 +719,8 @@ def _get_cls_by_field(
729719
field_cls[field.name] = dataclasses.make_dataclass(
730720
"Entry",
731721
[
732-
("key", kt, dataclass_field(1, meta.map_types[0])),
733-
("value", vt, dataclass_field(2, meta.map_types[1])),
722+
("key", kt, dataclass_field(1, meta.map_types[0], default_factory=lambda: kt())),
723+
("value", vt, dataclass_field(2, meta.map_types[1], default_factory=lambda: vt())),
734724
],
735725
bases=(Message,),
736726
)
@@ -764,26 +754,27 @@ class Message(ABC):
764754
_betterproto_meta: ClassVar[ProtoClassMetadata]
765755

766756
def __post_init__(self) -> None:
767-
# Keep track of whether every field was default
768-
all_sentinel = True
757+
# # Keep track of whether every field was default
758+
# all_sentinel = True
769759

770760
# Set current field of each group after `__init__` has already been run.
771761
group_current: Dict[str, Optional[str]] = {}
772762
for field_name, meta in self._betterproto.meta_by_field_name.items():
773763
if meta.group:
774764
group_current.setdefault(meta.group)
775765

776-
value = self.__raw_get(field_name)
777-
if value is not PLACEHOLDER and not (meta.optional and value is None):
778-
# Found a non-sentinel value
779-
all_sentinel = False
766+
# value = self.__raw_get(field_name)
767+
# if value is not PLACEHOLDER and not (meta.optional and value is None):
768+
# # Found a non-sentinel value
769+
# all_sentinel = False
780770

781-
if meta.group:
782-
# This was set, so make it the selected value of the one-of.
783-
group_current[meta.group] = field_name
771+
# if meta.group:
772+
# # This was set, so make it the selected value of the one-of.
773+
# group_current[meta.group] = field_name
784774

785775
# Now that all the defaults are set, reset it!
786-
self.__dict__["_serialized_on_wire"] = not all_sentinel
776+
# self.__dict__["_serialized_on_wire"] = not all_sentinel
777+
self.__dict__["_serialized_on_wire"] = False
787778
self.__dict__["_unknown_fields"] = b""
788779
self.__dict__["_group_current"] = group_current
789780

@@ -797,12 +788,6 @@ def __eq__(self, other) -> bool:
797788
for field_name in self._betterproto.meta_by_field_name:
798789
self_val = self.__raw_get(field_name)
799790
other_val = other.__raw_get(field_name)
800-
if self_val is PLACEHOLDER:
801-
if other_val is PLACEHOLDER:
802-
continue
803-
self_val = self._get_field_default(field_name)
804-
elif other_val is PLACEHOLDER:
805-
other_val = other._get_field_default(field_name)
806791

807792
if self_val != other_val:
808793
# We consider two nan values to be the same for the
@@ -825,48 +810,12 @@ def __repr__(self) -> str:
825810
f"{field_name}={value!r}"
826811
for field_name in self._betterproto.sorted_field_names
827812
for value in (self.__raw_get(field_name),)
828-
if value is not PLACEHOLDER
829813
]
830814
return f"{self.__class__.__name__}({', '.join(parts)})"
831815

832-
def __rich_repr__(self) -> Iterable[Tuple[str, Any, Any]]:
833-
for field_name in self._betterproto.sorted_field_names:
834-
yield field_name, self.__raw_get(field_name), PLACEHOLDER
835-
836-
if not TYPE_CHECKING:
837-
838-
def __getattribute__(self, name: str) -> Any:
839-
"""
840-
Lazily initialize default values to avoid infinite recursion for recursive
841-
message types.
842-
Raise :class:`AttributeError` on attempts to access unset ``oneof`` fields.
843-
"""
844-
try:
845-
group_current = super().__getattribute__("_group_current")
846-
except AttributeError:
847-
pass
848-
else:
849-
if name not in {"__class__", "_betterproto"}:
850-
group = self._betterproto.oneof_group_by_field.get(name)
851-
if group is not None and group_current[group] != name:
852-
if sys.version_info < (3, 10):
853-
raise AttributeError(
854-
f"{group!r} is set to {group_current[group]!r}, not {name!r}"
855-
)
856-
else:
857-
raise AttributeError(
858-
f"{group!r} is set to {group_current[group]!r}, not {name!r}",
859-
name=name,
860-
obj=self,
861-
)
862-
863-
value = super().__getattribute__(name)
864-
if value is not PLACEHOLDER:
865-
return value
866-
867-
value = self._get_field_default(name)
868-
super().__setattr__(name, value)
869-
return value
816+
# def __rich_repr__(self) -> Iterable[Tuple[str, Any, Any]]:
817+
# for field_name in self._betterproto.sorted_field_names:
818+
# yield field_name, self.__raw_get(field_name), PLACEHOLDER
870819

871820
def __setattr__(self, attr: str, value: Any) -> None:
872821
if (
@@ -887,32 +836,29 @@ def __setattr__(self, attr: str, value: Any) -> None:
887836
if field.name == attr:
888837
self._group_current[group] = field.name
889838
else:
890-
super().__setattr__(field.name, PLACEHOLDER)
839+
super().__setattr__(field.name, None)
891840

892841
super().__setattr__(attr, value)
893842

894843
def __bool__(self) -> bool:
895844
"""True if the Message has any fields with non-default values."""
896845
return any(
897-
self.__raw_get(field_name)
898-
not in (PLACEHOLDER, self._get_field_default(field_name))
846+
self.__raw_get(field_name) != self._get_field_default(field_name)
899847
for field_name in self._betterproto.meta_by_field_name
900848
)
901849

902850
def __deepcopy__(self: T, _: Any = {}) -> T:
903851
kwargs = {}
904852
for name in self._betterproto.sorted_field_names:
905853
value = self.__raw_get(name)
906-
if value is not PLACEHOLDER:
907-
kwargs[name] = deepcopy(value)
854+
kwargs[name] = deepcopy(value)
908855
return self.__class__(**kwargs) # type: ignore
909856

910857
def __copy__(self: T, _: Any = {}) -> T:
911858
kwargs = {}
912859
for name in self._betterproto.sorted_field_names:
913860
value = self.__raw_get(name)
914-
if value is not PLACEHOLDER:
915-
kwargs[name] = value
861+
kwargs[name] = value
916862
return self.__class__(**kwargs) # type: ignore
917863

918864
@classproperty
@@ -1853,12 +1799,7 @@ def is_set(self, name: str) -> bool:
18531799
:class:`bool`
18541800
`True` if field has been set, otherwise `False`.
18551801
"""
1856-
default = (
1857-
PLACEHOLDER
1858-
if not self._betterproto.meta_by_field_name[name].optional
1859-
else None
1860-
)
1861-
return self.__raw_get(name) is not default
1802+
return self.__raw_get(name) is not self._get_field_default(name)
18621803

18631804
@classmethod
18641805
def _validate_field_groups(cls, values):

0 commit comments

Comments
 (0)
0