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