├── .gitignore ├── README.md ├── aifc_writer.py ├── aiff_reader.py ├── applications ├── psg_mp3_player.py └── wx_video_player.py ├── archiving ├── create_zip.py ├── creating_tarfile.py ├── reading_tarfile.py └── tar_extractall.py ├── argument_parsing ├── arg_demo.py ├── argparse_with_args.py ├── file_parser_with_description.py └── mutually_exclusive_args.py ├── async_comprehension.py ├── class_attributes.py ├── class_properties ├── chained_method.py ├── fee_property.py ├── fee_property2.py ├── getter_setter.py └── property_example.py ├── classmethods_example.py ├── data_descriptor.py ├── dearpygui_examples ├── dearpy_demo.py └── hello_world.py ├── debugging ├── debug_code.py ├── debug_code_with_breakpoint.py └── debug_code_with_settrace.py ├── decorators ├── decorator.py ├── decorator_as_a_class.py ├── decorator_with_args.py ├── decorator_without_at.py ├── doubler.py └── stacked_decorators.py ├── descriptor_validation.py ├── email ├── email_with_attachment.py ├── pop_email.py ├── pop_email_decoded.py └── send_email.py ├── excel ├── background_colors.py └── cell_text_alignment.py ├── exercises ├── loop_errror.py ├── math.py ├── non_functional.py └── shadow_function.py ├── games └── tic-tac-toe-pysimplegui │ ├── 01_app.py │ ├── 02_add_ui.py │ ├── 03_add_x_o.py │ ├── 04_final.py │ └── assets │ ├── BLANK.png │ ├── O.png │ └── X.png ├── getattr_hack.py ├── graphs ├── annotating.py ├── bar_chart_watermark.py ├── bokeh_sine.py ├── excel_bar_chart_3d.py ├── line_plot.py ├── matplotlib_bar_chart.py ├── matplotlib_subplots.py ├── matplotlib_subplots_mosaic.py └── seaborn_pie_chart.py ├── guis ├── kivy_boxlayout.py ├── psg_matplotlib.py └── wx_plotting.py ├── hello_excel.py ├── hello_json.py ├── hello_reportlab.py ├── hello_xml.py ├── images ├── lighthouse.jpg ├── watermark.py └── watermark_with_transparecy.py ├── logging ├── log_filter.py ├── log_formatting.py ├── log_multiple_locations.py ├── logging.conf ├── logging_1.py ├── logging_2.py ├── logging_3.py ├── logging_config_file.py ├── logging_dict_config.py ├── logging_exception_decorator.py ├── logging_smtp_handler.py ├── logging_stream_handler.py ├── rotating_log.py └── timed_rotating_log.py ├── pandas_examples ├── bar_plot.py ├── books.csv ├── books.xlsx ├── counting.py ├── create_excel.py ├── csv_to_excel.py ├── csv_to_sqlite.py ├── excel_to_csv.py ├── pandas.ipynb ├── pandas_books.csv ├── pandas_crosstab.py ├── read_excel_by_sheet.py ├── reading_csv.py └── reading_json.py ├── pdfs ├── borb_demo.py ├── buffalo.jpg ├── demo.pdf ├── flowers_dallas.jpg ├── img2pdf.py ├── imgs2pdf.py └── lighthouse.jpg ├── pop_quizzes ├── loosened_decorators.py └── nested_zero_division_error.py ├── profiling └── sample.py ├── read_source.py ├── regular_expressions ├── using_compile.py ├── using_findall.py └── using_search.py ├── sftp_example.py ├── single.py ├── standard_library ├── functools │ ├── decorator_with_wraps.py │ ├── decorator_without_wraps.py │ ├── functools_partial.py │ └── passing_partials.py └── itertools │ ├── itertools_count.py │ ├── itertools_cycle.py │ └── itertools_islice.py ├── system_admin └── get_mac_address.py ├── testing ├── dtest.py ├── mock_patch_urllib.py ├── mock_side_effect.py ├── mymath.py ├── test_mymath.py └── webreader.py ├── turtle_examples ├── olympics.py ├── pie_chart.py ├── rosette.py ├── square_offsets.py └── star.py ├── wav_writer.py ├── web_scraping ├── get_articles.py └── scrapy_spider.py ├── word └── creating_document.py └── youtube_video_downloader.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # Wing 132 | *.wpr 133 | *.wpu 134 | 135 | # Mac 136 | .DS_Store 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyTips - Mike Driscoll's Python Tips 2 | 3 | A curated listing of Python examples by Mike Driscoll 4 | 5 | Python snippets are grouped topically in folders. 6 | 7 | I also have repos for my Python books that contain code snippets: 8 | 9 | - [Automating Excel with Python and OpenPyXL](https://github.com/driscollis/automating_excel_with_python) 10 | - [Pillow: Image Processing with Python](https://github.com/driscollis/image_processing_with_python) 11 | - [Python 101 - 2nd Edition code](https://github.com/driscollis/python101code) 12 | - [Work with PDFs using Python](https://github.com/driscollis/reportlabbookcode) 13 | - [Jupyter Notebook 101](https://github.com/driscollis/jupyternotebook101) 14 | - Learn about [Creating GUIs with wxPython](https://github.com/driscollis/applications_with_wxpython) 15 | - [wxPython cookbook recipes](https://github.com/driscollis/wxpythoncookbookcode) 16 | 17 | Follow me on the following platforms: 18 | 19 | - Twitter - [@driscollis](https://twitter.com/driscollis) 20 | - Website - [Mouse vs Python](https://www.blog.pythonlibrary.org/) 21 | - [YouTube Channel](https://www.youtube.com/c/MouseVsPython) 22 | -------------------------------------------------------------------------------- /aifc_writer.py: -------------------------------------------------------------------------------- 1 | import aifc 2 | import random 3 | import struct 4 | 5 | sample_rate = 44100.0 # hertz 6 | 7 | obj = aifc.open('sound.aiff','w') 8 | obj.setnchannels(1) # mono 9 | obj.setsampwidth(2) 10 | obj.setframerate(sample_rate) 11 | 12 | for i in range(99999): 13 | value = random.randint(-32767, 32767) 14 | data = struct.pack('" + func() + "" 4 | return wrapper 5 | 6 | def italic(func): 7 | def wrapper(): 8 | return "" + func() + "" 9 | return wrapper 10 | 11 | @bold 12 | @italic 13 | def formatted_text(): 14 | return 'Python rocks!' 15 | 16 | print(formatted_text()) -------------------------------------------------------------------------------- /descriptor_validation.py: -------------------------------------------------------------------------------- 1 | from weakref import WeakKeyDictionary 2 | 3 | class Drinker: 4 | def __init__(self): 5 | self.req_age = 21 6 | self.age = WeakKeyDictionary() 7 | 8 | def __get__(self, instance_obj, objtype): 9 | return self.age.get(instance_obj, self.req_age) 10 | 11 | def __set__(self, instance, new_age): 12 | if new_age < 21: 13 | msg = '{name} is too young to legally imbibe' 14 | raise Exception(msg.format(name=instance.name)) 15 | self.age[instance] = new_age 16 | print('{name} can legally drink in the USA'.format( 17 | name=instance.name)) 18 | 19 | def __delete__(self, instance): 20 | del self.age[instance] 21 | 22 | 23 | class Person: 24 | drinker_age = Drinker() 25 | 26 | def __init__(self, name, age): 27 | self.name = name 28 | self.drinker_age = age 29 | 30 | 31 | p = Person('Miguel', 30) 32 | p = Person('Niki', 13) -------------------------------------------------------------------------------- /email/email_with_attachment.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | import sys 3 | 4 | from email import encoders 5 | from email.mime.text import MIMEText 6 | from email.mime.base import MIMEBase 7 | from email.mime.multipart import MIMEMultipart 8 | from email.utils import formatdate 9 | 10 | # ---------------------------------------------------------------------- 11 | def send_email_with_attachment(subject, body_text, to_emails, file_to_attach): 12 | """ 13 | Send an email with an attachment 14 | """ 15 | header = f"Content-Disposition", "attachment; filename={file_to_attach}" 16 | 17 | # extract server and from_addr from config 18 | host = "smtp.your_isp.com" 19 | from_addr = "mike@domain.com" 20 | 21 | # create the message 22 | msg = MIMEMultipart() 23 | msg["From"] = from_addr 24 | msg["Subject"] = subject 25 | msg["Date"] = formatdate(localtime=True) 26 | if body_text: 27 | msg.attach(MIMEText(body_text)) 28 | 29 | msg["To"] = ", ".join(to_emails) 30 | 31 | attachment = MIMEBase("application", "octet-stream") 32 | try: 33 | with open(file_to_attach, "rb") as fh: 34 | data = fh.read() 35 | attachment.set_payload(data) 36 | encoders.encode_base64(attachment) 37 | attachment.add_header(*header) 38 | msg.attach(attachment) 39 | except IOError: 40 | msg = "Error opening attachment file %s" % file_to_attach 41 | print(msg) 42 | sys.exit(1) 43 | 44 | emails = to_emails 45 | 46 | server = smtplib.SMTP(host) 47 | server.sendmail(from_addr, emails, msg.as_string()) 48 | server.quit() 49 | 50 | 51 | if __name__ == "__main__": 52 | emails = ["mike@some_domain.org"] 53 | 54 | subject = "Test email with attachment from Python" 55 | body_text = "This email contains an attachment!" 56 | path = "some_path/to/file" 57 | send_email_with_attachment(subject, body_text, emails, cc_emails, bcc_emails, path) 58 | -------------------------------------------------------------------------------- /email/pop_email.py: -------------------------------------------------------------------------------- 1 | import poplib 2 | 3 | server_name = "pop.mydomain.com" 4 | 5 | inbox = poplib.POP3(server_name, port=110) 6 | print(inbox.getwelcome()) 7 | user = "mike@mydomain.com" 8 | pw = "foobar" 9 | inbox.user(user) 10 | inbox.pass_(pw) 11 | number_of_emails = len(inbox.list()[1]) 12 | 13 | print('-' * 25) 14 | print(f"Number of emails: {number_of_emails}") 15 | for num in range(number_of_emails): 16 | for msg in inbox.retr(num+1)[1]: 17 | print(msg) 18 | print("-" * 30) 19 | 20 | inbox.quit() -------------------------------------------------------------------------------- /email/pop_email_decoded.py: -------------------------------------------------------------------------------- 1 | import poplib 2 | from email import parser 3 | 4 | server_name = "pop.mydomain.com" 5 | 6 | inbox = poplib.POP3(server_name, port=110) 7 | print(inbox.getwelcome()) 8 | user = "mike@mydomain.com" 9 | pw = "password" 10 | inbox.user(user) 11 | inbox.pass_(pw) 12 | 13 | messages = [inbox.retr(i) for i in range(1, len(inbox.list()[1]) + 1)] 14 | 15 | # decode messages 16 | messages = ['\n'.join(map(bytes.decode, msg[1])) for msg in messages] 17 | 18 | # Parse messages 19 | messages = [parser.Parser().parsestr(msg) for msg in messages] 20 | 21 | for message in messages: 22 | print(f"Subject: {message['subject']}") 23 | print(f"FROM: {message['from']}") 24 | for part in message.walk(): 25 | if part.get_content_type(): 26 | body = part.get_payload(decode=True) 27 | print(body) 28 | 29 | inbox.quit() -------------------------------------------------------------------------------- /email/send_email.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | 3 | HOST = "smtp.mydomain.com" 4 | SUBJECT = "Test email from Python" 5 | TO = "mike@mydomain.com" 6 | FROM = "python@mydomain.com" 7 | text = "blah blach blah" 8 | BODY = "\r\n".join(( 9 | f"From: {FROM}", 10 | f"To: {TO}", 11 | f"Subject: {SUBJECT}", 12 | "", 13 | text) 14 | ) 15 | server = smtplib.SMTP(HOST) 16 | server.sendmail(FROM, [TO], BODY) 17 | server.quit() 18 | 19 | -------------------------------------------------------------------------------- /excel/background_colors.py: -------------------------------------------------------------------------------- 1 | # background_colors.py 2 | 3 | from openpyxl import Workbook 4 | from openpyxl.styles import PatternFill 5 | 6 | 7 | def background_colors(path): 8 | workbook = Workbook() 9 | sheet = workbook.active 10 | yellow = "00FFFF00" 11 | for rows in sheet.iter_rows(min_row=1, max_row=10, min_col=1, max_col=12): 12 | for cell in rows: 13 | if cell.row % 2: 14 | cell.fill = PatternFill(start_color=yellow, end_color=yellow, 15 | fill_type = "solid") 16 | workbook.save(path) 17 | 18 | 19 | if __name__ == "__main__": 20 | background_colors("bg.xlsx") -------------------------------------------------------------------------------- /excel/cell_text_alignment.py: -------------------------------------------------------------------------------- 1 | # cell_text_alignment.py 2 | 3 | from openpyxl import Workbook 4 | from openpyxl.styles import Alignment 5 | 6 | 7 | def center_text(path, horizontal="center", vertical="center"): 8 | workbook = Workbook() 9 | sheet = workbook.active 10 | sheet["A1"] = "Hello" 11 | sheet["A1"].alignment = Alignment(horizontal=horizontal, 12 | vertical=vertical) 13 | sheet["A2"] = "from" 14 | sheet["A3"] = "OpenPyXL" 15 | sheet["A3"].alignment = Alignment(text_rotation=90) 16 | workbook.save(path) 17 | 18 | 19 | if __name__ == "__main__": 20 | center_text("alignment.xlsx") -------------------------------------------------------------------------------- /exercises/loop_errror.py: -------------------------------------------------------------------------------- 1 | # What's wrong with this code? 2 | 3 | x = 1 4 | while x != 10: 5 | print(f"{x=}") 6 | x += 2 -------------------------------------------------------------------------------- /exercises/math.py: -------------------------------------------------------------------------------- 1 | # What's wrong with this code? 2 | 3 | import math 4 | 5 | def main(number): 6 | print(f"The square root of {number} if {math.sqrt(number)}") 7 | 8 | main(8) -------------------------------------------------------------------------------- /exercises/non_functional.py: -------------------------------------------------------------------------------- 1 | # Make this code work 2 | 3 | from math import sq_root 4 | 5 | def get_the_root(number); 6 | return sq_root(number) 7 | 8 | if name == main: 9 | get_the_root(64) -------------------------------------------------------------------------------- /exercises/shadow_function.py: -------------------------------------------------------------------------------- 1 | # What's wrong with this code? 2 | 3 | import math 4 | 5 | def math(*args): 6 | return sum(args) 7 | 8 | def main(number): 9 | print(f"The square root of {number} is {math.sqrt(number)}") 10 | 11 | main(8) -------------------------------------------------------------------------------- /games/tic-tac-toe-pysimplegui/01_app.py: -------------------------------------------------------------------------------- 1 | import PySimpleGUI as sg 2 | 3 | 4 | def main(): 5 | window = sg.Window("Tic-Tac-Toe", layout=[[]], margins=(100, 50)) 6 | 7 | while True: 8 | event, values = window.read() 9 | if event == "Exit" or event == sg.WIN_CLOSED: 10 | break 11 | 12 | window.close() 13 | 14 | 15 | if __name__ == "__main__": 16 | main() 17 | -------------------------------------------------------------------------------- /games/tic-tac-toe-pysimplegui/02_add_ui.py: -------------------------------------------------------------------------------- 1 | import PySimpleGUI as sg 2 | 3 | BLANK_IMAGE_PATH = "assets/BLANK.png" 4 | 5 | 6 | def main(): 7 | layout = [ 8 | [ 9 | sg.Button( 10 | size=(10, 6), 11 | key=(row, col), 12 | button_color=("white", "white"), 13 | image_filename=BLANK_IMAGE_PATH, 14 | ) 15 | for row in range(3) 16 | ] 17 | for col in range(3) 18 | ] 19 | window = sg.Window("Tic-Tac-Toe", layout) 20 | 21 | while True: 22 | event, values = window.read() 23 | if event == "Exit" or event == sg.WIN_CLOSED: 24 | break 25 | 26 | window.close() 27 | 28 | 29 | if __name__ == "__main__": 30 | main() -------------------------------------------------------------------------------- /games/tic-tac-toe-pysimplegui/03_add_x_o.py: -------------------------------------------------------------------------------- 1 | import io 2 | import PySimpleGUI as sg 3 | 4 | from PIL import Image 5 | 6 | 7 | PLAYER_X_IMAGE_PATH = "assets/X.png" 8 | PLAYER_O_IMAGE_PATH = "assets/O.png" 9 | BLANK_IMAGE_PATH = "assets/BLANK.png" 10 | 11 | 12 | def update_game(button, player): 13 | """ 14 | Update the game 15 | """ 16 | original_player = player 17 | if player == "X": 18 | filename = PLAYER_X_IMAGE_PATH 19 | player = "O" 20 | else: 21 | filename = PLAYER_O_IMAGE_PATH 22 | player = "X" 23 | 24 | bio = io.BytesIO() 25 | image = Image.open(filename) 26 | image.save(bio, format="PNG") 27 | 28 | if not button.metadata: 29 | button.update(text=player, image_data=bio.getvalue()) 30 | button.metadata = original_player 31 | return player 32 | 33 | return original_player 34 | 35 | 36 | def main(): 37 | layout = [ 38 | [ 39 | sg.Button( 40 | size=(10, 6), 41 | key=(row, col), 42 | button_color=("white", "white"), 43 | image_filename=BLANK_IMAGE_PATH, 44 | ) 45 | for row in range(3) 46 | ] 47 | for col in range(3) 48 | ] 49 | window = sg.Window("Tic-Tac-Toe", layout) 50 | 51 | player = "X" 52 | while True: 53 | event, values = window.read() 54 | if event == "Exit" or event == sg.WIN_CLOSED: 55 | break 56 | if isinstance(event, tuple): 57 | btn_clicked = window[event] 58 | player = update_game(btn_clicked, player) 59 | 60 | window.close() 61 | 62 | 63 | if __name__ == "__main__": 64 | main() -------------------------------------------------------------------------------- /games/tic-tac-toe-pysimplegui/04_final.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | import PySimpleGUI as sg 4 | from PIL import Image 5 | 6 | PLAYER_X_IMAGE_PATH = "assets/X.png" 7 | PLAYER_O_IMAGE_PATH = "assets/O.png" 8 | BLANK_IMAGE_PATH = "assets/BLANK.png" 9 | INITIAL_PLAYER = "X" 10 | 11 | 12 | def ask_if_play_again(player): 13 | """ 14 | Ask the user if they want to play again or quit 15 | """ 16 | if player is None: 17 | message = "Tied Game!" 18 | else: 19 | message = f"{player} won!" 20 | layout = [ 21 | [sg.Text(f"{message} Do you want to play again or Quit?")], 22 | [sg.Button("Restart"), sg.Button("Quit")], 23 | ] 24 | event, values = sg.Window("Play Again?", layout, modal=True).read( 25 | close=True 26 | ) 27 | return True if event == "Restart" else False 28 | 29 | 30 | def check_if_won(winning_configurations): 31 | """ 32 | Check if anyone has won yet 33 | """ 34 | winner = None 35 | for configuration in winning_configurations: 36 | game_pieces = {btn.metadata for btn in configuration} 37 | is_won = None not in game_pieces and len(game_pieces) == 1 38 | if is_won: 39 | winner = game_pieces.pop() 40 | mark_win([*configuration]) 41 | return (True, winner) 42 | 43 | # Check if tied game 44 | data = [ 45 | btn.metadata 46 | for configuration in winning_configurations 47 | for btn in configuration 48 | ] 49 | 50 | if None not in data: 51 | # Tied game 52 | return (None, winner) 53 | 54 | # Keep playing 55 | return (False, winner) 56 | 57 | 58 | def get_winning_configurations(buttons): 59 | """ 60 | Returns a list of methods to win the game 61 | """ 62 | horizontal_ways_to_win = [ 63 | [buttons[0][0], buttons[1][0], buttons[2][0]], 64 | [buttons[0][1], buttons[1][1], buttons[2][1]], 65 | [buttons[0][2], buttons[1][2], buttons[2][2]], 66 | ] 67 | vertical_ways_to_win = [ 68 | [buttons[0][0], buttons[0][1], buttons[0][2]], 69 | [buttons[1][0], buttons[1][1], buttons[1][2]], 70 | [buttons[2][0], buttons[2][1], buttons[2][2]], 71 | ] 72 | diagonal_ways_to_win = [ 73 | [buttons[0][0], buttons[1][1], buttons[2][2]], 74 | [buttons[0][2], buttons[1][1], buttons[2][0]], 75 | ] 76 | return horizontal_ways_to_win + vertical_ways_to_win + diagonal_ways_to_win 77 | 78 | 79 | def mark_win(buttons): 80 | """ 81 | Mark the winning buttons with a different background color 82 | """ 83 | for button in buttons: 84 | button.update(button_color=["green", "green"]) 85 | 86 | 87 | def reset_game(buttons): 88 | """ 89 | Reset the game to play again 90 | """ 91 | bio = io.BytesIO() 92 | image = Image.open(BLANK_IMAGE_PATH) 93 | image.save(bio, format="PNG") 94 | for row in buttons: 95 | for button in row: 96 | button.update( 97 | image_data=bio.getvalue(), button_color=["white", "white"] 98 | ) 99 | button.metadata = None 100 | 101 | 102 | def update_game(button, player): 103 | """ 104 | Update the game 105 | """ 106 | original_player = player 107 | if player == "X": 108 | filename = PLAYER_X_IMAGE_PATH 109 | player = "O" 110 | else: 111 | filename = PLAYER_O_IMAGE_PATH 112 | player = "X" 113 | 114 | bio = io.BytesIO() 115 | image = Image.open(filename) 116 | image.save(bio, format="PNG") 117 | 118 | if not button.metadata: 119 | button.update(text=player, image_data=bio.getvalue()) 120 | button.metadata = original_player 121 | return player 122 | 123 | return original_player 124 | 125 | 126 | def main(): 127 | """ 128 | Create GUI and manage UI events 129 | """ 130 | layout = [ 131 | [ 132 | sg.Button( 133 | size=(7, 5), 134 | button_text=f"({row} {col})", 135 | key=(row, col), 136 | button_color=("white", "white"), 137 | image_filename=BLANK_IMAGE_PATH, 138 | ) 139 | for row in range(3) 140 | ] 141 | for col in range(3) 142 | ] 143 | window = sg.Window("Tic-Tac-Toe", layout) 144 | ways_to_win = get_winning_configurations(layout) 145 | 146 | player = INITIAL_PLAYER 147 | while True: 148 | event, values = window.read() 149 | if event == "Exit" or event == sg.WIN_CLOSED: 150 | break 151 | if isinstance(event, tuple): 152 | btn_clicked = window[event] 153 | player = update_game(btn_clicked, player) 154 | winning_configuration, winner = check_if_won(ways_to_win) 155 | if winning_configuration is not False: 156 | should_restart = ask_if_play_again(winner) 157 | if should_restart is False: 158 | # Close the application 159 | break 160 | player = INITIAL_PLAYER 161 | reset_game(layout) 162 | 163 | window.close() 164 | 165 | 166 | if __name__ == "__main__": 167 | main() -------------------------------------------------------------------------------- /games/tic-tac-toe-pysimplegui/assets/BLANK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driscollis/pytips/bd67b3a17ec81ccdf8b39b22eeaa5f59b92d140f/games/tic-tac-toe-pysimplegui/assets/BLANK.png -------------------------------------------------------------------------------- /games/tic-tac-toe-pysimplegui/assets/O.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driscollis/pytips/bd67b3a17ec81ccdf8b39b22eeaa5f59b92d140f/games/tic-tac-toe-pysimplegui/assets/O.png -------------------------------------------------------------------------------- /games/tic-tac-toe-pysimplegui/assets/X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driscollis/pytips/bd67b3a17ec81ccdf8b39b22eeaa5f59b92d140f/games/tic-tac-toe-pysimplegui/assets/X.png -------------------------------------------------------------------------------- /getattr_hack.py: -------------------------------------------------------------------------------- 1 | # Works in Python 3.7+ 2 | 3 | def __getattr__(expression): 4 | operator, number = expression.split("_") 5 | number = int(number) 6 | operations = {"times": lambda val: val * number} 7 | if operator not in operations: 8 | print(f"Unknown operator: {operator}") 9 | return print 10 | return operations[operator] 11 | -------------------------------------------------------------------------------- /graphs/annotating.py: -------------------------------------------------------------------------------- 1 | # Example from: https://www.analyticsvidhya.com/blog/2020/05/10-matplotlib-tricks-data-visualization-python/ 2 | 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | 6 | fig=plt.figure(figsize=(8,6)) 7 | 8 | X = list(range(10)) 9 | plt.plot(X, np.exp(X)) 10 | plt.title('Annotating Exponential Plot using plt.annotate()') 11 | plt.xlabel('x-axis') 12 | plt.ylabel('y-axis') 13 | 14 | plt.annotate('Point 1', xy=(6,400), 15 | arrowprops=dict(arrowstyle='->'), 16 | xytext=(4,600)) 17 | 18 | plt.annotate('Point 2', xy=(7,1150), 19 | arrowprops=dict(arrowstyle='->', 20 | connectionstyle='arc3,rad=-.2'), 21 | xytext=(4.5,2000)) 22 | 23 | plt.annotate('Point 3', xy=(8,3000), 24 | arrowprops=dict(arrowstyle='-|>', 25 | connectionstyle='angle,angleA=90,angleB=0'), 26 | xytext=(8.5,2200)) 27 | 28 | plt.show() -------------------------------------------------------------------------------- /graphs/bar_chart_watermark.py: -------------------------------------------------------------------------------- 1 | # bar_chart_watermark.py 2 | 3 | import matplotlib.pyplot as plt 4 | 5 | def bar_chart(numbers, labels, pos): 6 | fig = plt.figure(figsize=(5, 8)) 7 | plt.bar(pos, numbers, color='red') 8 | 9 | # add watermark 10 | fig.text(1, 0.15, 'Mouse vs Python', 11 | fontsize=45, color='blue', 12 | ha='right', va='bottom', alpha=0.4, 13 | rotation=25) 14 | 15 | plt.xticks(ticks=pos, labels=labels) 16 | plt.show() 17 | 18 | if __name__ == '__main__': 19 | numbers = [2, 1, 4, 6] 20 | labels = ['Electric', 'Solar', 'Diesel', 'Unleaded'] 21 | pos = list(range(4)) 22 | bar_chart(numbers, labels, pos) -------------------------------------------------------------------------------- /graphs/bokeh_sine.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from bokeh.layouts import gridplot 4 | from bokeh.plotting import figure, output_file, show 5 | 6 | N = 100 7 | x = np.linspace(0, 4*np.pi, N) 8 | y0 = np.sin(x) 9 | 10 | output_file("sinewave.html") 11 | 12 | sine = figure(width=500, plot_height=500, title="Sine") 13 | sine.circle(x, y0, size=10, color="navy", alpha=0.5) 14 | 15 | p = gridplot([[sine]], toolbar_location=None) 16 | 17 | show(p) -------------------------------------------------------------------------------- /graphs/excel_bar_chart_3d.py: -------------------------------------------------------------------------------- 1 | # bar_chart_3d.py 2 | 3 | from openpyxl import Workbook 4 | from openpyxl.chart import BarChart3D, Reference 5 | 6 | 7 | def create_excel_data(sheet): 8 | data_rows = [ 9 | ["", "Kindle", "Paperback"], 10 | ["Python 101", 9.99, 25.99], 11 | ["Python 201: Intermediate Python", 9.99, 25.99], 12 | ["wxPython Cookbook", 9.99, 25.99], 13 | ["ReportLab: PDF Processing with Python", 4.99, 29.99], 14 | ["Jupyter Notebook 101", 4.99, 29.99], 15 | ["Creating GUI Applications with wxPython", 24.99, 29.99], 16 | ["Python Interviews", 24.99, 65.00], 17 | ["Pillow: Image Processing with Python", 24.99, 69.00], 18 | ["Automating Excel with Python", 24.99, 69.00], 19 | ] 20 | 21 | for row in data_rows: 22 | sheet.append(row) 23 | 24 | 25 | def create_bar_chart(sheet): 26 | bar_chart = BarChart3D() 27 | bar_chart.title = "Book Prices by Type" 28 | bar_chart.height = 20 29 | bar_chart.width = 30 30 | 31 | data = Reference(worksheet=sheet, 32 | min_row=2, 33 | max_row=10, 34 | min_col=2, 35 | max_col=3) 36 | titles = Reference(sheet, min_col=1, min_row=2, max_row=10) 37 | bar_chart.add_data(data, titles_from_data=True) 38 | bar_chart.set_categories(titles) 39 | sheet.add_chart(bar_chart, "E2") 40 | 41 | 42 | def main(): 43 | workbook = Workbook() 44 | sheet = workbook.active 45 | create_excel_data(sheet) 46 | create_bar_chart(sheet) 47 | workbook.save("bar_chart_3d.xlsx") 48 | 49 | 50 | if __name__ == "__main__": 51 | main() -------------------------------------------------------------------------------- /graphs/line_plot.py: -------------------------------------------------------------------------------- 1 | # line_plot.py 2 | 3 | import matplotlib.pyplot as plt 4 | 5 | def line_plot(numbers): 6 | plt.plot(numbers) 7 | plt.ylabel('Random numbers') 8 | plt.show() 9 | 10 | if __name__ == '__main__': 11 | numbers = [2, 4, 1, 6] 12 | line_plot(numbers) 13 | -------------------------------------------------------------------------------- /graphs/matplotlib_bar_chart.py: -------------------------------------------------------------------------------- 1 | # bar_chart.py 2 | 3 | import matplotlib.pyplot as plt 4 | 5 | def bar_chart(numbers, labels, pos): 6 | fig = plt.figure(figsize=(5, 8)) 7 | plt.bar(pos, numbers, color='blue') 8 | plt.xticks(ticks=pos, labels=labels) 9 | plt.show() 10 | 11 | if __name__ == '__main__': 12 | numbers = [2, 1, 4, 6] 13 | labels = ['Electric', 'Solar', 'Diesel', 'Unleaded'] 14 | pos = list(range(4)) 15 | bar_chart(numbers, labels, pos) -------------------------------------------------------------------------------- /graphs/matplotlib_subplots.py: -------------------------------------------------------------------------------- 1 | # matplotlib_subplots.py 2 | 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | 6 | def multiple_plots(): 7 | # Some example data to display 8 | x = np.linspace(0, 2 * np.pi, 400) 9 | y = np.sin(x ** 2) 10 | 11 | fig, axs = plt.subplots(2) 12 | fig.suptitle('Vertically stacked subplots') 13 | axs[0].plot(x, y) 14 | axs[1].plot(x, -y) 15 | plt.show() 16 | 17 | if __name__ == '__main__': 18 | multiple_plots() -------------------------------------------------------------------------------- /graphs/matplotlib_subplots_mosaic.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | 5 | x = np.linspace(0, 2 * np.pi, 400) 6 | y = np.sin(x ** 2) 7 | 8 | fig, axd = plt.subplot_mosaic([['upleft', 'right'], 9 | ['lowleft', 'right']], layout='constrained') 10 | axd['upleft'].set_title('upleft') 11 | axd['upleft'].plot(x, y) 12 | 13 | axd['lowleft'].set_title('lowleft') 14 | axd['lowleft'].plot(y, x) 15 | 16 | axd['right'].set_title('right') 17 | plt.show() -------------------------------------------------------------------------------- /graphs/seaborn_pie_chart.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import seaborn as sns 3 | 4 | # create some data 5 | data = [15, 25, 25, 30, 5] 6 | labels = ['Group 1', 'Group 2', 'Group 3', 'Group 4', 'Group 5'] 7 | 8 | # Set the color palette 9 | colors = sns.color_palette('pastel')[0:5] 10 | 11 | # create pie chart 12 | plt.pie(data, labels = labels, colors = colors, autopct='%.0f%%') 13 | plt.show() -------------------------------------------------------------------------------- /guis/kivy_boxlayout.py: -------------------------------------------------------------------------------- 1 | import kivy 2 | import random 3 | 4 | from kivy.app import App 5 | from kivy.uix.button import Button 6 | from kivy.uix.boxlayout import BoxLayout 7 | 8 | red = [1, 0, 0, 1] 9 | green = [0,1,0,1] 10 | blue = [0,0,1,1] 11 | purple = [1,0,1,1] 12 | 13 | 14 | class LayoutDemo(App): 15 | 16 | def build(self): 17 | layout = BoxLayout(padding=10, orientation="vertical") 18 | colors = [red, green, blue, purple] 19 | 20 | for i in range(3): 21 | h_layout = BoxLayout(padding=20) 22 | for i in range(5): 23 | btn = Button(text=f"Button {i+1}", 24 | background_color=random.choice(colors)) 25 | h_layout.add_widget(btn) 26 | layout.add_widget(h_layout) 27 | return layout 28 | 29 | 30 | if __name__ == "__main__": 31 | app = LayoutDemo() 32 | app.run() -------------------------------------------------------------------------------- /guis/psg_matplotlib.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg 3 | import PySimpleGUI as sg 4 | import matplotlib 5 | 6 | fig = matplotlib.figure.Figure(figsize=(5, 4), dpi=100) 7 | t = np.arange(0, 3, .01) 8 | fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t)) 9 | 10 | matplotlib.use("TkAgg") 11 | 12 | def draw_figure(canvas, figure): 13 | figure_canvas_agg = FigureCanvasTkAgg(figure, canvas) 14 | figure_canvas_agg.draw() 15 | figure_canvas_agg.get_tk_widget().pack(side="top", fill="both", expand=1) 16 | return figure_canvas_agg 17 | 18 | # Define the window layout 19 | layout = [ 20 | [sg.Text("Plot test")], 21 | [sg.Canvas(key="-CANVAS-")], 22 | [sg.Button("Ok")], 23 | ] 24 | 25 | # Create the form and show it without the plot 26 | window = sg.Window( 27 | "Matplotlib Single Graph", 28 | layout, 29 | location=(0, 0), 30 | finalize=True, 31 | element_justification="center", 32 | font="Helvetica 18", 33 | ) 34 | 35 | # Add the plot to the window 36 | draw_figure(window["-CANVAS-"].TKCanvas, fig) 37 | event, values = window.read() 38 | 39 | window.close() 40 | -------------------------------------------------------------------------------- /guis/wx_plotting.py: -------------------------------------------------------------------------------- 1 | import wx 2 | from wx.lib.plot import PolyLine, PlotCanvas, PlotGraphics 3 | 4 | 5 | def drawBarGraph(): 6 | # Bar graph 7 | points1=[(1,0), (1,10)] 8 | line1 = PolyLine(points1, colour='green', legend='Feb.', width=10) 9 | points1g=[(2,0), (2,4)] 10 | line1g = PolyLine(points1g, colour='red', legend='Mar.', width=10) 11 | points1b=[(3,0), (3,6)] 12 | line1b = PolyLine(points1b, colour='blue', legend='Apr.', width=10) 13 | 14 | points2=[(4,0), (4,12)] 15 | line2 = PolyLine(points2, colour='Yellow', legend='May', width=10) 16 | points2g=[(5,0), (5,8)] 17 | line2g = PolyLine(points2g, colour='orange', legend='June', width=10) 18 | points2b=[(6,0), (6,4)] 19 | line2b = PolyLine(points2b, colour='brown', legend='July', width=10) 20 | 21 | return PlotGraphics([line1, line1g, line1b, line2, line2g, line2b], 22 | "Bar Graph - (Turn on Grid, Legend)", "Months", 23 | "Number of Students") 24 | 25 | 26 | class MyGraph(wx.Frame): 27 | 28 | def __init__(self): 29 | wx.Frame.__init__(self, None, wx.ID_ANY, 30 | 'My First Plot (to take over the world!)') 31 | 32 | # Add a panel so it looks the correct on all platforms 33 | panel = wx.Panel(self, wx.ID_ANY) 34 | 35 | # create some sizers 36 | mainSizer = wx.BoxSizer(wx.VERTICAL) 37 | checkSizer = wx.BoxSizer(wx.HORIZONTAL) 38 | 39 | # create the widgets 40 | self.canvas = PlotCanvas(panel) 41 | self.canvas.Draw(drawBarGraph()) 42 | toggleGrid = wx.CheckBox(panel, label="Show Grid") 43 | toggleGrid.Bind(wx.EVT_CHECKBOX, self.onToggleGrid) 44 | toggleLegend = wx.CheckBox(panel, label="Show Legend") 45 | toggleLegend.Bind(wx.EVT_CHECKBOX, self.onToggleLegend) 46 | 47 | # layout the widgets 48 | mainSizer.Add(self.canvas, 1, wx.EXPAND) 49 | checkSizer.Add(toggleGrid, 0, wx.ALL, 5) 50 | checkSizer.Add(toggleLegend, 0, wx.ALL, 5) 51 | mainSizer.Add(checkSizer) 52 | panel.SetSizer(mainSizer) 53 | 54 | def onToggleGrid(self, event): 55 | self.canvas.SetEnableGrid(event.IsChecked()) 56 | 57 | def onToggleLegend(self, event): 58 | self.canvas.SetEnableLegend(event.IsChecked()) 59 | 60 | if __name__ == '__main__': 61 | app = wx.App(False) 62 | frame = MyGraph() 63 | frame.Show() 64 | app.MainLoop() -------------------------------------------------------------------------------- /hello_excel.py: -------------------------------------------------------------------------------- 1 | from openpyxl import Workbook 2 | 3 | workbook = Workbook() 4 | workbook.save("hello.xlsx") -------------------------------------------------------------------------------- /hello_json.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | def create_json_file(path, obj): 4 | with open(path, 'w') as fh: 5 | json.dump(obj, fh) 6 | 7 | if __name__ == '__main__': 8 | j = {"menu": { 9 | "id": "file", 10 | "value": "File", 11 | "popup": { 12 | "menuitem": [ 13 | {"value": "New", "onclick": "CreateNewDoc()"}, 14 | {"value": "Open", "onclick": "OpenDoc()"}, 15 | {"value": "Close", "onclick": "CloseDoc()"} 16 | ] 17 | } 18 | }} 19 | create_json_file('test.json', j) -------------------------------------------------------------------------------- /hello_reportlab.py: -------------------------------------------------------------------------------- 1 | from reportlab.pdfgen import canvas 2 | 3 | my_canvas = canvas.Canvas("hello.pdf") 4 | my_canvas.drawString(100, 750, "Welcome to Reportlab!") 5 | my_canvas.save() -------------------------------------------------------------------------------- /hello_xml.py: -------------------------------------------------------------------------------- 1 | import xml.etree.ElementTree as xml 2 | 3 | def create_xml(filename): 4 | """ 5 | Create an example XML file 6 | """ 7 | root = xml.Element("Appointments") 8 | appt = xml.Element("subAppointment") 9 | root.append(appt) 10 | 11 | # add appointment children 12 | begin = xml.SubElement(appt, "begin") 13 | begin.text = "1181251680" 14 | 15 | tree = xml.ElementTree(root) 16 | with open(filename, "wb") as fh: 17 | tree.write(fh) 18 | 19 | if __name__ == "__main__": 20 | create_xml("appt.xml") -------------------------------------------------------------------------------- /images/lighthouse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driscollis/pytips/bd67b3a17ec81ccdf8b39b22eeaa5f59b92d140f/images/lighthouse.jpg -------------------------------------------------------------------------------- /images/watermark.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | from PIL import ImageDraw 3 | from PIL import ImageFont 4 | 5 | 6 | def watermark_text(input_image_path, 7 | output_image_path, 8 | text, pos): 9 | photo = Image.open(input_image_path) 10 | 11 | # make the image editable 12 | drawing = ImageDraw.Draw(photo) 13 | 14 | black = (3, 8, 12) 15 | font = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 40) 16 | drawing.text(pos, text, fill=black, font=font) 17 | photo.show() 18 | photo.save(output_image_path) 19 | 20 | 21 | if __name__ == '__main__': 22 | img = 'lighthouse.jpg' 23 | watermark_text(img, 'lighthouse_watermarked.jpg', 24 | text='www.mousevspython.com', 25 | pos=(0, 0)) -------------------------------------------------------------------------------- /images/watermark_with_transparecy.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | 3 | def watermark_with_transparency(input_image_path, 4 | output_image_path, 5 | watermark_image_path, 6 | position): 7 | base_image = Image.open(input_image_path) 8 | watermark = Image.open(watermark_image_path) 9 | width, height = base_image.size 10 | 11 | transparent = Image.new('RGBA', (width, height), (0,0,0,0)) 12 | transparent.paste(base_image, (0,0)) 13 | transparent.paste(watermark, position, mask=watermark) 14 | transparent.show() 15 | transparent.save(output_image_path) 16 | 17 | 18 | if __name__ == '__main__': 19 | img = 'lighthouse.jpg' 20 | watermark_with_transparency(img, 'lighthouse_watermarked3.jpg', 21 | 'watermark.png', position=(0,0)) -------------------------------------------------------------------------------- /logging/log_filter.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import sys 3 | 4 | class MyFilter(logging.Filter): 5 | def filter(self, record): 6 | if record.funcName == 'a': 7 | return False 8 | return True 9 | 10 | logger = logging.getLogger('filter_test') 11 | logger.addFilter(MyFilter()) 12 | 13 | def a(): 14 | """ 15 | Ignore this function's log messages 16 | """ 17 | logger.debug('Message from function a') 18 | 19 | def b(): 20 | logger.debug('Message from B') 21 | 22 | if __name__ == '__main__': 23 | logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) 24 | a() 25 | b() -------------------------------------------------------------------------------- /logging/log_formatting.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logger = logging.getLogger('stream_logger') 4 | logger.setLevel(logging.INFO) 5 | 6 | console = logging.StreamHandler() 7 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(message)s') 8 | console.setFormatter(formatter) 9 | 10 | logger.addHandler(console) 11 | logger.info("This is an informational message") -------------------------------------------------------------------------------- /logging/log_multiple_locations.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | def log(path, multipleLocs=False): 4 | logger = logging.getLogger("Test_logger_%s" % fname) 5 | logger.setLevel(logging.INFO) 6 | fh = logging.FileHandler(path) 7 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(message)s') 8 | fh.setFormatter(formatter) 9 | logger.addHandler(fh) 10 | 11 | if multipleLocs: 12 | console = logging.StreamHandler() 13 | console.setLevel(logging.INFO) 14 | console.setFormatter(formatter) 15 | logger.addHandler(console) 16 | 17 | logger.info("This is an informational message") 18 | try: 19 | 1 / 0 20 | except ZeroDivisionError: 21 | logger.exception("You can't do that!") 22 | 23 | logger.critical("THIS IS A SHOW STOPPER!!!") -------------------------------------------------------------------------------- /logging/logging.conf: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root,exampleApp 3 | 4 | [handlers] 5 | keys=fileHandler, consoleHandler 6 | 7 | [formatters] 8 | keys=myFormatter 9 | 10 | [logger_root] 11 | level=CRITICAL 12 | handlers=consoleHandler 13 | 14 | [logger_exampleApp] 15 | level=INFO 16 | handlers=fileHandler 17 | qualname=exampleApp 18 | 19 | [handler_consoleHandler] 20 | class=StreamHandler 21 | level=DEBUG 22 | formatter=myFormatter 23 | args=(sys.stdout,) 24 | 25 | [handler_fileHandler] 26 | class=FileHandler 27 | formatter=myFormatter 28 | args=("config.log",) 29 | 30 | [formatter_myFormatter] 31 | format=%(asctime)s - %(name)s - %(levelname)s - %(message)s 32 | datefmt= -------------------------------------------------------------------------------- /logging/logging_1.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logging.warning("This is a warning message") # This is the default level 4 | logging.critical("Critical message") -------------------------------------------------------------------------------- /logging/logging_2.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | # add filemode="w" to overwrite 4 | logging.basicConfig(filename="sample.log", level=logging.INFO) 5 | 6 | logging.debug("This is a debug message") # This one won't log 7 | logging.info("Informational message") 8 | logging.error("An error has happened!") -------------------------------------------------------------------------------- /logging/logging_3.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logging.basicConfig(filename="ex_logger.log") 4 | log = logging.getLogger("ex") 5 | log.setLevel(logging.INFO) 6 | log.info("This is informational") -------------------------------------------------------------------------------- /logging/logging_config_file.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.config 3 | 4 | logging.config.fileConfig('logging.conf') 5 | logger = logging.getLogger("exampleApp") 6 | 7 | logger.info("Program started") 8 | logger.info("Done!") -------------------------------------------------------------------------------- /logging/logging_dict_config.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.config 3 | 4 | dictLogConfig = { 5 | "version":1, 6 | "handlers":{ 7 | "fileHandler":{ 8 | "class":"logging.FileHandler", 9 | "formatter":"myFormatter", 10 | "filename":"dict_config.log" 11 | } 12 | }, 13 | "loggers":{ 14 | "exampleApp":{ 15 | "handlers":["fileHandler"], 16 | "level":"INFO", 17 | } 18 | }, 19 | 20 | "formatters":{ 21 | "myFormatter":{ 22 | "format":"%(asctime)s - %(name)s - %(levelname)s - %(message)s" 23 | } 24 | } 25 | } 26 | 27 | logging.config.dictConfig(dictLogConfig) 28 | 29 | logger = logging.getLogger("exampleApp") 30 | 31 | logger.info("Program started") 32 | logger.info("Done!") -------------------------------------------------------------------------------- /logging/logging_exception_decorator.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import logging 3 | 4 | def create_logger(): 5 | """ 6 | Creates a logging object and returns it 7 | """ 8 | logger = logging.getLogger("example_logger") 9 | logger.setLevel(logging.INFO) 10 | 11 | # create the logging file handler 12 | fh = logging.FileHandler("/path/to/test.log") 13 | 14 | fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 15 | formatter = logging.Formatter(fmt) 16 | fh.setFormatter(formatter) 17 | 18 | # add handler to logger object 19 | logger.addHandler(fh) 20 | return logger 21 | 22 | 23 | def exception(function): 24 | """ 25 | A decorator that wraps the passed in function and logs 26 | exceptions should one occur 27 | """ 28 | @functools.wraps(function) 29 | def wrapper(*args, **kwargs): 30 | logger = create_logger() 31 | try: 32 | return function(*args, **kwargs) 33 | except: 34 | # log the exception 35 | err = "There was an exception in " 36 | err += function.__name__ 37 | logger.exception(err) 38 | 39 | # re-raise the exception 40 | raise 41 | return wrapper -------------------------------------------------------------------------------- /logging/logging_smtp_handler.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.handlers 3 | 4 | logger = logging.getLogger("email_logger") 5 | logger.setLevel(logging.INFO) 6 | fh = logging.handlers.SMTPHandler('smtp.my_server.com', 7 | fromaddr='log@my_server.com', 8 | toaddrs=['mike@my_server.com'], 9 | subject='Python log') 10 | logger.addHandler(fh) 11 | logger.info("This is an informational message") -------------------------------------------------------------------------------- /logging/logging_stream_handler.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logger = logging.getLogger('stream_logger') 4 | logger.setLevel(logging.INFO) 5 | 6 | console = logging.StreamHandler() 7 | 8 | logger.addHandler(console) 9 | logger.info("This is an informational message") -------------------------------------------------------------------------------- /logging/rotating_log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import time 3 | from logging.handlers import RotatingFileHandler 4 | 5 | def create_rotating_log(path): 6 | """ 7 | Creates a rotating log 8 | """ 9 | logger = logging.getLogger("Rotating Log") 10 | logger.setLevel(logging.INFO) 11 | 12 | # add a rotating handler 13 | handler = RotatingFileHandler(path, maxBytes=20, 14 | backupCount=5) 15 | logger.addHandler(handler) 16 | 17 | for i in range(10): 18 | logger.info("This is test log line %s" % i) 19 | time.sleep(1.5) 20 | 21 | 22 | if __name__ == "__main__": 23 | log_file = "rotated.log" 24 | create_rotating_log(log_file) -------------------------------------------------------------------------------- /logging/timed_rotating_log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import time 3 | from logging.handlers import TimedRotatingFileHandler 4 | 5 | 6 | def create_timed_rotating_log(path): 7 | """""" 8 | logger = logging.getLogger("Rotating Log") 9 | logger.setLevel(logging.INFO) 10 | 11 | handler = TimedRotatingFileHandler(path, 12 | when="s", 13 | interval=5, 14 | backupCount=5) 15 | logger.addHandler(handler) 16 | 17 | for i in range(6): 18 | logger.info("This is a test!") 19 | time.sleep(75) 20 | 21 | if __name__ == "__main__": 22 | log_file = "timed_rotation.log" 23 | create_timed_rotating_log(log_file) -------------------------------------------------------------------------------- /pandas_examples/bar_plot.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | df = pd.Series(np.random.randn(200), 5 | index=pd.date_range("1/1/2000", 6 | periods=200)) 7 | 8 | df.plot(kind="bar") -------------------------------------------------------------------------------- /pandas_examples/books.csv: -------------------------------------------------------------------------------- 1 | book_title,author,publisher,pub_date,isbn 2 | Python 101,Mike Driscoll, Mike Driscoll,2020,123456789 3 | wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8 4 | Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081 -------------------------------------------------------------------------------- /pandas_examples/books.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driscollis/pytips/bd67b3a17ec81ccdf8b39b22eeaa5f59b92d140f/pandas_examples/books.xlsx -------------------------------------------------------------------------------- /pandas_examples/counting.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | # Read only the first 5 rows from a CSV file 4 | df = pd.read_csv("books.csv", nrows=5) 5 | 6 | author_counts = df["author"] == "Mike Driscoll" 7 | print(author_counts.value_counts()) 8 | 9 | # Alternate way to count 10 | author_counts = df["author"].value_counts() 11 | print(f"Number of times 'Mike Driscoll' is an author = " 12 | f"{author_counts['Mike Driscoll']}") -------------------------------------------------------------------------------- /pandas_examples/create_excel.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | df = pd.DataFrame([[100, 433, 10], [34, 10, 0], [75, 125, 5]], 4 | index=['Python 101', 'Python 201', 'wxPython'], 5 | columns=['Amazon', 'Leanpub', 'Gumroad']) 6 | df.to_excel('pandas_to_excel.xlsx', sheet_name='Books') -------------------------------------------------------------------------------- /pandas_examples/csv_to_excel.py: -------------------------------------------------------------------------------- 1 | # csv_to_excel.py 2 | 3 | import pandas as pd 4 | 5 | 6 | def csv_to_excel(csv_file, excel_file, sheet_name): 7 | df = pd.read_csv(csv_file) 8 | df.to_excel(excel_file, sheet_name=sheet_name) 9 | 10 | 11 | if __name__ == "__main__": 12 | csv_to_excel("books.csv", "pandas_csv_to_excel.xlsx", "Books") -------------------------------------------------------------------------------- /pandas_examples/csv_to_sqlite.py: -------------------------------------------------------------------------------- 1 | # csv_to_sqlite.py 2 | 3 | import sqlite3 4 | import pandas as pd 5 | 6 | 7 | def csv_to_sqlite(csv_file, sql_file): 8 | df = pd.read_csv(csv_file) 9 | with sqlite3.connect(sql_file) as conn: 10 | df.to_sql("Books", conn) 11 | 12 | if __name__ == "__main__": 13 | csv_to_sqlite("books.csv", "books.db") -------------------------------------------------------------------------------- /pandas_examples/excel_to_csv.py: -------------------------------------------------------------------------------- 1 | # excel_to_csv.py 2 | 3 | import pandas as pd 4 | 5 | 6 | def excel_to_csv(excel_file, csv_file, sheet_name=0): 7 | df = pd.read_excel(excel_file, sheet_name=sheet_name) 8 | df.to_csv(csv_file) 9 | 10 | 11 | if __name__ == "__main__": 12 | excel_to_csv("books.xlsx", "pandas_books.csv") -------------------------------------------------------------------------------- /pandas_examples/pandas.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# `pandas` Experiments" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "# Create an empty DataFrame" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "metadata": {}, 21 | "outputs": [ 22 | { 23 | "name": "stdout", 24 | "output_type": "stream", 25 | "text": [ 26 | "Empty DataFrame\n", 27 | "Columns: []\n", 28 | "Index: []\n" 29 | ] 30 | } 31 | ], 32 | "source": [ 33 | "import pandas as pd\n", 34 | "\n", 35 | "df = pd.DataFrame()\n", 36 | "print(df)" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "# Add data to an empty DataFrame\n", 44 | "\n", 45 | "- https://www.geeksforgeeks.org/how-to-create-an-empty-dataframe-and-append-rows-columns-to-it-in-pandas/\n", 46 | "- https://www.geeksforgeeks.org/different-ways-to-create-pandas-dataframe/" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 3, 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "data": { 56 | "text/html": [ 57 | "
\n", 58 | "\n", 71 | "\n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | "
NameJobs
0GuidoDeveloper
1AlexAuthor
2SteveSpeaker
\n", 97 | "
" 98 | ], 99 | "text/plain": [ 100 | " Name Jobs\n", 101 | "0 Guido Developer\n", 102 | "1 Alex Author\n", 103 | "2 Steve Speaker" 104 | ] 105 | }, 106 | "execution_count": 3, 107 | "metadata": {}, 108 | "output_type": "execute_result" 109 | } 110 | ], 111 | "source": [ 112 | "import pandas as pd\n", 113 | "\n", 114 | "df = pd.DataFrame()\n", 115 | "df[\"Name\"] = [\"Guido\", \"Alex\", \"Steve\"]\n", 116 | "df[\"Jobs\"] = [\"Developer\", \"Author\", \"Speaker\"]\n", 117 | "df" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "# Convert a `dict` to a DataFrame" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 4, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "data": { 134 | "text/html": [ 135 | "
\n", 136 | "\n", 149 | "\n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | "
NamesJobsBooks
0MikeAuthorPython 101
1RodrigoContent CreatorPyDon'ts
2SundeepAuthorPython re(gex)?
\n", 179 | "
" 180 | ], 181 | "text/plain": [ 182 | " Names Jobs Books\n", 183 | "0 Mike Author Python 101\n", 184 | "1 Rodrigo Content Creator PyDon'ts\n", 185 | "2 Sundeep Author Python re(gex)?" 186 | ] 187 | }, 188 | "execution_count": 4, 189 | "metadata": {}, 190 | "output_type": "execute_result" 191 | } 192 | ], 193 | "source": [ 194 | "import pandas as pd\n", 195 | "\n", 196 | "data = {\"Names\": [\"Mike\", \"Rodrigo\", \"Sundeep\"],\n", 197 | " \"Jobs\": [\"Author\", \"Content Creator\", \"Author\"],\n", 198 | " \"Books\": [\"Python 101\", \"PyDon'ts\", \"Python re(gex)?\"]}\n", 199 | "df = pd.DataFrame(data)\n", 200 | "df" 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "metadata": {}, 206 | "source": [ 207 | "# Get a Specific Value from a DataFrame" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 5, 213 | "metadata": {}, 214 | "outputs": [ 215 | { 216 | "data": { 217 | "text/plain": [ 218 | "'Python re(gex)?'" 219 | ] 220 | }, 221 | "execution_count": 5, 222 | "metadata": {}, 223 | "output_type": "execute_result" 224 | } 225 | ], 226 | "source": [ 227 | "import pandas as pd\n", 228 | "\n", 229 | "data = {\"Names\": [\"Mike\", \"Rodrigo\", \"Sundeep\"],\n", 230 | " \"Jobs\": [\"Author\", \"Content Creator\", \"Author\"],\n", 231 | " \"Books\": [\"Python 101\", \"PyDon'ts\", \"Python re(gex)?\"]}\n", 232 | "df = pd.DataFrame(data)\n", 233 | "df = df.set_index(\"Names\")\n", 234 | "df.loc[\"Sundeep\", \"Books\"]" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 14, 240 | "metadata": {}, 241 | "outputs": [ 242 | { 243 | "name": "stdout", 244 | "output_type": "stream", 245 | "text": [ 246 | "Python re(gex)?\n", 247 | "Python re(gex)?\n" 248 | ] 249 | } 250 | ], 251 | "source": [ 252 | "import pandas as pd\n", 253 | "\n", 254 | "data = {\"Names\": [\"Mike\", \"Rodrigo\", \"Sundeep\"],\n", 255 | " \"Jobs\": [\"Author\", \"Content Creator\", \"Author\"],\n", 256 | " \"Books\": [\"Python 101\", \"PyDon'ts\", \"Python re(gex)?\"]}\n", 257 | "df = pd.DataFrame(data)\n", 258 | "\n", 259 | "# Get the column where the data is\n", 260 | "col = df.loc[df.columns == \"Books\"].index.values[0]\n", 261 | "\n", 262 | "# Get the row where the data is\n", 263 | "row = df.loc[df[\"Books\"] == \"Python re(gex)?\"].index.values[0]\n", 264 | "\n", 265 | "# Extract the data you want\n", 266 | "print(df.iloc[col, row])\n", 267 | "\n", 268 | "# Alternate method of getting the data\n", 269 | "print(df._get_value(row, df.columns[col]))\n", 270 | "\n", 271 | "# 3rd method \n", 272 | "# df.loc[df.Names == \"Sundeep\"].Books.iloc[0]" 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": 13, 278 | "metadata": {}, 279 | "outputs": [ 280 | { 281 | "data": { 282 | "text/plain": [ 283 | "'Python re(gex)?'" 284 | ] 285 | }, 286 | "execution_count": 13, 287 | "metadata": {}, 288 | "output_type": "execute_result" 289 | } 290 | ], 291 | "source": [ 292 | "df.loc[df.Names == \"Sundeep\"].Books.iloc[0]" 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": null, 298 | "metadata": {}, 299 | "outputs": [], 300 | "source": [] 301 | } 302 | ], 303 | "metadata": { 304 | "kernelspec": { 305 | "display_name": "Python 3", 306 | "language": "python", 307 | "name": "python3" 308 | }, 309 | "language_info": { 310 | "codemirror_mode": { 311 | "name": "ipython", 312 | "version": 3 313 | }, 314 | "file_extension": ".py", 315 | "mimetype": "text/x-python", 316 | "name": "python", 317 | "nbconvert_exporter": "python", 318 | "pygments_lexer": "ipython3", 319 | "version": "3.8.1" 320 | } 321 | }, 322 | "nbformat": 4, 323 | "nbformat_minor": 4 324 | } 325 | -------------------------------------------------------------------------------- /pandas_examples/pandas_books.csv: -------------------------------------------------------------------------------- 1 | ,Books,Unnamed: 1,Unnamed: 2,Unnamed: 3,Unnamed: 4,Unnamed: 5,Unnamed: 6 2 | 0,Title,Author,Publisher,Publishing Date,ISBN,, 3 | 1,Python 101,Mike Driscoll,Mouse vs Python,2020,1234567890,, 4 | 2,wxPython Recipes,Mike Driscoll,Apress,2018,978-1-4842-3237-8,, 5 | 3,Python Interviews,Mike Driscoll,Packt Publishing,2018,9781788399081,, 6 | -------------------------------------------------------------------------------- /pandas_examples/pandas_crosstab.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | df = pd.DataFrame(dict(departure=["DSM", "DSM", "LAX", "LAX", "DFW", "DSM"], 4 | arrival=["ORD", "DFW", "DFW", "ORD", "ATL", "ATL"], 5 | airlines=["Delta", "AA", "United", "SouthWest", "AA", "United"])) 6 | pd.crosstab(index=[df["departure"], df["airlines"]], 7 | columns=[df["arrival"]], 8 | rownames=["departure", "airlines"], 9 | colnames=["arrival"], 10 | margins=True 11 | ) 12 | -------------------------------------------------------------------------------- /pandas_examples/read_excel_by_sheet.py: -------------------------------------------------------------------------------- 1 | # read_excel_by_sheet.py 2 | 3 | import pandas as pd 4 | 5 | sheet_one_data = pd.read_excel('sample.xlsx', sheet_name=0) 6 | sheet_two_data = pd.read_excel('sample.xlsx', sheet_name="Sales") 7 | 8 | print(sheet_one_data) 9 | print(sheet_two_data) -------------------------------------------------------------------------------- /pandas_examples/reading_csv.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | # Read only the first 5 rows from a CSV file 4 | df = pd.read_csv("books.csv", nrows=5) 5 | print(df) 6 | 7 | df = pd.read_csv("books.csv", nrows=5, usecols=["author", "book_title"]) 8 | print(df) 9 | 10 | # Extract just the author column 11 | authors = df['author'] 12 | print(type(authors)) -------------------------------------------------------------------------------- /pandas_examples/reading_json.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | df = pd.read_json("https://api.github.com/users/driscollis/repos?perpage=100") 5 | columns = ["name", "stargazers_count", "forks"] 6 | 7 | # Get the top 10 repos sorted by stargazer count 8 | df[columns].sort_values("stargazers_count", ascending=False).head(10) -------------------------------------------------------------------------------- /pdfs/borb_demo.py: -------------------------------------------------------------------------------- 1 | from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout 2 | from borb.pdf.canvas.layout.text.paragraph import Paragraph 3 | from borb.pdf.document import Document 4 | from borb.pdf.page.page import Page 5 | from borb.pdf.pdf import PDF 6 | 7 | def main(pdf_path): 8 | pdf = Document() 9 | 10 | # Add a blank page to the PDF 11 | page = Page() 12 | pdf.append_page(page) 13 | 14 | # Create a layout to hold your text 15 | layout = SingleColumnLayout(page) 16 | 17 | # Add some text using the Paragraph class 18 | layout.add(Paragraph("Hello from borb!")) 19 | 20 | with open(pdf_path, "wb") as pdf_fh: 21 | PDF.dumps(pdf_fh, pdf) 22 | 23 | if __name__ == "__main__": 24 | main("demo.pdf") 25 | -------------------------------------------------------------------------------- /pdfs/buffalo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driscollis/pytips/bd67b3a17ec81ccdf8b39b22eeaa5f59b92d140f/pdfs/buffalo.jpg -------------------------------------------------------------------------------- /pdfs/demo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driscollis/pytips/bd67b3a17ec81ccdf8b39b22eeaa5f59b92d140f/pdfs/demo.pdf -------------------------------------------------------------------------------- /pdfs/flowers_dallas.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driscollis/pytips/bd67b3a17ec81ccdf8b39b22eeaa5f59b92d140f/pdfs/flowers_dallas.jpg -------------------------------------------------------------------------------- /pdfs/img2pdf.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | 3 | 4 | def img2pdf(image_file, pdf_file): 5 | img = Image.open(image_file) 6 | img.save(pdf_file) 7 | 8 | if __name__ == "__main__": 9 | img2pdf("buffalo.jpg", "buffalo.pdf") -------------------------------------------------------------------------------- /pdfs/imgs2pdf.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | 3 | 4 | def imgs2pdf(image_files: list[str], pdf_file: str) -> None: 5 | img = Image.open(image_files[0]).convert("RGB") 6 | image_objects =[Image.open(image).convert("RGB") for image in image_files[1:]] 7 | img.save(pdf_file, save_all=True, append_images=image_objects) 8 | 9 | if __name__ == "__main__": 10 | imgs2pdf(["buffalo.jpg", "flowers_dallas.jpg", "lighthouse.jpg"], "pictures.pdf") -------------------------------------------------------------------------------- /pdfs/lighthouse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driscollis/pytips/bd67b3a17ec81ccdf8b39b22eeaa5f59b92d140f/pdfs/lighthouse.jpg -------------------------------------------------------------------------------- /pop_quizzes/loosened_decorators.py: -------------------------------------------------------------------------------- 1 | class dog: 2 | ... 3 | 4 | @(lambda f: setattr(dog, "on_leash", f)) 5 | def walk(): 6 | print("bark, bark") 7 | 8 | print(dog.on_leash()) -------------------------------------------------------------------------------- /pop_quizzes/nested_zero_division_error.py: -------------------------------------------------------------------------------- 1 | try: 2 | for i in range(3): 3 | try: 4 | 1 / 0 5 | except ZeroDivisionError: 6 | raise ZeroDivisionError("Error: You divided by zero!") 7 | finally: 8 | print("Finally executed") 9 | break 10 | except ZeroDivisionError: 11 | print("Outer ZeroDivisionError exception caught") -------------------------------------------------------------------------------- /profiling/sample.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | def fast(): 4 | print("I am fast!") 5 | 6 | def slow(): 7 | time.sleep(2) 8 | print("I am slow") 9 | 10 | def snail(): 11 | time.sleep(10) 12 | print("snail!") 13 | 14 | def main(): 15 | fast() 16 | slow() 17 | snail() 18 | 19 | main() -------------------------------------------------------------------------------- /read_source.py: -------------------------------------------------------------------------------- 1 | # read_source.py 2 | 3 | def do_nothing(): 4 | pass 5 | 6 | def do_almost_nothing(): 7 | print("5") 8 | 9 | with open(__file__) as f: 10 | print(f.read()) -------------------------------------------------------------------------------- /regular_expressions/using_compile.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | text = "The ants go marching one by one" 4 | 5 | strings = ['the', 'one'] 6 | 7 | for string in strings: 8 | regex = re.compile(string) 9 | match = re.search(regex, text) 10 | if match: 11 | print('Found "{}" in "{}"'.format(string, text)) 12 | text_pos = match.span() 13 | print(text[match.start():match.end()]) 14 | else: 15 | print('Did not find "{}"'.format(string)) -------------------------------------------------------------------------------- /regular_expressions/using_findall.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | silly_string = "the cat in the hat" 4 | pattern = "the" 5 | 6 | for match in re.finditer(pattern, silly_string): 7 | s = "Found '{group}' at {begin}:{end}".format( 8 | group=match.group(), begin=match.start(), 9 | end=match.end()) 10 | print(s) -------------------------------------------------------------------------------- /regular_expressions/using_search.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | text = "The ants go marching one by one" 4 | 5 | strings = ['the', 'one'] 6 | 7 | for string in strings: 8 | match = re.search(string, text) 9 | if match: 10 | print('Found "{}" in "{}"'.format(string, text)) 11 | text_pos = match.span() 12 | print(text[match.start():match.end()]) 13 | else: 14 | print('Did not find "{}"'.format(string)) -------------------------------------------------------------------------------- /sftp_example.py: -------------------------------------------------------------------------------- 1 | import paramiko 2 | 3 | def main(): 4 | host = "myserver" 5 | port = 22 6 | username = "mike" 7 | password = "dingbat!" 8 | 9 | local_path = '/home/mld/projects/ssh/random_file.txt' 10 | remote_path = '/home/mdriscoll/random_file.txt' 11 | 12 | transport = paramiko.Transport((host, port)) 13 | transport.connect(username=username, password=password) 14 | sftp = paramiko.SFTPClient.from_transport(transport) 15 | sftp.put(local_path, remote_path) 16 | 17 | transport.close() 18 | 19 | main() -------------------------------------------------------------------------------- /single.py: -------------------------------------------------------------------------------- 1 | from functools import singledispatch 2 | 3 | 4 | @singledispatch 5 | def add(a, b): 6 | """The generic function""" 7 | raise NotImplementedError('Unsupported type') 8 | 9 | 10 | @add.register(int) 11 | def _(a, b): 12 | print("First argument is of type ", type(a)) 13 | print(a + b) 14 | 15 | 16 | @add.register(float) 17 | def _(a, b): 18 | print("First argument is of type ", type(a)) 19 | print(a + b) 20 | 21 | 22 | #add(1, 2) 23 | add(1.0, 2.0) 24 | # add((1,), (2,)) 25 | #add([1, 2, 3], [5, 6, 7]) -------------------------------------------------------------------------------- /standard_library/functools/decorator_with_wraps.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | 4 | def another_function(func): 5 | """ 6 | A function that accepts another function 7 | """ 8 | 9 | @wraps(func) 10 | def wrapper(): 11 | """ 12 | A wrapping function 13 | """ 14 | val = f"The result of {func()} is {eval(func())}" 15 | return val 16 | return wrapper 17 | 18 | 19 | @another_function 20 | def a_function(): 21 | """A pretty useless function""" 22 | return "1+1" 23 | 24 | 25 | if __name__ == "__main__": 26 | print(a_function.__name__) 27 | print(a_function.__doc__) -------------------------------------------------------------------------------- /standard_library/functools/decorator_without_wraps.py: -------------------------------------------------------------------------------- 1 | 2 | def another_function(func): 3 | """ 4 | A function that accepts another function (i.e. a decorator) 5 | """ 6 | 7 | def wrapper(): 8 | """ 9 | A wrapping function 10 | """ 11 | val = f"The result of {func()} is {eval(func())}" 12 | return val 13 | return wrapper 14 | 15 | 16 | @another_function 17 | def a_function(): 18 | """A pretty useless function""" 19 | return "1+1" 20 | 21 | 22 | if __name__ == "__main__": 23 | print(a_function.__name__) 24 | print(a_function.__doc__) -------------------------------------------------------------------------------- /standard_library/functools/functools_partial.py: -------------------------------------------------------------------------------- 1 | from functools import partial 2 | 3 | def add(x, y): 4 | return a + b 5 | 6 | if __name__ == "__main__": 7 | p_add = partial(add, 2) 8 | print(p_add(4)) -------------------------------------------------------------------------------- /standard_library/functools/passing_partials.py: -------------------------------------------------------------------------------- 1 | from functools import partial 2 | 3 | 4 | def add(x, y): 5 | """""" 6 | return x + y 7 | 8 | 9 | def multiply(x, y): 10 | return x * y 11 | 12 | 13 | def run(func): 14 | """ 15 | Run a partial function 16 | """ 17 | print(func()) 18 | 19 | 20 | def main(): 21 | a1 = partial(add, 1, 2) 22 | m1 = partial(multiply, 5, 8) 23 | run(a1) 24 | run(m1) 25 | 26 | if __name__ == "__main__": 27 | main() -------------------------------------------------------------------------------- /standard_library/itertools/itertools_count.py: -------------------------------------------------------------------------------- 1 | from itertools import count 2 | 3 | for i in count(10): 4 | if i > 20: 5 | break 6 | else: 7 | print(i) 8 | -------------------------------------------------------------------------------- /standard_library/itertools/itertools_cycle.py: -------------------------------------------------------------------------------- 1 | from itertools import cycle 2 | 3 | count = 0 4 | for item in cycle('XYZ'): 5 | if count > 7: 6 | break 7 | print(item) 8 | count += 1 9 | -------------------------------------------------------------------------------- /standard_library/itertools/itertools_islice.py: -------------------------------------------------------------------------------- 1 | from itertools import count, islice 2 | 3 | for i in islice(count(10), 5): 4 | print(i) -------------------------------------------------------------------------------- /system_admin/get_mac_address.py: -------------------------------------------------------------------------------- 1 | from uuid import getnode 2 | 3 | # Strip off hex character from front 4 | mac = hex(getnode())[2:].upper() 5 | 6 | # Add semi-colons every two characters 7 | mac = ':'.join(mac[i:i+2] for i in range(0, len(mac), 2)) -------------------------------------------------------------------------------- /testing/dtest.py: -------------------------------------------------------------------------------- 1 | def double(a): 2 | """ 3 | >>> double(4) 4 | 8 5 | >>> double(9) 6 | 18 7 | """ 8 | return a*2 9 | 10 | 11 | if __name__ == "__main__": 12 | import doctest 13 | doctest.testmod(verbose=True) -------------------------------------------------------------------------------- /testing/mock_patch_urllib.py: -------------------------------------------------------------------------------- 1 | import webreader 2 | 3 | from unittest.mock import patch 4 | 5 | 6 | @patch('urllib.request.urlopen') 7 | def dummy_reader(mock_obj): 8 | result = webreader.read_webpage('https://www.google.com/') 9 | mock_obj.assert_called_with('https://www.google.com/') 10 | print(result) 11 | 12 | if __name__ == '__main__': 13 | dummy_reader() -------------------------------------------------------------------------------- /testing/mock_side_effect.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import Mock 2 | 3 | 4 | def my_side_effect(): 5 | print('Updating database!') 6 | 7 | def main(): 8 | mock = Mock(side_effect=my_side_effect) 9 | mock() 10 | 11 | if __name__ == '__main__': 12 | main() -------------------------------------------------------------------------------- /testing/mymath.py: -------------------------------------------------------------------------------- 1 | # mymath.py 2 | 3 | def add(a, b): 4 | return a + b 5 | 6 | 7 | def subtract(a, b): 8 | return a - b 9 | 10 | 11 | def multiply(a, b): 12 | return a * b 13 | 14 | 15 | def divide(numerator, denominator): 16 | return float(numerator) / denominator -------------------------------------------------------------------------------- /testing/test_mymath.py: -------------------------------------------------------------------------------- 1 | import mymath 2 | import unittest 3 | 4 | 5 | class TestAdd(unittest.TestCase): 6 | """ 7 | Test the add function from the mymath library 8 | """ 9 | 10 | def test_add_integers(self): 11 | """ 12 | Test that the addition of two integers returns the correct total 13 | """ 14 | result = mymath.add(1, 2) 15 | self.assertEqual(result, 3) 16 | 17 | def test_add_floats(self): 18 | """ 19 | Test that the addition of two floats returns the correct result 20 | """ 21 | result = mymath.add(10.5, 2) 22 | self.assertEqual(result, 12.5) 23 | 24 | def test_add_strings(self): 25 | """ 26 | Test the addition of two strings returns the two string as one 27 | concatenated string 28 | """ 29 | result = mymath.add('abc', 'def') 30 | self.assertEqual(result, 'abcdef') 31 | 32 | 33 | if __name__ == '__main__': 34 | unittest.main() -------------------------------------------------------------------------------- /testing/webreader.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | 3 | 4 | def read_webpage(url): 5 | response = urllib.request.urlopen(url) 6 | return response.read() -------------------------------------------------------------------------------- /turtle_examples/olympics.py: -------------------------------------------------------------------------------- 1 | import turtle 2 | 3 | 4 | class MyTurtle(turtle.Turtle): 5 | 6 | def __init__(self): 7 | """Turtle Constructor""" 8 | turtle.Turtle.__init__(self, shape="turtle") 9 | screen = turtle.Screen() 10 | screen.bgcolor("lightgrey") 11 | self.pensize(3) 12 | 13 | def drawCircle(self, x, y, color, radius=50): 14 | """ 15 | Moves the turtle to the correct position and draws a circle 16 | """ 17 | self.penup() 18 | self.setposition(x, y) 19 | self.pendown() 20 | self.color(color) 21 | self.circle(radius) 22 | 23 | def drawOlympicSymbol(self): 24 | """ 25 | Iterates over a set of positions to draw the Olympics logo 26 | """ 27 | positions = [(0, 0, "blue"), (-120, 0, "purple"), (60,60, "red"), 28 | (-60, 60, "yellow"), (-180, 60, "green")] 29 | for x, y, color in positions: 30 | self.drawCircle(x, y, color) 31 | 32 | self.drawText() 33 | 34 | def drawText(self): 35 | """ 36 | Draw text to the screen 37 | """ 38 | self.penup() 39 | self.setposition(-60, 0) 40 | self.setheading(0) 41 | self.pendown() 42 | self.color("black") 43 | self.write("Mouse vs Python", font=("Arial", 16, "bold")) 44 | 45 | if __name__ == "__main__": 46 | t = MyTurtle() 47 | t.drawOlympicSymbol() 48 | turtle.getscreen()._root.mainloop() -------------------------------------------------------------------------------- /turtle_examples/pie_chart.py: -------------------------------------------------------------------------------- 1 | # Based on the following StackOverflow article 2 | # https://stackoverflow.com/questions/41274903/different-color-for-each-segment-of-a-pie-chart-using-turtle-in-python 3 | 4 | from turtle import Turtle, Screen 5 | from itertools import cycle 6 | 7 | languages = [("Python", 50), ("C++", 10), ("Ruby", 20), (".NET", 20)] 8 | 9 | COLORS = cycle(['green', 'yellow', 'red', 'cyan', 'white']) 10 | 11 | RADIUS = 175 12 | LABEL_RADIUS = RADIUS * 1.33 13 | FONTSIZE = 18 14 | FONT = ("Ariel", FONTSIZE, "bold") 15 | 16 | # The pie slices 17 | 18 | total = 100 19 | 20 | my_turtle = Turtle() 21 | my_turtle.penup() 22 | my_turtle.sety(-RADIUS) 23 | my_turtle.pendown() 24 | 25 | for _, fraction in languages: 26 | my_turtle.fillcolor(next(COLORS)) 27 | my_turtle.begin_fill() 28 | my_turtle.circle(RADIUS, fraction * 360 / total) 29 | position = my_turtle.position() 30 | my_turtle.goto(0, 0) 31 | my_turtle.end_fill() 32 | my_turtle.setposition(position) 33 | 34 | # The labels 35 | 36 | my_turtle.penup() 37 | my_turtle.sety(-LABEL_RADIUS) 38 | 39 | for label, fraction in languages: 40 | my_turtle.circle(LABEL_RADIUS, fraction * 360 / total / 2) 41 | my_turtle.write(label, align="center", font=FONT) 42 | my_turtle.circle(LABEL_RADIUS, fraction * 360 / total / 2) 43 | 44 | my_turtle.hideturtle() 45 | 46 | screen = Screen() 47 | screen.exitonclick() -------------------------------------------------------------------------------- /turtle_examples/rosette.py: -------------------------------------------------------------------------------- 1 | from turtle import Screen, Turtle, mainloop 2 | from time import perf_counter as clock, sleep 3 | 4 | def mn_eck(original_turtle, ne,sz): 5 | turtlelist = [original_turtle] 6 | # create ne-1 additional turtles 7 | for i in range(1,ne): 8 | cloned_turtle = original_turtle.clone() 9 | cloned_turtle.rt(360.0/ne) 10 | turtlelist.append(cloned_turtle) 11 | original_turtle = cloned_turtle 12 | for i in range(ne): 13 | c = abs(ne/2.0-i)/(ne*.7) 14 | # let those cloned turtles make a step 15 | # in parallel: 16 | for turtl in turtlelist: 17 | turtl.rt(360./ne) 18 | turtl.pencolor(1-c,0,c) 19 | turtl.fd(sz) 20 | 21 | def main(): 22 | screen = Screen() 23 | screen.bgcolor("black") 24 | box_turtle = Turtle() 25 | box_turtle.speed(0) 26 | box_turtle.hideturtle() 27 | box_turtle.pencolor("red") 28 | box_turtle.pensize(3) 29 | 30 | screen.tracer(36,0) 31 | 32 | begin_time = clock() 33 | mn_eck(box_turtle, 36, 19) 34 | end_time = clock() 35 | z1 = end_time-begin_time 36 | 37 | sleep(1) 38 | 39 | begin_time = clock() 40 | while any(t.undobufferentries() for t in screen.turtles()): 41 | for t in screen.turtles(): 42 | t.undo() 43 | end_time = clock() 44 | return "runtime: %.3f sec" % (z1+end_time-begin_time) 45 | 46 | 47 | if __name__ == '__main__': 48 | msg = main() 49 | print(msg) 50 | mainloop() 51 | 52 | -------------------------------------------------------------------------------- /turtle_examples/square_offsets.py: -------------------------------------------------------------------------------- 1 | from turtle import * 2 | from random import randint 3 | 4 | bgcolor("black") 5 | x = 1 6 | speed(0) 7 | 8 | while x < 400: 9 | r = randint(0, 255) 10 | g = randint(0, 255) 11 | b = randint(0, 255) 12 | 13 | colormode(255) 14 | pencolor(r, g, b) 15 | fd(50 + x) 16 | rt(90.991) 17 | x += 1 18 | 19 | exitonclick() -------------------------------------------------------------------------------- /turtle_examples/star.py: -------------------------------------------------------------------------------- 1 | from turtle import color, begin_fill, end_fill 2 | from turtle import forward, left, pos, done 3 | 4 | color('red', 'yellow') 5 | begin_fill() 6 | 7 | while True: 8 | forward(200) 9 | left(170) 10 | if abs(pos()) < 1: 11 | break 12 | 13 | end_fill() 14 | done() -------------------------------------------------------------------------------- /wav_writer.py: -------------------------------------------------------------------------------- 1 | import random 2 | import struct 3 | import wave 4 | 5 | 6 | sample_rate = 44100.0 # hertz 7 | duration = 1.0 # seconds 8 | frequency = 440.0 # hertz 9 | 10 | wav = wave.open("sample.wav", "w") 11 | wav.setnchannels(1) # mono 12 | wav.setsampwidth(2) 13 | wav.setframerate(sample_rate) 14 | 15 | # Create a wav file _ hissy noise 16 | for i in range(2000): 17 | value = random.randint(-32767, 32767) 18 | data = struct.pack('