Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/google/api_core/rest_helpers.py: 28%

36 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:45 +0000

1# Copyright 2021 Google LLC 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15"""Helpers for rest transports.""" 

16 

17import functools 

18import operator 

19 

20 

21def flatten_query_params(obj, strict=False): 

22 """Flatten a dict into a list of (name,value) tuples. 

23 

24 The result is suitable for setting query params on an http request. 

25 

26 .. code-block:: python 

27 

28 >>> obj = {'a': 

29 ... {'b': 

30 ... {'c': ['x', 'y', 'z']} }, 

31 ... 'd': 'uvw', 

32 ... 'e': True, } 

33 >>> flatten_query_params(obj, strict=True) 

34 [('a.b.c', 'x'), ('a.b.c', 'y'), ('a.b.c', 'z'), ('d', 'uvw'), ('e', 'true')] 

35 

36 Note that, as described in 

37 https://github.com/googleapis/googleapis/blob/48d9fb8c8e287c472af500221c6450ecd45d7d39/google/api/http.proto#L117, 

38 repeated fields (i.e. list-valued fields) may only contain primitive types (not lists or dicts). 

39 This is enforced in this function. 

40 

41 Args: 

42 obj: a possibly nested dictionary (from json), or None 

43 strict: a bool, defaulting to False, to enforce that all values in the 

44 result tuples be strings and, if boolean, lower-cased. 

45 

46 Returns: a list of tuples, with each tuple having a (possibly) multi-part name 

47 and a scalar value. 

48 

49 Raises: 

50 TypeError if obj is not a dict or None 

51 ValueError if obj contains a list of non-primitive values. 

52 """ 

53 

54 if obj is not None and not isinstance(obj, dict): 

55 raise TypeError("flatten_query_params must be called with dict object") 

56 

57 return _flatten(obj, key_path=[], strict=strict) 

58 

59 

60def _flatten(obj, key_path, strict=False): 

61 if obj is None: 

62 return [] 

63 if isinstance(obj, dict): 

64 return _flatten_dict(obj, key_path=key_path, strict=strict) 

65 if isinstance(obj, list): 

66 return _flatten_list(obj, key_path=key_path, strict=strict) 

67 return _flatten_value(obj, key_path=key_path, strict=strict) 

68 

69 

70def _is_primitive_value(obj): 

71 if obj is None: 

72 return False 

73 

74 if isinstance(obj, (list, dict)): 

75 raise ValueError("query params may not contain repeated dicts or lists") 

76 

77 return True 

78 

79 

80def _flatten_value(obj, key_path, strict=False): 

81 return [(".".join(key_path), _canonicalize(obj, strict=strict))] 

82 

83 

84def _flatten_dict(obj, key_path, strict=False): 

85 items = ( 

86 _flatten(value, key_path=key_path + [key], strict=strict) 

87 for key, value in obj.items() 

88 ) 

89 return functools.reduce(operator.concat, items, []) 

90 

91 

92def _flatten_list(elems, key_path, strict=False): 

93 # Only lists of scalar values are supported. 

94 # The name (key_path) is repeated for each value. 

95 items = ( 

96 _flatten_value(elem, key_path=key_path, strict=strict) 

97 for elem in elems 

98 if _is_primitive_value(elem) 

99 ) 

100 return functools.reduce(operator.concat, items, []) 

101 

102 

103def _canonicalize(obj, strict=False): 

104 if strict: 

105 value = str(obj) 

106 if isinstance(obj, bool): 

107 value = value.lower() 

108 return value 

109 return obj