Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/looker_sdk/rtl/hooks.py: 30%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

40 statements  

1# The MIT License (MIT) 

2# 

3# Copyright (c) 2022 Looker Data Sciences, Inc. 

4# 

5# Permission is hereby granted, free of charge, to any person obtaining a copy 

6# of this software and associated documentation files (the "Software"), to deal 

7# in the Software without restriction, including without limitation the rights 

8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 

9# copies of the Software, and to permit persons to whom the Software is 

10# furnished to do so, subject to the following conditions: 

11# 

12# The above copyright notice and this permission notice shall be included in 

13# all copies or substantial portions of the Software. 

14# 

15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 

16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 

17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 

18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 

19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 

20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 

21# THE SOFTWARE. 

22 

23import datetime 

24import enum 

25import keyword 

26import sys 

27from typing import Type 

28 

29import attr 

30 

31 

32def unstructure_hook(converter, api_model): 

33 """cattr unstructure hook 

34 

35 Map reserved_ words in models to correct json field names. 

36 Also handle stripping None fields from dict while setting 

37 EXPLICIT_NULL fields to None so that we only send null 

38 in the json for fields the caller set EXPLICIT_NULL on. 

39 """ 

40 attr.resolve_types(api_model.__class__) 

41 data = converter.unstructure_attrs_asdict(api_model) 

42 for key, value in data.copy().items(): 

43 if value is None: 

44 del data[key] 

45 elif value == "EXPLICIT_NULL": 

46 data[key] = None 

47 # bug here: in the unittests cattrs unstructures this correctly 

48 # as an enum calling .value but in the integration tests we see 

49 # it doesn't for WriteCreateQueryTask.result_format for some reason 

50 # Haven't been able to debug it fully, so catching and processing 

51 # it here. 

52 elif isinstance(value, enum.Enum): 

53 data[key] = value.value 

54 for reserved in keyword.kwlist: 

55 if f"{reserved}_" in data: 

56 data[reserved] = data.pop(f"{reserved}_") 

57 return data 

58 

59 

60DATETIME_FMT = "%Y-%m-%dT%H:%M:%S.%f%z" 

61if sys.version_info < (3, 7): 

62 from dateutil import parser 

63 

64 def datetime_structure_hook( 

65 d: str, t: Type[datetime.datetime] 

66 ) -> datetime.datetime: 

67 return parser.isoparse(d) 

68 

69else: 

70 

71 def datetime_structure_hook( 

72 d: str, t: Type[datetime.datetime] 

73 ) -> datetime.datetime: 

74 if d.endswith("Z"): 

75 d = d[:-1] + "+00:00" 

76 try: 

77 return datetime.datetime.fromisoformat(d) 

78 except ValueError: 

79 return datetime.datetime.strptime(d, DATETIME_FMT) 

80 

81 

82def datetime_unstructure_hook(dt): 

83 return dt.strftime(DATETIME_FMT) 

84 

85 

86def tr_data_keys(data): 

87 """Map top level json keys to model property names. 

88 

89 Currently this translates reserved python keywords like "from" => "from_" 

90 """ 

91 for reserved in keyword.kwlist: 

92 if reserved in data and isinstance(data, dict): 

93 data[f"{reserved}_"] = data.pop(reserved) 

94 return data