api_implementation.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. # Protocol Buffers - Google's data interchange format
  2. # Copyright 2008 Google Inc. All rights reserved.
  3. #
  4. # Use of this source code is governed by a BSD-style
  5. # license that can be found in the LICENSE file or at
  6. # https://developers.google.com/open-source/licenses/bsd
  7. """Determine which implementation of the protobuf API is used in this process."""
  8. import importlib
  9. import os
  10. import sys
  11. import warnings
  12. _GOOGLE3_PYTHON_UPB_DEFAULT = True
  13. def _ApiVersionToImplementationType(api_version):
  14. if api_version == 2:
  15. return 'cpp'
  16. if api_version == 1:
  17. raise ValueError('api_version=1 is no longer supported.')
  18. if api_version == 0:
  19. return 'python'
  20. return None
  21. _implementation_type = None
  22. try:
  23. # pylint: disable=g-import-not-at-top
  24. from google.protobuf.internal import _api_implementation
  25. # The compile-time constants in the _api_implementation module can be used to
  26. # switch to a certain implementation of the Python API at build time.
  27. _implementation_type = _ApiVersionToImplementationType(
  28. _api_implementation.api_version
  29. )
  30. except ImportError:
  31. pass # Unspecified by compiler flags.
  32. def _CanImport(mod_name):
  33. try:
  34. mod = importlib.import_module(mod_name)
  35. # Work around a known issue in the classic bootstrap .par import hook.
  36. if not mod:
  37. raise ImportError(mod_name + ' import succeeded but was None')
  38. return True
  39. except ImportError:
  40. return False
  41. if _implementation_type is None:
  42. if _CanImport('google._upb._message'):
  43. _implementation_type = 'upb'
  44. elif _CanImport('google.protobuf.pyext._message'):
  45. _implementation_type = 'cpp'
  46. else:
  47. _implementation_type = 'python'
  48. # This environment variable can be used to switch to a certain implementation
  49. # of the Python API, overriding the compile-time constants in the
  50. # _api_implementation module. Right now only 'python', 'cpp' and 'upb' are
  51. # valid values. Any other value will raise error.
  52. _implementation_type = os.getenv(
  53. 'PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION', _implementation_type
  54. )
  55. if _implementation_type not in ('python', 'cpp', 'upb'):
  56. raise ValueError(
  57. 'PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION {0} is not '
  58. "supported. Please set to 'python', 'cpp' or "
  59. "'upb'.".format(_implementation_type)
  60. )
  61. if 'PyPy' in sys.version and _implementation_type == 'cpp':
  62. warnings.warn(
  63. 'PyPy does not work yet with cpp protocol buffers. '
  64. 'Falling back to the python implementation.'
  65. )
  66. _implementation_type = 'python'
  67. _c_module = None
  68. if _implementation_type == 'cpp':
  69. try:
  70. # pylint: disable=g-import-not-at-top
  71. from google.protobuf.pyext import _message
  72. sys.modules['google3.net.proto2.python.internal.cpp._message'] = _message
  73. _c_module = _message
  74. del _message
  75. except ImportError:
  76. # TODO: fail back to python
  77. warnings.warn('Selected implementation cpp is not available.')
  78. pass
  79. if _implementation_type == 'upb':
  80. try:
  81. # pylint: disable=g-import-not-at-top
  82. from google._upb import _message
  83. _c_module = _message
  84. del _message
  85. except ImportError:
  86. warnings.warn(
  87. 'Selected implementation upb is not available. '
  88. 'Falling back to the python implementation.'
  89. )
  90. _implementation_type = 'python'
  91. pass
  92. # Detect if serialization should be deterministic by default
  93. try:
  94. # The presence of this module in a build allows the proto implementation to
  95. # be upgraded merely via build deps.
  96. #
  97. # NOTE: Merely importing this automatically enables deterministic proto
  98. # serialization for C++ code, but we still need to export it as a boolean so
  99. # that we can do the same for `_implementation_type == 'python'`.
  100. #
  101. # NOTE2: It is possible for C++ code to enable deterministic serialization by
  102. # default _without_ affecting Python code, if the C++ implementation is not in
  103. # use by this module. That is intended behavior, so we don't actually expose
  104. # this boolean outside of this module.
  105. #
  106. # pylint: disable=g-import-not-at-top,unused-import
  107. from google.protobuf import enable_deterministic_proto_serialization
  108. _python_deterministic_proto_serialization = True
  109. except ImportError:
  110. _python_deterministic_proto_serialization = False
  111. # Usage of this function is discouraged. Clients shouldn't care which
  112. # implementation of the API is in use. Note that there is no guarantee
  113. # that differences between APIs will be maintained.
  114. # Please don't use this function if possible.
  115. def Type():
  116. return _implementation_type
  117. # For internal use only
  118. def IsPythonDefaultSerializationDeterministic():
  119. return _python_deterministic_proto_serialization