commit e85b3b21ca40bcd945935ad4971bc688fd091371 Author: Pamela Hathway Date: Sun Jul 20 22:10:03 2025 +0200 adds 2025 materials diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6856bdb --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.egg-info +*.DS_Store +*~$*.pptx \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/exercises/Exercise 1a Local imports.md b/exercises/Exercise 1a Local imports.md new file mode 100644 index 0000000..af80c27 --- /dev/null +++ b/exercises/Exercise 1a Local imports.md @@ -0,0 +1,34 @@ +## Exercise 1a: Local importing + +#### Goal + +Retrival practice in "basic" importing. + +#### Preparation + +(none) + +#### Tasks + +We are simulating having code in one folder and calling the code from the folder above. + +0. Create a file in the `src/` folder called `daily_menu.py` and copy the code below + into it. + +```python +def todays_special(): + pizza_margherita = make_margherita_pizza() + + schorle = make_apfelschorle() + + print("Today's special is ready! Buon Appetito!") + return pizza_margherita, schorle + +pizza, drink = todays_special() +``` + +1. Figure out what import statements are missing, either by visual inspection or + by running the code and seeing what does. Add the missing import statements at + the top of the file. You may need to inspect the files in `src/italianfood/`. + +2. Run `daily_menu.py`. Did it work? diff --git a/exercises/Exercise 1b Unprotected code.md b/exercises/Exercise 1b Unprotected code.md new file mode 100644 index 0000000..609ef60 --- /dev/null +++ b/exercises/Exercise 1b Unprotected code.md @@ -0,0 +1,24 @@ +## Exercise 1b: Unprotected code + +#### Goal + +Investigate what happens when importing from modules with "unprotected" code. + +#### Preparation + +(none) + +#### Tasks + +0. Create a file in the `src/` folder called `unprotectd_code.py`. + +1. Add a line in `unprotectd_code.py` that imports the `todays_special` function from `daily_menu.py`. + +2. **BEFORE YOU EXECUTE THE FILE**. Discuss with your partner what you think will happen when you run `unprotectd_code.py`. + +3. Run `unprotectd_code.py`. Does your prediction match reality? + +4. (optional, for those who know) Discuss with your partner: + * Why did this behaviour occur? + * Why is it not good? + * What can you do to "fix" the behaviour? diff --git a/exercises/Exercise 2 editable installation workflow.md b/exercises/Exercise 2 editable installation workflow.md new file mode 100644 index 0000000..2928c2b --- /dev/null +++ b/exercises/Exercise 2 editable installation workflow.md @@ -0,0 +1,27 @@ +## Exercise 2: Editable installation workflow + +#### Goal + +Experience that working with an editable installation does not change how you interact with your code. +This is supposed to be easy and fun, so run the inspection often and make mistakes with the potion. + +Use your git skills to commit the changes you made to a new branch, and create a pull request. + + +#### Tasks + +- In the `make_pizzas.py` file add another function that makes your favourite pizza. + Be creative with your toppings :). + +- Call this function from different places in your code + - in `make_pizzas.py` call your function in the if __name__ == "__main__" part + - add it to the tasting menu in the `scripts/run_pizza_restaurant.py` file + - replace the margherita pizza in the `src/daily_menu.py` file with your pizza + +------------- +#### Extra credit + +Once you are done, reflect on what you did to find out where the function making the pizza was and how it worked +- Where did you look, why did you look there first? +- How did you figure out what it does? What part of the function did you read first? +- Did it work on your first try? If not, how did you try to fix it - trial and error or read documentation? diff --git a/exercises/Exercise 4 PEP8.md b/exercises/Exercise 4 PEP8.md new file mode 100644 index 0000000..7b02bcb --- /dev/null +++ b/exercises/Exercise 4 PEP8.md @@ -0,0 +1,45 @@ +## Exercise 4: PEP8 + +#### Goal + +Get you familiar with some of the fun facts hidden in the PEP8 guide. + +#### Preparation + +(none) + +#### Tasks + +0. Navigate to [PEP8](https://peps.python.org/pep-0008/). + +1. Depending on your assigned letter, answer the questions in the corresponding + set below. Feel to tackle the questions out of order. You can also split the + questions between your pair, but be you must leave time to discuss the answers + together. + +##### Set A +1. What should you use instead of if y == None? +2. If you have an acronym in camel case, should you capitalize the first letter + only or the whole acronym? +3. How should you check if a variable equals False? +4. What is important about how underscores work with variable names? What happens + if I put an underscore after a variable? One before? Two before? +5. How many spaces should you use after a period in a comment? + +##### Set B +1. What are the capitalization guidelines for classes, functions, and variables? + Give examples. +2. How should you check if a path ends in .txt? +3. What is the difference between mixed case, camel case, and snake case? +4. How should you indicate block comments? +5. What are the whitespace rules around operators? Give several examples. + +##### Set C +1. If I need to import os, sys, numpy, matplotlib, and a local module called + _utils.py, what does my import block look like? +2. How many blank lines go before a function I define at the top of a module? How + many after? +3. Which of these is correct: x[3:4] or x[3 : 4]? +4. Should you use single or double quotes to indicate strings? +5. Give examples of a long line of code and how you can break it onto multiple + lines. diff --git a/exercises/Exercise 5 Virtual Environments.md b/exercises/Exercise 5 Virtual Environments.md new file mode 100644 index 0000000..be1fdfd --- /dev/null +++ b/exercises/Exercise 5 Virtual Environments.md @@ -0,0 +1,42 @@ +## Exercise 5: Virtual Environments + +#### Goal + +Create a virtual environment + install a package + see that that package was installed only in environment + +#### Tasks + +We will use `venv` as our environment manager - while commands might differ, the principles apply to all other package managers as well. + +1. Check which Python you are currently using, and which packages are installed. Also check which folders are in the folder you are installing the environment into. +3. Create and activate a new environment. +4. Check again which Python you are using and which packages are installed - are they different? +5. Install a specific version of a package using pip e.g. pandas=1.5.3 +6. See that dependencies are also installed (more packages than only pandas appear) +7. Deactivate and delete the environment +8. Check the packages that are installed when no environment is active again (as step 1). Have they changed? + + +#### Commands in case you get stuck (not in correct order): + +```bash +% investigate Python and packages +> which python +> pip freeze +> pip install +> pip install ==0.0.1 + +% create an environment option 1 (create folder called venv_folder for files related to virtual environment, feel free to change the name) +> cd +> mkdir venv_folder +> python3 -m venv venv_folder +> source venv_folder/bin/activate + +% create an environment option 2 +> python3 -m venv +> source /bin/activate + +% deactivate and delete a venv environment +> deactivate +> rm -rf venv_folder +``` diff --git a/materials/part0_intro.pptx b/materials/part0_intro.pptx new file mode 100644 index 0000000..4cb554f Binary files /dev/null and b/materials/part0_intro.pptx differ diff --git a/materials/part1_local_imports.pptx b/materials/part1_local_imports.pptx new file mode 100644 index 0000000..5bbaa9d Binary files /dev/null and b/materials/part1_local_imports.pptx differ diff --git a/materials/part2_packages_editable_install.pptx b/materials/part2_packages_editable_install.pptx new file mode 100644 index 0000000..a73844b Binary files /dev/null and b/materials/part2_packages_editable_install.pptx differ diff --git a/materials/part3_repo_structure.pptx b/materials/part3_repo_structure.pptx new file mode 100644 index 0000000..1381736 Binary files /dev/null and b/materials/part3_repo_structure.pptx differ diff --git a/materials/part4_accessibility.pptx b/materials/part4_accessibility.pptx new file mode 100644 index 0000000..661b8f1 Binary files /dev/null and b/materials/part4_accessibility.pptx differ diff --git a/materials/part5_environments.pptx b/materials/part5_environments.pptx new file mode 100644 index 0000000..b335d54 Binary files /dev/null and b/materials/part5_environments.pptx differ diff --git a/materials/part6_summary.pptx b/materials/part6_summary.pptx new file mode 100644 index 0000000..cc25dba Binary files /dev/null and b/materials/part6_summary.pptx differ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..822e058 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,11 @@ +[project] +name = "italianfood" +version = "0.1.1" +description = "This is a project about pizza making" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [] + +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/scripts/run_pizza_restaurant.py b/scripts/run_pizza_restaurant.py new file mode 100644 index 0000000..38b1bf2 --- /dev/null +++ b/scripts/run_pizza_restaurant.py @@ -0,0 +1,13 @@ +from italianfood.make_pizzas import make_margherita_pizza + + +def pizza_tasting_menu(): + pizza_margherita = make_margherita_pizza(num_pizzas=10) + + all_pizzas = [pizza_margherita] + + return all_pizzas + + +if __name__ == "__main__": + pizzas = pizza_tasting_menu() diff --git a/src/italianfood/__init__.py b/src/italianfood/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/italianfood/dough.py b/src/italianfood/dough.py new file mode 100644 index 0000000..b75062c --- /dev/null +++ b/src/italianfood/dough.py @@ -0,0 +1,16 @@ +class PizzaDough: + flour_weight: int + water_weight: int + salt_weight: int + yeast_weight: int + + def __init__(self, flour_weight, water_weight, salt_weight, yeast_weight): + self.hydration = water_weight / flour_weight + self.total_weight = flour_weight + water_weight + salt_weight + yeast_weight + self.prepare_dough() + + def prepare_dough(self): + print("Kneading the dough. This will be delicious!\n...") + + + diff --git a/src/italianfood/drinks.py b/src/italianfood/drinks.py new file mode 100644 index 0000000..4ec0700 --- /dev/null +++ b/src/italianfood/drinks.py @@ -0,0 +1,11 @@ +class Schorle: + juice: str + + def __init__(self, juice): + self.name = f"{juice}schorle" + + +def make_apfelschorle(): + print("Mixing a delicious Apfelschorle!\n...") + apfelschorle = Schorle(juice="apple") + return apfelschorle diff --git a/src/italianfood/ingredients_and_toppings.py b/src/italianfood/ingredients_and_toppings.py new file mode 100644 index 0000000..dcfa0c2 --- /dev/null +++ b/src/italianfood/ingredients_and_toppings.py @@ -0,0 +1,17 @@ +# Dough ingredients +FLOUR_PER_PIZZA = 250 # grams +WATER_PER_PIZZA = 150 # grams +SALT_PER_PIZZA = 5 # grams +YEAST_PER_PIZZA = 2 # grams + +# Toppings +TOMATO_SAUCE = "tomato sauce" +MOZZARELLA = "mozzarella" +TOPPINGS_MARGARITA_PIZZA = [TOMATO_SAUCE, MOZZARELLA] +TOPPINGS_FUNGHI_PIZZA = [TOMATO_SAUCE, MOZZARELLA, "mushrooms"] +TOPPINGS_VERDURE_GRIGLIATE_PIZZA = [ + TOMATO_SAUCE, + MOZZARELLA, + "grilled vegetables" +] + diff --git a/src/italianfood/make_pizza_refactored.py b/src/italianfood/make_pizza_refactored.py new file mode 100644 index 0000000..55a158e --- /dev/null +++ b/src/italianfood/make_pizza_refactored.py @@ -0,0 +1,77 @@ +from italianfood.dough import PizzaDough +from italianfood.ovens import bake_pizza + +STANDARD_FLOUR_WEIGHT = 180 # grams per pizza +STANDARD_WATER_WEIGHT = 126 # grams per pizza +STANDARD_SALT_WEIGHT = 2 # grams per pizza +STANDARD_YEAST_WEIGHT = 1 # grams per pizza + +MARGARITA_TOPPINGS = ["tomato sauce", "mozzarella cheese", "fresh basil"] +MUSHROOM_TOPPINGS = ["tomato sauce", "mozzarella cheese", "mushrooms"] + + +class Pizza: + dough: PizzaDough + num_pizzas: int = 1 + is_ready: bool = False + + def __init__(self, dough, num_pizza_balls): + if num_pizza_balls < 1: + raise ValueError("Number of pizza balls must be at least 1.") + self.num_pizzas = num_pizza_balls + self.dough = dough + self.make_pizza_balls() + + def make_pizza_balls(self): + self.weight_per_pizza_ball = self.dough.total_weight / self.num_pizzas + print( + f"Each Pizza will be made out of {self.weight_per_pizza_ball} g dough.\n..." + ) + print("Now imagine expert pizza tossing skills!\n...") + return self + + def add_toppings(self, toppings): + self.toppings = toppings + print(f"Adding {self.toppings} to pizza(s).\n...") + return self + + +def make_margarita_pizza_more_readable(num_pizzas: int = 1): + dough = make_pizza_dough(num_pizzas) + baked_pizza = make_and_bake_pizza(dough, num_pizzas, MARGARITA_TOPPINGS) + return baked_pizza + + +def make_pizza_dough(num_pizzas: int = 1): + dough = PizzaDough( + flour_weight=STANDARD_FLOUR_WEIGHT * num_pizzas, + water_weight=STANDARD_WATER_WEIGHT * num_pizzas, + salt_weight=STANDARD_SALT_WEIGHT * num_pizzas, + yeast_weight=STANDARD_YEAST_WEIGHT * num_pizzas, + ) + return dough + + +def make_and_bake_pizza(dough, num_pizzas, toppings): + pizza = Pizza(dough=dough, num_pizza_balls=num_pizzas) + pizza.add_toppings(toppings) + baked_pizza = bake_pizza(pizza) + return baked_pizza + + +def make_pizza_reusable(num_pizzas, toppings): + dough = make_pizza_dough(num_pizzas) + baked_pizza = make_and_bake_pizza(dough, num_pizzas, toppings) + return baked_pizza + + +def pizza_tasting_menu(): + all_pizzas = [] + + margarita_pizza = make_pizza_reusable(num_pizzas=1, toppings=MARGARITA_TOPPINGS) + all_pizzas.append(margarita_pizza) + + mushroom_pizza = make_pizza_reusable(num_pizzas=2, toppings=MUSHROOM_TOPPINGS) + all_pizzas.append(mushroom_pizza) + + return all_pizzas diff --git a/src/italianfood/make_pizzas.py b/src/italianfood/make_pizzas.py new file mode 100644 index 0000000..1b9fc47 --- /dev/null +++ b/src/italianfood/make_pizzas.py @@ -0,0 +1,51 @@ +from italianfood.dough import PizzaDough +from italianfood.ovens import bake_pizza + + +class Pizza: + dough: PizzaDough + num_pizzas: int = 1 + is_ready: bool = False + + def __init__(self, dough, num_pizza_balls): + if num_pizza_balls < 1: + raise ValueError("Number of pizza balls must be at least 1.") + self.num_pizzas = num_pizza_balls + self.dough = dough + self.make_pizza_balls() + + def make_pizza_balls(self): + self.weight_per_pizza_ball = self.dough.total_weight / self.num_pizzas + print( + f"Each Pizza will be made out of {self.weight_per_pizza_ball} g dough.\n..." + ) + print("Now imagine expert pizza tossing skills!\n...") + return self + + def add_toppings(self, toppings): + self.toppings = toppings + print(f"Adding {self.toppings} to pizza(s).\n...") + return self + + +def make_margherita_pizza(num_pizzas: int = 1): + total_flour_weight = 180 * num_pizzas + total_water_weight = 126 * num_pizzas + total_salt_weight = 2 * num_pizzas + total_yeast_weight = 1 * num_pizzas + + dough = PizzaDough( + flour_weight=total_flour_weight, + water_weight=total_water_weight, + salt_weight=total_salt_weight, + yeast_weight=total_yeast_weight, + ) + + toppings = ["tomato sauce", "mozzarella cheese", "fresh basil"] + + pizza = Pizza(dough=dough, num_pizza_balls=num_pizzas) + pizza.add_toppings(toppings) + + baked_pizza = bake_pizza(pizza) + + return baked_pizza diff --git a/src/italianfood/ovens.py b/src/italianfood/ovens.py new file mode 100644 index 0000000..d230a9f --- /dev/null +++ b/src/italianfood/ovens.py @@ -0,0 +1,7 @@ +def bake_pizza(pizza, baking_time=2, temperature=450): + # just pretend there is some complicated code + print( + f"The Pizza was baked for {baking_time} min at {temperature} C. It is now ready!\n..." + ) + pizza.is_ready = True + return pizza