_message.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. # Copyright (c) 2025-2026 Buf Technologies, Inc.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from __future__ import annotations
  15. from copy import copy, deepcopy
  16. from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypeVar, overload
  17. from . import _native_message
  18. from ._descriptors import (
  19. DescField,
  20. DescFieldValueEnum,
  21. DescFieldValueList,
  22. DescFieldValueMap,
  23. DescFieldValueMessage,
  24. DescFieldValueScalar,
  25. DescFieldValueSingular,
  26. DescMessage,
  27. DescOneof,
  28. DescUnknownField,
  29. )
  30. from ._extension import Extension
  31. from ._field_values import default_value, is_zero_value
  32. from ._from_binary import FromBinaryOptions, read_message
  33. from ._native_message import object_setattr
  34. from ._oneof import Oneof
  35. from ._to_binary import ToBinaryOptions, write_message
  36. from ._unknown import get_unknown_field, has_unknown_field, set_unknown_field
  37. from ._wire import BinaryReader, BinaryWriter
  38. if TYPE_CHECKING:
  39. from collections.abc import Iterator
  40. from ._registry import Registry
  41. Self = TypeVar("Self", bound="Message")
  42. # TypeVar for making Message generic over its field names
  43. FieldNamesT = TypeVar("FieldNamesT", bound=str)
  44. M = TypeVar("M", bound="Message")
  45. E = TypeVar("E")
  46. class _MessageMeta(type):
  47. """Metaclass for Message to insert native extension when available."""
  48. def __new__(
  49. cls, name: str, bases: tuple[type, ...], classdict: dict[str, Any]
  50. ) -> _MessageMeta:
  51. is_message_base = not any(isinstance(base, _MessageMeta) for base in bases)
  52. # Don't eagerly import the member to allow easier overriding in benchmarks
  53. native_message_class = _native_message.NativeMessageClass
  54. if native_message_class:
  55. if is_message_base:
  56. # Python does not allow inheriting from multiple classes with fixed size, which includes
  57. # native classes and classes with __slots__. We go ahead and define any needed private
  58. # fields from Message in NativeMessage as well. A small amount of duplication, though it
  59. # also means we can use native alternatives where appropriate.
  60. classdict = {**classdict, "__slots__": ()}
  61. elif not any(
  62. isinstance(base, type) and issubclass(base, native_message_class)
  63. for base in bases
  64. ):
  65. bases = (native_message_class, *bases)
  66. return super().__new__(cls, name, bases, classdict)
  67. MessageMeta = _MessageMeta if _native_message.NativeMessageClass else type
  68. class Message(Generic[FieldNamesT], metaclass=MessageMeta): # noqa: PLW1641
  69. """Base class for Protobuf message types.
  70. Most `Message` subclasses are generated from `.proto` files. A message instance
  71. behaves like a regular Python object: construct it with keyword arguments using
  72. Python field names, then read and assign fields through attributes. `Message`
  73. provides all the shared runtime behavior for operating on messages.
  74. Thread safety:
  75. Message instances are not thread safe for concurrent mutation with any
  76. other operation. Concurrent reads without mutation are safe.
  77. Examples:
  78. ```python
  79. user = User(first_name="Alice", active=True)
  80. user.last_name = "Smith"
  81. ```
  82. """
  83. __slots__ = ("__weakref__", "_present", "_unknown_fields")
  84. if TYPE_CHECKING:
  85. _desc: ClassVar[DescMessage]
  86. _present: set[int]
  87. _unknown_fields: dict[int, list[bytes]] | None
  88. def __new__(cls: type[Self], *_args: Any, **_kwargs: Any) -> Self:
  89. msg = object.__new__(cls)
  90. object_setattr(msg, "_present", set())
  91. object_setattr(msg, "_unknown_fields", None)
  92. return msg
  93. def __init__(self, **kwargs: Any) -> None:
  94. """Initialize an instance of the message.
  95. Args:
  96. **kwargs: Field names (Python local names) and their values.
  97. """
  98. for local_name, default in self._desc._defaults:
  99. if local_name in kwargs:
  100. value = kwargs.pop(local_name)
  101. if value is not None:
  102. setattr(self, local_name, value)
  103. continue
  104. if isinstance(default, (list, dict)):
  105. object_setattr(self, local_name, default.__class__())
  106. else:
  107. object_setattr(self, local_name, default)
  108. # Error on unexpected argument
  109. if len(kwargs) > 0:
  110. msg = f"{type(self).__qualname__}.__init__() got an unexpected keyword argument '{next(iter(kwargs))}'"
  111. raise TypeError(msg)
  112. def to_json(
  113. self,
  114. *,
  115. registry: Registry | None = None,
  116. always_emit_implicit: bool = False,
  117. print_enums_as_ints: bool = False,
  118. use_proto_field_name: bool = False,
  119. ) -> str:
  120. """Serialize this message to a ProtoJSON string.
  121. By default, fields with implicit presence are not serialized if
  122. they are set to their zero value.
  123. A registry is required to serialize google.protobuf.Any fields
  124. and extensions. Extensions not found in the registry are silently
  125. omitted.
  126. Args:
  127. registry: A registry for resolving google.protobuf.Any messages
  128. and extensions.
  129. always_emit_implicit: By default, fields with implicit presence
  130. are omitted when set to their zero value (e.g. an empty
  131. list, a proto3 int32 field with value 0). If `True`, include
  132. these fields in the output.
  133. print_enums_as_ints: By default, the enum value name as defined
  134. in Protobuf is used. If `True`, use the numeric value instead.
  135. use_proto_field_name: By default, field names use the
  136. json_name field option, which defaults to lowerCamelCase.
  137. If `True`, use the Protobuf field name instead.
  138. Raises:
  139. ValueError: If a google.protobuf.Any field cannot be resolved
  140. through the registry.
  141. """
  142. from ._validate import validate # noqa: PLC0415
  143. validate(self)
  144. # Needs to be lazy import since JSON specially handles many WKTs.
  145. from ._to_json import ToJsonOptions, to_json # noqa: PLC0415
  146. return to_json(
  147. self,
  148. ToJsonOptions(
  149. always_emit_implicit=always_emit_implicit,
  150. print_enums_as_ints=print_enums_as_ints,
  151. use_proto_field_name=use_proto_field_name,
  152. registry=registry,
  153. ),
  154. )
  155. def to_binary(self, *, write_unknown_fields: bool = True) -> bytes:
  156. """Serialize this message to binary protobuf format.
  157. Args:
  158. write_unknown_fields: If `True`, unknown fields encountered
  159. during parsing are preserved in the output.
  160. Returns:
  161. The serialized binary protobuf bytes.
  162. """
  163. from ._validate import validate # noqa: PLC0415
  164. validate(self)
  165. writer = BinaryWriter()
  166. write_message(
  167. self, writer, ToBinaryOptions(write_unknown_fields=write_unknown_fields)
  168. )
  169. return writer.finish()
  170. def __copy__(self: Self) -> Self:
  171. """Create a shallow copy with independent presence and unknown fields tracking."""
  172. new: Self = self.__class__.__new__(type(self))
  173. for name in (
  174. *self._desc._fields_by_local_name,
  175. *self._desc._oneofs_by_local_name,
  176. ):
  177. if hasattr(self, name):
  178. object_setattr(new, name, getattr(self, name))
  179. new._present.update(self._present)
  180. if uf := self._unknown_fields:
  181. new._get_or_init_unknown_fields().update(
  182. {k: v.copy() for k, v in uf.items()}
  183. )
  184. return new
  185. def __deepcopy__(self: Self, _memo: dict[int, Any], /) -> Self:
  186. """Create a deep copy of the message."""
  187. from ._merge import merge_from # noqa: PLC0415
  188. new = type(self)()
  189. merge_from(new, self)
  190. return new
  191. def __repr__(self) -> str:
  192. """Return a string representation in `__init__` syntax.
  193. Unknown fields and extensions are not included in the output.
  194. """
  195. parts: list[str] = []
  196. for member in self._desc.members:
  197. if isinstance(member, DescOneof):
  198. if (value := getattr(self, member.local_name)) is not None:
  199. parts.append(f"{member.local_name}={value!r}")
  200. continue
  201. if member in self:
  202. value = self[member]
  203. parts.append(f"{member.local_name}={value!r}")
  204. return f"{self.__class__.__qualname__}({', '.join(parts)})"
  205. def __replace__(self: Self, **kwargs: Any) -> Self:
  206. """Create a copy by replacing fields.
  207. Similar to dataclasses.replace(), creates a shallow copy of the message
  208. with the specified fields updated to new values. This method is designed
  209. to work with `copy.replace()` available in Python 3.13+.
  210. Args:
  211. **kwargs: Field names and their new values.
  212. Returns:
  213. A new message instance with the specified fields replaced.
  214. Raises:
  215. AttributeError: If an unknown field name is provided.
  216. Examples:
  217. ```python
  218. msg1 = Message(field1=1, field2=2)
  219. msg2 = copy.replace(msg1, field1=10) # Python 3.13+
  220. # msg2 is Message(field1=10, field2=2)
  221. ```
  222. """
  223. # Create a shallow copy first
  224. new_instance = copy(self)
  225. for key, value in kwargs.items():
  226. setattr(new_instance, key, value)
  227. return new_instance
  228. def __setattr__(self, name: str, value: Any, /) -> None:
  229. """Set a field or oneof attribute by local name.
  230. Raises:
  231. AttributeError: If name is not a known field, oneof, or internal attribute.
  232. """
  233. if not self._desc._requires_presence:
  234. return object_setattr(self, name, value)
  235. field = self._desc._fields_by_local_name.get(name)
  236. if field is not None and field._requires_presence:
  237. self._set_field_number_present(field.number)
  238. object_setattr(self, name, value)
  239. return None
  240. def has_field(self, key: FieldNamesT, /) -> bool:
  241. """Check if a field is set by its proto name (e.g., `msg.has_field("field_name")`).
  242. This can be used to check whether a field with explicit presence has been set.
  243. Args:
  244. key: The proto field name as a string.
  245. Returns:
  246. `True` if the field is set, `False` otherwise.
  247. Raises:
  248. KeyError: If the field does not exist on this message.
  249. """
  250. return self._resolve_field(key) in self
  251. def clear_field(self, key: FieldNamesT, /) -> None:
  252. """Clear a field by its proto name (e.g., `msg.clear_field("field_name")`).
  253. This can be used to clear a field with explicit presence or reset a
  254. value to its default.
  255. Args:
  256. key: The proto field name as a string.
  257. Raises:
  258. KeyError: If the field does not exist on this message.
  259. """
  260. del self[self._resolve_field(key)]
  261. @overload
  262. def __getitem__(self, key: DescField | DescUnknownField, /) -> Any: ...
  263. @overload
  264. def __getitem__(self, key: Extension[M, E], /) -> E: ...
  265. def __getitem__(self, key: DescField | DescUnknownField | Extension, /) -> Any:
  266. """Get a field value by descriptor.
  267. Args:
  268. key: A `DescField`, `DescUnknownField`, or `Extension`.
  269. Returns:
  270. The field value, or the default if unset. For message fields the
  271. default is `None`; for scalars the zero value (`0`, `""`,
  272. `False`, etc.); for repeated/map fields an empty `list`/`dict`.
  273. If key is a oneof, returns a [`Oneof`][] if one of its fields is
  274. set, `None` otherwise.
  275. Raises:
  276. KeyError: If the field does not exist on this message.
  277. TypeError: If the key is not a DescField, DescUnknownField, or Extension.
  278. """
  279. if isinstance(key, (Extension, DescUnknownField)):
  280. if isinstance(key, Extension):
  281. key._assert_message_type(self)
  282. number = key._desc.number
  283. field_value = key._desc.value
  284. else:
  285. number = key.number
  286. field_value = key.value
  287. if (value := get_unknown_field(self, number, field_value)) is not None:
  288. return value
  289. return default_value(field_value)
  290. member = self._validate_member(key)
  291. return self._get_member(member)
  292. def _get_member(self, member: DescField) -> Any:
  293. """Get a field without validating."""
  294. if (
  295. isinstance(member.value, DescFieldValueSingular)
  296. and member.value.oneof is not None
  297. ):
  298. # Return the value if the field is selected in the oneof.
  299. # Fall back to the zero value.
  300. value = getattr(self, member.value.oneof.local_name)
  301. if isinstance(value, Oneof) and value.field == member.name:
  302. return value.value
  303. return default_value(member.value)
  304. # Return the attribute as is
  305. return getattr(self, member.local_name)
  306. @overload
  307. def __setitem__(self, key: DescField | DescUnknownField, value: Any, /) -> None: ...
  308. @overload
  309. def __setitem__(self, key: Extension[M, E], value: E, /) -> None: ...
  310. def __setitem__(
  311. self, key: DescField | DescUnknownField | Extension, value: Any, /
  312. ) -> None:
  313. """Set a field value by descriptor or proto name.
  314. Fields in a oneof can be set like regular fields, which resets siblings.
  315. Args:
  316. key: A `DescField`, `DescUnknownField`, or `Extension`. If key is a oneof, a
  317. [`Oneof`][] is accepted.
  318. value: The value to assign.
  319. Raises:
  320. KeyError: If the field does not exist on this message.
  321. TypeError: If the key is not a DescField, DescUnknownField, or Extension.
  322. """
  323. if isinstance(key, (Extension, DescUnknownField)):
  324. if isinstance(key, Extension):
  325. key._assert_message_type(self)
  326. number = key._desc.number
  327. field_value = key._desc.value
  328. else:
  329. number = key.number
  330. field_value = key.value
  331. set_unknown_field(self, number, field_value, value)
  332. return None
  333. member = self._validate_member(key)
  334. return self._set_member(member, value)
  335. def _set_member(self, member: DescField, value: Any) -> None:
  336. """Set a field without validating."""
  337. if (
  338. isinstance(member.value, DescFieldValueSingular)
  339. and member.value.oneof is not None
  340. ):
  341. # Set a new Oneof with the selected field and value
  342. value = Oneof(field=member.name, value=value)
  343. object_setattr(self, member.value.oneof.local_name, value)
  344. else:
  345. # Set the attribute as is
  346. object_setattr(self, member.local_name, value)
  347. if member._requires_presence:
  348. self._set_field_number_present(member.number)
  349. @overload
  350. def __contains__(self, key: DescField | DescUnknownField, /) -> bool: ...
  351. @overload
  352. def __contains__(self, key: Extension[M, E], /) -> bool: ...
  353. def __contains__(self, key: DescField | DescUnknownField | Extension, /) -> bool:
  354. """Check if a field is set (e.g., `desc in msg`).
  355. For fields with explicit presence, checks if the field has been set.
  356. For fields without presence (implicit presence), compares against the
  357. default value.
  358. Args:
  359. key: A `DescField`, `DescUnknownField`, or `Extension`. If key is a oneof, a
  360. [`Oneof`][] is accepted.
  361. Returns:
  362. `True` if the field is set or non-zero. If key is a oneof,
  363. `True` if any of its fields is set.
  364. Raises:
  365. KeyError: If the field does not exist on this message.
  366. TypeError: If the key is not a DescField, DescUnknownField, or Extension.
  367. """
  368. if isinstance(key, (Extension, DescUnknownField)):
  369. if isinstance(key, Extension):
  370. if not key._is_correct_message_type(self):
  371. return False
  372. number = key._desc.number
  373. field_value = key._desc.value
  374. else:
  375. number = key.number
  376. field_value = key.value
  377. return has_unknown_field(self, number, field_value)
  378. member = self._validate_member(key)
  379. return self._contains_member(member)
  380. def _contains_member(self, member: DescField) -> bool:
  381. """Check if a field is set without validating."""
  382. match field_value := member.value:
  383. case (
  384. DescFieldValueScalar(oneof=desc_oneof)
  385. | DescFieldValueMessage(oneof=desc_oneof)
  386. | DescFieldValueEnum(oneof=desc_oneof)
  387. ) if desc_oneof is not None:
  388. oneof = getattr(self, desc_oneof.local_name)
  389. return isinstance(oneof, Oneof) and oneof.field == member.name
  390. case DescFieldValueScalar(oneof=None) | DescFieldValueEnum(oneof=None):
  391. if member._requires_presence:
  392. return self._get_field_number_present(member.number)
  393. return not is_zero_value(field_value, getattr(self, member.local_name))
  394. @overload
  395. def __delitem__(self, key: DescField | DescUnknownField, /) -> None: ...
  396. @overload
  397. def __delitem__(self, key: Extension[M, E], /) -> None: ...
  398. def __delitem__(self, key: DescField | DescUnknownField | Extension, /) -> None:
  399. """Clear a field by its key (e.g., `del msg[desc]`).
  400. Clears the field to its default value. Does not delete the attribute.
  401. For message fields, sets to `None`; for scalars, the zero value;
  402. for repeated/map fields, clears to an empty `list`/`dict`.
  403. Args:
  404. key: A `DescField`, `DescUnknownField`, or `Extension`.
  405. Raises:
  406. KeyError: If the field does not exist on this message.
  407. TypeError: If the key is not a DescField, DescUnknownField, or Extension.
  408. """
  409. if isinstance(key, (Extension, DescUnknownField)):
  410. if isinstance(key, Extension):
  411. key._assert_message_type(self)
  412. number = key._desc.number
  413. else:
  414. number = key.number
  415. if uf := self._unknown_fields:
  416. uf.pop(number, None)
  417. return
  418. member = self._validate_member(key)
  419. self._del_member(member)
  420. def _del_member(self, member: DescField) -> None:
  421. """Delete a field without validating."""
  422. attr = member.local_name
  423. match field_value := member.value:
  424. case (
  425. DescFieldValueScalar() | DescFieldValueMessage() | DescFieldValueEnum()
  426. ):
  427. if field_value.oneof is None:
  428. # Bypass __setattr__ to avoid marking the field as present
  429. object_setattr(self, attr, default_value(field_value))
  430. self._clear_field_number_present(member.number)
  431. else:
  432. oneof = getattr(self, field_value.oneof.local_name)
  433. if isinstance(oneof, Oneof) and oneof.field == member.name:
  434. # Clear the oneof attribute
  435. object_setattr(self, field_value.oneof.local_name, None)
  436. case DescFieldValueList() | DescFieldValueMap():
  437. # Get the collection and clear it, fall back to setting a new collection
  438. if not hasattr(self, attr):
  439. object_setattr(self, attr, default_value(field_value))
  440. return
  441. value = getattr(self, attr)
  442. if not isinstance(value, list) and not isinstance(value, dict):
  443. object_setattr(self, attr, default_value(field_value))
  444. return
  445. value.clear()
  446. def __iter__(self) -> Iterator[DescField]:
  447. """Iterate over all [`DescField`][]s in this message that are set."""
  448. for field in self._desc.fields:
  449. if self._contains_member(field):
  450. yield field
  451. def __eq__(self, other: object, /) -> bool:
  452. """Compare two messages for equality.
  453. Two messages are considered equal when all of the following hold:
  454. - They have the same type.
  455. - For every field, both messages agree on whether the field is set or unset.
  456. - All set fields have equal values.
  457. NaN-valued floats are treated as equal to each other, consistent with
  458. Python's container equality semantics (e.g. `list`, `dict`).
  459. Extensions and unknown fields are not considered in the comparison.
  460. """
  461. if not isinstance(other, type(self)):
  462. return NotImplemented
  463. for field in self._desc.fields:
  464. self_set = field in self
  465. other_set = field in other
  466. if self_set != other_set:
  467. return False
  468. if self_set:
  469. self_val = self[field]
  470. other_val = other[field]
  471. if self_val is not other_val and self_val != other_val:
  472. return False
  473. return True
  474. @classmethod
  475. def from_json(
  476. cls: type[Self],
  477. json: str | bytes | bytearray,
  478. *,
  479. ignore_unknown_fields: bool = False,
  480. registry: Registry | None = None,
  481. ) -> Self:
  482. """Create a new message from a ProtoJSON string.
  483. Args:
  484. json: A str, bytes, or bytearray instance containing the ProtoJSON.
  485. ignore_unknown_fields:
  486. Proto3 JSON parser should reject unknown fields by default.
  487. This option ignores unknown fields in parsing, as well as unrecognized
  488. enum string representations.
  489. registry:
  490. This option is required to read `google.protobuf.Any` and extensions
  491. from JSON format.
  492. Raises:
  493. json.JSONDecodeError: If json_source is not valid JSON.
  494. TypeError: If the JSON structure does not match expected types.
  495. ValueError: If a google.protobuf.Any or an extension cannot be resolved
  496. through the registry.
  497. """
  498. from ._from_json import merge_from_json # noqa: PLC0415
  499. msg = cls()
  500. merge_from_json(
  501. msg, json, ignore_unknown_fields=ignore_unknown_fields, registry=registry
  502. )
  503. return msg
  504. @classmethod
  505. def from_binary(
  506. cls: type[Self], data: bytes, *, ignore_unknown_fields: bool = False
  507. ) -> Self:
  508. """Create a new message by parsing serialized binary data.
  509. To merge into an existing message, use [`merge_from_binary`][].
  510. Args:
  511. data: Serialized binary protobuf data.
  512. ignore_unknown_fields: If `True`, unknown fields in the binary data are silently discarded.
  513. """
  514. message = cls()
  515. message._merge_from_binary(data, ignore_unknown_fields=ignore_unknown_fields)
  516. return message
  517. @classmethod
  518. def desc(cls) -> DescMessage:
  519. """Get the associated DescMessage with this type."""
  520. return cls._desc
  521. def __getstate__(self) -> object:
  522. return self.to_binary()
  523. def __setstate__(self, state: object, /) -> None:
  524. if not isinstance(state, bytes):
  525. msg = f"invalid state for unpickling {self.__class__.__name__}: expected bytes, got {type(state).__name__}"
  526. raise TypeError(msg)
  527. self.__init__()
  528. self._merge_from_binary(state, ignore_unknown_fields=False)
  529. def _validate_member(self, key: DescField) -> DescField:
  530. """Validates the DescField is part of this message.
  531. Raises:
  532. KeyError: If the field does not exist on this message.
  533. TypeError: If the key is not a DescField.
  534. """
  535. if isinstance(key, DescField):
  536. if key.parent.type_name == self._desc.type_name:
  537. return key
  538. msg = f"{key!s} cannot be used with {self._desc!s}"
  539. raise KeyError(msg)
  540. msg = f"key must be a DescField, not {type(key).__name__}"
  541. raise TypeError(msg)
  542. def _resolve_field(self, key: str) -> DescField:
  543. if not isinstance(key, str):
  544. msg = f"key must be a str, not {type(key).__name__}"
  545. raise TypeError(msg)
  546. if field := self._desc._fields_by_name.get(key):
  547. return field
  548. if field := self._desc._fields_by_local_name.get(key):
  549. msg = (
  550. f"unknown key for {self._desc!s}: {key!r}, did you mean {field.name!r}?"
  551. )
  552. raise KeyError(msg)
  553. msg = f"unknown key for {self._desc!s}: {key!r}"
  554. raise KeyError(msg)
  555. def _merge_from_binary(self, data: bytes, ignore_unknown_fields: bool) -> None: # noqa: FBT001
  556. opts = FromBinaryOptions(ignore_unknown_fields=ignore_unknown_fields)
  557. read_message(
  558. self, BinaryReader(memoryview(data)), opts, depth=0, length=len(data)
  559. )
  560. def _merge_from(self: Self, source: Self, ignore_unknown_fields: bool) -> None: # noqa: FBT001
  561. for field in source:
  562. match field_value := field.value:
  563. case DescFieldValueMessage():
  564. if field in self:
  565. self[field]._merge_from(
  566. source[field], ignore_unknown_fields=ignore_unknown_fields
  567. )
  568. else:
  569. self[field] = deepcopy(source[field])
  570. case DescFieldValueList():
  571. target_list: list = self[field]
  572. if isinstance(field_value.element, DescMessage):
  573. target_list.extend(deepcopy(m) for m in source[field])
  574. else:
  575. target_list.extend(source[field])
  576. case DescFieldValueMap():
  577. target_map: dict = self[field]
  578. if isinstance(field_value.value, DescMessage):
  579. for key, value in source[field].items():
  580. target_map[key] = deepcopy(value)
  581. else:
  582. target_map.update(source[field])
  583. case _:
  584. self[field] = source[field]
  585. if not ignore_unknown_fields and (uf := source._unknown_fields):
  586. for key, value in uf.items():
  587. self._get_or_init_unknown_fields().setdefault(key, []).extend(value)
  588. # Methods for updating whether a field is present or not by number. Overridden by native code.
  589. def _get_field_number_present(self, number: int) -> bool:
  590. return number in self._present
  591. def _set_field_number_present(self, number: int) -> None:
  592. self._present.add(number)
  593. def _clear_field_number_present(self, number: int) -> None:
  594. self._present.discard(number)
  595. def _get_or_init_unknown_fields(self) -> dict[int, list[bytes]]:
  596. if (uf := self._unknown_fields) is None:
  597. uf = {}
  598. object_setattr(self, "_unknown_fields", uf)
  599. return uf