├── .gitignore ├── .idea ├── furtherpython3.iml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── LICENSE ├── README.md ├── chapter11 ├── HelloWorldGame.py └── MousePlayApp.py ├── chapter12 ├── StarshipMeteors.py ├── meteor.png └── starship.png ├── chapter14 ├── calculator.py ├── exercises │ ├── accounts-app.py │ ├── fintech │ │ ├── __init__.py │ │ └── accounts.py │ └── test_CurrentAccount.py ├── external_module │ └── __init__.py ├── test.py ├── test_calculator.py └── testing-functions.py ├── chapter15 ├── exercises │ └── deck_of_cards.py ├── external_module │ └── __init__.py ├── mock_test1.py ├── mock_test2.py ├── mock_test3.py ├── mock_test4.py ├── mock_test5.py ├── mock_test6.py ├── mock_test7.py ├── people.py └── pytest-mock1.py ├── chapter17 ├── directories1.py ├── exercise │ ├── create_file_with_date.py │ └── load_date_from_file.py ├── files1.py ├── files2.py ├── files3.py ├── files4.py ├── files5.py ├── my-new-file.txt ├── myfile.txt ├── paths-app.py ├── rand-file-acces.py ├── read-file-using-with.py ├── tempfiles1.py ├── text.txt ├── textfile1.txt ├── textfile2.txt └── textfileexample.py ├── chapter18 ├── binary_streams.py ├── myfile.dat ├── myfile.txt ├── raw_io_example.py ├── sockets.py ├── starship.png ├── stdinout_examples.py ├── streams_options.py └── text_streams.py ├── chapter19 ├── __init__.py ├── csvdictexample.py ├── csvexample.py ├── exercises │ ├── __init__.py │ ├── fintech │ │ ├── __init__.py │ │ └── accounts.py │ └── write_accounts_file.py ├── names.csv └── sample.csv ├── chapter2 └── rgb_colours.py ├── chapter20 ├── exercises │ ├── __init__.py │ ├── accounts.xlsx │ ├── fintech │ │ ├── __init__.py │ │ └── accounts.py │ └── write_accounts_file.py ├── readExcelExample.py ├── sample.xlsx ├── sample2.xlsx └── writeExcelExample.py ├── chapter21 ├── exercises │ └── regex_solutions.py └── regex_examples.py ├── chapter24 ├── connect_example.py ├── create5.py ├── delete4.py ├── exercise │ ├── create_tables.py │ ├── fintech │ │ ├── __init__.py │ │ └── accounts.py │ └── write_account_info.py ├── insert2.py ├── mongo_examples.py ├── query1.py ├── query2.py └── update3.py ├── chapter26 ├── exercises │ ├── accounts-app.py │ ├── accounts.logging.config.yaml │ └── fintech │ │ ├── __init__.py │ │ └── accounts.py ├── logging.config.yaml ├── logging_example.py ├── logging_example1.py ├── logging_example10.py ├── logging_example11.py ├── logging_example2.py ├── logging_example3.py ├── logging_example4.py ├── logging_example5.py ├── logging_example6.py ├── logging_example7.py ├── logging_example8.py ├── logging_example9.py └── printer_lib.py ├── chapter28 ├── exercises │ └── printer_threading_app.py ├── threads.py ├── threads1.py ├── threads2.py ├── threads3.py ├── threads4.py ├── threads5.py ├── threads6.py ├── threads7.py └── timer_example.py ├── chapter29 ├── exercises │ └── multiprocessing_factorial.py ├── multiprocessing1.py ├── multiprocessing2.py ├── multiprocessing3.py ├── multiprocessing4.py ├── multiprocessing5.py ├── multiprocessing6.py └── multiprocessing7.py ├── chapter3 ├── coloured_shapes.py ├── exercises │ └── draw-hexagons.py ├── sample-window1.py ├── sample-window2.py ├── sample-window3.py └── sphere_example.py ├── chapter30 ├── barriers-app.py ├── barriers-app2.py ├── cond-app.py ├── events-app.py ├── events-app2.py ├── exercises │ ├── stack │ │ ├── Stack.py │ │ └── __init__.py │ └── stack_multithreaded_app.py ├── locks-app.py ├── queue-example.py └── semaphore-app.py ├── chapter31 ├── exercises │ └── factorial_future.py ├── future1.py ├── future2.py ├── future3.py ├── future4.py ├── future5.py ├── future6.py └── future7.py ├── chapter32 ├── asyncioapp1.py ├── asyncioapp2.py ├── asyncioapp3.py ├── asyncioapp4.py └── exercises │ └── async_factorial.py ├── chapter34 ├── reactive1.py ├── reactive2.py ├── reactive3a.py ├── reactive3b.py └── reactive4.py ├── chapter35 ├── exercises │ └── stocks.py ├── reactive_ops1.py ├── reactive_ops2.py ├── reactive_ops3.py ├── reactive_ops4.py └── reactive_ops5.py ├── chapter37 ├── BasicTCPIPSocketServer.py ├── BroadcastClient.py ├── BroadcastServer.py ├── MyHttpServer.py ├── MyTCPHandler.py ├── TCPIPSocketClient.py └── exercises │ ├── SimpleClient.py │ └── SimpleServer.py ├── chapter38 ├── hello_flask_world.py └── hello_flask_world2.py ├── chapter39 ├── bookshop_service1.py ├── bookshop_service2.py ├── bookshop_service3.py └── image_service4.py ├── chapter4 ├── circles-picture.py ├── exercises │ └── fractal_trees.py ├── mandelbrot.py ├── snowflake.py └── snowflake_koch.py ├── chapter5 ├── bar_chart8a.py ├── bar_chart8b.py ├── bar_chart8c.py ├── bar_chart8d.py ├── bar_chart8e.py ├── configuringaplot4.py ├── figure_example7.py ├── line_graph3.py ├── matplotlib2.py ├── pie_chart5.py ├── pie_chart_5a.py ├── scatter_plot6.py ├── scatter_plot_trendline6.py ├── simple_plot1.py ├── sub_plots9.py └── three-d-plot10.py ├── chapter7 ├── FrameAndPanelApp.py ├── SampleDCApp.py └── SimpleHelloWorldApp.py ├── chapter8 ├── HelloNamedApp.py ├── SimpleEventHandlerApp.py └── exercises │ ├── BirthdayGUIApp.py │ └── TicTacToeGuiApp.py ├── chapter9 ├── PyDraw.py ├── load.gif ├── new.gif └── save.gif ├── django-server └── mysite │ ├── db.sqlite3 │ ├── manage.py │ ├── mysite │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py │ └── polls │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ └── __init__.py │ ├── models.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── graphql ├── main.py ├── model.py └── schema.graphql ├── messaging ├── publisher.py └── receiver.py └── profiling ├── get_pay.log ├── memory_usage1.py ├── memory_usage2.py ├── memory_usage3.py ├── memory_usage4.py ├── profile_example1.py ├── profile_example2.py ├── timings1.py └── timings2.py /.gitignore: -------------------------------------------------------------------------------- 1 | /venv/bin/ 2 | /venv/lib/python3.8/site-packages/ 3 | /venv/pyvenv.cfg 4 | /.idea/shelf/ 5 | -------------------------------------------------------------------------------- /.idea/furtherpython3.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced Guide to Python3 Programming 2 | Code Repository for Advanced Guide to Python 3 Programming 3 | -------------------------------------------------------------------------------- /chapter11/HelloWorldGame.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | 4 | def main(): 5 | print('Starting Game') 6 | 7 | print('Initialising PyGame') 8 | pygame.init() # Required by every PyGame application 9 | 10 | print('Initialising HelloWorldGame') 11 | pygame.display.set_mode((200, 100)) # Note that this takes a tuple specifying the width and highet of the display 12 | pygame.display.set_caption('Hello World') 13 | print('Update display') 14 | pygame.display.update() 15 | 16 | print('Starting main Game Playing Loop') 17 | running = True 18 | while running: 19 | for event in pygame.event.get(): 20 | # There are lots of events generated by we are only interested on the Quit event 21 | if event.type == pygame.QUIT: 22 | print('Received Quit Event:', event) 23 | running = False 24 | 25 | print('Game Over') 26 | # Now tidy up and quit Python 27 | pygame.quit() 28 | 29 | 30 | if __name__ == '__main__': 31 | main() 32 | -------------------------------------------------------------------------------- /chapter11/MousePlayApp.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | FRAME_REFRESH_RATE = 30 4 | BLUE = (0, 0, 255) 5 | BACKGROUND = (255, 255, 255) 6 | WIDTH = 10 7 | HEIGHT = 10 8 | 9 | 10 | def main(): 11 | print('Initialising PyGame') 12 | pygame.init() # Required by every PyGame application 13 | 14 | print('Initialising Box Game') 15 | display_surface = pygame.display.set_mode((400, 300)) 16 | pygame.display.set_caption('Box Game') 17 | print('Update display') 18 | pygame.display.update() 19 | print('Setup the Clock') 20 | clock = pygame.time.Clock() 21 | # Clear the screen of current contents 22 | display_surface.fill(BACKGROUND) 23 | 24 | print('Starting main Game Playing Loop') 25 | running = True 26 | while running: 27 | for event in pygame.event.get(): 28 | # There are lots of events generated by we are only interested on the Quit event 29 | if event.type == pygame.QUIT: 30 | print('Received Quit Event:', event) 31 | running = False 32 | elif event.type == pygame.MOUSEBUTTONDOWN: 33 | print('Received Mouse Event', event) 34 | x, y = event.pos 35 | pygame.draw.rect(display_surface, BLUE, [x, y, WIDTH, HEIGHT]) 36 | 37 | # Update the display 38 | pygame.display.update() 39 | 40 | # Defines the frame rate. The number is number of frames per second 41 | # Should be called once per frame (but only once) 42 | clock.tick(FRAME_REFRESH_RATE) 43 | 44 | print('Game Over') 45 | # Now tidy up and quit Python 46 | pygame.quit() 47 | 48 | 49 | if __name__ == '__main__': 50 | main() 51 | -------------------------------------------------------------------------------- /chapter12/meteor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter12/meteor.png -------------------------------------------------------------------------------- /chapter12/starship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter12/starship.png -------------------------------------------------------------------------------- /chapter14/calculator.py: -------------------------------------------------------------------------------- 1 | class Calculator: 2 | def __init__(self): 3 | self.current = 0 4 | self.total = 0 5 | 6 | def set(self, value): 7 | self.current = value 8 | 9 | def add(self): 10 | self.total += self.current 11 | 12 | def sub(self): 13 | self.total -= self.current 14 | 15 | def total(self): 16 | return self.total -------------------------------------------------------------------------------- /chapter14/exercises/accounts-app.py: -------------------------------------------------------------------------------- 1 | import fintech.accounts as accounts 2 | 3 | acc1 = accounts.CurrentAccount('123', 'John', 10.05, 100.0) 4 | acc2 = accounts.DepositAccount('345', 'John', 23.55, 0.5) 5 | acc3 = accounts.InvestmentAccount('567', 'Phoebe', 12.45, 'high risk') 6 | 7 | print(acc1) 8 | print(acc2) 9 | print(acc3) 10 | 11 | acc1.deposit(23.45) 12 | acc1.withdraw(12.33) 13 | print('balance:', acc1.balance) 14 | 15 | print('Number of Account instances created:', accounts.Account.instance_count) 16 | 17 | try: 18 | print('balance:', acc1.balance) 19 | acc1.withdraw(300.00) 20 | print('balance:', acc1.balance) 21 | except accounts.BalanceError as e: 22 | print('Handling Exception') 23 | print(e) 24 | 25 | with accounts.CurrentAccount ('891', 'Adam', 5.0, 50.0) as acc: 26 | acc.deposit(23.0) 27 | acc.withdraw(12.50) 28 | print(acc.balance) 29 | 30 | print('acc1.branch:', acc1.branch) 31 | 32 | for transaction in acc1: 33 | print(transaction) 34 | 35 | acc1.deposit(-1.0) -------------------------------------------------------------------------------- /chapter14/exercises/fintech/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter14/exercises/fintech/__init__.py -------------------------------------------------------------------------------- /chapter14/exercises/fintech/accounts.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta 2 | from timeit import default_timer 3 | 4 | 5 | # Accounts module 6 | 7 | 8 | def timer(func): 9 | def inner(self, value): 10 | print('calling ', func.__name__, 'on', self, 'with', value) 11 | start = default_timer() 12 | func(self, value) 13 | end = default_timer() 14 | print('returned from ', func.__name__, 'it took', end - start, 'seconds') 15 | 16 | return inner 17 | 18 | 19 | class BalanceError(Exception): 20 | """ The Balance will be invalid """ 21 | 22 | def __init__(self, account): 23 | self.account = account 24 | 25 | 26 | class AmountError(Exception): 27 | 28 | def __init__(self, account, msg): 29 | self.account = account 30 | self.message = msg 31 | 32 | def __str__(self): 33 | return 'AmountError (' + self.message + ') on ' + str(self.account) 34 | 35 | 36 | class Transaction: 37 | """ A Class used to represent an individual Transaction """ 38 | def __init__(self, action, amount): 39 | self.action = action 40 | self.amount = amount 41 | 42 | def __str__(self): 43 | return 'Transaction[' + self.action + ': ' + str(self.amount) + ']' 44 | 45 | 46 | class Account(metaclass=ABCMeta): 47 | """" A class used to represent a type of account """ 48 | 49 | instance_count = 0 50 | 51 | @classmethod 52 | def increment_instance_count(cls): 53 | print('Creating new Account') 54 | cls.instance_count += 1 55 | 56 | def __init__(self, account_number, account_holder, opening_balance, account_type): 57 | Account.increment_instance_count() 58 | self.account_number = account_number 59 | self.account_holder = account_holder 60 | self._balance = opening_balance 61 | self.type = account_type 62 | # Note need to initialise the history list before you try to add a Transaction 63 | self.history = [] 64 | self._add_deposit_transaction(opening_balance) 65 | 66 | def __enter__(self): 67 | print('__enter__') 68 | return self 69 | 70 | def __exit__(self, *args): 71 | print('__exit__:', args) 72 | return True 73 | 74 | # Method called if attribute is unknown 75 | def __getattr__(self, attribute): 76 | print('__getattr__: unknown attribute accessed - ', attribute) 77 | return -1 78 | 79 | # Return the transaction hsitory as the iterable object for an Account 80 | # and any subclass of Account 81 | def __iter__(self): 82 | return iter(self.history) 83 | 84 | # Provide internal support for adding transactions 85 | # Note by convention methods starting with an '_' shoudl not be called 86 | # by clients of this class 87 | def _add_transaction(self, transaction): 88 | self.history.append(transaction) 89 | 90 | # These are convenience methods to make it easier to 91 | # record a deposit or withdrawal. 92 | def _add_deposit_transaction(self, amount): 93 | self._add_transaction(Transaction('deposit', amount)) 94 | 95 | def _add_withdraw_transaction(self, amount): 96 | self._add_transaction(Transaction('withdraw', amount)) 97 | 98 | @timer 99 | def deposit(self, amount): 100 | if amount < 0: 101 | print('You cannot deposit negative amounts') 102 | raise AmountError(account=self, msg='Cannot deposit negative amounts') 103 | else: 104 | self._balance += amount 105 | self._add_deposit_transaction(amount) 106 | 107 | @timer 108 | def withdraw(self, amount): 109 | if amount < 0: 110 | print('You cannot withdraw negative amounts') 111 | raise AmountError(self, 'Cannot withdraw negative amounts') 112 | else: 113 | self._balance -= amount 114 | self._add_withdraw_transaction(amount) 115 | 116 | @property 117 | def balance(self): 118 | """ Provides the current balance """ 119 | return self._balance 120 | 121 | def __str__(self): 122 | return 'Account[' + self.account_number + '] - ' + \ 123 | self.account_holder + ', ' + self.type + ' account = ' + str(self.balance) 124 | 125 | 126 | class CurrentAccount(Account): 127 | 128 | def __init__(self, account_number, account_holder, opening_balance, overdraft_limit): 129 | super().__init__(account_number, account_holder, opening_balance, 'current') 130 | self.overdraft_limit = -overdraft_limit 131 | 132 | @timer 133 | def withdraw(self, amount): 134 | if amount < 0: 135 | print('You cannot withdraw negative amounts') 136 | raise AmountError(self, 'Cannot withdraw negative amounts') 137 | elif self.balance - amount < self.overdraft_limit: 138 | print('Withdrawal would exceed your overdraft limit') 139 | raise BalanceError(self) 140 | else: 141 | self._balance -= amount 142 | self._add_withdraw_transaction(amount) 143 | 144 | def __str__(self): 145 | return super().__str__() + 'overdraft limit: ' + str(self.overdraft_limit) 146 | 147 | 148 | class DepositAccount(Account): 149 | 150 | def __init__(self, account_number, account_holder, opening_balance, interest_rate): 151 | super().__init__(account_number, account_holder, opening_balance, 'deposit') 152 | self.interest_rate = interest_rate 153 | 154 | def __str__(self): 155 | return super().__str__() + 'interest rate: ' + str(self.interest_rate) 156 | 157 | 158 | class InvestmentAccount(Account): 159 | def __init__(self, account_number, account_holder, opening_balance, investment_type): 160 | super().__init__(account_number, account_holder, opening_balance, 'investment') 161 | self.investment_type = investment_type 162 | 163 | def __str__(self): 164 | return super().__str__() + ', type: ' + self.type 165 | -------------------------------------------------------------------------------- /chapter14/exercises/test_CurrentAccount.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import fintech.accounts as accounts 3 | 4 | 5 | @pytest.fixture 6 | def current_account(): 7 | """Returns a CurrentAccount instance""" 8 | print('CurrentAccount fixture') 9 | return accounts.CurrentAccount('123', 'John', 0.0, 100.0) 10 | 11 | 12 | def test_opening_balance(current_account): 13 | assert current_account.balance == 0.0 14 | 15 | 16 | def test_alternative_opening_balance(): 17 | current_account = accounts.CurrentAccount('123', 'John', 10.0, 100.0) 18 | assert current_account.balance == 10.00 19 | 20 | 21 | def test_negative_opening_balance(): 22 | current_account = accounts.CurrentAccount('123', 'John', -10.0, 100.0) 23 | assert current_account.balance == -10.00 24 | 25 | 26 | def test_current_account_attributes(current_account): 27 | assert current_account.account_holder == 'John' 28 | assert current_account.account_number == '123' 29 | assert current_account.overdraft_limit == -100.0 30 | assert current_account.type == 'current' 31 | 32 | 33 | def test_deposit(current_account): 34 | current_account.deposit(5.0) 35 | assert current_account.balance == 5.0 36 | 37 | 38 | def test_deposit_twice(current_account): 39 | current_account.deposit(5.0) 40 | current_account.deposit(5.0) 41 | assert current_account.balance == 10.0 42 | 43 | 44 | def test_deposit_negative_amount(current_account): 45 | with pytest.raises(accounts.AmountError): 46 | current_account.deposit(-10.00) 47 | 48 | 49 | def test_deposit_zero(current_account): 50 | current_account.deposit(0.00) 51 | assert current_account.balance == 0.0 52 | 53 | 54 | def test_withdraw(current_account): 55 | current_account.withdraw(5.0) 56 | assert current_account.balance == -5.0 57 | 58 | 59 | def test_withdraw_negative_amount(current_account): 60 | with pytest.raises(accounts.AmountError): 61 | current_account.withdraw(-5.0) 62 | 63 | 64 | def test_withdraw_zero(current_account): 65 | current_account.withdraw(0.0) 66 | assert current_account.balance == 0.0 67 | 68 | 69 | def test_withdraw_twice(current_account): 70 | current_account.withdraw(5.0) 71 | current_account.withdraw(5.0) 72 | assert current_account.balance == -10.0 73 | 74 | 75 | def test_deposit_and_withdraw(current_account): 76 | current_account.deposit(10.0) 77 | current_account.withdraw(5.0) 78 | assert current_account.balance == 5.0 79 | 80 | 81 | def test_withdraw_and_deposit(current_account): 82 | current_account.withdraw(5.0) 83 | current_account.deposit(10.0) 84 | assert current_account.balance == 5.0 85 | 86 | 87 | def test_withdraw_above_overdraftlimit(current_account): 88 | with pytest.raises(accounts.BalanceError): 89 | current_account.withdraw(200.0) 90 | 91 | 92 | def test_initial_transaction_history_length(current_account): 93 | assert len(current_account.history) == 1 94 | 95 | 96 | def test_initial_transaction_details(current_account): 97 | transaction = current_account.history[0] 98 | assert transaction.action == 'deposit' 99 | assert transaction.amount == 0.0 100 | 101 | 102 | def test_deposit_transaction_history(current_account): 103 | current_account.deposit(10.0) 104 | current_account.deposit(5.0) 105 | assert len(current_account.history) == 3 106 | transaction1 = current_account.history[1] 107 | transaction2 = current_account.history[2] 108 | assert transaction1.action == 'deposit' 109 | assert transaction1.amount == 10.0 110 | assert transaction2.action == 'deposit' 111 | assert transaction2.amount == 5.0 112 | 113 | 114 | def test_withdrawal_transaction_history(current_account): 115 | current_account.withdraw(10.0) 116 | current_account.withdraw(5.0) 117 | assert len(current_account.history) == 3 118 | transaction1 = current_account.history[1] 119 | transaction2 = current_account.history[2] 120 | assert transaction1.action == 'withdraw' 121 | assert transaction1.amount == 10.0 122 | assert transaction2.action == 'withdraw' 123 | assert transaction2.amount == 5.0 124 | 125 | 126 | def test_withdrawal_and_deposit_transaction_history(current_account): 127 | current_account.deposit(10.0) 128 | current_account.withdraw(5.0) 129 | assert len(current_account.history) == 3 130 | transaction1 = current_account.history[1] 131 | transaction2 = current_account.history[2] 132 | assert transaction1.action == 'deposit' 133 | assert transaction1.amount == 10.0 134 | assert transaction2.action == 'withdraw' 135 | assert transaction2.amount == 5.0 136 | -------------------------------------------------------------------------------- /chapter14/external_module/__init__.py: -------------------------------------------------------------------------------- 1 | def api_call(): 2 | return '' -------------------------------------------------------------------------------- /chapter14/test.py: -------------------------------------------------------------------------------- 1 | from utils.functions import * 2 | f1() 3 | 4 | from utils.classes import * 5 | p = Processor() 6 | -------------------------------------------------------------------------------- /chapter14/test_calculator.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from calculator import Calculator 3 | 4 | 5 | @pytest.fixture(scope='session', autouse=True) 6 | def session_scope_fixture(): 7 | print('session_scope_fixture') 8 | 9 | 10 | @pytest.fixture(scope='module', autouse=True) 11 | def module_scope_fixture(): 12 | print('module_scope_fixture') 13 | 14 | 15 | @pytest.fixture(scope='class', autouse=True) 16 | def class_scope_fixture(): 17 | print('class_scope_fixture') 18 | 19 | 20 | @pytest.fixture 21 | def calculator(): 22 | """ Returns a Calculator instance """ 23 | print('calculator fixture') 24 | return Calculator() 25 | 26 | 27 | def test_initial_value(calculator): 28 | assert calculator.total == 0 29 | 30 | 31 | def test_add_one(calculator): 32 | calculator.set(1) 33 | calculator.add() 34 | assert calculator.total == 1 35 | 36 | 37 | def test_subtract_one(calculator): 38 | calculator.set(1) 39 | calculator.sub() 40 | assert calculator.total == -1 41 | 42 | 43 | def test_add_one_and_one(calculator): 44 | calculator.set(1) 45 | calculator.add() 46 | calculator.set(1) 47 | calculator.add() 48 | assert calculator.total == 2 49 | 50 | 51 | @pytest.mark.parametrize('input1,input2,expected', [ 52 | (3, 1, 4), 53 | (3, 2, 5), 54 | ]) 55 | def test_calculator_add_operation(calculator, input1, input2, expected): 56 | calculator.set(input1) 57 | calculator.add() 58 | calculator.set(input2) 59 | calculator.add() 60 | assert calculator.total == expected 61 | 62 | 63 | @pytest.mark.skip(reason='not implemented yet') 64 | def test_calculator_multiply(calculator): 65 | calculator.multiply(2, 3) 66 | assert calculator.total == 6 67 | -------------------------------------------------------------------------------- /chapter14/testing-functions.py: -------------------------------------------------------------------------------- 1 | def increment(x): 2 | return x + 1 3 | 4 | 5 | def test_increment_integer_3(): 6 | assert increment(3) == 4 7 | -------------------------------------------------------------------------------- /chapter15/exercises/deck_of_cards.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def create_suite(suite): 4 | return [ (i, suite) for i in range(1, 14)] 5 | 6 | def pick_a_card(deck): 7 | print('You picked') 8 | position = random.randint(0, 52) 9 | print(deck[position][0], "of", deck[position][1]) 10 | return (deck[position]) 11 | 12 | # Set up the data 13 | hearts = create_suite('hearts') 14 | spades = create_suite('spades') 15 | diamonds = create_suite('diamonds') 16 | clubs = create_suite('clubs') 17 | 18 | # Make the deck of cards 19 | deck = hearts + spades + diamonds + clubs 20 | 21 | # Randomly pick from the deck of cards 22 | card = pick_a_card(deck) 23 | -------------------------------------------------------------------------------- /chapter15/external_module/__init__.py: -------------------------------------------------------------------------------- 1 | def api_call(): 2 | return '' 3 | 4 | def api_call_with_param(param): 5 | return param + 'done' -------------------------------------------------------------------------------- /chapter15/mock_test1.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import * 2 | 3 | from unittest import TestCase 4 | from unittest import main 5 | 6 | class SomeClass(): 7 | 8 | def _hidden_method(self): 9 | return 0 10 | 11 | def public_method(self, x): 12 | return self._hidden_method() + x 13 | 14 | class test_SomeClass_public_interface(TestCase): 15 | 16 | def test_public_method(self): 17 | test_object = SomeClass() 18 | # Set up canned response on mock method 19 | test_object._hidden_method = MagicMock(name = 'hidden_method') 20 | test_object._hidden_method.return_value = 10 21 | # Test the object 22 | result = test_object.public_method(5) 23 | self.assertEqual(15, result, 'return value from public_method incorrect') 24 | 25 | if __name__ == '__main__': 26 | main() -------------------------------------------------------------------------------- /chapter15/mock_test2.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import * 2 | 3 | from unittest import TestCase 4 | from unittest import main 5 | 6 | class SomeClass(): 7 | 8 | def _hidden_method(self): 9 | return 0 10 | 11 | def public_method(self, x): 12 | return self._hidden_method() + x 13 | 14 | class test_SomeClass_public_interface(TestCase): 15 | 16 | @patch.object(SomeClass, '_hidden_method') 17 | def test_public_method(self, mock_method): 18 | # Set up canned response 19 | mock_method.return_value = 10 20 | # Create object to be tested 21 | test_object = SomeClass() 22 | result = test_object.public_method(5) 23 | self.assertEqual(15, result, 'return value from public_method incorrect') 24 | 25 | if __name__ == '__main__': 26 | main() 27 | -------------------------------------------------------------------------------- /chapter15/mock_test3.py: -------------------------------------------------------------------------------- 1 | import external_module 2 | 3 | from unittest.mock import * 4 | 5 | from unittest import TestCase 6 | from unittest import main 7 | import json 8 | 9 | 10 | def some_func(): 11 | # Calls out to external API - which we want to mock 12 | response = external_module.api_call() 13 | return response 14 | 15 | 16 | def some_func_with_param(param): 17 | # call out to api module 18 | response = external_module.api_call_with_param(param) 19 | return response 20 | 21 | 22 | class test_some_func_calling_api(TestCase): 23 | 24 | @patch('external_module.api_call') 25 | def test_some_func(self, mock_api_call): 26 | # Sets up mock version of api_call 27 | mock_api_call.return_value = MagicMock(status_code=200, response=json.dumps({'key': 'value'})) 28 | # Calls some_func() that calls the (mock) api_call() function 29 | result = some_func() 30 | # Check that the result returned from some_func() is what was expected 31 | self.assertEqual(result.status_code, 200, "returned status code is not 200") 32 | self.assertEqual(result.response, '{"key": "value"}', "response JSON incorrect") 33 | 34 | @patch('external_module.api_call_with_param') 35 | def test_some_func_with_param(self, mock_api_call): 36 | # Sets up mock version of api_call 37 | mock_api_call.return_value = MagicMock(status_code=200, response=json.dumps({'age': '23'})) 38 | result = some_func_with_param('Phoebe') 39 | # Check that the result returned from some_func() is what was expected 40 | self.assertEqual(result.response, '{age": "23"}', 'JSON result incorrect') 41 | # Verify that the mock_api_call was called with the correct params 42 | mock_api_call.api_call_with_param.assert_called_with('Phoebe') 43 | 44 | 45 | if __name__ == '__main__': 46 | main() 47 | -------------------------------------------------------------------------------- /chapter15/mock_test4.py: -------------------------------------------------------------------------------- 1 | import people 2 | 3 | from unittest.mock import * 4 | from unittest import TestCase 5 | from unittest import main 6 | 7 | 8 | class MyTest(TestCase): 9 | 10 | @patch('people.Person') 11 | def test_one(self, MockPerson): 12 | self.assertIs(people.Person, MockPerson) 13 | instance = MockPerson.return_value 14 | instance.calculate_pay.return_value = 250.0 15 | payroll = people.Payroll() 16 | result = payroll.generate_payslip(instance) 17 | self.assertEqual('You earned 250.0', result, 'payslip incorrect') 18 | -------------------------------------------------------------------------------- /chapter15/mock_test5.py: -------------------------------------------------------------------------------- 1 | import people 2 | 3 | from unittest.mock import * 4 | from unittest import TestCase 5 | 6 | 7 | class MyTest(TestCase): 8 | 9 | @patch('people.Person') 10 | def test_one(self, MockPerson): 11 | self.assertIs(people.Person, MockPerson) 12 | instance = MockPerson.return_value 13 | instance.age = 24 14 | instance.name = 'Adam' 15 | self.assertEqual(24, instance.age, 'age incorrect') 16 | self.assertEqual('Adam', instance.name, 'name incorrect') 17 | instance.address = MagicMock(name='Address') 18 | -------------------------------------------------------------------------------- /chapter15/mock_test6.py: -------------------------------------------------------------------------------- 1 | import people 2 | 3 | from unittest.mock import * 4 | from unittest import TestCase 5 | from unittest import main 6 | 7 | 8 | @patch('people.Person') 9 | class MyTest(TestCase): 10 | 11 | def test_one(self, MockPerson): 12 | self.assertIs(people.Person, MockPerson) 13 | 14 | def test_two(self, MockSomeClass): 15 | self.assertIs(people.Person, MockSomeClass) 16 | 17 | def do_something(self): 18 | return 'something' 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /chapter15/mock_test7.py: -------------------------------------------------------------------------------- 1 | import people 2 | 3 | from unittest.mock import * 4 | from unittest import TestCase 5 | from unittest import main 6 | 7 | 8 | class MyTest(TestCase): 9 | 10 | def test_one(self): 11 | with patch('people.Person') as MockPerson: 12 | self.assertIs(people.Person, MockPerson) 13 | instance = MockPerson.return_value 14 | instance.calculate_pay.return_value = 250.0 15 | payroll = people.Payroll() 16 | result = payroll.generate_payslip(instance) 17 | self.assertEqual('You earned 250.0', result, 'payslip incorrect') -------------------------------------------------------------------------------- /chapter15/people.py: -------------------------------------------------------------------------------- 1 | class Person: 2 | 3 | def calculate_pay(self): 4 | return 0.0 5 | 6 | 7 | class Payroll: 8 | 9 | def generate_payslip(self, person): 10 | return 'You earned ' + str(person.calculate_pay()) 11 | -------------------------------------------------------------------------------- /chapter15/pytest-mock1.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest_mock import mocker 3 | 4 | import people 5 | 6 | 7 | @pytest.fixture 8 | def payroll(): 9 | """ Returns a Payroll instance """ 10 | print('Payroll fixture') 11 | return people.Payroll() 12 | 13 | 14 | def test_payroll(mocker, payroll): 15 | # Create a mock version of Person with default return result 16 | mocker.patch.object(people.Person, 'calculate_pay') 17 | people.Person.calculate_pay.return_value = 250.0 18 | result = payroll.generate_payslip(people.Person()) 19 | # Verify that mock method was called 20 | people.Person.calculate_pay.assert_called() 21 | # Verify that the result from payroll was correct 22 | assert 'You earned 250.0' == result 23 | -------------------------------------------------------------------------------- /chapter17/directories1.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | print('os.getcwd(:', os.getcwd()) 4 | print('List contents of directory') 5 | print(os.listdir()) 6 | 7 | print('Create mydir') 8 | os.mkdir('mydir') 9 | print('List the updated contents of directory') 10 | print(os.listdir()) 11 | 12 | print('Change into mydir directory') 13 | os.chdir('mydir') 14 | print('os.getcwd(:', os.getcwd()) 15 | 16 | print('Change back to parent directory') 17 | os.chdir('..') 18 | print('os.getcwd(:', os.getcwd()) 19 | 20 | print('Remove mydir directory') 21 | os.rmdir('mydir') 22 | print('List the resulting contents of directory') 23 | print(os.listdir()) 24 | 25 | -------------------------------------------------------------------------------- /chapter17/exercise/create_file_with_date.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | print('Creating file') 4 | file = open('date_file.txt', 'w') 5 | print('Writing date information to file') 6 | todays_date = str(datetime.today()) 7 | file.write(todays_date) 8 | print('closing file') 9 | file.close() 10 | print('Done') 11 | 12 | 13 | -------------------------------------------------------------------------------- /chapter17/exercise/load_date_from_file.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | print('Opening file') 4 | file = open('date_file.txt', 'r') 5 | print('Reading contents)') 6 | lines = file.readlines() 7 | print('Accessing first line') 8 | date_str = lines[0] 9 | print('Date as a string:', date_str) 10 | datetime_object = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S.%f') 11 | print('Date as an object:', datetime_object) 12 | 13 | print('Done') 14 | -------------------------------------------------------------------------------- /chapter17/files1.py: -------------------------------------------------------------------------------- 1 | file = open('myfile.txt', 'r+') 2 | print('file.name:', file.name) 3 | print('file.closed:', file.closed) 4 | print('file.mode:', file.mode) 5 | file.close() 6 | print('file.closed now:', file.closed) -------------------------------------------------------------------------------- /chapter17/files2.py: -------------------------------------------------------------------------------- 1 | file = open('myfile.txt', 'r+') 2 | 3 | lines = file.readlines() 4 | for line in lines: 5 | print(line, end='') 6 | 7 | file.close() 8 | -------------------------------------------------------------------------------- /chapter17/files3.py: -------------------------------------------------------------------------------- 1 | print('Writing file') 2 | f = open('my-new-file.txt', 'w') 3 | f.write('Hello from Python!!\n') 4 | f.write('Working with files is easy...\n') 5 | f.write('It is cool ...\n') 6 | f.close() 7 | -------------------------------------------------------------------------------- /chapter17/files4.py: -------------------------------------------------------------------------------- 1 | import fileinput 2 | 3 | # Read multiple files 4 | with fileinput.input(files=('textfile1.txt', 'textfile2.txt')) as f: 5 | for line in f: 6 | print(line, end='') 7 | print() 8 | 9 | # Indicate some facilities 10 | with fileinput.input(files=('textfile1.txt', 'textfile2.txt')) as f: 11 | line = f.readline() 12 | print('f.filename():', f.filename()) 13 | print('f.isfirstline():', f.isfirstline()) 14 | print('f.lineno():', f.lineno()) 15 | print('f.filelineno():', f.filelineno()) 16 | for line in f: 17 | print(line, end='') 18 | -------------------------------------------------------------------------------- /chapter17/files5.py: -------------------------------------------------------------------------------- 1 | # Alternative to reading lines from a file 2 | # A file object is iterable 3 | 4 | file = open('myfile.txt', 'r') 5 | 6 | for line in file: 7 | print(line, end='') 8 | 9 | file.close() 10 | -------------------------------------------------------------------------------- /chapter17/my-new-file.txt: -------------------------------------------------------------------------------- 1 | Hello from Python!! 2 | Working with files is easy... 3 | It is cool ... 4 | -------------------------------------------------------------------------------- /chapter17/myfile.txt: -------------------------------------------------------------------------------- 1 | This is a line from a file 2 | To be or not to be 3 | -------------------------------------------------------------------------------- /chapter17/paths-app.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | print('Create Path object for current directory') 4 | p = Path('.') 5 | print('p:', p) 6 | print('p.exists():', p.exists()) 7 | print('p.is_dir():', p.is_dir()) 8 | print('p.is_file():', p.is_file()) 9 | print('p.absolute():', p.absolute()) 10 | 11 | print('-' * 10) 12 | for file in p.glob('*.txt'): 13 | print('file:', file) 14 | print('-' * 10) 15 | 16 | p = Path.cwd() 17 | print('Set up new directory') 18 | newdir = p / 'test' 19 | print('Check to see if newdir exists') 20 | print('newdir.exists():', newdir.exists()) 21 | print('Create new dir') 22 | newdir.mkdir() 23 | print('newdir.exists():', newdir.exists()) 24 | 25 | dir = Path('./test') 26 | print('Create new file') 27 | newfile = dir / 'text.txt' 28 | print('Write some text to file') 29 | newfile.write_text('Hello Python World!') 30 | print('Read the text back again') 31 | print(newfile.read_text()) 32 | 33 | print('Remove the file') 34 | newfile.unlink() 35 | print('Remove the directory') 36 | newdir.rmdir() -------------------------------------------------------------------------------- /chapter17/rand-file-acces.py: -------------------------------------------------------------------------------- 1 | f = open('text.txt', 'w') 2 | f.write('abcdefghijklmnopqrstuvwxyz\n') 3 | 4 | f.seek(10,0) 5 | f.write('HELLO') 6 | f.seek(6, 0) 7 | f.write ('BOO') 8 | f.close() 9 | 10 | with open('text.txt', 'r') as f: 11 | for line in f: 12 | print(line, end='') 13 | -------------------------------------------------------------------------------- /chapter17/read-file-using-with.py: -------------------------------------------------------------------------------- 1 | # File type implements the Context Manager Protocol 2 | # can therefore use a file in a with as statement 3 | 4 | with open('myfile.txt', 'r') as f: 5 | lines = f.readlines() 6 | for line in lines: 7 | print(line, end='') 8 | 9 | print('Done') 10 | -------------------------------------------------------------------------------- /chapter17/tempfiles1.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | 3 | print('tempfile.gettempdir():', tempfile.gettempdir()) 4 | 5 | temp = tempfile.TemporaryFile('w+') 6 | print('temp.name:', temp.name) 7 | print('temp.mode:', temp.mode) 8 | 9 | temp.write('Hello world!') 10 | temp.seek(0) 11 | line = temp.readline() 12 | print('line:', line) 13 | 14 | -------------------------------------------------------------------------------- /chapter17/text.txt: -------------------------------------------------------------------------------- 1 | abcdefBOOjHELLOpqrstuvwxyz 2 | -------------------------------------------------------------------------------- /chapter17/textfile1.txt: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | -------------------------------------------------------------------------------- /chapter17/textfile2.txt: -------------------------------------------------------------------------------- 1 | X 2 | Y 3 | Z -------------------------------------------------------------------------------- /chapter17/textfileexample.py: -------------------------------------------------------------------------------- 1 | print('Writing file') 2 | f = open('python1', 'w') 3 | f.write('Hello from Python!!\n') 4 | f.write('Working with files is easy...\n') 5 | f.write('It is cool ...\n') 6 | f.close() 7 | 8 | print('Reading file') 9 | f = open('python1', 'r') 10 | line1 = f.readline() 11 | line2 = f.readline() 12 | line3 = f.readline() 13 | print('---') 14 | print(line1, end='') 15 | print(line2, end='') 16 | print(line3, end='') 17 | 18 | f = open('python1', 'r') 19 | i = 0 20 | for line in f: 21 | print(i, ':', line, end='') 22 | i = i + 1 23 | f.close() 24 | 25 | f = open('python1', 'r') 26 | l = [line.upper() for line in f] 27 | f.close() 28 | print(l) 29 | 30 | f = open('python1', 'r') 31 | try: 32 | for line in f: 33 | print(line, end='') 34 | finally: 35 | f.close() 36 | 37 | with open('python1', 'r') as f: 38 | for line in f: 39 | print(line, end='') 40 | 41 | print('RAM') 42 | f = open('python2', 'w') 43 | f.write('abcdefghijklmnopqrstuvwxyz\n'); 44 | f.seek(10,0) 45 | f.write('HELLO') 46 | f.seek(6, 0) 47 | f.write ('BOO') 48 | f.close() 49 | with open('python2', 'r') as f: 50 | for line in f: 51 | print(line, end='') 52 | -------------------------------------------------------------------------------- /chapter18/binary_streams.py: -------------------------------------------------------------------------------- 1 | import io, os 2 | 3 | print('In memory Binary Streams') 4 | binary_stream = io.BytesIO() 5 | print('binary_stream', binary_stream) 6 | 7 | # Binary data and strings are different types, so a str 8 | # must be encoded to binary using ascii, utf-8, or other. 9 | binary_stream.write("Hello, world!\n".encode('ascii')) 10 | 11 | # Move cursor back to the beginning of the buffer 12 | binary_stream.seek(0) 13 | 14 | # Read all data from the stream 15 | stream_data = binary_stream.read() 16 | 17 | # The stream_data is type 'bytes', immutable 18 | print(type(stream_data)) 19 | print(stream_data) 20 | 21 | # To modify the actual contents of the existing buffer 22 | # use getbuffer() to get an object you can modify. 23 | # Modifying this object updates the underlying BytesIO buffer 24 | mutable_buffer = binary_stream.getbuffer() 25 | print(type(mutable_buffer)) # class 'memoryview' 26 | mutable_buffer[0] = 0xEF 27 | 28 | # Re-read the original stream. Contents will be modified 29 | # because we modified the mutable buffer 30 | binary_stream.seek(0) 31 | print(binary_stream.read()) 32 | 33 | print('-' * 25) 34 | 35 | print('File based binary stream') 36 | 37 | # Binary IO aka Buffered IO 38 | binary_stream_from_file = io.BufferedReader(io.BytesIO(b'starship.png')) 39 | print('f3', binary_stream_from_file) 40 | print('f3.read()', binary_stream_from_file.read()) # Read the whole of the file 41 | file_length_in_bytes = os.path.getsize('starship.png') 42 | print('file_length_in_bytes', file_length_in_bytes) 43 | binary_stream_from_file.seek(0, 0) # Go to the start fo the file 44 | bytes = binary_stream_from_file.read(4) 45 | print(bytes) 46 | 47 | 48 | -------------------------------------------------------------------------------- /chapter18/myfile.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter18/myfile.dat -------------------------------------------------------------------------------- /chapter18/myfile.txt: -------------------------------------------------------------------------------- 1 | Hello Python World -------------------------------------------------------------------------------- /chapter18/raw_io_example.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | f4 = io.FileIO('starship.png', mode='rb') 4 | 5 | print('f4', f4) -------------------------------------------------------------------------------- /chapter18/sockets.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | raw = SocketIO(xxx, 'r') 4 | buffer = io.BufferedReader(raw, io.DEFAULT_BUFFER_SIZE) 5 | -------------------------------------------------------------------------------- /chapter18/starship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter18/starship.png -------------------------------------------------------------------------------- /chapter18/stdinout_examples.py: -------------------------------------------------------------------------------- 1 | # Standard IO streams 2 | import io, sys 3 | 4 | print(sys.stdin) 5 | print(sys.stdout) 6 | print(sys.stderr) 7 | 8 | print('-' *25) 9 | 10 | wrapper = io.TextIOWrapper(sys.stdout, line_buffering=True) 11 | wrapper.write('Hello World') 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /chapter18/streams_options.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | # Text stream 4 | f1 = open('myfile.txt', mode='r', encoding='utf-8') 5 | print(f1) 6 | 7 | # Binary IO aka Buffered IO 8 | f2 = open('myfile.dat', mode='rb') 9 | print(f2) 10 | 11 | f3 = open('myfile.dat', mode='wb') 12 | print(f3) 13 | 14 | # Raw IO aka Unbufferedf IO 15 | f4 = open('starship.png', mode='rb', buffering=0) 16 | print(f4) 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /chapter18/text_streams.py: -------------------------------------------------------------------------------- 1 | import io, os 2 | 3 | # In memory stream 4 | in_memory_text_stream = io.StringIO('to be or not to be that is the question') 5 | print('in_memory_text_stream', in_memory_text_stream) 6 | print(in_memory_text_stream.getvalue()) 7 | in_memory_text_stream.close() 8 | 9 | print('-' * 25) 10 | 11 | print('File based text stream') 12 | 13 | f = io.FileIO('myfile.txt') 14 | br = io.BufferedReader(f) 15 | text_stream = io.TextIOWrapper(br, encoding='utf-8') 16 | 17 | print('text_stream', text_stream) 18 | print('text_stream.readable():', text_stream.readable()) 19 | print('text_stream.seekable()', text_stream.seekable()) 20 | print('text_stream.writeable()', text_stream.writable()) 21 | 22 | print(text_stream.read()) 23 | 24 | text_stream.close() 25 | 26 | 27 | -------------------------------------------------------------------------------- /chapter19/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter19/__init__.py -------------------------------------------------------------------------------- /chapter19/csvdictexample.py: -------------------------------------------------------------------------------- 1 | import csv 2 | 3 | 4 | def main(): 5 | print('Starting write of dict CSV example') 6 | with open('names.csv', 'w', newline='') as csvfile: 7 | fieldnames = ['first_name', 'last_name', 'result'] 8 | writer = csv.DictWriter(csvfile, fieldnames=fieldnames) 9 | writer.writeheader() 10 | writer.writerow({'first_name': 'John', 11 | 'last_name': 'Smith', 12 | 'result' : 54}) 13 | writer.writerow({'first_name': 'Jane', 'last_name': 'Lewis', 'result' : 63}) 14 | writer.writerow({'first_name': 'Chris', 'last_name': 'Davies', 'result' : 72}) 15 | 16 | print('Starting to read dict CSV example') 17 | with open('names.csv', newline='') as csvfile: 18 | reader = csv.DictReader(csvfile) 19 | for heading in reader.fieldnames: 20 | print(heading, end=' ') 21 | print('\n------------------------------') 22 | for row in reader: 23 | print(row['first_name'], row['last_name'], row['result']) 24 | print('Done') 25 | 26 | 27 | if __name__ == '__main__': 28 | main() -------------------------------------------------------------------------------- /chapter19/csvexample.py: -------------------------------------------------------------------------------- 1 | import csv 2 | 3 | 4 | def main(): 5 | print('Starting CSV Exmaple') 6 | print(csv.list_dialects()) 7 | 8 | print('Creating CSV file') 9 | with open('sample.csv', 'w', newline='') as csvfile: 10 | writer = csv.writer(csvfile) 11 | writer.writerow(['She Loves You', 'Sept', 1963]) 12 | writer.writerow(['I Want to Hold Your Hand', 'Dec', 1963]) 13 | writer.writerow(['Cant Buy Me Love', 'Apr', 1964]) 14 | writer.writerow(['A Hard Days Night', 'July', ' 1964']) 15 | 16 | print('-' * 100) 17 | 18 | print('Starting to read csv file') 19 | with open('sample.csv', newline='') as csvfile: 20 | reader = csv.reader(csvfile) 21 | # Process each row in the csv file 22 | for row in reader: 23 | row_length = len(row) 24 | print('row_length', row_length) 25 | if row_length != 3: 26 | print('Error in data (length is not 3):', row) 27 | print('In line:', reader.line_num) 28 | else: 29 | for i in range(row_length): 30 | # Each element in the row can be accessed via an index 31 | print(row[i], end=': ') 32 | print() 33 | try: 34 | year = int(row[2].strip()) 35 | if year == 1964: 36 | print('What a great year', row[0]) 37 | except ValueError as exp: 38 | print(exp) 39 | print("issue in row ", reader.line_num) 40 | print(row) 41 | 42 | print('Done Reading') 43 | 44 | if __name__ == '__main__': 45 | main() -------------------------------------------------------------------------------- /chapter19/exercises/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter19/exercises/__init__.py -------------------------------------------------------------------------------- /chapter19/exercises/fintech/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter19/exercises/fintech/__init__.py -------------------------------------------------------------------------------- /chapter19/exercises/fintech/accounts.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta 2 | from timeit import default_timer 3 | 4 | 5 | # Accounts module 6 | 7 | 8 | def timer(func): 9 | def inner(self, value): 10 | print('calling ', func.__name__, 'on', self, 'with', value) 11 | start = default_timer() 12 | func(self, value) 13 | end = default_timer() 14 | print('returned from ', func.__name__, 'it took', end - start, 'seconds') 15 | 16 | return inner 17 | 18 | 19 | class BalanceError(Exception): 20 | """ The Balance will be invalid """ 21 | 22 | def __init__(self, account): 23 | self.account = account 24 | 25 | 26 | class AmountError(Exception): 27 | 28 | def __init__(self, account, msg): 29 | self.account = account 30 | self.message = msg 31 | 32 | def __str__(self): 33 | return 'AmountError (' + self.message + ') on ' + str(self.account) 34 | 35 | 36 | class Transaction: 37 | """ A Class used to represent an individual Transaction """ 38 | def __init__(self, action, amount): 39 | self.action = action 40 | self.amount = amount 41 | 42 | def __str__(self): 43 | return 'Transaction[' + self.action + ': ' + str(self.amount) + ']' 44 | 45 | 46 | class Account(metaclass=ABCMeta): 47 | """" A class used to represent a type of account """ 48 | 49 | instance_count = 0 50 | 51 | @classmethod 52 | def increment_instance_count(cls): 53 | print('Creating new Account') 54 | cls.instance_count += 1 55 | 56 | def __init__(self, account_number, account_holder, opening_balance, account_type): 57 | Account.increment_instance_count() 58 | self.account_number = account_number 59 | self.account_holder = account_holder 60 | self._balance = opening_balance 61 | self.type = account_type 62 | # Note need to initialise the history list before you try to add a Transaction 63 | self.history = [] 64 | self._add_deposit_transaction(opening_balance) 65 | 66 | def __enter__(self): 67 | print('__enter__') 68 | return self 69 | 70 | def __exit__(self, *args): 71 | print('__exit__:', args) 72 | return True 73 | 74 | # Method called if attribute is unknown 75 | def __getattr__(self, attribute): 76 | print('__getattr__: unknown attribute accessed - ', attribute) 77 | return -1 78 | 79 | # Return the transaction hsitory as the iterable object for an Account 80 | # and any subclass of Account 81 | def __iter__(self): 82 | return iter(self.history) 83 | 84 | # Provide internal support for adding transactions 85 | # Note by convention methods starting with an '_' shoudl not be called 86 | # by clients of this class 87 | def _add_transaction(self, transaction): 88 | self.history.append(transaction) 89 | 90 | # These are convenience methods to make it easier to 91 | # record a deposit or withdrawal. 92 | def _add_deposit_transaction(self, amount): 93 | self._add_transaction(Transaction('deposit', amount)) 94 | 95 | def _add_withdraw_transaction(self, amount): 96 | self._add_transaction(Transaction('withdraw', amount)) 97 | 98 | @timer 99 | def deposit(self, amount): 100 | if amount < 0: 101 | print('You cannot deposit negative amounts') 102 | raise AmountError(account=self, msg='Cannot deposit negative amounts') 103 | else: 104 | self._balance += amount 105 | self._add_deposit_transaction(amount) 106 | 107 | @timer 108 | def withdraw(self, amount): 109 | if amount < 0: 110 | print('You cannot withdraw negative amounts') 111 | raise AmountError(self, 'Cannot withdraw negative amounts') 112 | else: 113 | self._balance -= amount 114 | self._add_withdraw_transaction(amount) 115 | 116 | @property 117 | def balance(self): 118 | """ Provides the current balance """ 119 | return self._balance 120 | 121 | def __str__(self): 122 | return 'Account[' + self.account_number + '] - ' + \ 123 | self.account_holder + ', ' + self.type + ' account = ' + str(self.balance) 124 | 125 | 126 | class CurrentAccount(Account): 127 | 128 | def __init__(self, account_number, account_holder, opening_balance, overdraft_limit): 129 | super().__init__(account_number, account_holder, opening_balance, 'current') 130 | self.overdraft_limit = -overdraft_limit 131 | 132 | @timer 133 | def withdraw(self, amount): 134 | if amount < 0: 135 | print('You cannot withdraw negative amounts') 136 | raise AmountError(self, 'Cannot withdraw negative amounts') 137 | elif self.balance - amount < self.overdraft_limit: 138 | print('Withdrawal would exceed your overdraft limit') 139 | raise BalanceError(self) 140 | else: 141 | self._balance -= amount 142 | self._add_withdraw_transaction(amount) 143 | 144 | def __str__(self): 145 | return super().__str__() + 'overdraft limit: ' + str(self.overdraft_limit) 146 | 147 | 148 | class DepositAccount(Account): 149 | 150 | def __init__(self, account_number, account_holder, opening_balance, interest_rate): 151 | super().__init__(account_number, account_holder, opening_balance, 'deposit') 152 | self.interest_rate = interest_rate 153 | 154 | def __str__(self): 155 | return super().__str__() + 'interest rate: ' + str(self.interest_rate) 156 | 157 | 158 | class InvestmentAccount(Account): 159 | def __init__(self, account_number, account_holder, opening_balance, investment_type): 160 | super().__init__(account_number, account_holder, opening_balance, 'investment') 161 | self.investment_type = investment_type 162 | 163 | def __str__(self): 164 | return super().__str__() + ', type: ' + self.type 165 | -------------------------------------------------------------------------------- /chapter19/exercises/write_accounts_file.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import fintech.accounts as accounts 3 | 4 | 5 | def write_account_transaction_to_csv(filename, account): 6 | print('Starting write of dict CSV example') 7 | with open(filename, 'w', newline='') as csvfile: 8 | fieldnames = ['transaction_type', 'amount'] 9 | writer = csv.DictWriter(csvfile, fieldnames=fieldnames) 10 | writer.writeheader() 11 | # Write out the transactions 12 | for transaction in account.history: 13 | writer.writerow({'transaction_type': transaction.action, 14 | 'amount': transaction.amount}) 15 | 16 | 17 | print('Starting') 18 | acc = accounts.CurrentAccount('123', 'John', 10.05, 100.0) 19 | acc.deposit(23.45) 20 | acc.withdraw(12.33) 21 | 22 | print('Writing Account Transactions') 23 | write_account_transaction_to_csv('accounts.csv', acc) 24 | 25 | print('Done') 26 | -------------------------------------------------------------------------------- /chapter19/names.csv: -------------------------------------------------------------------------------- 1 | first_name,last_name,result 2 | John,Smith,54 3 | Jane,Lewis,63 4 | Chris,Davies,72 5 | -------------------------------------------------------------------------------- /chapter19/sample.csv: -------------------------------------------------------------------------------- 1 | She Loves You,Sept,1963 2 | I Want to Hold Your Hand,Dec,1963 3 | Cant Buy Me Love,Apr,1964 4 | A Hard Days Night,July, 1964 5 | Blahh,Apr,jjj 6 | -------------------------------------------------------------------------------- /chapter2/rgb_colours.py: -------------------------------------------------------------------------------- 1 | """ Example illustrating create different colours using RGB codes """ 2 | 3 | import wx 4 | import wx.grid 5 | 6 | MAX_ROWS = 25 7 | 8 | # Create the Application Object 9 | app = wx.App() 10 | 11 | # Now create a Frame (representing the window) 12 | frame = wx.Frame(parent=None, title='Colour Chart') 13 | 14 | # Set up grid to be used to display colours 15 | grid = wx.grid.Grid(frame, -1) 16 | grid.CreateGrid(MAX_ROWS, 5) 17 | grid.SetColSize(0, 140) 18 | 19 | # Set up the column headings 20 | grid.SetColLabelValue(0, 'RGB') 21 | grid.SetColLabelValue(1, 'Solid') 22 | grid.SetColLabelValue(2, '75%') 23 | grid.SetColLabelValue(3, '50%') 24 | grid.SetColLabelValue(4, '25%') 25 | 26 | red = 0 27 | green = 0 28 | blue = 0 29 | add_green = False 30 | add_blue = False 31 | 32 | # Generate RGB colours 33 | for i in range(0, MAX_ROWS): 34 | # Set the colour and text 35 | grid.SetCellValue(i, 0, 'RGB(' + str(red) + ', ' + str(green) + ', ' + str(blue) + ')') 36 | # Solid version of colour 37 | grid.SetCellBackgroundColour(i, 1, wx.Colour(red, green, blue)) 38 | # Add a bit of transparency 75%, 50% and 25% 39 | grid.SetCellBackgroundColour(i, 2, wx.Colour(red, green, blue, alpha=191)) 40 | grid.SetCellBackgroundColour(i, 3, wx.Colour(red, green, blue, alpha=127)) 41 | grid.SetCellBackgroundColour(i, 4, wx.Colour(red, green, blue, alpha=64)) 42 | # Reset RGB values 43 | red = red + 30 44 | if red > 255: 45 | red = 0 46 | add_green = True 47 | if add_green: 48 | green = green + 30 49 | if green > 255: 50 | green = 0 51 | red = 0 52 | add_blue = True 53 | if add_blue: 54 | blue = blue + 30 55 | 56 | # Run the GUI application 57 | frame.Show() 58 | 59 | # Start the event loop 60 | app.MainLoop() 61 | -------------------------------------------------------------------------------- /chapter20/exercises/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter20/exercises/__init__.py -------------------------------------------------------------------------------- /chapter20/exercises/accounts.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter20/exercises/accounts.xlsx -------------------------------------------------------------------------------- /chapter20/exercises/fintech/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter20/exercises/fintech/__init__.py -------------------------------------------------------------------------------- /chapter20/exercises/write_accounts_file.py: -------------------------------------------------------------------------------- 1 | from openpyxl import Workbook 2 | import fintech.accounts as accounts 3 | 4 | 5 | def write_account_transaction_to_excel(filename, account): 6 | print('Starting write of Excel example') 7 | workbook = Workbook() 8 | # Get the current active worksheet 9 | ws = workbook.active 10 | ws.title = 'transactions' 11 | 12 | ws['A1'] = 'transaction type' 13 | ws['B1'] = 'amount' 14 | 15 | row = 2 16 | 17 | # Write out the transactions 18 | for transaction in account.history: 19 | ws['A' + str(row)] = transaction.action 20 | ws['B' + str(row)] = transaction.amount 21 | row += 1 22 | 23 | workbook.save(filename) 24 | 25 | print('Done Write Excel Example') 26 | 27 | 28 | print('Starting') 29 | acc = accounts.CurrentAccount('123', 'John', 10.05, 100.0) 30 | acc.deposit(23.45) 31 | acc.withdraw(12.33) 32 | 33 | print('Writing Account Transactions') 34 | write_account_transaction_to_excel('accounts.xlsx', acc) 35 | 36 | print('Done') 37 | -------------------------------------------------------------------------------- /chapter20/readExcelExample.py: -------------------------------------------------------------------------------- 1 | """ Example illustrating reading EXCEL files using the 2 | openpyxl library. """ 3 | 4 | from openpyxl import load_workbook 5 | 6 | 7 | def main(): 8 | print('Starting reading Excel file using openPyXL') 9 | 10 | # data_only = True loads cached reuslt of equations 11 | # data_only = False load equations (default) 12 | workbook = load_workbook(filename='sample.xlsx', data_only=True) 13 | print(workbook.active) 14 | print(workbook.sheetnames) 15 | print(workbook.worksheets) 16 | 17 | # print('-' * 10) 18 | ws = workbook['my worksheet'] 19 | # print(ws['A1'].value) 20 | # print(ws['B1'].value) 21 | 22 | # print('-' * 10) 23 | # for sheet in workbook: 24 | # print(sheet.title) 25 | 26 | print('-' * 10) 27 | # print(ws.max_column) 28 | # print(ws.max_row) 29 | 30 | cell_range = ws[ws.calculate_dimension()] 31 | for cell in cell_range: 32 | try: 33 | print(cell[0].value, end=", ") 34 | age = int(cell[1].value) 35 | if age > 18: 36 | print('You can drink') 37 | else: 38 | print('Underage') 39 | except ValueError: 40 | print('Error in age data') 41 | print(cell) 42 | print(cell[2].value, cell[3].value, cell[4].value) 43 | 44 | print('-' * 10) 45 | 46 | print('Finished reading Excel file using openPyXL') 47 | 48 | 49 | if __name__ == '__main__': 50 | main() 51 | -------------------------------------------------------------------------------- /chapter20/sample.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter20/sample.xlsx -------------------------------------------------------------------------------- /chapter20/sample2.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter20/sample2.xlsx -------------------------------------------------------------------------------- /chapter20/writeExcelExample.py: -------------------------------------------------------------------------------- 1 | from openpyxl import Workbook 2 | 3 | 4 | print('Starting Write Excel Example with openPyXL') 5 | 6 | # Create an empty workbook 7 | workbook = Workbook() 8 | # Get the current active worksheet 9 | sheet = workbook.active 10 | sheet.title = 'dataset1' 11 | sheet.sheet_properties.tabColor = '0F45F7' 12 | 13 | sheet['A1'] = 'John' 14 | sheet['B1'] = 42 15 | sheet['C1'] = 56 16 | sheet['D1'] = '=SUM(B1,C1)/2' 17 | sheet['A2'] = 'Adam' 18 | sheet['B2'] = 75 19 | sheet['C2'] = 86 20 | sheet['D2'] = '=SUM(B2, C2)/2' 21 | 22 | sheet2 = workbook.create_sheet(title='dataset2') 23 | sheet2.append(['John', 1, 2, 3, '=SUM(B1,D1)/3']) 24 | sheet2.append(['Adam', 5, 7, 8]) 25 | 26 | sheet2.cell(column=1, row=3, value='John') 27 | sheet2.cell(column=2, row=3, value=15) 28 | 29 | 30 | workbook.save('sample2.xlsx') 31 | 32 | print('Done Write Excel Example') 33 | -------------------------------------------------------------------------------- /chapter21/exercises/regex_solutions.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | # function to check string only contains letters and numbers 5 | def contains_only_characters_and_numbers(string): 6 | # Returns a match for any characters except those specified 7 | re_pattern = re.compile(r'[^a-zA-Z0-9]') 8 | # invert result as we are only interested in chars and numbers 9 | return not bool(re_pattern.search(string)) 10 | 11 | 12 | print(contains_only_characters_and_numbers('John')) # True 13 | print(contains_only_characters_and_numbers('!John_Hunt')) # False 14 | print(contains_only_characters_and_numbers('42')) # True 15 | print(contains_only_characters_and_numbers('John42')) # True 16 | print(contains_only_characters_and_numbers('John 42')) # False 17 | 18 | 19 | # function to verify a UK postcode 20 | def verify_postcode(postcode): 21 | re_pattern = re.compile(r'[a-zA-z]{2}[0-9]{1,2} [0-9]{1,2}[a-zA-z]{2}') 22 | return bool(re_pattern.search(postcode)) 23 | 24 | 25 | print("verify_postcode('SY23 3AA'):", verify_postcode('SY23 33AA')) # True 26 | print("verify_postcode('SY23 4ZZ'):", verify_postcode('SY23 4ZZ')) # True 27 | print("verify_postcode('BB1 3PO'):", verify_postcode('BB1 3PO')) # True 28 | print("verify_postcode('AA111 NN56'):", verify_postcode('AA111 NN56')) # False 29 | print("verify_postcode('AA1 56NN'):", verify_postcode('AA1 56NN')) # True 30 | print("verify_postcode('AA156NN'):", verify_postcode('AA156NN')) # False 31 | print("verify_postcode('AA NN'):", verify_postcode('AA NN')) # False 32 | 33 | 34 | # Function that will extract value held been start and end characters 35 | def extract_values(start_char, end_char, string): 36 | return re.findall(start_char + r'(.*?)' + end_char, string) 37 | 38 | 39 | print(extract_values('<', '>', '')) 40 | print(extract_values('<', '>', '<42>')) 41 | print(extract_values('<', '>', '')) 42 | print(extract_values('<', '>', 'The was in the ')) 43 | -------------------------------------------------------------------------------- /chapter21/regex_examples.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | s = 'Hello \n world' 4 | print(s) 5 | 6 | s = r'Hello \n world' 7 | print(s) 8 | 9 | text1 = 'john williams' 10 | pattern = '[Jj]ohn' 11 | print('looking in', text1, 'for the pattern', pattern) 12 | if re.search(pattern, text1, re.MULTILINE): 13 | print('Match has been found') 14 | 15 | line1 = 'The price is 23.55' 16 | containsIntegers = r'\d+' 17 | if re.search(containsIntegers, line1): 18 | print('Line 1 contains an integer') 19 | else: 20 | print('Line 1 does not contain an integer') 21 | 22 | rePattern = re.compile(containsIntegers) 23 | matchLine1 = rePattern.search(line1) 24 | if matchLine1: 25 | print('Line 1 contains a number') 26 | else: 27 | print('Line 1 does not contain a number') 28 | 29 | print('-' * 10) 30 | 31 | matchLine1 = re.search(containsIntegers, line1) 32 | if matchLine1: 33 | print('Line 1 contains a number') 34 | else: 35 | print('Line 1 does not contain a number') 36 | 37 | # Alternative words 38 | music = r'Beatles|Adele|Gorillaz' 39 | request = 'Play some Adele' 40 | if re.search(music, request): 41 | print('Set Fire to the Rain') 42 | else: 43 | print('No Adele Available') 44 | 45 | music2 = r'A (song|ballad|ditty) from (Paloma|Adele)' 46 | request = 'A ditty from Paloma' 47 | if re.search(music2, request): 48 | print('Only Love Can Hurt like this') 49 | 50 | line = 'root:*:0:0:System Administrator:/var/root:/bin/sh' 51 | rootUser = r'root:' 52 | if re.search(rootUser, line): 53 | print('Root') 54 | else: 55 | print('Not root') 56 | 57 | usesSh = r'/bin/sh$' 58 | if re.search(usesSh, line): 59 | print('sh') 60 | else: 61 | print('Some other shell') 62 | 63 | name = 'John Smith' 64 | nameRe = r'john' 65 | if re.search(nameRe, name, re.IGNORECASE): 66 | print('Match') 67 | 68 | sound = r'boink+' 69 | if re.search(sound, 'boink'): 70 | print('boink matches') 71 | if re.search(sound, 'boinkkkk'): 72 | print('boinkkkk matches') 73 | 74 | sound = r'(boink)+' 75 | if re.search(sound, 'boink'): 76 | print('boink matches') 77 | if re.search(sound, 'boinkboink'): 78 | print('boinkboink matches') 79 | 80 | inputStr = '123-44-7890' 81 | if re.search(r'\d{3}-\d{2,4}-\d{4,8}', inputStr): 82 | print('Input Matches') 83 | else: 84 | print('Input Does Not Match') 85 | 86 | components = r'(\D+)(\d+)(\D+)(\d+)' 87 | inputText = 'abcd123defg 456 ' 88 | match_results = re.search(components, inputText) 89 | captureGroups = match_results.groups() 90 | for group in captureGroups: 91 | print(group, '; ', end='') 92 | print() 93 | 94 | p = re.compile(r'\W+') 95 | s = '20 High Street' 96 | print(p.split(s)) 97 | 98 | pattern = '(England|Wales|Scotland)' 99 | input = 'England for football, Wales for Rugby and Scotland for the Highland games' 100 | 101 | print(re.sub(pattern, 'England', input)) 102 | print(re.subn(pattern, 'Scotland', input)) 103 | x = re.sub(pattern, 'Wales', input, 2) 104 | print(x) 105 | 106 | str = 'The rain in Spain stays mainly on the plain' 107 | results = re.findall('[a-zA-Z]{2}ai.', str) 108 | print(results) 109 | for s in results: 110 | print(s) 111 | 112 | str = 'It was a hot summer night' 113 | x = re.split('\s', str) 114 | print(x) 115 | -------------------------------------------------------------------------------- /chapter24/connect_example.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | 3 | print('Open database connection') 4 | connection = pymysql.connect('localhost', 'user', 'password', 'uni-database') 5 | print('connection:', connection) 6 | 7 | print('prepare a cursor object using cursor() method') 8 | cursor = connection.cursor() 9 | print('cursor:', cursor) 10 | 11 | # ... perform database operations 12 | 13 | print('disconnect from database server') 14 | connection.close() 15 | print('Done') -------------------------------------------------------------------------------- /chapter24/create5.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | 3 | # Open database connection 4 | connection = pymysql.connect('localhost', 'user', 'password', 'uni-database') 5 | connection.autocommit(False) 6 | 7 | # prepare a cursor object using cursor() method 8 | cursor = connection.cursor() 9 | 10 | try: 11 | # Execute CREATE command 12 | cursor.execute("CREATE TABLE log (message VARCHAR(100) NOT NULL)") 13 | 14 | # Commit the changes to the database 15 | connection.commit() 16 | except: 17 | # rollback the changes if an exception / error 18 | connection.rollback() 19 | 20 | # Close the database connection 21 | connection.close() 22 | -------------------------------------------------------------------------------- /chapter24/delete4.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | 3 | # Open database connection 4 | connection = pymysql.connect('localhost', 'user', 'password', 'uni-database') 5 | connection.autocommit(False) 6 | 7 | # prepare a cursor object using cursor() method 8 | cursor = connection.cursor() 9 | 10 | try: 11 | # Execute DELETE command 12 | cursor.execute("DELETE FROM students WHERE id = 7") 13 | 14 | # Commit the changes to the database 15 | connection.commit() 16 | except: 17 | # rollback the changes if an exception / error 18 | connection.rollback() 19 | 20 | # Close the database connection 21 | connection.close() 22 | -------------------------------------------------------------------------------- /chapter24/exercise/create_tables.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | 3 | # Open database connection 4 | connection = pymysql.connect('localhost', 'user', 'password', 'accounts') 5 | 6 | # prepare a cursor object using cursor() method 7 | cursor = connection.cursor() 8 | 9 | try: 10 | # Execute CREATE command 11 | cursor.execute("CREATE TABLE acc_info (idacc_info INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (idacc_info))") 12 | cursor.execute("CREATE TABLE transactions (idtransactions INT NOT NULL, type VARCHAR(45) NOT NULL, amount VARCHAR(45) NOT NULL, account INT NOT NULL, PRIMARY KEY (idtransactions))") 13 | 14 | # Commit the changes to the database 15 | connection.commit() 16 | except: 17 | # rollback the changes if an exception / error 18 | connection.rollback() 19 | 20 | # Close the database connection 21 | connection.close() 22 | -------------------------------------------------------------------------------- /chapter24/exercise/fintech/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter24/exercise/fintech/__init__.py -------------------------------------------------------------------------------- /chapter24/exercise/fintech/accounts.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta 2 | # Accounts module 3 | 4 | 5 | class BalanceError(Exception): 6 | """ The Balance will be invalid """ 7 | 8 | def __init__(self, account): 9 | self.account = account 10 | 11 | 12 | class AmountError(Exception): 13 | 14 | def __init__(self, account, msg): 15 | self.account = account 16 | self.message = msg 17 | 18 | def __str__(self): 19 | return 'AmountError (' + self.message + ') on ' + str(self.account) 20 | 21 | 22 | class Transaction: 23 | """ A Class used to represent an individual Transaction """ 24 | def __init__(self, id, action, amount): 25 | self.id = id 26 | self.action = action 27 | self.amount = amount 28 | 29 | def __str__(self): 30 | return 'Transaction[' + self.id + " - " + self.action + ': ' + str(self.amount) + ']' 31 | 32 | 33 | class CurrentAccount(metaclass=ABCMeta): 34 | """" A class used to represent a type of account """ 35 | 36 | @classmethod 37 | def increment_instance_count(cls): 38 | print('Creating new Account') 39 | cls.instance_count += 1 40 | 41 | def __init__(self, account_number, account_holder, opening_balance, overdraft_limit): 42 | self.account_number = account_number 43 | self.account_holder = account_holder 44 | self._balance = opening_balance 45 | self.overdraft_limit = -overdraft_limit 46 | # Note need to initialise the history list before you try to add a Transaction 47 | self.history = [] 48 | self._add_deposit_transaction(opening_balance) 49 | self.transaction_count = 0 50 | 51 | def get_next_transaction_id(self): 52 | self.transaction += 1 53 | return self.transaction 54 | 55 | def __enter__(self): 56 | print('__enter__') 57 | return self 58 | 59 | def __exit__(self, *args): 60 | print('__exit__:', args) 61 | return True 62 | 63 | # Method called if attribute is unknown 64 | def __getattr__(self, attribute): 65 | print('__getattr__: unknown attribute accessed - ', attribute) 66 | return -1 67 | 68 | # Return the transaction hsitory as the iterable object for an Account 69 | # and any subclass of Account 70 | def __iter__(self): 71 | return iter(self.history) 72 | 73 | # Provide internal support for adding transactions 74 | # Note by convention methods starting with an '_' shoudl not be called 75 | # by clients of this class 76 | def _add_transaction(self, transaction): 77 | self.history.append(transaction) 78 | 79 | # These are convenience methods to make it easier to 80 | # record a deposit or withdrawal. 81 | def _add_deposit_transaction(self, amount): 82 | self._add_transaction(Transaction(self.get_next_transaction_id(), 'deposit', amount)) 83 | 84 | def _add_withdraw_transaction(self, amount): 85 | self._add_transaction(Transaction(self.get_next_transaction_id(), 'withdraw', amount)) 86 | 87 | def deposit(self, amount): 88 | if amount < 0: 89 | print('You cannot deposit negative amounts') 90 | raise AmountError(account=self, msg='Cannot deposit negative amounts') 91 | else: 92 | self._balance += amount 93 | self._add_deposit_transaction(amount) 94 | 95 | def withdraw(self, amount): 96 | if amount < 0: 97 | print('You cannot withdraw negative amounts') 98 | raise AmountError(self, 'Cannot withdraw negative amounts') 99 | elif self.balance - amount < self.overdraft_limit: 100 | print('Withdrawal would exceed your overdraft limit') 101 | raise BalanceError(self) 102 | else: 103 | self._balance -= amount 104 | self._add_withdraw_transaction(amount) 105 | 106 | @property 107 | def balance(self): 108 | """ Provides the current balance """ 109 | return self._balance 110 | 111 | def __str__(self): 112 | return 'Account[' + self.account_number + '] - ' + \ 113 | self.account_holder + ', account = ' + str(self.balance) + \ 114 | 'overdraft limit: ' + str(self.overdraft_limit) 115 | 116 | 117 | -------------------------------------------------------------------------------- /chapter24/exercise/write_account_info.py: -------------------------------------------------------------------------------- 1 | import fintech.accounts as accounts 2 | import pymysql 3 | 4 | def write_account_transaction_to_db(filename, account): 5 | print('Starting write of DB example') 6 | 7 | # Open database connection 8 | connection = pymysql.connect('localhost', 'user', 'password', 'accounts') 9 | 10 | # prepare a cursor object using cursor() method 11 | cursor = connection.cursor() 12 | 13 | try: 14 | # Execute INSERT command 15 | account_number = account.account_number 16 | name = account.account_holder 17 | cursor.execute( 18 | "INSERT INTO acc_info (idacc_info, name) " + 19 | "VALUES (" + account_number + ", '" + name + "')") 20 | # Commit the changes to the database 21 | 22 | # Write out the transactions 23 | for transaction in account.history: 24 | id = transaction.id 25 | action = transaction.action 26 | amount = transaction.amount 27 | statement = "INSERT into transactions (idtransactions, type, amount, account) VALUES (" + str(id) + ", '" + action + "', " + str(amount) + ", " + str(account_number) + ")" 28 | print(statement) 29 | cursor.execute(statement) 30 | connection.commit() 31 | except Exception as exp: 32 | # Something went wrong 33 | # rollback the changes 34 | print(exp) 35 | connection.rollback() 36 | 37 | # Close the database connection 38 | connection.close() 39 | 40 | print('Done Write DB Example') 41 | 42 | 43 | 44 | print('Starting') 45 | acc = accounts.CurrentAccount('123', 'John', 10.05, 100.0) 46 | acc.deposit(23.45) 47 | acc.withdraw(12.33) 48 | 49 | print('Writing Account Transactions') 50 | write_account_transaction_to_db('accounts.xlsx', acc) 51 | 52 | print('Done') 53 | 54 | 55 | -------------------------------------------------------------------------------- /chapter24/insert2.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | 3 | # Open database connection 4 | connection = pymysql.connect('localhost', 'user', 'password', 'uni-database') 5 | connection.autocommit(False) 6 | 7 | # prepare a cursor object using cursor() method 8 | cursor = connection.cursor() 9 | 10 | try: 11 | # Execute INSERT command 12 | cursor.execute( 13 | "INSERT INTO students (id, name, surname, subject, email) VALUES (7, 'Denise', 'Byrne', 'History', 'db@my.com')") 14 | # Commit the changes to the database 15 | connection.commit() 16 | except: 17 | # Something went wrong 18 | # rollback the changes 19 | connection.rollback() 20 | 21 | # Close the database connection 22 | connection.close() 23 | -------------------------------------------------------------------------------- /chapter24/mongo_examples.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | 3 | print('Establishing a connection') 4 | client = pymongo.MongoClient() 5 | 6 | print('Obtain bookshop database') 7 | db = client.bookshop 8 | print(db) 9 | 10 | print('Access the books collection') 11 | books = db.books 12 | 13 | print('Create a book "document"') 14 | book = { 15 | 'author': 'Adam Cooke', 16 | 'title': 'Python Is Great', 17 | 'price': 12.99 18 | } 19 | 20 | print('Insert book') 21 | result = books.insert_one(book) 22 | print('Inserted book with id:', result.inserted_id) 23 | 24 | print('Select a book') 25 | result = books.find_one({'author': 'Adam Cooke'}) 26 | print(result) 27 | 28 | results = books.find({'author': 'Adam Cooke'}) 29 | for book in results: 30 | print('book:', book) 31 | 32 | print('Deleting a document') 33 | result = books.delete_one({'author': 'Adam Cooke'}) 34 | print('Deleted', result.deleted_count, 'books') 35 | 36 | print('Closing connection') 37 | client.close() 38 | -------------------------------------------------------------------------------- /chapter24/query1.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | 3 | # Open database connection 4 | connection = pymysql.connect('localhost', 'user', 'password', 'uni-database') 5 | 6 | # prepare a cursor object using cursor() method 7 | cursor = connection.cursor() 8 | 9 | # execute SQL query using execute() method. 10 | cursor.execute('SELECT * FROM students') 11 | 12 | print('cursor.rowcount', cursor.rowcount) 13 | print('cursor.description', cursor.description) 14 | 15 | # Fetch all the rows and then iterate over the data 16 | data = cursor.fetchall() 17 | for row in data: 18 | print('row:', row) 19 | 20 | # disconnect from server 21 | connection.close() 22 | -------------------------------------------------------------------------------- /chapter24/query2.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | 3 | 4 | class Student: 5 | def __init__(self, id, name, surname, subject, email): 6 | self.id = id 7 | self.name = name 8 | self.surname = surname 9 | self.subject = subject 10 | self.email = email 11 | 12 | def __str__(self): 13 | return 'Student[' + str(id) + '] ' + name + ' ' + surname + ' - ' + subject + ' ' + email 14 | 15 | 16 | # Open database connection 17 | connection = pymysql.connect('localhost', 'user', 'password', 'uni-database') 18 | 19 | # prepare a cursor object using cursor() method 20 | cursor = connection.cursor() 21 | 22 | # execute SQL query using execute() method. 23 | cursor.execute('SELECT * FROM students') 24 | 25 | # Fetch all the rows 26 | data = cursor.fetchall() 27 | 28 | # Convert data into Student objects 29 | for row in data: 30 | student_id, name, surname, subject, email = row 31 | student = Student(student_id, name, surname, subject, email) 32 | print(student) 33 | 34 | # disconnect from server 35 | connection.close() 36 | -------------------------------------------------------------------------------- /chapter24/update3.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | 3 | # Open database connection 4 | connection = pymysql.connect('localhost', 'user', 'password', 'uni-database') 5 | connection.autocommit(False) 6 | 7 | # prepare a cursor object using cursor() method 8 | cursor = connection.cursor() 9 | 10 | try: 11 | # Execute UPDATE command 12 | cursor.execute("UPDATE students SET email = 'denise@my.com' WHERE id = 7") 13 | 14 | # Commit the changes to the database 15 | connection.commit() 16 | except: 17 | # rollback the changes if an exception / error 18 | connection.rollback() 19 | 20 | # Close the database connection 21 | connection.close() 22 | -------------------------------------------------------------------------------- /chapter26/exercises/accounts-app.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.config 3 | import yaml 4 | import fintech.accounts as accounts 5 | 6 | with open('accounts.logging.config.yaml', 'r') as f: 7 | config = yaml.safe_load(f.read()) 8 | logging.config.dictConfig(config) 9 | 10 | logger = logging.getLogger() 11 | 12 | acc1 = accounts.CurrentAccount('123', 'John', 10.05, 100.0) 13 | acc2 = accounts.DepositAccount('345', 'John', 23.55, 0.5) 14 | acc3 = accounts.InvestmentAccount('567', 'Phoebe', 12.45, 'high risk') 15 | 16 | logger.info(acc1) 17 | logger.info(acc2) 18 | logger.info(acc3) 19 | 20 | acc1.deposit(23.45) 21 | acc1.withdraw(12.33) 22 | logger.info('balance:', acc1.balance) 23 | 24 | logger.info('Number of Account instances created:', accounts.Account.instance_count) 25 | 26 | try: 27 | logger.info('balance:', acc1.balance) 28 | acc1.withdraw(300.00) 29 | logger.info('balance:', acc1.balance) 30 | except accounts.BalanceError as e: 31 | logger.error('Handling a Balance Exception') 32 | logger.exception(e) 33 | 34 | with accounts.CurrentAccount ('891', 'Adam', 5.0, 50.0) as acc: 35 | acc.deposit(23.0) 36 | acc.withdraw(12.50) 37 | logger.info(acc.balance) 38 | 39 | logger.info('acc1.branch:', acc1.branch) 40 | 41 | for transaction in acc1: 42 | logger.info(transaction) 43 | 44 | try: 45 | acc1.deposit(-1.0) 46 | except accounts.AmountError as e: 47 | logger.error('Exception following a deposit') 48 | logger.exception(e) 49 | -------------------------------------------------------------------------------- /chapter26/exercises/accounts.logging.config.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | formatters: 3 | myformatter: 4 | format: '%(asctime)s [%(levelname)s] %(name)s.%(funcName)s: %(message)s' 5 | handlers: 6 | console: 7 | class: logging.StreamHandler 8 | level: DEBUG 9 | formatter: myformatter 10 | stream: ext://sys.stdout 11 | loggers: 12 | fintech.accounts: 13 | level: DEBUG 14 | handlers: [console] 15 | propagate: no 16 | root: 17 | level: ERROR 18 | handlers: [console] -------------------------------------------------------------------------------- /chapter26/exercises/fintech/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter26/exercises/fintech/__init__.py -------------------------------------------------------------------------------- /chapter26/logging.config.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | formatters: 3 | myformatter: 4 | format: '%(asctime)s [%(levelname)s] %(name)s.%(funcName)s: %(message)s' 5 | handlers: 6 | console: 7 | class: logging.StreamHandler 8 | level: DEBUG 9 | formatter: myformatter 10 | stream: ext://sys.stdout 11 | loggers: 12 | myLogger: 13 | level: DEBUG 14 | handlers: [console] 15 | propagate: no 16 | root: 17 | level: ERROR 18 | handlers: [console] -------------------------------------------------------------------------------- /chapter26/logging_example.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import printer_lib 3 | 4 | logging.basicConfig(filename='example.log', format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') 5 | 6 | logger = logging.getLogger(__name__) 7 | logger.setLevel(logging.DEBUG) 8 | 9 | def main(): 10 | logger.warning('This is a warning!') 11 | logger.info('This is just for information') 12 | logger.debug('This is to help with debugging') 13 | logger.error('This should be used with something unexpected') 14 | logger.critical('Something serious') 15 | 16 | logger.warning('%s is set to %d', 'count', 42) 17 | 18 | try: 19 | x = 1 / 0 20 | print(x) 21 | except: 22 | logger.exception('an exception message') 23 | 24 | printer_lib.do_something() 25 | 26 | pr = printer_lib.Printer() 27 | pr.print_something() 28 | 29 | 30 | if __name__ == '__main__': 31 | main() 32 | -------------------------------------------------------------------------------- /chapter26/logging_example1.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logging.basicConfig() 4 | logger = logging.getLogger() 5 | 6 | logger.info('This should be used with something unexpected') 7 | -------------------------------------------------------------------------------- /chapter26/logging_example10.py: -------------------------------------------------------------------------------- 1 | # Filter example 2 | 3 | import logging 4 | 5 | 6 | # Define a filter subclass 7 | class MyFilter(logging.Filter): 8 | 9 | def filter(self, record): 10 | if 'John' in record.msg: 11 | return False 12 | else: 13 | return True 14 | 15 | 16 | logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG) 17 | 18 | # Set up the filter on the logger 19 | logger = logging.getLogger(__name__) 20 | logger.addFilter(MyFilter()) 21 | 22 | # Application code with logging 23 | logger.debug('This is to help with debugging') 24 | logger.info('This is information on John') 25 | -------------------------------------------------------------------------------- /chapter26/logging_example11.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.config 3 | import yaml 4 | 5 | with open('logging.config.yaml', 'r') as f: 6 | config = yaml.safe_load(f.read()) 7 | logging.config.dictConfig(config) 8 | 9 | logger = logging.getLogger('myLogger') 10 | 11 | 12 | # 'application' code 13 | def do_something(): 14 | logger.debug('debug message') 15 | logger.info('info message') 16 | logger.warning('warn message') 17 | logger.error('error message') 18 | logger.critical('critical message') 19 | 20 | 21 | logger.info('Starting') 22 | do_something() 23 | logger.info('Done') 24 | -------------------------------------------------------------------------------- /chapter26/logging_example2.py: -------------------------------------------------------------------------------- 1 | # Setting the default format for log message output 2 | 3 | import logging 4 | 5 | logging.basicConfig(format='%(asctime)s - %(message)s') 6 | 7 | logger = logging.getLogger() 8 | 9 | logger.debug('This is to help with debugging') 10 | logger.error('This should be used with something unexpected') 11 | logger.critical('Something serious') 12 | 13 | -------------------------------------------------------------------------------- /chapter26/logging_example3.py: -------------------------------------------------------------------------------- 1 | # Using the logger.exception() method 2 | 3 | import logging 4 | 5 | logger = logging.getLogger() 6 | 7 | try: 8 | print('starting') 9 | x = 1 / 0 10 | print(x) 11 | except: 12 | logger.exception('an exception message') 13 | 14 | print('Done') 15 | -------------------------------------------------------------------------------- /chapter26/logging_example4.py: -------------------------------------------------------------------------------- 1 | # Root looger exmaple 2 | 3 | import logging 4 | 5 | # Set the root logger level 6 | logging.basicConfig(level=logging.DEBUG) 7 | 8 | # Use root (default) logger 9 | logging.debug('This is to help with debugging') 10 | logging.info('This is just for information') 11 | logging.warning('This is a warning!') 12 | logging.error('This should be used with something unexpected') 13 | logging.critical('Something serious') 14 | 15 | -------------------------------------------------------------------------------- /chapter26/logging_example5.py: -------------------------------------------------------------------------------- 1 | # Accessing named loggers 2 | 3 | import logging 4 | 5 | logger = logging.getLogger() 6 | print('Root logger:', logger) 7 | 8 | logger1 = logging.getLogger('my logger') 9 | print('Named logger:', logger1) 10 | 11 | logger2 = logging.getLogger(__name__) 12 | print('Module logger:', logger2) 13 | 14 | -------------------------------------------------------------------------------- /chapter26/logging_example6.py: -------------------------------------------------------------------------------- 1 | # Formatting examples 2 | 3 | import logging 4 | 5 | # Several different formatting options - try uncommenting different ones 6 | # logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG) 7 | # logging.basicConfig(format='%(asctime)s[%(levelname)s] %(funcName)s: %(message)s', level=logging.DEBUG) 8 | logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.DEBUG) 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | 13 | def do_something(): 14 | logger.debug('This is to help with debugging') 15 | logger.info('This is just for information') 16 | logger.warning('This is a warning!') 17 | logger.error('This should be used with something unexpected') 18 | logger.critical('Something serious') 19 | 20 | 21 | do_something() 22 | -------------------------------------------------------------------------------- /chapter26/logging_example7.py: -------------------------------------------------------------------------------- 1 | # Example of logging to a file 2 | 3 | import logging 4 | 5 | # Sets a file handler ont he root logger to 6 | # save log messages to the example.log file 7 | logging.basicConfig(filename='example.log',level=logging.DEBUG) 8 | 9 | # If no handler is explicitly set on the name logger 10 | # it will delegate the messages to the parent logger to handle 11 | logger = logging.getLogger(__name__) 12 | 13 | logger.debug('This is to help with debugging') 14 | logger.info('This is just for information') 15 | logger.warning('This is a warning!') 16 | logger.error('This should be used with something unexpected') 17 | logger.critical('Something serious') -------------------------------------------------------------------------------- /chapter26/logging_example8.py: -------------------------------------------------------------------------------- 1 | # Programmatically setting the handler 2 | 3 | import logging 4 | 5 | # Empty basic config turns off default console handler 6 | logging.basicConfig() 7 | logger = logging.getLogger(__name__) 8 | logger.setLevel(logging.DEBUG) 9 | 10 | # create file handler which logs to the specified file 11 | file_handler = logging.FileHandler('detailed.log') 12 | 13 | # Create formatter for the file_handler 14 | formatter = logging.Formatter('%(asctime)s - %(funcName)s - %(message)s') 15 | file_handler.setFormatter(formatter) 16 | 17 | logger.addHandler(file_handler) 18 | 19 | 20 | # 'application' code 21 | def do_something(): 22 | logger.debug('debug message') 23 | logger.info('info message') 24 | logger.warning('warn message') 25 | logger.error('error message') 26 | logger.critical('critical message') 27 | 28 | 29 | logger.info('Starting') 30 | do_something() 31 | logger.info('Done') 32 | 33 | -------------------------------------------------------------------------------- /chapter26/logging_example9.py: -------------------------------------------------------------------------------- 1 | # Multiple Handlers and formatters 2 | import logging 3 | 4 | # Set up the default root logger to do nothing 5 | logging.basicConfig(handlers=[logging.NullHandler()]) 6 | 7 | # Obtain the module level logger and set level to DEBUG 8 | logger = logging.getLogger(__name__) 9 | logger.setLevel(logging.DEBUG) 10 | 11 | # Create file handler 12 | file_handler = logging.FileHandler('detailed.log') 13 | 14 | # Create console handler with a higher log level 15 | console_handler = logging.StreamHandler() 16 | console_handler.setLevel(logging.WARNING) 17 | 18 | # Create formatter for the file handler 19 | fh_formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(name)s.%(funcName)s: %(message)s', 20 | datefmt='%m-%d-%Y %I:%M:%S %p') 21 | file_handler.setFormatter(fh_formatter) 22 | 23 | # Create formatter for the console handler 24 | console_formatter = logging.Formatter('%(asctime)s - %(funcName)s - %(message)s') 25 | console_handler.setFormatter(console_formatter) 26 | 27 | # Add the handlers to logger 28 | logger.addHandler(console_handler) 29 | logger.addHandler(file_handler) 30 | 31 | 32 | # 'application' code 33 | def do_something(): 34 | logger.debug('debug message') 35 | logger.info('info message') 36 | logger.warning('warn message') 37 | logger.error('error message') 38 | logger.critical('critical message') 39 | 40 | 41 | logger.info('Starting') 42 | do_something() 43 | logger.info('Done') 44 | -------------------------------------------------------------------------------- /chapter26/printer_lib.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logger = logging.getLogger(__name__) 4 | logger.setLevel(logging.DEBUG) 5 | 6 | logger.warning('Well how about that then!') 7 | 8 | 9 | def do_something(): 10 | logger.info('do something!') 11 | 12 | 13 | class Printer: 14 | 15 | def print_something(self): 16 | logger.info('print it') 17 | print('something') 18 | -------------------------------------------------------------------------------- /chapter28/exercises/printer_threading_app.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | from time import sleep 3 | from random import randint 4 | 5 | 6 | def printer(msg, max_sleep): 7 | for _ in range(0, 10): 8 | time_to_sleep = randint(1, max_sleep) 9 | sleep(time_to_sleep) 10 | print(msg, end='') 11 | 12 | 13 | t1 = Thread(target=printer, args=('A', 10)) 14 | t2 = Thread(target=printer, args=('B', 5)) 15 | t3 = Thread(target=printer, args=('C', 15)) 16 | t4 = Thread(target=printer, args=('D', 7)) 17 | t5 = Thread(target=printer, args=('E', 2)) 18 | 19 | t1.start() 20 | t2.start() 21 | t3.start() 22 | t4.start() 23 | t5.start() 24 | -------------------------------------------------------------------------------- /chapter28/threads.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | 3 | 4 | def simple_worker(): 5 | print('hello') 6 | 7 | 8 | # Create a new thread and start it 9 | # The thread will run the function simple_worker 10 | t1 = Thread(target=simple_worker) 11 | t1.start() 12 | -------------------------------------------------------------------------------- /chapter28/threads1.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | 3 | 4 | def simple_worker(): 5 | print('hello') 6 | 7 | 8 | t1 = Thread(target=simple_worker) 9 | t1.start() 10 | 11 | # Get information about a Thread 12 | print(t1.getName()) 13 | print(t1.ident) 14 | print(t1.is_alive()) 15 | -------------------------------------------------------------------------------- /chapter28/threads2.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | from time import sleep 3 | 4 | 5 | def worker(): 6 | for i in range(0, 10): 7 | print('.', end='', flush=True) 8 | sleep(1) 9 | 10 | 11 | print('Starting') 12 | 13 | # Create read object with reference to worker function 14 | t = Thread(target=worker) 15 | # Start the thread object
 16 | t.start() 17 | # Wait for the thread to complete
 18 | t.join() 19 | 20 | print('\nDone') 21 | -------------------------------------------------------------------------------- /chapter28/threads3.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | from time import sleep 3 | 4 | 5 | def worker(msg): 6 | for i in range(0, 10): 7 | print(msg, end='', flush=True) 8 | sleep(1) 9 | 10 | 11 | print('Starting') 12 | t1 = Thread(target=worker, args='A') 13 | t2 = Thread(target=worker, args='B') 14 | t3 = Thread(target=worker, args='C') 15 | t1.start() 16 | t2.start() 17 | t3.start() 18 | print('Done') 19 | 20 | -------------------------------------------------------------------------------- /chapter28/threads4.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | from time import sleep 3 | 4 | # Example extending the Thread class 5 | 6 | class WorkerThread(Thread): 7 | def __init__(self, daemon=None, target=None, name=None): 8 | super().__init__(daemon=daemon, target=target, name=name) 9 | 10 | def run(self): 11 | for i in range(0, 10): 12 | print('.', end='', flush=True) 13 | sleep(1) 14 | 15 | 16 | print('Starting') 17 | t = WorkerThread() 18 | t.start() 19 | print('\nDone') 20 | -------------------------------------------------------------------------------- /chapter28/threads5.py: -------------------------------------------------------------------------------- 1 | from threading import Thread 2 | from time import sleep 3 | 4 | 5 | def worker(msg): 6 | for i in range(0, 10): 7 | print(msg, end='', flush=True) 8 | sleep(1) 9 | 10 | print('Starting') 11 | 12 | # Create a daemon thread 13 | d = Thread(daemon=True, target=worker, args='C') 14 | d.start() 15 | 16 | sleep(5) 17 | print('Done') -------------------------------------------------------------------------------- /chapter28/threads6.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from threading import Thread 3 | from time import sleep 4 | 5 | 6 | def worker(msg): 7 | for i in range(0, 10): 8 | print(msg, end='', flush=True) 9 | sleep(1) 10 | 11 | # Start two normal threads and a daemon thread 12 | 13 | 14 | t1 = Thread(name='worker', target=worker, args='A') 15 | t2 = Thread(target=worker, args='B') # use default name e.g. Thread-1 16 | d = Thread(daemon = True, name='daemon', target=worker, args='C') 17 | 18 | t1.start() 19 | t2.start() 20 | d.start() 21 | 22 | print() 23 | for t in threading.enumerate(): 24 | print(t.getName()) 25 | -------------------------------------------------------------------------------- /chapter28/threads7.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, local, currentThread 2 | from random import randint 3 | 4 | 5 | def show_value(data): 6 | try: 7 | val = data.value 8 | except AttributeError: 9 | print(currentThread().name, ' - No value yet') 10 | else: 11 | print(currentThread().name, ' - value =', val) 12 | 13 | 14 | def worker(data): 15 | show_value(data) 16 | data.value = randint(1, 100) 17 | show_value(data) 18 | 19 | 20 | print(currentThread().name, ' - Starting') 21 | 22 | # Create thread local data object 23 | local_data = local() 24 | show_value(local_data) 25 | 26 | for i in range(2): 27 | t = Thread(name='W' + str(i), 28 | target=worker, args=[local_data]) 29 | t.start() 30 | 31 | show_value(local_data) 32 | print(currentThread().name, ' - Done') 33 | -------------------------------------------------------------------------------- /chapter28/timer_example.py: -------------------------------------------------------------------------------- 1 | from threading import Timer 2 | 3 | 4 | def hello(): 5 | print("hello") 6 | 7 | 8 | print('Starting') 9 | 10 | # Set up timer to wait 5 seconds 11 | # and then run hello function 12 | t = Timer(5, hello) 13 | t.start() 14 | 15 | print('Done') 16 | -------------------------------------------------------------------------------- /chapter29/exercises/multiprocessing_factorial.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Pool 2 | 3 | 4 | def factorial(num): 5 | if num == 0: 6 | return 1 7 | else: 8 | factorial_value = 1 9 | for i in range(1, num + 1): 10 | factorial_value = factorial_value * i 11 | return factorial_value 12 | 13 | 14 | data = (5, 8, 10, 15, 3, 6, 4) 15 | 16 | # Collect results into a list and print using pool.map 17 | with Pool(processes=4) as pool: 18 | results = pool.map(factorial, data) 19 | print(results) 20 | -------------------------------------------------------------------------------- /chapter29/multiprocessing1.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Process 2 | from time import sleep 3 | 4 | 5 | def worker(msg): 6 | for i in range(0, 10): 7 | print(msg, end='', flush=True) 8 | sleep(1) 9 | 10 | 11 | print('Starting') 12 | 13 | t2 = Process(target=worker, args='A') 14 | t3 = Process(target=worker, args='B') 15 | t4 = Process(target=worker, args='C') 16 | 17 | t2.start() 18 | t3.start() 19 | t4.start() 20 | 21 | print('Done') 22 | -------------------------------------------------------------------------------- /chapter29/multiprocessing2.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Process 2 | from multiprocessing import set_start_method 3 | from time import sleep 4 | import os 5 | 6 | 7 | def worker(msg): 8 | print('module name:', __name__) 9 | print('parent process:', os.getppid()) 10 | print('process id:', os.getpid()) 11 | for i in range(0, 10): 12 | print(msg, end='', flush=True) 13 | sleep(1) 14 | 15 | 16 | def main(): 17 | print('Starting') 18 | print('Root application process id:', os.getpid()) 19 | set_start_method('spawn') 20 | t = Process(target=worker, args='A') 21 | t.start() 22 | 23 | print('Done') 24 | 25 | 26 | if __name__ == '__main__': 27 | main() 28 | -------------------------------------------------------------------------------- /chapter29/multiprocessing3.py: -------------------------------------------------------------------------------- 1 | # Using a Pool 2 | from multiprocessing import Pool 3 | 4 | 5 | def worker(x): 6 | print('In worker with: ', x) 7 | return x * x 8 | 9 | 10 | def main(): 11 | with Pool(processes=4) as pool: 12 | print(pool.map(worker, [0, 1, 2, 3, 4, 5])) 13 | 14 | 15 | if __name__ == '__main__': 16 | main() 17 | -------------------------------------------------------------------------------- /chapter29/multiprocessing4.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Pool 2 | 3 | 4 | def worker(x): 5 | print('In worker with: ', x) 6 | return x * x 7 | 8 | 9 | def main(): 10 | with Pool(processes=4) as pool: 11 | for result in pool.imap_unordered(worker, 12 | [0, 1, 2, 3, 4, 5]): 13 | print(result) 14 | 15 | 16 | if __name__ == '__main__': 17 | main() 18 | -------------------------------------------------------------------------------- /chapter29/multiprocessing5.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Pool 2 | 3 | 4 | def collect_results(result): 5 | print('In collect_results: ', result) 6 | 7 | 8 | def worker(x): 9 | print('In worker with: ', x) 10 | return x * x 11 | 12 | 13 | def main(): 14 | with Pool(processes=2) as pool: 15 | # get based example 16 | res = pool.apply_async(worker, [6]) 17 | print('Result from async: ', res.get(timeout=1)) 18 | 19 | with Pool(processes=2) as pool: 20 | # callback based example 21 | pool.apply_async(worker, args=[4], 22 | callback=collect_results) 23 | 24 | 25 | if __name__ == '__main__': 26 | main() 27 | -------------------------------------------------------------------------------- /chapter29/multiprocessing6.py: -------------------------------------------------------------------------------- 1 | # Using a pipe to communicate between two processes 2 | 3 | from multiprocessing import Process, Pipe 4 | from time import sleep 5 | 6 | 7 | def worker(conn): 8 | print('Worker - started now sleeping for 1 second') 9 | sleep(1) 10 | print('Worker - sending data via Pipe') 11 | conn.send('hello') 12 | print('Worker - closing worker end of connection') 13 | conn.close() 14 | 15 | 16 | def main(): 17 | print('Main - Starting, creating the Pipe') 18 | main_connection, worker_connection = Pipe() 19 | print('Main - Setting up the process') 20 | p = Process(target=worker, args=[worker_connection]) 21 | print('Main - Starting the process') 22 | p.start() 23 | print('Main - Wait for a response from the child process') 24 | print(main_connection.recv()) 25 | print('Main - closing parent process end of connection') 26 | main_connection.close() 27 | print('Main - Done') 28 | 29 | 30 | if __name__ == '__main__': 31 | main() 32 | -------------------------------------------------------------------------------- /chapter29/multiprocessing7.py: -------------------------------------------------------------------------------- 1 | # Using shared data between processes 2 | 3 | from multiprocessing import Process, Value, Array 4 | 5 | 6 | def worker(n, a): 7 | n.value = 3.1415927 8 | for i in range(len(a)): 9 | a[i] = -a[i] 10 | 11 | 12 | def main(): 13 | print('Starting') 14 | 15 | num = Value('d', 0.0) 16 | arr = Array('i', range(10)) 17 | 18 | p = Process(target=worker, args=(num, arr)) 19 | p.start() 20 | p.join() 21 | 22 | print(num.value) 23 | print(*arr) 24 | 25 | print('Done') 26 | 27 | 28 | if __name__ == '__main__': 29 | main() 30 | -------------------------------------------------------------------------------- /chapter3/coloured_shapes.py: -------------------------------------------------------------------------------- 1 | # Lets play with some colours 2 | import turtle 3 | from random import randint 4 | 5 | 6 | def get_input_angle(): 7 | """ Obtain input from user and convert to an int""" 8 | message = 'Please provide an angle:' 9 | value_as_string = input(message) 10 | while not value_as_string.isnumeric(): 11 | print('The input must be an integer!') 12 | value_as_string = input(message) 13 | return int(value_as_string) 14 | 15 | 16 | def generate_random_colour(): 17 | """Generates an R,G,B values randomly in range 18 | 0 to 255 """ 19 | r = randint(0, 255) 20 | g = randint(0, 255) 21 | b = randint(0, 255) 22 | return r, g, b 23 | 24 | 25 | print('Set up Screen') 26 | turtle.title('Colourful pattern') 27 | turtle.setup(640, 600) 28 | turtle.hideturtle() 29 | turtle.bgcolor('black') # Set the background colour of the screen 30 | turtle.colormode(255) # Indicates RGB numbers will be in the range 0 to 255 31 | turtle.speed(10) 32 | 33 | angle = get_input_angle() 34 | 35 | print('Start the drawing') 36 | for i in range(0, 200): 37 | turtle.color(generate_random_colour()) 38 | turtle.forward(i) 39 | turtle.right(angle) 40 | 41 | print('Done') 42 | turtle.done() 43 | -------------------------------------------------------------------------------- /chapter3/exercises/draw-hexagons.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | 3 | 4 | # Function to draw a hexagon 5 | def hexagon(): 6 | for _ in range(6): 7 | turtle.forward(50) 8 | turtle.left(60) 9 | 10 | print('Set up') 11 | # Setup window 12 | turtle.title('Hexagons') 13 | turtle.setup(400, 400, 0, 0) 14 | turtle.speed(10) 15 | turtle.hideturtle() 16 | turtle.pencolor('blue') 17 | turtle.tracer(300) 18 | turtle.penup() 19 | turtle.setposition(-30,50) 20 | turtle.pendown() 21 | 22 | print('Start to draw hexagons') 23 | # Draw six hexagons 24 | for _ in range(6): 25 | hexagon() 26 | turtle.forward(50) 27 | turtle.right(60) 28 | 29 | # Ensure that all the drawing is rendered 30 | turtle.update() 31 | 32 | print('Done') 33 | turtle.done() 34 | -------------------------------------------------------------------------------- /chapter3/sample-window1.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | 3 | # set a title for your canvas window 4 | turtle.title('My Turtle Animation') 5 | 6 | # set up the screen size (in pixels) 7 | # set the starting point of the turtle (0, 0) 8 | turtle.setup(width=200, height=200, startx=0, starty=0) 9 | 10 | # sets the pen color to red 11 | turtle.pencolor('red') 12 | 13 | # Draw a square 14 | turtle.forward(50) 15 | turtle.right(90) 16 | turtle.forward(50) 17 | turtle.right(90) 18 | turtle.forward(50) 19 | turtle.right(90) 20 | turtle.forward(50) 21 | turtle.right(90) 22 | 23 | # Add this so that the window will close when clicked on 24 | turtle.exitonclick() 25 | -------------------------------------------------------------------------------- /chapter3/sample-window2.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | 3 | 4 | def setup(): 5 | """ Provide the config for the screen """ 6 | turtle.title('Multiple Squares Animation') 7 | turtle.setup(100, 100, 0, 0) 8 | turtle.hideturtle() 9 | 10 | 11 | def draw_square(size): 12 | """ Draw a square in the current direction """ 13 | turtle.forward(size) 14 | turtle.right(90) 15 | turtle.forward(size) 16 | turtle.right(90) 17 | turtle.forward(size) 18 | turtle.right(90) 19 | turtle.forward(size) 20 | 21 | 22 | setup() 23 | 24 | for _ in range(0, 12): 25 | draw_square(50) 26 | # Rotate the starting direction 27 | turtle.right(120) 28 | 29 | # Add this so that the window will close when clicked on 30 | turtle.exitonclick() 31 | -------------------------------------------------------------------------------- /chapter3/sample-window3.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | 3 | def draw_square(size): 4 | """ Function to draw a square """ 5 | turtle.forward(size) 6 | turtle.right(90) 7 | turtle.forward(size) 8 | turtle.right(90) 9 | turtle.forward(size) 10 | turtle.right(90) 11 | turtle.forward(size) 12 | 13 | 14 | turtle.title('Filled Square Example') 15 | turtle.setup(100, 100, 0, 0) 16 | turtle.hideturtle() 17 | 18 | turtle.pencolor('red') 19 | turtle.fillcolor('yellow') 20 | turtle.begin_fill() 21 | 22 | draw_square(60) 23 | 24 | turtle.end_fill() 25 | turtle.done() 26 | -------------------------------------------------------------------------------- /chapter3/sphere_example.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GLUT import * 2 | from OpenGL.GL import * 3 | 4 | 5 | def display(): 6 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 7 | glPushMatrix() 8 | glRotatef(20.0, 1.0, 0.0, 0.0) 9 | glPushMatrix() 10 | glTranslatef(-0.75, 0.5, 0.0) 11 | glRotatef(90.0, 1.0, 0.0, 0.0) 12 | glutSolidTorus(0.275, 0.85, 15, 15) 13 | glPopMatrix() 14 | 15 | glPushMatrix() 16 | glTranslatef(-0.75, -0.5, 0.0) 17 | glRotatef(270.0, 1.0, 0.0, 0.0) 18 | glutSolidCone(1.0, 2.0, 15, 15) 19 | glPopMatrix() 20 | 21 | glPopMatrix() 22 | glFlush() 23 | 24 | 25 | def reshape(w, h): 26 | glViewport(0, 0, w, h) 27 | glMatrixMode(GL_PROJECTION) 28 | glLoadIdentity() 29 | if w <= h: 30 | glOrtho(-2.5, 2.5, -2.5 * h / w, 31 | 2.5 * h / w, -10.0, 10.0) 32 | else: 33 | glOrtho(-2.5 * w / h, 34 | 2.5 * w / h, -2.5, 2.5, -10.0, 10.0) 35 | glMatrixMode(GL_MODELVIEW) 36 | glLoadIdentity() 37 | 38 | 39 | glutInit() 40 | glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH) 41 | glutInitWindowSize(500, 500) 42 | glutCreateWindow('Scene') 43 | glEnable(GL_LIGHTING) 44 | glEnable(GL_LIGHT0) 45 | glEnable(GL_DEPTH_TEST) 46 | 47 | glutReshapeFunc(reshape) 48 | glutDisplayFunc(display) 49 | glutMainLoop() 50 | -------------------------------------------------------------------------------- /chapter30/barriers-app.py: -------------------------------------------------------------------------------- 1 | from threading import Barrier, Thread 2 | from time import sleep 3 | from random import randint 4 | 5 | 6 | def print_it(msg, barrier): 7 | print('print_it for:', msg) 8 | for i in range(0, 10): 9 | print(msg, end='', flush=True) 10 | sleep(1) 11 | sleep(randint(1, 6)) 12 | print('Wait for barrier with:', msg) 13 | barrier.wait() 14 | print('Returning from print_it:', msg) 15 | 16 | 17 | def callback(): 18 | print('\nCallback Executing') 19 | 20 | 21 | print('Main - Starting') 22 | 23 | barrier = Barrier(3, callback) 24 | t1 = Thread(target=print_it, args=('A', barrier)) 25 | t2 = Thread(target=print_it, args=('B', barrier)) 26 | t3 = Thread(target=print_it, args=('C', barrier)) 27 | t1.start() 28 | t2.start() 29 | t3.start() 30 | 31 | print('Main - Done') 32 | -------------------------------------------------------------------------------- /chapter30/barriers-app2.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Barrier, Process 2 | from time import sleep 3 | from random import randint 4 | 5 | 6 | def print_it(msg, barrier): 7 | print('print_it for:', msg) 8 | for i in range(0, 10): 9 | print(msg, end='', flush=True) 10 | sleep(1) 11 | sleep(randint(1, 6)) 12 | print('Wait for barrier with:', msg) 13 | barrier.wait() 14 | print('Returning from print_it:', msg) 15 | 16 | 17 | def callback(): 18 | print('\nCallback Executing') 19 | 20 | 21 | print('Main - Starting') 22 | barrier = Barrier(3, callback) 23 | t1 = Process(target=print_it, args=('A', barrier)) 24 | t2 = Process(target=print_it, args=('B', barrier)) 25 | t3 = Process(target=print_it, args=('C', barrier)) 26 | t1.start() 27 | t2.start() 28 | t3.start() 29 | print('Main - Done') 30 | -------------------------------------------------------------------------------- /chapter30/cond-app.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, Condition, currentThread 2 | from time import sleep 3 | from random import randint 4 | 5 | class DataResource: 6 | 7 | def __init__(self): 8 | print('DataResource - Initializing the empty data') 9 | self.data = None 10 | print('DataResource - Setting up the Condition object') 11 | self.condition = Condition() 12 | 13 | def consumer(self): 14 | """wait for the condition and use the resource""" 15 | print('DataResource - Starting consumer method in', currentThread().name) 16 | with self.condition: 17 | self.condition.wait() 18 | print('DataResource - Resource is available to', currentThread().name) 19 | print('DataResource - Data read in', currentThread().name, ':', self.data) 20 | 21 | def producer(self): 22 | """set up the resource to be used by the consumer""" 23 | print('DataResource - Starting producer method') 24 | with self.condition: 25 | print('DataResource - Producer setting data') 26 | self.data = randint(1, 100) 27 | print('DataResource - Producer notifying all waiting threads') 28 | self.condition.notifyAll() 29 | 30 | 31 | print('Main - Starting') 32 | print('Main - Creating the DataResource object') 33 | resource = DataResource() 34 | 35 | print('Main - Create the Consumer Threads') 36 | c1 = Thread(target=resource.consumer) 37 | c1.name = 'Consumer1' 38 | c2 = Thread(target=resource.consumer) 39 | c2.name = 'Consumer2' 40 | print('Main - Create the Producer Thread') 41 | p = Thread(target=resource.producer) 42 | 43 | print('Main - Starting consumer threads') 44 | c1.start() 45 | c2.start() 46 | sleep(1) 47 | 48 | print('Main - Starting producer thread') 49 | p.start() 50 | 51 | print('Main - Done') 52 | -------------------------------------------------------------------------------- /chapter30/events-app.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Process, Event 2 | from time import sleep 3 | 4 | 5 | def wait_for_event(event): 6 | print('wait_for_event - Entered and waiting') 7 | event_is_set = event.wait() 8 | print('wait_for_event - Event is set: ', event_is_set) 9 | 10 | 11 | def set_event(event): 12 | print('set_event - Entered but about to sleep') 13 | sleep(5) 14 | print('set_event - Waking up and setting event') 15 | event.set() 16 | print('set_event - Event set') 17 | 18 | 19 | print('Starting') 20 | 21 | # Create the event object 22 | event = Event() 23 | 24 | # Start a Process to wait for the event notification 25 | p1 = Process(target=wait_for_event, args=[event]) 26 | p1.start() 27 | 28 | # Set up a process to set the event 29 | p2 = Process(target=set_event, args=[event]) 30 | p2.start() 31 | 32 | # Wait for the first process to complete 33 | p1.join() 34 | 35 | print('Done') 36 | -------------------------------------------------------------------------------- /chapter30/events-app2.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, Event 2 | from time import sleep 3 | 4 | 5 | def wait_for_event(e): 6 | print('wait_for_event - entered and waiting') 7 | event_is_set = e.wait() 8 | print('wait_for_event - Event is set: ', event_is_set) 9 | 10 | 11 | def set_event(e): 12 | print('set_event - entered but about to sleep') 13 | sleep(5) 14 | print('set_event - Waking up and setting event') 15 | e.set() 16 | print('set_event - Event set') 17 | 18 | 19 | print('Starting') 20 | e = Event() 21 | t1 = Thread(target=wait_for_event, args=[e]) 22 | t1.start() 23 | t2 = Thread(target=set_event, args=[e]) 24 | t2.start() 25 | t1.join() 26 | print('Done') -------------------------------------------------------------------------------- /chapter30/exercises/stack/Stack.py: -------------------------------------------------------------------------------- 1 | from threading import Condition 2 | 3 | class Stack: 4 | 5 | def __init__(self): 6 | self._list = [] # initial internal data 7 | # Set up condition to use to synchronise interactions 8 | self.condition = Condition() 9 | 10 | def push(self, element): 11 | with self.condition: 12 | self._list.append(element) 13 | self.condition.notify() 14 | 15 | def pop(self): 16 | with self.condition: 17 | self.condition.wait() 18 | return self._list.pop() 19 | 20 | def top(self): 21 | return self._list[self.length() - 1] 22 | 23 | def length(self): 24 | return len(self._list) 25 | 26 | def is_empty(self): 27 | return self.length() == 0 28 | 29 | def __str__(self): 30 | return 'Stack: ' + str(self._list) 31 | 32 | -------------------------------------------------------------------------------- /chapter30/exercises/stack/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnehunt/advancedpython3/ed210f539c42fd14f01786274cbab39e74d1c1b9/chapter30/exercises/stack/__init__.py -------------------------------------------------------------------------------- /chapter30/exercises/stack_multithreaded_app.py: -------------------------------------------------------------------------------- 1 | from stack.Stack import Stack 2 | from time import sleep 3 | from threading import Thread 4 | 5 | 6 | def producer(stack): 7 | for i in range(0, 6): 8 | data = 'Task' + str(i) 9 | print('Producer pushing:', data) 10 | stack.push(data) 11 | sleep(2) 12 | 13 | 14 | def consumer(label, stack): 15 | while True: 16 | print(label, 'stack.pop():', stack.pop()) 17 | 18 | 19 | print('Create shared stack') 20 | stack = Stack() 21 | print('Stack:', stack) 22 | 23 | print('Creating and starting consumer threads') 24 | consumer1 = Thread(target=consumer, args=('Consumer1', stack)) 25 | consumer2 = Thread(target=consumer, args=('Consumer2', stack)) 26 | consumer3 = Thread(target=consumer, args=('Consumer3', stack)) 27 | consumer1.start() 28 | consumer2.start() 29 | consumer3.start() 30 | 31 | print('Creating and starting producer thread') 32 | producer = Thread(target=producer, args=[stack]) 33 | producer.start() 34 | -------------------------------------------------------------------------------- /chapter30/locks-app.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, Lock 2 | 3 | 4 | class SharedData(object): 5 | 6 | def __init__(self): 7 | self.value = 0 8 | self.lock = Lock() 9 | 10 | def read_value(self): 11 | try: 12 | print('read_value Acquiring Lock') 13 | self.lock.acquire() 14 | return self.value 15 | finally: 16 | print('read_value releasing Lock') 17 | self.lock.release() 18 | 19 | def change_value(self): 20 | print('change_value acquiring lock') 21 | with self.lock: 22 | self.value = self.value + 1 23 | print('change_value lock released') 24 | 25 | 26 | shared_data = SharedData() 27 | 28 | 29 | def reader(): 30 | while True: 31 | print(shared_data.read_value()) 32 | 33 | 34 | def updater(): 35 | while True: 36 | shared_data.change_value() 37 | 38 | 39 | print('Starting') 40 | 41 | t1 = Thread(target=reader) 42 | t2 = Thread(target=updater) 43 | 44 | t1.start() 45 | t2.start() 46 | 47 | print('Done') 48 | -------------------------------------------------------------------------------- /chapter30/queue-example.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Process, Queue 2 | from time import sleep 3 | 4 | 5 | def worker(queue): 6 | print('Worker - going to sleep') 7 | sleep(2) 8 | print('Worker - woken up and putting data on queue') 9 | queue.put('Hello World') 10 | 11 | 12 | def main(): 13 | print('Main - Starting') 14 | queue = Queue() 15 | p = Process(target=worker, args=[queue]) 16 | print('Main - Starting the process') 17 | p.start() 18 | print('Main - waiting for data') 19 | print(queue.get()) 20 | print('Main - Done') 21 | 22 | 23 | if __name__ == '__main__': 24 | main() 25 | -------------------------------------------------------------------------------- /chapter30/semaphore-app.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, Semaphore, currentThread 2 | from time import sleep 3 | 4 | 5 | def worker(semaphore): 6 | with semaphore: 7 | print(currentThread().getName() + " - entered") 8 | sleep(0.5) 9 | print(currentThread().getName() + " - exiting") 10 | 11 | 12 | print('MainThread - Starting') 13 | 14 | semaphore = Semaphore(2) 15 | for i in range(0, 5): 16 | thread = Thread(name='T' + str(i), target=worker, args=[semaphore]) 17 | thread.start() 18 | 19 | print('MainThread - Done') 20 | -------------------------------------------------------------------------------- /chapter31/exercises/factorial_future.py: -------------------------------------------------------------------------------- 1 | from concurrent.futures import ThreadPoolExecutor 2 | from time import sleep 3 | 4 | 5 | # Function to calculate factorials 6 | def factorial(num): 7 | if num == 0: 8 | return 1 9 | else: 10 | factorial_value = 1 11 | for i in range(1, num + 1): 12 | sleep(0.1) 13 | factorial_value = factorial_value * i 14 | return factorial_value 15 | 16 | 17 | # Function to print the result 18 | def print_future_result(future): 19 | print('In callback Future result: ', future.result()) 20 | 21 | 22 | print('Started') 23 | data = [5, 7, 3, 6] 24 | 25 | pool = ThreadPoolExecutor(5) 26 | for v in data: 27 | future = pool.submit(factorial, v) 28 | future.add_done_callback(print_future_result) 29 | 30 | print('Done') 31 | -------------------------------------------------------------------------------- /chapter31/future1.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | from concurrent.futures import ThreadPoolExecutor 3 | 4 | 5 | # define function to be used with future 6 | def worker(msg): 7 | for i in range(0, 10): 8 | print(msg, end='', flush=True) 9 | sleep(1) 10 | return i 11 | 12 | 13 | print('Setting up the ThreadPoolExecutor') 14 | pool = ThreadPoolExecutor(1) 15 | 16 | # Submit the function ot the pool to run 17 | # concurrently - obtain a future from pool 18 | print('Submitting the worker to the pool') 19 | future = pool.submit(worker, 'A') 20 | 21 | print('Obtained a reference to the future object', future) 22 | 23 | # Obtain the result form the future - wait if necessary 24 | print('future.result():', future.result()) 25 | 26 | print('Done') 27 | -------------------------------------------------------------------------------- /chapter31/future2.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | from concurrent.futures import ProcessPoolExecutor 3 | 4 | 5 | def worker(msg): 6 | for i in range(0, 10): 7 | print(msg, end='', flush=True) 8 | sleep(1) 9 | return i 10 | 11 | 12 | print('Setting up the ThreadPoolExecutor') 13 | pool = ProcessPoolExecutor(1) 14 | 15 | print('Submitting the worker to the pool') 16 | future = pool.submit(worker, 'A') 17 | 18 | print('Obtained a reference to the future object', future) 19 | print('future.result():', future.result()) 20 | print('Done') 21 | -------------------------------------------------------------------------------- /chapter31/future3.py: -------------------------------------------------------------------------------- 1 | # Multiple futures example 2 | 3 | from concurrent.futures import ThreadPoolExecutor 4 | from time import sleep 5 | 6 | 7 | def worker(msg): 8 | for i in range(0, 10): 9 | print(msg, end='', flush=True) 10 | sleep(1) 11 | return i 12 | 13 | 14 | print('Starting...') 15 | pool = ThreadPoolExecutor(3) 16 | future1 = pool.submit(worker, 'A') 17 | future2 = pool.submit(worker, 'B') 18 | future3 = pool.submit(worker, 'C') 19 | future4 = pool.submit(worker, 'D') 20 | print('\nfuture4.result():', future4.result()) 21 | print('All Done') 22 | -------------------------------------------------------------------------------- /chapter31/future4.py: -------------------------------------------------------------------------------- 1 | from concurrent.futures import ProcessPoolExecutor 2 | from time import sleep 3 | 4 | 5 | def worker(msg): 6 | for i in range(0,10): 7 | print(msg,end='', flush=True) 8 | sleep(1) 9 | return i 10 | 11 | 12 | print('Starting...') 13 | pool = ProcessPoolExecutor(3) 14 | future1 = pool.submit(worker, 'A') 15 | future2 = pool.submit(worker, 'B') 16 | future3 = pool.submit(worker, 'C') 17 | future4 = pool.submit(worker, 'D') 18 | print('\nfuture4.result():', future4.result()) 19 | print('All Done') -------------------------------------------------------------------------------- /chapter31/future5.py: -------------------------------------------------------------------------------- 1 | from concurrent.futures import ProcessPoolExecutor 2 | from concurrent.futures import wait 3 | from time import sleep 4 | 5 | 6 | def worker(msg): 7 | for i in range(0,10): 8 | print(msg,end='', flush=True) 9 | sleep(1) 10 | return i 11 | 12 | 13 | print('Starting...setting up pool') 14 | pool = ProcessPoolExecutor(3) 15 | futures = [] 16 | 17 | print('Submitting futures') 18 | future1 = pool.submit(worker, 'A') 19 | futures.append(future1) 20 | future2 = pool.submit(worker, 'B') 21 | futures.append(future2) 22 | future3 = pool.submit(worker, 'C') 23 | futures.append(future3) 24 | future4 = pool.submit(worker, 'D') 25 | futures.append(future4) 26 | 27 | print('Waiting for futures to complete') 28 | wait(futures) 29 | 30 | print('\nAll Done') 31 | -------------------------------------------------------------------------------- /chapter31/future6.py: -------------------------------------------------------------------------------- 1 | from concurrent.futures import ThreadPoolExecutor, as_completed 2 | from time import sleep 3 | from random import randint 4 | 5 | 6 | def is_even(n): 7 | print('Checking if', n , 'is even') 8 | sleep(randint(1, 5)) 9 | return str(n) + ' ' + str(n % 2 == 0) 10 | 11 | 12 | print('Started') 13 | data = [1, 2, 3, 4, 5, 6] 14 | 15 | pool = ThreadPoolExecutor(5) 16 | futures = [] 17 | 18 | for v in data: 19 | futures.append(pool.submit(is_even, v)) 20 | 21 | for f in as_completed(futures): 22 | print(f.result()) 23 | 24 | print('Done') 25 | -------------------------------------------------------------------------------- /chapter31/future7.py: -------------------------------------------------------------------------------- 1 | from concurrent.futures import ThreadPoolExecutor 2 | from time import sleep 3 | from random import randint 4 | 5 | 6 | def is_even(n): 7 | print('Checking if', n, 'is even') 8 | sleep(randint(1, 5)) 9 | return str(n) + ' ' + str(n % 2 == 0) 10 | 11 | 12 | def print_future_result(future): 13 | print('In callback Future result: ', future.result()) 14 | 15 | 16 | print('Started') 17 | data = [1, 2, 3, 4, 5, 6] 18 | 19 | pool = ThreadPoolExecutor(5) 20 | 21 | for v in data: 22 | future = pool.submit(is_even, v) 23 | future.add_done_callback(print_future_result) 24 | 25 | print('Done') 26 | -------------------------------------------------------------------------------- /chapter32/asyncioapp1.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | 4 | 5 | async def do_something(): 6 | print('do_something - will wait for worker') 7 | result = await worker() 8 | print('do_something - result:', result) 9 | 10 | 11 | async def worker(): 12 | print('worker - will take some time') 13 | time.sleep(3) 14 | print('worker - done it') 15 | return 42 16 | 17 | 18 | def main(): 19 | print('Main - Starting') 20 | asyncio.run(do_something()) 21 | print('Main - Done') 22 | 23 | 24 | if __name__ == '__main__': 25 | main() 26 | -------------------------------------------------------------------------------- /chapter32/asyncioapp2.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | 4 | async def worker(): 5 | print('worker - will take some time') 6 | await asyncio.sleep(1) 7 | print('worker - Done it') 8 | return 42 9 | 10 | 11 | def print_it(task): 12 | print('print_it result:', task.result()) 13 | 14 | 15 | async def do_something(): 16 | print('do_something - create task for worker') 17 | task = asyncio.create_task(worker()) 18 | 19 | print('do_something - add a callback') 20 | task.add_done_callback(print_it) 21 | 22 | await task 23 | 24 | # Information on task 25 | print('do_something - task.cancelled():', task.cancelled()) 26 | print('do_something - task.done():', task.done()) 27 | print('do_something - task.result():', task.result()) 28 | print('do_something - task.exception():', task.exception()) 29 | 30 | print('do_something - finished') 31 | 32 | 33 | def main(): 34 | print('Main - Starting') 35 | asyncio.run(do_something()) 36 | print('Main - Done') 37 | 38 | 39 | if __name__ == '__main__': 40 | main() 41 | -------------------------------------------------------------------------------- /chapter32/asyncioapp3.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import random 3 | 4 | 5 | async def worker(): 6 | print('Worker - will take some time') 7 | await asyncio.sleep(1) 8 | result = random.randint(1, 10) 9 | print('Worker - Done it') 10 | return result 11 | 12 | 13 | async def do_something(): 14 | print('do_something - will wait for worker') 15 | # Run three calls to worker concurrently and collect results 16 | results = await asyncio.gather(worker(), worker(), worker()) 17 | print('results from calls:', results) 18 | 19 | 20 | def main(): 21 | print('Main - Starting') 22 | asyncio.run(do_something()) 23 | print('Main - Done') 24 | 25 | 26 | if __name__ == '__main__': 27 | main() 28 | -------------------------------------------------------------------------------- /chapter32/asyncioapp4.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import random 3 | 4 | 5 | async def worker(label): 6 | print('Worker - will take some time') 7 | await asyncio.sleep(1) 8 | result = random.randint(1, 10) 9 | print('Worker - Done it') 10 | return label + str(result) 11 | 12 | 13 | async def do_something(): 14 | print('do_something - will wait for worker') 15 | # Run three calls to worker concurrently and collect results 16 | for async_func in asyncio.as_completed((worker('A'), worker('B'), worker('C'))): 17 | result = await async_func 18 | print('do_something - result:', result) 19 | 20 | 21 | def main(): 22 | print('Main - Starting') 23 | asyncio.run(do_something()) 24 | print('Main - Done') 25 | 26 | 27 | if __name__ == '__main__': 28 | main() 29 | -------------------------------------------------------------------------------- /chapter32/exercises/async_factorial.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | 4 | async def factorial(num): 5 | if num == 0: 6 | return 1 7 | else: 8 | factorial_value = 1 9 | for i in range(1, num + 1): 10 | await asyncio.sleep(0.1) 11 | factorial_value = factorial_value * i 12 | return factorial_value 13 | 14 | 15 | async def calculate_factorials(data): 16 | for async_func in asyncio.as_completed([factorial(v) for v in data]): 17 | result = await async_func 18 | print('calculate_factorials - result:', result) 19 | 20 | 21 | def main(): 22 | print('Main - Starting') 23 | asyncio.run(calculate_factorials([5, 7, 3, 6])) 24 | print('Main - Done') 25 | 26 | 27 | if __name__ == '__main__': 28 | main() 29 | -------------------------------------------------------------------------------- /chapter34/reactive1.py: -------------------------------------------------------------------------------- 1 | import rx 2 | 3 | print('Create the Observable object') 4 | # Create an observable using data in a list 5 | observable = rx.from_list([2, 3, 5, 7]) 6 | 7 | 8 | class PrimeNumberObserver: 9 | """ An Observer class """ 10 | 11 | def on_next(self, value): 12 | print('Object Received', value) 13 | 14 | def on_completed(self): 15 | print('Data Stream Completed') 16 | 17 | def on_error(self, error): 18 | print('Error Occurred', error) 19 | 20 | 21 | def prime_number_reporter(value): 22 | print('Function Received', value) 23 | 24 | 25 | print('Set up Observers / Subscribers') 26 | 27 | # Subscribe a lambda function 28 | observable.subscribe(lambda value: print('Lambda Received', value)) 29 | # Subscribe a named function 30 | observable.subscribe(prime_number_reporter) 31 | # Subscribe an Observer object 32 | observable.subscribe(PrimeNumberObserver()) 33 | 34 | # Use lambdas to set up all three functions 35 | observable.subscribe( 36 | on_next=lambda value: print('Received on_next', value), 37 | on_error=lambda exp: print('Error Occurred', exp), 38 | on_completed=lambda: print('Received completed notification') 39 | ) 40 | 41 | print('Done') 42 | -------------------------------------------------------------------------------- /chapter34/reactive2.py: -------------------------------------------------------------------------------- 1 | # A subscribers example 2 | 3 | import rx 4 | from rx.subjects import Subject 5 | from datetime import datetime 6 | 7 | # You can choose which of these to use 8 | # source = rx.from_([2, 3, 5, 7]) 9 | # source = rx.from_iterable([2, 3, 5, 7]) 10 | source = rx.from_list([2, 3, 5, 7]) 11 | 12 | 13 | class TimeStampSubject(Subject): 14 | """ Class implementing a Subject """ 15 | 16 | def on_next(self, value): 17 | print('Subject Received', value) 18 | super().on_next((value, datetime.now())) 19 | 20 | def on_completed(self): 21 | print('Data Stream Completed') 22 | super().on_completed() 23 | 24 | def on_error(self, error): 25 | print('In Subject - Error Occurred', error) 26 | super().on_error(error) 27 | 28 | 29 | def prime_number_reporter(value): 30 | print('Function Received', value) 31 | 32 | 33 | print('Set up') 34 | 35 | # Create the Subject 36 | subject = TimeStampSubject() 37 | 38 | # Set up subscribers for the subject 39 | subject.subscribe(prime_number_reporter) 40 | subject.subscribe(lambda value: print('Lambda Received', value)) 41 | subject.subscribe( 42 | on_next = lambda value: print('Received on_next', value), 43 | on_error = lambda exp: print('Error Occurred', exp), 44 | on_completed = lambda: print('Received completed notification') 45 | ) 46 | 47 | # Subscribe the Subject to the observable source 48 | source.subscribe(subject) 49 | 50 | print('Done') 51 | -------------------------------------------------------------------------------- /chapter34/reactive3a.py: -------------------------------------------------------------------------------- 1 | import rx 2 | 3 | # Set up an observable 4 | observable = rx.from_list([2, 3, 5]) 5 | 6 | # Subscribe three observers 7 | observable.subscribe(lambda v: print('Lambda1 Received', v)) 8 | observable.subscribe(lambda v: print('Lambda2 Received', v)) 9 | observable.subscribe(lambda v: print('Lambda3 Received', v)) 10 | -------------------------------------------------------------------------------- /chapter34/reactive3b.py: -------------------------------------------------------------------------------- 1 | import rx 2 | from rx.concurrency import NewThreadScheduler, ThreadPoolScheduler, ImmediateScheduler 3 | 4 | observable = rx.from_list([2, 3, 5]) 5 | 6 | observable.subscribe(lambda v: print('Lambda1 Received', v), scheduler=ThreadPoolScheduler(3)) 7 | observable.subscribe(lambda v: print('Lambda2 Received', v), scheduler=ImmediateScheduler()) 8 | observable.subscribe(lambda v: print('Lambda3 Received', v), scheduler=NewThreadScheduler()) 9 | 10 | # As the observable runs in a separate thread we need 11 | # to ensure that the main thread does not terminate 12 | input('Press enter to finish') 13 | -------------------------------------------------------------------------------- /chapter34/reactive4.py: -------------------------------------------------------------------------------- 1 | # Example of a 'cold' Observable 2 | import rx 3 | from rx.concurrency import NewThreadScheduler 4 | import time 5 | 6 | 7 | def observer_function(value): 8 | time.sleep(1) 9 | print(value * value) 10 | 11 | 12 | rx.range(1, 100000, scheduler=NewThreadScheduler())\ 13 | .subscribe(observer_function) 14 | 15 | # As the observable runs in a separate thread need 16 | # ensure that the main thread does not terminate 17 | input('Press enter to finish') -------------------------------------------------------------------------------- /chapter35/exercises/stocks.py: -------------------------------------------------------------------------------- 1 | import rx 2 | from rx import operators as op 3 | 4 | def reporter(value): 5 | print(value) 6 | 7 | stocks = (('APPL', 12.45), ('IBM', 15.55), ('MSFT', 5.66), ('APPL', 13.33)) 8 | 9 | # Select only APPL 10 | source = rx.from_list(stocks).pipe( 11 | op.filter(lambda stock: stock[0] == 'APPL') 12 | ).subscribe(reporter) 13 | 14 | print('-' * 25) 15 | 16 | # ALl stocks over 15.00 17 | source = rx.from_list(stocks).pipe( 18 | op.filter(lambda stock: stock[1] > 15.00) 19 | ).subscribe(reporter) 20 | 21 | print('-' * 25) 22 | 23 | # Find the average 24 | source = rx.from_list(stocks).pipe( 25 | op.map(lambda v: v[1]), 26 | op.average() 27 | ).subscribe(reporter) 28 | 29 | print('=' * 25) 30 | 31 | 32 | stocks2 = (('GOOG', 8.95), ('APPL', 7.65), ('APPL', 12.45), ('MSFT', 5.66), ('GOOG', 7.56), ('IBM', 12.76)) 33 | 34 | source1 = rx.from_list(stocks) 35 | source2 = rx.from_list(stocks2) 36 | 37 | # Find the max 38 | rx.merge(source1, source2).pipe( 39 | op.map(lambda v: v[1]), 40 | op.max() 41 | ).subscribe(reporter) 42 | 43 | print('-' * 25) 44 | 45 | # Find the min 46 | rx.merge(source1, source2).pipe( 47 | op.map(lambda v: v[1]), 48 | op.min() 49 | ).subscribe(reporter) 50 | 51 | print('-' * 25) 52 | 53 | # Only publish unique values 54 | rx.merge(source1, source2).pipe( 55 | op.distinct() 56 | ).subscribe(reporter) -------------------------------------------------------------------------------- /chapter35/reactive_ops1.py: -------------------------------------------------------------------------------- 1 | # Apply a transformation to a data source to convert 2 | # integers into strings 3 | import rx 4 | from rx import operators as op 5 | 6 | # Set up a source with a map function 7 | source = rx.from_list([2, 3, 5, 7]).pipe( 8 | op.map(lambda value: "'" + str(value) + "'") 9 | ) 10 | 11 | # Subscribe a lambda function 12 | source.subscribe(lambda value: print('Lambda Received', 13 | value, 14 | ' is a string ', 15 | isinstance(value, str))) 16 | -------------------------------------------------------------------------------- /chapter35/reactive_ops2.py: -------------------------------------------------------------------------------- 1 | # An example illustrating how to merge two data sources 2 | import rx 3 | 4 | # Set up two sources 5 | source1 = rx.from_list([2, 3, 5, 7]) 6 | source2 = rx.from_list([10, 11, 12]) 7 | 8 | # Use the merge function to create a single observable data stream 9 | rx.merge(source1, source2)\ 10 | .subscribe(lambda v: print(v, end=',')) -------------------------------------------------------------------------------- /chapter35/reactive_ops3.py: -------------------------------------------------------------------------------- 1 | # Filter source for even numbers 2 | import rx 3 | from rx import operators as op 4 | 5 | # Set up a source with a filter 6 | source = rx.from_list([2, 3, 5, 7, 4, 9, 8]).pipe( 7 | op.filter(lambda value: value % 2 == 0) 8 | ) 9 | 10 | # Subscribe a lambda function 11 | source.subscribe(lambda value: print('Lambda Received', value)) 12 | 13 | # Use distinct to suppress duplicates 14 | source = rx.from_list([2, 3, 5, 2, 4, 3, 2]).pipe( 15 | op.distinct() 16 | ) 17 | 18 | # Subscribe a lambda function 19 | source.subscribe(lambda value: print('Received', value)) -------------------------------------------------------------------------------- /chapter35/reactive_ops4.py: -------------------------------------------------------------------------------- 1 | # Example of summing all the values in a data stream 2 | import rx 3 | from rx import operators as op 4 | 5 | # Set up a source 6 | observable = rx.from_list([2, 3, 5, 7]) 7 | # Apply sum function to initial source 8 | observable2 = observable.pipe( 9 | op.sum() 10 | ) 11 | # Subscribe to the result generated by sum 12 | observable2.subscribe(lambda v: print(v)) 13 | 14 | print('-' * 20) 15 | 16 | # Rolling or incremental sum 17 | rx.from_([2, 3, 5, 7]).pipe( 18 | op.scan(lambda subtotal, i: subtotal+i) 19 | ).subscribe(lambda v: print(v)) -------------------------------------------------------------------------------- /chapter35/reactive_ops5.py: -------------------------------------------------------------------------------- 1 | # Example of chaining operators together 2 | import rx 3 | from rx import operators as op 4 | 5 | # Set up a source with a filter and a map 6 | source = rx.from_list([2, 3, 5, 7, 4, 9, 8]) 7 | pipe = source.pipe( 8 | op.filter(lambda value: value % 2 == 0), 9 | op.map(lambda value: "'" + str(value) + "'") 10 | ) 11 | 12 | # Subscribe a lambda function 13 | pipe.subscribe(lambda value: print('Received', value)) 14 | -------------------------------------------------------------------------------- /chapter37/BasicTCPIPSocketServer.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | 4 | def main(): 5 | # Setup names and offices 6 | addresses = {'JOHN': 'C45', 7 | 'DENISE': 'C44', 8 | 'PHOEBE': 'D52', 9 | 'ADAM': 'B23'} 10 | 11 | print('Starting Server') 12 | print('Create the socket') 13 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 14 | 15 | print('Bind the socket to the port') 16 | server_address = (socket.gethostname(), 8084) 17 | print('Starting up on', server_address) 18 | sock.bind(server_address) 19 | 20 | # specifies the number of connections 21 | # before refusing new connections. 22 | print('Listen for incoming connections') 23 | sock.listen(1) 24 | while True: 25 | print('Waiting for a connection') 26 | connection, client_address = sock.accept() 27 | try: 28 | print('Connection from', client_address) 29 | while True: 30 | data = connection.recv(1024).decode() 31 | print('Received: ', data) 32 | if data: 33 | key = str(data).upper() 34 | response = addresses[key] 35 | print('sending data back to the client: ', 36 | response) 37 | connection.sendall(response.encode()) 38 | else: 39 | print('No more data from', client_address) 40 | break 41 | finally: 42 | connection.close() 43 | 44 | 45 | if __name__ == '__main__': 46 | main() 47 | -------------------------------------------------------------------------------- /chapter37/BroadcastClient.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import sys 3 | 4 | # Create a UDP socket - note use of socket.SOCK_DGRAM 5 | # Indicates braodcast datagram 6 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | 8 | # Set the server address 9 | server_address = ('localhost', 10000) 10 | message = b'This is the message. It will be repeated.' 11 | 12 | try: 13 | 14 | # Send data 15 | print('sending {!r}'.format(message)) 16 | sent = sock.sendto(message, server_address) 17 | 18 | # Receive response 19 | print('waiting to receive') 20 | data, server = sock.recvfrom(4096) 21 | print('received {!r}'.format(data)) 22 | 23 | finally: 24 | print('closing socket') 25 | sock.close() 26 | -------------------------------------------------------------------------------- /chapter37/BroadcastServer.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import sys 3 | 4 | # Create a UDP socket - note use of socket.SOCK_DGRAM 5 | # this indicaztes its a broadcast datagram socket not a TCP/IP socket 6 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | 8 | # Bind the socket to the port 9 | server_address = ('localhost', 10000) 10 | print('starting up on {} port {}'.format(*server_address)) 11 | sock.bind(server_address) 12 | 13 | while True: 14 | print('\nwaiting to receive message') 15 | data, address = sock.recvfrom(4096) 16 | 17 | print('received {} bytes from {}'.format( 18 | len(data), address)) 19 | print(data) 20 | 21 | if data: 22 | sent = sock.sendto(data, address) 23 | print('sent {} bytes back to {}'.format( 24 | sent, address)) 25 | -------------------------------------------------------------------------------- /chapter37/MyHttpServer.py: -------------------------------------------------------------------------------- 1 | from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer 2 | from socketserver import ThreadingMixIn 3 | from datetime import datetime 4 | 5 | 6 | # class ThreadingHTTPServer(ThreadingMixIn, HTTPServer): 7 | # """Simple multi-threaded HTTP server """ 8 | # pass 9 | 10 | 11 | class MyHttpRequestHandler(BaseHTTPRequestHandler): 12 | """Very simple request handler. Only supports GET.""" 13 | 14 | def do_GET(self): 15 | print("do_GET() starting to process request") 16 | welcome_msg = 'Hello From Server at ' + str(datetime.today()) 17 | byte_msg = bytes(welcome_msg, 'utf-8') 18 | self.send_response(200) 19 | self.send_header("Content-type", 'text/plain; charset-utf-8') 20 | self.send_header('Content-length', str(len(byte_msg))) 21 | self.end_headers() 22 | print('do_GET() replying with message') 23 | self.wfile.write(byte_msg) 24 | 25 | 26 | def main(): 27 | print('Setting up server') 28 | server_address = ('localhost', 8080) 29 | httpd = ThreadingHTTPServer(server_address, MyHttpRequestHandler) 30 | print('Activating HTTP server') 31 | httpd.serve_forever() 32 | 33 | 34 | if __name__ == '__main__': 35 | main() 36 | -------------------------------------------------------------------------------- /chapter37/MyTCPHandler.py: -------------------------------------------------------------------------------- 1 | import socketserver 2 | 3 | 4 | class MyTCPHandler(socketserver.BaseRequestHandler): 5 | """ 6 | The RequestHandler class for the server. 7 | """ 8 | 9 | def __init__(self, request, client_address, server): 10 | print('Setup names and offices') 11 | self.addresses = {'JOHN': 'C45', 12 | 'DENISE': 'C44', 13 | 'PHOEBE': 'D52', 14 | 'ADAM': 'B23'} 15 | super().__init__(request, client_address, server) 16 | 17 | def handle(self): 18 | print('In Handle') 19 | # self.request is the TCP socket connected to the client 20 | data = self.request.recv(1024).decode() 21 | print('data received:', data) 22 | key = str(data).upper() 23 | response = self.addresses[key] 24 | print('response:', response) 25 | # Send the result back to the client 26 | self.request.sendall(response.encode()) 27 | 28 | 29 | def main(): 30 | print('Setting up server') 31 | server_address = ('localhost', 8084) 32 | print('Creating server') 33 | server = socketserver.TCPServer(server_address, 34 | MyTCPHandler) 35 | print('Activating server') 36 | server.serve_forever() 37 | 38 | 39 | if __name__ == '__main__': 40 | main() 41 | -------------------------------------------------------------------------------- /chapter37/TCPIPSocketClient.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | 4 | def main(): 5 | print('Starting Client') 6 | print('Create a TCP/IP socket') 7 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 | print('Connect the socket to the server port') 9 | server_address = ('localhost', 8084) 10 | print('Connecting to: ', server_address) 11 | sock.connect(server_address) 12 | print('Connected to server') 13 | try: 14 | print('Send data') 15 | message = 'John' 16 | print('Sending: ', message) 17 | sock.send(message.encode()) 18 | data = sock.recv(1024).decode() 19 | print('Received from server: ', data) 20 | finally: 21 | print('Closing socket') 22 | sock.close() 23 | 24 | 25 | if __name__ == '__main__': 26 | main() 27 | -------------------------------------------------------------------------------- /chapter37/exercises/SimpleClient.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | 4 | def get_input(): 5 | message = 'Please provide an input (Date, Time, DataAndTime or -1 to exit): ' 6 | return input(message) 7 | 8 | 9 | def main(): 10 | print('Starting Client') 11 | user_input = get_input() 12 | while user_input != '-1': 13 | try: 14 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15 | sock.connect(('localhost', 8080)) 16 | print('Connected to server') 17 | print('Sending data') 18 | sock.send(user_input.encode()) 19 | data = sock.recv(1024).decode() 20 | print('Received from server: ', data) 21 | finally: 22 | print('Closing socket') 23 | sock.close() 24 | user_input = get_input() 25 | 26 | 27 | if __name__ == '__main__': 28 | main() 29 | -------------------------------------------------------------------------------- /chapter37/exercises/SimpleServer.py: -------------------------------------------------------------------------------- 1 | import socketserver 2 | from datetime import datetime, date 3 | 4 | 5 | class MyTCPHandler(socketserver.BaseRequestHandler): 6 | 7 | def handle(self): 8 | print('In Handle') 9 | # Obtain inpout data 10 | data = self.request.recv(1024).decode() 11 | print('data received:', data) 12 | request = str(data).upper() 13 | if request == 'DATE': 14 | response = str(date.today()) 15 | elif request == 'TIME': 16 | now = datetime.now() 17 | response = now.strftime("%H:%M:%S") 18 | elif request == 'DATEANDTIME': 19 | response = str(datetime.today()) 20 | else: 21 | response = 'UNKNOWN OPTION:' + request 22 | 23 | print('response:', response) 24 | 25 | # Send the result back to the client 26 | self.request.sendall(response.encode()) 27 | 28 | 29 | def main(): 30 | print('Starting') 31 | address = ('localhost', 8080) 32 | server = socketserver.ThreadingTCPServer(address, 33 | MyTCPHandler) 34 | print('Activating server') 35 | server.serve_forever() 36 | 37 | 38 | if __name__ == '__main__': 39 | main() 40 | -------------------------------------------------------------------------------- /chapter38/hello_flask_world.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify 2 | 3 | # Initialise Flask 4 | app = Flask(__name__) 5 | 6 | 7 | # Create a mapping from URL to function 8 | @app.route('/hello', methods=['GET']) 9 | def welcome(): 10 | return jsonify({'msg': 'Hello Flask World'}) 11 | 12 | 13 | # Start up the web service 14 | app.run(debug=True) 15 | -------------------------------------------------------------------------------- /chapter38/hello_flask_world2.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, url_for 2 | 3 | 4 | def create_service(): 5 | app = Flask(__name__) 6 | 7 | @app.route('/hello', methods=['GET']) 8 | def welcome(): 9 | return jsonify({'msg': 'Hello Flask World'}) 10 | 11 | with app.test_request_context(): 12 | print(url_for('welcome')) 13 | 14 | return app 15 | 16 | if __name__ == '__main__': 17 | app = create_service() 18 | app.run(debug=True) 19 | -------------------------------------------------------------------------------- /chapter39/bookshop_service1.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, abort 2 | 3 | 4 | class Book: 5 | """ Represents a book in the bookshop""" 6 | 7 | def __init__(self, isbn, title, author, price): 8 | self.isbn = isbn 9 | self.title = title 10 | self.author = author 11 | self.price = price 12 | 13 | def __str__(self): 14 | return self.title + ' by ' + self.author + ' @ ' + str(self.price) 15 | 16 | def to_json(self): 17 | return { 18 | 'isbn': self.isbn, 19 | 'title': self.title, 20 | 'author': self.author, 21 | 'price': self.price 22 | } 23 | 24 | 25 | class Bookshop: 26 | """Represents the bookshop within the service""" 27 | 28 | def __init__(self, books): 29 | self.books = books 30 | 31 | def get(self, isbn): 32 | if isbn > len(self.books): 33 | abort(404) 34 | return list(filter(lambda b: b.isbn == isbn, self.books))[0] 35 | 36 | def add_book(self, book): 37 | self.books.append(book) 38 | 39 | def delete_book(self, isbn): 40 | self.books = list(filter(lambda b: b.isbn != isbn, self.books)) 41 | 42 | 43 | # Global value used to hold the Bookshop object 44 | bookshop = Bookshop([Book(1, 'XML', 'Gryff Smith', 10.99), 45 | Book(2, 'Java', 'Phoebe Cooke', 12.99), 46 | Book(3, 'Scala', 'Adam Davies', 11.99), 47 | Book(4, 'Python', 'Jasmine Byrne', 15.99)]) 48 | 49 | 50 | def configure_bookshop_service(): 51 | """Configures the Flask Application Object 52 | for the bookshop service""" 53 | app = Flask(__name__) 54 | 55 | @app.route('/book/list', methods=['GET']) 56 | def get_books(): 57 | return jsonify({'books': [b.to_json() for b in bookshop.books]}) 58 | 59 | @app.route('/book/', methods=['GET']) 60 | def get_book(isbn): 61 | book = bookshop.get(isbn) 62 | return jsonify({'book': book.to_json()}) 63 | 64 | return app 65 | 66 | 67 | if __name__ == '__main__': 68 | app = configure_bookshop_service() 69 | app.run(debug=True) 70 | -------------------------------------------------------------------------------- /chapter39/bookshop_service2.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, request, abort, make_response 2 | 3 | from flask.json import JSONEncoder 4 | 5 | 6 | class Book: 7 | def __init__(self, isbn, title, author, price): 8 | self.isbn = isbn 9 | self.title = title 10 | self.author = author 11 | self.price = price 12 | 13 | def __str__(self): 14 | return self.title + ' by ' + self.author + ' @ ' + str(self.price) 15 | 16 | 17 | class BookJSONEncoder(JSONEncoder): 18 | def default(self, obj): 19 | if isinstance(obj, Book): 20 | return { 21 | 'isbn': obj.isbn, 22 | 'title': obj.title, 23 | 'author': obj.author, 24 | 'price': obj.price 25 | } 26 | else: 27 | return super(BookJSONEncoder, self).default(obj) 28 | 29 | 30 | class Bookshop: 31 | def __init__(self, books): 32 | self.books = books 33 | 34 | def get(self, isbn): 35 | if int(isbn) > len(self.books): 36 | abort(404) 37 | return list(filter(lambda b: b.isbn == isbn, self.books))[0] 38 | 39 | def add_book(self, book): 40 | self.books.append(book) 41 | 42 | def delete_book(self, isbn): 43 | self.books = list(filter(lambda b: b.isbn != isbn, self.books)) 44 | 45 | 46 | bookshop = Bookshop([Book(1, 'XML', 'Gryff Smith', 10.99), 47 | Book(2, 'Java', 'Phoebe Cooke', 12.99), 48 | Book(3, 'Scala', 'Adam Davies', 11.99), 49 | Book(4, 'Python', 'Jasmine Byrne', 15.99)]) 50 | 51 | def create_bookshop_service(): 52 | app = Flask(__name__) 53 | app.json_encoder = BookJSONEncoder 54 | 55 | 56 | @app.route('/book/list', methods=['GET']) 57 | def get_books(): 58 | return jsonify({'books': bookshop.books}) 59 | 60 | 61 | @app.route('/book/', methods=['GET']) 62 | def get_book(isbn): 63 | book = bookshop.get(isbn) 64 | return jsonify({'book': book}) 65 | 66 | 67 | @app.route('/book', methods=['POST']) 68 | def create_book(): 69 | print('create book') 70 | if not request.json or not 'isbn' in request.json: 71 | abort(400) 72 | book = Book(request.json['isbn'], 73 | request.json['title'], 74 | request.json.get('author', ""), 75 | float(request.json['price'])) 76 | bookshop.add_book(book) 77 | return jsonify({'book': book}), 201 78 | 79 | 80 | @app.route('/book', methods=['PUT']) 81 | def update_book(): 82 | if not request.json or not 'isbn' in request.json: 83 | abort(400) 84 | isbn = request.json['isbn'] 85 | book = bookshop.get(isbn) 86 | book.title = request.json['title'] 87 | book.author = request.json['author'] 88 | book.price = request.json['price'] 89 | return jsonify({'book': book}), 201 90 | 91 | 92 | @app.route('/book/', methods=['DELETE']) 93 | def delete_book(isbn): 94 | bookshop.delete_book(isbn) 95 | return jsonify({'result': True}) 96 | 97 | 98 | @app.errorhandler(400) 99 | def not_found(error): 100 | return make_response(jsonify({'book': 'Not found'}), 400) 101 | 102 | return app 103 | 104 | if __name__ == '__main__': 105 | app = create_bookshop_service() 106 | app.run(debug=True) 107 | -------------------------------------------------------------------------------- /chapter39/bookshop_service3.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, request, abort, make_response 2 | from flask.json import JSONEncoder 3 | import pymysql 4 | 5 | class Room: 6 | def __init__(self, id, name, description): 7 | self.id = id 8 | self.name = name 9 | self.description = description 10 | 11 | def __str__(self): 12 | return self.id + ' ' + self.name + ' ( ' + self.description + ')' 13 | 14 | 15 | class BookJSONEncoder(JSONEncoder): 16 | def default(self, obj): 17 | if isinstance(obj, Room): 18 | return { 19 | 'id': obj.id, 20 | 'name': obj.name, 21 | 'description': obj.description 22 | } 23 | else: 24 | return super(BookJSONEncoder, self).default(obj) 25 | 26 | 27 | class RoomService: 28 | def __init__(self, rooms=[]): 29 | self.rooms = rooms 30 | 31 | def get(self, id): 32 | if int(id) > len(self.rooms): 33 | abort(404) 34 | return list(filter(lambda b: b.isbn == id, self.rooms))[0] 35 | 36 | def add_room(self, room): 37 | self.rooms.append(room) 38 | 39 | def delete_room(self, id): 40 | self.rooms = list(filter(lambda b: b.isbn != id, self.rooms)) 41 | 42 | 43 | room_service = RoomService() 44 | connection = None 45 | 46 | 47 | def setup_database_connection(): 48 | global connection 49 | # Open database connection 50 | connection = pymysql.connect('localhost', 'user', 'user123', 'room_monitoring') 51 | 52 | 53 | def load_rooms_from_db(): 54 | # prepare a cursor object using cursor() method 55 | cursor = connection.cursor() 56 | # execute SQL query using execute() method. 57 | cursor.execute('SELECT * FROM rooms') 58 | 59 | data = cursor.fetchall() 60 | for row in data: 61 | print(row) 62 | room_service.add_room(Room(int(row[0]), row[1], row[2])) 63 | 64 | # disconnect from server 65 | connection.close() 66 | 67 | 68 | def update_room_in_db(room): 69 | # prepare a cursor object using cursor() method 70 | connection.autocommit(False) 71 | cursor = connection.cursor() 72 | try: 73 | update_string = "UPDATE rooms " 74 | update_string = update_string + "SET name = '" + str(room.name) + "' " 75 | update_string = update_string + "SET description = '" + str(room.description) + "' " 76 | update_string = update_string + "WHERE id = " + str(room.id) 77 | cursor.execute(update_string) 78 | connection.commit() 79 | except: 80 | # Something went wrong 81 | # rollback the changes 82 | connection.rollback() 83 | 84 | 85 | def save_room_in_db(room): 86 | # prepare a cursor object using cursor() method 87 | connection.autocommit(False) 88 | cursor = connection.cursor() 89 | try: 90 | insert_string = "INSERT INTO rooms (id, name, description) VALUES (" 91 | insert_string = insert_string + "'" + str(room.id) + "', " 92 | insert_string = insert_string + "'" + str(room.name) + "', " 93 | insert_string = insert_string + "'" + str(room.description) + "')" 94 | cursor.execute(insert_string) 95 | connection.commit() 96 | except: 97 | # Something went wrong 98 | # rollback the changes 99 | connection.rollback() 100 | 101 | 102 | def delete_room_in_db(room): 103 | connection.autocommit(False) 104 | cursor = connection.cursor() 105 | try: 106 | delete_string = "DELETE FROM students WHERE id = " + str(room.id) 107 | cursor.execute(delete_string) 108 | connection.commit() 109 | except: 110 | # Something went wrong 111 | # rollback the changes 112 | connection.rollback() 113 | 114 | 115 | def create_rooms_service(): 116 | app = Flask(__name__) 117 | app.json_encoder = BookJSONEncoder 118 | 119 | 120 | @app.route('/room/list', methods=['GET']) 121 | def get_rooms(): 122 | return jsonify({'rooms': room_service.rooms}) 123 | 124 | 125 | @app.route('/room/', methods=['GET']) 126 | def get_room(isbn): 127 | room = room_service.get(isbn) 128 | return jsonify({'room': room}) 129 | 130 | 131 | @app.route('/room', methods=['POST']) 132 | def create_room(): 133 | print('create room') 134 | if not request.json or not 'id' in request.json: 135 | abort(400) 136 | room = Room(request.json['id'], 137 | request.json['name'], 138 | request.json.get('description', "")) 139 | # Add the room the cache 140 | room_service.add_room(room) 141 | # Permanently save it to the database 142 | save_room_in_db(room) 143 | return jsonify({'room': room}), 201 144 | 145 | 146 | @app.route('/room', methods=['PUT']) 147 | def update_room(): 148 | if not request.json or not 'id' in request.json: 149 | abort(400) 150 | id = request.json['id'] 151 | room = room_service.get(id) 152 | room.title = request.json['name'] 153 | room.author = request.json['description'] 154 | update_room(room) 155 | return jsonify({'room': room}), 201 156 | 157 | 158 | @app.route('/room/', methods=['DELETE']) 159 | def delete_room(id): 160 | delete_room(room_service.get(id)) 161 | room_service.delete_room(id) 162 | return jsonify({'result': True}) 163 | 164 | 165 | @app.errorhandler(400) 166 | def not_found(error): 167 | return make_response(jsonify({'room': 'Not found'}), 400) 168 | 169 | return app 170 | 171 | 172 | if __name__ == '__main__': 173 | setup_database_connection() 174 | load_rooms_from_db() 175 | app = create_rooms_service() 176 | app.run(debug=True) 177 | -------------------------------------------------------------------------------- /chapter39/image_service4.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from flask import Flask, jsonify, request, send_from_directory, make_response 4 | from werkzeug.utils import secure_filename 5 | 6 | PROJECT_HOME = os.path.dirname(os.path.realpath(__file__)) 7 | UPLOAD_FOLDER = '{}/uploads/'.format(PROJECT_HOME) 8 | 9 | 10 | def create_new_folder(local_dir): 11 | new_path = local_dir 12 | if not os.path.exists(new_path): 13 | os.makedirs(new_path) 14 | return new_path 15 | 16 | 17 | def create_image_service(): 18 | app = Flask(__name__) 19 | app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER 20 | app.config['UPLOAD_EXTENSIONS'] = ['.jpg', '.png', '.gif'] 21 | 22 | 23 | @app.route('/api/image/', methods=['GET']) 24 | def get_image(file): 25 | img_name = secure_filename(file) 26 | return send_from_directory(app.config['UPLOAD_FOLDER'], img_name, as_attachment=True) 27 | 28 | 29 | @app.route('/api/image', methods=['POST']) 30 | def upload_image(): 31 | print('upload_image()') 32 | if request.files['file']: 33 | print(app.config['UPLOAD_FOLDER']) 34 | img = request.files['file'] 35 | img_name = secure_filename(img.filename) 36 | print('Secure version of image name ', img_name) 37 | create_new_folder(app.config['UPLOAD_FOLDER']) 38 | saved_path = os.path.join(app.config['UPLOAD_FOLDER'], img_name) 39 | print("saving to " + str(saved_path)) 40 | img.save(saved_path) 41 | # Return a url to the image 42 | # return send_from_directory(app.config['UPLOAD_FOLDER'], img_name, as_attachment=True) 43 | return 'Success' 44 | else: 45 | return "Where is the image?" 46 | 47 | @app.errorhandler(400) 48 | def not_found(error): 49 | return make_response(jsonify({'file': 'Error'}), 400) 50 | 51 | return app 52 | 53 | 54 | if __name__ == '__main__': 55 | app = create_image_service() 56 | app.run(debug=True) 57 | -------------------------------------------------------------------------------- /chapter4/circles-picture.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | 3 | WIDTH = 640 4 | HEIGHT = 360 5 | 6 | 7 | def setup_window(): 8 | # Set up the window 9 | turtle.title('Circles in My Mind') 10 | turtle.setup(WIDTH, HEIGHT, 0, 0) 11 | turtle.colormode(255) # Indicates RGB numbers will be in the range 0 to 255 12 | turtle.hideturtle() 13 | # Batch drawing to the screen for faster rendering 14 | turtle.tracer(2000) 15 | 16 | # Speed up drawing process 17 | turtle.speed(10) 18 | turtle.penup() 19 | 20 | 21 | def draw_circle(x, y, radius, red=50, green=255, blue=10, width=7): 22 | """ Draw a circle at a specific x, y location. 23 | Then draw four smaller circles recursively""" 24 | colour = (red, green, blue) 25 | 26 | # Recursively drawn smaller circles 27 | if radius > 50: 28 | # Calculate colours and line width for smaller circles 29 | if red < 216: 30 | red = red + 33 31 | green = green - 42 32 | blue = blue + 10 33 | width -= 1 34 | else: 35 | red = 0 36 | green = 255 37 | # Calculate the radius for the smaller circles 38 | new_radius = int(radius / 1.3) 39 | # Drawn four circles 40 | draw_circle(int(x + new_radius), y, new_radius, red, green, blue, width) 41 | draw_circle(x - new_radius, y, new_radius, red, green, blue, width) 42 | draw_circle(x, int(y + new_radius), new_radius, red, green, blue, width) 43 | draw_circle(x, int(y - new_radius), new_radius, red, green, blue, width) 44 | 45 | # Draw the original circle 46 | turtle.goto(x, y) 47 | turtle.color(colour) 48 | turtle.width(width) 49 | turtle.pendown() 50 | turtle.circle(radius) 51 | turtle.penup() 52 | 53 | 54 | # Run the program 55 | print('Starting') 56 | setup_window() 57 | draw_circle(25, -100, 200) 58 | 59 | # Ensure that all the drawing is rendered 60 | turtle.update() 61 | print('Done') 62 | turtle.done() 63 | -------------------------------------------------------------------------------- /chapter4/exercises/fractal_trees.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | 3 | # Set up 'constants' 4 | 5 | # image size 6 | IMAGE_SIZE_X = 500 7 | IMAGE_SIZE_Y = 500 8 | # Determines depth of tree - try 2 and 1.25 as alternatives 9 | FACTOR = 1.45 10 | 11 | 12 | def draw_tree(length, width=9): 13 | color = 'brown' 14 | if length < 1: 15 | return 16 | elif length < 3: 17 | color = 'green' 18 | 19 | if width < 1: 20 | width = 1 21 | 22 | turtle.color(color) 23 | turtle.width(width) 24 | turtle.forward(length) 25 | turtle.left(30) 26 | draw_tree(length / FACTOR, width - 1) 27 | turtle.right(60) 28 | draw_tree(length / FACTOR, width - 1) 29 | turtle.left(30) 30 | turtle.color(color) 31 | turtle.width(width) 32 | turtle.backward(length) 33 | 34 | 35 | def setup_screen(title, background='white', screen_size_x=640, screen_size_y=320, tracer_size=200): 36 | """ Sets up Turtle screen with useful defaults """ 37 | print('Set up Screen') 38 | turtle.title(title) 39 | turtle.setup(screen_size_x, screen_size_y) 40 | turtle.hideturtle() 41 | turtle.penup() 42 | turtle.backward(240) 43 | turtle.tracer(tracer_size) 44 | turtle.bgcolor(background) # Set the background colour of the screen 45 | 46 | 47 | print("Starting ...") 48 | setup_screen('Fractal Tree', screen_size_x=IMAGE_SIZE_X, screen_size_y=IMAGE_SIZE_Y, tracer_size=2000) 49 | 50 | # Ensure tree is centred and pointing in the right direction 51 | turtle.setposition(-50, -140) 52 | turtle.left(90) 53 | turtle.down() 54 | 55 | # Draw the tree 56 | draw_tree(100) 57 | 58 | # Ensure that all the drawing is rendered 59 | turtle.update() 60 | 61 | print('Done') 62 | turtle.done() 63 | -------------------------------------------------------------------------------- /chapter4/mandelbrot.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | 3 | # Set up constants 4 | SCREEN_OFFSET_X = 250 5 | SCREEN_OFFSET_Y = 240 6 | 7 | # max iterations allowed 8 | MAX_ITERATIONS = 255 9 | 10 | # image size 11 | IMAGE_SIZE_X = 512 12 | IMAGE_SIZE_Y = 512 13 | 14 | # Drawing area 15 | MIN_X = -2.0 16 | MAX_X = 1.0 17 | MIN_Y = -1.5 18 | MAX_Y = 1.5 19 | 20 | 21 | def setup_screen(title, background='white', screen_size_x=640, screen_size_y=320, tracer_size=200): 22 | print('Set up Screen') 23 | turtle.title(title) 24 | turtle.setup(screen_size_x, screen_size_y) 25 | turtle.hideturtle() 26 | turtle.penup() 27 | turtle.backward(240) 28 | turtle.tracer(tracer_size) 29 | turtle.bgcolor(background) # Set the background colour of the screen 30 | 31 | 32 | setup_screen('Mandelbrot', screen_size_x=IMAGE_SIZE_X, screen_size_y=IMAGE_SIZE_Y, tracer_size=20000) 33 | turtle.colormode(255) # Indicates RGB numbers will be in the range 0 to 255 34 | 35 | # Generate Mandelbrot 36 | for y in range(IMAGE_SIZE_Y): 37 | zy = y * (MAX_Y - MIN_Y) / (IMAGE_SIZE_Y - 1) + MIN_Y 38 | for x in range(IMAGE_SIZE_X): 39 | zx = x * (MAX_X - MIN_X) / (IMAGE_SIZE_Y - 1) + MIN_X 40 | z = zx + zy * 1j 41 | c = z 42 | for i in range(MAX_ITERATIONS): 43 | if abs(z) > 2.0: 44 | break 45 | z = z * z + c 46 | turtle.color((i % 4 * 64, i % 8 * 32, i % 16 * 16)) 47 | turtle.setposition(x - SCREEN_OFFSET_X, y - SCREEN_OFFSET_Y) 48 | turtle.pendown() 49 | turtle.dot(1) 50 | turtle.penup() 51 | 52 | # Ensure that all the drawing is rendered 53 | turtle.update() 54 | 55 | print('Done') 56 | turtle.done() 57 | -------------------------------------------------------------------------------- /chapter4/snowflake.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | from random import randint 3 | 4 | 5 | def generate_random_colour(): 6 | """Generates an R,G,B values randomly in range 7 | 0 to 255 """ 8 | r = randint(0, 255) 9 | g = randint(0, 255) 10 | b = randint(0, 255) 11 | return r, g, b 12 | 13 | def setup_screen(title, background = 'white'): 14 | print('Set up Screen') 15 | turtle.title(title) 16 | turtle.setup(640, 600) 17 | turtle.hideturtle() 18 | turtle.penup() 19 | turtle.tracer(200) 20 | turtle.bgcolor(background) # Set the background colour of the screen 21 | 22 | def draw_snowflake(size): 23 | """ Draw a picture of a snowflake """ 24 | turtle.penup() 25 | turtle.forward(10 * size) 26 | turtle.left(45) 27 | turtle.pendown() 28 | turtle.color(generate_random_colour()) 29 | 30 | # draw branch 8 times to make a snowflake 31 | for _ in range(8): 32 | draw_branch(size) 33 | turtle.forward(size) 34 | turtle.left(45) 35 | 36 | turtle.penup() 37 | 38 | def draw_branch(size): 39 | """ Draw an individual branch on a snowflake """ 40 | side_branch_size = size / 3 41 | for _ in range(3): 42 | for i in range(3): 43 | turtle.forward(side_branch_size) 44 | turtle.backward(side_branch_size) 45 | turtle.right(45) 46 | turtle.left(90) 47 | turtle.backward(side_branch_size) 48 | turtle.left(45) 49 | turtle.right(90) 50 | 51 | 52 | setup_screen('Snowflakes') 53 | turtle.colormode(255) # Indicates RGB numbers will be in the range 0 to 255 54 | 55 | print("Drawing snowflakes at random locations") 56 | for _ in range(30): 57 | x = randint(-320, 100) 58 | y = randint(-320, 80) 59 | snowflake_size = randint(1, 5) * 10 60 | turtle.goto(x, y) 61 | turtle.right(15) 62 | draw_snowflake(snowflake_size) 63 | 64 | turtle.update() 65 | 66 | print('Done') 67 | turtle.done() 68 | -------------------------------------------------------------------------------- /chapter4/snowflake_koch.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | 3 | # Set up Constants 4 | ANGLES = [60, -120, 60, 0] 5 | SIZE_OF_SNOWFLAKE = 300 6 | 7 | 8 | def get_input_depth(): 9 | """ Obtain input from user and convert to an int""" 10 | message = 'Please provide the depth (0 or a positive interger):' 11 | value_as_string = input(message) 12 | while not value_as_string.isnumeric(): 13 | print('The input must be an integer!') 14 | value_as_string = input(message) 15 | return int(value_as_string) 16 | 17 | 18 | def setup_screen(title, background='white', screen_size_x=640, screen_size_y=320, tracer_size=800): 19 | print('Set up Screen') 20 | turtle.title(title) 21 | turtle.setup(screen_size_x, screen_size_y) 22 | turtle.hideturtle() 23 | turtle.penup() 24 | turtle.backward(240) 25 | # Batch drawing to the screen for faster rendering 26 | turtle.tracer(tracer_size) 27 | turtle.bgcolor(background) # Set the background colour of the screen 28 | 29 | 30 | def draw_koch(size, depth): 31 | if depth > 0: 32 | for angle in ANGLES: 33 | draw_koch(size / 3, depth - 1) 34 | turtle.left(angle) 35 | else: 36 | turtle.forward(size) 37 | 38 | depth = get_input_depth() 39 | 40 | setup_screen('Koch Snowflake (depth ' + str(depth) + ')', 41 | background='black', 42 | screen_size_x=420, screen_size_y=420) 43 | # Set foreground colours 44 | turtle.color('sky blue') 45 | 46 | # Ensure snowflake is centred 47 | turtle.penup() 48 | turtle.setposition(-180,0) 49 | turtle.left(30) 50 | turtle.pendown() 51 | 52 | # Draw three sides of snowflake 53 | for _ in range(3): 54 | draw_koch(SIZE_OF_SNOWFLAKE, depth) 55 | turtle.right(120) 56 | 57 | # Ensure that all the drawing is rendered 58 | turtle.update() 59 | print('Done') 60 | turtle.done() 61 | -------------------------------------------------------------------------------- /chapter5/bar_chart8a.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | # Set up the data 4 | labels = ('Python', 'Scala', 'C#', 'Java', 'PHP') 5 | index = (1, 2, 3, 4, 5) 6 | sizes = [45, 10, 15, 30, 22] 7 | 8 | # Set up the bar chart 9 | pyplot.bar(index, sizes, tick_label=labels) 10 | 11 | # Configure the layout 12 | pyplot.ylabel('Usage') 13 | pyplot.xlabel('Programming Languages') 14 | 15 | # Display the chart 16 | pyplot.show() 17 | -------------------------------------------------------------------------------- /chapter5/bar_chart8b.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | # Set up the data 4 | labels = ('Python', 'Scala', 'C#', 'Java', 'PHP') 5 | index = (1, 2, 3, 4, 5) 6 | sizes = [45, 10, 15, 30, 22] 7 | 8 | # Set up the horizontal bar chart 9 | pyplot.barh(index, sizes, tick_label=labels) 10 | 11 | # Configure the layout 12 | pyplot.ylabel('Usage') 13 | pyplot.xlabel('Programming Languages') 14 | 15 | # Display the chart 16 | pyplot.show() -------------------------------------------------------------------------------- /chapter5/bar_chart8c.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | # Set up the data 4 | labels = ('Python', 'Scala', 'C#', 'Java', 'PHP') 5 | index = (1, 2, 3, 4, 5) 6 | sizes = [45, 10, 15, 30, 22] 7 | 8 | # Set up the multi-coloured bar chart 9 | pyplot.bar(index, sizes, tick_label=labels, color=('red', 'green', 'blue', 'yellow', 'orange')) 10 | 11 | # Configure the layout 12 | pyplot.ylabel('Usage') 13 | pyplot.xlabel('Programming Languages') 14 | 15 | # Display the chart 16 | pyplot.show() 17 | -------------------------------------------------------------------------------- /chapter5/bar_chart8d.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | # Set up the data 4 | labels = ('Python', 'Scala', 'C#', 'Java', 'PHP') 5 | index = (1, 2, 3, 4, 5) 6 | web_usage = [20, 2, 5, 10, 14] 7 | data_science_usage = [15, 8, 5, 15, 2] 8 | games_usage = [10, 1, 5, 5, 4] 9 | 10 | # Set up the bar chart 11 | pyplot.bar(index, web_usage, tick_label=labels, label='web') 12 | pyplot.bar(index, data_science_usage, tick_label=labels, label='data science', bottom=web_usage) 13 | 14 | web_and_games_usage = [web_usage[i] + data_science_usage[i] for i in range(0, len(web_usage))] 15 | pyplot.bar(index, games_usage, tick_label=labels, label='games', bottom=web_and_games_usage) 16 | 17 | # Configure the layout 18 | pyplot.ylabel('Usage') 19 | pyplot.xlabel('Programming Languages') 20 | pyplot.legend() 21 | 22 | # Display the chart 23 | pyplot.show() -------------------------------------------------------------------------------- /chapter5/bar_chart8e.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | BAR_WIDTH = 0.35 4 | 5 | # set up grouped bar charts 6 | teama_results = (60, 75, 56, 62, 58) 7 | teamb_results = (55, 68, 80, 73, 55) 8 | # Set up the index for each bar 9 | index_teama = (1, 2, 3, 4, 5) 10 | index_teamb = [i + BAR_WIDTH for i in index_teama] 11 | 12 | # Determine the mid point for the ticks 13 | ticks = [i + BAR_WIDTH / 2 for i in index_teama] 14 | tick_labels = ('Lab 1', 'Lab 2', 'Lab 3', 'Lab 4', 'Lab 5') 15 | 16 | # Plot the bar charts 17 | pyplot.bar(index_teama, teama_results, BAR_WIDTH, color='b', label='Team A') 18 | pyplot.bar(index_teamb, teamb_results, BAR_WIDTH, color='g', label='Team B') 19 | 20 | # Set up the graph 21 | pyplot.xlabel('Labs') 22 | pyplot.ylabel('Scores') 23 | pyplot.title('Scores by Lab') 24 | pyplot.xticks(ticks, tick_labels) 25 | pyplot.legend() 26 | 27 | # Display the graph 28 | pyplot.show() 29 | -------------------------------------------------------------------------------- /chapter5/configuringaplot4.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | x = range(1, 11) 4 | y = [3, 4, 6, 9, 11, 12, 10, 11, 14, 16] 5 | 6 | # Set the axes headings 7 | plt.ylabel('y values', fontsize=12) 8 | plt.xlabel('x values', fontsize=12) 9 | 10 | # Set the title 11 | plt.title("Sample Graph") 12 | 13 | plt.plot(x, y, linewidth=2.0, label="samples", color='blue', linestyle='--') 14 | plt.plot(y, x, label='inverse', color='green') 15 | plt.plot(x, range(2, 12), 'bo', label='ranged', linestyle=':', color='red') 16 | 17 | plt.legend() 18 | 19 | plt.show() 20 | 21 | # Can also write it to a file 22 | # plt.savefig("foo.png") -------------------------------------------------------------------------------- /chapter5/figure_example7.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | import numpy as np 3 | 4 | # Data for plotting 5 | t = np.arange(0.0, 2.0, 0.01) 6 | s = 1 + np.sin(2 * np.pi * t) 7 | 8 | # Initialize a Figure 9 | figure = pyplot.figure() 10 | 11 | # Add Axes to the Figure 12 | axis = figure.add_subplot(111) 13 | axis.plot(t, s, color='green', label='yyy') 14 | axis.set(xlabel='time (s)', ylabel='voltage (mV)', title='Simple Plot') 15 | 16 | # Show the grid 17 | axis.grid(linestyle='dashed') 18 | 19 | # Display the Legend 20 | axis.legend() 21 | 22 | # Generate the plot 23 | pyplot.show() 24 | 25 | -------------------------------------------------------------------------------- /chapter5/line_graph3.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | # Set up the data 4 | x = [0, 1, 2, 3, 4, 5, 6] 5 | y = [0, 2, 6, 14, 30, 43, 75] 6 | 7 | # Set the axes headings 8 | pyplot.ylabel('Speed', fontsize=12) 9 | pyplot.xlabel('Time', fontsize=12) 10 | 11 | # Set the title 12 | pyplot.title("Speed v Time") 13 | 14 | # Plot and display the graph 15 | # Using blue circles for markers ('bo') 16 | # and a solid line ('-') 17 | pyplot.plot(x, y, 'bo-') 18 | pyplot.show() 19 | -------------------------------------------------------------------------------- /chapter5/matplotlib2.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | import numpy as np 3 | 4 | # Data for plotting 5 | t = np.arange(0.0, 2.0, 0.01) 6 | s = 1 + np.sin(2 * np.pi * t) 7 | 8 | # Initialize a Figure 9 | figure = pyplot.figure() 10 | 11 | # Add Axes to the Figure 12 | axis = figure.add_subplot(111) 13 | axis.plot(t, s, color='green', label='yyy') 14 | axis.set(xlabel='time (s)', ylabel='voltage (mV)', title='Simple Plot') 15 | 16 | x = 2.25 * np.random.rand(10) 17 | y = 2.25 * np.random.rand(10) 18 | axis.scatter(x, y, marker='o', label='xxx') 19 | 20 | # Show the grid 21 | axis.grid(linestyle='dashed') 22 | 23 | # Display the Legend 24 | axis.legend() 25 | 26 | # Generate the plot 27 | pyplot.show() 28 | 29 | -------------------------------------------------------------------------------- /chapter5/pie_chart5.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | labels = ('Python', 'Java', 'Scala', 'C#') 4 | sizes = [45, 30, 15, 10] 5 | 6 | pyplot.pie(sizes, 7 | labels=labels, 8 | autopct='%1.f%%', 9 | counterclock=False, 10 | startangle=90) 11 | 12 | pyplot.show() 13 | -------------------------------------------------------------------------------- /chapter5/pie_chart_5a.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | labels = ('Python', 'Java', 'Scala', 'C#') 4 | sizes = [45, 30, 15, 10] 5 | 6 | # only "explode" the 1st slice (i.e. 'Python') 7 | explode = (0.1, 0, 0, 0) 8 | 9 | pyplot.pie(sizes, 10 | explode=explode, 11 | labels=labels, 12 | autopct='%1.f%%', 13 | shadow=True, 14 | counterclock=False, 15 | startangle=90) 16 | 17 | pyplot.show() 18 | -------------------------------------------------------------------------------- /chapter5/scatter_plot6.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | # Create data 4 | riding = ((17, 18, 21, 22, 19, 21, 25, 22, 25, 24), 5 | (3, 6, 3.5, 4, 5, 6.3, 4.5, 5, 4.5, 4)) 6 | swimming = ((17, 18, 20, 19, 22, 21, 23, 19, 21, 24), 7 | (8, 9, 7, 10, 7.5, 9, 8, 7, 8.5, 9)) 8 | sailing = ((31, 28, 29, 36, 27, 32, 34, 35, 33, 39), 9 | (4, 6.3, 6, 3, 5, 7.5, 2, 5, 7, 4)) 10 | 11 | # Plot the data 12 | pyplot.scatter(x=riding[0], y=riding[1], c='red', marker='o', label='riding') 13 | pyplot.scatter(x=swimming[0], y=swimming[1], c='green', marker='^', label='swimming') 14 | pyplot.scatter(x=sailing[0], y=sailing[1], c='blue', marker='*', label='sailing') 15 | 16 | # Configure graph 17 | pyplot.xlabel('Age') 18 | pyplot.ylabel('Hours') 19 | pyplot.title('Activities Scatter Graph') 20 | pyplot.legend() 21 | 22 | # Display the chart 23 | pyplot.show() 24 | -------------------------------------------------------------------------------- /chapter5/scatter_plot_trendline6.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as pyplot 3 | 4 | x = (5, 5.5, 6, 6.5, 7, 8, 9, 10) 5 | y = (120, 115, 100, 112, 80, 85, 69, 65) 6 | 7 | # Generate the scatter plot 8 | pyplot.scatter(x, y) 9 | 10 | # Generate the trend line 11 | z = np.polyfit(x, y, 1) 12 | p = np.poly1d(z) 13 | pyplot.plot(x, p(x), 'r') 14 | 15 | # Display the figure 16 | pyplot.show() 17 | -------------------------------------------------------------------------------- /chapter5/simple_plot1.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | # Plot a sequence of values 4 | pyplot.plot([1, 0.25, 0.5, 2, 3, 3.75, 3.5]) 5 | 6 | # Display the chart in a window 7 | pyplot.show() 8 | -------------------------------------------------------------------------------- /chapter5/sub_plots9.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | 3 | t = range(0, 20) 4 | s = range(30, 10, -1) 5 | # Set up the grid of subplots to be 2 by 2 6 | grid_size='22' 7 | 8 | # Initialize a Figure 9 | figure = pyplot.figure() 10 | 11 | # Add first subplot 12 | position = grid_size + '1' 13 | print('Adding first subplot to position', position) 14 | axis1 = figure.add_subplot(position) 15 | axis1.set(title='subplot(2,2,1)') 16 | axis1.plot(t, s) 17 | 18 | # Add second subplot 19 | position = grid_size + '2' 20 | print('Adding second subplot to position', position) 21 | axis2 = figure.add_subplot(position) 22 | axis2.set(title='subplot(2,2,2)') 23 | axis2.plot(t, s, 'r-') 24 | 25 | # Add third subplot 26 | position = grid_size + '3' 27 | print('Adding third subplot to position', position) 28 | axis3 = figure.add_subplot(position) 29 | axis3.set(title='subplot(2,2,3)') 30 | axis3.plot(t, s, 'g-') 31 | 32 | # Add fourth subplot 33 | position = grid_size + '4' 34 | print('Adding fourth subplot to position', position) 35 | axis4 = figure.add_subplot(position) 36 | axis4.set(title='subplot(2,2,4)') 37 | axis4.plot(t, s, 'y-') 38 | 39 | # Display the chart 40 | pyplot.show() 41 | -------------------------------------------------------------------------------- /chapter5/three-d-plot10.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as pyplot 2 | # Import matplotlib colour map 3 | from matplotlib import cm as colourmap 4 | # Required for 3D Projections 5 | from mpl_toolkits.mplot3d import Axes3D 6 | # Provide access to numpy functions 7 | import numpy as np 8 | 9 | # Make the data to be displayed 10 | x_values = np.arange(-6, 6, 0.3) 11 | y_values = np.arange(-6, 6, 0.3) 12 | 13 | # Generate coordinate matrices from coordinate vectors 14 | x_values, y_values = np.meshgrid(x_values, y_values) 15 | 16 | # Generate Z values as sin of x plus y values 17 | z_values = np.sin(x_values + y_values) 18 | 19 | # Obtain the figure object 20 | figure = pyplot.figure() 21 | 22 | # Get the axes object for the 3D graph 23 | axes = figure.gca(projection='3d') 24 | 25 | # Plot the surface. 26 | surf = axes.plot_surface(x_values, 27 | y_values, 28 | z_values, 29 | cmap=colourmap.coolwarm) 30 | 31 | # Add a color bar which maps values to colors. 32 | figure.colorbar(surf) 33 | 34 | # Add labels to the graph 35 | pyplot.title("3D Graph") 36 | axes.set_ylabel('y values', fontsize=8) 37 | axes.set_xlabel('x values', fontsize=8) 38 | axes.set_zlabel('z values', fontsize=8) 39 | 40 | # Display the graph 41 | pyplot.show() 42 | -------------------------------------------------------------------------------- /chapter7/FrameAndPanelApp.py: -------------------------------------------------------------------------------- 1 | import wx 2 | 3 | 4 | class SampleFrame(wx.Frame): 5 | 6 | def __init__(self): 7 | super().__init__(parent=None, 8 | title='Sample App', 9 | size=(300, 300)) 10 | 11 | # Set up the first Panel to be at position 1, 1 12 | # and of size 300 by 100 with a blue background 13 | self.panel1 = wx.Panel(self) 14 | self.panel1.SetSize(300, 100) 15 | self.panel1.SetBackgroundColour(wx.Colour(0, 0, 255)) 16 | 17 | # Set up the second Panel to be at position 1, 110 18 | # and of size 300 by 100 with a red background 19 | self.panel2 = wx.Panel(self) 20 | self.panel2.SetSize(1, 110, 300, 100) 21 | self.panel2.SetBackgroundColour(wx.Colour(255, 0, 0)) 22 | 23 | 24 | class MainApp(wx.App): 25 | 26 | def OnInit(self): 27 | """ Initialise the main GUI Application""" 28 | frame = SampleFrame() 29 | frame.Show() 30 | return True 31 | 32 | 33 | # Run the GUI application 34 | app = MainApp() 35 | app.MainLoop() 36 | -------------------------------------------------------------------------------- /chapter7/SampleDCApp.py: -------------------------------------------------------------------------------- 1 | import wx 2 | 3 | 4 | class DrawingFrame(wx.Frame): 5 | 6 | def __init__(self, title): 7 | super().__init__(None, 8 | title=title, 9 | size=(300, 200)) 10 | 11 | self.Bind(wx.EVT_PAINT, self.on_paint) 12 | 13 | def on_paint(self, event): 14 | """set up the device context (DC) for painting""" 15 | dc = wx.PaintDC(self) 16 | dc.DrawLine(10, 10, 60, 20) 17 | dc.DrawRectangle(20, 40, 40, 20) 18 | dc.DrawText("Hello World", 30, 70) 19 | dc.DrawCircle(130, 40, radius=15) 20 | 21 | 22 | class GraphicApp(wx.App): 23 | 24 | def OnInit(self): 25 | """ Initialise the GUI display""" 26 | frame = DrawingFrame(title='PyDraw') 27 | frame.Show() 28 | return True 29 | 30 | 31 | # Run the GUI application 32 | app = GraphicApp() 33 | app.MainLoop() 34 | -------------------------------------------------------------------------------- /chapter7/SimpleHelloWorldApp.py: -------------------------------------------------------------------------------- 1 | import wx 2 | 3 | # Create the Application Object 4 | app = wx.App() 5 | 6 | # Now create a Frame (representing the window) 7 | frame = wx.Frame(parent=None, title='Simple Hello World') 8 | # And add a text label to it 9 | text = wx.StaticText(parent=frame, label='Hello Python') 10 | 11 | # Display the window (frame) 12 | frame.Show() 13 | 14 | # Start the event loop 15 | app.MainLoop() -------------------------------------------------------------------------------- /chapter8/HelloNamedApp.py: -------------------------------------------------------------------------------- 1 | import wx 2 | 3 | 4 | class HelloFrame(wx.Frame): 5 | 6 | def __init__(self, title): 7 | super().__init__(None, 8 | title=title, 9 | size=(300, 200)) 10 | 11 | self.name = '' 12 | 13 | # Create the BoxSizer to use for the Frame 14 | vertical_box_sizer = wx.BoxSizer(wx.VERTICAL) 15 | self.SetSizer(vertical_box_sizer) 16 | 17 | # Create the panel to contain the widgets 18 | panel = wx.Panel(self) 19 | # Add the Panel to the Frames Sizer 20 | vertical_box_sizer.Add(panel, 21 | wx.ID_ANY, 22 | wx.EXPAND | wx.ALL, 23 | 20) 24 | 25 | # Create the GridSizer to use with the Panel 26 | grid = wx.GridSizer(4, 1, 5, 5) 27 | 28 | # Set up the input field 29 | self.text = wx.TextCtrl(panel, size=(150, -1)) 30 | 31 | # Now configure the enter button 32 | enter_button = wx.Button(panel, label='Enter') 33 | enter_button.Bind(wx.EVT_BUTTON, self.set_name) 34 | 35 | # Next set up the text label 36 | self.label = wx.StaticText(panel, 37 | label='Welcome', 38 | style=wx.ALIGN_LEFT) 39 | 40 | # Now configure the Show Message button 41 | message_button = wx.Button(panel, label='Show Message') 42 | message_button.Bind(wx.EVT_BUTTON, self.show_message) 43 | 44 | # Add all the widgets to the grid sizer to handle layout 45 | grid.AddMany([self.text, enter_button, self.label, message_button]) 46 | 47 | # Set the sizer on the panel 48 | panel.SetSizer(grid) 49 | 50 | # Centre the Frame on the Computer Screen 51 | self.Centre() 52 | 53 | def show_message(self, event): 54 | """ Event Handler to display the Message Dialog 55 | using the current value of the name attribute. """ 56 | dialog = wx.MessageDialog(None, 57 | message='Welcome To Python ' + self.name, 58 | caption='Hello', 59 | style=wx.OK) 60 | dialog.ShowModal() 61 | 62 | def set_name(self, event): 63 | """ Event Handler for the Enter button. 64 | Retrieves the text entered into the input field 65 | and sets the self.name attribute. This is then 66 | used to set the text label """ 67 | self.name = self.text.GetLineText(0) 68 | self.label.SetLabelText('Welcome ' + self.name) 69 | 70 | 71 | class MainApp(wx.App): 72 | 73 | def OnInit(self): 74 | """ Initialise the GUI display""" 75 | frame = HelloFrame(title='Sample App') 76 | frame.Show() 77 | # Indicate whether processing should continue or not 78 | return True 79 | 80 | def OnExit(self): 81 | """ Executes when the GUI application shuts down""" 82 | print('Goodbye') 83 | # Need to indicate success or failure 84 | return True 85 | 86 | 87 | # Run the GUI application 88 | app = MainApp() 89 | app.MainLoop() 90 | -------------------------------------------------------------------------------- /chapter8/SimpleEventHandlerApp.py: -------------------------------------------------------------------------------- 1 | import wx 2 | 3 | 4 | class WelcomeFrame(wx.Frame): 5 | """ The Main Window / Frame of the application """ 6 | 7 | def __init__(self): 8 | super().__init__(parent=None, 9 | title='Sample App', 10 | size=(300, 200)) 11 | 12 | # Set up panel within the frame and text label 13 | self.panel = wx.Panel(self) 14 | self.text = wx.StaticText(self.panel, label='Hello') 15 | 16 | # Bind the on_mouse_click method to the Mouse Event via the 17 | # left mouse click binder 18 | self.panel.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_click) 19 | 20 | def on_mouse_click(self, mouse_event): 21 | """ When the left mouse button is clicked this 22 | method is called. It will obtain the current 23 | mouse coordinates, and reposition the text label 24 | to this position. """ 25 | x, y = mouse_event.GetPosition() 26 | print(x, y) 27 | self.text.SetPosition(wx.Point(x, y)) 28 | 29 | 30 | class MainApp(wx.App): 31 | 32 | def OnInit(self): 33 | """ Initialise the main GUI Application""" 34 | frame = WelcomeFrame() 35 | frame.Show() 36 | # Indicate whether processing should continue or not 37 | return True 38 | 39 | 40 | # Run the GUI application 41 | app = MainApp() 42 | app.MainLoop() 43 | -------------------------------------------------------------------------------- /chapter8/exercises/BirthdayGUIApp.py: -------------------------------------------------------------------------------- 1 | import wx 2 | 3 | 4 | class BirthdayFrame(wx.Frame): 5 | 6 | def __init__(self): 7 | super().__init__(parent=None, 8 | title='Happy Birthday App', 9 | size=(300, 200)) 10 | 11 | self.name = '