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# For internal use only 
    135def IsPythonDefaultSerializationDeterministic(): 
    136  return _python_deterministic_proto_serialization