Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/botocore/docs/sharedexample.py: 13%

142 statements  

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

1# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 

2# 

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

4# may not use this file except in compliance with the License. A copy of 

5# the License is located at 

6# 

7# http://aws.amazon.com/apache2.0/ 

8# 

9# or in the "license" file accompanying this file. This file is 

10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 

11# ANY KIND, either express or implied. See the License for the specific 

12# language governing permissions and limitations under the License. 

13import numbers 

14import re 

15 

16from botocore.docs.utils import escape_controls 

17from botocore.utils import parse_timestamp 

18 

19 

20class SharedExampleDocumenter: 

21 def document_shared_example( 

22 self, example, prefix, section, operation_model 

23 ): 

24 """Documents a single shared example based on its definition. 

25 

26 :param example: The model of the example 

27 

28 :param prefix: The prefix to use in the method example. 

29 

30 :param section: The section to write to. 

31 

32 :param operation_model: The model of the operation used in the example 

33 """ 

34 section.style.new_paragraph() 

35 section.write(example.get('description')) 

36 section.style.new_line() 

37 self.document_input( 

38 section, example, prefix, operation_model.input_shape 

39 ) 

40 self.document_output(section, example, operation_model.output_shape) 

41 

42 def document_input(self, section, example, prefix, shape): 

43 input_section = section.add_new_section('input') 

44 input_section.style.start_codeblock() 

45 if prefix is not None: 

46 input_section.write(prefix) 

47 params = example.get('input', {}) 

48 comments = example.get('comments') 

49 if comments: 

50 comments = comments.get('input') 

51 param_section = input_section.add_new_section('parameters') 

52 self._document_params(param_section, params, comments, [], shape) 

53 closing_section = input_section.add_new_section('input-close') 

54 closing_section.style.new_line() 

55 closing_section.style.new_line() 

56 closing_section.write('print(response)') 

57 closing_section.style.end_codeblock() 

58 

59 def document_output(self, section, example, shape): 

60 output_section = section.add_new_section('output') 

61 output_section.style.new_line() 

62 output_section.write('Expected Output:') 

63 output_section.style.new_line() 

64 output_section.style.start_codeblock() 

65 params = example.get('output', {}) 

66 

67 # There might not be an output, but we will return metadata anyway 

68 params['ResponseMetadata'] = {"...": "..."} 

69 comments = example.get('comments') 

70 if comments: 

71 comments = comments.get('output') 

72 self._document_dict(output_section, params, comments, [], shape, True) 

73 closing_section = output_section.add_new_section('output-close') 

74 closing_section.style.end_codeblock() 

75 

76 def _document(self, section, value, comments, path, shape): 

77 """ 

78 :param section: The section to add the docs to. 

79 

80 :param value: The input / output values representing the parameters that 

81 are included in the example. 

82 

83 :param comments: The dictionary containing all the comments to be 

84 applied to the example. 

85 

86 :param path: A list describing where the documenter is in traversing the 

87 parameters. This is used to find the equivalent location 

88 in the comments dictionary. 

89 """ 

90 if isinstance(value, dict): 

91 self._document_dict(section, value, comments, path, shape) 

92 elif isinstance(value, list): 

93 self._document_list(section, value, comments, path, shape) 

94 elif isinstance(value, numbers.Number): 

95 self._document_number(section, value, path) 

96 elif shape and shape.type_name == 'timestamp': 

97 self._document_datetime(section, value, path) 

98 else: 

99 self._document_str(section, value, path) 

100 

101 def _document_dict( 

102 self, section, value, comments, path, shape, top_level=False 

103 ): 

104 dict_section = section.add_new_section('dict-value') 

105 self._start_nested_value(dict_section, '{') 

106 for key, val in value.items(): 

107 path.append('.%s' % key) 

108 item_section = dict_section.add_new_section(key) 

109 item_section.style.new_line() 

110 item_comment = self._get_comment(path, comments) 

111 if item_comment: 

112 item_section.write(item_comment) 

113 item_section.style.new_line() 

114 item_section.write("'%s': " % key) 

115 

116 # Shape could be none if there is no output besides ResponseMetadata 

117 item_shape = None 

118 if shape: 

119 if shape.type_name == 'structure': 

120 item_shape = shape.members.get(key) 

121 elif shape.type_name == 'map': 

122 item_shape = shape.value 

123 self._document(item_section, val, comments, path, item_shape) 

124 path.pop() 

125 dict_section_end = dict_section.add_new_section('ending-brace') 

126 self._end_nested_value(dict_section_end, '}') 

127 if not top_level: 

128 dict_section_end.write(',') 

129 

130 def _document_params(self, section, value, comments, path, shape): 

131 param_section = section.add_new_section('param-values') 

132 self._start_nested_value(param_section, '(') 

133 for key, val in value.items(): 

134 path.append('.%s' % key) 

135 item_section = param_section.add_new_section(key) 

136 item_section.style.new_line() 

137 item_comment = self._get_comment(path, comments) 

138 if item_comment: 

139 item_section.write(item_comment) 

140 item_section.style.new_line() 

141 item_section.write(key + '=') 

142 

143 # Shape could be none if there are no input parameters 

144 item_shape = None 

145 if shape: 

146 item_shape = shape.members.get(key) 

147 self._document(item_section, val, comments, path, item_shape) 

148 path.pop() 

149 param_section_end = param_section.add_new_section('ending-parenthesis') 

150 self._end_nested_value(param_section_end, ')') 

151 

152 def _document_list(self, section, value, comments, path, shape): 

153 list_section = section.add_new_section('list-section') 

154 self._start_nested_value(list_section, '[') 

155 item_shape = shape.member 

156 for index, val in enumerate(value): 

157 item_section = list_section.add_new_section(index) 

158 item_section.style.new_line() 

159 path.append('[%s]' % index) 

160 item_comment = self._get_comment(path, comments) 

161 if item_comment: 

162 item_section.write(item_comment) 

163 item_section.style.new_line() 

164 self._document(item_section, val, comments, path, item_shape) 

165 path.pop() 

166 list_section_end = list_section.add_new_section('ending-bracket') 

167 self._end_nested_value(list_section_end, '],') 

168 

169 def _document_str(self, section, value, path): 

170 # We do the string conversion because this might accept a type that 

171 # we don't specifically address. 

172 safe_value = escape_controls(value) 

173 section.write(f"'{safe_value}',") 

174 

175 def _document_number(self, section, value, path): 

176 section.write("%s," % str(value)) 

177 

178 def _document_datetime(self, section, value, path): 

179 datetime_tuple = parse_timestamp(value).timetuple() 

180 datetime_str = str(datetime_tuple[0]) 

181 for i in range(1, len(datetime_tuple)): 

182 datetime_str += ", " + str(datetime_tuple[i]) 

183 section.write("datetime(%s)," % datetime_str) 

184 

185 def _get_comment(self, path, comments): 

186 key = re.sub(r'^\.', '', ''.join(path)) 

187 if comments and key in comments: 

188 return '# ' + comments[key] 

189 else: 

190 return '' 

191 

192 def _start_nested_value(self, section, start): 

193 section.write(start) 

194 section.style.indent() 

195 section.style.indent() 

196 

197 def _end_nested_value(self, section, end): 

198 section.style.dedent() 

199 section.style.dedent() 

200 section.style.new_line() 

201 section.write(end) 

202 

203 

204def document_shared_examples( 

205 section, operation_model, example_prefix, shared_examples 

206): 

207 """Documents the shared examples 

208 

209 :param section: The section to write to. 

210 

211 :param operation_model: The model of the operation. 

212 

213 :param example_prefix: The prefix to use in the method example. 

214 

215 :param shared_examples: The shared JSON examples from the model. 

216 """ 

217 container_section = section.add_new_section('shared-examples') 

218 container_section.style.new_paragraph() 

219 container_section.style.bold('Examples') 

220 documenter = SharedExampleDocumenter() 

221 for example in shared_examples: 

222 documenter.document_shared_example( 

223 example=example, 

224 section=container_section.add_new_section(example['id']), 

225 prefix=example_prefix, 

226 operation_model=operation_model, 

227 )