From f21fbc7f6232bfb85d31a908fa6bf7278754f08c Mon Sep 17 00:00:00 2001
From: Stockton Jenkins <jsjenkins4@wisc.edu>
Date: Thu, 20 Feb 2025 17:14:18 -0600
Subject: [PATCH] debugging-autobadger

---
 debugging-autobadger.md | 224 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 224 insertions(+)
 create mode 100644 debugging-autobadger.md

diff --git a/debugging-autobadger.md b/debugging-autobadger.md
new file mode 100644
index 0000000..45aac22
--- /dev/null
+++ b/debugging-autobadger.md
@@ -0,0 +1,224 @@
+# Read-only Access
+
+We've opened up the `autobadger` tool in attempt to make things more visible to you and less of a "black box". We've done this by making the repository *read-only*, meaning you should be able to `git clone` the repo but not `git push` to it.
+
+To start, navigate to a directory outside of any class project. I'd recommend cloning to the same directory as your projects.
+
+```bash
+git clone https://oauth2:glpat-CSTX_tgpf38eJHyUW213@git.doit.wisc.edu/cdis/cs/courses/cs544/s25/tools/autobadger.git
+```
+
+
+> **NOTE**: if you want to use this method throughout the semester, you'll need to `git pull` to get up-to-date code for each project.
+
+
+Your folder structure should look something like
+
+```
+some-directory/
+	autobadger/
+	p1/
+	p2/
+    ... # other projects
+```
+
+# Making Changes
+
+You can change the code inside of `autobadger`. The only files that will be of interest to you are inside the `projects/` directory, i.e. `projects/*.py`). Your changes will be for debugging, i.e. `print()` or `breakpoint()` statements.
+#### Using `pip`
+
+For whatever project you're working on, you will need to *apply* any changes you make using `pip`
+
+For example, assuming
+- I'm working on `p2`
+- in my `p2` directory
+- and have my `venv` activated
+
+I would do something like:
+
+```bash
+pip3 install ../autobadger/.
+```
+
+This would install and replace my local version of `autobadger` . Now when I run 
+
+```
+autobadger --project=p2
+```
+
+I will see my changes in effect.
+
+# Breakpoints
+
+Since `breakpoint()` is less known and straightforward, I will teach about it here.
+
+> **NOTE**: It is not required to use `breakpoint()`. You are also welcome to use `print()` instead. `breakpoint()` has a **steeper learning curve**, but may **help you iterate more quickly and save you time** once the basic concepts are well-understood.
+
+### What is a breakpoint?
+
+`breakpoint()` is a built-in function in Python and starts the **debugger** at the point where it is called. It allows developers to inspect variables, step through code, and debug interactively.
+#### Simple Example:
+
+```python
+# Inside of /path/to/file.py
+
+def calculate_sum(a, b):
+    breakpoint()  # Debugger starts here
+    return a + b 
+
+
+calculate_sum(3, 5)  # execute function
+```
+
+Adding a `breakpoint()`  will pause execution, allowing you to inspect `a` and `b` before proceeding. I would see something like:
+
+```
+> /path/to/file.py(3)calculate_sum()
+-> return a + b
+```
+
+in the terminal, which displays
+1. the next line to be executed `return a + b`
+2. `(3)calculate_sum()` tells me the line number and the function name (if applicable)
+3. `/path/to/file.py` tells me the current file
+
+### Navigating the debugger
+
+While the Python debugger is active, you can use several commands to navigate through your program and investigate.
+
+- `Variable name`:  I can type any variable that is in scope and get it's value.
+	- Ex: Typing `a` in the previous example would return the *value* of `a`
+	- **NOTE**: if a variable name also coincides with a command keyword in the debugger, you may need to use `print(<variable_name>)` instead. `b` is one of those commands, so to print the value of `b` to the terminal, I would need to do `print(b)`:
+- `Evaluation`: I can also evaluate statements (i.e. add two numbers)
+
+```
+In [3]: calculate_sum(3, 5)
+> <ipython-input-2-443b6e8e0b0a>(3)calculate_sum()
+-> return a + b
+
+(Pdb) print(a)
+3
+
+(Pdb) print(b)
+5
+
+(Pdb) print(a + b)
+8
+```
+
+- `n`: Steps to the next line of my program
+- `c`: Continues execution of the program until the next breakpoint, or until the program ends.
+- `s`: Steps *into* a function or method call
+- `exit`: kills the debugger and ends the program
+
+# An example
+
+### Using breakpoints
+
+Suppose I want to investigate `Q4` for `p2`. I can add `breakpoint()` statements to the Q4 test method for the `ProjectTwoTest` class.
+
+Navigating to `projects/p2.py` inside of `autobadger`, I find:
+
+```python
+@graded(Q=4, points=10)  
+def test_simple_http(self) -> int | TestError:  
+    address = self._test_cache_server("-cache-1")  
+    if isinstance(address, TestError):  
+        return address  
+    r = requests.get(f"{address}/lookup/53706")  
+    r.raise_for_status()  
+    result = r.json()  
+    if "addrs" not in result or "source" not in result:  
+        return TestError(  
+            message=f"Result body should be JSON with 'addrs' and 'source' fields, but got {result}.",  
+            earned=5,  
+        )  
+    return 10
+```
+
+> Note: This is Q4 since I have `Q=4` in the decorator.
+
+**I can edit this method by adding *breakpoints*!**
+
+```python
+@graded(Q=4, points=10)  
+def test_simple_http(self) -> int | TestError:  
+    breakpoint()  
+    address = self._test_cache_server("-cache-1")  
+    if isinstance(address, TestError):  
+        return address  
+    r = requests.get(f"{address}/lookup/53706")  
+    breakpoint()
+    r.raise_for_status()
+    result = r.json()  
+    if "addrs" not in result or "source" not in result:  
+        return TestError(  
+            message=f"Result body should be JSON with 'addrs' and 'source' fields, but got {result}.",  
+            earned=5,  
+        )  
+    return 10
+```
+
+Now, after I update with `pip` as mentioned above, I can run `autobadger --project=p2` and get:
+
+```
+> /Users/.../p2.py(103)test_simple_http()
+-> address = self._test_cache_server("-cache-1")
+```
+
+Note that in this situation, typing `address` would give me an error cause it **not yet defined**:
+
+```
+(Pdb) address
+*** NameError: name 'address' is not defined
+```
+###### Using `n` (next line)
+
+`address` defined on the *next line*. So, I use the `n` command to step!
+
+```
+(Pdb) n
+> /Users/.../p2.py(104)test_simple_http()
+-> if isinstance(address, TestError):
+
+(Pdb) address
+'http://localhost:64879'
+```
+###### Using `s` (step into)
+
+I could have also used `s` to *step into* `self._test_cache_server(...)` if I had wanted to investigate further:
+
+```
+> /Users/.../p2.py(103)test_simple_http()
+-> address = self._test_cache_server("-cache-1")
+
+(Pdb) s
+--Call--
+> /Users/.../p2.py(118)_test_cache_server()
+-> def _test_cache_server(self, server_suffix: str) -> str | TestError:
+       # Now in a new method — _test_cache_server
+
+(Pdb) n
+> /Users/.../p2.py(119)_test_cache_server()
+-> cache_server = [c for c in self.containers if c["Name"].endswith(server_suffix)]
+
+```
+###### Using `c` (continue)
+
+I can also *continue* till the next breakpoint, which is quite convenient if you don't need to step over every line of code:
+
+```
+> /Users/.../p2.py(103)test_simple_http()
+-> address = self._test_cache_server("-cache-1")
+
+(Pdb) c
+> /Users/.../p2.py(108)test_simple_http()
+-> r.raise_for_status()
+
+(Pdb) print(r.json())
+{'addrs': [...], 'error': None, 'source': '...'}
+```
+
+Using `c` jumped from line `103` to line `108`, where I had my two breakpoints defined.
+
+> **NOTE**: using `c` again would continue the Python program till the end of its execution since I have no other `breakpoint()` statements
\ No newline at end of file
-- 
GitLab