Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitdaa096e

Browse files
committed
files for chapter 18B - async/await
1 parent5e3d379 commitdaa096e

File tree

10 files changed

+662
-0
lines changed

10 files changed

+662
-0
lines changed

‎18b-async-await/README.rst‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Sample code for Chapter 18 - "Concurrency with asyncio"
2+
3+
From the book "Fluent Python" by Luciano Ramalho (O'Reilly, 2015)
4+
http://shop.oreilly.com/product/0636920032519.do
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Unicode character finder utility:
5+
find characters based on words in their official names.
6+
7+
This can be used from the command line, just pass words as arguments.
8+
9+
Here is the ``main`` function which makes it happen::
10+
11+
>>> main('rook') # doctest: +NORMALIZE_WHITESPACE
12+
U+2656 ♖ WHITE CHESS ROOK
13+
U+265C ♜ BLACK CHESS ROOK
14+
(2 matches for 'rook')
15+
>>> main('rook', 'black') # doctest: +NORMALIZE_WHITESPACE
16+
U+265C ♜ BLACK CHESS ROOK
17+
(1 match for 'rook black')
18+
>>> main('white bishop') # doctest: +NORMALIZE_WHITESPACE
19+
U+2657 ♗ WHITE CHESS BISHOP
20+
(1 match for 'white bishop')
21+
>>> main("jabberwocky's vest")
22+
(No match for "jabberwocky's vest")
23+
24+
25+
For exploring words that occur in the character names, there is the
26+
``word_report`` function::
27+
28+
>>> index = UnicodeNameIndex(sample_chars)
29+
>>> index.word_report()
30+
3 SIGN
31+
2 A
32+
2 EURO
33+
2 LATIN
34+
2 LETTER
35+
1 CAPITAL
36+
1 CURRENCY
37+
1 DOLLAR
38+
1 SMALL
39+
>>> index = UnicodeNameIndex()
40+
>>> index.word_report(10)
41+
75821 CJK
42+
75761 IDEOGRAPH
43+
74656 UNIFIED
44+
13196 SYLLABLE
45+
11735 HANGUL
46+
7616 LETTER
47+
2232 WITH
48+
2180 SIGN
49+
2122 SMALL
50+
1709 CAPITAL
51+
52+
Note: characters with names starting with 'CJK UNIFIED IDEOGRAPH'
53+
are indexed with those three words only, excluding the hexadecimal
54+
codepoint at the end of the name.
55+
56+
"""
57+
58+
importsys
59+
importre
60+
importunicodedata
61+
importpickle
62+
importwarnings
63+
importitertools
64+
importfunctools
65+
fromcollectionsimportnamedtuple
66+
67+
RE_WORD=re.compile('\w+')
68+
RE_UNICODE_NAME=re.compile('^[A-Z0-9 -]+$')
69+
RE_CODEPOINT=re.compile('U\+([0-9A-F]{4,6})')
70+
71+
INDEX_NAME='charfinder_index.pickle'
72+
MINIMUM_SAVE_LEN=10000
73+
CJK_UNI_PREFIX='CJK UNIFIED IDEOGRAPH'
74+
CJK_CMP_PREFIX='CJK COMPATIBILITY IDEOGRAPH'
75+
76+
sample_chars= [
77+
'$',# DOLLAR SIGN
78+
'A',# LATIN CAPITAL LETTER A
79+
'a',# LATIN SMALL LETTER A
80+
'\u20a0',# EURO-CURRENCY SIGN
81+
'\u20ac',# EURO SIGN
82+
]
83+
84+
CharDescription=namedtuple('CharDescription','code_str char name')
85+
86+
QueryResult=namedtuple('QueryResult','count items')
87+
88+
89+
deftokenize(text):
90+
"""return iterable of uppercased words"""
91+
formatchinRE_WORD.finditer(text):
92+
yieldmatch.group().upper()
93+
94+
95+
defquery_type(text):
96+
text_upper=text.upper()
97+
if'U+'intext_upper:
98+
return'CODEPOINT'
99+
elifRE_UNICODE_NAME.match(text_upper):
100+
return'NAME'
101+
else:
102+
return'CHARACTERS'
103+
104+
105+
classUnicodeNameIndex:
106+
107+
def__init__(self,chars=None):
108+
self.load(chars)
109+
110+
defload(self,chars=None):
111+
self.index=None
112+
ifcharsisNone:
113+
try:
114+
withopen(INDEX_NAME,'rb')asfp:
115+
self.index=pickle.load(fp)
116+
exceptOSError:
117+
pass
118+
ifself.indexisNone:
119+
self.build_index(chars)
120+
iflen(self.index)>MINIMUM_SAVE_LEN:
121+
try:
122+
self.save()
123+
exceptOSErrorasexc:
124+
warnings.warn('Could not save {!r}: {}'
125+
.format(INDEX_NAME,exc))
126+
127+
defsave(self):
128+
withopen(INDEX_NAME,'wb')asfp:
129+
pickle.dump(self.index,fp)
130+
131+
defbuild_index(self,chars=None):
132+
ifcharsisNone:
133+
chars= (chr(i)foriinrange(32,sys.maxunicode))
134+
index= {}
135+
forcharinchars:
136+
try:
137+
name=unicodedata.name(char)
138+
exceptValueError:
139+
continue
140+
ifname.startswith(CJK_UNI_PREFIX):
141+
name=CJK_UNI_PREFIX
142+
elifname.startswith(CJK_CMP_PREFIX):
143+
name=CJK_CMP_PREFIX
144+
145+
forwordintokenize(name):
146+
index.setdefault(word,set()).add(char)
147+
148+
self.index=index
149+
150+
defword_rank(self,top=None):
151+
res= [(len(self.index[key]),key)forkeyinself.index]
152+
res.sort(key=lambdaitem: (-item[0],item[1]))
153+
iftopisnotNone:
154+
res=res[:top]
155+
returnres
156+
157+
defword_report(self,top=None):
158+
forpostings,keyinself.word_rank(top):
159+
print('{:5} {}'.format(postings,key))
160+
161+
deffind_chars(self,query,start=0,stop=None):
162+
stop=sys.maxsizeifstopisNoneelsestop
163+
result_sets= []
164+
forwordintokenize(query):
165+
chars=self.index.get(word)
166+
ifcharsisNone:# shorcut: no such word
167+
result_sets= []
168+
break
169+
result_sets.append(chars)
170+
171+
ifnotresult_sets:
172+
returnQueryResult(0, ())
173+
174+
result=functools.reduce(set.intersection,result_sets)
175+
result=sorted(result)# must sort to support start, stop
176+
result_iter=itertools.islice(result,start,stop)
177+
returnQueryResult(len(result),
178+
(charforcharinresult_iter))
179+
180+
defdescribe(self,char):
181+
code_str='U+{:04X}'.format(ord(char))
182+
name=unicodedata.name(char)
183+
returnCharDescription(code_str,char,name)
184+
185+
deffind_descriptions(self,query,start=0,stop=None):
186+
forcharinself.find_chars(query,start,stop).items:
187+
yieldself.describe(char)
188+
189+
defget_descriptions(self,chars):
190+
forcharinchars:
191+
yieldself.describe(char)
192+
193+
defdescribe_str(self,char):
194+
return'{:7}\t{}\t{}'.format(*self.describe(char))
195+
196+
deffind_description_strs(self,query,start=0,stop=None):
197+
forcharinself.find_chars(query,start,stop).items:
198+
yieldself.describe_str(char)
199+
200+
@staticmethod# not an instance method due to concurrency
201+
defstatus(query,counter):
202+
ifcounter==0:
203+
msg='No match'
204+
elifcounter==1:
205+
msg='1 match'
206+
else:
207+
msg='{} matches'.format(counter)
208+
return'{} for {!r}'.format(msg,query)
209+
210+
211+
defmain(*args):
212+
index=UnicodeNameIndex()
213+
query=' '.join(args)
214+
n=0
215+
forn,lineinenumerate(index.find_description_strs(query),1):
216+
print(line)
217+
print('({})'.format(index.status(query,n)))
218+
219+
if__name__=='__main__':
220+
iflen(sys.argv)>1:
221+
main(*sys.argv[1:])
222+
else:
223+
print('Usage: {} word1 [word2]...'.format(sys.argv[0]))
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!DOCTYPE html>
2+
<htmllang="en">
3+
<head>
4+
<metacharset="utf-8">
5+
<title>Charfinder</title>
6+
</head>
7+
<body>
8+
Examples: {links}
9+
<p>
10+
<formaction="/">
11+
<inputtype="search"name="query"value="{query}">
12+
<inputtype="submit"value="find"> {message}
13+
</form>
14+
</p>
15+
<table>
16+
{result}
17+
</table>
18+
</body>
19+
</html>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env python3
2+
3+
importsys
4+
importasyncio
5+
fromaiohttpimportweb
6+
7+
fromcharfinderimportUnicodeNameIndex
8+
9+
TEMPLATE_NAME='http_charfinder.html'
10+
CONTENT_TYPE='text/html; charset=UTF-8'
11+
SAMPLE_WORDS= ('bismillah chess cat circled Malayalam digit'
12+
' Roman face Ethiopic black mark symbol dot'
13+
' operator Braille hexagram').split()
14+
15+
ROW_TPL='<tr><td>{code_str}</td><th>{char}</th><td>{name}</td></tr>'
16+
LINK_TPL='<a href="/?query={0}" title="find &quot;{0}&quot;">{0}</a>'
17+
LINKS_HTML=', '.join(LINK_TPL.format(word)forwordin
18+
sorted(SAMPLE_WORDS,key=str.upper))
19+
20+
21+
index=UnicodeNameIndex()
22+
withopen(TEMPLATE_NAME)astpl:
23+
template=tpl.read()
24+
template=template.replace('{links}',LINKS_HTML)
25+
26+
# BEGIN HTTP_CHARFINDER_HOME
27+
defhome(request):# <1>
28+
query=request.GET.get('query','').strip()# <2>
29+
print('Query: {!r}'.format(query))# <3>
30+
ifquery:# <4>
31+
descriptions=list(index.find_descriptions(query))
32+
res='\n'.join(ROW_TPL.format(**vars(descr))
33+
fordescrindescriptions)
34+
msg=index.status(query,len(descriptions))
35+
else:
36+
descriptions= []
37+
res=''
38+
msg='Enter words describing characters.'
39+
40+
html=template.format(query=query,result=res,# <5>
41+
message=msg)
42+
print('Sending {} results'.format(len(descriptions)))# <6>
43+
returnweb.Response(content_type=CONTENT_TYPE,text=html)# <7>
44+
# END HTTP_CHARFINDER_HOME
45+
46+
47+
# BEGIN HTTP_CHARFINDER_SETUP
48+
@asyncio.coroutine
49+
definit(loop,address,port):# <1>
50+
app=web.Application(loop=loop)# <2>
51+
app.router.add_route('GET','/',home)# <3>
52+
handler=app.make_handler()# <4>
53+
server=yieldfromloop.create_server(handler,
54+
address,port)# <5>
55+
returnserver.sockets[0].getsockname()# <6>
56+
57+
defmain(address="127.0.0.1",port=8888):
58+
port=int(port)
59+
loop=asyncio.get_event_loop()
60+
host=loop.run_until_complete(init(loop,address,port))# <7>
61+
print('Serving on {}. Hit CTRL-C to stop.'.format(host))
62+
try:
63+
loop.run_forever()# <8>
64+
exceptKeyboardInterrupt:# CTRL+C pressed
65+
pass
66+
print('Server shutting down.')
67+
loop.close()# <9>
68+
69+
70+
if__name__=='__main__':
71+
main(*sys.argv[1:])
72+
# END HTTP_CHARFINDER_SETUP
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env python3
2+
3+
# BEGIN TCP_CHARFINDER_TOP
4+
importsys
5+
importasyncio
6+
7+
fromcharfinderimportUnicodeNameIndex# <1>
8+
9+
CRLF=b'\r\n'
10+
PROMPT=b'?> '
11+
12+
index=UnicodeNameIndex()# <2>
13+
14+
@asyncio.coroutine
15+
defhandle_queries(reader,writer):# <3>
16+
whileTrue:# <4>
17+
writer.write(PROMPT)# can't yield from! # <5>
18+
yieldfromwriter.drain()# must yield from! # <6>
19+
data=yieldfromreader.readline()# <7>
20+
try:
21+
query=data.decode().strip()
22+
exceptUnicodeDecodeError:# <8>
23+
query='\x00'
24+
client=writer.get_extra_info('peername')# <9>
25+
print('Received from {}: {!r}'.format(client,query))# <10>
26+
ifquery:
27+
iford(query[:1])<32:# <11>
28+
break
29+
lines=list(index.find_description_strs(query))# <12>
30+
iflines:
31+
writer.writelines(line.encode()+CRLFforlineinlines)# <13>
32+
writer.write(index.status(query,len(lines)).encode()+CRLF)# <14>
33+
34+
yieldfromwriter.drain()# <15>
35+
print('Sent {} results'.format(len(lines)))# <16>
36+
37+
print('Close the client socket')# <17>
38+
writer.close()# <18>
39+
# END TCP_CHARFINDER_TOP
40+
41+
# BEGIN TCP_CHARFINDER_MAIN
42+
defmain(address='127.0.0.1',port=2323):# <1>
43+
port=int(port)
44+
loop=asyncio.get_event_loop()
45+
server_coro=asyncio.start_server(handle_queries,address,port,
46+
loop=loop)# <2>
47+
server=loop.run_until_complete(server_coro)# <3>
48+
49+
host=server.sockets[0].getsockname()# <4>
50+
print('Serving on {}. Hit CTRL-C to stop.'.format(host))# <5>
51+
try:
52+
loop.run_forever()# <6>
53+
exceptKeyboardInterrupt:# CTRL+C pressed
54+
pass
55+
56+
print('Server shutting down.')
57+
server.close()# <7>
58+
loop.run_until_complete(server.wait_closed())# <8>
59+
loop.close()# <9>
60+
61+
62+
if__name__=='__main__':
63+
main(*sys.argv[1:])# <10>
64+
# END TCP_CHARFINDER_MAIN

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp