diff --git a/_quarto.yml b/_quarto.yml
index 38e9ce16..9777cf9f 100644
--- a/_quarto.yml
+++ b/_quarto.yml
@@ -204,6 +204,28 @@ website:
- text: ' 6.1. Exercises'
href: modules/module6/module6-23-function_design_questions.qmd
- href: modules/module6/module6-26-what_did_we_just_learn.qmd
+ - section: "**Module 7: Importing Files and the Coding Style Guide**"
+ contents:
+ - href: modules/module7/module7-00-module_learning_outcomes.qmd
+ - href: modules/module7/module7-01-importing_python_libraries.qmd
+ - text: ' 1.1. Exercises'
+ href: modules/module7/module7-02-importing_packages.qmd
+ - href: modules/module7/module7-05-working_with_other_files.qmd
+ - text: ' 2.1. Exercises'
+ href: modules/module7/module7-06-importin_your_own_functions_quesitons.qmd
+ - href: modules/module7/module7-08-testing_your_own_functions_with_pytest.qmd
+ - text: ' 3.1. Exercises'
+ href: modules/module7/module7-09-using_pytest_questions.qmd
+ - href: modules/module7/module7-12-automatic_style_formatters.qmd
+ - text: ' 4.1. Exercises'
+ href: modules/module7/module7-13-flake8_and_black.qmd
+ - href: modules/module7/module7-15-formatting_that_can't_be_fixed_automatically.qmd
+ - text: ' 5.1. Exercises'
+ href: modules/module7/module7-16-writing_useful_comments.qmd
+ - href: modules/module7/module7-18-the_python_debugger.qmd
+ - text: ' 6.1. Exercises'
+ href: modules/module7/module7-19-using_the_python_debugger.qmd
+ - href: modules/module7/module7-20-what_did_we_just_learn.qmd
# Since we are declaring options for two formats here (html and revealjs)
# each qmd file needs to include a yaml block including which format to use for that file.
diff --git a/environment.yaml b/environment.yaml
index dcb82d02..4e54f5f5 100644
--- a/environment.yaml
+++ b/environment.yaml
@@ -10,5 +10,8 @@ dependencies:
- matplotlib
- jupyter
- quarto=1.6.43
+ - flake8-nb
+ - black[jupyter]
+ - pytest
- pip
- openpyxl
\ No newline at end of file
diff --git a/modules/module7/module7-00-module_learning_outcomes.qmd b/modules/module7/module7-00-module_learning_outcomes.qmd
new file mode 100644
index 00000000..95149c88
--- /dev/null
+++ b/modules/module7/module7-00-module_learning_outcomes.qmd
@@ -0,0 +1,29 @@
+---
+format:
+ html:
+ page-layout: full
+---
+
+# 0. Module Learning Outcomes
+
+::: {.panel-tabset .nav-pills}
+
+## Video
+
+
+
+## Slides
+
+
+
+:::
diff --git a/modules/module7/module7-01-importing_python_libraries.qmd b/modules/module7/module7-01-importing_python_libraries.qmd
new file mode 100644
index 00000000..dbfc7870
--- /dev/null
+++ b/modules/module7/module7-01-importing_python_libraries.qmd
@@ -0,0 +1,29 @@
+---
+format:
+ html:
+ page-layout: full
+---
+
+# 1. Importing Python Libraries
+
+::: {.panel-tabset .nav-pills}
+
+## Video
+
+
+
+## Slides
+
+
+
+:::
diff --git a/modules/module7/module7-02-importing_packages.qmd b/modules/module7/module7-02-importing_packages.qmd
new file mode 100644
index 00000000..cc4199a4
--- /dev/null
+++ b/modules/module7/module7-02-importing_packages.qmd
@@ -0,0 +1,136 @@
+---
+format: live-html
+---
+
+
+
+# 1.1. Exercises
+
+## Importing packages
+
+
+
+
+
+
+
+## Importing a Package Function
+
+
+
+
+
+## Importing Packages... Again
+
+**Instructions:**
+Running a coding exercise for the first time could take a bit of time for everything to load. Be patient, it could take a few minutes.
+
+**When you see `____` in a coding exercise, replace it with what you assume to be the correct code. Run it and see if you obtain the desired output. Submit your code to validate if you were correct.**
+
+_**Make sure you remove the hash (`#`) symbol in the coding portions of this question. We have commented them so that the line won't execute and you can test your code after each step.**_
+
+Ok, so we've seen this `numpy` package, let's actually load in one of the functions and use it! If you are wondering what this package does, don't worry, you'll learn more of this in the next module. `numpy` has a function called `power()`.
+
+**Tasks:**
+
+- Import the `power()` function from the `numpy` package.
+- Use the `power()` function to find 7 to the power of 5 and save it in an object named `power7_5` - you may want to use `?power` to see what arguments the function requires.
+- Display your results.
+
+```{pyodide}
+#| setup: true
+#| exercise: importing_packages_again
+import pandas as pd
+```
+
+```{pyodide}
+#| exercise: importing_packages_again
+# Import the power() function from the numpy package
+____
+
+# Use the power function to find 7 to the power of 5
+# Save your solution in an object named `power7_5`
+____ = ____
+
+# Display your results
+____
+```
+
+```{pyodide}
+#| exercise: importing_packages_again
+#| check: true
+from numpy import power
+from src.utils import print_correct_msg
+
+assert result == power(7, 5), "Check your result."
+print_correct_msg()
+```
+
+:::: { .hint exercise="importing_packages_again"}
+::: { .callout-note collapse="false"}
+
+## Hint 1
+
+- Are you using `power(7, 5)`?
+- Are you importing using `from`?
+
+:::
+::::
+
+:::: { .solution exercise="importing_packages_again" }
+::: { .callout-tip collapse="false"}
+
+## Fully worked solution:
+
+```{pyodide}
+# Import the power() function from the numpy package
+from numpy import power
+
+# Use the power function to find 7 to the power of 5
+# Save your solution in an object named `power7_5`
+power7_5 = power(7, 5)
+
+# Display your results
+power7_5
+```
+
+:::
+::::
\ No newline at end of file
diff --git a/modules/module7/module7-05-working_with_other_files.qmd b/modules/module7/module7-05-working_with_other_files.qmd
new file mode 100644
index 00000000..91dd83b2
--- /dev/null
+++ b/modules/module7/module7-05-working_with_other_files.qmd
@@ -0,0 +1,29 @@
+---
+format:
+ html:
+ page-layout: full
+---
+
+# 2. Working with Other Files
+
+::: {.panel-tabset .nav-pills}
+
+## Video
+
+
+
+## Slides
+
+
+
+:::
diff --git a/modules/module7/module7-06-importin_your_own_functions_quesitons.qmd b/modules/module7/module7-06-importin_your_own_functions_quesitons.qmd
new file mode 100644
index 00000000..93e97e23
--- /dev/null
+++ b/modules/module7/module7-06-importin_your_own_functions_quesitons.qmd
@@ -0,0 +1,56 @@
+---
+format: html
+---
+
+
+
+# 2.1. Exercises
+
+## Importing Your Own Functions Questions
+
+
+
+
+
+
+
+## More Importing Your Own Functions Questions
+
+
+
diff --git a/modules/module7/module7-08-testing_your_own_functions_with_pytest.qmd b/modules/module7/module7-08-testing_your_own_functions_with_pytest.qmd
new file mode 100644
index 00000000..44ef22e8
--- /dev/null
+++ b/modules/module7/module7-08-testing_your_own_functions_with_pytest.qmd
@@ -0,0 +1,29 @@
+---
+format:
+ html:
+ page-layout: full
+---
+
+# 3. Testing Your Own Functions with Pytest
+
+::: {.panel-tabset .nav-pills}
+
+## Video
+
+
+
+## Slides
+
+
+
+:::
diff --git a/modules/module7/module7-09-using_pytest_questions.qmd b/modules/module7/module7-09-using_pytest_questions.qmd
new file mode 100644
index 00000000..3a3e934a
--- /dev/null
+++ b/modules/module7/module7-09-using_pytest_questions.qmd
@@ -0,0 +1,159 @@
+---
+format: live-html
+---
+
+
+
+# 3.1. Exercises
+
+## Using Pytest Questions
+
+
+
+
+
+
+
+## More Questions on Using Pytest
+
+
+
+
+
+## Making a Test Function
+
+**Instructions:**
+Running a coding exercise for the first time could take a bit of time for everything to load. Be patient, it could take a few minutes.
+
+**When you see `____` in a coding exercise, replace it with what you assume to be the correct code. Run it and see if you obtain the desired output. Submit your code to validate if you were correct.**
+
+_**Make sure you remove the hash (`#`) symbol in the coding portions of this question. We have commented them so that the line won't execute and you can test your code after each step.**_
+
+Let's do the first step in testing the function `find_force()` with `pytest` by converting the tests provided for into an appropriate function.
+
+**Tasks:**
+
+- Take these unit tests we wrote and compile them together in a function to test the function `find_force()`.
+- Don't forget to give it a name compliant with `pytest`'s needs.
+
+```{pyodide}
+#| setup: true
+#| exercise: making_a_test_function
+import pandas as pd
+```
+
+```{pyodide}
+#| exercise: making_a_test_function
+def find_force(mass, acceleration):
+ return mass * acceleration
+
+# Take these unit tests compile them together in
+# a function to check the function find_force
+
+assert find_force(50, 3) == 150, 'Input arguments giving incorrect output'
+assert find_force(100, -2) == -200, 'Input arguments giving incorrect output'
+assert find_force(5, 20) == 100, 'Input arguments giving incorrect output'
+
+
+____
+
+ return
+
+# For testing purposes, replace ____ with your function name
+____.__code__
+```
+
+```{pyodide}
+#| exercise: making_a_test_function
+#| check: true
+from src.utils import print_correct_msg
+
+def dummy():
+ return
+
+assert isinstance(result, type(dummy.__code__)), "Please return your_function_name.__code__"
+assert result.co_argcount == 0, "These functions do not take any arguments."
+assert "find_force" in result.co_names, "Make sure you are testing find_force."
+assert {50, 3, 150, 100, -2, -200, 5, 20}.issubset(set(result.co_consts)), "Make sure you are including all the assert statements."
+print_correct_msg()
+```
+
+:::: { .hint exercise="making_a_test_function"}
+::: { .callout-note collapse="false"}
+
+## Hint 1
+
+- Are you naming it something starting with `test`?
+- Are you remembering these functions do not need to return anything?
+- These functions do not take any arguments.
+
+:::
+::::
+
+:::: { .solution exercise="making_a_test_function" }
+::: { .callout-tip collapse="false"}
+
+## Fully worked solution:
+
+```{pyodide}
+def find_force(mass, acceleration):
+ return mass * acceleration
+
+# Take these unit tests compile them together in
+# a function to check the function find_force
+
+assert find_force(50, 3) == 150, 'Input arguments giving incorrect output'
+assert find_force(100, -2) == -200, 'Input arguments giving incorrect output'
+assert find_force(5, 20) == 100, 'Input arguments giving incorrect output'
+
+
+def test_find_force():
+ assert find_force(50, 3) == 150, 'Input arguments giving incorrect output'
+ assert find_force(100, -2) == -200, 'Input arguments giving incorrect output'
+ assert find_force(5, 20) == 100, 'Input arguments giving incorrect output'
+
+# For testing purposes, replace ____ with your function name
+test_find_force.__code__
+```
+
+:::
+::::
\ No newline at end of file
diff --git a/modules/module7/module7-12-automatic_style_formatters.qmd b/modules/module7/module7-12-automatic_style_formatters.qmd
new file mode 100644
index 00000000..aaed2e05
--- /dev/null
+++ b/modules/module7/module7-12-automatic_style_formatters.qmd
@@ -0,0 +1,29 @@
+---
+format:
+ html:
+ page-layout: full
+---
+
+# 4. Automatic Style Formatting
+
+::: {.panel-tabset .nav-pills}
+
+## Video
+
+
+
+## Slides
+
+
+
+:::
diff --git a/modules/module7/module7-13-flake8_and_black.qmd b/modules/module7/module7-13-flake8_and_black.qmd
new file mode 100644
index 00000000..078bedce
--- /dev/null
+++ b/modules/module7/module7-13-flake8_and_black.qmd
@@ -0,0 +1,165 @@
+---
+format: live-html
+---
+
+
+
+# 4.1. Exercises
+
+## Flake8 and Black
+
+
+
+
+
+
+
+
+## Formatting your Code
+
+**Instructions:**
+Running a coding exercise for the first time could take a bit of time for everything to load. Be patient, it could take a few minutes.
+
+**When you see `____` in a coding exercise, replace it with what you assume to be the correct code. Run it and see if you obtain the desired output. Submit your code to validate if you were correct.**
+
+_**Make sure you remove the hash (`#`) symbol in the coding portions of this question. We have commented them so that the line won't execute and you can test your code after each step.**_
+
+Let's take the function named `cleanup()` which drops duplicate rows and columns. Rewrite the function code (not the docstring) so that it's written with necessary spaces and indentations.
+
+**Tasks:**
+
+- Amend the function `cleanup()` so that it adopts an approach that has spaces where necessary and blank space is removed. Make sure that you have indentations and empty lines where necessary.
+
+```{pyodide}
+#| exercise: formatting_your_code
+import pandas as pd
+
+def cleanup(data, columns):
+ '''
+ This removes any duplicate column names or any duplicate
+ rows in the dataframe.
+
+ Parameters
+ ----------
+ data : pandas.core.frame.DataFrame
+ The dataframe to clean
+ param2 : list
+ A list of columns to determine which are duplicated rows
+
+ Returns
+ -------
+ pandas.core.frame.DataFrame
+ A dataframe with unique columns and rows
+
+ Examples
+ --------
+ >>> cleanup(bakery,['bread'])
+ bread quantity
+ white 4
+ rye 6
+ wholegrain 2
+ '''
+
+ # Drops duplicate columns
+ data=data. loc[ :, ~data.columns.duplicated() ]
+
+ # Drops duplicate rows
+ data = data[ ~ data. duplicated(subset =columns , keep=False )
+ ]
+
+
+
+ return data
+```
+
+```{pyodide}
+#| exercise: formatting_your_code
+#| check: true
+
+assert False, "No tests available. Please check the solution."
+```
+
+:::: { .hint exercise="formatting_your_code"}
+::: { .callout-note collapse="false"}
+
+## Hint 1
+
+- Are you adding spaces between operators?
+- Are you removing spaces where appropriate?
+- Did you fix the indentation error?
+- How about removing the blank lines before the return statement?
+
+:::
+::::
+
+:::: { .solution exercise="formatting_your_code" }
+::: { .callout-tip collapse="false"}
+
+## Fully worked solution:
+
+```{pyodide}
+import pandas as pd
+
+def cleanup(data, columns):
+ '''
+ This removes any duplicate column names or any duplicate
+ rows in the dataframe.
+
+ Parameters
+ ----------
+ data : pandas.core.frame.DataFrame
+ The dataframe to clean
+ param2 : list
+ A list of columns to determine which are duplicated rows
+
+ Returns
+ -------
+ pandas.core.frame.DataFrame
+ A dataframe with unique columns and rows
+
+ Examples
+ --------
+ >>> cleanup(bakery,['bread'])
+ bread quantity
+ white 4
+ rye 6
+ wholegrain 2
+ '''
+
+ # Drops duplicate columns
+ data = data.loc[:, ~data.columns.duplicated()]
+
+ # Drops duplicate rows
+ data = data[~data.duplicated(subset=columns, keep=False)]
+
+ return data
+```
+
+:::
+::::
\ No newline at end of file
diff --git a/modules/module7/module7-15-formatting_that_can't_be_fixed_automatically.qmd b/modules/module7/module7-15-formatting_that_can't_be_fixed_automatically.qmd
new file mode 100644
index 00000000..e366c3b3
--- /dev/null
+++ b/modules/module7/module7-15-formatting_that_can't_be_fixed_automatically.qmd
@@ -0,0 +1,29 @@
+---
+format:
+ html:
+ page-layout: full
+---
+
+# 5. Formatting That Can't Be Fixed Automatically
+
+::: {.panel-tabset .nav-pills}
+
+## Video
+
+
+
+## Slides
+
+
+
+:::
diff --git a/modules/module7/module7-16-writing_useful_comments.qmd b/modules/module7/module7-16-writing_useful_comments.qmd
new file mode 100644
index 00000000..93073fdd
--- /dev/null
+++ b/modules/module7/module7-16-writing_useful_comments.qmd
@@ -0,0 +1,68 @@
+---
+format: html
+---
+
+
+
+# 5.1. Exercises
+
+## Writing Useful Comments
+
+Given the code here:
+
+```python
+candy = pd.read_csv('data/candybars.csv')
+chocolate = pd.read_csv('data/chocolate_types.csv')
+
+dessert = candy.merge(chocolate, how='inner').dropna()
+```
+
+
+
+
+## Choosing Good Variable Names
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/module7/module7-18-the_python_debugger.qmd b/modules/module7/module7-18-the_python_debugger.qmd
new file mode 100644
index 00000000..d5c32ccf
--- /dev/null
+++ b/modules/module7/module7-18-the_python_debugger.qmd
@@ -0,0 +1,29 @@
+---
+format:
+ html:
+ page-layout: full
+---
+
+# 6. The Python Debugger
+
+::: {.panel-tabset .nav-pills}
+
+## Video
+
+
+
+## Slides
+
+
+
+:::
diff --git a/modules/module7/module7-19-using_the_python_debugger.qmd b/modules/module7/module7-19-using_the_python_debugger.qmd
new file mode 100644
index 00000000..af2aa07e
--- /dev/null
+++ b/modules/module7/module7-19-using_the_python_debugger.qmd
@@ -0,0 +1,40 @@
+---
+format: html
+---
+
+
+
+# 6.1. Exercises
+
+## Using the Python Debugger
+
+
+
+
+
+
diff --git a/modules/module7/module7-20-what_did_we_just_learn.qmd b/modules/module7/module7-20-what_did_we_just_learn.qmd
new file mode 100644
index 00000000..e72c66c3
--- /dev/null
+++ b/modules/module7/module7-20-what_did_we_just_learn.qmd
@@ -0,0 +1,29 @@
+---
+format:
+ html:
+ page-layout: full
+---
+
+# 7. What Did We Just Learn?
+
+::: {.panel-tabset .nav-pills}
+
+## Video
+
+
+
+## Slides
+
+
+
+:::
diff --git a/modules/module7/slides/module7_00.qmd b/modules/module7/slides/module7_00.qmd
new file mode 100644
index 00000000..8f3c8cd7
--- /dev/null
+++ b/modules/module7/slides/module7_00.qmd
@@ -0,0 +1,29 @@
+---
+format: revealjs
+title: Module Learning Outcomes
+title-slide-attributes:
+ data-notes: |
+ In this module you will learn how to import files from other directories and how to write code that is styled for optimal readability.
+---
+
+```{python}
+# | echo: false
+%run src/utils.py
+```
+
+
+## Module Learning Outcomes
+
+By the end of the module, students are expected to:
+
+- Describe what Python libraries are, as well as explain when and why they are useful.
+- Identify where code can be improved concerning variable names, magic numbers, comments and whitespace.
+- Write code that is human readable and follows the black style guide.
+- Import files from other directories.
+- Use [`pytest`](https://docs.pytest.org/en/stable/) to check a function's tests.
+- When running [`pytest`](https://docs.pytest.org/en/stable/), explain how pytest finds the associated test functions.
+- Explain how the Python debugger can help rectify your code.
+
+
+
+# Let's Start!
\ No newline at end of file
diff --git a/modules/module7/slides/module7_01.qmd b/modules/module7/slides/module7_01.qmd
new file mode 100644
index 00000000..4d52b24b
--- /dev/null
+++ b/modules/module7/slides/module7_01.qmd
@@ -0,0 +1,97 @@
+---
+format: revealjs
+title: Importing Python Libraries
+title-slide-attributes:
+ data-notes: |
+---
+
+```{python}
+# | echo: false
+%run src/utils.py
+```
+
+
+```{python}
+import pandas
+```
+
+
+
+```{python}
+pandas.read_csv('data/cereal.csv')
+```
+
+
+:::{.notes}
+All the way back in Module 1, we learned how to import the `pandas` library for dataframe wrangling and `altair` to visualize our data with plots.
+
+We imported these libraries because basic Python does not have all the built-in tools that we need to accomplish what we want; therefore, we import other tools into our environment.
+
+To import a library, we saw that we can use the keyword `import` followed by the desired package name.
+
+In this case, we are importing `pandas`.
+
+This now lets us use verbs that reside in the `pandas` library, such as `read_csv()`.
+
+We need to specify the library name -`pandas` and then the verb - `read_csv()`.
+:::
+
+---
+
+```{python}
+import pandas as pd
+import altair as alt
+```
+
+
+
+```{python}
+pd.read_csv('data/cereal.csv')
+```
+
+
+:::{.notes}
+For efficiency, in the majority of this course, we have been importing our libraries by assigning them a shorter condensed name or alias.
+
+For example, in the assignments and practice exercises, we have been importing `pandas` and `altair` with names such as `pd` and `alt`, respectively.
+
+Now when we call functions from either of these libraries, we only type the short form alias we assigned to the library name.
+
+Now instead of writing `pandas.read_csv('data/cereal.csv')`, we can shorten it to `pd.read_csv('data/cereal.csv')`.
+:::
+
+---
+
+
+```{python}
+from pandas import read_csv
+```
+
+
+
+```{python}
+read_csv('data/cereal.csv')
+```
+
+
+:::{.notes}
+We can also import a single function from a library using the keyword `from`.
+
+If we only want the `read_csv()` function from the `pandas` package, we could first specify the library the function belongs to, followed by the function name:
+
+Here it's `from pandas import read_csv`.
+
+Now when we call `read_csv()`, we don't need to specify the package name or alias before it.
+
+This mostly helps if we have only a single function we wish to use, instead of importing the entire library.
+
+This works for Python libraries, but how do we import functions we've made that are located in another file?
+
+If we want to reuse code to adhere to the DRY principle, what is our next step?
+
+This question will be answered in the next section of this module.
+:::
+
+
+
+# Let’s apply what we learned!
\ No newline at end of file
diff --git a/modules/module7/slides/module7_05.qmd b/modules/module7/slides/module7_05.qmd
new file mode 100644
index 00000000..e0d91008
--- /dev/null
+++ b/modules/module7/slides/module7_05.qmd
@@ -0,0 +1,143 @@
+---
+format: revealjs
+title: Working with Other Files
+title-slide-attributes:
+ data-notes: |
+---
+
+```{python}
+# | echo: false
+%run src/utils.py
+```
+
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+We are going to talk about what to do when you have a function in one Jupyter notebook, but you want to use it in another jupyter notebook.
+
+Let's take this `exponent_a_list` function we’ve seen previously that creates a new list containing the exponent values of the input list.
+
+We are using this function inside our notebook called `exponents.ipynb`.
+
+Let’s remind ourselves how it works.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+First, we run the cell to put the function into Python’s memory, and we take some tests that we wrote earlier and run them to make sure our function still works.
+
+We then execute the cell that calls the function on a list containing the values `2`, `3`, and `4` and get the output.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+Let’s say we want to create a new jupyter notebook.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+We then named it `more-exp-calc.ipynb`.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+If we call the function `exponent_a list` with the values 1, 3, and 5 inside of this notebook, it will result in an error because exponent a list doesn't exist in this workspace.
+
+What can we do to solve this problem?
+
+One thing we could do is copy and paste the function into this notebook.
+
+This would be annoying to do that every single time that we want to use this function.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+Instead, we can create a python script and put the function inside that.
+
+Then for each notebook that needs this function, we can import it similarly to how we imported packages like pandas or Altair.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+Let's create a text file and rename it `exponent_a_list,` and instead of an ending of `.txt`, we're going to end it with `.py`.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+Inside of this python script `exponent_a_list.py`, we're going to copy the original function and save this file.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+Next, we can go into our `more-exp-calc.ipynb` notebook, and in a new cell at the top, we write a statement that will tell Python where the `exponent_a_list` function is located and bring it into the notebook environment.
+
+We write
+
+```python
+from exponent_a_list import exponent_a_list
+```
+
+You may wonder why we write exponent_a_list twice; well, the `exponent_a_list` is referencing the name of this python script file that we just created, so whatever we name this file is what we put after the `from` statement.
+
+The second `exponent_a_list` of our statement is telling us what function would like to import from that file.
+
+We only have one function in the file `exponent_a_list.py,` but you can have multiple functions that could live in this file.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+We can now run the cell containing the import statement followed by the function `exponent_a list` for values 1, 3, and 5.
+
+This time instead of an error, we get the expected results.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+:::{.notes}
+We can go back to our original notebook `exponent.ipynb` and replace the function we had written with that import statement.
+
+This now gives us the ability to run all of the cells in this notebook the way we just did in the other notebook `more-exp-calc.ipynb`.
+:::
+
+
+# Let’s apply what we learned!
\ No newline at end of file
diff --git a/modules/module7/slides/module7_08.qmd b/modules/module7/slides/module7_08.qmd
new file mode 100644
index 00000000..e01e7a43
--- /dev/null
+++ b/modules/module7/slides/module7_08.qmd
@@ -0,0 +1,152 @@
+---
+format: revealjs
+title: Testing Your Own Functions with Pytest
+title-slide-attributes:
+ data-notes: |
+---
+
+```{python}
+# | echo: false
+%run src/utils.py
+```
+
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+Now that we've learned how to move our functions to different files, it can be useful to move our test to different files as well.
+
+Let's take a look at how we can do this, looking at the `exponent_a_list` function.
+
+Inside this one notebook `exponent`, we have written our test, but they're kind of out of place and not really relevant exactly for our analysis in this notebook.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+We are going to put them in their own file that we can run and test independently before we did our analysis and just have our analysis code inside of our jupyter notebook.
+
+We can do this by making a new python file by creating a text file.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+We can rename this file as `test_exponent_a_list.py`, ending the file with `.py` to indicate that it's a python script.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+We can rename this file as `test_exponent_a_list.py`, ending the file with `.py` to indicate that it's a python script.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+Going back to the `exponents.ipynb` file, we cut these tests and paste them inside of the `test_exponent_a_list` python script.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+For this to work, there's a few extra things we need to do.
+
+It's important that you wrap these inside of a function, so we're going to call this function `test_exponent_a_list`.
+
+This does not need any function arguments because we just want the test function to execute the assert statement.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+Finally, we need to add the import statement to tell python where the exponent a list function is coming from because it's not in this file.
+
+It's located in the `exponent_a_list` python script that we created earlier.
+
+To import this function we write:
+
+```python
+from exponent_a_list import exponent_a_list
+```
+
+We now have our tests saved inside of a function `test_exponent_a_list`, which is inside of a file named `test_exponent_a_list.py`.
+
+One thing to notice is both the function name and the file name begin with test.
+
+This is a nice trick that we use with our testing tool named `pytest` which automatically runs tests for us.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+We must move to a terminal to run `pytest`. Scroll down and open “terminal”.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+To run `pytest`, we must be in the same directory where we have all of our test files stored.
+
+It’s going to look for all the files that start with `test` and run all the functions inside of those files that start with `test`.
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+We write `pytest` in the terminal, and this results in output that indicates to us if our tests pass.
+
+This looks like all our tests pass!
+:::
+
+---
+
+{fig-align="center" width="95%" fig-alt="404 image"}
+
+
+:::{.notes}
+Let’s look at an example where our tests don’t pass.
+
+Errors could arise because of either an error in our test or in our function.
+
+Let’s return to the terminal and run the `pytest` command again.
+
+This time we get a lot more information.
+
+We got a very loud failure that something didn't go correctly.
+
+We get the output from the assert statement about which test failed.
+
+At this point, we would go back to either our function or test and try and fix the issue.
+:::
+
+
+# Let’s apply what we learned!
\ No newline at end of file
diff --git a/modules/module7/slides/module7_12.qmd b/modules/module7/slides/module7_12.qmd
new file mode 100644
index 00000000..917fd2f9
--- /dev/null
+++ b/modules/module7/slides/module7_12.qmd
@@ -0,0 +1,455 @@
+---
+format: revealjs
+title: Automatic Style Formatting
+title-slide-attributes:
+ data-notes: |
+---
+
+```{python}
+# | echo: false
+%run src/utils.py
+```
+
+
+
+
+{fig-align="center" width="90%" fig-alt="404 image"}
+
+Photos/Images: Clement H
+Photos/Images by #WOCinTech/#WOCinTech Chat.
+
+
+:::{.notes}
+We've talked a lot about how to make sure our code works and that it does what we want it to, but just because it works doesn't mean it's maintainable!
+
+Code has two “users” - the computer (which turns it into machine instructions) and humans, who will likely read and/or modify the code in the future.
+
+This is why it's important to make your code suitable to that second audience, humans.
+
+Writing readable and understandable code is important when sharing code to other users and reading back as your future self!
+
+Remember: “Code is read much more often than it is written.”
+:::
+
+---
+
+### PEP8
+
+PEP8 is a style guide that recommends formatting such as:
+
+- Indenting using 4 spaces
+- Having whitespace around operators, e.g. x = 1 not x=1
+- Avoiding extra whitespace such as f(1), not f (1)
+- Single and double quotes for strings, but only using “””triple double quotes”””, not ‘’’triple single quotes’’’
+- Variable and function names using underscores_between_words
+
+
+
+### flake8
+
+{fig-align="center" width="45%" fig-alt="404 image"}
+
+
+:::{.notes}
+PEP8 is one of the many style guides used in programming.
+
+PEP8 recommends formatting such as:
+
+- Indenting using 4 spaces
+- Having whitespace around operators, e.g. x = 1 not x=1
+- But avoiding extra whitespace such as f(1), not f (1)
+- Single and double quotes both fine for strings, but only using “””triple double quotes”””, not ‘’’triple single quotes’’’
+- Variable and function names use underscores_between_words
+
+We can check our code to see if it complies with PEP8 formatting using a Python library called `flake8`.
+
+Think of it as a grammar check but for your code.
+
+`flake8` will tell us how and where our code is formatted poorly, but it won't make any changes to it. That is up to us.
+
+We will show you shortly how to use `flake8` in your Jupyter notebooks.
+:::
+
+---
+
+## Black
+
+**Before `black`**
+```{python}
+def exponent_a_list(numerical_list , exponent = 2):
+
+ if type(numerical_list ) is not list :
+ raise Exception( "You are not using a list for the numerical_list input."
+ )
+
+ new_exponent_list = list()
+ for number_in_new_exponent_list in numerical_list:
+ new_exponent_list.append( number_in_new_exponent_list ** exponent )
+ return new_exponent_list
+```
+
+**After `black`**
+```{python}
+def exponent_a_list(numerical_list, exponent=2):
+
+ if type(numerical_list) is not list:
+ raise Exception("You are not using a list for the numerical_list input.")
+
+ new_exponent_list = list()
+ for number_in_new_exponent_list in numerical_list:
+ new_exponent_list.append(number_in_new_exponent_list ** exponent)
+ return new_exponent_list
+```
+
+
+:::{.notes}
+Unlike PEP8, which is a style guide, and `flake8` which just tells you where your code needs changes, `black` is a tool that will format your code.
+
+`black` will mostly follow the PEP8 style guide but with a few differences.
+
+When you use `black` with your code, you are wiping it of bad formatting like trailing whitespace and poor indentation.
+:::
+
+---
+
+**After `black`**
+```{python}
+def exponent_a_list(numerical_list, exponent=2):
+
+ if type(numerical_list) is not list:
+ raise Exception("You are not using a list for the numerical_list input.")
+
+ new_exponent_list = list()
+ for number_in_new_exponent_list in numerical_list:
+ new_exponent_list.append(number_in_new_exponent_list ** exponent)
+ return new_exponent_list
+```
+
+
+
+**Checking with `flake8` again**
+
+{width="45%" fig-alt="404 image"}
+
+
+:::{.notes}
+It's important to know that `flake8` and our formatter `black` are using slightly different rules.
+Even after `black` is run on our code, `flake8` still may point out issues and complain that it isn't stylized correctly.
+
+We’re not going to worry about that for now. It can be fixed by customizing `flake8,` but that’s outside the scope of this course.
+
+Now let's see how we can use both of these in a Jupyter notebook.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+Now that you know a little bit about what `flake8` and `black` can do let's see how we use them.
+
+Here is a blank Jupyter notebook with the `exponent_a_list` Python script that you saw in the last section.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+This time, our `exponent_a_list()` function is not as it was formatted before.
+
+We've got space and indentation issues, and it looks like we are missing white space in areas as well.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+First let’s see if the `exponent_a_list()` function works.
+
+I've got this empty notebook that we need to add a new cell to.
+
+We can do so by clicking the `+` button in the toolbar.
+
+By default, it will add a code type cell to the notebook, but what if we want a text cell?
+
+All we have to do is click on `markdown` in the toolbar, and it will change to a text cell.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+:::{.notes}
+Let's import our function using the same code Tiffany showed us before.
+
+We specify first `from` and then the name of the script - in this case, the file name is `exponent_a_list`, and we follow that with the name of the specific function so `exponent_a_list` again.
+
+Next, we run it, and it looks like it’s imported into our notebook.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+:::{.notes}
+Let's test out the function `exponent_a_list()` with a list containing the values 1, 3, and 7.
+
+We are intentionally not adding spaces between the comma so that we can use it as a formatting example shortly.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+The function works even with the bad formatting but let’s make our code more readable for our human user now.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+Instead of doing everything ourselves and going line-by-line to check our code, we can use `flake8` to tell us exactly what we need to fix.
+
+By clicking on the addition sign on the top left of the toolbar, we can access the **Launcher**, where we can open our **terminal**.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+To use `flake8` in the terminal, all we have to do is type `flake8` followed by the name of the file we want to check; in this case, `exponent_a_list.py`.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+This produces an output of all the formatting issues we need to amend.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We can see that at line 1, column 45, we have `multiple spaces before the operator,` which means in our that’s where we will need to make changes in the file `exponent_a_list.py`.
+
+We can then go through all of these suggestions and correct them so that our `exponent_a_list.py` is adhering to a cleaner style.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+Not only can we check Python scripts but notebooks files as well!
+
+In our terminal, we write something a little different.
+
+We type `flake8-nb` followed by the name of the notebook:
+
+```
+flake8-nb example.ipynb
+```
+
+`example` is the name of the notebook, and Jupyter notebooks end with `.ipynb`.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We can see in this case that `flake8-nb` caught the missing white space after the commas in our code `exponent_a_list([1,3,7)` inside the notebook.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+Not only can you check `flake8` in a terminal, but you can check it in a Jupyter notebook as well.
+
+This time I’m going to run `flake8` but in a code cell in our `example` notebook.
+
+We write almost the same thing we did in our terminal except for this time; we precede the code with an exclamation mark:
+
+```
+!flake8 exponent_a_list.py
+```
+
+Now we see all the formatting flags in our notebook instead of our terminal.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We could go through all the issues one by one and fix them individually, or we can use `black` which does this (well, most of it) for us.
+
+Just like `flake8`, we can do this in the terminal or in our Jupyter notebook.
+
+Let’s first try it in a Jupyter notebook.
+
+We can use the exclamation mark followed by `black` and then the file name so in this case:
+
+```
+!black exponent_a_list.py
+```
+
+Before pressing enter and running this, let’s look at the file first.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We can see that the code in the `exponent_a_list.py` is still looking pretty messy.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+Now we can run this cell, and we get the output:
+
+```
+reformatted are exponent_a_list.py.
+All done! ✨ 🍰 ✨
+1 file reformatted
+```
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+When we open up the file `exponent_a_list.py`, we can see that a lot of the white space has been removed, and the indentations have been fixed!
+
+Remember, it's not perfect! We can still see blank lines here that probably shouldn't be, but it does a pretty good job.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+Now that we've done it in a Jupyter notebook, let’s try it in our terminal.
+
+We do the same thing as in a Jupyter notebook, but this time without the exclamation point.
+
+```
+Black exponent_a_list.py
+```
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+This time this file has also already been formatted, so the output now is
+
+```
+All done! ✨ 🍰 ✨
+1 file unchanged
+```
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+One last quick tool that we want to show you is this `black` Jupyter notebook extension. This lets you format your code cells in your Jupyter notebook directly.
+
+All you have to do is right-click on the cell you want to format and press “format cell”.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+It will formats your cell right away.
+
+So that is how you can use `flake8` and black to clean up your code.
+
+Remember, these tools don’t do everything.
+
+You’ll learn about some of the things that `black` and `flake8` don’t pick up in the next section.
+:::
+
+
+# Let’s apply what we learned!
\ No newline at end of file
diff --git a/modules/module7/slides/module7_15.qmd b/modules/module7/slides/module7_15.qmd
new file mode 100644
index 00000000..d087b67c
--- /dev/null
+++ b/modules/module7/slides/module7_15.qmd
@@ -0,0 +1,295 @@
+---
+format: revealjs
+title: Non-automatic style formatting
+title-slide-attributes:
+ data-notes: |
+---
+
+```{python}
+# | echo: false
+%run src/utils.py
+```
+
+## Comments
+
+**Bad Comments:** Example of a comment that doesn't make sense
+
+```{python}
+# The estimated stock room size minus the rented space
+screen_time = 23 * 1.10
+```
+
+
+
+**Bad Comments:** Example of commenting gone overboard
+
+```{python}
+# | eval: false
+# Reading in the cereal dataframe
+cereal_dataframe = pd.read_csv('data/cereal.csv')
+
+# Saving the cereal dataframe's columns as cereal_columns
+cereal_columns = cereal_dataframe.columns
+
+cereal_dataframe.head() # Displaying the first 5 rows of the cereal_dataframe
+```
+
+
+
+**Good Comments:** Example of a useful comment
+
+```{python}
+# | eval: false
+# Obtaining the cereals with calories between 130 and 150
+cereal_dataframe[(cereal_dataframe['calories'] >130) & (cereal_dataframe['calories'] <150)]
+```
+
+
+:::{.notes}
+We've learned about some tools that can help format and standardize our code, such as white space and indentations, but what about the things that a formatter can't automatically change?
+
+Let's start with how we write comments.
+
+Comments are important for understanding your code.
+
+While docstrings cover what a function does, your comments will help document how your code achieves its goal.
+
+python.org has some strong opinions about how comments should be written, and the first thing they mention is that our comments should reflect what the code is doing.
+
+It sounds easy enough, but when working on projects that are constantly changing, it's easy to change the code but forget to change the comments which do not affect the output of the code.
+
+In cases like this, it's better that our code has no comments than comments that contradict it.
+
+It's also important that comments add to the understanding of our coding instead of simply commenting for the sake of commenting.
+
+Not all code needs a comment, especially if it's redundant for understanding what the code does.
+:::
+
+---
+
+Guidelines according to PEP8 and python.org:
+
+- Comments should start with a `#` followed by a single space.
+- They should be complete sentences. The first word should be capitalized unless it is an identifier that begins with a lower case letter.
+- Comments should be clear and easily understandable to other speakers of the language you are writing in.
+- For block comments, each line of a block comment should start with a `#` followed by a single space and should be indented to the same level as the code it precedes.
+
+
+:::{.notes}
+Here are some basic guidelines according to PEP8 and python.org that are recommended when writing comments:
+
+- Comments should start with `#` followed by a single space.
+- They should be complete sentences.
+- The first word should be capitalized unless it is an identifier that begins with a lower case letter.
+- They should be clear and easily understandable to other speakers of the language you are writing in.
+- If you are using block comments, each line of a block comment should start with a `#` followed by a single space and should be indented to the same level as the code it precedes.
+:::
+
+---
+
+**BAD comment**
+```{python}
+# | eval: false
+# adding 6.99
+cost = cost + 6.99
+```
+
+**Better comment**
+```{python}
+# | eval: false
+# Accounting for shipping charges
+cost = cost + 6.99
+```
+
+
+
+**BAD comment**
+```{python}
+x = 0
+
+# This code iterates over the numbers 1 to 5 each time adding the number
+# to the variable x to get a sum of the numbers from 1, 2, 3, 4, and 5.
+for i in range(1,5):
+ x = x + i
+```
+
+**Better comment**
+```{python}
+x = 0
+
+# Sum up the values 1 to 5
+for i in range(1,5):
+ x = x + i
+```
+
+
+:::{.notes}
+Here is an example of a bad comment where we say "adding 6.99" to the `cost` variable. This comment doesn't tell us why we are doing this operation. A more reasonable comment would be to correct the capitalize the comment and explain that we are adding 6.99 to the variable `cost` to account for shipping charges.
+
+Code that is concise is preferred over long-winded explanations. In this next example case, there is no need to write a comment this long when something short like "Sum up the values 1 to 5" does the job.
+
+When writing comments, it's important to make sure they are meaningful, concise, and are a supplement to the understanding of your code.
+:::
+
+---
+
+## Naming convention
+
+Some common variable naming recommendations:
+
+ - Variable names should use underscores
+ - Variable names should be lowercase
+
+**Fine**
+```{python}
+# | eval: false
+lego
+```
+
+**Fine**
+```{python}
+# | eval: false
+lego_themes
+```
+
+**Fine**
+```{python}
+# | eval: false
+lego_df
+```
+
+**Not Recommended**
+```{python}
+# | eval: false
+lego_DF
+```
+
+**Not Recommended**
+```{python}
+# | eval: false
+LEGO
+```
+
+**Not Recommended**
+```{python}
+# | eval: false
+legothemes
+```
+
+
+:::{.notes}
+Python naming convention is somewhat inconsistent, as stated on Python.org's website
+
+That being said, it's useful to try to set consistent standards which helps the Python community and will help you keep track of your code at a later time.
+
+Some common variable naming recommendations are as follows:
+
+- Variable names should use underscores
+- Variable names should be lowercase
+
+You could use the names `lego`, `lego_themes`, `lego_df`, but we advise again things like `lego_DF`, `LEGO` or `legothemes`.
+:::
+
+---
+
+## Variables without Keywords
+
+### Don't Do This
+```{python}
+# | eval: false
+list = []
+```
+
+
+
+### Or This
+```{python}
+# | eval: false
+def tuple(argument):
+ return
+```
+
+
+
+### Or This
+```{python}
+# | eval: false
+str = 4
+type = 67 * str
+```
+
+
+:::{.notes}
+Something you should not name your variables are Python keywords.
+
+This will create a multitude of problems for you.
+
+For example, If you did name a variable with the specific keyword, the next time that you attempt to use that keyword for its intended functionality, an error will be thrown because it will try to use your variable instead!
+:::
+
+---
+
+## Meaningful Names
+
+```{python}
+a = 100
+b = 23
+c = 0.56
+
+d = a + b
+e = c * d
+```
+
+
+
+```{python}
+apples = 100
+bananas = 23
+fruit_price = 0.56
+
+fruit_total = apples + bananas
+cost = fruit_price * fruit_total
+```
+
+
+:::{.notes}
+Just like how we use comments to explain our code, it's good coding style to name your variables thoughtfully and in ways that help make your coding more "readable".
+
+Naming your variables helps others (and future you) make sense of the instructions you are writing for the computer.
+
+For example, let's try writing the code here again but with variable names that are a bit more descriptive.
+
+Giving these new variables names, we can follow a bit more of the reasoning behind the calculations.
+:::
+
+---
+
+## Concise Names
+
+```{python}
+mass_of_the_object_in_motion = 45
+the_acceleration_of_the_object_in_motion = 1.8
+
+force_acting_on_an_object = mass_of_the_object_in_motion * the_acceleration_of_the_object_in_motion
+```
+
+
+
+```{python}
+mass = 45
+acceleration = 1.8
+
+force = mass * acceleration
+```
+
+
+:::{.notes}
+Similarly to how variables named without meaning makes code readability difficult, the same can be said about variables with excessively long names.
+
+You want to be efficient yet understandable.
+
+In this example, we can see that the second body of code is much easier on our eye, and it takes much less effort to understand what our code is trying to convey.
+:::
+
+
+# Let’s apply what we learned!
\ No newline at end of file
diff --git a/modules/module7/slides/module7_18.qmd b/modules/module7/slides/module7_18.qmd
new file mode 100644
index 00000000..cb3ae257
--- /dev/null
+++ b/modules/module7/slides/module7_18.qmd
@@ -0,0 +1,332 @@
+---
+format: revealjs
+title: The Python Debugger
+title-slide-attributes:
+ data-notes: |
+---
+
+```{python}
+# | echo: false
+%run src/utils.py
+```
+
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We are going to talk about the Python Debugger.
+
+To do so, we are going to examine a piece of code that has a bug in it, and we're going to try to hunt down that bug with the debugger.
+
+The piece of code we are going to examine is a function called `random_walker`. This function simulates a random walk in two dimensions
+
+- so you can walk in any of four directions up, down, left, or right, and each one has a 1/4 chance of occurring.
+
+The function takes in the number of steps that you want as an argument.
+
+For example, if you pass in 10, `random_walker()` will take 10 steps and prints out the location every time and return the squared distance.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+The `random()` function that we import in from the `random` library generates a float from 0 and 1.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+The code works by checking if the number generated is between (upper bounds excluded):
+
+- 0.00-0.25
+- 0.25-0.5
+- 0.5-0.75
+- or 0.75-1
+
+Where each internal is pertaining to one of the directions left, right, up, or down.
+
+This means each direction has a 25% chance of happening, but there is a bug in this code that we will soon discover.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We are going to run the cell `random_walker(20),` which will print 20 steps.
+
+It’s hard to know immediately that something is wrong, but you can see that we’ve moved negatively in x directions (to the left) and positive in the y-direction (upwards).
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+If we run it again, we are going to get different outputs since it uses a random number generator `random(),` but weirdly, we see the same thing again.
+
+We seem to be consistently moving left and up.
+
+When we run it over and over, we see these results repeating.
+
+Why do we keep moving to the left and up when this function is supposed to result in equal probability for any of the four choices.
+
+Something seems a little bit suspicious.
+
+What is going on?
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+To get help in figuring this out, we are going to use something called a `breakpoint()`.
+
+`Breakpoint()` works by stopping the executing process. Now when Python gets to this `breakpoint()` function (which is part of the Python debugger), the code will stop running.
+
+We then can execute the code line by line and attempt to diagnose the problem.
+
+We run the `random_walker()` function again to redefine it since we’ve added this `breakpoint()` function.
+
+Now when the `random_walker()` function is called, it’s going to stop executing at this breakpoint.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+This is what is returned.
+
+We see this `pdb` which stands for python debugger.
+
+Our code has stopped, and it shows the line Python is currently stopped on, in this case, it's` if rand < 0.25:`.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+If we type `print(rand)`, we can see what the random number `rand` was, and it tells us 0.957.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+If we type `n` in the debugger, it runs to the next line.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We don't expect Python to go into the condition body, which is next in the code since `rand` does not meet the condition.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+The next 2 lines skip the statement bodies because they are not met as well.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We do, however, meet the else condition, and so 1 is subtracted from `y`.
+Nothing seems terribly wrong yet.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+Pressing `n` again brings us back to the top of the `for` loop.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We reassign `rand` a new random value, which turns out to be 0.0057.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+Let's go through another round of these `if` with our new random value.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We expect to go inside of this first `if` statement because the random number is actually less than a 0.25. Because our values are less than 0.25, we expect to move to the right and add 1 to `x`.
+
+We run this code, and we moved to the right just like we said we would.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We keep going and check the next condition.
+
+This is where things get suspicious.
+
+We move to the left **and** to the right, which is not the intention of the code.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+The intention behind this code is that only one of these four directions would be taken.
+If the number was between zero and a quarter, the step would be to the right. If it were between a quarter and a half, the step would be to the left, between half and three quarters, the steps would be up, and between three quarters and one, the step would be down.
+
+This way, there is always an equal chance of each direction.
+
+When the random number was .005, it moved in 2 directions, which doesn't make sense since only 1 step was supposed to be taken.
+
+Here it’s moving to the left, to the right and upward.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+The reason that this happens is because the two inner if statements should be `elif` statements and not `if` statements.
+
+In other words:
+
+*if this is the case, do this* ***but don't do anything else*** *or if this is the case, do this* ***but don't do anything else.***
+
+By accidentally having `if` statements instead of `elif` statements, it was allowing the execution of multiple condition bodies.
+
+Whenever a small number was generated, the movement would be left and right or just left, but it would be impossible to move right without moving left.
+
+In general, the movement would always be left and up and not right.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+So we’ve fixed the code, and we're done with the debugger.
+
+We stepped through the code step by step, which helped us solve the bug.
+
+We could try and do in our head, but that can be really hard as code gets more complicated. This breakpoint is convenient because it allows us to actually see what's happening at each step.
+
+
+To get out of the debugger, we write `q` for "quit".
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+We can remove the `breakpoint()` function by deleting it or commenting it out temporarily and run our cell again with the fixed code.
+:::
+
+---
+
+
+
+{fig-align="center" width="100%" fig-alt="404 image"}
+
+
+:::{.notes}
+It's really hard to test code that's random since we can't just look at the output and recognize that it’s been fixed.
+We can, however, run it a few times and see that steps are now being taken in different directions and things seem a little more reasonable.
+
+The Python debugger has other functions that can help debug your code and you can explore them in the documentation.
+:::
+
+
+# Let’s apply what we learned!
\ No newline at end of file
diff --git a/modules/module7/slides/module7_20.qmd b/modules/module7/slides/module7_20.qmd
new file mode 100644
index 00000000..83cfb94c
--- /dev/null
+++ b/modules/module7/slides/module7_20.qmd
@@ -0,0 +1,42 @@
+---
+format: revealjs
+title: What Did we Learn and What to Expect in Assignment 7
+title-slide-attributes:
+ data-notes: |
+---
+
+```{python}
+# | echo: false
+%run src/utils.py
+```
+
+
+## Summary
+
+Students are now expected to be able to:
+
+- Describe what Python libraries are, as well as explain when and why they are useful.
+- Identify where code can be improved concerning variable names, magic numbers, comments and whitespace.
+- Write code that is human readable and follows the black style guide.
+- Import files from other directories.
+- Use `pytest` to check a function's tests.
+- When running `pytest`, explain how pytest finds the associated test functions.
+- Explain how the Python debugger can help rectify your code.
+
+
+:::{.notes}
+The assignment will concentrate on the learning objectives as well as building knowledge on existing concepts.
+:::
+
+---
+
+## Attribution
+
+The cereal dataset:
+
+ “[80 Cereals](https://www.kaggle.com/crawford/80-cereals/)” (c) by [Chris Crawford](https://www.linkedin.com/in/crawforc3/) is licensed
+under [Creative Commons Attribution-ShareAlike 3.0 Unported](http://creativecommons.org/licenses/by-sa/3.0/)
+
+
+
+# On to Assignment 7!
\ No newline at end of file
diff --git a/styles.scss b/styles.scss
index 80d27e67..d685bb3e 100644
--- a/styles.scss
+++ b/styles.scss
@@ -92,7 +92,6 @@ code {
.reveal.show-notes .speaker-notes code,
.reveal.show-notes .speaker-notes div.sourceCode {
-
/* The ubuntu mono font is quite small */
font-size: 1.2em;
}