adds 2025 materials

This commit is contained in:
Pamela Hathway 2025-07-20 22:10:03 +02:00
commit e85b3b21ca
23 changed files with 378 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*.egg-info
*.DS_Store
*~$*.pptx

0
README.md Normal file
View file

View file

@ -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?

View file

@ -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?

View file

@ -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?

View file

@ -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.

View file

@ -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 <package-name>
> pip install <package-name>==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 <path-to-project_folder>
> mkdir venv_folder
> python3 -m venv venv_folder
> source venv_folder/bin/activate
% create an environment option 2
> python3 -m venv <path-to-folder-for-venv>
> source <path-to-folder-for-venv>/bin/activate
% deactivate and delete a venv environment
> deactivate
> rm -rf venv_folder
```

BIN
materials/part0_intro.pptx Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

11
pyproject.toml Normal file
View file

@ -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"

View file

@ -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()

View file

16
src/italianfood/dough.py Normal file
View file

@ -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...")

11
src/italianfood/drinks.py Normal file
View file

@ -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

View file

@ -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"
]

View file

@ -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

View file

@ -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

7
src/italianfood/ovens.py Normal file
View file

@ -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