Skip to content

Commit f19d82b

Browse files
committed
Prototype for a somewhat reasonable solution.
1 parent 6f91845 commit f19d82b

File tree

3 files changed

+119
-56
lines changed

3 files changed

+119
-56
lines changed

aws/client.py

Lines changed: 106 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -103,63 +103,93 @@ def cache_key(call):
103103
)
104104

105105

106-
def get_aws_resource(
106+
def get_single_region(
107107
service_name,
108108
method_name,
109109
call_args,
110110
call_kwargs,
111111
cache,
112-
profiles,
113-
regions,
112+
profile,
113+
region,
114114
result_from_error=None,
115115
debug_calls=False,
116116
debug_cache=False,
117117
):
118118
"""
119-
Fetches and yields AWS API JSON responses for all profiles and regions (list params)
119+
Fetches AWS API JSON responses for a single profile and region.
120120
"""
121-
for profile, region in itertools.product(profiles, regions):
122-
call = default_call._replace(
123-
profile=profile,
124-
region=region,
125-
service=service_name,
126-
method=method_name,
127-
args=call_args,
128-
kwargs=call_kwargs,
129-
)
121+
call = default_call._replace(
122+
profile=profile,
123+
region=region,
124+
service=service_name,
125+
method=method_name,
126+
args=call_args,
127+
kwargs=call_kwargs,
128+
)
130129

131-
if debug_calls:
132-
print("calling", call)
130+
if debug_calls:
131+
print("calling", call)
133132

134-
result = None
135-
if cache is not None:
136-
ckey = cache_key(call)
137-
result = cache.get(ckey, None)
133+
result = None
134+
if cache is not None:
135+
ckey = cache_key(call)
136+
result = cache.get(ckey, None)
137+
138+
if debug_cache and result is not None:
139+
print("found cached value for", ckey)
138140

139-
if debug_cache and result is not None:
140-
print("found cached value for", ckey)
141+
if result is None:
142+
client = get_client(call.profile, call.region, call.service)
143+
try:
144+
result = full_results(client, call.method, call.args, call.kwargs)
145+
result["__pytest_meta"] = dict(profile=call.profile, region=call.region)
146+
except botocore.exceptions.ClientError as error:
147+
if result_from_error is None:
148+
raise error
149+
else:
150+
if debug_calls:
151+
print("error fetching resource", error, call)
141152

142-
if result is None:
143-
client = get_client(call.profile, call.region, call.service)
144-
try:
145-
result = full_results(client, call.method, call.args, call.kwargs)
146-
result["__pytest_meta"] = dict(profile=call.profile, region=call.region)
147-
except botocore.exceptions.ClientError as error:
148-
if result_from_error is None:
149-
raise error
150-
else:
151-
if debug_calls:
152-
print("error fetching resource", error, call)
153+
result = result_from_error(error, call)
153154

154-
result = result_from_error(error, call)
155+
if cache is not None:
156+
if debug_cache:
157+
print("setting cache value for", ckey)
155158

156-
if cache is not None:
157-
if debug_cache:
158-
print("setting cache value for", ckey)
159+
cache.set(ckey, result)
159160

160-
cache.set(ckey, result)
161+
return result
161162

162-
yield result
163+
164+
def get_aws_resource(
165+
service_name,
166+
method_name,
167+
call_args,
168+
call_kwargs,
169+
cache,
170+
profiles,
171+
regions,
172+
result_from_error=None,
173+
debug_calls=False,
174+
debug_cache=False,
175+
):
176+
"""
177+
Fetches and yields AWS API JSON responses for all profiles and regions (list params)
178+
"""
179+
for profile in profiles:
180+
for region in regions:
181+
yield get_single_region(
182+
service_name,
183+
method_name,
184+
call_args,
185+
call_kwargs,
186+
cache,
187+
profile,
188+
region,
189+
result_from_error=None,
190+
debug_calls=False,
191+
debug_cache=False,
192+
)
163193

164194

165195
class BotocoreClient:
@@ -176,8 +206,6 @@ def __init__(self, profiles, cache, debug_calls, debug_cache, offline):
176206
else:
177207
self.regions = get_available_regions()
178208

179-
self.results = []
180-
181209
def get_regions(self):
182210
if self.offline:
183211
return []
@@ -204,9 +232,9 @@ def get(
204232
regions = ["us-east-1"]
205233

206234
if self.offline:
207-
self.results = []
235+
results = []
208236
else:
209-
self.results = list(
237+
results = list(
210238
get_aws_resource(
211239
service_name,
212240
method_name,
@@ -221,7 +249,41 @@ def get(
221249
)
222250
)
223251

224-
return self
252+
return BotocoreClientResult(results)
253+
254+
def get_details(
255+
self,
256+
resource,
257+
service_name,
258+
method_name,
259+
call_args,
260+
call_kwargs,
261+
result_from_error=None,
262+
do_not_cache=False,
263+
):
264+
if self.offline:
265+
return None
266+
return get_single_region(
267+
service_name,
268+
method_name,
269+
call_args,
270+
call_kwargs,
271+
profile=resource["__pytest_meta"]["profile"],
272+
region=resource["__pytest_meta"]["region"],
273+
cache=self.cache if not do_not_cache else None,
274+
result_from_error=result_from_error,
275+
debug_calls=self.debug_calls,
276+
debug_cache=self.debug_cache,
277+
)
278+
279+
280+
class BotocoreClientResult:
281+
"""
282+
A result list returned by BotocoreClient.get().
283+
"""
284+
285+
def __init__(self, results):
286+
self.results = results
225287

226288
def values(self):
227289
"""Returns the wrapped value
@@ -315,7 +377,7 @@ def flatten(self):
315377
...
316378
TypeError: can only concatenate list (not "dict") to list
317379
"""
318-
self.results = sum(self.results, [])
380+
self.results = list(itertools.chain.from_iterable(self.results))
319381
return self
320382

321383
def debug(self):

aws/sns/resources.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
from conftest import botocore_client
22

3+
34
def sns_subscriptions():
45
"https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sns.html#subscription"
5-
return(
6+
return (
67
botocore_client.get("sns", "list_subscriptions", [], {})
78
.extract_key("Subscriptions")
89
.flatten()
910
.values()
1011
)
1112

13+
1214
def sns_subscription_attributes():
1315
"https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sns.html#subscription"
14-
return [
15-
botocore_client.get(
16+
for subscription in sns_subscriptions():
17+
yield botocore_client.get_details(
18+
resource=subscription,
1619
service_name="sns",
1720
method_name="get_subscription_attributes",
1821
call_args=[],
1922
call_kwargs={"SubscriptionArn": subscription["SubscriptionArn"]},
20-
)
21-
.extract_key("Attributes")
22-
for subscription in sns_subscriptions()
23-
]
23+
)["Attributes"]

aws/sns/test_sns_pending_verified.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
from aws.sns.resources import sns_subscription_attributes
44

5+
56
@pytest.mark.sns
67
@pytest.mark.parametrize(
7-
"pending_verification",
8-
sns_subscription_attributes(),
9-
ids=lambda subscription: subscription["PendingVerification"],
8+
"subscription_attrs",
9+
sns_subscription_attributes(),
10+
ids=lambda subscription: subscription["SubscriptionArn"],
1011
)
11-
def test_sns_pending_verified(pending_verification):
12-
assert pending_verification == "false"
12+
def test_sns_pending_verified(subscription_attrs):
13+
assert subscription_attrs["PendingConfirmation"] == "false"

0 commit comments

Comments
 (0)