Skip to content
This repository was archived by the owner on Dec 2, 2021. It is now read-only.

Commit eeb6b3d

Browse files
committed
some chapter 17 examples updated for Python 3.7
1 parent 3dd1174 commit eeb6b3d

File tree

7 files changed

+254
-0
lines changed

7 files changed

+254
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.vscode/
2+
.venv3?/
13
*.sublime-project
24
*.sublime-workspace
35
.env*

17-futures-py3.7/README.rst

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Updated sample code for Chapter 17 - "Concurrency with futures"
2+
3+
From the book "Fluent Python" by Luciano Ramalho (O'Reilly, 2015)
4+
http://shop.oreilly.com/product/0636920032519.do
5+
6+
This directory contains code updated to run with Python 3.7 and
7+
**aiohttp** 3.5. When the first edition of "Fluent Python" was
8+
written, the **asyncio** package was provisional, and the latest
9+
version of **aiohttp** was 0.13.1. The API for both packages had
10+
significant breaking changes.

17-futures-py3.7/countries/flags.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""Download flags of top 20 countries by population
2+
3+
Sequential version
4+
5+
Sample run::
6+
7+
$ python3 flags.py
8+
BD BR CD CN DE EG ET FR ID IN IR JP MX NG PH PK RU TR US VN
9+
20 flags downloaded in 5.49s
10+
11+
"""
12+
# BEGIN FLAGS_PY
13+
import os
14+
import time
15+
import sys
16+
17+
import requests # <1>
18+
19+
POP20_CC = ('CN IN US ID BR PK NG BD RU JP '
20+
'MX PH VN ET EG DE IR TR CD FR').split() # <2>
21+
22+
BASE_URL = 'http://flupy.org/data/flags' # <3>
23+
24+
DEST_DIR = 'downloads/' # <4>
25+
26+
27+
def save_flag(img, filename): # <5>
28+
path = os.path.join(DEST_DIR, filename)
29+
with open(path, 'wb') as fp:
30+
fp.write(img)
31+
32+
33+
def get_flag(cc): # <6>
34+
url = '{}/{cc}/{cc}.gif'.format(BASE_URL, cc=cc.lower())
35+
resp = requests.get(url)
36+
return resp.content
37+
38+
39+
def show(text): # <7>
40+
print(text, end=' ')
41+
sys.stdout.flush()
42+
43+
44+
def download_many(cc_list): # <8>
45+
for cc in sorted(cc_list): # <9>
46+
image = get_flag(cc)
47+
show(cc)
48+
save_flag(image, cc.lower() + '.gif')
49+
50+
return len(cc_list)
51+
52+
53+
def main(): # <10>
54+
t0 = time.time()
55+
count = download_many(POP20_CC)
56+
elapsed = time.time() - t0
57+
msg = '\n{} flags downloaded in {:.2f}s'
58+
print(msg.format(count, elapsed))
59+
60+
61+
if __name__ == '__main__':
62+
main()
63+
# END FLAGS_PY
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""Download flags of top 20 countries by population
2+
3+
asyncio + aiottp version
4+
5+
Sample run::
6+
7+
$ python3 flags_asyncio.py
8+
CN EG BR IN ID RU NG VN JP DE TR PK FR ET MX PH US IR CD BD
9+
20 flags downloaded in 0.35s
10+
11+
"""
12+
# BEGIN FLAGS_ASYNCIO
13+
import os
14+
import time
15+
import sys
16+
import asyncio # <1>
17+
18+
import aiohttp # <2>
19+
20+
21+
POP20_CC = ('CN IN US ID BR PK NG BD RU JP '
22+
'MX PH VN ET EG DE IR TR CD FR').split()
23+
24+
BASE_URL = 'http://flupy.org/data/flags'
25+
26+
DEST_DIR = 'downloads/'
27+
28+
29+
def save_flag(img, filename):
30+
path = os.path.join(DEST_DIR, filename)
31+
with open(path, 'wb') as fp:
32+
fp.write(img)
33+
34+
35+
async def get_flag(session, cc): # <3>
36+
url = '{}/{cc}/{cc}.gif'.format(BASE_URL, cc=cc.lower())
37+
async with session.get(url) as resp: # <4>
38+
return await resp.read() # <5>
39+
40+
41+
def show(text):
42+
print(text, end=' ')
43+
sys.stdout.flush()
44+
45+
46+
async def download_one(session, cc): # <6>
47+
image = await get_flag(session, cc) # <7>
48+
show(cc)
49+
save_flag(image, cc.lower() + '.gif')
50+
return cc
51+
52+
53+
async def download_many(cc_list):
54+
async with aiohttp.ClientSession() as session: # <8>
55+
res = await asyncio.gather( # <9>
56+
*[asyncio.create_task(download_one(session, cc))
57+
for cc in sorted(cc_list)])
58+
59+
return len(res)
60+
61+
62+
def main(): # <10>
63+
t0 = time.time()
64+
count = asyncio.run(download_many(POP20_CC))
65+
elapsed = time.time() - t0
66+
msg = '\n{} flags downloaded in {:.2f}s'
67+
print(msg.format(count, elapsed))
68+
69+
70+
if __name__ == '__main__':
71+
main()
72+
# END FLAGS_ASYNCIO
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""Download flags of top 20 countries by population
2+
3+
ThreadPoolExecutor version
4+
5+
Sample run::
6+
7+
$ python3 flags_threadpool.py
8+
DE FR BD CN EG RU IN TR VN ID JP BR NG MX PK ET PH CD US IR
9+
20 flags downloaded in 0.35s
10+
11+
"""
12+
# BEGIN FLAGS_THREADPOOL
13+
import os
14+
import time
15+
import sys
16+
from concurrent import futures # <1>
17+
18+
import requests
19+
20+
POP20_CC = ('CN IN US ID BR PK NG BD RU JP '
21+
'MX PH VN ET EG DE IR TR CD FR').split()
22+
23+
BASE_URL = 'http://flupy.org/data/flags'
24+
25+
DEST_DIR = 'downloads/'
26+
27+
MAX_WORKERS = 20 # <2>
28+
29+
def save_flag(img, filename):
30+
path = os.path.join(DEST_DIR, filename)
31+
with open(path, 'wb') as fp:
32+
fp.write(img)
33+
34+
35+
def get_flag(cc):
36+
url = '{}/{cc}/{cc}.gif'.format(BASE_URL, cc=cc.lower())
37+
resp = requests.get(url)
38+
return resp.content
39+
40+
41+
def show(text):
42+
print(text, end=' ')
43+
sys.stdout.flush()
44+
45+
46+
def download_one(cc): # <3>
47+
image = get_flag(cc)
48+
show(cc)
49+
save_flag(image, cc.lower() + '.gif')
50+
return cc
51+
52+
53+
def download_many(cc_list):
54+
workers = min(MAX_WORKERS, len(cc_list)) # <4>
55+
with futures.ThreadPoolExecutor(workers) as executor: # <5>
56+
res = executor.map(download_one, sorted(cc_list)) # <6>
57+
58+
return len(list(res)) # <7>
59+
60+
61+
def main(): # <10>
62+
t0 = time.time()
63+
count = download_many(POP20_CC)
64+
elapsed = time.time() - t0
65+
msg = '\n{} flags downloaded in {:.2f}s'
66+
print(msg.format(count, elapsed))
67+
68+
69+
if __name__ == '__main__':
70+
main()
71+
# END FLAGS_THREADPOOL
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
requests==2.21.0
2+
aiohttp==3.5.4

17-futures-py3.7/demo_executor_map.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""
2+
Experiment with ``ThreadPoolExecutor.map``
3+
"""
4+
# BEGIN EXECUTOR_MAP
5+
from time import sleep, strftime
6+
from concurrent import futures
7+
8+
9+
def display(*args): # <1>
10+
print(strftime('[%H:%M:%S]'), end=' ')
11+
print(*args)
12+
13+
14+
def loiter(n): # <2>
15+
msg = '{}loiter({}): doing nothing for {}s...'
16+
display(msg.format('\t'*n, n, n))
17+
sleep(n)
18+
msg = '{}loiter({}): done.'
19+
display(msg.format('\t'*n, n))
20+
return n * 10 # <3>
21+
22+
23+
def main():
24+
display('Script starting.')
25+
executor = futures.ThreadPoolExecutor(max_workers=3) # <4>
26+
results = executor.map(loiter, range(5)) # <5>
27+
display('results:', results) # <6>.
28+
display('Waiting for individual results:')
29+
for i, result in enumerate(results): # <7>
30+
display('result {}: {}'.format(i, result))
31+
32+
33+
main()
34+
# END EXECUTOR_MAP

0 commit comments

Comments
 (0)