├── .gitignore ├── Examples ├── DB │ ├── example_1_sql.py │ ├── example_2_sqlalchemy.py │ ├── example_3_orm.py │ ├── hard_words.txt │ ├── test_orm.db │ ├── test_orm_declarative.db │ ├── test_sql.db │ └── words.txt ├── __init__.py ├── command_line │ ├── __init__.py │ ├── example_1_sys_args.py │ ├── example_2_argparse.py │ ├── example_3_click.py │ └── module.py ├── gui │ ├── example_1_tkinter.py │ └── example_2_pysimplegui.py ├── modules │ ├── example_1_modules.py │ ├── example_2_namespaces.py │ └── package │ │ ├── __init__.py │ │ ├── package_module.py │ │ └── subpackage │ │ ├── __init__.py │ │ └── sub_module.py └── tests │ ├── __init__.py │ ├── example_1_assert.py │ ├── example_2_unittest.py │ ├── example_3_pytest.py │ ├── example_4_pytest_parameterized.py │ ├── rock_paper_scissors_buggy.py │ └── rock_paper_scissors_fixed.py ├── Project ├── Solutions │ ├── game_1_command_line.py │ ├── game_2_tkinter.py │ └── game_3_pysimplegui.py ├── game_1_command_line.py └── game_2_gui.py ├── README.md ├── Sample notebook.ipynb ├── docs ├── WININSTALL.md ├── WINSETPATH.md ├── installer_1.png ├── installer_2.png └── installer_3.png ├── requirements.txt └── word_game ├── data ├── __init__.py ├── get_data.py └── words.db └── game.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Virtual environments 2 | venv*/ 3 | .venv*/ 4 | 5 | # IDE settings 6 | .idea 7 | .vscode 8 | 9 | # Caches 10 | *.py[cod] 11 | __pycache__/ 12 | .pytest_cache 13 | 14 | # Notebook history 15 | .ipynb_checkpoints 16 | 17 | # Mac folder stuff 18 | .DS_Store 19 | -------------------------------------------------------------------------------- /Examples/DB/example_1_sql.py: -------------------------------------------------------------------------------- 1 | import random 2 | import sqlite3 3 | 4 | from sqlite3 import Error 5 | 6 | 7 | def sql_connection(): 8 | try: 9 | con = sqlite3.connect('test_sql.db') 10 | return con 11 | except Error: 12 | print(Error) 13 | 14 | 15 | def create_table(connection): 16 | cursor = connection.cursor() 17 | # Check if table already exists 18 | cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='words'") 19 | rows = cursor.fetchall() 20 | 21 | # If not, create table 22 | if len(rows) == 0: 23 | cursor.execute("CREATE TABLE words(word TEXT, difficult INTEGER)") 24 | connection.commit() 25 | 26 | 27 | def insert_word(connection, word, difficult): 28 | connection.cursor().execute("INSERT INTO words (word, difficult) VALUES(?, ?)", (word, difficult)) 29 | connection.commit() 30 | 31 | 32 | def fetch_words(connection, difficult=None): 33 | cursor = connection.cursor() 34 | if difficult is None: 35 | cursor.execute('SELECT word FROM words') 36 | else: 37 | values = (1,) if difficult else (0,) 38 | cursor.execute('SELECT word FROM words WHERE difficult=?', values) 39 | rows = cursor.fetchall() 40 | return [row[0] for row in rows] 41 | 42 | 43 | def get_random_word(connection, difficult): 44 | possible_words = fetch_words(connection, difficult) 45 | word = random.choice(possible_words) 46 | return word 47 | 48 | 49 | def load_words(connection): 50 | with open('words.txt', 'r') as file: 51 | for line in file.readlines(): 52 | word = line.strip().lower() 53 | insert_word(connection, word, difficult=0) 54 | 55 | with open('hard_words.txt', 'r') as file: 56 | for line in file.readlines(): 57 | word = line.strip().lower() 58 | insert_word(connection, word, difficult=1) 59 | connection.commit() 60 | 61 | 62 | if __name__ == '__main__': 63 | con = sql_connection() 64 | create_table(con) 65 | 66 | word_list = fetch_words(con) 67 | 68 | # Load words if empty 69 | if len(word_list) == 0: 70 | load_words(con) 71 | 72 | word_list = fetch_words(con) 73 | assert len(word_list) > 200 74 | print(f"There are {len(word_list)} words in the database") 75 | easy_word = get_random_word(con, difficult=0) 76 | print(f"Easy word: {easy_word}") 77 | difficult_word = get_random_word(con, difficult=1) 78 | print(f"Difficult word: {difficult_word}") 79 | con.close() 80 | -------------------------------------------------------------------------------- /Examples/DB/example_2_sqlalchemy.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from sqlalchemy import ( 4 | Boolean, 5 | Column, 6 | create_engine, 7 | MetaData, 8 | Table, 9 | String, 10 | ) 11 | 12 | engine = create_engine(f'sqlite:///test_orm.db', echo=True) 13 | 14 | meta = MetaData() 15 | 16 | words = Table( 17 | 'words', meta, 18 | Column('word', String), 19 | Column('difficult', Boolean), 20 | ) 21 | 22 | 23 | def sql_connection(): 24 | return engine.connect() 25 | 26 | 27 | def create_table(): 28 | meta.create_all(engine, [words]) 29 | 30 | 31 | def insert_word(connection, word, difficult): 32 | insert = words.insert().values(word=word, difficult=difficult) 33 | connection.execute(insert) 34 | 35 | 36 | def fetch_words(connection, difficult=None): 37 | q = words.select() 38 | if difficult is not None: 39 | q = q.where(words.c.difficult == difficult) 40 | result = connection.execute(q).fetchall() 41 | return [row.word for row in result] 42 | 43 | 44 | def get_random_word(connection, difficult=False): 45 | possible_words = fetch_words(connection, difficult) 46 | word = random.choice(possible_words) 47 | return word 48 | 49 | 50 | def load_words(connection): 51 | with open('words.txt', 'r') as file: 52 | for line in file.readlines(): 53 | word = line.strip().lower() 54 | insert_word(connection, word, difficult=False) 55 | with open('hard_words.txt', 'r') as file: 56 | for line in file.readlines(): 57 | word = line.strip().lower() 58 | insert_word(connection, word, difficult=True) 59 | 60 | 61 | if __name__ == '__main__': 62 | # Create table 63 | con = sql_connection() 64 | create_table() 65 | 66 | word_list = fetch_words(con) 67 | 68 | # Load words if empty 69 | if len(word_list) == 0: 70 | load_words(con) 71 | 72 | word_list = fetch_words(con) 73 | assert len(word_list) > 200 74 | print(f"There are {len(word_list)} words in the database") 75 | easy_word = get_random_word(con, difficult=False) 76 | print(f"Easy word: {easy_word}") 77 | difficult_word = get_random_word(con, difficult=True) 78 | print(f"Difficult word: {difficult_word}") 79 | con.close() 80 | -------------------------------------------------------------------------------- /Examples/DB/example_3_orm.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from sqlalchemy import Column, Integer, String, Boolean, create_engine 4 | from sqlalchemy.orm import declarative_base, sessionmaker 5 | 6 | 7 | # Connect to db file 8 | engine = create_engine(f'sqlite:///test_orm_declarative.db') 9 | DBSession = sessionmaker(bind=engine) 10 | 11 | # Declarative base class 12 | Base = declarative_base() 13 | 14 | 15 | # Table declaration 16 | class Word(Base): 17 | __tablename__ = 'word' 18 | 19 | id = Column(Integer, primary_key=True) 20 | word = Column(String) 21 | difficult = Column(Boolean) 22 | 23 | 24 | def create_table(): 25 | Base.metadata.create_all(engine) 26 | 27 | 28 | def insert_word(s, word, difficult=False): 29 | new_word = Word(word=word, difficult=difficult) 30 | s.add(new_word) 31 | s.commit() 32 | 33 | 34 | def fetch_words(s, difficult=None): 35 | q = s.query(Word) 36 | if difficult is not None: 37 | q = q.filter(Word.difficult == difficult) 38 | results = q.all() 39 | return [row.word for row in results] 40 | 41 | 42 | def get_random_word(s, difficult): 43 | possible_words = fetch_words(s, difficult) 44 | word = random.choice(possible_words) 45 | return word 46 | 47 | 48 | def load_words(s): 49 | with open('words.txt', 'r') as file: 50 | for line in file.readlines(): 51 | word = line.strip().lower() 52 | insert_word(s, word, difficult=False) 53 | with open('hard_words.txt', 'r') as file: 54 | for line in file.readlines(): 55 | word = line.strip().lower() 56 | insert_word(s, word, difficult=True) 57 | 58 | 59 | if __name__ == "__main__": 60 | session = DBSession() 61 | 62 | # Create table 63 | create_table() 64 | 65 | word_list = fetch_words(session) 66 | 67 | # Load words if empty 68 | if len(word_list) == 0: 69 | load_words(session) 70 | 71 | word_list = fetch_words(session) 72 | assert len(word_list) > 200, f"{len(word_list)} words in db" 73 | print(f"There are {len(word_list)} words in the database") 74 | easy_word = get_random_word(session, difficult=False) 75 | print(f"Easy word: {easy_word}") 76 | difficult_word = get_random_word(session, difficult=True) 77 | print(f"Difficult word: {difficult_word}") 78 | session.close() 79 | -------------------------------------------------------------------------------- /Examples/DB/hard_words.txt: -------------------------------------------------------------------------------- 1 | Awkward 2 | Bagpipes 3 | Banjo 4 | Bungler 5 | Croquet 6 | Crypt 7 | Dwarves 8 | Fervid 9 | Fishhook 10 | Fjord 11 | Gazebo 12 | Gypsy 13 | Haiku 14 | Haphazard 15 | Hyphen 16 | Ivory 17 | Jazzy 18 | Jiffy 19 | Jinx 20 | Jukebox 21 | Kayak 22 | Kiosk 23 | Klutz 24 | Memento 25 | Mystify 26 | Numbskull 27 | Ostracize 28 | Oxygen 29 | Pajama 30 | Phlegm 31 | Pixel 32 | Polka 33 | Quad 34 | Quip 35 | Rhythmic 36 | Rogue 37 | Sphinx 38 | Squawk 39 | Swivel 40 | Toady 41 | Twelfth 42 | Unzip 43 | Waxy 44 | Wildebeest 45 | Yacht 46 | Zealous 47 | Zigzag 48 | Zippy 49 | Zombie 50 | -------------------------------------------------------------------------------- /Examples/DB/test_orm.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariannedee/python-environments/44a1d7d7d1e50bbc044411e7d396d29f8f69f670/Examples/DB/test_orm.db -------------------------------------------------------------------------------- /Examples/DB/test_orm_declarative.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariannedee/python-environments/44a1d7d7d1e50bbc044411e7d396d29f8f69f670/Examples/DB/test_orm_declarative.db -------------------------------------------------------------------------------- /Examples/DB/test_sql.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariannedee/python-environments/44a1d7d7d1e50bbc044411e7d396d29f8f69f670/Examples/DB/test_sql.db -------------------------------------------------------------------------------- /Examples/DB/words.txt: -------------------------------------------------------------------------------- 1 | account 2 | addition 3 | adjustment 4 | advertisement 5 | agreement 6 | amount 7 | amusement 8 | animal 9 | answer 10 | apparatus 11 | approval 12 | argument 13 | attack 14 | attempt 15 | attention 16 | attraction 17 | authority 18 | balance 19 | behavior 20 | belief 21 | breath 22 | brother 23 | building 24 | business 25 | butter 26 | canvas 27 | chance 28 | change 29 | comfort 30 | committee 31 | company 32 | comparison 33 | competition 34 | condition 35 | connection 36 | control 37 | copper 38 | cotton 39 | country 40 | credit 41 | current 42 | damage 43 | danger 44 | daughter 45 | decision 46 | degree 47 | design 48 | desire 49 | destruction 50 | detail 51 | development 52 | digestion 53 | direction 54 | discovery 55 | discussion 56 | disease 57 | disgust 58 | distance 59 | distribution 60 | division 61 | driving 62 | education 63 | effect 64 | example 65 | exchange 66 | existence 67 | expansion 68 | experience 69 | expert 70 | family 71 | father 72 | feeling 73 | fiction 74 | flight 75 | flower 76 | friend 77 | government 78 | growth 79 | harbor 80 | harmony 81 | hearing 82 | history 83 | impulse 84 | increase 85 | industry 86 | insect 87 | instrument 88 | insurance 89 | interest 90 | invention 91 | journey 92 | knowledge 93 | language 94 | learning 95 | leather 96 | letter 97 | liquid 98 | machine 99 | manager 100 | market 101 | measure 102 | meeting 103 | memory 104 | middle 105 | minute 106 | morning 107 | mother 108 | motion 109 | mountain 110 | nation 111 | number 112 | observation 113 | operation 114 | opinion 115 | organisation 116 | ornament 117 | payment 118 | person 119 | pleasure 120 | poison 121 | polish 122 | porter 123 | position 124 | powder 125 | process 126 | produce 127 | profit 128 | property 129 | protest 130 | punishment 131 | purpose 132 | quality 133 | question 134 | reaction 135 | reading 136 | reason 137 | record 138 | regret 139 | relation 140 | religion 141 | representative 142 | request 143 | respect 144 | reward 145 | rhythm 146 | science 147 | secretary 148 | selection 149 | servant 150 | silver 151 | sister 152 | sneeze 153 | society 154 | statement 155 | stitch 156 | stretch 157 | structure 158 | substance 159 | suggestion 160 | summer 161 | support 162 | surprise 163 | system 164 | teaching 165 | tendency 166 | theory 167 | thought 168 | thunder 169 | transport 170 | trouble 171 | vessel 172 | weather 173 | weight 174 | winter 175 | writing 176 | -------------------------------------------------------------------------------- /Examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariannedee/python-environments/44a1d7d7d1e50bbc044411e7d396d29f8f69f670/Examples/__init__.py -------------------------------------------------------------------------------- /Examples/command_line/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariannedee/python-environments/44a1d7d7d1e50bbc044411e7d396d29f8f69f670/Examples/command_line/__init__.py -------------------------------------------------------------------------------- /Examples/command_line/example_1_sys_args.py: -------------------------------------------------------------------------------- 1 | """ 2 | Python files can accept arguments from the command line. 3 | $ python file.py arg1 arg2 arg3 4 | 5 | The first argument is always the filename. 6 | All arguments are strings. 7 | """ 8 | 9 | import sys 10 | 11 | from module import greet 12 | 13 | args = sys.argv 14 | 15 | print(f'Received {len(args)} arguments:') 16 | for arg in args: 17 | print(' ' + arg) 18 | 19 | # ------------------------------------------ # 20 | 21 | shout = False 22 | num = 1 23 | for arg in args[1:]: 24 | if arg == '--shout': 25 | shout = True 26 | else: 27 | num = int(arg) 28 | 29 | name = input("What's your name? ") 30 | greet(name, num, shout) 31 | -------------------------------------------------------------------------------- /Examples/command_line/example_2_argparse.py: -------------------------------------------------------------------------------- 1 | """ 2 | Arguments using the built-in argparse module 3 | """ 4 | import argparse 5 | 6 | from module import greet 7 | 8 | parser = argparse.ArgumentParser(description='An example program') 9 | parser.add_argument('--shout', action="store_true") 10 | parser.add_argument('number', type=int, nargs='?', default=1) 11 | 12 | args = parser.parse_args() 13 | 14 | print(f'shout {args.shout}') 15 | print(f'number {args.number}') 16 | 17 | # ------------------------------------------ # 18 | 19 | name = input("What's your name? ") 20 | greet(name, args.number, args.shout) 21 | -------------------------------------------------------------------------------- /Examples/command_line/example_3_click.py: -------------------------------------------------------------------------------- 1 | #! /Library/Frameworks/Python.framework/Versions/3.10/bin/python3 2 | """ 3 | Creating command line applications using the click library 4 | Install using $ pip install click 5 | """ 6 | import click 7 | 8 | from module import greet 9 | 10 | 11 | @click.command() 12 | @click.argument('num', default=1) 13 | @click.option('--shout', is_flag=True) 14 | @click.option('--name', prompt='Your name', help='The person to greet.') 15 | def hello(num, name, shout): 16 | greet(name, num, shout) 17 | 18 | 19 | hello() 20 | -------------------------------------------------------------------------------- /Examples/command_line/module.py: -------------------------------------------------------------------------------- 1 | """ 2 | print "Hello ", count number of times 3 | Make greeting all uppercase if shout == True 4 | """ 5 | 6 | 7 | def greet(name, count=1, shout=False): 8 | greeting = f'Hello {name}' 9 | if shout: 10 | greeting = greeting.upper() 11 | for i in range(count): 12 | print(greeting) 13 | 14 | 15 | if __name__ == "__main__": 16 | greet("Arianne", 5) 17 | greet("Young-Woo", 2, shout=True) 18 | -------------------------------------------------------------------------------- /Examples/gui/example_1_tkinter.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | 4 | class Application(tk.Frame): 5 | def __init__(self, master=None): 6 | super().__init__(master) 7 | self.master = master 8 | self.pack() 9 | self.text = 'Hello' 10 | self.create_widgets() 11 | 12 | def create_widgets(self): 13 | self.label = tk.Label(self, {'text': 'This is a heading'}, font=("Helvetica", 24)) 14 | self.label.pack(pady=20, padx=30) 15 | 16 | self.string_variable = tk.StringVar() 17 | self.string_variable.set(self.text) 18 | self.word_state = tk.Label(self, textvariable=self.string_variable) 19 | self.word_state.pack() 20 | 21 | self.input = tk.Entry(self) 22 | self.input.pack(side=tk.LEFT, padx=20, pady=20) 23 | 24 | self.button = tk.Button(self) 25 | self.button["text"] = 'Save' 26 | self.button["command"] = self.save_btn 27 | self.button.pack(side=tk.LEFT, padx=20, pady=20) 28 | 29 | def save_btn(self): 30 | self.text = self.input.get() 31 | self.string_variable.set(self.text) 32 | self.input.delete(0, len(self.text)) 33 | 34 | 35 | if __name__ == '__main__': 36 | root = tk.Tk() 37 | app = Application(master=root) 38 | app.mainloop() 39 | -------------------------------------------------------------------------------- /Examples/gui/example_2_pysimplegui.py: -------------------------------------------------------------------------------- 1 | import PySimpleGUI as sg 2 | 3 | sg.theme('Light Green') 4 | 5 | # 1- the layout 6 | layout = [[sg.Text('Your typed chars appear here:'), sg.Text(size=(15, 1), key='-OUTPUT-')], 7 | [sg.Input(key='-IN-')], 8 | [sg.Button('Show'), sg.Button('Exit')]] 9 | 10 | # 2 - the window 11 | window = sg.Window('Pattern 2', layout) 12 | 13 | # 3 - the event loop 14 | while True: 15 | event, values = window.read() 16 | print(event, values) 17 | if event == sg.WIN_CLOSED or event == 'Exit': 18 | break 19 | if event == 'Show': 20 | # Select the "output" text element and set the text to the value of "input" element 21 | window['-OUTPUT-'].update(values['-IN-']) 22 | 23 | # 4 - the close 24 | window.close() 25 | -------------------------------------------------------------------------------- /Examples/modules/example_1_modules.py: -------------------------------------------------------------------------------- 1 | from package import package_func 2 | from package.package_module import package_module_func as pmf 3 | from package.subpackage import sub_module_func 4 | from pprint import pprint 5 | 6 | def func(): 7 | print('example 1 modules: ' + __name__) 8 | 9 | 10 | if __name__ == '__main__': 11 | func() 12 | package_func() 13 | pmf() 14 | sub_module_func() 15 | 16 | import sys 17 | pprint(sys.path) 18 | -------------------------------------------------------------------------------- /Examples/modules/example_2_namespaces.py: -------------------------------------------------------------------------------- 1 | """ 2 | There are 4 types of namespaces: 3 | - built-in 4 | - global 5 | - enclosing 6 | - local 7 | """ 8 | import math 9 | from random import * 10 | 11 | pi = math.pi 12 | 13 | print(f'Built-ins\n{dir(__builtins__)}\n') 14 | 15 | 16 | def outer_function(a): 17 | def inner_function(b): 18 | a = 'Z' # Creates a new local variable (a) that is destroyed once out of inner_function 19 | print(f'Inner function locals\n{locals()}\n') 20 | 21 | inner_function("B") 22 | print(f'Outer function locals\n{locals()}\n') 23 | 24 | 25 | print(f'Globals\n{globals()}\n') 26 | 27 | outer_function("A") 28 | -------------------------------------------------------------------------------- /Examples/modules/package/__init__.py: -------------------------------------------------------------------------------- 1 | print("Package imported") 2 | 3 | 4 | def package_func(): 5 | print('package init: ' + __name__) 6 | 7 | 8 | if __name__ == '__main__': 9 | package_func() 10 | -------------------------------------------------------------------------------- /Examples/modules/package/package_module.py: -------------------------------------------------------------------------------- 1 | def package_module_func(): 2 | print('package module: ' + __name__) 3 | -------------------------------------------------------------------------------- /Examples/modules/package/subpackage/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Anything imported in __init__.py can be imported from the package 3 | 4 | e.g. You can do: 5 | from package.subpackage import sub_module_func 6 | 7 | As well as the standard: 8 | from package.subpackage.sub_module import sub_module_func 9 | """ 10 | 11 | from .sub_module import sub_module_func # relative import 12 | -------------------------------------------------------------------------------- /Examples/modules/package/subpackage/sub_module.py: -------------------------------------------------------------------------------- 1 | def sub_module_func(): 2 | print('sub module: ' + __name__) 3 | -------------------------------------------------------------------------------- /Examples/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariannedee/python-environments/44a1d7d7d1e50bbc044411e7d396d29f8f69f670/Examples/tests/__init__.py -------------------------------------------------------------------------------- /Examples/tests/example_1_assert.py: -------------------------------------------------------------------------------- 1 | from rock_paper_scissors_buggy import determine_winner, game_over, YOU, COMP 2 | 3 | 4 | def assert_equals(actual, expected): 5 | assert actual == expected, f"Expected {expected}, got {actual}" 6 | 7 | 8 | def test_determine_winner(): 9 | test_cases = ( 10 | ('r', 'r', None), 11 | ('r', 'p', COMP), 12 | ('r', 's', YOU), 13 | ('p', 'r', YOU), 14 | ('p', 'p', None), 15 | ('p', 's', COMP), 16 | ('s', 'r', COMP), 17 | ('s', 'p', YOU), 18 | ('s', 's', None), 19 | ) 20 | 21 | for case in test_cases: 22 | you, comp, winner = case 23 | assert_equals(determine_winner(you, comp), winner) 24 | 25 | print('determine_winner tests passed') 26 | 27 | 28 | def test_game_over(): 29 | test_cases = ( 30 | (3, [0, 0], None), 31 | (3, [1, 1], None), 32 | (3, [2, 1], YOU), 33 | (3, [1, 2], COMP), 34 | (5, [2, 2], None), 35 | (5, [3, 0], YOU), 36 | (5, [1, 3], COMP), 37 | ) 38 | 39 | for case in test_cases: 40 | best_of, score, winner = case 41 | assert_equals(game_over(best_of, score), winner) 42 | 43 | print('game_over tests passed') 44 | 45 | 46 | test_determine_winner() 47 | test_game_over() 48 | 49 | print("Tests passed") 50 | -------------------------------------------------------------------------------- /Examples/tests/example_2_unittest.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from rock_paper_scissors_buggy import determine_winner, game_over, YOU, COMP 4 | 5 | 6 | class TestRPSGame(unittest.TestCase): 7 | def test_determine_winner(self): 8 | self.assertEqual(determine_winner('r', 'r'), None) 9 | self.assertEqual(determine_winner('r', 'p'), COMP) 10 | self.assertEqual(determine_winner('r', 's'), YOU) 11 | self.assertEqual(determine_winner('p', 'r'), YOU) 12 | self.assertEqual(determine_winner('p', 'p'), None) 13 | self.assertEqual(determine_winner('p', 's'), COMP) 14 | self.assertEqual(determine_winner('s', 'r'), COMP) 15 | self.assertEqual(determine_winner('s', 'p'), YOU) 16 | self.assertEqual(determine_winner('s', 's'), None) 17 | 18 | def test_game_over(self): 19 | self.assertEqual(game_over(3, [0, 0]), None) 20 | self.assertEqual(game_over(3, [1, 1]), None) 21 | self.assertEqual(game_over(3, [2, 1]), YOU) 22 | self.assertEqual(game_over(3, [1, 2]), COMP) 23 | self.assertEqual(game_over(5, [2, 2]), None) 24 | self.assertEqual(game_over(5, [3, 0]), YOU) 25 | self.assertEqual(game_over(5, [1, 3]), COMP) 26 | 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /Examples/tests/example_3_pytest.py: -------------------------------------------------------------------------------- 1 | """ 2 | In terminal, run $ pytest 3 | """ 4 | from .rock_paper_scissors_buggy import determine_winner, game_over, YOU, COMP 5 | 6 | 7 | def test_determine_winner(): 8 | test_cases = ( 9 | ('r', 'r', None), 10 | ('r', 'p', COMP), 11 | ('r', 's', YOU), 12 | ('p', 'r', YOU), 13 | ('p', 'p', None), 14 | ('p', 's', COMP), 15 | ('s', 'r', COMP), 16 | ('s', 'p', YOU), 17 | ('s', 's', None), 18 | ) 19 | 20 | for case in test_cases: 21 | you, comp, winner = case 22 | assert determine_winner(you, comp) == winner 23 | 24 | 25 | def test_game_over(): 26 | test_cases = ( 27 | (3, [0, 0], None), 28 | (3, [1, 1], None), 29 | (3, [2, 1], YOU), 30 | (3, [1, 2], COMP), 31 | (5, [2, 2], None), 32 | (5, [3, 0], YOU), 33 | (5, [1, 3], COMP), 34 | ) 35 | 36 | for case in test_cases: 37 | best_of, score, winner = case 38 | assert game_over(best_of, score) == winner 39 | -------------------------------------------------------------------------------- /Examples/tests/example_4_pytest_parameterized.py: -------------------------------------------------------------------------------- 1 | """ 2 | import pytest 3 | In terminal, run $ pytest 4 | """ 5 | import pytest 6 | 7 | from .rock_paper_scissors_buggy import determine_winner, game_over, YOU, COMP 8 | 9 | 10 | @pytest.mark.parametrize("you, comp, expected_winner", [ 11 | ('r', 'r', None), 12 | ('r', 'p', COMP), 13 | ('r', 's', YOU), 14 | ('p', 'r', YOU), 15 | ('p', 'p', None), 16 | ('p', 's', COMP), 17 | ('s', 'r', COMP), 18 | ('s', 'p', YOU), 19 | ('s', 's', None), 20 | ]) 21 | def test_determine_winner(you, comp, expected_winner): 22 | assert determine_winner(you, comp) == expected_winner 23 | 24 | 25 | @pytest.mark.parametrize("best_of, score, expected_winner", [ 26 | (3, [0, 0], None), 27 | (3, [1, 1], None), 28 | (3, [2, 1], YOU), 29 | (3, [1, 2], COMP), 30 | (5, [2, 2], None), 31 | (5, [3, 0], YOU), 32 | (5, [1, 3], COMP) 33 | ]) 34 | def test_game_over(best_of, score, expected_winner): 35 | assert game_over(best_of, score) == expected_winner 36 | -------------------------------------------------------------------------------- /Examples/tests/rock_paper_scissors_buggy.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | YOU = 0 4 | COMP = 1 5 | 6 | CHOICES = ['r', 'p', 's'] 7 | CHOICE_MAP = {'r': 'Rock', 'p': 'Paper', 's': 'Scissors'} 8 | 9 | 10 | def play_game(best_of=3): 11 | """ 12 | Play a game of rock, paper, scissors 13 | """ 14 | score = [0, 0] 15 | 16 | print(f'Rock, paper, scissors - best of {best_of}') 17 | 18 | while True: 19 | winner = run_round() 20 | update_score(score, winner) 21 | game_winner = game_over(best_of, score) 22 | 23 | if game_winner is not None: 24 | break 25 | 26 | won_or_lost = 'won' if game_winner == YOU else 'lost' 27 | print(f"You {won_or_lost} {score[YOU]} games to {score[COMP]}") 28 | 29 | 30 | def update_score(score, winner): 31 | if winner is not None: 32 | score[winner] += 1 33 | print(f'{score[YOU]} - {score[COMP]}') 34 | 35 | 36 | def run_round(): 37 | your_choice = get_user_choice() 38 | computer_choice = random.choice(CHOICES) 39 | 40 | winner = determine_winner(your_choice, computer_choice) 41 | print_outcome(winner, your_choice, computer_choice) 42 | return winner 43 | 44 | 45 | def determine_winner(choice, computer_choice): 46 | """ 47 | Returns: 48 | YOU if you won 49 | COMP if computer won 50 | None if it was a tie 51 | """ 52 | if choice == 'r': 53 | return YOU if computer_choice == 's' else COMP 54 | elif choice == 'p': 55 | return YOU if computer_choice == 'r' else COMP 56 | elif choice == 's': 57 | return YOU if computer_choice == 'p' else COMP 58 | else: 59 | return None 60 | 61 | 62 | def print_outcome(winner, you, computer): 63 | if winner == YOU: 64 | result = 'WINS against' 65 | elif winner == COMP: 66 | result = 'LOSES to' 67 | else: 68 | result = "TIES with" 69 | print(f'{CHOICE_MAP[you]} {result} {CHOICE_MAP[computer]}') 70 | 71 | 72 | def game_over(best_of, score): 73 | num_wins_needed = best_of / 2 74 | if score[YOU] == num_wins_needed: 75 | return YOU 76 | elif score[COMP] == num_wins_needed: 77 | return COMP 78 | return None 79 | 80 | 81 | def get_user_choice(): 82 | return input("\nRock (r), paper (p), or scissors (s)?: ").lower().strip() 83 | 84 | 85 | if __name__ == '__main__': 86 | play_game() 87 | -------------------------------------------------------------------------------- /Examples/tests/rock_paper_scissors_fixed.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | YOU = 0 4 | COMP = 1 5 | 6 | CHOICES = ['r', 'p', 's'] 7 | CHOICE_MAP = {'r': 'Rock', 'p': 'Paper', 's': 'Scissors'} 8 | 9 | 10 | def play_game(best_of=3): 11 | """ 12 | Play a game of rock, paper, scissors 13 | """ 14 | score = [0, 0] 15 | 16 | print(f'Rock, paper, scissors - best of {best_of}') 17 | 18 | while True: 19 | winner = run_round() 20 | update_score(score, winner) 21 | game_winner = game_over(best_of, score) 22 | 23 | if game_winner is not None: 24 | break 25 | 26 | won_or_lost = 'won' if game_winner == YOU else 'lost' 27 | print(f"You {won_or_lost} {score[YOU]} games to {score[COMP]}") 28 | 29 | 30 | def update_score(score, winner): 31 | if winner is not None: 32 | score[winner] += 1 33 | print(f'{score[YOU]} - {score[COMP]}') 34 | 35 | 36 | def run_round(): 37 | your_choice = get_user_choice() 38 | computer_choice = random.choice(CHOICES) 39 | 40 | winner = determine_winner(your_choice, computer_choice) 41 | print_outcome(winner, your_choice, computer_choice) 42 | return winner 43 | 44 | 45 | def determine_winner(choice, computer_choice): 46 | """ 47 | Returns: 48 | YOU if you won 49 | COMP if computer won 50 | None if it was a tie 51 | """ 52 | if choice == computer_choice: 53 | return None 54 | elif choice == 'r': 55 | return YOU if computer_choice == 's' else COMP 56 | elif choice == 'p': 57 | return YOU if computer_choice == 'r' else COMP 58 | else: 59 | return YOU if computer_choice == 'p' else COMP 60 | 61 | 62 | def print_outcome(winner, you, computer): 63 | if winner == YOU: 64 | result = 'WINS against' 65 | elif winner == COMP: 66 | result = 'LOSES to' 67 | else: 68 | result = "TIES with" 69 | print(f'{CHOICE_MAP[you]} {result} {CHOICE_MAP[computer]}') 70 | 71 | 72 | def game_over(best_of, score): 73 | num_wins_needed = (best_of + 1) / 2 74 | 75 | if score[YOU] >= num_wins_needed: 76 | return YOU 77 | elif score[COMP] >= num_wins_needed: 78 | return COMP 79 | return None 80 | 81 | 82 | def get_user_choice(): 83 | choice = input("\nRock (r), paper (p), or scissors (s)?: ").lower().strip() 84 | if choice not in CHOICES: 85 | print("Invalid choice!") 86 | return get_user_choice() 87 | return choice 88 | 89 | 90 | if __name__ == '__main__': 91 | play_game() 92 | -------------------------------------------------------------------------------- /Project/Solutions/game_1_command_line.py: -------------------------------------------------------------------------------- 1 | """ 2 | A word guessing game 3 | Run from the command line 4 | Accepts an optional "num" argument for the number of wrong guesses allowed (default is 6) 5 | Accepts an optional "--hard" flag to play with a hard word 6 | """ 7 | import click 8 | 9 | from word_game.game import WordGame 10 | 11 | 12 | @click.command() 13 | @click.argument('num', default=6) 14 | @click.option('--hard', is_flag=True) 15 | def game(num, hard): 16 | WordGame(num_wrong_guesses=num, hard_word=hard).play_game() 17 | 18 | 19 | if __name__ == '__main__': 20 | game() 21 | -------------------------------------------------------------------------------- /Project/Solutions/game_2_tkinter.py: -------------------------------------------------------------------------------- 1 | """ 2 | A GUI word guessing game built in Tkinter 3 | """ 4 | import tkinter as tk 5 | from functools import partial 6 | 7 | from word_game import game 8 | 9 | 10 | class Application(tk.Frame): 11 | def __init__(self, master=None): 12 | super().__init__(master) 13 | self.game = game.WordGame() 14 | self.master = master 15 | self.pack() 16 | self.create_widgets() 17 | 18 | def create_widgets(self): 19 | self.title = tk.Label(self, {'text': 'Guess the word'}, font=("Helvetica", 24)) 20 | self.title.pack(pady=20) 21 | 22 | self.display_word = tk.StringVar() 23 | self.display_word.set(self.game.display_word) 24 | self.word_state = tk.Label(self, textvariable=self.display_word, font=("Helvetica", 24)) 25 | self.word_state.pack() 26 | 27 | self.game_state = tk.StringVar() 28 | self.game_state.set(f'{self.game.wrong_guesses_left} wrong guesses left') 29 | self.wrong_guesses = tk.Label(self, textvariable=self.game_state) 30 | self.wrong_guesses.pack(pady=10) 31 | 32 | self.buttons = [] 33 | self.frame1 = tk.Frame() 34 | self.frame2 = tk.Frame() 35 | self.frame1.pack(padx=40) 36 | self.frame2.pack(padx=40, pady=30) 37 | for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': 38 | if letter <= 'N': 39 | frame = self.frame1 40 | else: 41 | frame = self.frame2 42 | button = tk.Button(frame) 43 | button["text"] = letter 44 | button["command"] = partial(self.guess_letter(button)) 45 | button.pack(side=tk.LEFT) 46 | self.buttons.append(button) 47 | 48 | def update_state(self): 49 | if self.game.game_over(): 50 | self.display_word.set(self.game.word.upper()) 51 | for button in self.buttons: 52 | button['state'] = 'disabled' 53 | else: 54 | self.display_word.set(self.game.display_word.upper()) 55 | self.game_state.set(f'{self.game.wrong_guesses_left} wrong guesses left') 56 | 57 | if self.game.game_lost(): 58 | self.game_state.set('You lost') 59 | elif self.game.game_won(): 60 | self.game_state.set(f'You won!') 61 | self.update_idletasks() 62 | 63 | def guess_letter(self, button): 64 | letter = button['text'] 65 | 66 | def inner(): 67 | self.game.guess_letter(letter) 68 | self.update_state() 69 | button["state"] = "disabled" 70 | 71 | return inner 72 | 73 | 74 | if __name__ == '__main__': 75 | root = tk.Tk() 76 | app = Application(master=root) 77 | app.mainloop() 78 | -------------------------------------------------------------------------------- /Project/Solutions/game_3_pysimplegui.py: -------------------------------------------------------------------------------- 1 | """ 2 | A GUI word guessing game built in PySimpleGui 3 | """ 4 | import PySimpleGUI as sg 5 | 6 | from word_game.game import WordGame 7 | 8 | game = WordGame() 9 | 10 | # Set theme 11 | sg.theme('Material2') 12 | 13 | # Set layout 14 | buttons_row_1 = [] 15 | buttons_row_2 = [] 16 | for char in "abcdefghijklmnopqrstuvwxyz".upper(): 17 | if char < 'N': 18 | buttons_row_1.append(sg.Button(char)) 19 | else: 20 | buttons_row_2.append(sg.Button(char)) 21 | 22 | layout = [[sg.Text('Guess the word'), sg.Text(size=(24, 1))], 23 | [sg.Text(''), sg.Text(size=(24, 1), key='-DISPLAY-')], 24 | [sg.Text(''), sg.Text(size=(16, 1), key='-STATE-')], 25 | buttons_row_1, 26 | buttons_row_2] 27 | 28 | # Create window 29 | window = sg.Window('Guessing game', layout) 30 | window.finalize() 31 | 32 | # Set initial state 33 | window['-DISPLAY-'].update(game.display_word) 34 | window['-STATE-'].update(f'{game.wrong_guesses_left} wrong guesses left') 35 | 36 | # Event loop (wait for event and react) 37 | while True: 38 | event, values = window.read() 39 | print(event, values) 40 | if event is None: 41 | break 42 | game.guess_letter(event) 43 | window['-DISPLAY-'].update(game.display_word) 44 | new_status = '' 45 | window[event].update(disabled=True) 46 | if game.game_won(): 47 | new_status = 'You won!' 48 | elif game.game_lost(): 49 | new_status = 'You lost' 50 | else: 51 | new_status = f'{game.wrong_guesses_left} wrong guesses left' 52 | 53 | window['-STATE-'].update(new_status) 54 | 55 | # Close window 56 | window.close() 57 | -------------------------------------------------------------------------------- /Project/game_1_command_line.py: -------------------------------------------------------------------------------- 1 | """ 2 | A word guessing game 3 | Run from the command line 4 | Accepts an optional "num" argument for the number of wrong guesses allowed (default is 6) 5 | Accepts an optional "--hard" flag to play with a hard word 6 | """ 7 | -------------------------------------------------------------------------------- /Project/game_2_gui.py: -------------------------------------------------------------------------------- 1 | """ 2 | A GUI word guessing game 3 | """ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Environments and Best Practises Live Training 2 | 3 | This is the code for the *O'Reilly Live Training* - **Python Environments and Best Practises** presented by Arianne Dee 4 | 5 | **Note**: If you're looking for the project code for a specific date in the past, 6 | look for the specific class [here](https://github.com/ariannedee/python-environments/releases) 7 | 8 | Before the class, please follow these instructions: 9 | 1. [Install Python](#1-install-python-38-or-higher) 10 | 1. [Check that Python was installed properly](#2-make-sure-that-python-is-properly-installed) 11 | 1. [Install PyCharm](#3-download-pycharm-community-edition) 12 | 1. [Download the code](#4-download-the-course-files) 13 | 14 | ## Set up instructions 15 | ### 1. Install Python 3.8 or higher 16 | Go to https://www.python.org/downloads/ 17 | 18 | Click the yellow button at the top to download the latest version of Python. 19 | 20 | #### On Mac or Linux 21 | Follow the prompts and install using the default settings. 22 | 23 | #### On Windows 24 | The default settings don't add Python to your PATH 25 | so your computer doesn't know where to look for it when Python runs 26 | (for some inexplicable reason). 27 | 28 | ##### If you're just installing Python now 29 | Follow the instructions here: [Windows Python installer instructions](docs/WININSTALL.md) 30 | 31 | ##### If you've already installed Python with the default settings 32 | Follow the instructions here: [Add Python to PATH variable in Windows](docs/WINSETPATH.md) 33 | 34 | ### 2. Make sure that Python is properly installed 35 | 1. Open the *Command Prompt* application in Windows 36 | or *Terminal* on Mac or Linux 37 | 38 | 1. Type `python --version` and press enter 39 | 40 | 1. Type `python3 --version` and press enter 41 | 42 | 1. One or both of those commands should print 43 | a Python version of 3.8 or higher 44 | (whichever version you just downloaded). 45 | If it doesn't, you have to follow instructions to 46 | [add Python to your PATH variable](docs/WINSETPATH.md). 47 | 48 | **Note:** 49 | You can now type just the `python` or `python3` command 50 | in *Command Prompt* or *Terminal* 51 | to run the Python interpreter. 52 | You can also run a *.py* file by running 53 | `python filename.py` 54 | 55 | ### 3. Download PyCharm (Community Edition) 56 | Download here: https://www.jetbrains.com/pycharm/download/ 57 | 58 | Install, open, and use the default settings. 59 | 60 | ### 4. Download the course files 61 | If you're viewing this on GitHub already, stay on this page. 62 | Otherwise, go to the GitHub repository: https://github.com/ariannedee/python-environments 63 | 64 | #### If you know git: 65 | Clone the repository. 66 | 67 | #### If you don't know git: 68 | 1. Click the "Clone or download" (green) button at the top-right of the page 69 | 2. Click "Download ZIP" 70 | 3. Unzip it and move the **python-environments-main** folder to a convenient location 71 | 72 | ## FAQs 73 | ### Can I use Python 2? 74 | 75 | No. Please use Python 3.8 or higher. 76 | 77 | ### Can I use a different code editor besides PyCharm? 78 | 79 | You can use VS Code for this class. 80 | 81 | Jupyter notebooks are not ideal since we'll be working from multiple folders throughout the class. 82 | 83 | ### PyCharm can't find Python 3 84 | 85 | On a Mac: 86 | - Go to **PyCharm** > **Preferences** 87 | 88 | On a PC: 89 | - Go to **File** > **Settings** 90 | 91 | Once in Settings: 92 | 1. Go to **Project: python-environments** > **Project Interpreter** 93 | 1. Look for your Python version in the Project Interpreter dropdown 94 | 1. If it's not there, click **gear icon** > **Add...** 95 | 1. In the new window, select **System Interpreter** on the left, and then look for the Python version in the dropdown 96 | 1. If it's not there, click the **...** button and navigate to your Python location 97 | - To find where Python is located, [look in these directories](docs/PATH_LOCATIONS.md) 98 | - You may have to search the internet for where Python gets installed by default on your operating system 99 | 100 | ### Do you offer private Python help? 101 | Yes, email **arianne.dee.studios at gmail.com** if you have any questions 102 | or would like to set up some remote training. 103 | -------------------------------------------------------------------------------- /Sample notebook.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "6a59701e", 6 | "metadata": {}, 7 | "source": [ 8 | "# My notebook\n", 9 | "\n", 10 | "## Some subtitle\n", 11 | "\n", 12 | "I'm showing you how to use notebooks" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "id": "9eb182d1", 18 | "metadata": {}, 19 | "source": [ 20 | "### Variables" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 1, 26 | "id": "4235e3e3", 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "name": "stdout", 31 | "output_type": "stream", 32 | "text": [ 33 | "13\n" 34 | ] 35 | } 36 | ], 37 | "source": [ 38 | "my_var = 10\n", 39 | "my_var += 3\n", 40 | "print(my_var)" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "id": "d627740c", 46 | "metadata": {}, 47 | "source": [ 48 | "### Functions" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 2, 54 | "id": "15646f84", 55 | "metadata": {}, 56 | "outputs": [ 57 | { 58 | "data": { 59 | "text/plain": [ 60 | "5" 61 | ] 62 | }, 63 | "execution_count": 2, 64 | "metadata": {}, 65 | "output_type": "execute_result" 66 | } 67 | ], 68 | "source": [ 69 | "def my_func(n1, n2):\n", 70 | " return n1 + n2\n", 71 | "\n", 72 | "my_func(2, 3)" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "id": "7e36aa85", 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [] 82 | } 83 | ], 84 | "metadata": { 85 | "kernelspec": { 86 | "display_name": "Python 3", 87 | "language": "python", 88 | "name": "python3" 89 | }, 90 | "language_info": { 91 | "codemirror_mode": { 92 | "name": "ipython", 93 | "version": 3 94 | }, 95 | "file_extension": ".py", 96 | "mimetype": "text/x-python", 97 | "name": "python", 98 | "nbconvert_exporter": "python", 99 | "pygments_lexer": "ipython3", 100 | "version": "3.8.2" 101 | } 102 | }, 103 | "nbformat": 4, 104 | "nbformat_minor": 5 105 | } 106 | -------------------------------------------------------------------------------- /docs/WININSTALL.md: -------------------------------------------------------------------------------- 1 | ## Installing Python on Windows 2 | The Python installer for Windows doesn't use the optimal default settings. 3 | Follow these instructions when running the installer. 4 | If you have already installed Python with the default settings, 5 | follow the instructions here instead: [add Python to the PATH variable](WINSETPATH.md) 6 | 7 | 1. Check the *Add Python to PATH* box 8 | 2. Choose the *Customize installation* option 9 | 10 | 11 | 3. Keep the default settings and click *Next* 12 | 13 | 14 | 4. Check the *Install for all users* box 15 | 5. Customize the install location: **C:\Python39** or whatever version number you're installing 16 | 6. Click *Install* 17 | 18 | -------------------------------------------------------------------------------- /docs/WINSETPATH.md: -------------------------------------------------------------------------------- 1 | ## Windows set up instruction 2 | If you installed Python with the default options, 3 | you will probably need to add Python to the PATH variable. 4 | This let's your operating system know where to look for the Python executable 5 | when you try running it. 6 | 7 | To add Python to your PATH variable: 8 | 1. Find the path of **python.exe** on your system. 9 | It could be in **C:\Python39** or **C:\Program Files\Python39** 10 | or **C:\Users\username\AppData\Local\Programs\Python\Python39-XX**, 11 | but you can always just search for it. 12 | 13 | 1. Open *System Properties* and click on the *Advanced* tab 14 | 15 | 1. Click on *Environment Variables* 16 | 17 | 1. Under *System variables* find and click on the *Path* variable 18 | 19 | 1. In edit mode, go to the end of the line and add **;C:\Python39** or whatever folder *python.exe* is in. 20 | Note the semicolon before the path; this will separate it from the previous path. 21 | 22 | To check that the PATH variable was set properly: 23 | 1. Open the *Command Prompt* application in Windows 24 | or *Terminal* on Mac or Linux 25 | 26 | 1. Type `python --version` and press enter 27 | 28 | 1. Type `python3 --version` and press enter 29 | 30 | 1. Type `py --version` and press enter (Windows) 31 | 32 | 1. At least one of these commands should print 33 | a Python version of 3.6 or higher 34 | (whichever version you just downloaded) 35 | 36 | If you are having problems: 37 | 38 | Search the internet for "**Add python to path on Windows *10 / Vista / XP / etc***" 39 | to find instructions for your version of Windows. 40 | -------------------------------------------------------------------------------- /docs/installer_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariannedee/python-environments/44a1d7d7d1e50bbc044411e7d396d29f8f69f670/docs/installer_1.png -------------------------------------------------------------------------------- /docs/installer_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariannedee/python-environments/44a1d7d7d1e50bbc044411e7d396d29f8f69f670/docs/installer_2.png -------------------------------------------------------------------------------- /docs/installer_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariannedee/python-environments/44a1d7d7d1e50bbc044411e7d396d29f8f69f670/docs/installer_3.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | click # https://click.palletsprojects.com/ 2 | PySimpleGUI==5.0.99.99 # https://pysimplegui.readthedocs.io/ 3 | pytest>=6 # https://docs.pytest.org/ 4 | SQLAlchemy>=1,<2 # https://www.sqlalchemy.org/ 5 | -------------------------------------------------------------------------------- /word_game/data/__init__.py: -------------------------------------------------------------------------------- 1 | from .get_data import get_random_word 2 | -------------------------------------------------------------------------------- /word_game/data/get_data.py: -------------------------------------------------------------------------------- 1 | import random 2 | from pathlib import Path 3 | 4 | from sqlalchemy import ( 5 | Boolean, 6 | Column, 7 | create_engine, 8 | MetaData, 9 | Table, 10 | String, 11 | ) 12 | 13 | 14 | def get_path(filename): 15 | folder = Path(__file__).parent 16 | full_path = folder / filename 17 | return full_path 18 | 19 | 20 | engine = create_engine(f'sqlite:///{get_path("words.db")}', echo=True) 21 | 22 | meta = MetaData() 23 | 24 | words = Table( 25 | 'words', meta, 26 | Column('word', String), 27 | Column('difficult', Boolean), 28 | ) 29 | 30 | 31 | def sql_connection(): 32 | return engine.connect() 33 | 34 | 35 | def create_table(): 36 | meta.create_all(engine, [words]) 37 | 38 | 39 | def insert_word(connection, word, difficult): 40 | insert = words.insert().values(word=word, difficult=difficult) 41 | connection.execute(insert) 42 | 43 | 44 | def fetch_words(connection, difficult=None): 45 | q = words.select() 46 | if difficult is not None: 47 | q = q.where(words.c.difficult == difficult) 48 | result = connection.execute(q).fetchall() 49 | return [row[0] for row in result] 50 | 51 | 52 | def get_random_word(difficult=False): 53 | con = sql_connection() 54 | possible_words = fetch_words(con, difficult) 55 | con.close() 56 | word = random.choice(possible_words) 57 | return word 58 | -------------------------------------------------------------------------------- /word_game/data/words.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ariannedee/python-environments/44a1d7d7d1e50bbc044411e7d396d29f8f69f670/word_game/data/words.db -------------------------------------------------------------------------------- /word_game/game.py: -------------------------------------------------------------------------------- 1 | """ 2 | Word guessing game. When player guesses 6 wrong letters, they lose. 3 | """ 4 | from .data import get_random_word 5 | 6 | 7 | class WordGame(object): 8 | def __init__(self, hard_word=False, num_wrong_guesses=6): 9 | self.word = get_random_word().lower().strip() 10 | self.guessed_letters = [] 11 | self.wrong_guesses_left = num_wrong_guesses 12 | print(f'New game created{": hard mode" if hard_word else ""}') 13 | 14 | @property 15 | def display_word(self): 16 | return ' '.join([letter if letter in self.guessed_letters else '_' 17 | for letter in self.word]) 18 | 19 | def guess_is_correct(self, guess): 20 | return guess in self.word 21 | 22 | def game_won(self): 23 | for letter in self.word: 24 | if letter not in self.guessed_letters: 25 | return False 26 | return True 27 | 28 | def game_lost(self): 29 | return self.wrong_guesses_left == 0 30 | 31 | def game_over(self): 32 | return self.game_lost() or self.game_won() 33 | 34 | def play_game(self): 35 | while True: 36 | # Display current state of the game 37 | print(self.display_word) 38 | print(f'Guessed letters: {" ".join(self.guessed_letters) if len(self.guessed_letters) else "None"}') 39 | print(f'Guesses left: {self.wrong_guesses_left}\n') 40 | 41 | # Get a guess from the user 42 | guess = input('Guess a letter: ') 43 | print() 44 | 45 | correct = self.guess_letter(guess) 46 | if correct: 47 | print('Correct!') 48 | else: 49 | print('Nope!') 50 | 51 | # Check to see if they won or lost 52 | if self.game_won(): 53 | print(f'You won :) The word was "{self.word}"') 54 | return 55 | elif self.game_lost(): 56 | print(f'You lost :( The word was "{self.word}"') 57 | return 58 | 59 | def guess_letter(self, guess): 60 | guess = guess.lower() 61 | self.guessed_letters.append(guess) 62 | if self.guess_is_correct(guess): 63 | correct = True 64 | else: 65 | self.wrong_guesses_left -= 1 66 | correct = False 67 | return correct 68 | 69 | 70 | if __name__ == '__main__': 71 | game = WordGame() 72 | game.play_game() 73 | --------------------------------------------------------------------------------