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