• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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