Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/boto3/resources/action.py: 27%

70 statements  

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

1# Copyright 2014 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# https://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. 

13 

14import logging 

15 

16from botocore import xform_name 

17 

18from boto3.docs.docstring import ActionDocstring 

19from boto3.utils import inject_attribute 

20 

21from .model import Action 

22from .params import create_request_parameters 

23from .response import RawHandler, ResourceHandler 

24 

25logger = logging.getLogger(__name__) 

26 

27 

28class ServiceAction: 

29 """ 

30 A class representing a callable action on a resource, for example 

31 ``sqs.get_queue_by_name(...)`` or ``s3.Bucket('foo').delete()``. 

32 The action may construct parameters from existing resource identifiers 

33 and may return either a raw response or a new resource instance. 

34 

35 :type action_model: :py:class`~boto3.resources.model.Action` 

36 :param action_model: The action model. 

37 

38 :type factory: ResourceFactory 

39 :param factory: The factory that created the resource class to which 

40 this action is attached. 

41 

42 :type service_context: :py:class:`~boto3.utils.ServiceContext` 

43 :param service_context: Context about the AWS service 

44 """ 

45 

46 def __init__(self, action_model, factory=None, service_context=None): 

47 self._action_model = action_model 

48 

49 # In the simplest case we just return the response, but if a 

50 # resource is defined, then we must create these before returning. 

51 resource_response_model = action_model.resource 

52 if resource_response_model: 

53 self._response_handler = ResourceHandler( 

54 search_path=resource_response_model.path, 

55 factory=factory, 

56 resource_model=resource_response_model, 

57 service_context=service_context, 

58 operation_name=action_model.request.operation, 

59 ) 

60 else: 

61 self._response_handler = RawHandler(action_model.path) 

62 

63 def __call__(self, parent, *args, **kwargs): 

64 """ 

65 Perform the action's request operation after building operation 

66 parameters and build any defined resources from the response. 

67 

68 :type parent: :py:class:`~boto3.resources.base.ServiceResource` 

69 :param parent: The resource instance to which this action is attached. 

70 :rtype: dict or ServiceResource or list(ServiceResource) 

71 :return: The response, either as a raw dict or resource instance(s). 

72 """ 

73 operation_name = xform_name(self._action_model.request.operation) 

74 

75 # First, build predefined params and then update with the 

76 # user-supplied kwargs, which allows overriding the pre-built 

77 # params if needed. 

78 params = create_request_parameters(parent, self._action_model.request) 

79 params.update(kwargs) 

80 

81 logger.debug( 

82 'Calling %s:%s with %r', 

83 parent.meta.service_name, 

84 operation_name, 

85 params, 

86 ) 

87 

88 response = getattr(parent.meta.client, operation_name)(*args, **params) 

89 

90 logger.debug('Response: %r', response) 

91 

92 return self._response_handler(parent, params, response) 

93 

94 

95class BatchAction(ServiceAction): 

96 """ 

97 An action which operates on a batch of items in a collection, typically 

98 a single page of results from the collection's underlying service 

99 operation call. For example, this allows you to delete up to 999 

100 S3 objects in a single operation rather than calling ``.delete()`` on 

101 each one individually. 

102 

103 :type action_model: :py:class`~boto3.resources.model.Action` 

104 :param action_model: The action model. 

105 

106 :type factory: ResourceFactory 

107 :param factory: The factory that created the resource class to which 

108 this action is attached. 

109 

110 :type service_context: :py:class:`~boto3.utils.ServiceContext` 

111 :param service_context: Context about the AWS service 

112 """ 

113 

114 def __call__(self, parent, *args, **kwargs): 

115 """ 

116 Perform the batch action's operation on every page of results 

117 from the collection. 

118 

119 :type parent: 

120 :py:class:`~boto3.resources.collection.ResourceCollection` 

121 :param parent: The collection iterator to which this action 

122 is attached. 

123 :rtype: list(dict) 

124 :return: A list of low-level response dicts from each call. 

125 """ 

126 service_name = None 

127 client = None 

128 responses = [] 

129 operation_name = xform_name(self._action_model.request.operation) 

130 

131 # Unlike the simple action above, a batch action must operate 

132 # on batches (or pages) of items. So we get each page, construct 

133 # the necessary parameters and call the batch operation. 

134 for page in parent.pages(): 

135 params = {} 

136 for index, resource in enumerate(page): 

137 # There is no public interface to get a service name 

138 # or low-level client from a collection, so we get 

139 # these from the first resource in the collection. 

140 if service_name is None: 

141 service_name = resource.meta.service_name 

142 if client is None: 

143 client = resource.meta.client 

144 

145 create_request_parameters( 

146 resource, 

147 self._action_model.request, 

148 params=params, 

149 index=index, 

150 ) 

151 

152 if not params: 

153 # There are no items, no need to make a call. 

154 break 

155 

156 params.update(kwargs) 

157 

158 logger.debug( 

159 'Calling %s:%s with %r', service_name, operation_name, params 

160 ) 

161 

162 response = getattr(client, operation_name)(*args, **params) 

163 

164 logger.debug('Response: %r', response) 

165 

166 responses.append(self._response_handler(parent, params, response)) 

167 

168 return responses 

169 

170 

171class WaiterAction: 

172 """ 

173 A class representing a callable waiter action on a resource, for example 

174 ``s3.Bucket('foo').wait_until_bucket_exists()``. 

175 The waiter action may construct parameters from existing resource 

176 identifiers. 

177 

178 :type waiter_model: :py:class`~boto3.resources.model.Waiter` 

179 :param waiter_model: The action waiter. 

180 :type waiter_resource_name: string 

181 :param waiter_resource_name: The name of the waiter action for the 

182 resource. It usually begins with a 

183 ``wait_until_`` 

184 """ 

185 

186 def __init__(self, waiter_model, waiter_resource_name): 

187 self._waiter_model = waiter_model 

188 self._waiter_resource_name = waiter_resource_name 

189 

190 def __call__(self, parent, *args, **kwargs): 

191 """ 

192 Perform the wait operation after building operation 

193 parameters. 

194 

195 :type parent: :py:class:`~boto3.resources.base.ServiceResource` 

196 :param parent: The resource instance to which this action is attached. 

197 """ 

198 client_waiter_name = xform_name(self._waiter_model.waiter_name) 

199 

200 # First, build predefined params and then update with the 

201 # user-supplied kwargs, which allows overriding the pre-built 

202 # params if needed. 

203 params = create_request_parameters(parent, self._waiter_model) 

204 params.update(kwargs) 

205 

206 logger.debug( 

207 'Calling %s:%s with %r', 

208 parent.meta.service_name, 

209 self._waiter_resource_name, 

210 params, 

211 ) 

212 

213 client = parent.meta.client 

214 waiter = client.get_waiter(client_waiter_name) 

215 response = waiter.wait(**params) 

216 

217 logger.debug('Response: %r', response) 

218 

219 

220class CustomModeledAction: 

221 """A custom, modeled action to inject into a resource.""" 

222 

223 def __init__(self, action_name, action_model, function, event_emitter): 

224 """ 

225 :type action_name: str 

226 :param action_name: The name of the action to inject, e.g. 

227 'delete_tags' 

228 

229 :type action_model: dict 

230 :param action_model: A JSON definition of the action, as if it were 

231 part of the resource model. 

232 

233 :type function: function 

234 :param function: The function to perform when the action is called. 

235 The first argument should be 'self', which will be the resource 

236 the function is to be called on. 

237 

238 :type event_emitter: :py:class:`botocore.hooks.BaseEventHooks` 

239 :param event_emitter: The session event emitter. 

240 """ 

241 self.name = action_name 

242 self.model = action_model 

243 self.function = function 

244 self.emitter = event_emitter 

245 

246 def inject(self, class_attributes, service_context, event_name, **kwargs): 

247 resource_name = event_name.rsplit(".")[-1] 

248 action = Action(self.name, self.model, {}) 

249 self.function.__name__ = self.name 

250 self.function.__doc__ = ActionDocstring( 

251 resource_name=resource_name, 

252 event_emitter=self.emitter, 

253 action_model=action, 

254 service_model=service_context.service_model, 

255 include_signature=False, 

256 ) 

257 inject_attribute(class_attributes, self.name, self.function)