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))