From 9916d83c7ed2bec9a4d3d32ebdfb174d86d9027f Mon Sep 17 00:00:00 2001 From: Bill Lubanovic Date: Sat, 21 Mar 2020 21:19:14 -0500 Subject: [PATCH] Second edition, first upload --- .gitignore | 2 + 1st_edition/README.md | 26 ++++++++ {art => 1st_edition/art}/matplotlib1.py | 0 {art => 1st_edition/art}/panda1.py | 0 {boxes => 1st_edition/boxes}/report.py | 0 {boxes => 1st_edition/boxes}/report2.py | 0 {boxes => 1st_edition/boxes}/test1.py | 0 {boxes => 1st_edition/boxes}/test2.py | 0 {boxes => 1st_edition/boxes}/test3.py | 0 {boxes => 1st_edition/boxes}/weatherman2.py | 0 {boxes => 1st_edition/boxes}/weatherman3.py | 0 {boxes => 1st_edition/boxes}/weatherman4.py | 0 {bus => 1st_edition/bus}/bubbles1.py | 0 {bus => 1st_edition/bus}/map1.py | 0 {bus => 1st_edition/bus}/zoo.csv | 0 {bus => 1st_edition/bus}/zoo_counts.py | 0 {dev => 1st_edition/dev}/cap.py | 0 {dev => 1st_edition/dev}/capitals.py | 0 {dev => 1st_edition/dev}/capitals2.py | 0 {dev => 1st_edition/dev}/cities1.csv | 0 {dev => 1st_edition/dev}/cities2.csv | 0 {dev => 1st_edition/dev}/dump1.py | 0 {dev => 1st_edition/dev}/ftoc1.py | 0 {dev => 1st_edition/dev}/ftoc2.py | 0 {dev => 1st_edition/dev}/style1.py | 0 {dev => 1st_edition/dev}/style2.py | 0 {dev => 1st_edition/dev}/style3.py | 0 {dev => 1st_edition/dev}/test_cap.py | 0 {dev => 1st_edition/dev}/test_cap_nose.py | 0 {dev => 1st_edition/dev}/test_dump.py | 0 {dev => 1st_edition/dev}/time1.py | 0 {dev => 1st_edition/dev}/time2.py | 0 {dev => 1st_edition/dev}/time_lists.py | 0 {dev => 1st_edition/dev}/timeit1.py | 0 {dev => 1st_edition/dev}/timeit2.py | 0 {intro => 1st_edition/intro}/54321.py | 0 {intro => 1st_edition/intro}/61.py | 0 {intro => 1st_edition/intro}/archive.py | 0 {intro => 1st_edition/intro}/archive2.py | 0 {intro => 1st_edition/intro}/cliches.py | 0 {intro => 1st_edition/intro}/im.c | 0 {intro => 1st_edition/intro}/im.cpp | 0 {intro => 1st_edition/intro}/im.java | 0 {intro => 1st_edition/intro}/im.php | 0 {intro => 1st_edition/intro}/im.pl | 0 {intro => 1st_edition/intro}/im.py | 0 {intro => 1st_edition/intro}/im.rb | 0 {intro => 1st_edition/intro}/im.sh | 0 {intro => 1st_edition/intro}/stooges.py | 0 {intro => 1st_edition/intro}/youtube.py | 0 {intro => 1st_edition/intro}/youtube2.py | 0 {net => 1st_edition/net}/dishes.py | 0 {net => 1st_edition/net}/fab1.py | 0 {net => 1st_edition/net}/fab2.py | 0 {net => 1st_edition/net}/fab3.py | 0 {net => 1st_edition/net}/fab4.py | 0 {net => 1st_edition/net}/gevent_monkey.py | 0 {net => 1st_edition/net}/gevent_test.py | 0 {net => 1st_edition/net}/knock_client.py | 0 {net => 1st_edition/net}/knock_server.py | 0 {net => 1st_edition/net}/msppack_client.py | 0 {net => 1st_edition/net}/msppack_server.py | 0 {net => 1st_edition/net}/redis_dryer.py | 0 {net => 1st_edition/net}/redis_dryer2.py | 0 {net => 1st_edition/net}/redis_pub.py | 0 {net => 1st_edition/net}/redis_sub.py | 0 {net => 1st_edition/net}/redis_washer.py | 0 {net => 1st_edition/net}/tcp_client.py | 0 {net => 1st_edition/net}/tcp_server.py | 0 {net => 1st_edition/net}/thread_dishes.py | 0 {net => 1st_edition/net}/threads.py | 0 {net => 1st_edition/net}/udp_client.py | 0 {net => 1st_edition/net}/udp_server.py | 0 {net => 1st_edition/net}/xmlrpc_client.py | 0 {net => 1st_edition/net}/xmlrpc_server.py | 0 {net => 1st_edition/net}/zmq_client.py | 0 {net => 1st_edition/net}/zmq_pub.py | 0 {net => 1st_edition/net}/zmq_server.py | 0 {net => 1st_edition/net}/zmq_sub.py | 0 {storage => 1st_edition/storage}/lolz.xml | 0 .../storage}/mcintyre.yaml | 0 {storage => 1st_edition/storage}/settings.cfg | 0 {sys => 1st_edition/sys}/mp.py | 0 {sys => 1st_edition/sys}/mp3.py | 0 {web => 1st_edition/web}/bottle1.py | 0 {web => 1st_edition/web}/bottle2.py | 0 {web => 1st_edition/web}/bottle3.py | 0 {web => 1st_edition/web}/bottle_test.py | 0 {web => 1st_edition/web}/flask1.py | 0 {web => 1st_edition/web}/flask2.py | 0 {web => 1st_edition/web}/flask3a.py | 0 {web => 1st_edition/web}/flask3b.py | 0 {web => 1st_edition/web}/flask3c.py | 0 {web => 1st_edition/web}/home.wsgi | 0 {web => 1st_edition/web}/links.py | 0 .../web}/templates/flask3.html | 0 .../web}/templates/flasks.html | 0 {web => 1st_edition/web}/templates/home.html | 0 README.md | 27 +------- ch01/archive.py | 19 ++++++ ch01/archive2.py | 16 +++++ ch01/countdown.py | 2 + ch01/quotes.py | 7 ++ ch01/spells.py | 9 +++ ch05/poem.py | 5 ++ ch05/poem2.py | 5 ++ ch05/poem3.py | 6 ++ ch11/choices/advice.oy | 7 ++ ch11/choices/fast.py | 8 +++ ch11/fast.py | 8 +++ ch11/fast2.py | 6 ++ ch11/fast3.py | 4 ++ ch11/fast4.py | 4 ++ ch11/fast5.py | 4 ++ ch11/lunch.py | 4 ++ ch11/questions.py | 4 ++ ch12/mammoth.txt | 24 +++++++ ch14/convert_image.py | 35 ++++++++++ ch15/cf.py | 35 ++++++++++ ch15/cf2.py | 35 ++++++++++ ch15/dishes.py | 20 ++++++ ch15/gevent_monkey.py | 10 +++ ch15/gevent_test.py | 9 +++ ch15/knock_client.py | 25 ++++++++ ch15/knock_server.py | 18 ++++++ ch15/mp.py | 12 ++++ ch15/mp2.py | 21 ++++++ ch15/redis_dryer.py | 13 ++++ ch15/redis_dryer2.py | 26 ++++++++ ch15/redis_washer.py | 11 ++++ ch15/tasks.py | 8 +++ ch15/thread1.py | 14 ++++ ch15/thread_dishes.py | 23 +++++++ ch16/villains.csv | 6 ++ ch17/jsonrpc_client.py | 5 ++ ch17/jsonrpc_server.py | 8 +++ ch17/msgpack_client.py | 6 ++ ch17/msgpack_server.py | 9 +++ ch17/redis_pub.py | 11 ++++ ch17/redis_sub.py | 11 ++++ ch17/tcp_client.py | 13 ++++ ch17/tcp_server.py | 19 ++++++ ch17/udp_client.py | 12 ++++ ch17/udp_server.py | 16 +++++ ch17/xmlrpc_client.py | 6 ++ ch17/xmlrpc_server.py | 8 +++ ch17/zerorpc_client.py | 7 ++ ch17/zerorpc_server.py | 9 +++ ch17/zmq_client.py | 14 ++++ ch17/zmq_pub.py | 19 ++++++ ch17/zmq_server.py | 15 +++++ ch17/zmq_sub.py | 15 +++++ ch18/bottle1.py | 7 ++ ch18/bottle2.py | 7 ++ ch18/bottle3.py | 11 ++++ ch18/bottle_test.py | 8 +++ ch18/flask1.py | 13 ++++ ch18/flask2.html | 8 +++ ch18/flask2.py | 9 +++ ch18/flask3a.py | 9 +++ ch18/flask3b.py | 11 ++++ ch18/flask3c.py | 12 ++++ ch18/home.wsgi | 7 ++ ch18/ia.py | 22 +++++++ ch18/ia_movies.py | 60 ++++++++++++++++++ ch18/links.py | 16 +++++ ch19/cap.py | 2 + ch19/cap.pyc | Bin 0 -> 322 bytes ch19/cap2.py | 15 +++++ ch19/capitals.py | 14 ++++ ch19/capitals2.py | 14 ++++ ch19/cities.csv | 4 ++ ch19/cities2.csv | 15 +++++ ch19/dump.py | 10 +++ ch19/dump.pyc | Bin 0 -> 771 bytes ch19/ftoc1.py | 16 +++++ ch19/ftoc2.py | 17 +++++ ch19/style1.py | 5 ++ ch19/style2.py | 6 ++ ch19/style3.py | 12 ++++ ch19/test.py | 1 + ch19/test_cap.py | 23 +++++++ ch19/test_cap_nose.py | 22 +++++++ ch19/test_dump.py | 11 ++++ ch19/time1.py | 6 ++ ch19/time2.py | 5 ++ ch19/time_lists.py | 14 ++++ ch19/timeit1.py | 3 + ch19/timeit2.py | 3 + 189 files changed, 1115 insertions(+), 24 deletions(-) create mode 100644 .gitignore create mode 100644 1st_edition/README.md rename {art => 1st_edition/art}/matplotlib1.py (100%) rename {art => 1st_edition/art}/panda1.py (100%) rename {boxes => 1st_edition/boxes}/report.py (100%) rename {boxes => 1st_edition/boxes}/report2.py (100%) rename {boxes => 1st_edition/boxes}/test1.py (100%) rename {boxes => 1st_edition/boxes}/test2.py (100%) rename {boxes => 1st_edition/boxes}/test3.py (100%) rename {boxes => 1st_edition/boxes}/weatherman2.py (100%) rename {boxes => 1st_edition/boxes}/weatherman3.py (100%) rename {boxes => 1st_edition/boxes}/weatherman4.py (100%) rename {bus => 1st_edition/bus}/bubbles1.py (100%) rename {bus => 1st_edition/bus}/map1.py (100%) rename {bus => 1st_edition/bus}/zoo.csv (100%) rename {bus => 1st_edition/bus}/zoo_counts.py (100%) rename {dev => 1st_edition/dev}/cap.py (100%) rename {dev => 1st_edition/dev}/capitals.py (100%) rename {dev => 1st_edition/dev}/capitals2.py (100%) rename {dev => 1st_edition/dev}/cities1.csv (100%) rename {dev => 1st_edition/dev}/cities2.csv (100%) rename {dev => 1st_edition/dev}/dump1.py (100%) rename {dev => 1st_edition/dev}/ftoc1.py (100%) rename {dev => 1st_edition/dev}/ftoc2.py (100%) rename {dev => 1st_edition/dev}/style1.py (100%) rename {dev => 1st_edition/dev}/style2.py (100%) rename {dev => 1st_edition/dev}/style3.py (100%) rename {dev => 1st_edition/dev}/test_cap.py (100%) rename {dev => 1st_edition/dev}/test_cap_nose.py (100%) rename {dev => 1st_edition/dev}/test_dump.py (100%) rename {dev => 1st_edition/dev}/time1.py (100%) rename {dev => 1st_edition/dev}/time2.py (100%) rename {dev => 1st_edition/dev}/time_lists.py (100%) rename {dev => 1st_edition/dev}/timeit1.py (100%) rename {dev => 1st_edition/dev}/timeit2.py (100%) rename {intro => 1st_edition/intro}/54321.py (100%) rename {intro => 1st_edition/intro}/61.py (100%) rename {intro => 1st_edition/intro}/archive.py (100%) rename {intro => 1st_edition/intro}/archive2.py (100%) rename {intro => 1st_edition/intro}/cliches.py (100%) rename {intro => 1st_edition/intro}/im.c (100%) rename {intro => 1st_edition/intro}/im.cpp (100%) rename {intro => 1st_edition/intro}/im.java (100%) rename {intro => 1st_edition/intro}/im.php (100%) rename {intro => 1st_edition/intro}/im.pl (100%) rename {intro => 1st_edition/intro}/im.py (100%) rename {intro => 1st_edition/intro}/im.rb (100%) rename {intro => 1st_edition/intro}/im.sh (100%) rename {intro => 1st_edition/intro}/stooges.py (100%) rename {intro => 1st_edition/intro}/youtube.py (100%) rename {intro => 1st_edition/intro}/youtube2.py (100%) rename {net => 1st_edition/net}/dishes.py (100%) rename {net => 1st_edition/net}/fab1.py (100%) rename {net => 1st_edition/net}/fab2.py (100%) rename {net => 1st_edition/net}/fab3.py (100%) rename {net => 1st_edition/net}/fab4.py (100%) rename {net => 1st_edition/net}/gevent_monkey.py (100%) rename {net => 1st_edition/net}/gevent_test.py (100%) rename {net => 1st_edition/net}/knock_client.py (100%) rename {net => 1st_edition/net}/knock_server.py (100%) rename {net => 1st_edition/net}/msppack_client.py (100%) rename {net => 1st_edition/net}/msppack_server.py (100%) rename {net => 1st_edition/net}/redis_dryer.py (100%) rename {net => 1st_edition/net}/redis_dryer2.py (100%) rename {net => 1st_edition/net}/redis_pub.py (100%) rename {net => 1st_edition/net}/redis_sub.py (100%) rename {net => 1st_edition/net}/redis_washer.py (100%) rename {net => 1st_edition/net}/tcp_client.py (100%) rename {net => 1st_edition/net}/tcp_server.py (100%) rename {net => 1st_edition/net}/thread_dishes.py (100%) rename {net => 1st_edition/net}/threads.py (100%) rename {net => 1st_edition/net}/udp_client.py (100%) rename {net => 1st_edition/net}/udp_server.py (100%) rename {net => 1st_edition/net}/xmlrpc_client.py (100%) rename {net => 1st_edition/net}/xmlrpc_server.py (100%) rename {net => 1st_edition/net}/zmq_client.py (100%) rename {net => 1st_edition/net}/zmq_pub.py (100%) rename {net => 1st_edition/net}/zmq_server.py (100%) rename {net => 1st_edition/net}/zmq_sub.py (100%) rename {storage => 1st_edition/storage}/lolz.xml (100%) rename {storage => 1st_edition/storage}/mcintyre.yaml (100%) rename {storage => 1st_edition/storage}/settings.cfg (100%) rename {sys => 1st_edition/sys}/mp.py (100%) rename {sys => 1st_edition/sys}/mp3.py (100%) rename {web => 1st_edition/web}/bottle1.py (100%) rename {web => 1st_edition/web}/bottle2.py (100%) rename {web => 1st_edition/web}/bottle3.py (100%) rename {web => 1st_edition/web}/bottle_test.py (100%) rename {web => 1st_edition/web}/flask1.py (100%) rename {web => 1st_edition/web}/flask2.py (100%) rename {web => 1st_edition/web}/flask3a.py (100%) rename {web => 1st_edition/web}/flask3b.py (100%) rename {web => 1st_edition/web}/flask3c.py (100%) rename {web => 1st_edition/web}/home.wsgi (100%) rename {web => 1st_edition/web}/links.py (100%) rename {web => 1st_edition/web}/templates/flask3.html (100%) rename {web => 1st_edition/web}/templates/flasks.html (100%) rename {web => 1st_edition/web}/templates/home.html (100%) create mode 100644 ch01/archive.py create mode 100644 ch01/archive2.py create mode 100644 ch01/countdown.py create mode 100644 ch01/quotes.py create mode 100644 ch01/spells.py create mode 100644 ch05/poem.py create mode 100644 ch05/poem2.py create mode 100644 ch05/poem3.py create mode 100644 ch11/choices/advice.oy create mode 100644 ch11/choices/fast.py create mode 100644 ch11/fast.py create mode 100644 ch11/fast2.py create mode 100644 ch11/fast3.py create mode 100644 ch11/fast4.py create mode 100644 ch11/fast5.py create mode 100644 ch11/lunch.py create mode 100644 ch11/questions.py create mode 100644 ch12/mammoth.txt create mode 100644 ch14/convert_image.py create mode 100644 ch15/cf.py create mode 100644 ch15/cf2.py create mode 100644 ch15/dishes.py create mode 100644 ch15/gevent_monkey.py create mode 100644 ch15/gevent_test.py create mode 100644 ch15/knock_client.py create mode 100644 ch15/knock_server.py create mode 100644 ch15/mp.py create mode 100644 ch15/mp2.py create mode 100644 ch15/redis_dryer.py create mode 100644 ch15/redis_dryer2.py create mode 100644 ch15/redis_washer.py create mode 100644 ch15/tasks.py create mode 100644 ch15/thread1.py create mode 100644 ch15/thread_dishes.py create mode 100644 ch16/villains.csv create mode 100644 ch17/jsonrpc_client.py create mode 100644 ch17/jsonrpc_server.py create mode 100644 ch17/msgpack_client.py create mode 100644 ch17/msgpack_server.py create mode 100644 ch17/redis_pub.py create mode 100644 ch17/redis_sub.py create mode 100644 ch17/tcp_client.py create mode 100644 ch17/tcp_server.py create mode 100644 ch17/udp_client.py create mode 100644 ch17/udp_server.py create mode 100644 ch17/xmlrpc_client.py create mode 100644 ch17/xmlrpc_server.py create mode 100644 ch17/zerorpc_client.py create mode 100644 ch17/zerorpc_server.py create mode 100644 ch17/zmq_client.py create mode 100644 ch17/zmq_pub.py create mode 100644 ch17/zmq_server.py create mode 100644 ch17/zmq_sub.py create mode 100644 ch18/bottle1.py create mode 100644 ch18/bottle2.py create mode 100644 ch18/bottle3.py create mode 100644 ch18/bottle_test.py create mode 100644 ch18/flask1.py create mode 100644 ch18/flask2.html create mode 100644 ch18/flask2.py create mode 100644 ch18/flask3a.py create mode 100644 ch18/flask3b.py create mode 100644 ch18/flask3c.py create mode 100644 ch18/home.wsgi create mode 100644 ch18/ia.py create mode 100644 ch18/ia_movies.py create mode 100644 ch18/links.py create mode 100644 ch19/cap.py create mode 100644 ch19/cap.pyc create mode 100644 ch19/cap2.py create mode 100644 ch19/capitals.py create mode 100644 ch19/capitals2.py create mode 100644 ch19/cities.csv create mode 100644 ch19/cities2.csv create mode 100644 ch19/dump.py create mode 100644 ch19/dump.pyc create mode 100644 ch19/ftoc1.py create mode 100644 ch19/ftoc2.py create mode 100644 ch19/style1.py create mode 100644 ch19/style2.py create mode 100644 ch19/style3.py create mode 100644 ch19/test.py create mode 100644 ch19/test_cap.py create mode 100644 ch19/test_cap_nose.py create mode 100644 ch19/test_dump.py create mode 100644 ch19/time1.py create mode 100644 ch19/time2.py create mode 100644 ch19/time_lists.py create mode 100644 ch19/timeit1.py create mode 100644 ch19/timeit2.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a60b85 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +*.pyc diff --git a/1st_edition/README.md b/1st_edition/README.md new file mode 100644 index 0000000..296d758 --- /dev/null +++ b/1st_edition/README.md @@ -0,0 +1,26 @@ +Introducing Python +================= + +This repository contains the programs featured in _Introducing Python_. +Some examples have been updated for the second and third printings. + +|directory|chapter| +|---|---| +|[intro](intro)| 1. A taste of Py +| | 2. Py ingredients: numbers, strings, and variables +| | 3. Py filling: lists, tuples, dictionaries, and sets +| | 4. Py crust: code structures +|[boxes](boxes)| 5. Py boxes: modules, packages, and programs +| | 6. Oh oh: objects and classes +| | 7. Mangle data like a pro +|[storage](storage)|8. Data has to go somewhere +|[web](web) | 9. The web, untangled +|[sys](sys) | 10. Systems +|[net](net) | 11. Concurrency and networks +|[dev](dev) | 12. Be a pythonista +|[art](art) | A. Py art +|[bus](bus) | B. Py at work +| | C. Py sci +| | D. Install Python 3 +| | E. Answers to exercises +| | F. Cheatsheets diff --git a/art/matplotlib1.py b/1st_edition/art/matplotlib1.py similarity index 100% rename from art/matplotlib1.py rename to 1st_edition/art/matplotlib1.py diff --git a/art/panda1.py b/1st_edition/art/panda1.py similarity index 100% rename from art/panda1.py rename to 1st_edition/art/panda1.py diff --git a/boxes/report.py b/1st_edition/boxes/report.py similarity index 100% rename from boxes/report.py rename to 1st_edition/boxes/report.py diff --git a/boxes/report2.py b/1st_edition/boxes/report2.py similarity index 100% rename from boxes/report2.py rename to 1st_edition/boxes/report2.py diff --git a/boxes/test1.py b/1st_edition/boxes/test1.py similarity index 100% rename from boxes/test1.py rename to 1st_edition/boxes/test1.py diff --git a/boxes/test2.py b/1st_edition/boxes/test2.py similarity index 100% rename from boxes/test2.py rename to 1st_edition/boxes/test2.py diff --git a/boxes/test3.py b/1st_edition/boxes/test3.py similarity index 100% rename from boxes/test3.py rename to 1st_edition/boxes/test3.py diff --git a/boxes/weatherman2.py b/1st_edition/boxes/weatherman2.py similarity index 100% rename from boxes/weatherman2.py rename to 1st_edition/boxes/weatherman2.py diff --git a/boxes/weatherman3.py b/1st_edition/boxes/weatherman3.py similarity index 100% rename from boxes/weatherman3.py rename to 1st_edition/boxes/weatherman3.py diff --git a/boxes/weatherman4.py b/1st_edition/boxes/weatherman4.py similarity index 100% rename from boxes/weatherman4.py rename to 1st_edition/boxes/weatherman4.py diff --git a/bus/bubbles1.py b/1st_edition/bus/bubbles1.py similarity index 100% rename from bus/bubbles1.py rename to 1st_edition/bus/bubbles1.py diff --git a/bus/map1.py b/1st_edition/bus/map1.py similarity index 100% rename from bus/map1.py rename to 1st_edition/bus/map1.py diff --git a/bus/zoo.csv b/1st_edition/bus/zoo.csv similarity index 100% rename from bus/zoo.csv rename to 1st_edition/bus/zoo.csv diff --git a/bus/zoo_counts.py b/1st_edition/bus/zoo_counts.py similarity index 100% rename from bus/zoo_counts.py rename to 1st_edition/bus/zoo_counts.py diff --git a/dev/cap.py b/1st_edition/dev/cap.py similarity index 100% rename from dev/cap.py rename to 1st_edition/dev/cap.py diff --git a/dev/capitals.py b/1st_edition/dev/capitals.py similarity index 100% rename from dev/capitals.py rename to 1st_edition/dev/capitals.py diff --git a/dev/capitals2.py b/1st_edition/dev/capitals2.py similarity index 100% rename from dev/capitals2.py rename to 1st_edition/dev/capitals2.py diff --git a/dev/cities1.csv b/1st_edition/dev/cities1.csv similarity index 100% rename from dev/cities1.csv rename to 1st_edition/dev/cities1.csv diff --git a/dev/cities2.csv b/1st_edition/dev/cities2.csv similarity index 100% rename from dev/cities2.csv rename to 1st_edition/dev/cities2.csv diff --git a/dev/dump1.py b/1st_edition/dev/dump1.py similarity index 100% rename from dev/dump1.py rename to 1st_edition/dev/dump1.py diff --git a/dev/ftoc1.py b/1st_edition/dev/ftoc1.py similarity index 100% rename from dev/ftoc1.py rename to 1st_edition/dev/ftoc1.py diff --git a/dev/ftoc2.py b/1st_edition/dev/ftoc2.py similarity index 100% rename from dev/ftoc2.py rename to 1st_edition/dev/ftoc2.py diff --git a/dev/style1.py b/1st_edition/dev/style1.py similarity index 100% rename from dev/style1.py rename to 1st_edition/dev/style1.py diff --git a/dev/style2.py b/1st_edition/dev/style2.py similarity index 100% rename from dev/style2.py rename to 1st_edition/dev/style2.py diff --git a/dev/style3.py b/1st_edition/dev/style3.py similarity index 100% rename from dev/style3.py rename to 1st_edition/dev/style3.py diff --git a/dev/test_cap.py b/1st_edition/dev/test_cap.py similarity index 100% rename from dev/test_cap.py rename to 1st_edition/dev/test_cap.py diff --git a/dev/test_cap_nose.py b/1st_edition/dev/test_cap_nose.py similarity index 100% rename from dev/test_cap_nose.py rename to 1st_edition/dev/test_cap_nose.py diff --git a/dev/test_dump.py b/1st_edition/dev/test_dump.py similarity index 100% rename from dev/test_dump.py rename to 1st_edition/dev/test_dump.py diff --git a/dev/time1.py b/1st_edition/dev/time1.py similarity index 100% rename from dev/time1.py rename to 1st_edition/dev/time1.py diff --git a/dev/time2.py b/1st_edition/dev/time2.py similarity index 100% rename from dev/time2.py rename to 1st_edition/dev/time2.py diff --git a/dev/time_lists.py b/1st_edition/dev/time_lists.py similarity index 100% rename from dev/time_lists.py rename to 1st_edition/dev/time_lists.py diff --git a/dev/timeit1.py b/1st_edition/dev/timeit1.py similarity index 100% rename from dev/timeit1.py rename to 1st_edition/dev/timeit1.py diff --git a/dev/timeit2.py b/1st_edition/dev/timeit2.py similarity index 100% rename from dev/timeit2.py rename to 1st_edition/dev/timeit2.py diff --git a/intro/54321.py b/1st_edition/intro/54321.py similarity index 100% rename from intro/54321.py rename to 1st_edition/intro/54321.py diff --git a/intro/61.py b/1st_edition/intro/61.py similarity index 100% rename from intro/61.py rename to 1st_edition/intro/61.py diff --git a/intro/archive.py b/1st_edition/intro/archive.py similarity index 100% rename from intro/archive.py rename to 1st_edition/intro/archive.py diff --git a/intro/archive2.py b/1st_edition/intro/archive2.py similarity index 100% rename from intro/archive2.py rename to 1st_edition/intro/archive2.py diff --git a/intro/cliches.py b/1st_edition/intro/cliches.py similarity index 100% rename from intro/cliches.py rename to 1st_edition/intro/cliches.py diff --git a/intro/im.c b/1st_edition/intro/im.c similarity index 100% rename from intro/im.c rename to 1st_edition/intro/im.c diff --git a/intro/im.cpp b/1st_edition/intro/im.cpp similarity index 100% rename from intro/im.cpp rename to 1st_edition/intro/im.cpp diff --git a/intro/im.java b/1st_edition/intro/im.java similarity index 100% rename from intro/im.java rename to 1st_edition/intro/im.java diff --git a/intro/im.php b/1st_edition/intro/im.php similarity index 100% rename from intro/im.php rename to 1st_edition/intro/im.php diff --git a/intro/im.pl b/1st_edition/intro/im.pl similarity index 100% rename from intro/im.pl rename to 1st_edition/intro/im.pl diff --git a/intro/im.py b/1st_edition/intro/im.py similarity index 100% rename from intro/im.py rename to 1st_edition/intro/im.py diff --git a/intro/im.rb b/1st_edition/intro/im.rb similarity index 100% rename from intro/im.rb rename to 1st_edition/intro/im.rb diff --git a/intro/im.sh b/1st_edition/intro/im.sh similarity index 100% rename from intro/im.sh rename to 1st_edition/intro/im.sh diff --git a/intro/stooges.py b/1st_edition/intro/stooges.py similarity index 100% rename from intro/stooges.py rename to 1st_edition/intro/stooges.py diff --git a/intro/youtube.py b/1st_edition/intro/youtube.py similarity index 100% rename from intro/youtube.py rename to 1st_edition/intro/youtube.py diff --git a/intro/youtube2.py b/1st_edition/intro/youtube2.py similarity index 100% rename from intro/youtube2.py rename to 1st_edition/intro/youtube2.py diff --git a/net/dishes.py b/1st_edition/net/dishes.py similarity index 100% rename from net/dishes.py rename to 1st_edition/net/dishes.py diff --git a/net/fab1.py b/1st_edition/net/fab1.py similarity index 100% rename from net/fab1.py rename to 1st_edition/net/fab1.py diff --git a/net/fab2.py b/1st_edition/net/fab2.py similarity index 100% rename from net/fab2.py rename to 1st_edition/net/fab2.py diff --git a/net/fab3.py b/1st_edition/net/fab3.py similarity index 100% rename from net/fab3.py rename to 1st_edition/net/fab3.py diff --git a/net/fab4.py b/1st_edition/net/fab4.py similarity index 100% rename from net/fab4.py rename to 1st_edition/net/fab4.py diff --git a/net/gevent_monkey.py b/1st_edition/net/gevent_monkey.py similarity index 100% rename from net/gevent_monkey.py rename to 1st_edition/net/gevent_monkey.py diff --git a/net/gevent_test.py b/1st_edition/net/gevent_test.py similarity index 100% rename from net/gevent_test.py rename to 1st_edition/net/gevent_test.py diff --git a/net/knock_client.py b/1st_edition/net/knock_client.py similarity index 100% rename from net/knock_client.py rename to 1st_edition/net/knock_client.py diff --git a/net/knock_server.py b/1st_edition/net/knock_server.py similarity index 100% rename from net/knock_server.py rename to 1st_edition/net/knock_server.py diff --git a/net/msppack_client.py b/1st_edition/net/msppack_client.py similarity index 100% rename from net/msppack_client.py rename to 1st_edition/net/msppack_client.py diff --git a/net/msppack_server.py b/1st_edition/net/msppack_server.py similarity index 100% rename from net/msppack_server.py rename to 1st_edition/net/msppack_server.py diff --git a/net/redis_dryer.py b/1st_edition/net/redis_dryer.py similarity index 100% rename from net/redis_dryer.py rename to 1st_edition/net/redis_dryer.py diff --git a/net/redis_dryer2.py b/1st_edition/net/redis_dryer2.py similarity index 100% rename from net/redis_dryer2.py rename to 1st_edition/net/redis_dryer2.py diff --git a/net/redis_pub.py b/1st_edition/net/redis_pub.py similarity index 100% rename from net/redis_pub.py rename to 1st_edition/net/redis_pub.py diff --git a/net/redis_sub.py b/1st_edition/net/redis_sub.py similarity index 100% rename from net/redis_sub.py rename to 1st_edition/net/redis_sub.py diff --git a/net/redis_washer.py b/1st_edition/net/redis_washer.py similarity index 100% rename from net/redis_washer.py rename to 1st_edition/net/redis_washer.py diff --git a/net/tcp_client.py b/1st_edition/net/tcp_client.py similarity index 100% rename from net/tcp_client.py rename to 1st_edition/net/tcp_client.py diff --git a/net/tcp_server.py b/1st_edition/net/tcp_server.py similarity index 100% rename from net/tcp_server.py rename to 1st_edition/net/tcp_server.py diff --git a/net/thread_dishes.py b/1st_edition/net/thread_dishes.py similarity index 100% rename from net/thread_dishes.py rename to 1st_edition/net/thread_dishes.py diff --git a/net/threads.py b/1st_edition/net/threads.py similarity index 100% rename from net/threads.py rename to 1st_edition/net/threads.py diff --git a/net/udp_client.py b/1st_edition/net/udp_client.py similarity index 100% rename from net/udp_client.py rename to 1st_edition/net/udp_client.py diff --git a/net/udp_server.py b/1st_edition/net/udp_server.py similarity index 100% rename from net/udp_server.py rename to 1st_edition/net/udp_server.py diff --git a/net/xmlrpc_client.py b/1st_edition/net/xmlrpc_client.py similarity index 100% rename from net/xmlrpc_client.py rename to 1st_edition/net/xmlrpc_client.py diff --git a/net/xmlrpc_server.py b/1st_edition/net/xmlrpc_server.py similarity index 100% rename from net/xmlrpc_server.py rename to 1st_edition/net/xmlrpc_server.py diff --git a/net/zmq_client.py b/1st_edition/net/zmq_client.py similarity index 100% rename from net/zmq_client.py rename to 1st_edition/net/zmq_client.py diff --git a/net/zmq_pub.py b/1st_edition/net/zmq_pub.py similarity index 100% rename from net/zmq_pub.py rename to 1st_edition/net/zmq_pub.py diff --git a/net/zmq_server.py b/1st_edition/net/zmq_server.py similarity index 100% rename from net/zmq_server.py rename to 1st_edition/net/zmq_server.py diff --git a/net/zmq_sub.py b/1st_edition/net/zmq_sub.py similarity index 100% rename from net/zmq_sub.py rename to 1st_edition/net/zmq_sub.py diff --git a/storage/lolz.xml b/1st_edition/storage/lolz.xml similarity index 100% rename from storage/lolz.xml rename to 1st_edition/storage/lolz.xml diff --git a/storage/mcintyre.yaml b/1st_edition/storage/mcintyre.yaml similarity index 100% rename from storage/mcintyre.yaml rename to 1st_edition/storage/mcintyre.yaml diff --git a/storage/settings.cfg b/1st_edition/storage/settings.cfg similarity index 100% rename from storage/settings.cfg rename to 1st_edition/storage/settings.cfg diff --git a/sys/mp.py b/1st_edition/sys/mp.py similarity index 100% rename from sys/mp.py rename to 1st_edition/sys/mp.py diff --git a/sys/mp3.py b/1st_edition/sys/mp3.py similarity index 100% rename from sys/mp3.py rename to 1st_edition/sys/mp3.py diff --git a/web/bottle1.py b/1st_edition/web/bottle1.py similarity index 100% rename from web/bottle1.py rename to 1st_edition/web/bottle1.py diff --git a/web/bottle2.py b/1st_edition/web/bottle2.py similarity index 100% rename from web/bottle2.py rename to 1st_edition/web/bottle2.py diff --git a/web/bottle3.py b/1st_edition/web/bottle3.py similarity index 100% rename from web/bottle3.py rename to 1st_edition/web/bottle3.py diff --git a/web/bottle_test.py b/1st_edition/web/bottle_test.py similarity index 100% rename from web/bottle_test.py rename to 1st_edition/web/bottle_test.py diff --git a/web/flask1.py b/1st_edition/web/flask1.py similarity index 100% rename from web/flask1.py rename to 1st_edition/web/flask1.py diff --git a/web/flask2.py b/1st_edition/web/flask2.py similarity index 100% rename from web/flask2.py rename to 1st_edition/web/flask2.py diff --git a/web/flask3a.py b/1st_edition/web/flask3a.py similarity index 100% rename from web/flask3a.py rename to 1st_edition/web/flask3a.py diff --git a/web/flask3b.py b/1st_edition/web/flask3b.py similarity index 100% rename from web/flask3b.py rename to 1st_edition/web/flask3b.py diff --git a/web/flask3c.py b/1st_edition/web/flask3c.py similarity index 100% rename from web/flask3c.py rename to 1st_edition/web/flask3c.py diff --git a/web/home.wsgi b/1st_edition/web/home.wsgi similarity index 100% rename from web/home.wsgi rename to 1st_edition/web/home.wsgi diff --git a/web/links.py b/1st_edition/web/links.py similarity index 100% rename from web/links.py rename to 1st_edition/web/links.py diff --git a/web/templates/flask3.html b/1st_edition/web/templates/flask3.html similarity index 100% rename from web/templates/flask3.html rename to 1st_edition/web/templates/flask3.html diff --git a/web/templates/flasks.html b/1st_edition/web/templates/flasks.html similarity index 100% rename from web/templates/flasks.html rename to 1st_edition/web/templates/flasks.html diff --git a/web/templates/home.html b/1st_edition/web/templates/home.html similarity index 100% rename from web/templates/home.html rename to 1st_edition/web/templates/home.html diff --git a/README.md b/README.md index 296d758..9f943ed 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,5 @@ -Introducing Python +Introducing Python -- Second Edition ================= -This repository contains the programs featured in _Introducing Python_. -Some examples have been updated for the second and third printings. - -|directory|chapter| -|---|---| -|[intro](intro)| 1. A taste of Py -| | 2. Py ingredients: numbers, strings, and variables -| | 3. Py filling: lists, tuples, dictionaries, and sets -| | 4. Py crust: code structures -|[boxes](boxes)| 5. Py boxes: modules, packages, and programs -| | 6. Oh oh: objects and classes -| | 7. Mangle data like a pro -|[storage](storage)|8. Data has to go somewhere -|[web](web) | 9. The web, untangled -|[sys](sys) | 10. Systems -|[net](net) | 11. Concurrency and networks -|[dev](dev) | 12. Be a pythonista -|[art](art) | A. Py art -|[bus](bus) | B. Py at work -| | C. Py sci -| | D. Install Python 3 -| | E. Answers to exercises -| | F. Cheatsheets +This repository contains the programs featured in +the second edition of the book _Introducing Python_. diff --git a/ch01/archive.py b/ch01/archive.py new file mode 100644 index 0000000..828349e --- /dev/null +++ b/ch01/archive.py @@ -0,0 +1,19 @@ +import webbrowser +import json +from urllib.request import urlopen + +print("Let's find an old website.") +site = input("Type a website URL: ") +era = input("Type a year, month, and day, like 20150613: ") +url = "http://archive.org/wayback/available?url=%s×tamp=%s" % (site, era) +response = urlopen(url) +contents = response.read() +text = contents.decode("utf-8") +data = json.loads(text) +try: + old_site = data["archived_snapshots"]["closest"]["url"] + print("Found this copy: ", old_site) + print("It should appear in your browser now.") + webbrowser.open(old_site) +except: + print("Sorry, no luck finding", site) diff --git a/ch01/archive2.py b/ch01/archive2.py new file mode 100644 index 0000000..1028ad0 --- /dev/null +++ b/ch01/archive2.py @@ -0,0 +1,16 @@ +import webbrowser +import requests + +print("Let's find an old website.") +site = input("Type a website URL: ") +era = input("Type a year, month, and day, like 20150613: ") +url = "http://archive.org/wayback/available?url=%s×tamp=%s" % (site, era) +response = requests.get(url) +data = response.json() +try: + old_site = data["archived_snapshots"]["closest"]["url"] + print("Found this copy: ", old_site) + print("It should appear in your browser now.") + webbrowser.open(old_site) +except: + print("Sorry, no luck finding", site) diff --git a/ch01/countdown.py b/ch01/countdown.py new file mode 100644 index 0000000..ea676da --- /dev/null +++ b/ch01/countdown.py @@ -0,0 +1,2 @@ +for countdown in 5, 4, 3, 2, 1, "hey!": + print(countdown) diff --git a/ch01/quotes.py b/ch01/quotes.py new file mode 100644 index 0000000..74d0457 --- /dev/null +++ b/ch01/quotes.py @@ -0,0 +1,7 @@ +quotes = { + "Moe": "A wise guy, huh?", + "Larry": "Ow!", + "Curly": "Nyuk nyuk!", + } +stooge = "Curly" +print(stooge, "says:", quotes[stooge]) diff --git a/ch01/spells.py b/ch01/spells.py new file mode 100644 index 0000000..a42af60 --- /dev/null +++ b/ch01/spells.py @@ -0,0 +1,9 @@ +spells = [ + "Riddikulus!", + "Wingardium Leviosa!", + "Avada Kedavra!", + "Expecto Patronum!", + "Nox!", + "Lumos!", + ] +print(spells[3]) diff --git a/ch05/poem.py b/ch05/poem.py new file mode 100644 index 0000000..a9726be --- /dev/null +++ b/ch05/poem.py @@ -0,0 +1,5 @@ +poem = '''There was a Young Lady of Norway, +Who casually sat in a doorway; +When the door squeezed her flat, +She exclaimed, "What of that?" +This courageous Young Lady of Norway.''' diff --git a/ch05/poem2.py b/ch05/poem2.py new file mode 100644 index 0000000..97d9e6f --- /dev/null +++ b/ch05/poem2.py @@ -0,0 +1,5 @@ +poem2 = '''I do not like thee, Doctor Fell. + The reason why, I cannot tell. + But this I know, and know full well: + I do not like thee, Doctor Fell. +''' diff --git a/ch05/poem3.py b/ch05/poem3.py new file mode 100644 index 0000000..87380ca --- /dev/null +++ b/ch05/poem3.py @@ -0,0 +1,6 @@ +poem = '''All that doth flow we cannot liquid name +Or else would fire and water be the same; +But that is liquid which is moist and wet +Fire that property can never get. +Then 'tis not cold that doth the fire put out +But 'tis the wet that makes it die, no doubt.''' diff --git a/ch11/choices/advice.oy b/ch11/choices/advice.oy new file mode 100644 index 0000000..4d9307e --- /dev/null +++ b/ch11/choices/advice.oy @@ -0,0 +1,7 @@ +from random import choice + +answers = ["Yes!", "No!", "Reply hazy", "Sorry, what?"] + +def give(): + """Return random advice""" + return choice(answers) diff --git a/ch11/choices/fast.py b/ch11/choices/fast.py new file mode 100644 index 0000000..45cd5a1 --- /dev/null +++ b/ch11/choices/fast.py @@ -0,0 +1,8 @@ +from random import choice + +places = ["McDonalds", "KFC", "Burger King", "Taco Bell", + "Wendys", "Arbys", "Pizza Hut"] + +def pick(): + """Return random fast food place""" + return choice(places) diff --git a/ch11/fast.py b/ch11/fast.py new file mode 100644 index 0000000..7d921cf --- /dev/null +++ b/ch11/fast.py @@ -0,0 +1,8 @@ +from random import choice + +places = ["McDonalds", "KFC", "Burger King", "Taco Bell", + "Wendys", "Arbys", "Pizza Hut"] + +def pick(): # see the docstring below? + """Return random fast food place""" + return choice(places) diff --git a/ch11/fast2.py b/ch11/fast2.py new file mode 100644 index 0000000..efb0884 --- /dev/null +++ b/ch11/fast2.py @@ -0,0 +1,6 @@ +places = ["McDonalds", "KFC", "Burger King", "Taco Bell", + "Wendys", "Arbys", "Pizza Hut"] + +def pick(): + import random + return random.choice(places) diff --git a/ch11/fast3.py b/ch11/fast3.py new file mode 100644 index 0000000..1ad555a --- /dev/null +++ b/ch11/fast3.py @@ -0,0 +1,4 @@ +import fast as f + +place = f.pick() +print("Let's go to", place) diff --git a/ch11/fast4.py b/ch11/fast4.py new file mode 100644 index 0000000..4a7533e --- /dev/null +++ b/ch11/fast4.py @@ -0,0 +1,4 @@ +from fast import pick + +place = pick() +print("Let's go to", place) diff --git a/ch11/fast5.py b/ch11/fast5.py new file mode 100644 index 0000000..bb0a885 --- /dev/null +++ b/ch11/fast5.py @@ -0,0 +1,4 @@ +from fast import pick as who_cares + +place = who_cares() +print("Let's go to", place) diff --git a/ch11/lunch.py b/ch11/lunch.py new file mode 100644 index 0000000..65cfea0 --- /dev/null +++ b/ch11/lunch.py @@ -0,0 +1,4 @@ +import fast + +place = fast.pick() +print("Let's go to", place) diff --git a/ch11/questions.py b/ch11/questions.py new file mode 100644 index 0000000..bb0a885 --- /dev/null +++ b/ch11/questions.py @@ -0,0 +1,4 @@ +from fast import pick as who_cares + +place = who_cares() +print("Let's go to", place) diff --git a/ch12/mammoth.txt b/ch12/mammoth.txt new file mode 100644 index 0000000..4338c97 --- /dev/null +++ b/ch12/mammoth.txt @@ -0,0 +1,24 @@ +We have seen thee, queen of cheese, +Lying quietly at your ease, +Gently fanned by evening breeze, +Thy fair form no flies dare seize. +All gaily dressed soon you'll go +To the great Provincial show, +To be admired by many a beau +In the city of Toronto. +Cows numerous as a swarm of bees, +Or as the leaves upon the trees, +It did require to make thee please, +And stand unrivalled, queen of cheese. +May you not receive a scar as +We have heard that Mr. Harris +Intends to send you off as far as +The great world's show at Paris. +Of the youth beware of these, +For some of them might rudely squeeze +And bite your cheek, then songs or glees +We could not sing, oh! queen of cheese. +We'rt thou suspended from balloon, +You'd cast a shade even at noon, +Folks would think it was the moon +About to fall and crush them soon. diff --git a/ch14/convert_image.py b/ch14/convert_image.py new file mode 100644 index 0000000..aa1c71c --- /dev/null +++ b/ch14/convert_image.py @@ -0,0 +1,35 @@ +from io import BytesIO +from PIL import Image +import sys + +def data_to_img(data): + """Return PIL Image object, with data from in-memory """ + fp = BytesIO(data) + return Image.open(fp) # reads from memory + +def img_to_data(img, fmt=None): + """Return image data from PIL Image , in format""" + fp = BytesIO() + if not fmt: + fmt = img.format # keeps the original format + img.save(fp, fmt) # writes to memory + return fp.getvalue() + +def convert_image(data, fmt=None): + """Convert image to PIL image data""" + img = data_to_img(data) + return img_to_data(img, fmt) + +def get_file_data(name): + """Return PIL Image object for image file """ + img = Image.open(name) + print("img", img, img.format) + return img_to_data(img) + +if __name__ == "__main__": + for name in sys.argv[1:]: + data = get_file_data(name) + print("in", len(data), data[:10]) + for fmt in ("gif", "png", "jpeg"): + out_data = convert_image(data, fmt) + print("out", len(out_data), out_data[:10]) diff --git a/ch15/cf.py b/ch15/cf.py new file mode 100644 index 0000000..8650d4e --- /dev/null +++ b/ch15/cf.py @@ -0,0 +1,35 @@ +from concurrent import futures +import math +import time +import sys + +def calc(val): + time.sleep(1) + result = math.sqrt(float(val)) + return result + +def use_threads(num, values): + t1 = time.time() + with futures.ThreadPoolExecutor(num) as tex: + results = tex.map(calc, values) + t2 = time.time() + return t2 - t1 + +def use_processes(num, values): + t1 = time.time() + with futures.ProcessPoolExecutor(num) as pex: + results = pex.map(calc, values) + t2 = time.time() + return t2 - t1 + +def main(workers, values): + print(f"Using {workers} workers for {len(values)} values") + t_sec = use_threads(workers, values) + print(f"Threads took {t_sec:.4f} seconds") + p_sec = use_processes(workers, values) + print(f"Processes took {p_sec:.4f} seconds") + +if __name__ == '__main__': + workers = int(sys.argv[1]) + values = list(range(1, 6)) # 1 .. 5 + main(workers, values) diff --git a/ch15/cf2.py b/ch15/cf2.py new file mode 100644 index 0000000..324bd06 --- /dev/null +++ b/ch15/cf2.py @@ -0,0 +1,35 @@ +from concurrent import futures +import math +import sys + +def calc(val): + result = math.sqrt(float(val)) + return val, result + +def use_threads(num, values): + with futures.ThreadPoolExecutor(num) as tex: + tasks = [tex.submit(calc, value) for value in values] + for f in futures.as_completed(tasks): + yield f.result() + +def use_processes(num, values): + with futures.ProcessPoolExecutor(num) as pex: + tasks = [pex.submit(calc, value) for value in values] + for f in futures.as_completed(tasks): + yield f.result() + +def main(workers, values): + print(f"Using {workers} workers for {len(values)} values") + print("Using threads:") + for val, result in use_threads(workers, values): + print(f'{val} {result:.4f}') + print("Using processes:") + for val, result in use_processes(workers, values): + print(f'{val} {result:.4f}') + +if __name__ == '__main__': + workers = 3 + if len(sys.argv) > 1: + workers = int(sys.argv[1]) + values = list(range(1, 6)) # 1 .. 5 + main(workers, values) diff --git a/ch15/dishes.py b/ch15/dishes.py new file mode 100644 index 0000000..55ae94d --- /dev/null +++ b/ch15/dishes.py @@ -0,0 +1,20 @@ +import multiprocessing as mp + +def washer(dishes, output): + for dish in dishes: + print('Washing', dish, 'dish') + output.put(dish) + +def dryer(input): + while True: + dish = input.get() + print('Drying', dish, 'dish') + input.task_done() + +dish_queue = mp.JoinableQueue() +dryer_proc = mp.Process(target=dryer, args=(dish_queue,)) +dryer_proc.daemon = True +dryer_proc.start() +dishes = ['salad', 'bread', 'entree', 'dessert'] +washer(dishes, dish_queue) +dish_queue.join() diff --git a/ch15/gevent_monkey.py b/ch15/gevent_monkey.py new file mode 100644 index 0000000..a0a55e9 --- /dev/null +++ b/ch15/gevent_monkey.py @@ -0,0 +1,10 @@ +import gevent +from gevent import monkey; monkey.patch_all() +import socket + +hosts = ['www.crappytaxidermy.com', 'www.walterpottertaxidermy.com', + 'www.antique-taxidermy.com'] +jobs = [gevent.spawn(socket.gethostbyname, host) for host in hosts] +gevent.joinall(jobs, timeout=5) +for job in jobs: + print(job.value) diff --git a/ch15/gevent_test.py b/ch15/gevent_test.py new file mode 100644 index 0000000..ce93020 --- /dev/null +++ b/ch15/gevent_test.py @@ -0,0 +1,9 @@ +import gevent +from gevent import socket + +hosts = ['www.crappytaxidermy.com', 'www.walterpottertaxidermy.com', + 'www.antique-taxidermy.com'] +jobs = [gevent.spawn(gevent.socket.gethostbyname, host) for host in hosts] +gevent.joinall(jobs, timeout=5) +for job in jobs: + print(job.value) diff --git a/ch15/knock_client.py b/ch15/knock_client.py new file mode 100644 index 0000000..bd0ea37 --- /dev/null +++ b/ch15/knock_client.py @@ -0,0 +1,25 @@ +from twisted.internet import reactor, protocol + +class KnockClient(protocol.Protocol): + + def connectionMade(self): + self.transport.write("Knock knock") + + def dataReceived(self, data): + if data.startswith("Who's there?"): + response = "Disappearing client" + self.transport.write(response) + else: + self.transport.loseConnection() + reactor.stop() + +class KnockFactory(protocol.ClientFactory): + protocol = KnockClient + +def main(): + f = KnockFactory() + reactor.connectTCP("localhost", 8000, f) + reactor.run() + +if __name__ == '__main__': + main() diff --git a/ch15/knock_server.py b/ch15/knock_server.py new file mode 100644 index 0000000..423ca08 --- /dev/null +++ b/ch15/knock_server.py @@ -0,0 +1,18 @@ +from twisted.internet import protocol, reactor + +class Knock(protocol.Protocol): + def dataReceived(self, data): + print('Client:', data) + if data.startswith("Knock knock"): + response = "Who's there?" + else: + response = data + " who?" + print('Server:', response) + self.transport.write(response) + +class KnockFactory(protocol.Factory): + def buildProtocol(self, addr): + return Knock() + +reactor.listenTCP(8000, KnockFactory()) +reactor.run() diff --git a/ch15/mp.py b/ch15/mp.py new file mode 100644 index 0000000..f9d1c53 --- /dev/null +++ b/ch15/mp.py @@ -0,0 +1,12 @@ +import multiprocessing +import os + +def whoami(what): + print("Process %s says: %s" % (os.getpid(), what)) + +if __name__ == "__main__": + whoami("I'm the main program") + for n in range(4): + p = multiprocessing.Process(target=whoami, + args=("I'm function %s" % n,)) + p.start() diff --git a/ch15/mp2.py b/ch15/mp2.py new file mode 100644 index 0000000..2c8e01f --- /dev/null +++ b/ch15/mp2.py @@ -0,0 +1,21 @@ +import multiprocessing +import time +import os + +def whoami(name): + print("I'm %s, in process %s" % (name, os.getpid())) + +def loopy(name): + whoami(name) + start = 1 + stop = 1000000 + for num in range(start, stop): + print("\tNumber %s of %s. Honk!" % (num, stop)) + time.sleep(1) + +if __name__ == "__main__": + whoami("main") + p = multiprocessing.Process(target=loopy, args=("loopy",)) + p.start() + time.sleep(5) + p.terminate() diff --git a/ch15/redis_dryer.py b/ch15/redis_dryer.py new file mode 100644 index 0000000..79b9103 --- /dev/null +++ b/ch15/redis_dryer.py @@ -0,0 +1,13 @@ +import redis + +conn = redis.Redis() +print('Dryer is starting') +while True: + msg = conn.blpop('dishes') + if not msg: + break + val = msg[1].decode('utf-8') + if val == 'quit': + break + print('Dried', val) +print('Dishes are dried') diff --git a/ch15/redis_dryer2.py b/ch15/redis_dryer2.py new file mode 100644 index 0000000..b94fbe4 --- /dev/null +++ b/ch15/redis_dryer2.py @@ -0,0 +1,26 @@ +def dryer(): + import redis + import os + import time + + conn = redis.Redis() + pid = os.getpid() + timeout = 20 + print('Dryer process %s is starting' % pid) + while True: + msg = conn.blpop('dishes', timeout) + if not msg: + break + val = msg[1].decode('utf-8') + if val == 'quit': + break + print('%s: dried %s' % (pid, val)) + time.sleep(0.1) + print('Dryer process %s is done' % pid) + +import multiprocessing + +DRYERS=3 +for num in range(DRYERS): + p = multiprocessing.Process(target=dryer) + p.start() diff --git a/ch15/redis_washer.py b/ch15/redis_washer.py new file mode 100644 index 0000000..cd1f9b2 --- /dev/null +++ b/ch15/redis_washer.py @@ -0,0 +1,11 @@ +import redis + +conn = redis.Redis() +print('Washer is starting') +dishes = ['salad', 'bread', 'entree', 'dessert'] +for dish in dishes: + msg = dish.encode('utf-8') + conn.rpush('dishes', msg) + print('Washed', dish) +conn.rpush('dishes', 'quit') +print('Washer is done') diff --git a/ch15/tasks.py b/ch15/tasks.py new file mode 100644 index 0000000..c784258 --- /dev/null +++ b/ch15/tasks.py @@ -0,0 +1,8 @@ +from invoke import task + +@task +def mytime(ctx): + import time + now = time.time() + time_str = time.asctime(time.localtime(now)) + print("Local time is", time_str) diff --git a/ch15/thread1.py b/ch15/thread1.py new file mode 100644 index 0000000..650a565 --- /dev/null +++ b/ch15/thread1.py @@ -0,0 +1,14 @@ +import threading + +def do_this(what): + whoami(what) + +def whoami(what): + print("Thread %s says: %s" % (threading.current_thread(), what)) + +if __name__ == "__main__": + whoami("I'm the main program") + for n in range(4): + p = threading.Thread(target=do_this, + args=("I'm function %s" % n,)) + p.start() diff --git a/ch15/thread_dishes.py b/ch15/thread_dishes.py new file mode 100644 index 0000000..5037c3d --- /dev/null +++ b/ch15/thread_dishes.py @@ -0,0 +1,23 @@ +import threading, queue +import time + +def washer(dishes, dish_queue): + for dish in dishes: + print ("Washing", dish) + time.sleep(5) + dish_queue.put(dish) + +def dryer(dish_queue): + while True: + dish = dish_queue.get() + print ("Drying", dish) + time.sleep(10) + dish_queue.task_done() + +dish_queue = queue.Queue() +for n in range(2): + dryer_thread = threading.Thread(target=dryer, args=(dish_queue,)) + dryer_thread.start() +dishes = ['salad', 'bread', 'entree', 'dessert'] +washer(dishes, dish_queue) +dish_queue.join() diff --git a/ch16/villains.csv b/ch16/villains.csv new file mode 100644 index 0000000..ea5ec98 --- /dev/null +++ b/ch16/villains.csv @@ -0,0 +1,6 @@ +first,last +Doctor,No +Rosa,Klebb +Mister,Big +Auric,Goldfinger +Ernst,Blofeld diff --git a/ch17/jsonrpc_client.py b/ch17/jsonrpc_client.py new file mode 100644 index 0000000..097c024 --- /dev/null +++ b/ch17/jsonrpc_client.py @@ -0,0 +1,5 @@ +from jsonrpcclient import request + +num = 7 +response = request("http://localhost:5000", "double", num=num) +print("Double", num, "is", response.data.result) diff --git a/ch17/jsonrpc_server.py b/ch17/jsonrpc_server.py new file mode 100644 index 0000000..ba757cb --- /dev/null +++ b/ch17/jsonrpc_server.py @@ -0,0 +1,8 @@ +from jsonrpcserver import method, serve + +@method +def double(num): + return num * 2 + +if __name__ == "__main__": + serve() diff --git a/ch17/msgpack_client.py b/ch17/msgpack_client.py new file mode 100644 index 0000000..a708eca --- /dev/null +++ b/ch17/msgpack_client.py @@ -0,0 +1,6 @@ +from msgpackrpc import Client, Address + +client = Client(Address("localhost", 6789)) +num = 8 +result = client.call('double', num) +print("Double %s is %s" % (num, result)) diff --git a/ch17/msgpack_server.py b/ch17/msgpack_server.py new file mode 100644 index 0000000..ea1a0d5 --- /dev/null +++ b/ch17/msgpack_server.py @@ -0,0 +1,9 @@ +from msgpackrpc import Server, Address + +class Services(): + def double(self, num): + return num * 2 + +server = Server(Services()) +server.listen(Address("localhost", 6789)) +server.start() diff --git a/ch17/redis_pub.py b/ch17/redis_pub.py new file mode 100644 index 0000000..e7f3f02 --- /dev/null +++ b/ch17/redis_pub.py @@ -0,0 +1,11 @@ +import redis +import random + +conn = redis.Redis() +cats = ['siamese', 'persian', 'maine coon', 'norwegian forest'] +hats = ['stovepipe', 'bowler', 'tam-o-shanter', 'fedora'] +for msg in range(10): + cat = random.choice(cats) + hat = random.choice(hats) + print('Publish: %s wears a %s' % (cat, hat)) + conn.publish(cat, hat) diff --git a/ch17/redis_sub.py b/ch17/redis_sub.py new file mode 100644 index 0000000..1e23a3c --- /dev/null +++ b/ch17/redis_sub.py @@ -0,0 +1,11 @@ +import redis + +conn = redis.Redis() +topics = ['maine coon', 'persian'] +sub = conn.pubsub() +sub.subscribe(topics) +for msg in sub.listen(): + if msg['type'] == 'message': + cat = msg['channel'] + hat = msg['data'] + print('Subscribe: %s wears a %s' % (cat, hat)) diff --git a/ch17/tcp_client.py b/ch17/tcp_client.py new file mode 100644 index 0000000..19ada69 --- /dev/null +++ b/ch17/tcp_client.py @@ -0,0 +1,13 @@ +import socket +from datetime import datetime + +address = ('localhost', 6789) +max_size = 1000 + +print('Starting the client at', datetime.now()) +client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +client.connect(address) +client.sendall(b'Hey!') +data = client.recv(max_size) +print('At', datetime.now(), 'someone replied', data) +client.close() diff --git a/ch17/tcp_server.py b/ch17/tcp_server.py new file mode 100644 index 0000000..592c417 --- /dev/null +++ b/ch17/tcp_server.py @@ -0,0 +1,19 @@ +from datetime import datetime +import socket + +address = ('localhost', 6789) +max_size = 1000 + +print('Starting the server at', datetime.now()) +print('Waiting for a client to call.') +server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +server.bind(address) +server.listen(5) + +client, addr = server.accept() +data = client.recv(max_size) + +print('At', datetime.now(), client, 'said', data) +client.sendall(b'Are you talking to me?') +client.close() +server.close() diff --git a/ch17/udp_client.py b/ch17/udp_client.py new file mode 100644 index 0000000..33029f6 --- /dev/null +++ b/ch17/udp_client.py @@ -0,0 +1,12 @@ +import socket +from datetime import datetime + +server_address = ('localhost', 6789) +max_size = 4096 + +print('Starting the client at', datetime.now()) +client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +client.sendto(b'Hey!', server_address) +data, server = client.recvfrom(max_size) +print('At', datetime.now(), server, 'said', data) +client.close() diff --git a/ch17/udp_server.py b/ch17/udp_server.py new file mode 100644 index 0000000..f5c6524 --- /dev/null +++ b/ch17/udp_server.py @@ -0,0 +1,16 @@ +from datetime import datetime +import socket + +server_address = ('localhost', 6789) +max_size = 4096 + +print('Starting the server at', datetime.now()) +print('Waiting for a client to call.') +server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +server.bind(server_address) + +data, client = server.recvfrom(max_size) + +print('At', datetime.now(), client, 'said', data) +server.sendto(b'Are you talking to me?', client) +server.close() diff --git a/ch17/xmlrpc_client.py b/ch17/xmlrpc_client.py new file mode 100644 index 0000000..e6d43be --- /dev/null +++ b/ch17/xmlrpc_client.py @@ -0,0 +1,6 @@ +import xmlrpc.client + +proxy = xmlrpc.client.ServerProxy("http://localhost:6789/") +num = 7 +result = proxy.double(num) +print("Double %s is %s" % (num, result)) diff --git a/ch17/xmlrpc_server.py b/ch17/xmlrpc_server.py new file mode 100644 index 0000000..c5dc15c --- /dev/null +++ b/ch17/xmlrpc_server.py @@ -0,0 +1,8 @@ +from xmlrpc.server import SimpleXMLRPCServer + +def double(num): + return num * 2 + +server = SimpleXMLRPCServer(("localhost", 6789)) +server.register_function(double, "double") +server.serve_forever() diff --git a/ch17/zerorpc_client.py b/ch17/zerorpc_client.py new file mode 100644 index 0000000..530a3f3 --- /dev/null +++ b/ch17/zerorpc_client.py @@ -0,0 +1,7 @@ +import zerorpc + +client = zerorpc.Client() +client.connect("tcp://127.0.0.1:4242") +num = 7 +result = client.double(num) +print("Double", num, "is", result) diff --git a/ch17/zerorpc_server.py b/ch17/zerorpc_server.py new file mode 100644 index 0000000..8a83512 --- /dev/null +++ b/ch17/zerorpc_server.py @@ -0,0 +1,9 @@ +import zerorpc + +class RPC(): + def double(self, num): + return 2 * num + +server = zerorpc.Server(RPC()) +server.bind("tcp://0.0.0.0:4242") +server.run() diff --git a/ch17/zmq_client.py b/ch17/zmq_client.py new file mode 100644 index 0000000..81dc286 --- /dev/null +++ b/ch17/zmq_client.py @@ -0,0 +1,14 @@ +import zmq + +host = '127.0.0.1' +port = 6789 +context = zmq.Context() +client = context.socket(zmq.REQ) +client.connect("tcp://%s:%s" % (host, port)) +for num in range(1, 6): + request_str = "message #%s" % num + request_bytes = request_str.encode('utf-8') + client.send(request_bytes) + reply_bytes = client.recv() + reply_str = reply_bytes.decode('utf-8') + print("Sent %s, received %s" % (request_str, reply_str)) diff --git a/ch17/zmq_pub.py b/ch17/zmq_pub.py new file mode 100644 index 0000000..cc2f794 --- /dev/null +++ b/ch17/zmq_pub.py @@ -0,0 +1,19 @@ +import zmq +import random +import time + +host = '*' +port = 6789 +ctx = zmq.Context() +pub = ctx.socket(zmq.PUB) +pub.bind('tcp://%s:%s' % (host, port)) +cats = ['siamese', 'persian', 'maine coon', 'norwegian forest'] +hats = ['stovepipe', 'bowler', 'tam-o-shanter', 'fedora'] +time.sleep(1) +for msg in range(10): + cat = random.choice(cats) + cat_bytes = cat.encode('utf-8') + hat = random.choice(hats) + hat_bytes = hat.encode('utf-8') + print('Publish: %s wears a %s' % (cat, hat)) + pub.send_multipart([cat_bytes, hat_bytes]) diff --git a/ch17/zmq_server.py b/ch17/zmq_server.py new file mode 100644 index 0000000..5a3223a --- /dev/null +++ b/ch17/zmq_server.py @@ -0,0 +1,15 @@ +import zmq + +host = '127.0.0.1' +port = 6789 +context = zmq.Context() +server = context.socket(zmq.REP) +server.bind("tcp://%s:%s" % (host, port)) +while True: + # Wait for next request from client + request_bytes = server.recv() + request_str = request_bytes.decode('utf-8') + print("That voice in my head says: %s" % request_str) + reply_str = "Stop saying: %s" % request_str + reply_bytes = bytes(reply_str, 'utf-8') + server.send(reply_bytes) diff --git a/ch17/zmq_sub.py b/ch17/zmq_sub.py new file mode 100644 index 0000000..735fffe --- /dev/null +++ b/ch17/zmq_sub.py @@ -0,0 +1,15 @@ +import zmq + +host = '127.0.0.1' +port = 6789 +ctx = zmq.Context() +sub = ctx.socket(zmq.SUB) +sub.connect('tcp://%s:%s' % (host, port)) +topics = ['maine coon', 'persian'] +for topic in topics: + sub.setsockopt(zmq.SUBSCRIBE, topic.encode('utf-8')) +while True: + cat_bytes, hat_bytes = sub.recv_multipart() + cat = cat_bytes.decode('utf-8') + hat = hat_bytes.decode('utf-8') + print('Subscribe: %s wears a %s' % (cat, hat)) diff --git a/ch18/bottle1.py b/ch18/bottle1.py new file mode 100644 index 0000000..cd1b7e9 --- /dev/null +++ b/ch18/bottle1.py @@ -0,0 +1,7 @@ +from bottle import route, run + +@route('/') +def home(): + return "It isn't fancy, but it's my home page" + +run(host='localhost', port=9999) diff --git a/ch18/bottle2.py b/ch18/bottle2.py new file mode 100644 index 0000000..25293b8 --- /dev/null +++ b/ch18/bottle2.py @@ -0,0 +1,7 @@ +from bottle import route, run, static_file + +@route('/') +def main(): + return static_file('index.html', root='.') + +run(host='localhost', port=9999) diff --git a/ch18/bottle3.py b/ch18/bottle3.py new file mode 100644 index 0000000..3cbbc09 --- /dev/null +++ b/ch18/bottle3.py @@ -0,0 +1,11 @@ +from bottle import route, run, static_file + +@route('/') +def home(): + return static_file('index.html', root='.') + +@route('/echo/') +def echo(thing): + return "Say hello to my little friend: %s!" % thing + +run(host='localhost', port=9999) diff --git a/ch18/bottle_test.py b/ch18/bottle_test.py new file mode 100644 index 0000000..72c16b0 --- /dev/null +++ b/ch18/bottle_test.py @@ -0,0 +1,8 @@ +import requests + +resp = requests.get('http://localhost:9999/echo/Mothra') +if resp.status_code == 200 and \ + resp.text == 'Say hello to my little friend: Mothra!': + print('It worked! That almost never happens!') +else: + print('Argh, got this:', resp.text) diff --git a/ch18/flask1.py b/ch18/flask1.py new file mode 100644 index 0000000..82ef7ca --- /dev/null +++ b/ch18/flask1.py @@ -0,0 +1,13 @@ +from flask import Flask + +app = Flask(__name__, static_folder='.', static_url_path='') + +@app.route('/') +def home(): + return app.send_static_file('index.html') + +@app.route('/echo/') +def echo(thing): + return "Say hello to my little friend: %s" % thing + +app.run(port=9999, debug=True) diff --git a/ch18/flask2.html b/ch18/flask2.html new file mode 100644 index 0000000..e11614e --- /dev/null +++ b/ch18/flask2.html @@ -0,0 +1,8 @@ + + +Flask2 Example + + +Say hello to my little friend: {{ thing }} + + diff --git a/ch18/flask2.py b/ch18/flask2.py new file mode 100644 index 0000000..32448f5 --- /dev/null +++ b/ch18/flask2.py @@ -0,0 +1,9 @@ +from flask import Flask, render_template + +app = Flask(__name__) + +@app.route('/echo/') +def echo(thing): + return render_template('flask2.html', thing=thing) + +app.run(port=9999, debug=True) diff --git a/ch18/flask3a.py b/ch18/flask3a.py new file mode 100644 index 0000000..b7cbf07 --- /dev/null +++ b/ch18/flask3a.py @@ -0,0 +1,9 @@ +from flask import Flask, render_template + +app = Flask(__name__) + +@app.route('/echo//') +def echo(thing, place): + return render_template('flask3.html', thing=thing, place=place) + +app.run(port=9999, debug=True) diff --git a/ch18/flask3b.py b/ch18/flask3b.py new file mode 100644 index 0000000..3d56a4b --- /dev/null +++ b/ch18/flask3b.py @@ -0,0 +1,11 @@ +from flask import Flask, render_template, request + +app = Flask(__name__) + +@app.route('/echo/') +def echo(): + thing = request.args.get('thing') + place = request.args.get('place') + return render_template('flask3.html', thing=thing, place=place) + +app.run(port=9999, debug=True) diff --git a/ch18/flask3c.py b/ch18/flask3c.py new file mode 100644 index 0000000..52666a3 --- /dev/null +++ b/ch18/flask3c.py @@ -0,0 +1,12 @@ +from flask import Flask, render_template, request + +app = Flask(__name__) + +@app.route('/echo/') +def echo(): + kwargs = {} + kwargs['thing'] = request.args.get('thing') + kwargs['place'] = request.args.get('place') + return render_template('flask3.html', **kwargs) + +app.run(port=9999, debug=True) diff --git a/ch18/home.wsgi b/ch18/home.wsgi new file mode 100644 index 0000000..a23b6df --- /dev/null +++ b/ch18/home.wsgi @@ -0,0 +1,7 @@ +import bottle + +application = bottle.default_app() + +@bottle.route('/') +def home(): + return "apache and wsgi, sitting in a tree" diff --git a/ch18/ia.py b/ch18/ia.py new file mode 100644 index 0000000..c6e1517 --- /dev/null +++ b/ch18/ia.py @@ -0,0 +1,22 @@ +import json +import sys +import requests + +def search(title): + url = "http://archive.org/advancedsearch.php" + params = {"q": f"title:({title})", + "output": "json", + "fields": "identifier,title", + "rows": 50, + "page": 1,} + resp = requests.get(url, params=params) + return resp.json() + +if __name__ == "__main__": + title = sys.argv[1] + data = search(title) + docs = data["response"]["docs"] + print(f"Found {len(docs)} items, showing first 10") + print("identifier\ttitle") + for row in docs[:10]: + print(row["identifier"], row["title"], sep="\t") diff --git a/ch18/ia_movies.py b/ch18/ia_movies.py new file mode 100644 index 0000000..38b3bd0 --- /dev/null +++ b/ch18/ia_movies.py @@ -0,0 +1,60 @@ +"""Find a video at the Internet Archive +by a partial title match and display it.""" + +import sys +import webbrowser +import requests + +def search(title): + """Return a list of 3-item tuples (identifier, + title, description) about videos + whose titles partially match :title.""" + search_url = "https://archive.org/advancedsearch.php" + params = { + "q": "title:({}) AND mediatype:(movies)".format(title), + "fl": "identifier,title,description", + "output": "json", + "rows": 10, + "page": 1, + } + resp = requests.get(search_url, params=params) + data = resp.json() + docs = [(doc["identifier"], doc["title"], doc["description"]) + for doc in data["response"]["docs"]] + return docs + +def choose(docs): + """Print line number, title and truncated description for + each tuple in :docs. Get the user to pick a line + number. If it's valid, return the first item in the + chosen tuple (the "identifier"). Otherwise, return None.""" + last = len(docs) - 1 + for num, doc in enumerate(docs): + print(f"{num}: ({doc[1]}) {doc[2][:30]}...") + index = input(f"Which would you like to see (0 to {last})? ") + try: + return docs[int(index)][0] + except: + return None + +def display(identifier): + """Display the Archive video with :identifier in the browser""" + details_url = "https://archive.org/details/{}".format(identifier) + print("Loading", details_url) + webbrowser.open(details_url) + +def main(title): + """Find any movies that match :title. + Get the user's choice and display it in the browser.""" + identifiers = search(title) + if identifiers: + identifier = choose(identifiers) + if identifier: + display(identifier) + else: + print("Nothing selected") + else: + print("Nothing found for", title) + +if __name__ == "__main__": + main(sys.argv[1]) diff --git a/ch18/links.py b/ch18/links.py new file mode 100644 index 0000000..52ffbd1 --- /dev/null +++ b/ch18/links.py @@ -0,0 +1,16 @@ +def get_links(url): + import requests + from bs4 import BeautifulSoup as soup + result = requests.get(url) + page = result.text + doc = soup(page) + links = [element.get('href') for element in doc.find_all('a')] + return links + +if __name__ == '__main__': + import sys + for url in sys.argv[1:]: + print('Links in', url) + for num, link in enumerate(get_links(url), start=1): + print(num, link) + print() diff --git a/ch19/cap.py b/ch19/cap.py new file mode 100644 index 0000000..8aded87 --- /dev/null +++ b/ch19/cap.py @@ -0,0 +1,2 @@ +def just_do_it(text): + return text.capitalize() diff --git a/ch19/cap.pyc b/ch19/cap.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bd91e070f201407b350081e49f9e07ac205d8b31 GIT binary patch literal 322 zcmZSn%*)ktpe!z#0SXv_v;z}hA1F|ks(-v2`G{bl80eukUB0PQNzHH z#lX$Wsdiw?Kz0EDLz6~G literal 0 HcmV?d00001 diff --git a/ch19/cap2.py b/ch19/cap2.py new file mode 100644 index 0000000..7f7c599 --- /dev/null +++ b/ch19/cap2.py @@ -0,0 +1,15 @@ +def just_do_it(text): + """ + >>> just_do_it('duck') + 'Duck' + >>> just_do_it('a veritable flock of ducks') + 'A Veritable Flock Of Ducks' + >>> just_do_it("I'm fresh out of ideas") + "I'm Fresh Out Of Ideas" + """ + from string import capwords + return capwords(text) + +if __name__ == '__main__': + import doctest + doctest.testmod() diff --git a/ch19/capitals.py b/ch19/capitals.py new file mode 100644 index 0000000..6d50fb3 --- /dev/null +++ b/ch19/capitals.py @@ -0,0 +1,14 @@ +def process_cities(filename): + with open(filename, 'rt') as file: + for line in file: + line = line.strip() + if 'quit' in line.lower(): + return + country, city = line.split(',') + city = city.strip() + country = country.strip() + print(city.title(), country.title(), sep=',') + +if __name__ == '__main__': + import sys + process_cities(sys.argv[1]) diff --git a/ch19/capitals2.py b/ch19/capitals2.py new file mode 100644 index 0000000..72119e8 --- /dev/null +++ b/ch19/capitals2.py @@ -0,0 +1,14 @@ +def process_cities(filename): + with open(filename, 'rt') as file: + for line in file: + line = line.strip() + if 'quit' == line.lower(): + return + country, city = line.split(',') + city = city.strip() + country = country.strip() + print(city.title(), country.title(), sep=',') + +if __name__ == '__main__': + import sys + process_cities(sys.argv[1]) diff --git a/ch19/cities.csv b/ch19/cities.csv new file mode 100644 index 0000000..3245ae4 --- /dev/null +++ b/ch19/cities.csv @@ -0,0 +1,4 @@ +France, Paris +venuzuela,caracas + LithuaniA,vilnius + quit diff --git a/ch19/cities2.csv b/ch19/cities2.csv new file mode 100644 index 0000000..c83b87f --- /dev/null +++ b/ch19/cities2.csv @@ -0,0 +1,15 @@ +argentina,buenos aires +bolivia,la paz +brazil,brasilia +chile,santiago +colombia,Bogotá +ecuador,quito +falkland islands,stanley +french guiana,cayenne +guyana,georgetown +paraguay,Asunción +peru,lima +suriname,paramaribo +uruguay,montevideo +venezuela,caracas +quit diff --git a/ch19/dump.py b/ch19/dump.py new file mode 100644 index 0000000..0241e9d --- /dev/null +++ b/ch19/dump.py @@ -0,0 +1,10 @@ +def dump(func): + "Print input arguments and output value(s)" + def wrapped(*args, **kwargs): + print("Function name:", func.__name__) + print("Input arguments:", ' '.join(map(str, args))) + print("Input keyword arguments:", kwargs.items()) + output = func(*args, **kwargs) + print("Output:", output) + return output + return wrapped diff --git a/ch19/dump.pyc b/ch19/dump.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31abaa531762cb9a015b72da8b17553bb416787f GIT binary patch literal 771 zcmbtRJx{|x4E3eu`&%q5h>T%?hzU_4#Kgx^P%9P&s*nUoNiI=*X@yj#B4FY_@sE)B z13X^~h?z+Cou7Sv&ra=gVfN#_cNNn3Q#cP{yZ{#wJrP~vqNwdTKtjpOMXUznRk#%F_@+6 zD^V8=4jrFF4n;NUDl!h48V!hs4h_{fSr_VVordFTJVXVsH|WC42^u(~Qk-pX678G3 z2!B-R&?LEbb&$mkUIujfS8&6~M*G+d`6O* to Celsius and return it." + f_boil_temp = 212.0 + f_freeze_temp = 32.0 + c_boil_temp = 100.0 + c_freeze_temp = 0.0 + f_range = f_boil_temp - f_freeze_temp + c_range = c_boil_temp - c_freeze_temp + f_c_ratio = c_range / f_range + c_temp = (f_temp - f_freeze_temp) * f_c_ratio + c_freeze_temp + return c_temp + +if __name__ == '__main__': + for f_temp in [-40.0, 0.0, 32.0, 100.0, 212.0]: + c_temp = ftoc(f_temp) + print('%f F => %f C' % (f_temp, c_temp)) diff --git a/ch19/ftoc2.py b/ch19/ftoc2.py new file mode 100644 index 0000000..155c49d --- /dev/null +++ b/ch19/ftoc2.py @@ -0,0 +1,17 @@ +F_BOIL_TEMP = 212.0 +F_FREEZE_TEMP = 32.0 +C_BOIL_TEMP = 100.0 +C_FREEZE_TEMP = 0.0 +F_RANGE = F_BOIL_TEMP - F_FREEZE_TEMP +C_RANGE = C_BOIL_TEMP - C_FREEZE_TEMP +F_C_RATIO = C_RANGE / F_RANGE + +def ftoc(f_temp): + "Convert Fahrenheit temperature to Celsius and return it." + c_temp = (f_temp - F_FREEZE_TEMP) * F_C_RATIO + C_FREEZE_TEMP + return c_temp + +if __name__ == '__main__': + for f_temp in [-40.0, 0.0, 32.0, 100.0, 212.0]: + c_temp = ftoc(f_temp) + print('%f F => %f C' % (f_temp, c_temp)) diff --git a/ch19/style1.py b/ch19/style1.py new file mode 100644 index 0000000..1361f86 --- /dev/null +++ b/ch19/style1.py @@ -0,0 +1,5 @@ +a = 1 +b = 2 +print(a) +print(b) +print(c) diff --git a/ch19/style2.py b/ch19/style2.py new file mode 100644 index 0000000..4cc3384 --- /dev/null +++ b/ch19/style2.py @@ -0,0 +1,6 @@ +a = 1 +b = 2 +c = 3 +print(a) +print(b) +print(c) diff --git a/ch19/style3.py b/ch19/style3.py new file mode 100644 index 0000000..cd19d2e --- /dev/null +++ b/ch19/style3.py @@ -0,0 +1,12 @@ +"Module docstring goes here" + +def func(): + "Function docstring goes here. Hi, Mom!" + first = 1 + second = 2 + third = 3 + print(first) + print(second) + print(third) + +func() diff --git a/ch19/test.py b/ch19/test.py new file mode 100644 index 0000000..76b8c39 --- /dev/null +++ b/ch19/test.py @@ -0,0 +1 @@ +print('Oops') diff --git a/ch19/test_cap.py b/ch19/test_cap.py new file mode 100644 index 0000000..310b744 --- /dev/null +++ b/ch19/test_cap.py @@ -0,0 +1,23 @@ +import unittest +import cap + +class TestCap(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_one_word(self): + text = 'duck' + result = cap.just_do_it(text) + self.assertEqual(result, 'Duck') + + def test_multiple_words(self): + text = 'a veritable flock of ducks' + result = cap.just_do_it(text) + self.assertEqual(result, 'A Veritable Flock Of Ducks') + +if __name__ == '__main__': + unittest.main() diff --git a/ch19/test_cap_nose.py b/ch19/test_cap_nose.py new file mode 100644 index 0000000..c69ce43 --- /dev/null +++ b/ch19/test_cap_nose.py @@ -0,0 +1,22 @@ +import cap2 +from nose.tools import eq_ + +def test_one_word(): + text = 'duck' + result = cap.just_do_it(text) + eq_(result, 'Duck') + +def test_multiple_words(): + text = 'a veritable flock of ducks' + result = cap.just_do_it(text) + eq_(result, 'A Veritable Flock Of Ducks') + +def test_words_with_apostrophes(): + text = "I'm fresh out of ideas" + result = cap.just_do_it(text) + eq_(result, "I'm Fresh Out Of Ideas") + +def test_words_with_quotes(): + text = "\"You're despicable,\" said Daffy Duck" + result = cap.just_do_it(text) + eq_(result, "\"You're Despicable,\" Said Daffy Duck") diff --git a/ch19/test_dump.py b/ch19/test_dump.py new file mode 100644 index 0000000..4762343 --- /dev/null +++ b/ch19/test_dump.py @@ -0,0 +1,11 @@ +from dump import dump + +@dump +def double(*args, **kwargs): + "Double every argument" + output_list = [ 2 * arg for arg in args ] + output_dict = { k:2*v for k,v in kwargs.items() } + return output_list, output_dict + +if __name__ == '__main__': + output = double(3, 5, first=100, next=98.6, last=-40) diff --git a/ch19/time1.py b/ch19/time1.py new file mode 100644 index 0000000..7538282 --- /dev/null +++ b/ch19/time1.py @@ -0,0 +1,6 @@ +from time import time + +t1 = time() +num = 5 +num *= 2 +print(time() - t1) diff --git a/ch19/time2.py b/ch19/time2.py new file mode 100644 index 0000000..bd62731 --- /dev/null +++ b/ch19/time2.py @@ -0,0 +1,5 @@ +from time import time, sleep + +t1 = time() +sleep(1.0) +print(time() - t1) diff --git a/ch19/time_lists.py b/ch19/time_lists.py new file mode 100644 index 0000000..fdecfe6 --- /dev/null +++ b/ch19/time_lists.py @@ -0,0 +1,14 @@ +from timeit import timeit + +def make_list_1(): + result = [] + for value in range(1000): + result.append(value) + return result + +def make_list_2(): + result = [value for value in range(1000)] + return result + +print('make_list_1 takes', timeit(make_list_1, number=1000), 'seconds') +print('make_list_2 takes', timeit(make_list_2, number=1000), 'seconds') diff --git a/ch19/timeit1.py b/ch19/timeit1.py new file mode 100644 index 0000000..9e145bf --- /dev/null +++ b/ch19/timeit1.py @@ -0,0 +1,3 @@ +from timeit import timeit + +print(timeit('num = 5; num *= 2', number=1)) diff --git a/ch19/timeit2.py b/ch19/timeit2.py new file mode 100644 index 0000000..f1a4647 --- /dev/null +++ b/ch19/timeit2.py @@ -0,0 +1,3 @@ +from timeit import repeat + +print(repeat('num = 5; num *= 2', number=1, repeat=3))