ch22: new README.md and minor edits
This commit is contained in:
41
22-async/mojifinder/README.md
Normal file
41
22-async/mojifinder/README.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Mojifinder: Unicode character search examples
|
||||||
|
|
||||||
|
Examples from _Fluent Python, Second Edition_—Chapter 22, _Asynchronous Programming_.
|
||||||
|
|
||||||
|
## How to run `web_mojifinder.py`
|
||||||
|
|
||||||
|
`web_mojifinder.py` is a Web application built with _[FastAPI](https://fastapi.tiangolo.com/)_.
|
||||||
|
To run it, first install _FastAPI_ and an ASGI server.
|
||||||
|
The application was tested with _[Uvicorn](https://www.uvicorn.org/)_.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pip install fastapi uvicorn
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can use `uvicorn` to run the app.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ uvicorn web_mojifinder:app
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, visit http://127.0.0.1:8000/ with your browser to see the search form.
|
||||||
|
|
||||||
|
|
||||||
|
## Directory contents
|
||||||
|
|
||||||
|
These files can be run as scripts directly from the command line:
|
||||||
|
|
||||||
|
- `charindex.py`: libray used by the Mojifinder examples. Also works as CLI search script.
|
||||||
|
- `tcp_mojifinder.py`: TCP/IP Unicode search server. Depends only on the Python 3.9 standard library. Use a telnet application as client.
|
||||||
|
- `web_mojifinder_bottle.py`: Unicode Web service. Depends on `bottle.py` and `static/form.html`. Use an HTTP browser as client.
|
||||||
|
|
||||||
|
This program requires an ASGI server to run it:
|
||||||
|
|
||||||
|
- `web_mojifinder.py`: Unicode Web service. Depends on _[FastAPI](https://fastapi.tiangolo.com/)_ and `static/form.html`.
|
||||||
|
|
||||||
|
Support files:
|
||||||
|
|
||||||
|
- `bottle.py`: local copy of the single-file _[Bottle](https://bottlepy.org/)_ Web framework.
|
||||||
|
- `requirements.txt`: list of dependencies for `web_mojifinder.py`.
|
||||||
|
- `static/form.html`: HTML form used by the `web_*` examples.
|
||||||
|
- `README.md`: this file!
|
||||||
@@ -16,7 +16,7 @@ License: MIT (see LICENSE for details)
|
|||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
|
|
||||||
__author__ = 'Marcel Hellkamp'
|
__author__ = 'Marcel Hellkamp'
|
||||||
__version__ = '0.12.18'
|
__version__ = '0.12.19'
|
||||||
__license__ = 'MIT'
|
__license__ = 'MIT'
|
||||||
|
|
||||||
# The gevent server adapter needs to patch some modules before they are imported
|
# The gevent server adapter needs to patch some modules before they are imported
|
||||||
@@ -440,7 +440,7 @@ class Router(object):
|
|||||||
nocheck = set(methods)
|
nocheck = set(methods)
|
||||||
for method in set(self.static) - nocheck:
|
for method in set(self.static) - nocheck:
|
||||||
if path in self.static[method]:
|
if path in self.static[method]:
|
||||||
allowed.add(verb)
|
allowed.add(method)
|
||||||
for method in set(self.dyna_regexes) - allowed - nocheck:
|
for method in set(self.dyna_regexes) - allowed - nocheck:
|
||||||
for combined, rules in self.dyna_regexes[method]:
|
for combined, rules in self.dyna_regexes[method]:
|
||||||
match = combined(path)
|
match = combined(path)
|
||||||
@@ -2585,7 +2585,7 @@ def parse_range_header(header, maxlen=0):
|
|||||||
|
|
||||||
def _parse_qsl(qs):
|
def _parse_qsl(qs):
|
||||||
r = []
|
r = []
|
||||||
for pair in qs.replace(';','&').split('&'):
|
for pair in qs.split('&'):
|
||||||
if not pair: continue
|
if not pair: continue
|
||||||
nv = pair.split('=', 1)
|
nv = pair.split('=', 1)
|
||||||
if len(nv) != 2: nv.append('')
|
if len(nv) != 2: nv.append('')
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
click==7.1.2
|
click==7.1.2
|
||||||
fastapi==0.63.0
|
fastapi==0.63.0
|
||||||
h11==0.12.0
|
h11==0.12.0
|
||||||
pydantic==1.7.3
|
pydantic==1.8.1
|
||||||
starlette==0.13.6
|
starlette==0.13.6
|
||||||
|
typing-extensions==3.7.4.3
|
||||||
uvicorn==0.13.4
|
uvicorn==0.13.4
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import pathlib
|
from pathlib import Path
|
||||||
from unicodedata import name
|
from unicodedata import name
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
@@ -18,9 +18,8 @@ class CharName(BaseModel): # <2>
|
|||||||
|
|
||||||
def init(app): # <3>
|
def init(app): # <3>
|
||||||
app.state.index = InvertedIndex()
|
app.state.index = InvertedIndex()
|
||||||
static = pathlib.Path(__file__).parent.absolute() / 'static' # <4>
|
static = Path(__file__).parent.absolute() / 'static' # <4>
|
||||||
with open(static / 'form.html') as fp:
|
app.state.form = (static / 'form.html').read_text()
|
||||||
app.state.form = fp.read()
|
|
||||||
|
|
||||||
init(app) # <5>
|
init(app) # <5>
|
||||||
|
|
||||||
@@ -33,4 +32,4 @@ async def search(q: str): # <7>
|
|||||||
def form(): # <9>
|
def form(): # <9>
|
||||||
return app.state.form
|
return app.state.form
|
||||||
|
|
||||||
# no main funcion # <10>
|
# no main funcion # <10>
|
||||||
@@ -11,7 +11,7 @@ index = {}
|
|||||||
|
|
||||||
@route('/')
|
@route('/')
|
||||||
def form():
|
def form():
|
||||||
return static_file('form.html', root = 'static/')
|
return static_file('form.html', root='static/')
|
||||||
|
|
||||||
|
|
||||||
@route('/search')
|
@route('/search')
|
||||||
@@ -28,10 +28,8 @@ def search():
|
|||||||
def main(port):
|
def main(port):
|
||||||
global index
|
global index
|
||||||
index = InvertedIndex()
|
index = InvertedIndex()
|
||||||
host = 'localhost'
|
|
||||||
run(host='localhost', port=port, debug=True)
|
run(host='localhost', port=port, debug=True)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main(8000)
|
main(8000)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user