github.com/apache/beam/sdks/v2@v2.48.2/python/apache_beam/internal/gcp/json_value.py (about)

     1  #
     2  # Licensed to the Apache Software Foundation (ASF) under one or more
     3  # contributor license agreements.  See the NOTICE file distributed with
     4  # this work for additional information regarding copyright ownership.
     5  # The ASF licenses this file to You under the Apache License, Version 2.0
     6  # (the "License"); you may not use this file except in compliance with
     7  # the License.  You may obtain a copy of the License at
     8  #
     9  #    http://www.apache.org/licenses/LICENSE-2.0
    10  #
    11  # Unless required by applicable law or agreed to in writing, software
    12  # distributed under the License is distributed on an "AS IS" BASIS,
    13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  # See the License for the specific language governing permissions and
    15  # limitations under the License.
    16  #
    17  
    18  """JSON conversion utility functions."""
    19  
    20  # pytype: skip-file
    21  
    22  from apache_beam.options.value_provider import ValueProvider
    23  
    24  # Protect against environments where apitools library is not available.
    25  # pylint: disable=wrong-import-order, wrong-import-position
    26  try:
    27    from apitools.base.py import extra_types
    28  except ImportError:
    29    extra_types = None
    30  # pylint: enable=wrong-import-order, wrong-import-position
    31  
    32  _MAXINT64 = (1 << 63) - 1
    33  _MININT64 = -(1 << 63)
    34  
    35  
    36  def get_typed_value_descriptor(obj):
    37    """For internal use only; no backwards-compatibility guarantees.
    38  
    39    Converts a basic type into a @type/value dictionary.
    40  
    41    Args:
    42      obj: A bytes, unicode, bool, int, or float to be converted.
    43  
    44    Returns:
    45      A dictionary containing the keys ``@type`` and ``value`` with the value for
    46      the ``@type`` of appropriate type.
    47  
    48    Raises:
    49      TypeError: if the Python object has a type that is not
    50        supported.
    51    """
    52    if isinstance(obj, (bytes, str)):
    53      type_name = 'Text'
    54    elif isinstance(obj, bool):
    55      type_name = 'Boolean'
    56    elif isinstance(obj, int):
    57      type_name = 'Integer'
    58    elif isinstance(obj, float):
    59      type_name = 'Float'
    60    else:
    61      raise TypeError('Cannot get a type descriptor for %s.' % repr(obj))
    62    return {'@type': 'http://schema.org/%s' % type_name, 'value': obj}
    63  
    64  
    65  def to_json_value(obj, with_type=False):
    66    """For internal use only; no backwards-compatibility guarantees.
    67  
    68    Converts Python objects into extra_types.JsonValue objects.
    69  
    70    Args:
    71      obj: Python object to be converted. Can be :data:`None`.
    72      with_type: If true then the basic types (``bytes``, ``unicode``, ``int``,
    73        ``float``, ``bool``) will be wrapped in ``@type:value`` dictionaries.
    74        Otherwise the straight value is encoded into a ``JsonValue``.
    75  
    76    Returns:
    77      A ``JsonValue`` object using ``JsonValue``, ``JsonArray`` and ``JsonObject``
    78      types for the corresponding values, lists, or dictionaries.
    79  
    80    Raises:
    81      TypeError: if the Python object contains a type that is not
    82        supported.
    83  
    84    The types supported are ``str``, ``bool``, ``list``, ``tuple``, ``dict``, and
    85    ``None``. The Dataflow API requires JsonValue(s) in many places, and it is
    86    quite convenient to be able to specify these hierarchical objects using
    87    Python syntax.
    88    """
    89    if obj is None:
    90      return extra_types.JsonValue(is_null=True)
    91    elif isinstance(obj, (list, tuple)):
    92      return extra_types.JsonValue(
    93          array_value=extra_types.JsonArray(
    94              entries=[to_json_value(o, with_type=with_type) for o in obj]))
    95    elif isinstance(obj, dict):
    96      json_object = extra_types.JsonObject()
    97      for k, v in obj.items():
    98        json_object.properties.append(
    99            extra_types.JsonObject.Property(
   100                key=k, value=to_json_value(v, with_type=with_type)))
   101      return extra_types.JsonValue(object_value=json_object)
   102    elif with_type:
   103      return to_json_value(get_typed_value_descriptor(obj), with_type=False)
   104    elif isinstance(obj, str):
   105      return extra_types.JsonValue(string_value=obj)
   106    elif isinstance(obj, bytes):
   107      return extra_types.JsonValue(string_value=obj.decode('utf8'))
   108    elif isinstance(obj, bool):
   109      return extra_types.JsonValue(boolean_value=obj)
   110    elif isinstance(obj, int):
   111      if _MININT64 <= obj <= _MAXINT64:
   112        return extra_types.JsonValue(integer_value=obj)
   113      else:
   114        raise TypeError('Can not encode {} as a 64-bit integer'.format(obj))
   115    elif isinstance(obj, float):
   116      return extra_types.JsonValue(double_value=obj)
   117    elif isinstance(obj, ValueProvider):
   118      if obj.is_accessible():
   119        return to_json_value(obj.get())
   120      return extra_types.JsonValue(is_null=True)
   121    else:
   122      raise TypeError('Cannot convert %s to a JSON value.' % repr(obj))
   123  
   124  
   125  def from_json_value(v):
   126    """For internal use only; no backwards-compatibility guarantees.
   127  
   128    Converts ``extra_types.JsonValue`` objects into Python objects.
   129  
   130    Args:
   131      v: ``JsonValue`` object to be converted.
   132  
   133    Returns:
   134      A Python object structured as values, lists, and dictionaries corresponding
   135      to ``JsonValue``, ``JsonArray`` and ``JsonObject`` types.
   136  
   137    Raises:
   138      TypeError: if the ``JsonValue`` object contains a type that is
   139        not supported.
   140  
   141    The types supported are ``str``, ``bool``, ``list``, ``dict``, and ``None``.
   142    The Dataflow API returns JsonValue(s) in many places and it is quite
   143    convenient to be able to convert these hierarchical objects to much simpler
   144    Python objects.
   145    """
   146    if isinstance(v, extra_types.JsonValue):
   147      if v.string_value is not None:
   148        return v.string_value
   149      elif v.boolean_value is not None:
   150        return v.boolean_value
   151      elif v.integer_value is not None:
   152        return v.integer_value
   153      elif v.double_value is not None:
   154        return v.double_value
   155      elif v.array_value is not None:
   156        return from_json_value(v.array_value)
   157      elif v.object_value is not None:
   158        return from_json_value(v.object_value)
   159      elif v.is_null:
   160        return None
   161    elif isinstance(v, extra_types.JsonArray):
   162      return [from_json_value(e) for e in v.entries]
   163    elif isinstance(v, extra_types.JsonObject):
   164      return {p.key: from_json_value(p.value) for p in v.properties}
   165    raise TypeError('Cannot convert %s from a JSON value.' % repr(v))