api_implementation.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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. """
  9. import importlib
  10. import os
  11. import sys
  12. import warnings
  13. _GOOGLE3_PYTHON_UPB_DEFAULT = True
  14. def _ApiVersionToImplementationType(api_version):
  15. if api_version == 2:
  16. return 'cpp'
  17. if api_version == 1:
  18. raise ValueError('api_version=1 is no longer supported.')
  19. if api_version == 0:
  20. return 'python'
  21. return None
  22. _implementation_type = None
  23. try:
  24. # pylint: disable=g-import-not-at-top
  25. from google.protobuf.internal import _api_implementation
  26. # The compile-time constants in the _api_implementation module can be used to
  27. # switch to a certain implementation of the Python API at build time.
  28. _implementation_type = _ApiVersionToImplementationType(
  29. _api_implementation.api_version)
  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('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION',
  53. _implementation_type)
  54. if _implementation_type not in ('python', 'cpp', 'upb'):
  55. raise ValueError('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION {0} is not '
  56. 'supported. Please set to \'python\', \'cpp\' or '
  57. '\'upb\'.'.format(_implementation_type))
  58. if 'PyPy' in sys.version and _implementation_type == 'cpp':
  59. warnings.warn('PyPy does not work yet with cpp protocol buffers. '
  60. 'Falling back to the python implementation.')
  61. _implementation_type = 'python'
  62. _c_module = None
  63. if _implementation_type == 'cpp':
  64. try:
  65. # pylint: disable=g-import-not-at-top
  66. from google.protobuf.pyext import _message
  67. sys.modules['google3.net.proto2.python.internal.cpp._message'] = _message
  68. _c_module = _message
  69. del _message
  70. except ImportError:
  71. # TODO: fail back to python
  72. warnings.warn(
  73. 'Selected implementation cpp is not available.')
  74. pass
  75. if _implementation_type == 'upb':
  76. try:
  77. # pylint: disable=g-import-not-at-top
  78. from google._upb import _message
  79. _c_module = _message
  80. del _message
  81. except ImportError:
  82. warnings.warn('Selected implementation upb is not available. '
  83. 'Falling back to the python implementation.')
  84. _implementation_type = 'python'
  85. pass
  86. # Detect if serialization should be deterministic by default
  87. try:
  88. # The presence of this module in a build allows the proto implementation to
  89. # be upgraded merely via build deps.
  90. #
  91. # NOTE: Merely importing this automatically enables deterministic proto
  92. # serialization for C++ code, but we still need to export it as a boolean so
  93. # that we can do the same for `_implementation_type == 'python'`.
  94. #
  95. # NOTE2: It is possible for C++ code to enable deterministic serialization by
  96. # default _without_ affecting Python code, if the C++ implementation is not in
  97. # use by this module. That is intended behavior, so we don't actually expose
  98. # this boolean outside of this module.
  99. #
  100. # pylint: disable=g-import-not-at-top,unused-import
  101. from google.protobuf import enable_deterministic_proto_serialization
  102. _python_deterministic_proto_serialization = True
  103. except ImportError:
  104. _python_deterministic_proto_serialization = False
  105. # Usage of this function is discouraged. Clients shouldn't care which
  106. # implementation of the API is in use. Note that there is no guarantee
  107. # that differences between APIs will be maintained.
  108. # Please don't use this function if possible.
  109. def Type():
  110. return _implementation_type
  111. # See comment on 'Type' above.
  112. # TODO: Remove the API, it returns a constant. b/228102101
  113. def Version():
  114. return 2
  115. # For internal use only
  116. def IsPythonDefaultSerializationDeterministic():
  117. return _python_deterministic_proto_serialization