├── .gitignore ├── 1st_edition ├── README.md ├── art │ ├── matplotlib1.py │ └── panda1.py ├── boxes │ ├── report.py │ ├── report2.py │ ├── test1.py │ ├── test2.py │ ├── test3.py │ ├── weatherman2.py │ ├── weatherman3.py │ └── weatherman4.py ├── bus │ ├── bubbles1.py │ ├── map1.py │ ├── zoo.csv │ └── zoo_counts.py ├── dev │ ├── cap.py │ ├── capitals.py │ ├── capitals2.py │ ├── cities1.csv │ ├── cities2.csv │ ├── dump1.py │ ├── ftoc1.py │ ├── ftoc2.py │ ├── style1.py │ ├── style2.py │ ├── style3.py │ ├── test_cap.py │ ├── test_cap_nose.py │ ├── test_dump.py │ ├── time1.py │ ├── time2.py │ ├── time_lists.py │ ├── timeit1.py │ └── timeit2.py ├── intro │ ├── 54321.py │ ├── 61.py │ ├── archive.py │ ├── archive2.py │ ├── cliches.py │ ├── im.c │ ├── im.cpp │ ├── im.java │ ├── im.php │ ├── im.pl │ ├── im.py │ ├── im.rb │ ├── im.sh │ ├── stooges.py │ ├── youtube.py │ └── youtube2.py ├── net │ ├── dishes.py │ ├── fab1.py │ ├── fab2.py │ ├── fab3.py │ ├── fab4.py │ ├── gevent_monkey.py │ ├── gevent_test.py │ ├── knock_client.py │ ├── knock_server.py │ ├── msppack_client.py │ ├── msppack_server.py │ ├── redis_dryer.py │ ├── redis_dryer2.py │ ├── redis_pub.py │ ├── redis_sub.py │ ├── redis_washer.py │ ├── tcp_client.py │ ├── tcp_server.py │ ├── thread_dishes.py │ ├── threads.py │ ├── udp_client.py │ ├── udp_server.py │ ├── xmlrpc_client.py │ ├── xmlrpc_server.py │ ├── zmq_client.py │ ├── zmq_pub.py │ ├── zmq_server.py │ └── zmq_sub.py ├── storage │ ├── lolz.xml │ ├── mcintyre.yaml │ └── settings.cfg ├── sys │ ├── mp.py │ └── mp3.py └── web │ ├── bottle1.py │ ├── bottle2.py │ ├── bottle3.py │ ├── bottle_test.py │ ├── flask1.py │ ├── flask2.py │ ├── flask3a.py │ ├── flask3b.py │ ├── flask3c.py │ ├── home.wsgi │ ├── links.py │ └── templates │ ├── flask3.html │ ├── flasks.html │ └── home.html ├── README.md ├── ch01 ├── archive.py ├── archive2.py ├── countdown.py ├── quotes.py └── spells.py ├── ch05 ├── poem.py ├── poem2.py └── poem3.py ├── ch11 ├── choices │ ├── advice.oy │ └── fast.py ├── fast.py ├── fast2.py ├── fast3.py ├── fast4.py ├── fast5.py ├── lunch.py └── questions.py ├── ch12 └── mammoth.txt ├── ch14 └── convert_image.py ├── ch15 ├── cf.py ├── cf2.py ├── dishes.py ├── gevent_monkey.py ├── gevent_test.py ├── knock_client.py ├── knock_server.py ├── mp.py ├── mp2.py ├── redis_dryer.py ├── redis_dryer2.py ├── redis_washer.py ├── tasks.py ├── thread1.py └── thread_dishes.py ├── ch16 └── villains.csv ├── ch17 ├── jsonrpc_client.py ├── jsonrpc_server.py ├── msgpack_client.py ├── msgpack_server.py ├── redis_pub.py ├── redis_sub.py ├── tcp_client.py ├── tcp_server.py ├── udp_client.py ├── udp_server.py ├── xmlrpc_client.py ├── xmlrpc_server.py ├── zerorpc_client.py ├── zerorpc_server.py ├── zmq_client.py ├── zmq_pub.py ├── zmq_server.py └── zmq_sub.py ├── ch18 ├── bottle1.py ├── bottle2.py ├── bottle3.py ├── bottle_test.py ├── flask1.py ├── flask2.html ├── flask2.py ├── flask3a.py ├── flask3b.py ├── flask3c.py ├── home.wsgi ├── ia.py ├── ia_movies.py └── links.py └── ch19 ├── cap.py ├── cap.pyc ├── cap2.py ├── capitals.py ├── capitals2.py ├── cities.csv ├── cities2.csv ├── dump.py ├── dump.pyc ├── ftoc1.py ├── ftoc2.py ├── style1.py ├── style2.py ├── style3.py ├── test.py ├── test_cap.py ├── test_cap_nose.py ├── test_dump.py ├── time1.py ├── time2.py ├── time_lists.py ├── timeit1.py └── timeit2.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.pyc 3 | -------------------------------------------------------------------------------- /1st_edition/README.md: -------------------------------------------------------------------------------- 1 | Introducing Python 2 | ================= 3 | 4 | This repository contains the programs featured in _Introducing Python_. 5 | Some examples have been updated for the second and third printings. 6 | 7 | |directory|chapter| 8 | |---|---| 9 | |[intro](intro)| 1. A taste of Py 10 | | | 2. Py ingredients: numbers, strings, and variables 11 | | | 3. Py filling: lists, tuples, dictionaries, and sets 12 | | | 4. Py crust: code structures 13 | |[boxes](boxes)| 5. Py boxes: modules, packages, and programs 14 | | | 6. Oh oh: objects and classes 15 | | | 7. Mangle data like a pro 16 | |[storage](storage)|8. Data has to go somewhere 17 | |[web](web) | 9. The web, untangled 18 | |[sys](sys) | 10. Systems 19 | |[net](net) | 11. Concurrency and networks 20 | |[dev](dev) | 12. Be a pythonista 21 | |[art](art) | A. Py art 22 | |[bus](bus) | B. Py at work 23 | | | C. Py sci 24 | | | D. Install Python 3 25 | | | E. Answers to exercises 26 | | | F. Cheatsheets 27 | -------------------------------------------------------------------------------- /1st_edition/art/matplotlib1.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plot 2 | import matplotlib.image as image 3 | 4 | img = image.imread('oreilly.png') 5 | plot.imshow(img) 6 | plot.show() 7 | -------------------------------------------------------------------------------- /1st_edition/art/panda1.py: -------------------------------------------------------------------------------- 1 | from direct.showbase.ShowBase import ShowBase 2 | 3 | class MyApp(ShowBase): 4 | 5 | def __init__(self): 6 | ShowBase.__init__(self) 7 | 8 | # Load the environment model. 9 | self.environ = self.loader.loadModel("models/environment") 10 | # Reparent the model to render. 11 | self.environ.reparentTo(self.render) 12 | # Apply scale and position transforms on the model. 13 | self.environ.setScale(0.25, 0.25, 0.25) 14 | self.environ.setPos(-8, 42, 0) 15 | 16 | app = MyApp() 17 | app.run() 18 | -------------------------------------------------------------------------------- /1st_edition/boxes/report.py: -------------------------------------------------------------------------------- 1 | def get_description(): # see the docstring below? 2 | """Return random weather, just like the pros""" 3 | from random import choice 4 | possibilities = ['rain', 'snow', 'sleet', 'fog', 'sun', 'who knows'] 5 | return choice(possibilities) 6 | -------------------------------------------------------------------------------- /1st_edition/boxes/report2.py: -------------------------------------------------------------------------------- 1 | def get_description(): 2 | import random 3 | possibilities = ['rain', 'snow', 'sleet', 'fog', 'sun', 'who knows'] 4 | return random.choice(possibilities) 5 | -------------------------------------------------------------------------------- /1st_edition/boxes/test1.py: -------------------------------------------------------------------------------- 1 | print("This standalone program works!") 2 | -------------------------------------------------------------------------------- /1st_edition/boxes/test2.py: -------------------------------------------------------------------------------- 1 | import sys 2 | print('Program arguments:', sys.argv) 3 | -------------------------------------------------------------------------------- /1st_edition/boxes/test3.py: -------------------------------------------------------------------------------- 1 | import report 2 | 3 | description = report.get_description() 4 | print("Today's weather:", description) 5 | -------------------------------------------------------------------------------- /1st_edition/boxes/weatherman2.py: -------------------------------------------------------------------------------- 1 | import report as wr 2 | description = wr.get_description() 3 | print("Today's weather:", description) 4 | -------------------------------------------------------------------------------- /1st_edition/boxes/weatherman3.py: -------------------------------------------------------------------------------- 1 | from report import get_description 2 | description = get_description() 3 | print("Today's weather:", description) 4 | -------------------------------------------------------------------------------- /1st_edition/boxes/weatherman4.py: -------------------------------------------------------------------------------- 1 | from report import get_description as do_it 2 | description = do_it() 3 | print("Today's weather:", description) 4 | 5 | -------------------------------------------------------------------------------- /1st_edition/bus/bubbles1.py: -------------------------------------------------------------------------------- 1 | import bubbles 2 | 3 | p = bubbles.Pipeline() 4 | p.source(bubbles.data_object('csv_source', 'zoo.csv', infer_fields=True)) 5 | p.aggregate('animal', 'hush') 6 | p.pretty_print() 7 | -------------------------------------------------------------------------------- /1st_edition/bus/map1.py: -------------------------------------------------------------------------------- 1 | def display_shapefile(name, iwidth=500, iheight=500): 2 | import shapefile 3 | from PIL import Image, ImageDraw 4 | r = shapefile.Reader(name) 5 | mleft, mbottom, mright, mtop = r.bbox 6 | # map units 7 | mwidth = mright - mleft 8 | mheight = mtop - mbottom 9 | # scale map units to image units 10 | hscale = iwidth/mwidth 11 | vscale = iheight/mheight 12 | img = Image.new("RGB", (iwidth, iheight), "white") 13 | draw = ImageDraw.Draw(img) 14 | for shape in r.shapes(): 15 | pixels = [ 16 | (int(iwidth - ((mright - x) * hscale)), int((mtop - y) * vscale)) 17 | for x, y in shape.points] 18 | if shape.shapeType == shapefile.POLYGON: 19 | draw.polygon(pixels, outline='black') 20 | elif shape.shapeType == shapefile.POLYLINE: 21 | draw.line(pixels, fill='black') 22 | img.show() 23 | 24 | if __name__ == '__main__': 25 | import sys 26 | display_shapefile(sys.argv[1], 700, 700) 27 | -------------------------------------------------------------------------------- /1st_edition/bus/zoo.csv: -------------------------------------------------------------------------------- 1 | animal,bites,stitches,hush 2 | bear,1,35,300 3 | marmoset,1,2,250 4 | bear,2,42,500 5 | elk,1,30,100 6 | weasel,4,7,50 7 | duck,2,0,10 8 | -------------------------------------------------------------------------------- /1st_edition/bus/zoo_counts.py: -------------------------------------------------------------------------------- 1 | import csv 2 | from collections import Counter 3 | 4 | counts = Counter() 5 | with open('zoo.csv', 'rt') as fin: 6 | cin = csv.reader(fin) 7 | for num, row in enumerate(cin): 8 | if num > 0: 9 | counts[row[0]] += int(row[-1]) 10 | for animal, hush in counts.items(): 11 | print("%10s %10s" % (animal, hush)) 12 | -------------------------------------------------------------------------------- /1st_edition/dev/cap.py: -------------------------------------------------------------------------------- 1 | def just_do_it(text): 2 | "Capitalize all words in " 3 | return text.capitalize() 4 | -------------------------------------------------------------------------------- /1st_edition/dev/capitals.py: -------------------------------------------------------------------------------- 1 | def process_cities(filename): 2 | with open(filename, 'rt') as file: 3 | for line in file: 4 | line = line.strip() 5 | if 'quit' in line.lower(): 6 | return 7 | country, city = line.split(',') 8 | city = city.strip() 9 | country = country.strip() 10 | print(city.title(), country.title(), sep=',') 11 | 12 | if __name__ == '__main__': 13 | import sys 14 | process_cities(sys.argv[1]) 15 | -------------------------------------------------------------------------------- /1st_edition/dev/capitals2.py: -------------------------------------------------------------------------------- 1 | def process_cities(filename): 2 | with open(filename, 'rt') as file: 3 | for line in file: 4 | line = line.strip() 5 | if 'quit' == line.lower(): 6 | return 7 | country, city = line.split(',') 8 | city = city.strip() 9 | country = country.strip() 10 | print(city.title(), country.title(), sep=',') 11 | 12 | if __name__ == '__main__': 13 | import sys 14 | process_cities(sys.argv[1]) 15 | -------------------------------------------------------------------------------- /1st_edition/dev/cities1.csv: -------------------------------------------------------------------------------- 1 | France, Paris 2 | venuzuela,caracas 3 | LithuniA,vilnius 4 | quit 5 | -------------------------------------------------------------------------------- /1st_edition/dev/cities2.csv: -------------------------------------------------------------------------------- 1 | argentina,buenos aires 2 | bolivia,la paz 3 | brazil,brasilia 4 | chile,santiago 5 | colombia,Bogotá 6 | ecuador,quito 7 | falkland islands,stanley 8 | french guiana,cayenne 9 | guyana,georgetown 10 | paraguay,Asunción 11 | peru,lima 12 | suriname,paramaribo 13 | uruguay,montevideo 14 | venezuela,caracas 15 | quit 16 | -------------------------------------------------------------------------------- /1st_edition/dev/dump1.py: -------------------------------------------------------------------------------- 1 | def dump(func): 2 | "Print input arguments and output value(s)" 3 | def wrapped(*args, **kwargs): 4 | print("Function name: %s" % func.__name__) 5 | print("Input arguments: %s" % ' '.join(map(str, args))) 6 | print("Input keyword arguments: %s" % kwargs.items()) 7 | output = func(*args, **kwargs) 8 | print("Output:", output) 9 | return output 10 | return wrapped 11 | -------------------------------------------------------------------------------- /1st_edition/dev/ftoc1.py: -------------------------------------------------------------------------------- 1 | def ftoc(f_temp): 2 | "Convert Fahrenheit temperature to Celsius and return it." 3 | f_boil_temp = 212.0 4 | f_freeze_temp = 32.0 5 | c_boil_temp = 100.0 6 | c_freeze_temp = 0.0 7 | f_range = f_boil_temp - f_freeze_temp 8 | c_range = c_boil_temp - c_freeze_temp 9 | f_c_ratio = c_range / f_range 10 | c_temp = (f_temp - f_freeze_temp) * f_c_ratio + c_freeze_temp 11 | return c_temp 12 | 13 | if __name__ == '__main__': 14 | for f_temp in [-40.0, 0.0, 32.0, 100.0, 212.0]: 15 | c_temp = ftoc(f_temp) 16 | print('%f F => %f C' % (f_temp, c_temp)) 17 | -------------------------------------------------------------------------------- /1st_edition/dev/ftoc2.py: -------------------------------------------------------------------------------- 1 | F_BOIL_TEMP = 212.0 2 | F_FREEZE_TEMP = 32.0 3 | C_BOIL_TEMP = 100.0 4 | C_FREEZE_TEMP = 0.0 5 | F_RANGE = F_BOIL_TEMP - F_FREEZE_TEMP 6 | C_RANGE = C_BOIL_TEMP - C_FREEZE_TEMP 7 | F_C_RATIO = C_RANGE / F_RANGE 8 | 9 | def ftoc(f_temp): 10 | "Convert Fahrenheit temperature to Celsius and return it." 11 | c_temp = (f_temp - F_FREEZE_TEMP) * F_C_RATIO + C_FREEZE_TEMP 12 | return c_temp 13 | 14 | if __name__ == '__main__': 15 | for f_temp in [-40.0, 0.0, 32.0, 100.0, 212.0]: 16 | c_temp = ftoc(f_temp) 17 | print('%f F => %f C' % (f_temp, c_temp)) 18 | -------------------------------------------------------------------------------- /1st_edition/dev/style1.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | b = 2 3 | print(a) 4 | print(b) 5 | print(c) 6 | -------------------------------------------------------------------------------- /1st_edition/dev/style2.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | b = 2 3 | c = 3 4 | print(a) 5 | print(b) 6 | print(c) 7 | -------------------------------------------------------------------------------- /1st_edition/dev/style3.py: -------------------------------------------------------------------------------- 1 | "Module docstring goes here" 2 | 3 | def func(): 4 | "Function docstring goes here. Hi, Mom!" 5 | first = 1 6 | second = 2 7 | third = 3 8 | print(first) 9 | print(second) 10 | print(third) 11 | 12 | func() 13 | -------------------------------------------------------------------------------- /1st_edition/dev/test_cap.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import cap 3 | 4 | class TestCap(unittest.TestCase): 5 | 6 | def setUp(self): 7 | pass 8 | 9 | def tearDown(self): 10 | pass 11 | 12 | def test_one_word(self): 13 | text = 'duck' 14 | result = cap.just_do_it(text) 15 | self.assertEqual(result, 'Duck') 16 | 17 | def test_multiple_words(self): 18 | text = 'a veritable flock of ducks' 19 | result = cap.just_do_it(text) 20 | self.assertEqual(result, 'A Veritable Flock Of Ducks') 21 | 22 | 23 | if __name__ == '__main__': 24 | unittest.main() 25 | -------------------------------------------------------------------------------- /1st_edition/dev/test_cap_nose.py: -------------------------------------------------------------------------------- 1 | import cap 2 | from nose.tools import eq_ 3 | 4 | def test_one_word(): 5 | text = 'duck' 6 | result = cap.just_do_it(text) 7 | eq_(result, 'Duck') 8 | 9 | def test_multiple_words(): 10 | text = 'a veritable flock of ducks' 11 | result = cap.just_do_it(text) 12 | eq_(result, 'A Veritable Flock Of Ducks') 13 | 14 | def test_words_with_apostrophes(): 15 | text = "I'm fresh out of ideas" 16 | result = cap.just_do_it(text) 17 | eq_(result, "I'm Fresh Out Of Ideas") 18 | 19 | def test_words_with_quotes(): 20 | text = "\"You're despicable,\" said Daffy Duck" 21 | result = cap.just_do_it(text) 22 | eq_(result, "\"You're Despicable,\" Said Daffy Duck") 23 | -------------------------------------------------------------------------------- /1st_edition/dev/test_dump.py: -------------------------------------------------------------------------------- 1 | from dump1 import dump 2 | 3 | @dump 4 | def double(*args, **kwargs): 5 | "Double every argument" 6 | output_list = [ 2 * arg for arg in args ] 7 | output_dict = { k:2*v for k,v in kwargs.items() } 8 | return output_list, output_dict 9 | 10 | if __name__ == '__main__': 11 | output = double(3, 5, first=100, next=98.6, last=-40) 12 | -------------------------------------------------------------------------------- /1st_edition/dev/time1.py: -------------------------------------------------------------------------------- 1 | from time import time 2 | 3 | t1 = time() 4 | num = 5 5 | num *= 2 6 | print(time() - t1) 7 | -------------------------------------------------------------------------------- /1st_edition/dev/time2.py: -------------------------------------------------------------------------------- 1 | from time import time, sleep 2 | 3 | t1 = time() 4 | sleep(1.0) 5 | print(time() - t1) 6 | -------------------------------------------------------------------------------- /1st_edition/dev/time_lists.py: -------------------------------------------------------------------------------- 1 | from timeit import timeit 2 | 3 | def make_list_1(): 4 | result = [] 5 | for value in range(1000): 6 | result.append(value) 7 | return result 8 | 9 | def make_list_2(): 10 | result = [value for value in range(1000)] 11 | return result 12 | 13 | print('make_list_1 takes', timeit(make_list_1, number=1000), 'seconds') 14 | print('make_list_2 takes', timeit(make_list_2, number=1000), 'seconds') 15 | -------------------------------------------------------------------------------- /1st_edition/dev/timeit1.py: -------------------------------------------------------------------------------- 1 | from timeit import timeit 2 | print(timeit('num = 5; num *= 2', number=1)) 3 | -------------------------------------------------------------------------------- /1st_edition/dev/timeit2.py: -------------------------------------------------------------------------------- 1 | from timeit import repeat 2 | print(repeat('num = 5; num *= 2', number=1, repeat=3)) 3 | -------------------------------------------------------------------------------- /1st_edition/intro/54321.py: -------------------------------------------------------------------------------- 1 | for countdown in 5, 4, 3, 2, 1, "hey!": 2 | print(countdown) 3 | -------------------------------------------------------------------------------- /1st_edition/intro/61.py: -------------------------------------------------------------------------------- 1 | print(61) 2 | -------------------------------------------------------------------------------- /1st_edition/intro/archive.py: -------------------------------------------------------------------------------- 1 | import webbrowser 2 | import json 3 | from urllib.request import urlopen 4 | 5 | print("Let's find an old website.") 6 | site = input("Type a website URL: ") 7 | era = input("Type a year, month, and day, like 20150613: ") 8 | url = "http://archive.org/wayback/available?url=%s×tamp=%s" % (site, era) 9 | response = urlopen(url) 10 | contents = response.read() 11 | text = contents.decode("utf-8") 12 | data = json.loads(text) 13 | try : 14 | old_site = data["archived_snapshots"]["closest"]["url"] 15 | print("Found this copy: ", old_site) 16 | print("It should appear in your browser now.") 17 | webbrowser.open(old_site) 18 | except : 19 | print("Sorry, no luck finding", site) 20 | -------------------------------------------------------------------------------- /1st_edition/intro/archive2.py: -------------------------------------------------------------------------------- 1 | import webbrowser 2 | import requests 3 | 4 | print("Let's find an old website.") 5 | site = input("Type a website URL: ") 6 | era = input("Type a year, month, and day, like 20150613: ") 7 | url = "http://archive.org/wayback/available?url=%s×tamp=%s" % (site, era) 8 | response = requests.get(url) 9 | data = response.json() 10 | try : 11 | old_site = data["archived_snapshots"]["closest"]["url"] 12 | print("Found this copy: ", old_site) 13 | print("It should appear in your browser now.") 14 | webbrowser.open(old_site) 15 | except : 16 | print("Sorry, no luck finding", site) 17 | -------------------------------------------------------------------------------- /1st_edition/intro/cliches.py: -------------------------------------------------------------------------------- 1 | cliches = [ 2 | "At the end of the day", 3 | "Having said that", 4 | "The fact of the matter is", 5 | "Be that as it may", 6 | "The bottom line is", 7 | "If you will", 8 | ] 9 | print(cliches[3]) 10 | -------------------------------------------------------------------------------- /1st_edition/intro/im.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char *argv[]) { 3 | int language = 1; 4 | printf("Language %d: I am C! Behold me and tremble!\n", language); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /1st_edition/intro/im.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int main() { 4 | int language = 2; 5 | cout << "Language " << language << \ 6 | ": I am C++! Pay no attention to that C behind the curtain!" << \ 7 | endl; 8 | return(0); 9 | } 10 | -------------------------------------------------------------------------------- /1st_edition/intro/im.java: -------------------------------------------------------------------------------- 1 | public class Overlord { 2 | public static void main (String[] args) { 3 | int language = 3; 4 | System.out.format("Language %d: I am Java! Scarier than C!\n", language); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /1st_edition/intro/im.php: -------------------------------------------------------------------------------- 1 | language = 5 2 | puts "Language #{language}: I am Ruby, ready and aglow." 3 | -------------------------------------------------------------------------------- /1st_edition/intro/im.pl: -------------------------------------------------------------------------------- 1 | my $language = 4; 2 | print "Language $language: I am Perl, the camel of languages.\n"; 3 | -------------------------------------------------------------------------------- /1st_edition/intro/im.py: -------------------------------------------------------------------------------- 1 | language = 7 2 | print("Language %s: I am Python. What's for supper?" % language) 3 | -------------------------------------------------------------------------------- /1st_edition/intro/im.rb: -------------------------------------------------------------------------------- 1 | language = 5 2 | puts "Language #{language}: I am Ruby, ready and aglow." 3 | -------------------------------------------------------------------------------- /1st_edition/intro/im.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | language=0 3 | echo "Language $language: I am the shell. So there." 4 | -------------------------------------------------------------------------------- /1st_edition/intro/stooges.py: -------------------------------------------------------------------------------- 1 | quotes = { 2 | "Moe": "A wise guy, huh?", 3 | "Larry": "Ow!", 4 | "Curly": "Nyuk nyuk!", 5 | } 6 | stooge = "Curly" 7 | print(stooge, "says:", quotes[stooge]) 8 | -------------------------------------------------------------------------------- /1st_edition/intro/youtube.py: -------------------------------------------------------------------------------- 1 | import json 2 | from urllib.request import urlopen 3 | url = "https://gdata.youtube.com/feeds/api/standardfeeds/top_rated?alt=json" 4 | response = urlopen(url) 5 | contents = response.read() 6 | text = contents.decode('utf8') 7 | data = json.loads(text) 8 | for video in data['feed']['entry'][0:6]: 9 | print(video['title']['$t']) 10 | -------------------------------------------------------------------------------- /1st_edition/intro/youtube2.py: -------------------------------------------------------------------------------- 1 | import requests 2 | url = "https://gdata.youtube.com/feeds/api/standardfeeds/top_rated?alt=json" 3 | response = requests.get(url) 4 | data = response.json() 5 | for video in data['feed']['entry'][0:6]: 6 | print(video['title']['$t']) 7 | -------------------------------------------------------------------------------- /1st_edition/net/dishes.py: -------------------------------------------------------------------------------- 1 | import multiprocessing as mp 2 | 3 | def washer(dishes, output): 4 | for dish in dishes: 5 | print('Washing', dish, 'dish') 6 | output.put(dish) 7 | 8 | def dryer(input): 9 | while True: 10 | dish = input.get() 11 | print('Drying', dish, 'dish') 12 | input.task_done() 13 | 14 | dish_queue = mp.JoinableQueue() 15 | dryer_proc = mp.Process(target=dryer, args=(dish_queue,)) 16 | dryer_proc.daemon = True 17 | dryer_proc.start() 18 | 19 | dishes = ['salad', 'bread', 'entree', 'dessert'] 20 | washer(dishes, dish_queue) 21 | dish_queue.join() 22 | -------------------------------------------------------------------------------- /1st_edition/net/fab1.py: -------------------------------------------------------------------------------- 1 | def iso(): 2 | from datetime import date 3 | print(date.today().isoformat()) 4 | -------------------------------------------------------------------------------- /1st_edition/net/fab2.py: -------------------------------------------------------------------------------- 1 | from fabric.api import local 2 | 3 | def iso(): 4 | local('date -u') 5 | -------------------------------------------------------------------------------- /1st_edition/net/fab3.py: -------------------------------------------------------------------------------- 1 | from fabric.api import run 2 | 3 | def iso(): 4 | run('date -u') 5 | -------------------------------------------------------------------------------- /1st_edition/net/fab4.py: -------------------------------------------------------------------------------- 1 | from fabric.api import run 2 | from fabric.context_managers import env 3 | 4 | env.password = "your password goes here" 5 | 6 | def iso(): 7 | run('date -u') 8 | -------------------------------------------------------------------------------- /1st_edition/net/gevent_monkey.py: -------------------------------------------------------------------------------- 1 | import gevent 2 | from gevent import monkey; monkey.patch_all() 3 | import socket 4 | hosts = ['www.crappytaxidermy.com', 'www.walterpottertaxidermy.com', 5 | 'www.antique-taxidermy.com'] 6 | jobs = [gevent.spawn(socket.gethostbyname, host) for host in hosts] 7 | gevent.joinall(jobs, timeout=5) 8 | for job in jobs: 9 | print(job.value) 10 | -------------------------------------------------------------------------------- /1st_edition/net/gevent_test.py: -------------------------------------------------------------------------------- 1 | import gevent 2 | from gevent import socket 3 | hosts = ['www.crappytaxidermy.com', 'www.walterpottertaxidermy.com', 4 | 'www.antique-taxidermy.com'] 5 | jobs = [gevent.spawn(gevent.socket.gethostbyname, host) for host in hosts] 6 | gevent.joinall(jobs, timeout=5) 7 | for job in jobs: 8 | print(job.value) 9 | -------------------------------------------------------------------------------- /1st_edition/net/knock_client.py: -------------------------------------------------------------------------------- 1 | from twisted.internet import reactor, protocol 2 | 3 | class KnockClient(protocol.Protocol): 4 | def connectionMade(self): 5 | self.transport.write("Knock knock") 6 | 7 | def dataReceived(self, data): 8 | if data.startswith("Who's there?"): 9 | response = "Disappearing client" 10 | self.transport.write(response) 11 | else: 12 | self.transport.loseConnection() 13 | reactor.stop() 14 | 15 | class KnockFactory(protocol.ClientFactory): 16 | protocol = KnockClient 17 | 18 | def main(): 19 | f = KnockFactory() 20 | reactor.connectTCP("localhost", 8000, f) 21 | reactor.run() 22 | 23 | if __name__ == '__main__': 24 | main() 25 | -------------------------------------------------------------------------------- /1st_edition/net/knock_server.py: -------------------------------------------------------------------------------- 1 | from twisted.internet import protocol, reactor 2 | 3 | class Knock(protocol.Protocol): 4 | def dataReceived(self, data): 5 | print 'Client:', data 6 | if data.startswith("Knock knock"): 7 | response = "Who's there?" 8 | else: 9 | response = data + " who?" 10 | print 'Server:', response 11 | self.transport.write(response) 12 | 13 | class KnockFactory(protocol.Factory): 14 | def buildProtocol(self, addr): 15 | return Knock() 16 | 17 | reactor.listenTCP(8000, KnockFactory()) 18 | reactor.run() 19 | -------------------------------------------------------------------------------- /1st_edition/net/msppack_client.py: -------------------------------------------------------------------------------- 1 | from msgpackrpc import Client, Address 2 | 3 | client = Client(Address("localhost", 6789)) 4 | num = 8 5 | result = client.call('double', num) 6 | print("Double %s is %s" % (num, result)) 7 | -------------------------------------------------------------------------------- /1st_edition/net/msppack_server.py: -------------------------------------------------------------------------------- 1 | from msgpackrpc import Server, Address 2 | 3 | class Services(): 4 | def double(self, num): 5 | return num * 2 6 | 7 | server = Server(Services()) 8 | server.listen(Address("localhost", 6789)) 9 | server.start() 10 | -------------------------------------------------------------------------------- /1st_edition/net/redis_dryer.py: -------------------------------------------------------------------------------- 1 | import redis 2 | conn = redis.Redis() 3 | print('Dryer is starting') 4 | while True: 5 | msg = conn.blpop('dishes') 6 | if not msg: 7 | break 8 | val = msg[1].decode('utf-8') 9 | if val == 'quit': 10 | break 11 | print('Dried', val) 12 | print('Dishes are dried') 13 | -------------------------------------------------------------------------------- /1st_edition/net/redis_dryer2.py: -------------------------------------------------------------------------------- 1 | def dryer(): 2 | import redis 3 | import os 4 | import time 5 | conn = redis.Redis() 6 | pid = os.getpid() 7 | timeout = 20 8 | print('Dryer process %s is starting' % pid) 9 | while True: 10 | msg = conn.blpop('dishes', timeout) 11 | if not msg: 12 | break 13 | val = msg[1].decode('utf-8') 14 | if val == 'quit': 15 | break 16 | print('%s: dried %s' % (pid, val)) 17 | time.sleep(0.1) 18 | print('Dryer process %s is done' % pid) 19 | 20 | import multiprocessing 21 | DRYERS=3 22 | for num in range(DRYERS): 23 | p = multiprocessing.Process(target=dryer) 24 | p.start() 25 | -------------------------------------------------------------------------------- /1st_edition/net/redis_pub.py: -------------------------------------------------------------------------------- 1 | import redis 2 | import random 3 | 4 | conn = redis.Redis() 5 | cats = ['siamese', 'persian', 'maine coon', 'norwegian forest'] 6 | hats = ['stovepipe', 'bowler', 'tam-o-shanter', 'fedora'] 7 | for msg in range(10): 8 | cat = random.choice(cats) 9 | hat = random.choice(hats) 10 | print('Publish: %s wears a %s' % (cat, hat)) 11 | conn.publish(cat, hat) 12 | -------------------------------------------------------------------------------- /1st_edition/net/redis_sub.py: -------------------------------------------------------------------------------- 1 | import redis 2 | conn = redis.Redis() 3 | 4 | topics = ['maine coon', 'persian'] 5 | sub = conn.pubsub() 6 | sub.subscribe(topics) 7 | for msg in sub.listen(): 8 | if msg['type'] == 'message': 9 | cat = msg['channel'] 10 | hat = msg['data'] 11 | print('Subscribe: %s wears a %s' % (cat, hat)) 12 | -------------------------------------------------------------------------------- /1st_edition/net/redis_washer.py: -------------------------------------------------------------------------------- 1 | import redis 2 | conn = redis.Redis() 3 | print('Washer is starting') 4 | dishes = ['salad', 'bread', 'entree', 'dessert'] 5 | for dish in dishes: 6 | msg = dish.encode('utf-8') 7 | conn.rpush('dishes', msg) 8 | print('Washed', num) 9 | conn.rpush('dishes', 'quit') 10 | print('Washer is done') 11 | -------------------------------------------------------------------------------- /1st_edition/net/tcp_client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from datetime import datetime 3 | 4 | address = ('localhost', 6789) 5 | max_size = 1000 6 | 7 | print('Starting the client at', datetime.now()) 8 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 | client.connect(address) 10 | client.sendall(b'Hey!') 11 | data = client.recv(max_size) 12 | print('At', datetime.now(), 'someone replied', data) 13 | client.close() 14 | -------------------------------------------------------------------------------- /1st_edition/net/tcp_server.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | import socket 3 | 4 | address = ('localhost', 6789) 5 | max_size = 1000 6 | 7 | print('Starting the server at', datetime.now()) 8 | print('Waiting for a client to call.') 9 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 | server.bind(address) 11 | server.listen(5) 12 | 13 | client, addr = server.accept() 14 | data = client.recv(max_size) 15 | 16 | print('At', datetime.now(), client, 'said', data) 17 | client.sendall(b'Are you talking to me?') 18 | client.close() 19 | server.close() 20 | -------------------------------------------------------------------------------- /1st_edition/net/thread_dishes.py: -------------------------------------------------------------------------------- 1 | import threading, queue 2 | import time 3 | 4 | def washer(dishes, dish_queue): 5 | for dish in dishes: 6 | print ("Washing", dish) 7 | time.sleep(5) 8 | dish_queue.put(dish) 9 | 10 | def dryer(dish_queue): 11 | while True: 12 | dish = dish_queue.get() 13 | print ("Drying", dish) 14 | time.sleep(10) 15 | dish_queue.task_done() 16 | 17 | 18 | dish_queue = queue.Queue() 19 | for n in range(2): 20 | dryer_thread = threading.Thread(target=dryer, args=(dish_queue,)) 21 | dryer_thread.start() 22 | 23 | dishes = ['salad', 'bread', 'entree', 'desert'] 24 | washer(dishes, dish_queue) 25 | dish_queue.join() 26 | -------------------------------------------------------------------------------- /1st_edition/net/threads.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | def do_this(what): 4 | whoami(what) 5 | 6 | def whoami(what): 7 | print("Thread %s says: %s" % (threading.current_thread(), what)) 8 | 9 | if __name__ == "__main__": 10 | whoami("I'm the main program") 11 | for n in range(4): 12 | p = threading.Thread(target=do_this, 13 | args=("I'm function %s" % n,)) 14 | p.start() 15 | -------------------------------------------------------------------------------- /1st_edition/net/udp_client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from datetime import datetime 3 | 4 | server_address = ('localhost', 6789) 5 | max_size = 4096 6 | 7 | print('Starting the client at', datetime.now()) 8 | client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 9 | client.sendto(b'Hey!', server_address) 10 | data, server = client.recvfrom(max_size) 11 | print('At', datetime.now(), server, 'said', data) 12 | client.close() 13 | -------------------------------------------------------------------------------- /1st_edition/net/udp_server.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | import socket 3 | 4 | server_address = ('localhost', 6789) 5 | max_size = 4096 6 | 7 | print('Starting the server at', datetime.now()) 8 | print('Waiting for a client to call.') 9 | server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 10 | server.bind(server_address) 11 | 12 | data, client = server.recvfrom(max_size) 13 | 14 | print('At', datetime.now(), client, 'said', data) 15 | server.sendto(b'Are you talking to me?', client) 16 | server.close() 17 | -------------------------------------------------------------------------------- /1st_edition/net/xmlrpc_client.py: -------------------------------------------------------------------------------- 1 | import xmlrpc.client 2 | 3 | proxy = xmlrpc.client.ServerProxy("http://localhost:6789/") 4 | num = 7 5 | result = proxy.double(num) 6 | print("Double %s is %s" % (num, result)) 7 | -------------------------------------------------------------------------------- /1st_edition/net/xmlrpc_server.py: -------------------------------------------------------------------------------- 1 | from xmlrpc.server import SimpleXMLRPCServer 2 | 3 | def double(num): 4 | return num * 2 5 | 6 | server = SimpleXMLRPCServer(("localhost", 6789)) 7 | server.register_function(double, "double") 8 | server.serve_forever() 9 | -------------------------------------------------------------------------------- /1st_edition/net/zmq_client.py: -------------------------------------------------------------------------------- 1 | import zmq 2 | 3 | host = '127.0.0.1' 4 | port = 6789 5 | context = zmq.Context() 6 | client = context.socket(zmq.REQ) 7 | client.connect("tcp://%s:%s" % (host, port)) 8 | for num in range(1, 6): 9 | request_str = "message #%s" % num 10 | request_bytes = request_str.encode('utf-8') 11 | client.send(request_bytes) 12 | reply_bytes = client.recv() 13 | reply_str = reply_bytes.decode('utf-8') 14 | print("Sent %s, received %s" % (request_str, reply_str)) 15 | -------------------------------------------------------------------------------- /1st_edition/net/zmq_pub.py: -------------------------------------------------------------------------------- 1 | import zmq 2 | import random 3 | import time 4 | host = '*' 5 | port = 6789 6 | ctx = zmq.Context() 7 | pub = ctx.socket(zmq.PUB) 8 | pub.bind('tcp://%s:%s' % (host, port)) 9 | cats = ['siamese', 'persian', 'maine coon', 'norwegian forest'] 10 | hats = ['stovepipe', 'bowler', 'tam-o-shanter', 'fedora'] 11 | time.sleep(1) 12 | for msg in range(10): 13 | cat = random.choice(cats) 14 | cat_bytes = cat.encode('utf-8') 15 | hat = random.choice(hats) 16 | hat_bytes = hat.encode('utf-8') 17 | print('Publish: %s wears a %s' % (cat, hat)) 18 | pub.send_multipart([cat_bytes, hat_bytes]) 19 | -------------------------------------------------------------------------------- /1st_edition/net/zmq_server.py: -------------------------------------------------------------------------------- 1 | import zmq 2 | 3 | host = '127.0.0.1' 4 | port = 6789 5 | context = zmq.Context() 6 | server = context.socket(zmq.REP) 7 | server.bind("tcp://%s:%s" % (host, port)) 8 | while True: 9 | # Wait for next request from client 10 | request_bytes = server.recv() 11 | request_str = request_bytes.decode('utf-8') 12 | print("That voice in my head says: %s" % request_str) 13 | reply_str = "Stop saying: %s" % request_str 14 | reply_bytes = bytes(reply_str, 'utf-8') 15 | server.send(reply_bytes) 16 | -------------------------------------------------------------------------------- /1st_edition/net/zmq_sub.py: -------------------------------------------------------------------------------- 1 | import zmq 2 | host = '127.0.0.1' 3 | port = 6789 4 | ctx = zmq.Context() 5 | sub = ctx.socket(zmq.SUB) 6 | sub.connect('tcp://%s:%s' % (host, port)) 7 | topics = ['maine coon', 'persian'] 8 | for topic in topics: 9 | sub.setsockopt(zmq.SUBSCRIBE, topic.encode('utf-8')) 10 | while True: 11 | cat_bytes, hat_bytes = sub.recv_multipart() 12 | cat = cat_bytes.decode('utf-8') 13 | hat = hat_bytes.decode('utf-8') 14 | print('Subscribe: %s wears a %s' % (cat, hat)) 15 | -------------------------------------------------------------------------------- /1st_edition/storage/lolz.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ]> 14 | &lol9; 15 | -------------------------------------------------------------------------------- /1st_edition/storage/mcintyre.yaml: -------------------------------------------------------------------------------- 1 | name: 2 | first: James 3 | last: McIntyre 4 | dates: 5 | birth: 1828-05-25 6 | death: 1906-03-31 7 | details: 8 | bearded: true 9 | themes: [cheese, Canada] 10 | books: 11 | url: http://www.gutenberg.org/files/36068/36068-h/36068-h.htm 12 | poems: 13 | - title: 'Motto' 14 | text: | 15 | Politeness, perseverance and pluck, 16 | To their possessor will bring good luck. 17 | - title: 'Canadian Charms' 18 | text: | 19 | Here industry is not in vain, 20 | For we have bounteous crops of grain, 21 | And you behold on every field 22 | Of grass and roots abundant yield, 23 | But after all the greatest charm 24 | Is the snug home upon the farm, 25 | And stone walls now keep cattle warm. 26 | -------------------------------------------------------------------------------- /1st_edition/storage/settings.cfg: -------------------------------------------------------------------------------- 1 | [english] 2 | greeting = Hello 3 | 4 | [french] 5 | greeting = Bonjour 6 | 7 | [files] 8 | home = /usr/local 9 | # simple interpolation: 10 | bin = %(home)s/bin 11 | -------------------------------------------------------------------------------- /1st_edition/sys/mp.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | import os 3 | 4 | def do_this(what): 5 | whoami(what) 6 | 7 | def whoami(what): 8 | print("Process %s says: %s" % (os.getpid(), what)) 9 | 10 | if __name__ == "__main__": 11 | whoami("I'm the main program") 12 | for n in range(4): 13 | p = multiprocessing.Process(target=do_this, 14 | args=("I'm function %s" % n,)) 15 | p.start() 16 | -------------------------------------------------------------------------------- /1st_edition/sys/mp3.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | import time 3 | import os 4 | 5 | def whoami(name): 6 | print("I'm %s, in process %s" % (name, os.getpid())) 7 | 8 | def loopy(name): 9 | whoami(name) 10 | start = 1 11 | stop = 1000000 12 | for num in range(start, stop): 13 | print("\tNumber %s of %s. Honk!" % (num, stop)) 14 | time.sleep(1) 15 | 16 | if __name__ == "__main__": 17 | whoami("main") 18 | p = multiprocessing.Process(target=loopy, args=("loopy",)) 19 | p.start() 20 | time.sleep(5) 21 | p.terminate() 22 | -------------------------------------------------------------------------------- /1st_edition/web/bottle1.py: -------------------------------------------------------------------------------- 1 | from bottle import route, run 2 | 3 | @route('/') 4 | def home(): 5 | return "It isn't fancy, but it's my home page" 6 | 7 | run(host='localhost', port=9999) 8 | -------------------------------------------------------------------------------- /1st_edition/web/bottle2.py: -------------------------------------------------------------------------------- 1 | from bottle import route, run, static_file 2 | 3 | @route('/') 4 | def main(): 5 | return static_file('index.html', root='.') 6 | 7 | run(host='localhost', port=9999) 8 | -------------------------------------------------------------------------------- /1st_edition/web/bottle3.py: -------------------------------------------------------------------------------- 1 | from bottle import route, run, static_file 2 | 3 | @route('/') 4 | def home(): 5 | return static_file('index.html', root='.') 6 | 7 | @route('/echo/') 8 | def echo(thing): 9 | return "Say hello to my little friend: %s!" % thing 10 | 11 | run(host='localhost', port=9999) 12 | -------------------------------------------------------------------------------- /1st_edition/web/bottle_test.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | resp = requests.get('http://localhost:9999/echo/Mothra') 4 | if resp.status_code == 200 and \ 5 | resp.text == 'Say hello to my little friend: Mothra!': 6 | print('It worked! That almost never happens!') 7 | else: 8 | print('Argh, got this:', resp.text) 9 | -------------------------------------------------------------------------------- /1st_edition/web/flask1.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__, static_folder='.', static_url_path='') 4 | 5 | @app.route('/') 6 | def home(): 7 | return app.send_static_file('index.html') 8 | 9 | @app.route('/echo/') 10 | def echo(thing): 11 | return thing 12 | 13 | app.run(port=9999, debug=True) 14 | -------------------------------------------------------------------------------- /1st_edition/web/flask2.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/echo/') 6 | def echo(thing): 7 | return render_template('flask2.html', thing=thing) 8 | 9 | app.run(port=9999, debug=True) 10 | -------------------------------------------------------------------------------- /1st_edition/web/flask3a.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/echo//') 6 | def echo(thing, place): 7 | return render_template('flask3.html', thing=thing, place=place) 8 | 9 | app.run(port=9999, debug=True) 10 | -------------------------------------------------------------------------------- /1st_edition/web/flask3b.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/echo/') 6 | def echo(): 7 | thing = request.args.get('thing') 8 | place = request.args.get('place') 9 | return render_template('flask3.html', thing=thing, place=place) 10 | 11 | app.run(port=9999, debug=True) 12 | -------------------------------------------------------------------------------- /1st_edition/web/flask3c.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/echo/') 6 | def echo(): 7 | kwargs = {} 8 | kwargs['thing'] = request.args.get('thing') 9 | kwargs['place'] = request.args.get('place') 10 | return render_template('flask3.html', **kwargs) 11 | 12 | app.run(port=9999, debug=True) 13 | -------------------------------------------------------------------------------- /1st_edition/web/home.wsgi: -------------------------------------------------------------------------------- 1 | import bottle 2 | 3 | application = bottle.default_app() 4 | 5 | @bottle.route('/') 6 | def home(): 7 | return "apache and wsgi, sitting in a tree" 8 | -------------------------------------------------------------------------------- /1st_edition/web/links.py: -------------------------------------------------------------------------------- 1 | def get_links(url): 2 | import requests 3 | from bs4 import BeautifulSoup as soup 4 | result = requests.get(url) 5 | page = result.text 6 | doc = soup(page) 7 | links = [element.get('href') for element in doc.find_all('a')] 8 | return links 9 | 10 | if __name__ == '__main__': 11 | import sys 12 | for url in sys.argv[1:]: 13 | print('Links in', url) 14 | for num, link in enumerate(get_links(url), start=1): 15 | print(num, link) 16 | print() 17 | -------------------------------------------------------------------------------- /1st_edition/web/templates/flask3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Flask3 Example 4 | 5 | 6 | Say hello to my little friend: {{ thing }}. 7 | Alas, it just destroyed {{ place }}! 8 | 9 | 10 | -------------------------------------------------------------------------------- /1st_edition/web/templates/flasks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Flask2 Example 4 | 5 | 6 | Say hello to my little friend: {{ thing }} 7 | 8 | 9 | -------------------------------------------------------------------------------- /1st_edition/web/templates/home.html: -------------------------------------------------------------------------------- 1 | I'm of course referring to {{thing}}, which is {{height}} feet tall and {{color}}. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Introducing Python -- Second Edition 2 | ================= 3 | 4 | This repository contains the programs featured in 5 | the second edition of the book _Introducing Python_. 6 | -------------------------------------------------------------------------------- /ch01/archive.py: -------------------------------------------------------------------------------- 1 | import webbrowser 2 | import json 3 | from urllib.request import urlopen 4 | 5 | print("Let's find an old website.") 6 | site = input("Type a website URL: ") 7 | era = input("Type a year, month, and day, like 20150613: ") 8 | url = "http://archive.org/wayback/available?url=%s×tamp=%s" % (site, era) 9 | response = urlopen(url) 10 | contents = response.read() 11 | text = contents.decode("utf-8") 12 | data = json.loads(text) 13 | try: 14 | old_site = data["archived_snapshots"]["closest"]["url"] 15 | print("Found this copy: ", old_site) 16 | print("It should appear in your browser now.") 17 | webbrowser.open(old_site) 18 | except: 19 | print("Sorry, no luck finding", site) 20 | -------------------------------------------------------------------------------- /ch01/archive2.py: -------------------------------------------------------------------------------- 1 | import webbrowser 2 | import requests 3 | 4 | print("Let's find an old website.") 5 | site = input("Type a website URL: ") 6 | era = input("Type a year, month, and day, like 20150613: ") 7 | url = "http://archive.org/wayback/available?url=%s×tamp=%s" % (site, era) 8 | response = requests.get(url) 9 | data = response.json() 10 | try: 11 | old_site = data["archived_snapshots"]["closest"]["url"] 12 | print("Found this copy: ", old_site) 13 | print("It should appear in your browser now.") 14 | webbrowser.open(old_site) 15 | except: 16 | print("Sorry, no luck finding", site) 17 | -------------------------------------------------------------------------------- /ch01/countdown.py: -------------------------------------------------------------------------------- 1 | for countdown in 5, 4, 3, 2, 1, "hey!": 2 | print(countdown) 3 | -------------------------------------------------------------------------------- /ch01/quotes.py: -------------------------------------------------------------------------------- 1 | quotes = { 2 | "Moe": "A wise guy, huh?", 3 | "Larry": "Ow!", 4 | "Curly": "Nyuk nyuk!", 5 | } 6 | stooge = "Curly" 7 | print(stooge, "says:", quotes[stooge]) 8 | -------------------------------------------------------------------------------- /ch01/spells.py: -------------------------------------------------------------------------------- 1 | spells = [ 2 | "Riddikulus!", 3 | "Wingardium Leviosa!", 4 | "Avada Kedavra!", 5 | "Expecto Patronum!", 6 | "Nox!", 7 | "Lumos!", 8 | ] 9 | print(spells[3]) 10 | -------------------------------------------------------------------------------- /ch05/poem.py: -------------------------------------------------------------------------------- 1 | poem = '''There was a Young Lady of Norway, 2 | Who casually sat in a doorway; 3 | When the door squeezed her flat, 4 | She exclaimed, "What of that?" 5 | This courageous Young Lady of Norway.''' 6 | -------------------------------------------------------------------------------- /ch05/poem2.py: -------------------------------------------------------------------------------- 1 | poem2 = '''I do not like thee, Doctor Fell. 2 | The reason why, I cannot tell. 3 | But this I know, and know full well: 4 | I do not like thee, Doctor Fell. 5 | ''' 6 | -------------------------------------------------------------------------------- /ch05/poem3.py: -------------------------------------------------------------------------------- 1 | poem = '''All that doth flow we cannot liquid name 2 | Or else would fire and water be the same; 3 | But that is liquid which is moist and wet 4 | Fire that property can never get. 5 | Then 'tis not cold that doth the fire put out 6 | But 'tis the wet that makes it die, no doubt.''' 7 | -------------------------------------------------------------------------------- /ch11/choices/advice.oy: -------------------------------------------------------------------------------- 1 | from random import choice 2 | 3 | answers = ["Yes!", "No!", "Reply hazy", "Sorry, what?"] 4 | 5 | def give(): 6 | """Return random advice""" 7 | return choice(answers) 8 | -------------------------------------------------------------------------------- /ch11/choices/fast.py: -------------------------------------------------------------------------------- 1 | from random import choice 2 | 3 | places = ["McDonalds", "KFC", "Burger King", "Taco Bell", 4 | "Wendys", "Arbys", "Pizza Hut"] 5 | 6 | def pick(): 7 | """Return random fast food place""" 8 | return choice(places) 9 | -------------------------------------------------------------------------------- /ch11/fast.py: -------------------------------------------------------------------------------- 1 | from random import choice 2 | 3 | places = ["McDonalds", "KFC", "Burger King", "Taco Bell", 4 | "Wendys", "Arbys", "Pizza Hut"] 5 | 6 | def pick(): # see the docstring below? 7 | """Return random fast food place""" 8 | return choice(places) 9 | -------------------------------------------------------------------------------- /ch11/fast2.py: -------------------------------------------------------------------------------- 1 | places = ["McDonalds", "KFC", "Burger King", "Taco Bell", 2 | "Wendys", "Arbys", "Pizza Hut"] 3 | 4 | def pick(): 5 | import random 6 | return random.choice(places) 7 | -------------------------------------------------------------------------------- /ch11/fast3.py: -------------------------------------------------------------------------------- 1 | import fast as f 2 | 3 | place = f.pick() 4 | print("Let's go to", place) 5 | -------------------------------------------------------------------------------- /ch11/fast4.py: -------------------------------------------------------------------------------- 1 | from fast import pick 2 | 3 | place = pick() 4 | print("Let's go to", place) 5 | -------------------------------------------------------------------------------- /ch11/fast5.py: -------------------------------------------------------------------------------- 1 | from fast import pick as who_cares 2 | 3 | place = who_cares() 4 | print("Let's go to", place) 5 | -------------------------------------------------------------------------------- /ch11/lunch.py: -------------------------------------------------------------------------------- 1 | import fast 2 | 3 | place = fast.pick() 4 | print("Let's go to", place) 5 | -------------------------------------------------------------------------------- /ch11/questions.py: -------------------------------------------------------------------------------- 1 | from fast import pick as who_cares 2 | 3 | place = who_cares() 4 | print("Let's go to", place) 5 | -------------------------------------------------------------------------------- /ch12/mammoth.txt: -------------------------------------------------------------------------------- 1 | We have seen thee, queen of cheese, 2 | Lying quietly at your ease, 3 | Gently fanned by evening breeze, 4 | Thy fair form no flies dare seize. 5 | All gaily dressed soon you'll go 6 | To the great Provincial show, 7 | To be admired by many a beau 8 | In the city of Toronto. 9 | Cows numerous as a swarm of bees, 10 | Or as the leaves upon the trees, 11 | It did require to make thee please, 12 | And stand unrivalled, queen of cheese. 13 | May you not receive a scar as 14 | We have heard that Mr. Harris 15 | Intends to send you off as far as 16 | The great world's show at Paris. 17 | Of the youth beware of these, 18 | For some of them might rudely squeeze 19 | And bite your cheek, then songs or glees 20 | We could not sing, oh! queen of cheese. 21 | We'rt thou suspended from balloon, 22 | You'd cast a shade even at noon, 23 | Folks would think it was the moon 24 | About to fall and crush them soon. 25 | -------------------------------------------------------------------------------- /ch14/convert_image.py: -------------------------------------------------------------------------------- 1 | from io import BytesIO 2 | from PIL import Image 3 | import sys 4 | 5 | def data_to_img(data): 6 | """Return PIL Image object, with data from in-memory """ 7 | fp = BytesIO(data) 8 | return Image.open(fp) # reads from memory 9 | 10 | def img_to_data(img, fmt=None): 11 | """Return image data from PIL Image , in format""" 12 | fp = BytesIO() 13 | if not fmt: 14 | fmt = img.format # keeps the original format 15 | img.save(fp, fmt) # writes to memory 16 | return fp.getvalue() 17 | 18 | def convert_image(data, fmt=None): 19 | """Convert image to PIL image data""" 20 | img = data_to_img(data) 21 | return img_to_data(img, fmt) 22 | 23 | def get_file_data(name): 24 | """Return PIL Image object for image file """ 25 | img = Image.open(name) 26 | print("img", img, img.format) 27 | return img_to_data(img) 28 | 29 | if __name__ == "__main__": 30 | for name in sys.argv[1:]: 31 | data = get_file_data(name) 32 | print("in", len(data), data[:10]) 33 | for fmt in ("gif", "png", "jpeg"): 34 | out_data = convert_image(data, fmt) 35 | print("out", len(out_data), out_data[:10]) 36 | -------------------------------------------------------------------------------- /ch15/cf.py: -------------------------------------------------------------------------------- 1 | from concurrent import futures 2 | import math 3 | import time 4 | import sys 5 | 6 | def calc(val): 7 | time.sleep(1) 8 | result = math.sqrt(float(val)) 9 | return result 10 | 11 | def use_threads(num, values): 12 | t1 = time.time() 13 | with futures.ThreadPoolExecutor(num) as tex: 14 | results = tex.map(calc, values) 15 | t2 = time.time() 16 | return t2 - t1 17 | 18 | def use_processes(num, values): 19 | t1 = time.time() 20 | with futures.ProcessPoolExecutor(num) as pex: 21 | results = pex.map(calc, values) 22 | t2 = time.time() 23 | return t2 - t1 24 | 25 | def main(workers, values): 26 | print(f"Using {workers} workers for {len(values)} values") 27 | t_sec = use_threads(workers, values) 28 | print(f"Threads took {t_sec:.4f} seconds") 29 | p_sec = use_processes(workers, values) 30 | print(f"Processes took {p_sec:.4f} seconds") 31 | 32 | if __name__ == '__main__': 33 | workers = int(sys.argv[1]) 34 | values = list(range(1, 6)) # 1 .. 5 35 | main(workers, values) 36 | -------------------------------------------------------------------------------- /ch15/cf2.py: -------------------------------------------------------------------------------- 1 | from concurrent import futures 2 | import math 3 | import sys 4 | 5 | def calc(val): 6 | result = math.sqrt(float(val)) 7 | return val, result 8 | 9 | def use_threads(num, values): 10 | with futures.ThreadPoolExecutor(num) as tex: 11 | tasks = [tex.submit(calc, value) for value in values] 12 | for f in futures.as_completed(tasks): 13 | yield f.result() 14 | 15 | def use_processes(num, values): 16 | with futures.ProcessPoolExecutor(num) as pex: 17 | tasks = [pex.submit(calc, value) for value in values] 18 | for f in futures.as_completed(tasks): 19 | yield f.result() 20 | 21 | def main(workers, values): 22 | print(f"Using {workers} workers for {len(values)} values") 23 | print("Using threads:") 24 | for val, result in use_threads(workers, values): 25 | print(f'{val} {result:.4f}') 26 | print("Using processes:") 27 | for val, result in use_processes(workers, values): 28 | print(f'{val} {result:.4f}') 29 | 30 | if __name__ == '__main__': 31 | workers = 3 32 | if len(sys.argv) > 1: 33 | workers = int(sys.argv[1]) 34 | values = list(range(1, 6)) # 1 .. 5 35 | main(workers, values) 36 | -------------------------------------------------------------------------------- /ch15/dishes.py: -------------------------------------------------------------------------------- 1 | import multiprocessing as mp 2 | 3 | def washer(dishes, output): 4 | for dish in dishes: 5 | print('Washing', dish, 'dish') 6 | output.put(dish) 7 | 8 | def dryer(input): 9 | while True: 10 | dish = input.get() 11 | print('Drying', dish, 'dish') 12 | input.task_done() 13 | 14 | dish_queue = mp.JoinableQueue() 15 | dryer_proc = mp.Process(target=dryer, args=(dish_queue,)) 16 | dryer_proc.daemon = True 17 | dryer_proc.start() 18 | dishes = ['salad', 'bread', 'entree', 'dessert'] 19 | washer(dishes, dish_queue) 20 | dish_queue.join() 21 | -------------------------------------------------------------------------------- /ch15/gevent_monkey.py: -------------------------------------------------------------------------------- 1 | import gevent 2 | from gevent import monkey; monkey.patch_all() 3 | import socket 4 | 5 | hosts = ['www.crappytaxidermy.com', 'www.walterpottertaxidermy.com', 6 | 'www.antique-taxidermy.com'] 7 | jobs = [gevent.spawn(socket.gethostbyname, host) for host in hosts] 8 | gevent.joinall(jobs, timeout=5) 9 | for job in jobs: 10 | print(job.value) 11 | -------------------------------------------------------------------------------- /ch15/gevent_test.py: -------------------------------------------------------------------------------- 1 | import gevent 2 | from gevent import socket 3 | 4 | hosts = ['www.crappytaxidermy.com', 'www.walterpottertaxidermy.com', 5 | 'www.antique-taxidermy.com'] 6 | jobs = [gevent.spawn(gevent.socket.gethostbyname, host) for host in hosts] 7 | gevent.joinall(jobs, timeout=5) 8 | for job in jobs: 9 | print(job.value) 10 | -------------------------------------------------------------------------------- /ch15/knock_client.py: -------------------------------------------------------------------------------- 1 | from twisted.internet import reactor, protocol 2 | 3 | class KnockClient(protocol.Protocol): 4 | 5 | def connectionMade(self): 6 | self.transport.write("Knock knock") 7 | 8 | def dataReceived(self, data): 9 | if data.startswith("Who's there?"): 10 | response = "Disappearing client" 11 | self.transport.write(response) 12 | else: 13 | self.transport.loseConnection() 14 | reactor.stop() 15 | 16 | class KnockFactory(protocol.ClientFactory): 17 | protocol = KnockClient 18 | 19 | def main(): 20 | f = KnockFactory() 21 | reactor.connectTCP("localhost", 8000, f) 22 | reactor.run() 23 | 24 | if __name__ == '__main__': 25 | main() 26 | -------------------------------------------------------------------------------- /ch15/knock_server.py: -------------------------------------------------------------------------------- 1 | from twisted.internet import protocol, reactor 2 | 3 | class Knock(protocol.Protocol): 4 | def dataReceived(self, data): 5 | print('Client:', data) 6 | if data.startswith("Knock knock"): 7 | response = "Who's there?" 8 | else: 9 | response = data + " who?" 10 | print('Server:', response) 11 | self.transport.write(response) 12 | 13 | class KnockFactory(protocol.Factory): 14 | def buildProtocol(self, addr): 15 | return Knock() 16 | 17 | reactor.listenTCP(8000, KnockFactory()) 18 | reactor.run() 19 | -------------------------------------------------------------------------------- /ch15/mp.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | import os 3 | 4 | def whoami(what): 5 | print("Process %s says: %s" % (os.getpid(), what)) 6 | 7 | if __name__ == "__main__": 8 | whoami("I'm the main program") 9 | for n in range(4): 10 | p = multiprocessing.Process(target=whoami, 11 | args=("I'm function %s" % n,)) 12 | p.start() 13 | -------------------------------------------------------------------------------- /ch15/mp2.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | import time 3 | import os 4 | 5 | def whoami(name): 6 | print("I'm %s, in process %s" % (name, os.getpid())) 7 | 8 | def loopy(name): 9 | whoami(name) 10 | start = 1 11 | stop = 1000000 12 | for num in range(start, stop): 13 | print("\tNumber %s of %s. Honk!" % (num, stop)) 14 | time.sleep(1) 15 | 16 | if __name__ == "__main__": 17 | whoami("main") 18 | p = multiprocessing.Process(target=loopy, args=("loopy",)) 19 | p.start() 20 | time.sleep(5) 21 | p.terminate() 22 | -------------------------------------------------------------------------------- /ch15/redis_dryer.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | conn = redis.Redis() 4 | print('Dryer is starting') 5 | while True: 6 | msg = conn.blpop('dishes') 7 | if not msg: 8 | break 9 | val = msg[1].decode('utf-8') 10 | if val == 'quit': 11 | break 12 | print('Dried', val) 13 | print('Dishes are dried') 14 | -------------------------------------------------------------------------------- /ch15/redis_dryer2.py: -------------------------------------------------------------------------------- 1 | def dryer(): 2 | import redis 3 | import os 4 | import time 5 | 6 | conn = redis.Redis() 7 | pid = os.getpid() 8 | timeout = 20 9 | print('Dryer process %s is starting' % pid) 10 | while True: 11 | msg = conn.blpop('dishes', timeout) 12 | if not msg: 13 | break 14 | val = msg[1].decode('utf-8') 15 | if val == 'quit': 16 | break 17 | print('%s: dried %s' % (pid, val)) 18 | time.sleep(0.1) 19 | print('Dryer process %s is done' % pid) 20 | 21 | import multiprocessing 22 | 23 | DRYERS=3 24 | for num in range(DRYERS): 25 | p = multiprocessing.Process(target=dryer) 26 | p.start() 27 | -------------------------------------------------------------------------------- /ch15/redis_washer.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | conn = redis.Redis() 4 | print('Washer is starting') 5 | dishes = ['salad', 'bread', 'entree', 'dessert'] 6 | for dish in dishes: 7 | msg = dish.encode('utf-8') 8 | conn.rpush('dishes', msg) 9 | print('Washed', dish) 10 | conn.rpush('dishes', 'quit') 11 | print('Washer is done') 12 | -------------------------------------------------------------------------------- /ch15/tasks.py: -------------------------------------------------------------------------------- 1 | from invoke import task 2 | 3 | @task 4 | def mytime(ctx): 5 | import time 6 | now = time.time() 7 | time_str = time.asctime(time.localtime(now)) 8 | print("Local time is", time_str) 9 | -------------------------------------------------------------------------------- /ch15/thread1.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | def do_this(what): 4 | whoami(what) 5 | 6 | def whoami(what): 7 | print("Thread %s says: %s" % (threading.current_thread(), what)) 8 | 9 | if __name__ == "__main__": 10 | whoami("I'm the main program") 11 | for n in range(4): 12 | p = threading.Thread(target=do_this, 13 | args=("I'm function %s" % n,)) 14 | p.start() 15 | -------------------------------------------------------------------------------- /ch15/thread_dishes.py: -------------------------------------------------------------------------------- 1 | import threading, queue 2 | import time 3 | 4 | def washer(dishes, dish_queue): 5 | for dish in dishes: 6 | print ("Washing", dish) 7 | time.sleep(5) 8 | dish_queue.put(dish) 9 | 10 | def dryer(dish_queue): 11 | while True: 12 | dish = dish_queue.get() 13 | print ("Drying", dish) 14 | time.sleep(10) 15 | dish_queue.task_done() 16 | 17 | dish_queue = queue.Queue() 18 | for n in range(2): 19 | dryer_thread = threading.Thread(target=dryer, args=(dish_queue,)) 20 | dryer_thread.start() 21 | dishes = ['salad', 'bread', 'entree', 'dessert'] 22 | washer(dishes, dish_queue) 23 | dish_queue.join() 24 | -------------------------------------------------------------------------------- /ch16/villains.csv: -------------------------------------------------------------------------------- 1 | first,last 2 | Doctor,No 3 | Rosa,Klebb 4 | Mister,Big 5 | Auric,Goldfinger 6 | Ernst,Blofeld 7 | -------------------------------------------------------------------------------- /ch17/jsonrpc_client.py: -------------------------------------------------------------------------------- 1 | from jsonrpcclient import request 2 | 3 | num = 7 4 | response = request("http://localhost:5000", "double", num=num) 5 | print("Double", num, "is", response.data.result) 6 | -------------------------------------------------------------------------------- /ch17/jsonrpc_server.py: -------------------------------------------------------------------------------- 1 | from jsonrpcserver import method, serve 2 | 3 | @method 4 | def double(num): 5 | return num * 2 6 | 7 | if __name__ == "__main__": 8 | serve() 9 | -------------------------------------------------------------------------------- /ch17/msgpack_client.py: -------------------------------------------------------------------------------- 1 | from msgpackrpc import Client, Address 2 | 3 | client = Client(Address("localhost", 6789)) 4 | num = 8 5 | result = client.call('double', num) 6 | print("Double %s is %s" % (num, result)) 7 | -------------------------------------------------------------------------------- /ch17/msgpack_server.py: -------------------------------------------------------------------------------- 1 | from msgpackrpc import Server, Address 2 | 3 | class Services(): 4 | def double(self, num): 5 | return num * 2 6 | 7 | server = Server(Services()) 8 | server.listen(Address("localhost", 6789)) 9 | server.start() 10 | -------------------------------------------------------------------------------- /ch17/redis_pub.py: -------------------------------------------------------------------------------- 1 | import redis 2 | import random 3 | 4 | conn = redis.Redis() 5 | cats = ['siamese', 'persian', 'maine coon', 'norwegian forest'] 6 | hats = ['stovepipe', 'bowler', 'tam-o-shanter', 'fedora'] 7 | for msg in range(10): 8 | cat = random.choice(cats) 9 | hat = random.choice(hats) 10 | print('Publish: %s wears a %s' % (cat, hat)) 11 | conn.publish(cat, hat) 12 | -------------------------------------------------------------------------------- /ch17/redis_sub.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | conn = redis.Redis() 4 | topics = ['maine coon', 'persian'] 5 | sub = conn.pubsub() 6 | sub.subscribe(topics) 7 | for msg in sub.listen(): 8 | if msg['type'] == 'message': 9 | cat = msg['channel'] 10 | hat = msg['data'] 11 | print('Subscribe: %s wears a %s' % (cat, hat)) 12 | -------------------------------------------------------------------------------- /ch17/tcp_client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from datetime import datetime 3 | 4 | address = ('localhost', 6789) 5 | max_size = 1000 6 | 7 | print('Starting the client at', datetime.now()) 8 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 | client.connect(address) 10 | client.sendall(b'Hey!') 11 | data = client.recv(max_size) 12 | print('At', datetime.now(), 'someone replied', data) 13 | client.close() 14 | -------------------------------------------------------------------------------- /ch17/tcp_server.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | import socket 3 | 4 | address = ('localhost', 6789) 5 | max_size = 1000 6 | 7 | print('Starting the server at', datetime.now()) 8 | print('Waiting for a client to call.') 9 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 | server.bind(address) 11 | server.listen(5) 12 | 13 | client, addr = server.accept() 14 | data = client.recv(max_size) 15 | 16 | print('At', datetime.now(), client, 'said', data) 17 | client.sendall(b'Are you talking to me?') 18 | client.close() 19 | server.close() 20 | -------------------------------------------------------------------------------- /ch17/udp_client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from datetime import datetime 3 | 4 | server_address = ('localhost', 6789) 5 | max_size = 4096 6 | 7 | print('Starting the client at', datetime.now()) 8 | client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 9 | client.sendto(b'Hey!', server_address) 10 | data, server = client.recvfrom(max_size) 11 | print('At', datetime.now(), server, 'said', data) 12 | client.close() 13 | -------------------------------------------------------------------------------- /ch17/udp_server.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | import socket 3 | 4 | server_address = ('localhost', 6789) 5 | max_size = 4096 6 | 7 | print('Starting the server at', datetime.now()) 8 | print('Waiting for a client to call.') 9 | server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 10 | server.bind(server_address) 11 | 12 | data, client = server.recvfrom(max_size) 13 | 14 | print('At', datetime.now(), client, 'said', data) 15 | server.sendto(b'Are you talking to me?', client) 16 | server.close() 17 | -------------------------------------------------------------------------------- /ch17/xmlrpc_client.py: -------------------------------------------------------------------------------- 1 | import xmlrpc.client 2 | 3 | proxy = xmlrpc.client.ServerProxy("http://localhost:6789/") 4 | num = 7 5 | result = proxy.double(num) 6 | print("Double %s is %s" % (num, result)) 7 | -------------------------------------------------------------------------------- /ch17/xmlrpc_server.py: -------------------------------------------------------------------------------- 1 | from xmlrpc.server import SimpleXMLRPCServer 2 | 3 | def double(num): 4 | return num * 2 5 | 6 | server = SimpleXMLRPCServer(("localhost", 6789)) 7 | server.register_function(double, "double") 8 | server.serve_forever() 9 | -------------------------------------------------------------------------------- /ch17/zerorpc_client.py: -------------------------------------------------------------------------------- 1 | import zerorpc 2 | 3 | client = zerorpc.Client() 4 | client.connect("tcp://127.0.0.1:4242") 5 | num = 7 6 | result = client.double(num) 7 | print("Double", num, "is", result) 8 | -------------------------------------------------------------------------------- /ch17/zerorpc_server.py: -------------------------------------------------------------------------------- 1 | import zerorpc 2 | 3 | class RPC(): 4 | def double(self, num): 5 | return 2 * num 6 | 7 | server = zerorpc.Server(RPC()) 8 | server.bind("tcp://0.0.0.0:4242") 9 | server.run() 10 | -------------------------------------------------------------------------------- /ch17/zmq_client.py: -------------------------------------------------------------------------------- 1 | import zmq 2 | 3 | host = '127.0.0.1' 4 | port = 6789 5 | context = zmq.Context() 6 | client = context.socket(zmq.REQ) 7 | client.connect("tcp://%s:%s" % (host, port)) 8 | for num in range(1, 6): 9 | request_str = "message #%s" % num 10 | request_bytes = request_str.encode('utf-8') 11 | client.send(request_bytes) 12 | reply_bytes = client.recv() 13 | reply_str = reply_bytes.decode('utf-8') 14 | print("Sent %s, received %s" % (request_str, reply_str)) 15 | -------------------------------------------------------------------------------- /ch17/zmq_pub.py: -------------------------------------------------------------------------------- 1 | import zmq 2 | import random 3 | import time 4 | 5 | host = '*' 6 | port = 6789 7 | ctx = zmq.Context() 8 | pub = ctx.socket(zmq.PUB) 9 | pub.bind('tcp://%s:%s' % (host, port)) 10 | cats = ['siamese', 'persian', 'maine coon', 'norwegian forest'] 11 | hats = ['stovepipe', 'bowler', 'tam-o-shanter', 'fedora'] 12 | time.sleep(1) 13 | for msg in range(10): 14 | cat = random.choice(cats) 15 | cat_bytes = cat.encode('utf-8') 16 | hat = random.choice(hats) 17 | hat_bytes = hat.encode('utf-8') 18 | print('Publish: %s wears a %s' % (cat, hat)) 19 | pub.send_multipart([cat_bytes, hat_bytes]) 20 | -------------------------------------------------------------------------------- /ch17/zmq_server.py: -------------------------------------------------------------------------------- 1 | import zmq 2 | 3 | host = '127.0.0.1' 4 | port = 6789 5 | context = zmq.Context() 6 | server = context.socket(zmq.REP) 7 | server.bind("tcp://%s:%s" % (host, port)) 8 | while True: 9 | # Wait for next request from client 10 | request_bytes = server.recv() 11 | request_str = request_bytes.decode('utf-8') 12 | print("That voice in my head says: %s" % request_str) 13 | reply_str = "Stop saying: %s" % request_str 14 | reply_bytes = bytes(reply_str, 'utf-8') 15 | server.send(reply_bytes) 16 | -------------------------------------------------------------------------------- /ch17/zmq_sub.py: -------------------------------------------------------------------------------- 1 | import zmq 2 | 3 | host = '127.0.0.1' 4 | port = 6789 5 | ctx = zmq.Context() 6 | sub = ctx.socket(zmq.SUB) 7 | sub.connect('tcp://%s:%s' % (host, port)) 8 | topics = ['maine coon', 'persian'] 9 | for topic in topics: 10 | sub.setsockopt(zmq.SUBSCRIBE, topic.encode('utf-8')) 11 | while True: 12 | cat_bytes, hat_bytes = sub.recv_multipart() 13 | cat = cat_bytes.decode('utf-8') 14 | hat = hat_bytes.decode('utf-8') 15 | print('Subscribe: %s wears a %s' % (cat, hat)) 16 | -------------------------------------------------------------------------------- /ch18/bottle1.py: -------------------------------------------------------------------------------- 1 | from bottle import route, run 2 | 3 | @route('/') 4 | def home(): 5 | return "It isn't fancy, but it's my home page" 6 | 7 | run(host='localhost', port=9999) 8 | -------------------------------------------------------------------------------- /ch18/bottle2.py: -------------------------------------------------------------------------------- 1 | from bottle import route, run, static_file 2 | 3 | @route('/') 4 | def main(): 5 | return static_file('index.html', root='.') 6 | 7 | run(host='localhost', port=9999) 8 | -------------------------------------------------------------------------------- /ch18/bottle3.py: -------------------------------------------------------------------------------- 1 | from bottle import route, run, static_file 2 | 3 | @route('/') 4 | def home(): 5 | return static_file('index.html', root='.') 6 | 7 | @route('/echo/') 8 | def echo(thing): 9 | return "Say hello to my little friend: %s!" % thing 10 | 11 | run(host='localhost', port=9999) 12 | -------------------------------------------------------------------------------- /ch18/bottle_test.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | resp = requests.get('http://localhost:9999/echo/Mothra') 4 | if resp.status_code == 200 and \ 5 | resp.text == 'Say hello to my little friend: Mothra!': 6 | print('It worked! That almost never happens!') 7 | else: 8 | print('Argh, got this:', resp.text) 9 | -------------------------------------------------------------------------------- /ch18/flask1.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__, static_folder='.', static_url_path='') 4 | 5 | @app.route('/') 6 | def home(): 7 | return app.send_static_file('index.html') 8 | 9 | @app.route('/echo/') 10 | def echo(thing): 11 | return "Say hello to my little friend: %s" % thing 12 | 13 | app.run(port=9999, debug=True) 14 | -------------------------------------------------------------------------------- /ch18/flask2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Flask2 Example 4 | 5 | 6 | Say hello to my little friend: {{ thing }} 7 | 8 | 9 | -------------------------------------------------------------------------------- /ch18/flask2.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/echo/') 6 | def echo(thing): 7 | return render_template('flask2.html', thing=thing) 8 | 9 | app.run(port=9999, debug=True) 10 | -------------------------------------------------------------------------------- /ch18/flask3a.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/echo//') 6 | def echo(thing, place): 7 | return render_template('flask3.html', thing=thing, place=place) 8 | 9 | app.run(port=9999, debug=True) 10 | -------------------------------------------------------------------------------- /ch18/flask3b.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/echo/') 6 | def echo(): 7 | thing = request.args.get('thing') 8 | place = request.args.get('place') 9 | return render_template('flask3.html', thing=thing, place=place) 10 | 11 | app.run(port=9999, debug=True) 12 | -------------------------------------------------------------------------------- /ch18/flask3c.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/echo/') 6 | def echo(): 7 | kwargs = {} 8 | kwargs['thing'] = request.args.get('thing') 9 | kwargs['place'] = request.args.get('place') 10 | return render_template('flask3.html', **kwargs) 11 | 12 | app.run(port=9999, debug=True) 13 | -------------------------------------------------------------------------------- /ch18/home.wsgi: -------------------------------------------------------------------------------- 1 | import bottle 2 | 3 | application = bottle.default_app() 4 | 5 | @bottle.route('/') 6 | def home(): 7 | return "apache and wsgi, sitting in a tree" 8 | -------------------------------------------------------------------------------- /ch18/ia.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | import requests 4 | 5 | def search(title): 6 | url = "http://archive.org/advancedsearch.php" 7 | params = {"q": f"title:({title})", 8 | "output": "json", 9 | "fields": "identifier,title", 10 | "rows": 50, 11 | "page": 1,} 12 | resp = requests.get(url, params=params) 13 | return resp.json() 14 | 15 | if __name__ == "__main__": 16 | title = sys.argv[1] 17 | data = search(title) 18 | docs = data["response"]["docs"] 19 | print(f"Found {len(docs)} items, showing first 10") 20 | print("identifier\ttitle") 21 | for row in docs[:10]: 22 | print(row["identifier"], row["title"], sep="\t") 23 | -------------------------------------------------------------------------------- /ch18/ia_movies.py: -------------------------------------------------------------------------------- 1 | """Find a video at the Internet Archive 2 | by a partial title match and display it.""" 3 | 4 | import sys 5 | import webbrowser 6 | import requests 7 | 8 | def search(title): 9 | """Return a list of 3-item tuples (identifier, 10 | title, description) about videos 11 | whose titles partially match :title.""" 12 | search_url = "https://archive.org/advancedsearch.php" 13 | params = { 14 | "q": "title:({}) AND mediatype:(movies)".format(title), 15 | "fl": "identifier,title,description", 16 | "output": "json", 17 | "rows": 10, 18 | "page": 1, 19 | } 20 | resp = requests.get(search_url, params=params) 21 | data = resp.json() 22 | docs = [(doc["identifier"], doc["title"], doc["description"]) 23 | for doc in data["response"]["docs"]] 24 | return docs 25 | 26 | def choose(docs): 27 | """Print line number, title and truncated description for 28 | each tuple in :docs. Get the user to pick a line 29 | number. If it's valid, return the first item in the 30 | chosen tuple (the "identifier"). Otherwise, return None.""" 31 | last = len(docs) - 1 32 | for num, doc in enumerate(docs): 33 | print(f"{num}: ({doc[1]}) {doc[2][:30]}...") 34 | index = input(f"Which would you like to see (0 to {last})? ") 35 | try: 36 | return docs[int(index)][0] 37 | except: 38 | return None 39 | 40 | def display(identifier): 41 | """Display the Archive video with :identifier in the browser""" 42 | details_url = "https://archive.org/details/{}".format(identifier) 43 | print("Loading", details_url) 44 | webbrowser.open(details_url) 45 | 46 | def main(title): 47 | """Find any movies that match :title. 48 | Get the user's choice and display it in the browser.""" 49 | identifiers = search(title) 50 | if identifiers: 51 | identifier = choose(identifiers) 52 | if identifier: 53 | display(identifier) 54 | else: 55 | print("Nothing selected") 56 | else: 57 | print("Nothing found for", title) 58 | 59 | if __name__ == "__main__": 60 | main(sys.argv[1]) 61 | -------------------------------------------------------------------------------- /ch18/links.py: -------------------------------------------------------------------------------- 1 | def get_links(url): 2 | import requests 3 | from bs4 import BeautifulSoup as soup 4 | result = requests.get(url) 5 | page = result.text 6 | doc = soup(page) 7 | links = [element.get('href') for element in doc.find_all('a')] 8 | return links 9 | 10 | if __name__ == '__main__': 11 | import sys 12 | for url in sys.argv[1:]: 13 | print('Links in', url) 14 | for num, link in enumerate(get_links(url), start=1): 15 | print(num, link) 16 | print() 17 | -------------------------------------------------------------------------------- /ch19/cap.py: -------------------------------------------------------------------------------- 1 | def just_do_it(text): 2 | return text.capitalize() 3 | -------------------------------------------------------------------------------- /ch19/cap.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madscheme/introducing-python/a0eaab9c523cd0af8877dc6175fd4a60ab000cb5/ch19/cap.pyc -------------------------------------------------------------------------------- /ch19/cap2.py: -------------------------------------------------------------------------------- 1 | def just_do_it(text): 2 | """ 3 | >>> just_do_it('duck') 4 | 'Duck' 5 | >>> just_do_it('a veritable flock of ducks') 6 | 'A Veritable Flock Of Ducks' 7 | >>> just_do_it("I'm fresh out of ideas") 8 | "I'm Fresh Out Of Ideas" 9 | """ 10 | from string import capwords 11 | return capwords(text) 12 | 13 | if __name__ == '__main__': 14 | import doctest 15 | doctest.testmod() 16 | -------------------------------------------------------------------------------- /ch19/capitals.py: -------------------------------------------------------------------------------- 1 | def process_cities(filename): 2 | with open(filename, 'rt') as file: 3 | for line in file: 4 | line = line.strip() 5 | if 'quit' in line.lower(): 6 | return 7 | country, city = line.split(',') 8 | city = city.strip() 9 | country = country.strip() 10 | print(city.title(), country.title(), sep=',') 11 | 12 | if __name__ == '__main__': 13 | import sys 14 | process_cities(sys.argv[1]) 15 | -------------------------------------------------------------------------------- /ch19/capitals2.py: -------------------------------------------------------------------------------- 1 | def process_cities(filename): 2 | with open(filename, 'rt') as file: 3 | for line in file: 4 | line = line.strip() 5 | if 'quit' == line.lower(): 6 | return 7 | country, city = line.split(',') 8 | city = city.strip() 9 | country = country.strip() 10 | print(city.title(), country.title(), sep=',') 11 | 12 | if __name__ == '__main__': 13 | import sys 14 | process_cities(sys.argv[1]) 15 | -------------------------------------------------------------------------------- /ch19/cities.csv: -------------------------------------------------------------------------------- 1 | France, Paris 2 | venuzuela,caracas 3 | LithuaniA,vilnius 4 | quit 5 | -------------------------------------------------------------------------------- /ch19/cities2.csv: -------------------------------------------------------------------------------- 1 | argentina,buenos aires 2 | bolivia,la paz 3 | brazil,brasilia 4 | chile,santiago 5 | colombia,Bogotá 6 | ecuador,quito 7 | falkland islands,stanley 8 | french guiana,cayenne 9 | guyana,georgetown 10 | paraguay,Asunción 11 | peru,lima 12 | suriname,paramaribo 13 | uruguay,montevideo 14 | venezuela,caracas 15 | quit 16 | -------------------------------------------------------------------------------- /ch19/dump.py: -------------------------------------------------------------------------------- 1 | def dump(func): 2 | "Print input arguments and output value(s)" 3 | def wrapped(*args, **kwargs): 4 | print("Function name:", func.__name__) 5 | print("Input arguments:", ' '.join(map(str, args))) 6 | print("Input keyword arguments:", kwargs.items()) 7 | output = func(*args, **kwargs) 8 | print("Output:", output) 9 | return output 10 | return wrapped 11 | -------------------------------------------------------------------------------- /ch19/dump.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madscheme/introducing-python/a0eaab9c523cd0af8877dc6175fd4a60ab000cb5/ch19/dump.pyc -------------------------------------------------------------------------------- /ch19/ftoc1.py: -------------------------------------------------------------------------------- 1 | def ftoc(f_temp): 2 | "Convert Fahrenheit temperature to Celsius and return it." 3 | f_boil_temp = 212.0 4 | f_freeze_temp = 32.0 5 | c_boil_temp = 100.0 6 | c_freeze_temp = 0.0 7 | f_range = f_boil_temp - f_freeze_temp 8 | c_range = c_boil_temp - c_freeze_temp 9 | f_c_ratio = c_range / f_range 10 | c_temp = (f_temp - f_freeze_temp) * f_c_ratio + c_freeze_temp 11 | return c_temp 12 | 13 | if __name__ == '__main__': 14 | for f_temp in [-40.0, 0.0, 32.0, 100.0, 212.0]: 15 | c_temp = ftoc(f_temp) 16 | print('%f F => %f C' % (f_temp, c_temp)) 17 | -------------------------------------------------------------------------------- /ch19/ftoc2.py: -------------------------------------------------------------------------------- 1 | F_BOIL_TEMP = 212.0 2 | F_FREEZE_TEMP = 32.0 3 | C_BOIL_TEMP = 100.0 4 | C_FREEZE_TEMP = 0.0 5 | F_RANGE = F_BOIL_TEMP - F_FREEZE_TEMP 6 | C_RANGE = C_BOIL_TEMP - C_FREEZE_TEMP 7 | F_C_RATIO = C_RANGE / F_RANGE 8 | 9 | def ftoc(f_temp): 10 | "Convert Fahrenheit temperature to Celsius and return it." 11 | c_temp = (f_temp - F_FREEZE_TEMP) * F_C_RATIO + C_FREEZE_TEMP 12 | return c_temp 13 | 14 | if __name__ == '__main__': 15 | for f_temp in [-40.0, 0.0, 32.0, 100.0, 212.0]: 16 | c_temp = ftoc(f_temp) 17 | print('%f F => %f C' % (f_temp, c_temp)) 18 | -------------------------------------------------------------------------------- /ch19/style1.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | b = 2 3 | print(a) 4 | print(b) 5 | print(c) 6 | -------------------------------------------------------------------------------- /ch19/style2.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | b = 2 3 | c = 3 4 | print(a) 5 | print(b) 6 | print(c) 7 | -------------------------------------------------------------------------------- /ch19/style3.py: -------------------------------------------------------------------------------- 1 | "Module docstring goes here" 2 | 3 | def func(): 4 | "Function docstring goes here. Hi, Mom!" 5 | first = 1 6 | second = 2 7 | third = 3 8 | print(first) 9 | print(second) 10 | print(third) 11 | 12 | func() 13 | -------------------------------------------------------------------------------- /ch19/test.py: -------------------------------------------------------------------------------- 1 | print('Oops') 2 | -------------------------------------------------------------------------------- /ch19/test_cap.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import cap 3 | 4 | class TestCap(unittest.TestCase): 5 | 6 | def setUp(self): 7 | pass 8 | 9 | def tearDown(self): 10 | pass 11 | 12 | def test_one_word(self): 13 | text = 'duck' 14 | result = cap.just_do_it(text) 15 | self.assertEqual(result, 'Duck') 16 | 17 | def test_multiple_words(self): 18 | text = 'a veritable flock of ducks' 19 | result = cap.just_do_it(text) 20 | self.assertEqual(result, 'A Veritable Flock Of Ducks') 21 | 22 | if __name__ == '__main__': 23 | unittest.main() 24 | -------------------------------------------------------------------------------- /ch19/test_cap_nose.py: -------------------------------------------------------------------------------- 1 | import cap2 2 | from nose.tools import eq_ 3 | 4 | def test_one_word(): 5 | text = 'duck' 6 | result = cap.just_do_it(text) 7 | eq_(result, 'Duck') 8 | 9 | def test_multiple_words(): 10 | text = 'a veritable flock of ducks' 11 | result = cap.just_do_it(text) 12 | eq_(result, 'A Veritable Flock Of Ducks') 13 | 14 | def test_words_with_apostrophes(): 15 | text = "I'm fresh out of ideas" 16 | result = cap.just_do_it(text) 17 | eq_(result, "I'm Fresh Out Of Ideas") 18 | 19 | def test_words_with_quotes(): 20 | text = "\"You're despicable,\" said Daffy Duck" 21 | result = cap.just_do_it(text) 22 | eq_(result, "\"You're Despicable,\" Said Daffy Duck") 23 | -------------------------------------------------------------------------------- /ch19/test_dump.py: -------------------------------------------------------------------------------- 1 | from dump import dump 2 | 3 | @dump 4 | def double(*args, **kwargs): 5 | "Double every argument" 6 | output_list = [ 2 * arg for arg in args ] 7 | output_dict = { k:2*v for k,v in kwargs.items() } 8 | return output_list, output_dict 9 | 10 | if __name__ == '__main__': 11 | output = double(3, 5, first=100, next=98.6, last=-40) 12 | -------------------------------------------------------------------------------- /ch19/time1.py: -------------------------------------------------------------------------------- 1 | from time import time 2 | 3 | t1 = time() 4 | num = 5 5 | num *= 2 6 | print(time() - t1) 7 | -------------------------------------------------------------------------------- /ch19/time2.py: -------------------------------------------------------------------------------- 1 | from time import time, sleep 2 | 3 | t1 = time() 4 | sleep(1.0) 5 | print(time() - t1) 6 | -------------------------------------------------------------------------------- /ch19/time_lists.py: -------------------------------------------------------------------------------- 1 | from timeit import timeit 2 | 3 | def make_list_1(): 4 | result = [] 5 | for value in range(1000): 6 | result.append(value) 7 | return result 8 | 9 | def make_list_2(): 10 | result = [value for value in range(1000)] 11 | return result 12 | 13 | print('make_list_1 takes', timeit(make_list_1, number=1000), 'seconds') 14 | print('make_list_2 takes', timeit(make_list_2, number=1000), 'seconds') 15 | -------------------------------------------------------------------------------- /ch19/timeit1.py: -------------------------------------------------------------------------------- 1 | from timeit import timeit 2 | 3 | print(timeit('num = 5; num *= 2', number=1)) 4 | -------------------------------------------------------------------------------- /ch19/timeit2.py: -------------------------------------------------------------------------------- 1 | from timeit import repeat 2 | 3 | print(repeat('num = 5; num *= 2', number=1, repeat=3)) 4 | --------------------------------------------------------------------------------