Skip to content

Commit 31e2c4f

Browse files
committed
flags2 await refactoring start
1 parent 22cfc8d commit 31e2c4f

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
"""Download flags of countries (with error handling).
2+
3+
asyncio version
4+
5+
Sample run::
6+
7+
$ python3 flags2_asyncio.py -s ERROR -e -m 200
8+
ERROR site: http://localhost:8003/flags
9+
Searching for 676 flags: from AA to ZZ
10+
200 concurrent connections will be used.
11+
--------------------
12+
146 flags downloaded.
13+
363 not found.
14+
167 errors.
15+
Elapsed time: 2.59s
16+
17+
"""
18+
# BEGIN FLAGS2_ASYNCIO_TOP
19+
importasyncio
20+
importcollections
21+
22+
importaiohttp
23+
fromaiohttpimportweb
24+
importtqdm
25+
26+
fromflags2_commonimportmain, HTTPStatus, Result, save_flag
27+
28+
# default set low to avoid errors from remote site, such as
29+
# 503 - Service Temporarily Unavailable
30+
DEFAULT_CONCUR_REQ=5
31+
MAX_CONCUR_REQ=1000
32+
33+
34+
classFetchError(Exception): # <1>
35+
def__init__(self, country_code):
36+
self.country_code=country_code
37+
38+
39+
@asyncio.coroutine
40+
defget_flag(base_url, cc): # <2>
41+
url='{}/{cc}/{cc}.gif'.format(base_url, cc=cc.lower())
42+
resp=yieldfromaiohttp.request('GET', url)
43+
ifresp.status==200:
44+
image=yieldfromresp.read()
45+
returnimage
46+
elifresp.status==404:
47+
raiseweb.HTTPNotFound()
48+
else:
49+
raiseaiohttp.HttpProcessingError(
50+
code=resp.status, message=resp.reason,
51+
headers=resp.headers)
52+
53+
54+
@asyncio.coroutine
55+
defdownload_one(cc, base_url, semaphore, verbose): # <3>
56+
try:
57+
with (yieldfromsemaphore): # <4>
58+
image=yieldfromget_flag(base_url, cc) # <5>
59+
exceptweb.HTTPNotFound: # <6>
60+
status=HTTPStatus.not_found
61+
msg='not found'
62+
exceptExceptionasexc:
63+
raiseFetchError(cc) fromexc# <7>
64+
else:
65+
save_flag(image, cc.lower() +'.gif') # <8>
66+
status=HTTPStatus.ok
67+
msg='OK'
68+
69+
ifverboseandmsg:
70+
print(cc, msg)
71+
72+
returnResult(status, cc)
73+
# END FLAGS2_ASYNCIO_TOP
74+
75+
# BEGIN FLAGS2_ASYNCIO_DOWNLOAD_MANY
76+
@asyncio.coroutine
77+
defdownloader_coro(cc_list, base_url, verbose, concur_req): # <1>
78+
counter=collections.Counter()
79+
semaphore=asyncio.Semaphore(concur_req) # <2>
80+
to_do= [download_one(cc, base_url, semaphore, verbose)
81+
forccinsorted(cc_list)] # <3>
82+
83+
to_do_iter=asyncio.as_completed(to_do) # <4>
84+
ifnotverbose:
85+
to_do_iter=tqdm.tqdm(to_do_iter, total=len(cc_list)) # <5>
86+
forfutureinto_do_iter: # <6>
87+
try:
88+
res=yieldfromfuture# <7>
89+
exceptFetchErrorasexc: # <8>
90+
country_code=exc.country_code# <9>
91+
try:
92+
error_msg=exc.__cause__.args[0] # <10>
93+
exceptIndexError:
94+
error_msg=exc.__cause__.__class__.__name__# <11>
95+
ifverboseanderror_msg:
96+
msg='*** Error for{}:{}'
97+
print(msg.format(country_code, error_msg))
98+
status=HTTPStatus.error
99+
else:
100+
status=res.status
101+
102+
counter[status] +=1# <12>
103+
104+
returncounter# <13>
105+
106+
107+
defdownload_many(cc_list, base_url, verbose, concur_req):
108+
loop=asyncio.get_event_loop()
109+
coro=downloader_coro(cc_list, base_url, verbose, concur_req)
110+
counts=loop.run_until_complete(coro) # <14>
111+
loop.close() # <15>
112+
113+
returncounts
114+
115+
116+
if__name__=='__main__':
117+
main(download_many, DEFAULT_CONCUR_REQ, MAX_CONCUR_REQ)
118+
# END FLAGS2_ASYNCIO_DOWNLOAD_MANY

0 commit comments

Comments
(0)