├── Chapter01 ├── example_1_2_1.py ├── example_1_2_2.py ├── example_1_2_3.py ├── example_1_2_4.py ├── example_1_2_5.py └── example_1_2_6.py ├── Chapter02 ├── py27.py └── py34.py ├── Chapter03 ├── cyclic │ ├── a.py │ └── b.py └── example │ └── data │ └── datafile.txt ├── Chapter04 ├── pep8_example.py └── tab_trouble.py ├── Chapter05 ├── example02 │ ├── ap0.py │ ├── ap1.py │ ├── ap2.py │ ├── ap3.py │ └── ap4.py ├── example03 │ ├── simple.py │ ├── special.py │ └── usecmd.py ├── example04 │ └── echo.py └── example05 │ └── echo.py ├── Chapter06 ├── example1 │ ├── ascompleted.py │ ├── cancel.py │ ├── example1_1.py │ ├── example1_2.py │ ├── poolmap.py │ ├── poolsubmit.py │ ├── poolsubmit2.py │ └── waiting.py └── example2 │ ├── condition.py │ ├── event.py │ ├── lock.py │ ├── manager.py │ ├── pipe.py │ ├── primes.py │ ├── queue.py │ ├── semaphore.py │ └── squares.py ├── Chapter07 ├── example1 │ └── coroutine.py ├── example2 │ ├── coroutine.py │ ├── run_forever.py │ ├── run_until_complete.py │ └── run_until_complete_with_closing.py ├── example3 │ ├── futures.py │ └── iterable.py ├── example4 │ ├── as_completed.py │ ├── gather.py │ ├── queue_usage.py │ └── wait_for.py └── example5 │ ├── client.py │ └── server.py ├── Chapter08 ├── adapted.py ├── adapted_only.py ├── async_trans.py ├── attritems.py ├── before_and_after.py ├── database.py ├── factory.py ├── ints_only.py ├── only.py ├── register.py ├── remote.py ├── store_args.py └── trans.py ├── Chapter09 ├── suite │ ├── test_one.py │ └── test_two.py ├── test_examples.py └── uncovered.py ├── Chapter10 ├── rxzoo │ ├── __main__.py │ └── animals.py └── zoo │ ├── __main__.py │ ├── animals.py │ └── reactive.py ├── Chapter11 ├── demo_flask │ ├── __init__.py │ ├── endpoint.py │ ├── person.py │ ├── service.py │ └── test.py └── demo_nameko │ ├── person.py │ ├── service.py │ └── test.py ├── Chapter12 ├── demo_ctypes │ ├── __init__.py │ ├── demo.py │ └── libc.py └── demo_cython │ └── setup.py ├── LICENSE └── README.md /Chapter01/example_1_2_1.py: -------------------------------------------------------------------------------- 1 | print(1) 2 | print(1 + 1) 3 | print(3 * 1 + 2) 4 | print(3 * (1 + 2)) 5 | 6 | if 2 > 1: 7 | print("One is the loneliest number") 8 | else: 9 | print('Two is the lonliest number?') 10 | 11 | -------------------------------------------------------------------------------- /Chapter01/example_1_2_2.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def example_function(name, radius): 4 | area = math.pi * radius ** 2 5 | return "The area of {} is {}".format(name, area) 6 | 7 | print(example_function('Bob', 5)) 8 | -------------------------------------------------------------------------------- /Chapter01/example_1_2_3.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def example_function(name: str, radius: float) -> str: 4 | area = math.pi * radius ** 2 5 | return "The area of {} is {}".format(name, area) 6 | 7 | print(example_function('Bob', 5)) 8 | -------------------------------------------------------------------------------- /Chapter01/example_1_2_4.py: -------------------------------------------------------------------------------- 1 | outer = "Hello world" 2 | 3 | def example_function(param): 4 | inner = "Hello function: {}".format(param) 5 | print(inner, outer) 6 | 7 | example_function("first") 8 | example_function("second") 9 | print(inner) 10 | -------------------------------------------------------------------------------- /Chapter01/example_1_2_5.py: -------------------------------------------------------------------------------- 1 | class Frood: 2 | def __init__(self, age): 3 | self.age = age 4 | print("Frood initialized") 5 | 6 | def anniversary(self): 7 | self.age += 1 8 | print("Frood is now {} years old".format(self.age)) 9 | 10 | f1 = Frood(12) 11 | f2 = Frood(97) 12 | f1.anniversary() 13 | f2.anniversary() 14 | f1.anniversary() 15 | f2.anniversary() 16 | -------------------------------------------------------------------------------- /Chapter01/example_1_2_6.py: -------------------------------------------------------------------------------- 1 | selector = 5 2 | 3 | if selector < 3: 4 | print("less than three") 5 | elif selector < 6: 6 | print("less than six") 7 | else: 8 | print("six or more") 9 | 10 | while selector > 0: 11 | print('selector is {}'.format(selector)) 12 | selector -= 1 13 | 14 | for x in ['a', 'b', 'c', 'd']: 15 | print(x) 16 | 17 | for x in range(5): 18 | print(x) 19 | 20 | -------------------------------------------------------------------------------- /Chapter02/py27.py: -------------------------------------------------------------------------------- 1 | from urllib2 import urlopen, URLError 2 | 3 | 4 | def fetch_email(url): 5 | try: 6 | data = urlopen(url).read() 7 | return data.split('mailto:')[1].split('"')[0] 8 | except (IndexError, URLError), error: 9 | print error 10 | return 'invalid@example.com' 11 | -------------------------------------------------------------------------------- /Chapter02/py34.py: -------------------------------------------------------------------------------- 1 | from urllib.request import urlopen 2 | from urllib.error import URLError 3 | 4 | def fetch_email(url): 5 | try: 6 | data = urlopen(url).read().decode('utf8') 7 | return data.split('mailto:')[1].split('"')[0] 8 | except (IndexError, URLError) as error: 9 | print(error) 10 | return 'invalid@example.com' 11 | -------------------------------------------------------------------------------- /Chapter03/cyclic/a.py: -------------------------------------------------------------------------------- 1 | import .b 2 | 3 | class A: 4 | def __init__(self): 5 | print(str(self)) 6 | 7 | class C(b.B): 8 | def __str__(self): 9 | return 'C' 10 | -------------------------------------------------------------------------------- /Chapter03/cyclic/b.py: -------------------------------------------------------------------------------- 1 | import .a 2 | 3 | class B(a.A): 4 | def __str__(self): 5 | return 'B' 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/example/data/datafile.txt: -------------------------------------------------------------------------------- 1 | Hello world of data 2 | -------------------------------------------------------------------------------- /Chapter04/pep8_example.py: -------------------------------------------------------------------------------- 1 | """Demonstrate PEP 8 layout 2 | 3 | This module does nothing useful, aside from demonstrating most of the 4 | layout rules of PEP 8. 5 | 6 | """ 7 | 8 | import sys 9 | import re 10 | from pickle import loads, dumps 11 | 12 | class Elephant: 13 | """Tracks elephants and their optional associated dormice. 14 | 15 | """ 16 | def __init__(self, dormouse = None): 17 | """Create an Elephant, and optionally tie it to a DorMouse. 18 | 19 | If specified, the dormouse parameter should be a DorMouse 20 | instance which should be associated with this Elephant. 21 | 22 | """ 23 | self.dormouse = dormouse 24 | 25 | if dormouse: 26 | dormouse.set_elephant(self) 27 | 28 | 29 | class DorMouse: 30 | """Tracks dormice, optionally associated with elephants. 31 | 32 | Each DorMouse instance has the ability to associate with 0 or 1 33 | Elephant instances. Use the set_elephant method to establish that 34 | association. 35 | 36 | """ 37 | def __init__(self): 38 | """Initialize the DorMouse, setting the Elephant to None.""" 39 | self.elephant = None 40 | 41 | def set_elephant(self, elephant): 42 | """Associate an Elephant with this DorMouse. 43 | 44 | The elephant parameter must be an Elephant instance, or None. 45 | Setting the elephant to None breaks the association between 46 | this DorMouse and its Elephant. 47 | 48 | """ 49 | if self.elephant: 50 | self.elephant.dormouse = None 51 | self.elephant = elephant 52 | 53 | 54 | # The ScarePair function creates a ScarePair object, which is actually 55 | # just a tuple containing a linked Elephant and DorMouse pair. 56 | def ScarePair(): 57 | """Create a ScarePair object linking an Elephant and a DorMouse. 58 | 59 | Both the Elephant and the DorMouse instances of the pair are newly 60 | created. They are fully associated before the pair is returned. 61 | 62 | """ 63 | dormouse = DorMouse() 64 | elephant = Elephant(dormouse) 65 | 66 | return elephant, dormouse 67 | 68 | 69 | def munge(left, right): 70 | """Make a horrible mess. 71 | 72 | This function takes a pair of ScarePair objects and twists them up 73 | into a pretzel. 74 | 75 | """ 76 | left[1].set_elephant(right[0]) 77 | right[1].set_elephant(left[0]) 78 | 79 | new_left = (left[0], right[1]) 80 | new_right = (right[0], left[1]) 81 | 82 | return lew_left, new_right 83 | -------------------------------------------------------------------------------- /Chapter04/tab_trouble.py: -------------------------------------------------------------------------------- 1 | def tabs_cause_problems(): 2 | with open('test.txt') as f: 3 | for line in f: 4 | try: 5 | print(int(line)) 6 | except ValueError: 7 | print('Not an integer') 8 | 9 | -------------------------------------------------------------------------------- /Chapter05/example02/ap0.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | parser = argparse.ArgumentParser() 3 | args = parser.parse_args() 4 | -------------------------------------------------------------------------------- /Chapter05/example02/ap1.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | parser = argparse.ArgumentParser(description="Hello world") 3 | args = parser.parse_args() 4 | -------------------------------------------------------------------------------- /Chapter05/example02/ap2.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | parser = argparse.ArgumentParser( 3 | prog = 'python -m apdemo', 4 | description="Hello world" 5 | ) 6 | args = parser.parse_args() 7 | -------------------------------------------------------------------------------- /Chapter05/example02/ap3.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | parser = argparse.ArgumentParser( 3 | prog = 'python -m apdemo', 4 | description="Hello world" 5 | ) 6 | parser.add_argument('-p', '--print', action='store_true', default = False) 7 | args = parser.parse_args() 8 | -------------------------------------------------------------------------------- /Chapter05/example02/ap4.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | parser = argparse.ArgumentParser( 3 | prog = 'python -m apdemo', 4 | description="Hello world" 5 | ) 6 | parser.add_argument('-p', '--print', action='store_true', default = False) 7 | parser.add_argument('name', nargs='+') 8 | args = parser.parse_args() 9 | -------------------------------------------------------------------------------- /Chapter05/example03/simple.py: -------------------------------------------------------------------------------- 1 | print("Hello World") 2 | name = input("Name: ") 3 | print("Hello", name) 4 | -------------------------------------------------------------------------------- /Chapter05/example03/special.py: -------------------------------------------------------------------------------- 1 | from getpass import getpass 2 | from pprint import pprint 3 | 4 | password = getpass('Password: ') 5 | pprint([{1: 2, 3: 4}, {5: 6, 7: list(range(25))}]) 6 | -------------------------------------------------------------------------------- /Chapter05/example03/usecmd.py: -------------------------------------------------------------------------------- 1 | import cmd 2 | 3 | class Interface(cmd.Cmd): 4 | prompt = 'Command: ' 5 | 6 | def do_foo(self, arg): 7 | print(arg) 8 | 9 | interface = Interface() 10 | interface.cmdloop() 11 | -------------------------------------------------------------------------------- /Chapter05/example04/echo.py: -------------------------------------------------------------------------------- 1 | while True: 2 | x = input() 3 | print('echoed:', x) 4 | -------------------------------------------------------------------------------- /Chapter05/example05/echo.py: -------------------------------------------------------------------------------- 1 | while True: 2 | x = input() 3 | print('echoed:', x) 4 | -------------------------------------------------------------------------------- /Chapter06/example1/ascompleted.py: -------------------------------------------------------------------------------- 1 | from concurrent import futures 2 | 3 | class FooError(Exception): 4 | pass 5 | 6 | def foo(x, y): 7 | if x > y: 8 | raise FooError 9 | return y - x 10 | 11 | with futures.ProcessPoolExecutor() as pool: 12 | running = [pool.submit(foo, 5, 8), 13 | pool.submit(foo, 6, 9)] 14 | 15 | for future in futures.as_completed(running): 16 | data = future.result() 17 | ... do whatever we need with data ... 18 | 19 | -------------------------------------------------------------------------------- /Chapter06/example1/cancel.py: -------------------------------------------------------------------------------- 1 | from concurrent import futures 2 | 3 | class FooError(Exception): 4 | pass 5 | 6 | def foo(x, y): 7 | if x > y: 8 | raise FooError 9 | return y - x 10 | 11 | with futures.ProcessPoolExecutor() as pool: 12 | running = [pool.submit(foo, 5, 8), 13 | pool.submit(foo, 6, 9)] 14 | 15 | if running[0].cancel(): 16 | print('Successfully cancelled') 17 | else: 18 | print('Too late') 19 | 20 | -------------------------------------------------------------------------------- /Chapter06/example1/example1_1.py: -------------------------------------------------------------------------------- 1 | from concurrent import futures 2 | 3 | def factorize(n): 4 | """Return the prime factors of *n* 5 | 6 | This is a **very** bad factoring algorithm, which makes it a good 7 | example of a CPU bound task. 8 | 9 | """ 10 | n = int(n) 11 | 12 | if n == 1: 13 | return 1, [] 14 | 15 | found = [] 16 | 17 | for i in range(2, (n // 2) + 1): 18 | if n % i == 0: 19 | if all(i % j != 0 for j in found): 20 | found.append(i) 21 | 22 | if not found: 23 | return n, [n] 24 | 25 | return n, found 26 | 27 | if __name__ == '__main__': 28 | with futures.ProcessPoolExecutor() as pool: 29 | for number, factors in pool.map(factorize, range(1, 10001)): 30 | print('{}: {}'.format(number, factors)) 31 | -------------------------------------------------------------------------------- /Chapter06/example1/example1_2.py: -------------------------------------------------------------------------------- 1 | from concurrent import futures 2 | 3 | def factorize(n): 4 | """Return the prime factors of *n* 5 | 6 | This is a **very** bad factoring algorithm, which makes it a good 7 | example of a CPU bound task. 8 | 9 | """ 10 | n = int(n) 11 | 12 | if n < 2: 13 | raise ValueError('Invalid number for factorization', n) 14 | 15 | found = [] 16 | 17 | for i in range(2, (n // 2) + 1): 18 | if n % i == 0: 19 | if all(i % j != 0 for j in found): 20 | found.append(i) 21 | 22 | if not found: 23 | return n, [n] 24 | 25 | return n, found 26 | 27 | if __name__ == '__main__': 28 | with futures.ProcessPoolExecutor() as pool: 29 | fs = [pool.submit(factorize, x) for x in range(1, 10001)] 30 | for f in futures.as_completed(fs): 31 | try: 32 | number, factors = f.result() 33 | except ValueError: 34 | continue 35 | print('{}: {}'.format(number, factors)) 36 | -------------------------------------------------------------------------------- /Chapter06/example1/poolmap.py: -------------------------------------------------------------------------------- 1 | from concurrent import futures 2 | 3 | def foo(x, y): 4 | return y - x 5 | 6 | with futures.ProcessPoolExecutor() as pool: 7 | pool.map(foo, [1, 2, 3], [4, 5, 6]) 8 | 9 | <<< means >>> 10 | 11 | foo(1, 4) 12 | foo(2, 5) 13 | foo(3, 6) 14 | 15 | -------------------------------------------------------------------------------- /Chapter06/example1/poolsubmit.py: -------------------------------------------------------------------------------- 1 | from concurrent import futures 2 | 3 | class FooError(Exception): 4 | pass 5 | 6 | def foo(x, y): 7 | if x > y: 8 | raise FooError 9 | return y - x 10 | 11 | with futures.ProcessPoolExecutor() as pool: 12 | future = pool.submit(foo, 4, 7) 13 | 14 | while not future.done(): 15 | ... do other stuff ... 16 | 17 | try: 18 | data = future.result() 19 | except FooError: 20 | data = None 21 | -------------------------------------------------------------------------------- /Chapter06/example1/poolsubmit2.py: -------------------------------------------------------------------------------- 1 | from concurrent import futures 2 | 3 | class FooError(Exception): 4 | pass 5 | 6 | def foo(x, y): 7 | if x > y: 8 | raise FooError 9 | return y - x 10 | 11 | with futures.ProcessPoolExecutor() as pool: 12 | future = pool.submit(foo, 4, 7) 13 | 14 | while not future.done(): 15 | ... do other stuff ... 16 | 17 | while True: 18 | try: 19 | data = future.result(timeout = 0.5) 20 | except futures.TimeoutError: 21 | print('Working...') 22 | continue 23 | except FooError: 24 | data = None 25 | 26 | break 27 | -------------------------------------------------------------------------------- /Chapter06/example1/waiting.py: -------------------------------------------------------------------------------- 1 | from concurrent import futures 2 | 3 | class FooError(Exception): 4 | pass 5 | 6 | def foo(x, y): 7 | if x > y: 8 | raise FooError 9 | return y - x 10 | 11 | with futures.ProcessPoolExecutor() as pool: 12 | running = [pool.submit(foo, 5, 8), 13 | pool.submit(foo, 6, 9)] 14 | 15 | while running: 16 | done, running = futures.wait(running, timeout = 2.5) 17 | for future in done: 18 | data = future.result() 19 | ... do whatever we need with data ... 20 | 21 | -------------------------------------------------------------------------------- /Chapter06/example2/condition.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Manager 2 | 3 | manager = Manager() 4 | 5 | cond = manager.Condition() 6 | 7 | cond.acquire() 8 | cond.wait() 9 | 10 | # ... manipulate data ... 11 | 12 | cond.release() 13 | 14 | # in another process 15 | 16 | cond.acquire() 17 | 18 | # ... manipulate data ... 19 | 20 | cond.notify() 21 | cond.release() 22 | -------------------------------------------------------------------------------- /Chapter06/example2/event.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Manager 2 | 3 | manager = Manager() 4 | 5 | event = manager.Event() 6 | 7 | event.clear() 8 | event.wait() 9 | 10 | # In a different process 11 | 12 | event.set() 13 | 14 | 15 | -------------------------------------------------------------------------------- /Chapter06/example2/lock.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Manager 2 | 3 | manager = Manager() 4 | 5 | lock = manager.Lock() 6 | 7 | lock.acquire() 8 | 9 | # ... manipulate data ... 10 | 11 | lock.release() 12 | -------------------------------------------------------------------------------- /Chapter06/example2/manager.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Manager 2 | 3 | manager = Manager() 4 | 5 | dictionary = manager.dict() 6 | sequence = manager.list() 7 | obj = manager.Namespace() 8 | 9 | dictionary['hello'] = 'world' 10 | sequence.append(57) 11 | obj.attribute = 'This is shared data' 12 | 13 | lock = manager.Lock() 14 | event = manager.Event() 15 | cond = manager.Condition() 16 | sem = manager.BoundedSemaphore(3) 17 | -------------------------------------------------------------------------------- /Chapter06/example2/pipe.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Pipe 2 | 3 | near, far = Pipe() 4 | 5 | # ... Pass far on to a different process ... 6 | 7 | near.send(('hello', 5)) 8 | 9 | if near.poll(timeout = 2.5): 10 | data = near.recv() 11 | -------------------------------------------------------------------------------- /Chapter06/example2/primes.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Process, Pipe, Queue 2 | 3 | class Multiples(Process): 4 | """Process to calculate multiples of a base number. 5 | 6 | The set of multiples of a number is a countably infinite set, so 7 | this process can never complete its job. However, other processes 8 | can stop it when the list is long enough by sending 'stop' through 9 | the contol pipe. It can also be retasked to a new number by sending 10 | that number through the control pipe. 11 | 12 | """ 13 | def __init__(self, base, control, output): 14 | super().__init__() 15 | self.base = base 16 | self.control = control 17 | self.output = output 18 | 19 | def run(self): 20 | """Perform the calculations.""" 21 | base = self.base 22 | control = self.control 23 | output = self.output 24 | 25 | current = base 26 | 27 | while True: 28 | if control.poll(timeout = 0.1): 29 | try: 30 | command = control.recv() 31 | except EOFError: 32 | command = 'stop' 33 | 34 | if command == 'stop': 35 | break 36 | else: 37 | base = current = int(command) 38 | 39 | current = current + base 40 | output.put((base, current)) 41 | 42 | if __name__ == '__main__': 43 | maximum = 100 44 | numbers = set(range(2, maximum)) 45 | tried = set() 46 | output = Queue() 47 | controls = {} 48 | 49 | for i in range(2, 5): 50 | near, far = Pipe() 51 | tried.add(i) 52 | proc = Multiples(i, far, output) 53 | proc.start() 54 | controls[i] = near 55 | 56 | while controls: 57 | base, num = output.get() 58 | 59 | if base not in controls: 60 | continue 61 | 62 | print(numbers) 63 | 64 | numbers.discard(num) 65 | 66 | if num > maximum: 67 | control = base 68 | elif num in controls: 69 | control = num 70 | else: 71 | control = 0 72 | 73 | if control > 0: 74 | ctrl = controls.get(control) 75 | if ctrl is not None: 76 | del controls[control] 77 | 78 | try: 79 | new_base = next(iter(numbers - tried)) 80 | except StopIteration: 81 | ctrl.send('stop') 82 | else: 83 | tried.add(new_base) 84 | controls[new_base] = ctrl 85 | ctrl.send(new_base) 86 | -------------------------------------------------------------------------------- /Chapter06/example2/queue.py: -------------------------------------------------------------------------------- 1 | from queue import Empty 2 | from multiprocessing import Queue 3 | from multiprocessing import JoinableQueue 4 | 5 | q = Queue() 6 | 7 | q.put('hello') 8 | 9 | result = q.get() 10 | 11 | try: 12 | data = q.get_nowait() 13 | except Empty: 14 | data = None 15 | 16 | try: 17 | more = q.get(timeout = 2.5) 18 | except Empty: 19 | more = None 20 | -------------------------------------------------------------------------------- /Chapter06/example2/semaphore.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Manager 2 | 3 | manager = Manager() 4 | 5 | sem = manager.BoundedSemaphore(3) 6 | 7 | sem.acquire() 8 | 9 | # ... access limited resource ... 10 | 11 | sem.release() 12 | -------------------------------------------------------------------------------- /Chapter06/example2/squares.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Process 2 | 3 | class Squares(Process): 4 | def run(self): 5 | for i in range(10): 6 | print(i ** 2) 7 | 8 | squares = Squares() 9 | 10 | squares.start() 11 | 12 | -------------------------------------------------------------------------------- /Chapter07/example1/coroutine.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | async def example(): 4 | x = await do_stuff() 5 | return 'Hello world', x 6 | 7 | async def very_long(): 8 | while True: 9 | await asyncio.sleep(0) 10 | 11 | -------------------------------------------------------------------------------- /Chapter07/example2/coroutine.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | async def example(): 4 | await asyncio.sleep(5) 5 | return 5 6 | 7 | -------------------------------------------------------------------------------- /Chapter07/example2/run_forever.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | 4 | async def coro1(): 5 | while True: 6 | for i in range(100000): 7 | await asyncio.sleep(0.1) 8 | print('coro1') 9 | 10 | async def coro2(): 11 | for i in range(25): 12 | await asyncio.sleep(0.5) 13 | print(i) 14 | 15 | loop = asyncio.get_event_loop() 16 | loop.stop() 17 | 18 | 19 | logging.getLogger('asyncio').setLevel('CRITICAL') 20 | 21 | asyncio.ensure_future(coro1()) 22 | asyncio.ensure_future(coro2()) 23 | 24 | loop = asyncio.get_event_loop() 25 | loop.run_forever() 26 | loop.close() 27 | -------------------------------------------------------------------------------- /Chapter07/example2/run_until_complete.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | 4 | async def coro1(): 5 | while True: 6 | for i in range(100000): 7 | await asyncio.sleep(0.1) 8 | print('coro1') 9 | 10 | async def coro2(): 11 | for i in range(25): 12 | await asyncio.sleep(0.5) 13 | print(i) 14 | 15 | logging.getLogger('asyncio').setLevel('CRITICAL') 16 | 17 | asyncio.ensure_future(coro1()) 18 | f = asyncio.ensure_future(coro2()) 19 | 20 | loop = asyncio.get_event_loop() 21 | loop.run_until_complete(f) 22 | loop.close() 23 | -------------------------------------------------------------------------------- /Chapter07/example2/run_until_complete_with_closing.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | import contextlib 4 | 5 | async def coro1(): 6 | while True: 7 | for i in range(100000): 8 | await asyncio.sleep(0.1) 9 | print('coro1') 10 | 11 | async def coro2(): 12 | for i in range(25): 13 | await asyncio.sleep(0.5) 14 | print(i) 15 | 16 | logging.getLogger('asyncio').setLevel('CRITICAL') 17 | 18 | asyncio.ensure_future(coro1()) 19 | f = asyncio.ensure_future(coro2()) 20 | 21 | with contextlib.closing(asyncio.get_event_loop()) as loop: 22 | loop.run_until_complete(f) 23 | -------------------------------------------------------------------------------- /Chapter07/example3/futures.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | async def get_future_values(future1, future2): 4 | value1 = await future1 5 | value2 = future2.result() if future2.done() else None 6 | return value1, value2 7 | -------------------------------------------------------------------------------- /Chapter07/example3/iterable.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | class SlowSequence: 4 | class Iterator: 5 | def __init__(self, slowseq): 6 | self.values = list(slowseq.values) 7 | 8 | async def __anext__(self): 9 | await asyncio.sleep(2) 10 | try: 11 | return self.values.pop(0) 12 | except IndexError: 13 | raise StopAsyncIteration 14 | 15 | def __init__(self, *values): 16 | self.values = values 17 | 18 | async def __aiter__(self): 19 | return SlowSequence.Iterator(self) 20 | 21 | async def main(): 22 | seq = SlowSequence(1, 2, 3, 4, 5) 23 | 24 | async for value in seq: 25 | print(value) 26 | 27 | loop = asyncio.get_event_loop() 28 | loop.run_until_complete(asyncio.ensure_future(main())) 29 | loop.close() 30 | -------------------------------------------------------------------------------- /Chapter07/example4/as_completed.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import random 3 | 4 | async def delayed_value(value): 5 | await asyncio.sleep(random.randrange(5)) 6 | return value 7 | 8 | async def main(): 9 | futures = [ 10 | asyncio.ensure_future(delayed_value(1)), 11 | asyncio.ensure_future(delayed_value(2)), 12 | asyncio.ensure_future(delayed_value(3)), 13 | asyncio.ensure_future(delayed_value(4)), 14 | asyncio.ensure_future(delayed_value(5)), 15 | ] 16 | 17 | for future in asyncio.as_completed(futures): 18 | value = await future 19 | print(value) 20 | 21 | loop = asyncio.get_event_loop() 22 | loop.run_until_complete(asyncio.ensure_future(main())) 23 | loop.close() 24 | -------------------------------------------------------------------------------- /Chapter07/example4/gather.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import random 3 | 4 | async def delayed_print(value): 5 | await asyncio.sleep(random.randrange(5)) 6 | print(value) 7 | 8 | main = asyncio.gather( 9 | asyncio.ensure_future(delayed_print(1)), 10 | asyncio.ensure_future(delayed_print(2)), 11 | asyncio.ensure_future(delayed_print(3)), 12 | asyncio.ensure_future(delayed_print(4)), 13 | asyncio.ensure_future(delayed_print(5)), 14 | ) 15 | 16 | loop = asyncio.get_event_loop() 17 | loop.run_until_complete(main) 18 | loop.close() 19 | -------------------------------------------------------------------------------- /Chapter07/example4/queue_usage.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | async def using_queues(): 4 | q = asyncio.Queue() 5 | 6 | q.put_nowait('Hello') 7 | 8 | await q.get() 9 | 10 | await q.put('world') 11 | 12 | q.get_nowait() 13 | 14 | 15 | pq = asyncio.PriorityQueue() 16 | 17 | stack = asyncio.LifoQueue() 18 | -------------------------------------------------------------------------------- /Chapter07/example4/wait_for.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | async def call_coro(coro): 4 | x = await coro() 5 | 6 | async def call_coro_with_five_second_timeout(coro): 7 | x = await asyncio.wait_for(coro(), 5) 8 | 9 | async def call_coro_with_timeout_and_handle_exception(coro): 10 | try: 11 | x = await asyncio.wait_for(coro(), 5) 12 | except asyncio.TimeoutError: 13 | print('Too slow') 14 | 15 | -------------------------------------------------------------------------------- /Chapter07/example5/client.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import itertools 3 | import contextlib 4 | 5 | async def client(host, port): 6 | reader, writer = await asyncio.open_connection(host, port) 7 | 8 | for i in itertools.count(): 9 | writer.write(b'ping\n') 10 | response = await reader.readline() 11 | if response == b'pong\n': 12 | print(i) 13 | else: 14 | return 15 | 16 | main = asyncio.ensure_future(client('127.0.0.1', 8899)) 17 | loop = asyncio.get_event_loop() 18 | 19 | with contextlib.closing(loop): 20 | loop.run_until_complete(main) 21 | -------------------------------------------------------------------------------- /Chapter07/example5/server.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import contextlib 3 | 4 | async def serve(reader, writer): 5 | while True: 6 | try: 7 | request = await reader.readline() 8 | except ConnectionResetError: 9 | return 10 | if request == b'': 11 | return 12 | elif request == b'ping\n': 13 | writer.write(b'pong\n') 14 | else: 15 | writer.write(b'done\n') 16 | 17 | async def launch(host, port): 18 | server = await asyncio.start_server(serve, host, port) 19 | await server.wait_closed() 20 | 21 | main = asyncio.ensure_future(launch('127.0.0.1', 8899)) 22 | loop = asyncio.get_event_loop() 23 | 24 | with contextlib.closing(loop): 25 | loop.run_until_complete(main) 26 | 27 | -------------------------------------------------------------------------------- /Chapter08/adapted.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | def adapted(func): 4 | @wraps(func) 5 | def wrapper(**kwargs): 6 | final_args = {} 7 | 8 | for name, value in kwargs.items(): 9 | adapt = func.__annotations__.get(name) 10 | if adapt is not None: 11 | final_args[name] = adapt(value) 12 | else: 13 | final_args[name] = value 14 | 15 | result = func(**final_args) 16 | 17 | adapt = func.__annotations__.get('return') 18 | if adapt is not None: 19 | return adapt(result) 20 | return result 21 | 22 | return wrapper 23 | 24 | @adapted 25 | def foo(a : int, b : repr) -> str: 26 | return a 27 | -------------------------------------------------------------------------------- /Chapter08/adapted_only.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | def only(adapt = int): 4 | def decorator(func): 5 | @wraps(func): 6 | def wrapper(*args, **kawrgs): 7 | args = [adapt(x) for x in args] 8 | kwargs = {n: adapt(v) 9 | for n, v 10 | in kwargs.items()} 11 | return func(*args, **kwargs) 12 | return wrapper 13 | return decorator 14 | 15 | @only(int) 16 | def add(left, right): 17 | return left + right 18 | 19 | add('57', 99.5) 20 | -------------------------------------------------------------------------------- /Chapter08/async_trans.py: -------------------------------------------------------------------------------- 1 | from collections import ChainMap 2 | 3 | class AsyncTransactionDict(dict): 4 | async def __aenter__(self): 5 | self.writes = dict() 6 | return ChainMap(self.writes, self) 7 | 8 | async def __aexit__(self, exc_type, exc_val, tb): 9 | if exc_type is None: 10 | self.update(self.writes) 11 | self.writes = None 12 | -------------------------------------------------------------------------------- /Chapter08/attritems.py: -------------------------------------------------------------------------------- 1 | def attritems(class_): 2 | def _getitem(self, key): 3 | return getattr(self, key) 4 | 5 | setattr(class_, '__getitem__', _getitem) 6 | 7 | if getattr(class_, '__setitem__', None): 8 | delattr(class_, '__setitem__') 9 | 10 | if getattr(class_, '__delitem__', None): 11 | delattr(class_, '__delitem__') 12 | 13 | return class_ 14 | 15 | @attritems 16 | class Foo: 17 | def __init__(self): 18 | self.a = 'hello' 19 | self.b = 'world' 20 | 21 | f = Foo() 22 | 23 | assert f['a'] == 'hello' 24 | assert f['b'] == 'world' 25 | -------------------------------------------------------------------------------- /Chapter08/before_and_after.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | 3 | @contextlib.contextmanager 4 | def before_and_after(): 5 | print("Before") 6 | try: 7 | yield (lambda: print("During")) 8 | finally: 9 | print("After") 10 | -------------------------------------------------------------------------------- /Chapter08/database.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | def database(connclass): 4 | fname = getattr(connclass, 'database', 'default.sqlite') 5 | connection = sqlite3.connect(fname, detect_types=sqlite3.PARSE_DECLTYPES) 6 | 7 | for tablename in dir(connclass): 8 | if tablename.startswith('_'): 9 | continue 10 | 11 | tabledata = getattr(connclass, tablename, None) 12 | 13 | if not isinstance(tabledata, type): 14 | continue 15 | 16 | columns = [] 17 | 18 | for colname in dir(tabledata): 19 | if colname.startswith('_'): 20 | continue 21 | coldata = getattr(tabledata, colname, None) 22 | if coldata in ('INTEGER', 'TEXT'): 23 | columns.append('{} {}'.format(colname, coldata)) 24 | 25 | sql = 'CREATE TABLE IF NOT EXISTS {} ({});' 26 | sql = sql.format(tablename, ', '.join(columns)) 27 | 28 | connection.execute(sql) 29 | 30 | return connection 31 | -------------------------------------------------------------------------------- /Chapter08/factory.py: -------------------------------------------------------------------------------- 1 | from weakref import WeakValueDictionary 2 | 3 | def factory_constructed(class_): 4 | cache = WeakValueDictionary() 5 | 6 | def factory(*args, **kwargs): 7 | key = (args, frozenset(kwargs.items())) 8 | instance = cache.get(key) 9 | if instance is not None: 10 | return instance 11 | instance = class_(*args, **kwargs) 12 | cache[key] = instance 13 | return instance 14 | 15 | factory.type = class_ 16 | 17 | return factory 18 | -------------------------------------------------------------------------------- /Chapter08/ints_only.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | def ints_only(func): 4 | @wraps(func): 5 | def wrapper(*args, **kawrgs): 6 | args = [int(x) for x in args] 7 | kwargs = {n: int(v) 8 | for n, v 9 | in kwargs.items()} 10 | return func(*args, **kwargs) 11 | return wrapper 12 | 13 | @ints_only 14 | def add(left, right): 15 | return left + right 16 | 17 | add('57', 99.5) 18 | -------------------------------------------------------------------------------- /Chapter08/only.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | def only(adapt = int): 4 | def decorator(func): 5 | @wraps(func): 6 | def wrapper(*args, **kawrgs): 7 | args = [adapt(x) for x in args] 8 | kwargs = {n: adapt(v) 9 | for n, v 10 | in kwargs.items()} 11 | return func(*args, **kwargs) 12 | return wrapper 13 | return decorator 14 | 15 | @only(float) 16 | def add(left, right): 17 | return left + right 18 | -------------------------------------------------------------------------------- /Chapter08/register.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | class BasicMeta(type): 4 | @staticmethod 5 | def __prepare__(name, bases, **kwargs): 6 | return dict() 7 | 8 | class OrderedMeta(type): 9 | @staticmethod 10 | def __prepare__(name, bases, **kwargs): 11 | return OrderedDict() 12 | 13 | def __new__(cls, name, bases, namespace, **kwargs): 14 | class_ = type.__new__(cls, name, bases, namespace) 15 | class_.order = type(namespace.keys()) 16 | return class_ 17 | 18 | class RegisterDescendants(type): 19 | def __new__(cls, name, bases, namespace, **kwargs): 20 | class_ = type.__new__(cls, name, bases, namespace) 21 | registry = getattr(class_, 'REGISTRY', set()) 22 | registry.add(class_) 23 | setattr(class_, 'REGISTRY', registry) 24 | return class_ 25 | -------------------------------------------------------------------------------- /Chapter08/remote.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | class RemoteResource: 4 | def __init__(self, name): 5 | self.name = name 6 | 7 | def to_str(self, val): 8 | return str(val) 9 | 10 | def from_str(self, val): 11 | return val 12 | 13 | async def _fetcher(self, instance, name, future): 14 | out = instance.out 15 | in_ = instance.in_ 16 | pk = instance.pk 17 | out.write('fetch {} {}\n'.format(pk, name) 18 | value = await in_.readline() 19 | future.set_result(self.from_str(value)) 20 | 21 | def __get__(self, instance, class_): 22 | if instance is None: 23 | return self 24 | future = asyncio.Future() 25 | coro = self._fetcher(instance, self.name, future) 26 | asyncio.ensure_future(coro) 27 | return future 28 | 29 | def __set__(self, instance, value): 30 | pk = instance.pk 31 | name = self.name 32 | value = self.to_str(value) 33 | template = 'set {} {}\n{}\n' 34 | command = template.format(pk, name, value) 35 | instance.out.write(command) 36 | 37 | def __delete__(self, instance): 38 | pk = instance.pk 39 | name = self.name 40 | command = 'delete {} {}\n'.format(pk, name) 41 | instance.out.write(command) 42 | 43 | class RemoteInt(RemoteResource): 44 | def from_string(self, value): 45 | return int(value) 46 | 47 | class Record: 48 | name = RemoteResource('name') 49 | age = RemoteInt('age') 50 | 51 | def __init__(self, pk, reader, writer): 52 | self.out = writer 53 | self.in_ = reader 54 | self.pk = pk 55 | -------------------------------------------------------------------------------- /Chapter08/store_args.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | def store_args(func): 4 | @wraps(func) 5 | def wrapper(self, **kwargs): 6 | for name, value in kwargs.items(): 7 | attrib = func.__annotations__.get(name) 8 | if attrib is True: 9 | attrib = name 10 | if isinstance(attrib, str): 11 | setattr(self, attrib, value) 12 | return func(self, **kwargs) 13 | return wrapper 14 | 15 | class A: 16 | @store_args 17 | def __init__(self, first: True, second: 'example'): 18 | pass 19 | 20 | a = A(first = 5, second = 6) 21 | assert a.first == 5 22 | assert a.example == 6 23 | -------------------------------------------------------------------------------- /Chapter08/trans.py: -------------------------------------------------------------------------------- 1 | from collections import ChainMap 2 | 3 | class TransactionDict(dict): 4 | def __enter__(self): 5 | self.writes = dict() 6 | return ChainMap(self.writes, self) 7 | 8 | def __exit__(self, exc_type, exc_val, tb): 9 | if exc_type is None: 10 | self.update(self.writes) 11 | self.writes = None 12 | 13 | if __name__ == '__main__': 14 | tdict = TransactionDict() 15 | with tdict as trans: 16 | trans['a'] = 1 17 | -------------------------------------------------------------------------------- /Chapter09/suite/test_one.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | class BasicTest(unittest.TestCase): 4 | def test_addition(self): 5 | self.assertEqual(2 + 2, 4) 6 | -------------------------------------------------------------------------------- /Chapter09/suite/test_two.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | 4 | class SharedEnv(unittest.TestCase): 5 | def setUp(self): 6 | with open('test.txt', 'w') as f: 7 | f.write('a\nb\n') 8 | 9 | def tearDown(self): 10 | os.unlink('test.txt') 11 | 12 | def test_append(self): 13 | with open('test.txt', 'r') as f: 14 | lines = f.read().splitlines() 15 | 16 | self.assertEqual(lines, ['a', 'b']) 17 | 18 | lines.append('c') 19 | 20 | with open('test.txt', 'w') as f: 21 | f.write('\n'.join(lines)) 22 | 23 | def test_replace(self): 24 | with open('test.txt', 'r') as f: 25 | lines = f.read().splitlines() 26 | 27 | self.assertEqual(lines, ['a', 'b']) 28 | 29 | lines[0] = 'q' 30 | 31 | with open('test.txt', 'w') as f: 32 | f.write('\n'.join(lines)) 33 | -------------------------------------------------------------------------------- /Chapter09/test_examples.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | 4 | class BasicTest(unittest.TestCase): 5 | def test_addition(self): 6 | self.assertEqual(2 + 2, 4) 7 | 8 | class SharedEnv(unittest.TestCase): 9 | def setUp(self): 10 | with open('test.txt', 'w') as f: 11 | f.write('a\nb\n') 12 | 13 | def tearDown(self): 14 | os.unlink('test.txt') 15 | 16 | def test_append(self): 17 | with open('test.txt', 'r') as f: 18 | lines = f.read().splitlines() 19 | 20 | self.assertEqual(lines, ['a', 'b']) 21 | 22 | lines.append('c') 23 | 24 | with open('test.txt', 'w') as f: 25 | f.write('\n'.join(lines)) 26 | 27 | def test_replace(self): 28 | with open('test.txt', 'r') as f: 29 | lines = f.read().splitlines() 30 | 31 | self.assertEqual(lines, ['a', 'b']) 32 | 33 | lines[0] = 'q' 34 | 35 | with open('test.txt', 'w') as f: 36 | f.write('\n'.join(lines)) 37 | -------------------------------------------------------------------------------- /Chapter09/uncovered.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def square(x): 4 | return x ** 2 5 | 6 | def cube(x): 7 | return x ** 3 8 | 9 | def degrees(radians): 10 | return 180 * (radians / math.pi) 11 | 12 | not_quite_seven = math.sqrt(7) ** 2 13 | 14 | 15 | -------------------------------------------------------------------------------- /Chapter10/rxzoo/__main__.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from .animals import zoo 4 | 5 | 6 | if __name__ == '__main__': 7 | asyncio.get_event_loop().run_until_complete(zoo()) 8 | -------------------------------------------------------------------------------- /Chapter10/rxzoo/animals.py: -------------------------------------------------------------------------------- 1 | """A zoo 'simulation' 2 | 3 | Demonstrates ReactiveX event sequences 4 | 5 | """ 6 | 7 | import asyncio 8 | import random 9 | 10 | import rx 11 | 12 | 13 | class AnimalEvent: 14 | def __init__(self, source, action, value = ''): 15 | self.source = source 16 | self.action = action 17 | self.value = value 18 | 19 | 20 | class Animal: 21 | def __init__(self, name, sound): 22 | self.name = name 23 | self.sound = sound 24 | self.alive = True 25 | 26 | def generate_event(self): 27 | if random.random() < 0.01: 28 | self.alive = False 29 | return AnimalEvent(self, 'die') 30 | return AnimalEvent(self, 'noise', self.sound) 31 | 32 | def as_observable(self, scheduler): 33 | return rx.Observable.generate_with_relative_time( 34 | self, # initial state 35 | (lambda x: self.alive), # continue condition 36 | (lambda x: self), # next state 37 | (lambda x: self.generate_event()), # get next value 38 | (lambda x: random.random() * 10), # how long before next cycle 39 | scheduler 40 | ) 41 | 42 | 43 | def sometimes_loud(event): 44 | if event.action == 'noise' and random.random() < 0.25: 45 | return AnimalEvent(event.source, 46 | event.action, 47 | '{} loudly'.format(event.value)) 48 | return event 49 | 50 | 51 | def output(event): 52 | if event.action == 'die': 53 | print(event.source.name, 'died!') 54 | else: 55 | print(event.source.name, event.value) 56 | 57 | 58 | def zoo(): 59 | scheduler = rx.concurrency.AsyncIOScheduler() 60 | 61 | elephant = Animal('Lucretia', 'trumpets').as_observable(scheduler) 62 | lion = Animal('Arnold', 'roars').as_observable(scheduler) 63 | fox = Animal('Betty', 'goes chacha-chacha-chacha-chow').as_observable(scheduler) 64 | snake = Animal('Jake', 'hisses').as_observable(scheduler) 65 | 66 | louder = rx.Observable.merge(elephant, lion).select(sometimes_loud) 67 | 68 | out = rx.Observable.merge(fox, snake, louder).do_action(on_next = output) 69 | 70 | done = asyncio.Future() 71 | 72 | out.subscribe(on_completed = (lambda: done.set_result(True))) 73 | 74 | return done 75 | -------------------------------------------------------------------------------- /Chapter10/zoo/__main__.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from .animals import zoo 4 | 5 | 6 | if __name__ == '__main__': 7 | asyncio.get_event_loop().run_until_complete(zoo()) 8 | -------------------------------------------------------------------------------- /Chapter10/zoo/animals.py: -------------------------------------------------------------------------------- 1 | """A zoo 'simulation' 2 | 3 | Demonstrates the Observer and Observable classes from reactive.py 4 | 5 | """ 6 | 7 | import asyncio 8 | import random 9 | 10 | from .reactive import Observer, Observable 11 | 12 | 13 | class AnimalEvent: 14 | def __init__(self, source, action, value = ''): 15 | self.source = source 16 | self.action = action 17 | self.value = value 18 | 19 | 20 | class Animal(Observable): 21 | def __init__(self, name, sound): 22 | super().__init__() 23 | self.name = name 24 | self.sound = sound 25 | 26 | async def run(self): 27 | while True: 28 | await asyncio.sleep(random.random() * 10) 29 | 30 | if random.random() < 0.01: 31 | self._event(AnimalEvent(self, 'die')) 32 | self._complete() 33 | return 34 | 35 | self._event(AnimalEvent(self, 'noise', self.sound)) 36 | 37 | 38 | class SometimesLoud(Observable, Observer): 39 | def __init__(self, *sources): 40 | super().__init__() 41 | 42 | self.sources = sources 43 | 44 | for source in sources: 45 | source.subscribe(self) 46 | 47 | def on_event(self, event): 48 | if event.action == 'noise' and random.random() < 0.25: 49 | self._event(AnimalEvent(event.source, 50 | event.action, 51 | '{} loudly'.format(event.value))) 52 | else: 53 | self._event(event) 54 | 55 | def on_complete(self): 56 | if all(x.complete for x in self.sources): 57 | self._complete() 58 | 59 | 60 | class Output(Observer): 61 | def __init__(self, *sources): 62 | super().__init__() 63 | for source in sources: 64 | source.subscribe(self) 65 | 66 | def on_event(self, event): 67 | if event.action == 'die': 68 | print(event.source.name, 'died!') 69 | else: 70 | print(event.source.name, event.value) 71 | 72 | 73 | def zoo(): 74 | elephant = Animal('Lucretia', 'trumpets') 75 | lion = Animal('Arnold', 'roars') 76 | fox = Animal('Betty', 'goes chacha-chacha-chacha-chow') 77 | snake = Animal('Jake', 'hisses') 78 | 79 | out = Output(fox, snake, SometimesLoud(elephant, lion)) 80 | 81 | return asyncio.gather(elephant.run(), lion.run(), fox.run(), snake.run()) 82 | -------------------------------------------------------------------------------- /Chapter10/zoo/reactive.py: -------------------------------------------------------------------------------- 1 | """A very simple reactive programming system. 2 | 3 | Because most documentation of reactive programming systems is heavily 4 | oriented around static types and interfaces, we'll use Python's 5 | abstract base class functionality to define our interface protocols. 6 | 7 | """ 8 | 9 | import abc 10 | 11 | 12 | class Observer(abc.ABC): 13 | @abc.abstractmethod 14 | def on_event(self, event): 15 | pass 16 | 17 | def on_exception(self, exception): 18 | pass 19 | 20 | def on_complete(self): 21 | pass 22 | 23 | 24 | class Observable(abc.ABC): 25 | def __init__(self): 26 | self.observers = set() 27 | self.complete = False 28 | 29 | def subscribe(self, subscriber): 30 | if not isinstance(subscriber, Observer): 31 | raise ValueError('Only Observer objects are valid subscribers') 32 | self.observers.add(subscriber) 33 | 34 | def _event(self, event): 35 | if self.complete: 36 | raise RuntimeError("Can't send events on a completed Observable") 37 | for obs in self.observers: 38 | obs.on_event(event) 39 | 40 | def _exception(self, exception): 41 | if self.complete: 42 | raise RuntimeError("Can't send exceptions on a completed Observable") 43 | for obs in self.observers: 44 | obs.on_exception(event) 45 | 46 | def _complete(self): 47 | if self.complete: 48 | raise RuntimeError("Can't complete an already completed Observable") 49 | self.complete = True 50 | for obs in self.observers: 51 | obs.on_complete() 52 | -------------------------------------------------------------------------------- /Chapter11/demo_flask/__init__.py: -------------------------------------------------------------------------------- 1 | from .service import app 2 | -------------------------------------------------------------------------------- /Chapter11/demo_flask/endpoint.py: -------------------------------------------------------------------------------- 1 | import flask.views 2 | 3 | class Endpoint(flask.views.MethodView): 4 | def post(self): 5 | flask.abort(405) 6 | 7 | def get(self, id): 8 | flask.abort(405) 9 | 10 | def put(self, id): 11 | flask.abort(405) 12 | 13 | def delete(self, id): 14 | flask.abort(405) 15 | 16 | @classmethod 17 | def register(class_, app, base = '', default_id = None): 18 | view = class_.as_view(class_.__name__) 19 | 20 | # When no ID is provided, accept GET and use the default ID 21 | app.add_url_rule('{}/{}'.format(base, class_.__name__.lower()), 22 | defaults = {'id': default_id}, 23 | view_func = view, 24 | methods = ['GET']) 25 | 26 | # When no ID is provided, accept POST 27 | app.add_url_rule('{}/{}'.format(base, class_.__name__.lower()), 28 | view_func = view, 29 | methods = ['POST']) 30 | 31 | # When an ID is provided, accept GET, PUT, and DELETE 32 | app.add_url_rule('{}/{}/'.format(base, class_.__name__.lower()), 33 | view_func = view, 34 | methods = ['GET', 'PUT', 'DELETE']) 35 | 36 | -------------------------------------------------------------------------------- /Chapter11/demo_flask/person.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | import pkgutil 3 | 4 | 5 | connection = sqlite3.connect('demo.sqlite', detect_types = sqlite3.PARSE_DECLTYPES) 6 | connection.row_factory = sqlite3.Row 7 | connection.executescript(pkgutil.get_data('demo_flask', 'schema.sql').decode('utf8')) 8 | 9 | 10 | class Person: 11 | def __init__(self, id, first_name, last_name, age, member): 12 | self.id = id 13 | self.first_name = first_name 14 | self.last_name = last_name 15 | self.age = age 16 | self.member = member 17 | 18 | @staticmethod 19 | def list(): 20 | cursor = connection.cursor() 21 | cursor.execute('select * from person') 22 | rows = cursor.fetchmany() 23 | while rows: 24 | for row in rows: 25 | yield Person(row['id'], row['first_name'], row['last_name'], row['age'], bool(row['member'])) 26 | rows = cursor.fetchmany() 27 | 28 | @staticmethod 29 | def create(first_name, last_name, age, member = False): 30 | cursor = connection.cursor() 31 | cursor.execute('insert into person (first_name, last_name, age, member) values (?, ?, ?, ?)', 32 | [first_name, last_name, age, int(member)]) 33 | connection.commit() 34 | return Person(cursor.lastrowid, first_name, last_name, age, member) 35 | 36 | @staticmethod 37 | def load(id): 38 | cursor = connection.cursor() 39 | cursor.execute('select * from person where id = ? limit 1', [id]) 40 | row = cursor.fetchone() 41 | if row is None: 42 | raise KeyError(id) 43 | return Person(id, row['first_name'], row['last_name'], row['age'], bool(row['member'])) 44 | 45 | def store(self): 46 | cursor = connection.cursor() 47 | cursor.execute('update person set first_name = ?, last_name = ?, age = ?, member = ? WHERE id = ?', 48 | [self.first_name, self.last_name, self.age, int(self.member), self.id]) 49 | connection.commit() 50 | 51 | def delete(self): 52 | cursor = connection.cursor() 53 | cursor.execute('delete from person where id = ?', [self.id]) 54 | self.id = None 55 | connection.commit() 56 | 57 | def as_dict(self): 58 | return { 59 | 'id': self.id, 60 | 'first_name': self.first_name, 61 | 'last_name': self.last_name, 62 | 'age': self.age, 63 | 'member': self.member, 64 | } 65 | 66 | def __hash__(self): 67 | return hash(self.id) 68 | 69 | def __eq__(self, other): 70 | return self.id == other.id 71 | 72 | -------------------------------------------------------------------------------- /Chapter11/demo_flask/service.py: -------------------------------------------------------------------------------- 1 | import flask 2 | import json 3 | 4 | from .endpoint import Endpoint 5 | from .person import Person 6 | 7 | 8 | class PersonAPI(Endpoint): 9 | def post(self): 10 | first_name = flask.request.form['first_name'] 11 | last_name = flask.request.form['last_name'] 12 | age = int(flask.request.form['age']) 13 | try: 14 | member = flask.request.form['member'] == 'true' 15 | except KeyError: 16 | member = False 17 | 18 | person = Person.create(first_name, last_name, age, member) 19 | 20 | return json.dumps(person.as_dict()), 200, {'Content-Type': 'application/json'} 21 | 22 | def get(self, id): 23 | if id is None: 24 | return json.dumps([x.as_dict() for x in Person.list()]), 200, {'Content-Type': 'application/json'} 25 | 26 | try: 27 | person = Person.load(id) 28 | except KeyError: 29 | return json.dumps({'error': 'invalid id'}), 404, {'Content-Type': 'application/json'} 30 | 31 | return json.dumps(person.as_dict()), 200, {'Content-Type': 'application/json'} 32 | 33 | def put(self, id): 34 | try: 35 | person = Person.load(id) 36 | except KeyError: 37 | return json.dumps({'error': 'invalid id'}), 404, {'Content-Type': 'application/json'} 38 | 39 | def update(field_name, proc = (lambda x: x)): 40 | try: 41 | setattr(person, field_name, proc(flask.request.form[field_name])) 42 | except KeyError: 43 | pass 44 | 45 | update('first_name') 46 | update('last_name') 47 | update('age') 48 | update('member', (lambda x: x == 'true')) 49 | 50 | person.store() 51 | 52 | return json.dumps(person.as_dict()), 200, {'Content-Type': 'application/json'} 53 | 54 | def delete(self, id): 55 | try: 56 | person = Person.load(id) 57 | except KeyError: 58 | return json.dumps({'error': 'invalid id'}), 404, {'Content-Type': 'application/json'} 59 | 60 | person.delete() 61 | 62 | return json.dumps({'deleted': id}), 200, {'Content-Type': 'application/json'} 63 | 64 | app = flask.Flask('Flask Microservice Demo') 65 | PersonAPI.register(app) 66 | -------------------------------------------------------------------------------- /Chapter11/demo_flask/test.py: -------------------------------------------------------------------------------- 1 | from http.client import HTTPConnection 2 | from urllib.parse import urlencode 3 | from pprint import pprint 4 | import json 5 | 6 | def call(conn, method, path, body = None, content_type = 'application/x-www-form-urlencoded'): 7 | if isinstance(body, dict): 8 | body = urlencode(body) 9 | 10 | conn.request(method, path, body, {'Content-Type': content_type}) 11 | resp = conn.getresponse() 12 | print(resp.status, resp.reason) 13 | if resp.status != 200: 14 | return 15 | 16 | result = json.loads(resp.read().decode('utf8')) 17 | pprint(result) 18 | return result 19 | 20 | if __name__ == '__main__': 21 | conn = HTTPConnection('127.0.0.1', 5000) 22 | 23 | call(conn, 'GET', '/personapi') 24 | 25 | call(conn, 'POST', '/personapi', { 26 | 'first_name': 'Alice', 27 | 'last_name': 'Example', 28 | }) 29 | 30 | call(conn, 'GET', '/personapi') 31 | 32 | alice = call(conn, 'POST', '/personapi', { 33 | 'first_name': 'Alice', 34 | 'last_name': 'Example', 35 | 'age': (6 * 8) + (4 * 7) + 98 + 11 36 | })['id'] 37 | 38 | bob = call(conn, 'POST', '/personapi', { 39 | 'first_name': 'Bob', 40 | 'last_name': 'Example', 41 | 'age': 37 42 | })['id'] 43 | 44 | call(conn, 'GET', '/personapi') 45 | 46 | call(conn, 'PUT', '/personapi/{}'.format(alice), { 47 | 'age': 33, 48 | 'member': 'true' 49 | }) 50 | 51 | call(conn, 'GET', '/personapi') 52 | 53 | call(conn, 'DELETE', '/personapi/{}'.format(bob)) 54 | 55 | call(conn, 'GET', '/personapi') 56 | -------------------------------------------------------------------------------- /Chapter11/demo_nameko/person.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | import pkgutil 3 | 4 | 5 | connection = sqlite3.connect('demo.sqlite', detect_types = sqlite3.PARSE_DECLTYPES) 6 | connection.row_factory = sqlite3.Row 7 | connection.executescript(pkgutil.get_data('demo_nameko', 'schema.sql').decode('utf8')) 8 | 9 | 10 | class Person: 11 | def __init__(self, id, first_name, last_name, age, member): 12 | self.id = id 13 | self.first_name = first_name 14 | self.last_name = last_name 15 | self.age = age 16 | self.member = member 17 | 18 | @staticmethod 19 | def list(): 20 | cursor = connection.cursor() 21 | cursor.execute('select * from person') 22 | rows = cursor.fetchmany() 23 | while rows: 24 | for row in rows: 25 | yield Person(row['id'], row['first_name'], row['last_name'], row['age'], bool(row['member'])) 26 | rows = cursor.fetchmany() 27 | 28 | @staticmethod 29 | def create(first_name, last_name, age, member = False): 30 | cursor = connection.cursor() 31 | cursor.execute('insert into person (first_name, last_name, age, member) values (?, ?, ?, ?)', 32 | [first_name, last_name, age, int(member)]) 33 | connection.commit() 34 | return Person(cursor.lastrowid, first_name, last_name, age, member) 35 | 36 | @staticmethod 37 | def load(id): 38 | cursor = connection.cursor() 39 | cursor.execute('select * from person where id = ? limit 1', [id]) 40 | row = cursor.fetchone() 41 | if row is None: 42 | raise KeyError(id) 43 | return Person(id, row['first_name'], row['last_name'], row['age'], bool(row['member'])) 44 | 45 | def store(self): 46 | cursor = connection.cursor() 47 | cursor.execute('update person set first_name = ?, last_name = ?, age = ?, member = ? WHERE id = ?', 48 | [self.first_name, self.last_name, self.age, int(self.member), self.id]) 49 | connection.commit() 50 | 51 | def delete(self): 52 | cursor = connection.cursor() 53 | cursor.execute('delete from person where id = ?', [self.id]) 54 | self.id = None 55 | connection.commit() 56 | 57 | def as_dict(self): 58 | return { 59 | 'id': self.id, 60 | 'first_name': self.first_name, 61 | 'last_name': self.last_name, 62 | 'age': self.age, 63 | 'member': self.member, 64 | } 65 | 66 | def __hash__(self): 67 | return hash(self.id) 68 | 69 | def __eq__(self, other): 70 | return self.id == other.id 71 | 72 | -------------------------------------------------------------------------------- /Chapter11/demo_nameko/service.py: -------------------------------------------------------------------------------- 1 | from nameko.rpc import rpc 2 | 3 | from .person import Person 4 | 5 | 6 | class PersonAPI: 7 | name = 'person' 8 | 9 | @rpc 10 | def create(self, first_name, last_name, age, member = False): 11 | return Person.create(first_name, last_name, age, member).id 12 | 13 | @rpc 14 | def list(self): 15 | return [x.as_dict() for x in Person.list()] 16 | 17 | @rpc 18 | def get(self, id): 19 | return Person.load(id).as_dict() 20 | 21 | @rpc 22 | def set(self, id, **values): 23 | person = Person.load(id) 24 | 25 | for name, value in values.items(): 26 | setattr(person, name, value) 27 | 28 | person.store() 29 | 30 | @rpc 31 | def delete(self, id): 32 | Person.load(id).delete() 33 | 34 | -------------------------------------------------------------------------------- /Chapter11/demo_nameko/test.py: -------------------------------------------------------------------------------- 1 | from nameko.rpc import RpcProxy 2 | from nameko.timer import timer 3 | from pprint import pprint 4 | 5 | 6 | class TestService: 7 | name = 'test_person' 8 | 9 | person = RpcProxy('person') 10 | 11 | @timer(interval = 10) 12 | def test(self): 13 | pprint(self.person.list()) 14 | 15 | candide = self.person.create('Candide', 'Apples', 25) 16 | pprint(candide) 17 | 18 | pprint(self.person.list()) 19 | 20 | self.person.set(candide, age = 27) 21 | 22 | pprint(self.person.get(candide)) 23 | 24 | self.person.delete(candide) 25 | 26 | pprint(self.person.list()) 27 | -------------------------------------------------------------------------------- /Chapter12/demo_ctypes/__init__.py: -------------------------------------------------------------------------------- 1 | from .demo import * 2 | -------------------------------------------------------------------------------- /Chapter12/demo_ctypes/demo.py: -------------------------------------------------------------------------------- 1 | from .libc import printf, scanf, localtime, asctime 2 | from ctypes import c_int, create_string_buffer, byref, Structure 3 | 4 | def input_pair(): 5 | key = c_int() 6 | value = create_string_buffer(16) 7 | printf(b"[Input a pair as int:string] ") 8 | scanf(b"%i:%s", byref(key), byref(value)) 9 | return key, value.value 10 | 11 | def print_a_time(): 12 | timer = c_int(12345678) 13 | printf(asctime(localtime(byref(timer)))) 14 | 15 | -------------------------------------------------------------------------------- /Chapter12/demo_ctypes/libc.py: -------------------------------------------------------------------------------- 1 | import ctypes, ctypes.util 2 | 3 | def load_library(*alternates): 4 | for base_name in alternates: 5 | lib_name = ctypes.util.find_library(base_name) 6 | 7 | try: 8 | if lib_name: 9 | return ctypes.CDLL(lib_name) 10 | else: 11 | return ctypes.CDLL(base_name) 12 | except OSError: 13 | pass 14 | 15 | raise OSError('Unable to load any of: {}'.format(alternates)) 16 | 17 | _libc = load_library('c', 'msvcrt') 18 | 19 | class tm(ctypes.Structure): 20 | _fields_ = [ 21 | ('tm_sec', ctypes.c_int), 22 | ('tm_min', ctypes.c_int), 23 | ('tm_hour', ctypes.c_int), 24 | ('tm_mday', ctypes.c_int), 25 | ('tm_mon', ctypes.c_int), 26 | ('tm_year', ctypes.c_int), 27 | ('tm_wday', ctypes.c_int), 28 | ('tm_yday', ctypes.c_int), 29 | ('tm_isdst', ctypes.c_int), 30 | ] 31 | 32 | printf = _libc.printf 33 | 34 | scanf = _libc.scanf 35 | 36 | localtime = _libc.localtime 37 | localtime.argtypes = [ctypes.POINTER(ctypes.c_int)] 38 | localtime.restype = ctypes.POINTER(tm) 39 | 40 | asctime = _libc.asctime 41 | asctime.argtypes = [ctypes.POINTER(tm)] 42 | asctime.restype = ctypes.c_char_p 43 | -------------------------------------------------------------------------------- /Chapter12/demo_cython/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from Cython.Build import cythonize 3 | 4 | setup( 5 | ext_modules = cythonize('statistics.pyx') 6 | ) 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Daniel Arbuckle's Mastering Python 5 | 6 | This is the code repository for [Daniel Arbuckle’s Mastering Python](https://www.packtpub.com/application-development/daniel-arbuckle-mastering-python?utm_source=github&utm_medium=repository&utm_campaign=9781787283695), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the book from start to finish. 7 | 8 | ## About the Book 9 | Daniel Arbuckle's Mastering Python covers the basics of operating in a Python development environment, before moving on to more advanced topics. Daniel presents you with real-world solutions to Python 3.6 and advanced-level concepts, such as reactive programming, microservices, ctypes, and Cython tools. 10 | 11 | You don't need to be familiar with the Python language to use this book, as Daniel starts with a Python primer. Throughout, Daniel highlights the major aspects of managing your Python development environment, shows you how to handle parallel computation, and helps you to master asynchronous I/O with Python 3.6 to improve performance. Finally, Daniel will teach you the secrets of metaprogramming and unit testing in Python, helping you acquire the perfect skillset to be a Python expert. 12 | 13 | Daniel will get you up to speed on everything from basic programming practices to high-end tools and techniques, things that will help set you apart as a successful Python programmer. 14 | 15 | ## Instructions and Navigation 16 | All of the code is organized into folders. Each folder starts with a number followed by the application name. For example, Chapter02. 17 | 18 | 19 | 20 | The code will look like the following: 21 | ``` 22 | def example_function(name, radius): 23 | area = math.pi * radius ** 2 24 | return "The area of {} is {}" .format(name, area) 25 | ``` 26 | 27 | You will need Ubuntu 16.04 and Python (version 3.6). You can also run the code examples on Windows and macOS. 28 | You may opt to use VirtualBox as well to test the code in the book. 29 | 30 | ## Related Products 31 | 32 | * [Mastering Python Networking](https://www.packtpub.com/networking-and-servers/mastering-python-networking?utm_source=github&utm_medium=repository&utm_campaign=9781784397005) 33 | 34 | * [Mastering Python Forensics](https://www.packtpub.com/networking-and-servers/mastering-python-forensics?utm_source=github&utm_medium=repository&utm_campaign=9781783988044) 35 | 36 | * [Mastering Python](https://www.packtpub.com/application-development/mastering-python?utm_source=github&utm_medium=repository&utm_campaign=9781785289729) 37 | 38 | ### Suggestions and Feedback 39 | [Click here](https://docs.google.com/forms/d/e/1FAIpQLSe5qwunkGf6PUvzPirPDtuy1Du5Rlzew23UBp2S-P3wB-GcwQ/viewform) if you have any feedback or suggestions. 40 | ### Download a free PDF 41 | 42 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
43 |

https://packt.link/free-ebook/9781787283695

--------------------------------------------------------------------------------