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