_extension.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  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 typing import TYPE_CHECKING, Generic, TypeVar, final
  16. if TYPE_CHECKING:
  17. from ._descriptors import DescExtension
  18. from ._message import Message
  19. M = TypeVar("M", bound="Message")
  20. E = TypeVar("E")
  21. @final
  22. class Extension(Generic[M, E]):
  23. """A protobuf extension field.
  24. Extensions allow adding fields to a message without modifying the original
  25. message definition. This class provides type-safe access to extension fields
  26. on messages.
  27. This is meant for the generated code. For dynamic extensions use
  28. [`DescExtension.type`][protobuf.DescExtension.type].
  29. Attributes:
  30. desc: The extension descriptor.
  31. Examples:
  32. ```python
  33. # Given a protobuf extension definition:
  34. # extend Foo {
  35. # optional string extra = 1000;
  36. # }
  37. from .gen.ext_pb import ext_extra # The generated extension instance.
  38. from .gen.foo_pb import Foo
  39. foo = Foo()
  40. # Set a new extension value
  41. foo[ext_extra] = "new value"
  42. # Access the extension value
  43. value = foo[ext_extra]
  44. # Check if extension is set and clear it
  45. if ext_extra in foo:
  46. del foo[ext_extra]
  47. ```
  48. """
  49. __slots__ = ("__weakref__", "_desc")
  50. if TYPE_CHECKING:
  51. _desc: DescExtension
  52. def desc(self) -> DescExtension:
  53. """The extension descriptor."""
  54. return self._desc
  55. def _is_correct_message_type(self, message: Message) -> bool:
  56. return self._desc.extendee.type_name == message.desc().type_name
  57. def _assert_message_type(self, message: M) -> None:
  58. if not self._is_correct_message_type(message):
  59. msg = (
  60. f"extension {self._desc.name} extends {self._desc.extendee.type_name}, "
  61. f"but got message of type {message.desc().type_name}"
  62. )
  63. raise TypeError(msg)